Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15 235 lines 5.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/export.h> 3#include <linux/errno.h> 4#include <linux/gpio.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=%d): ", __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=%d): ", __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=%d) txbuf => ", __func__, len); 113 } 114 115 spi_message_init(&m); 116 spi_message_add_tail(&t, &m); 117 ret = spi_sync(par->spi, &m); 118 fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len, 119 "%s(len=%d) buf <= ", __func__, len); 120 121 return ret; 122} 123EXPORT_SYMBOL(fbtft_read_spi); 124 125/* 126 * Optimized use of gpiolib is twice as fast as no optimization 127 * only one driver can use the optimized version at a time 128 */ 129int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) 130{ 131 u8 data; 132 int i; 133#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 134 static u8 prev_data; 135#endif 136 137 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 138 "%s(len=%d): ", __func__, len); 139 140 while (len--) { 141 data = *(u8 *)buf; 142 143 /* Start writing by pulling down /WR */ 144 gpio_set_value(par->gpio.wr, 0); 145 146 /* Set data */ 147#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 148 if (data == prev_data) { 149 gpio_set_value(par->gpio.wr, 0); /* used as delay */ 150 } else { 151 for (i = 0; i < 8; i++) { 152 if ((data & 1) != (prev_data & 1)) 153 gpio_set_value(par->gpio.db[i], 154 data & 1); 155 data >>= 1; 156 prev_data >>= 1; 157 } 158 } 159#else 160 for (i = 0; i < 8; i++) { 161 gpio_set_value(par->gpio.db[i], data & 1); 162 data >>= 1; 163 } 164#endif 165 166 /* Pullup /WR */ 167 gpio_set_value(par->gpio.wr, 1); 168 169#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 170 prev_data = *(u8 *)buf; 171#endif 172 buf++; 173 } 174 175 return 0; 176} 177EXPORT_SYMBOL(fbtft_write_gpio8_wr); 178 179int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) 180{ 181 u16 data; 182 int i; 183#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 184 static u16 prev_data; 185#endif 186 187 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 188 "%s(len=%d): ", __func__, len); 189 190 while (len) { 191 data = *(u16 *)buf; 192 193 /* Start writing by pulling down /WR */ 194 gpio_set_value(par->gpio.wr, 0); 195 196 /* Set data */ 197#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 198 if (data == prev_data) { 199 gpio_set_value(par->gpio.wr, 0); /* used as delay */ 200 } else { 201 for (i = 0; i < 16; i++) { 202 if ((data & 1) != (prev_data & 1)) 203 gpio_set_value(par->gpio.db[i], 204 data & 1); 205 data >>= 1; 206 prev_data >>= 1; 207 } 208 } 209#else 210 for (i = 0; i < 16; i++) { 211 gpio_set_value(par->gpio.db[i], data & 1); 212 data >>= 1; 213 } 214#endif 215 216 /* Pullup /WR */ 217 gpio_set_value(par->gpio.wr, 1); 218 219#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 220 prev_data = *(u16 *)buf; 221#endif 222 buf += 2; 223 len -= 2; 224 } 225 226 return 0; 227} 228EXPORT_SYMBOL(fbtft_write_gpio16_wr); 229 230int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) 231{ 232 dev_err(par->info->device, "%s: function not implemented\n", __func__); 233 return -1; 234} 235EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);