fbtft-io.c (5314B)
1// SPDX-License-Identifier: GPL-2.0 2#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-bit 33 * @par: Driver data 34 * @buf: Buffer to write 35 * @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 optimization 128 * only one driver can use the optimized version at a time 129 */ 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_GPIO 135 static u8 prev_data; 136#endif 137 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_GPIO 149 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#else 161 for (i = 0; i < 8; i++) { 162 gpiod_set_value(par->gpio.db[i], data & 1); 163 data >>= 1; 164 } 165#endif 166 167 /* Pullup /WR */ 168 gpiod_set_value(par->gpio.wr, 0); 169 170#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 171 prev_data = *(u8 *)buf; 172#endif 173 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_GPIO 185 static u16 prev_data; 186#endif 187 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_GPIO 199 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#else 211 for (i = 0; i < 16; i++) { 212 gpiod_set_value(par->gpio.db[i], data & 1); 213 data >>= 1; 214 } 215#endif 216 217 /* Pullup /WR */ 218 gpiod_set_value(par->gpio.wr, 0); 219 220#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 221 prev_data = *(u16 *)buf; 222#endif 223 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);