Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/export.h>
0003 #include <linux/errno.h>
0004 #include <linux/gpio/consumer.h>
0005 #include <linux/spi/spi.h>
0006 #include "fbtft.h"
0007 
0008 int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
0009 {
0010     struct spi_transfer t = {
0011         .tx_buf = buf,
0012         .len = len,
0013     };
0014     struct spi_message m;
0015 
0016     fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
0017               "%s(len=%zu): ", __func__, len);
0018 
0019     if (!par->spi) {
0020         dev_err(par->info->device,
0021             "%s: par->spi is unexpectedly NULL\n", __func__);
0022         return -1;
0023     }
0024 
0025     spi_message_init(&m);
0026     spi_message_add_tail(&t, &m);
0027     return spi_sync(par->spi, &m);
0028 }
0029 EXPORT_SYMBOL(fbtft_write_spi);
0030 
0031 /**
0032  * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit
0033  * @par: Driver data
0034  * @buf: Buffer to write
0035  * @len: Length of buffer (must be divisible by 8)
0036  *
0037  * When 9-bit SPI is not available, this function can be used to emulate that.
0038  * par->extra must hold a transformation buffer used for transfer.
0039  */
0040 int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len)
0041 {
0042     u16 *src = buf;
0043     u8 *dst = par->extra;
0044     size_t size = len / 2;
0045     size_t added = 0;
0046     int bits, i, j;
0047     u64 val, dc, tmp;
0048 
0049     fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
0050               "%s(len=%zu): ", __func__, len);
0051 
0052     if (!par->extra) {
0053         dev_err(par->info->device, "%s: error: par->extra is NULL\n",
0054             __func__);
0055         return -EINVAL;
0056     }
0057     if ((len % 8) != 0) {
0058         dev_err(par->info->device,
0059             "error: len=%zu must be divisible by 8\n", len);
0060         return -EINVAL;
0061     }
0062 
0063     for (i = 0; i < size; i += 8) {
0064         tmp = 0;
0065         bits = 63;
0066         for (j = 0; j < 7; j++) {
0067             dc = (*src & 0x0100) ? 1 : 0;
0068             val = *src & 0x00FF;
0069             tmp |= dc << bits;
0070             bits -= 8;
0071             tmp |= val << bits--;
0072             src++;
0073         }
0074         tmp |= ((*src & 0x0100) ? 1 : 0);
0075         *(__be64 *)dst = cpu_to_be64(tmp);
0076         dst += 8;
0077         *dst++ = (u8)(*src++ & 0x00FF);
0078         added++;
0079     }
0080 
0081     return spi_write(par->spi, par->extra, size + added);
0082 }
0083 EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
0084 
0085 int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len)
0086 {
0087     int ret;
0088     u8 txbuf[32] = { 0, };
0089     struct spi_transfer t = {
0090             .speed_hz = 2000000,
0091             .rx_buf     = buf,
0092             .len        = len,
0093         };
0094     struct spi_message  m;
0095 
0096     if (!par->spi) {
0097         dev_err(par->info->device,
0098             "%s: par->spi is unexpectedly NULL\n", __func__);
0099         return -ENODEV;
0100     }
0101 
0102     if (par->startbyte) {
0103         if (len > 32) {
0104             dev_err(par->info->device,
0105                 "len=%zu can't be larger than 32 when using 'startbyte'\n",
0106                 len);
0107             return -EINVAL;
0108         }
0109         txbuf[0] = par->startbyte | 0x3;
0110         t.tx_buf = txbuf;
0111         fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8,
0112                   txbuf, len, "%s(len=%zu) txbuf => ",
0113                   __func__, len);
0114     }
0115 
0116     spi_message_init(&m);
0117     spi_message_add_tail(&t, &m);
0118     ret = spi_sync(par->spi, &m);
0119     fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len,
0120               "%s(len=%zu) buf <= ", __func__, len);
0121 
0122     return ret;
0123 }
0124 EXPORT_SYMBOL(fbtft_read_spi);
0125 
0126 /*
0127  * Optimized use of gpiolib is twice as fast as no optimization
0128  * only one driver can use the optimized version at a time
0129  */
0130 int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
0131 {
0132     u8 data;
0133     int i;
0134 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
0135     static u8 prev_data;
0136 #endif
0137 
0138     fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
0139               "%s(len=%zu): ", __func__, len);
0140 
0141     while (len--) {
0142         data = *(u8 *)buf;
0143 
0144         /* Start writing by pulling down /WR */
0145         gpiod_set_value(par->gpio.wr, 1);
0146 
0147         /* Set data */
0148 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
0149         if (data == prev_data) {
0150             gpiod_set_value(par->gpio.wr, 1); /* used as delay */
0151         } else {
0152             for (i = 0; i < 8; i++) {
0153                 if ((data & 1) != (prev_data & 1))
0154                     gpiod_set_value(par->gpio.db[i],
0155                             data & 1);
0156                 data >>= 1;
0157                 prev_data >>= 1;
0158             }
0159         }
0160 #else
0161         for (i = 0; i < 8; i++) {
0162             gpiod_set_value(par->gpio.db[i], data & 1);
0163             data >>= 1;
0164         }
0165 #endif
0166 
0167         /* Pullup /WR */
0168         gpiod_set_value(par->gpio.wr, 0);
0169 
0170 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
0171         prev_data = *(u8 *)buf;
0172 #endif
0173         buf++;
0174     }
0175 
0176     return 0;
0177 }
0178 EXPORT_SYMBOL(fbtft_write_gpio8_wr);
0179 
0180 int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
0181 {
0182     u16 data;
0183     int i;
0184 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
0185     static u16 prev_data;
0186 #endif
0187 
0188     fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
0189               "%s(len=%zu): ", __func__, len);
0190 
0191     while (len) {
0192         data = *(u16 *)buf;
0193 
0194         /* Start writing by pulling down /WR */
0195         gpiod_set_value(par->gpio.wr, 1);
0196 
0197         /* Set data */
0198 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
0199         if (data == prev_data) {
0200             gpiod_set_value(par->gpio.wr, 1); /* used as delay */
0201         } else {
0202             for (i = 0; i < 16; i++) {
0203                 if ((data & 1) != (prev_data & 1))
0204                     gpiod_set_value(par->gpio.db[i],
0205                             data & 1);
0206                 data >>= 1;
0207                 prev_data >>= 1;
0208             }
0209         }
0210 #else
0211         for (i = 0; i < 16; i++) {
0212             gpiod_set_value(par->gpio.db[i], data & 1);
0213             data >>= 1;
0214         }
0215 #endif
0216 
0217         /* Pullup /WR */
0218         gpiod_set_value(par->gpio.wr, 0);
0219 
0220 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
0221         prev_data = *(u16 *)buf;
0222 #endif
0223         buf += 2;
0224         len -= 2;
0225     }
0226 
0227     return 0;
0228 }
0229 EXPORT_SYMBOL(fbtft_write_gpio16_wr);
0230 
0231 int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len)
0232 {
0233     dev_err(par->info->device, "%s: function not implemented\n", __func__);
0234     return -1;
0235 }
0236 EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);