237 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/export.h>3#include <linux/errno.h>4#include <linux/gpio/consumer.h>5#include <linux/spi/spi.h>6#include "fbtft.h"7 8int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)9{10 struct spi_transfer t = {11 .tx_buf = buf,12 .len = len,13 };14 struct spi_message m;15 16 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,17 "%s(len=%zu): ", __func__, len);18 19 if (!par->spi) {20 dev_err(par->info->device,21 "%s: par->spi is unexpectedly NULL\n", __func__);22 return -1;23 }24 25 spi_message_init(&m);26 spi_message_add_tail(&t, &m);27 return spi_sync(par->spi, &m);28}29EXPORT_SYMBOL(fbtft_write_spi);30 31/**32 * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit33 * @par: Driver data34 * @buf: Buffer to write35 * @len: Length of buffer (must be divisible by 8)36 *37 * When 9-bit SPI is not available, this function can be used to emulate that.38 * par->extra must hold a transformation buffer used for transfer.39 */40int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len)41{42 u16 *src = buf;43 u8 *dst = par->extra;44 size_t size = len / 2;45 size_t added = 0;46 int bits, i, j;47 u64 val, dc, tmp;48 49 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,50 "%s(len=%zu): ", __func__, len);51 52 if (!par->extra) {53 dev_err(par->info->device, "%s: error: par->extra is NULL\n",54 __func__);55 return -EINVAL;56 }57 if ((len % 8) != 0) {58 dev_err(par->info->device,59 "error: len=%zu must be divisible by 8\n", len);60 return -EINVAL;61 }62 63 for (i = 0; i < size; i += 8) {64 tmp = 0;65 bits = 63;66 for (j = 0; j < 7; j++) {67 dc = (*src & 0x0100) ? 1 : 0;68 val = *src & 0x00FF;69 tmp |= dc << bits;70 bits -= 8;71 tmp |= val << bits--;72 src++;73 }74 tmp |= ((*src & 0x0100) ? 1 : 0);75 *(__be64 *)dst = cpu_to_be64(tmp);76 dst += 8;77 *dst++ = (u8)(*src++ & 0x00FF);78 added++;79 }80 81 return spi_write(par->spi, par->extra, size + added);82}83EXPORT_SYMBOL(fbtft_write_spi_emulate_9);84 85int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len)86{87 int ret;88 u8 txbuf[32] = { 0, };89 struct spi_transfer t = {90 .speed_hz = 2000000,91 .rx_buf = buf,92 .len = len,93 };94 struct spi_message m;95 96 if (!par->spi) {97 dev_err(par->info->device,98 "%s: par->spi is unexpectedly NULL\n", __func__);99 return -ENODEV;100 }101 102 if (par->startbyte) {103 if (len > 32) {104 dev_err(par->info->device,105 "len=%zu can't be larger than 32 when using 'startbyte'\n",106 len);107 return -EINVAL;108 }109 txbuf[0] = par->startbyte | 0x3;110 t.tx_buf = txbuf;111 fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8,112 txbuf, len, "%s(len=%zu) txbuf => ",113 __func__, len);114 }115 116 spi_message_init(&m);117 spi_message_add_tail(&t, &m);118 ret = spi_sync(par->spi, &m);119 fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len,120 "%s(len=%zu) buf <= ", __func__, len);121 122 return ret;123}124EXPORT_SYMBOL(fbtft_read_spi);125 126/*127 * Optimized use of gpiolib is twice as fast as no optimization128 * only one driver can use the optimized version at a time129 */130int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)131{132 u8 data;133 int i;134#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO135 static u8 prev_data;136#endif137 138 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,139 "%s(len=%zu): ", __func__, len);140 141 while (len--) {142 data = *(u8 *)buf;143 144 /* Start writing by pulling down /WR */145 gpiod_set_value(par->gpio.wr, 1);146 147 /* Set data */148#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO149 if (data == prev_data) {150 gpiod_set_value(par->gpio.wr, 1); /* used as delay */151 } else {152 for (i = 0; i < 8; i++) {153 if ((data & 1) != (prev_data & 1))154 gpiod_set_value(par->gpio.db[i],155 data & 1);156 data >>= 1;157 prev_data >>= 1;158 }159 }160#else161 for (i = 0; i < 8; i++) {162 gpiod_set_value(par->gpio.db[i], data & 1);163 data >>= 1;164 }165#endif166 167 /* Pullup /WR */168 gpiod_set_value(par->gpio.wr, 0);169 170#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO171 prev_data = *(u8 *)buf;172#endif173 buf++;174 }175 176 return 0;177}178EXPORT_SYMBOL(fbtft_write_gpio8_wr);179 180int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)181{182 u16 data;183 int i;184#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO185 static u16 prev_data;186#endif187 188 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,189 "%s(len=%zu): ", __func__, len);190 191 while (len) {192 data = *(u16 *)buf;193 194 /* Start writing by pulling down /WR */195 gpiod_set_value(par->gpio.wr, 1);196 197 /* Set data */198#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO199 if (data == prev_data) {200 gpiod_set_value(par->gpio.wr, 1); /* used as delay */201 } else {202 for (i = 0; i < 16; i++) {203 if ((data & 1) != (prev_data & 1))204 gpiod_set_value(par->gpio.db[i],205 data & 1);206 data >>= 1;207 prev_data >>= 1;208 }209 }210#else211 for (i = 0; i < 16; i++) {212 gpiod_set_value(par->gpio.db[i], data & 1);213 data >>= 1;214 }215#endif216 217 /* Pullup /WR */218 gpiod_set_value(par->gpio.wr, 0);219 220#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO221 prev_data = *(u16 *)buf;222#endif223 buf += 2;224 len -= 2;225 }226 227 return 0;228}229EXPORT_SYMBOL(fbtft_write_gpio16_wr);230 231int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len)232{233 dev_err(par->info->device, "%s: function not implemented\n", __func__);234 return -1;235}236EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);237