1 #include <linux/export.h>
2 #include <linux/errno.h>
3 #include <linux/gpio.h>
4 #include <linux/spi/spi.h>
7 int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
9 struct spi_transfer t = {
15 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
16 "%s(len=%d): ", __func__, len);
19 dev_err(par->info->device,
20 "%s: par->spi is unexpectedly NULL\n", __func__);
25 spi_message_add_tail(&t, &m);
26 return spi_sync(par->spi, &m);
28 EXPORT_SYMBOL(fbtft_write_spi);
31 * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit
33 * @buf: Buffer to write
34 * @len: Length of buffer (must be divisible by 8)
36 * When 9-bit SPI is not available, this function can be used to emulate that.
37 * par->extra must hold a transformation buffer used for transfer.
39 int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len)
43 size_t size = len / 2;
48 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
49 "%s(len=%d): ", __func__, len);
52 dev_err(par->info->device, "%s: error: par->extra is NULL\n",
57 dev_err(par->info->device,
58 "error: len=%zu must be divisible by 8\n", len);
62 for (i = 0; i < size; i += 8) {
65 for (j = 0; j < 7; j++) {
66 dc = (*src & 0x0100) ? 1 : 0;
73 tmp |= ((*src & 0x0100) ? 1 : 0);
74 *(__be64 *)dst = cpu_to_be64(tmp);
76 *dst++ = (u8)(*src++ & 0x00FF);
80 return spi_write(par->spi, par->extra, size + added);
82 EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
84 int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len)
87 u8 txbuf[32] = { 0, };
88 struct spi_transfer t = {
96 dev_err(par->info->device,
97 "%s: par->spi is unexpectedly NULL\n", __func__);
101 if (par->startbyte) {
103 dev_err(par->info->device,
104 "len=%zu can't be larger than 32 when using 'startbyte'\n",
108 txbuf[0] = par->startbyte | 0x3;
110 fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8,
111 txbuf, len, "%s(len=%d) txbuf => ", __func__, len);
114 spi_message_init(&m);
115 spi_message_add_tail(&t, &m);
116 ret = spi_sync(par->spi, &m);
117 fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len,
118 "%s(len=%d) buf <= ", __func__, len);
122 EXPORT_SYMBOL(fbtft_read_spi);
125 * Optimized use of gpiolib is twice as fast as no optimization
126 * only one driver can use the optimized version at a time
128 int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
132 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
136 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
137 "%s(len=%d): ", __func__, len);
142 /* Start writing by pulling down /WR */
143 gpio_set_value(par->gpio.wr, 0);
146 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
147 if (data == prev_data) {
148 gpio_set_value(par->gpio.wr, 0); /* used as delay */
150 for (i = 0; i < 8; i++) {
151 if ((data & 1) != (prev_data & 1))
152 gpio_set_value(par->gpio.db[i],
159 for (i = 0; i < 8; i++) {
160 gpio_set_value(par->gpio.db[i], data & 1);
166 gpio_set_value(par->gpio.wr, 1);
168 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
169 prev_data = *(u8 *)buf;
176 EXPORT_SYMBOL(fbtft_write_gpio8_wr);
178 int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
182 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
183 static u16 prev_data;
186 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
187 "%s(len=%d): ", __func__, len);
192 /* Start writing by pulling down /WR */
193 gpio_set_value(par->gpio.wr, 0);
196 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
197 if (data == prev_data) {
198 gpio_set_value(par->gpio.wr, 0); /* used as delay */
200 for (i = 0; i < 16; i++) {
201 if ((data & 1) != (prev_data & 1))
202 gpio_set_value(par->gpio.db[i],
209 for (i = 0; i < 16; i++) {
210 gpio_set_value(par->gpio.db[i], data & 1);
216 gpio_set_value(par->gpio.wr, 1);
218 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
219 prev_data = *(u16 *)buf;
227 EXPORT_SYMBOL(fbtft_write_gpio16_wr);
229 int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len)
231 dev_err(par->info->device, "%s: function not implemented\n", __func__);
234 EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);