1 #include <linux/export.h> 2 #include <linux/errno.h> 3 #include <linux/gpio.h> 4 #include <linux/spi/spi.h> 5 #include "fbtft.h" 6 7 /***************************************************************************** 8 * 9 * void (*write_reg)(struct fbtft_par *par, int len, ...); 10 * 11 *****************************************************************************/ 12 13 #define define_fbtft_write_reg(func, type, modifier) \ 14 void func(struct fbtft_par *par, int len, ...) \ 15 { \ 16 va_list args; \ 17 int i, ret; \ 18 int offset = 0; \ 19 type *buf = (type *)par->buf; \ 20 \ 21 if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { \ 22 va_start(args, len); \ 23 for (i = 0; i < len; i++) { \ 24 buf[i] = (type)va_arg(args, unsigned int); \ 25 } \ 26 va_end(args); \ 27 fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, type, buf, len, "%s: ", __func__); \ 28 } \ 29 \ 30 va_start(args, len); \ 31 \ 32 if (par->startbyte) { \ 33 *(u8 *)par->buf = par->startbyte; \ 34 buf = (type *)(par->buf + 1); \ 35 offset = 1; \ 36 } \ 37 \ 38 *buf = modifier((type)va_arg(args, unsigned int)); \ 39 ret = fbtft_write_buf_dc(par, par->buf, sizeof(type) + offset, 0); \ 40 if (ret < 0) \ 41 goto out; \ 42 len--; \ 43 \ 44 if (par->startbyte) \ 45 *(u8 *)par->buf = par->startbyte | 0x2; \ 46 \ 47 if (len) { \ 48 i = len; \ 49 while (i--) \ 50 *buf++ = modifier((type)va_arg(args, unsigned int)); \ 51 fbtft_write_buf_dc(par, par->buf, \ 52 len * (sizeof(type) + offset), 1); \ 53 } \ 54 out: \ 55 va_end(args); \ 56 } \ 57 EXPORT_SYMBOL(func); 58 59 define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, ) 60 define_fbtft_write_reg(fbtft_write_reg16_bus8, u16, cpu_to_be16) 61 define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, ) 62 63 void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...) 64 { 65 va_list args; 66 int i, ret; 67 int pad = 0; 68 u16 *buf = (u16 *)par->buf; 69 70 if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { 71 va_start(args, len); 72 for (i = 0; i < len; i++) 73 *(((u8 *)buf) + i) = (u8)va_arg(args, unsigned int); 74 va_end(args); 75 fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, 76 par->info->device, u8, buf, len, "%s: ", __func__); 77 } 78 if (len <= 0) 79 return; 80 81 if (par->spi && (par->spi->bits_per_word == 8)) { 82 /* we're emulating 9-bit, pad start of buffer with no-ops 83 * (assuming here that zero is a no-op) 84 */ 85 pad = (len % 4) ? 4 - (len % 4) : 0; 86 for (i = 0; i < pad; i++) 87 *buf++ = 0x000; 88 } 89 90 va_start(args, len); 91 *buf++ = (u8)va_arg(args, unsigned int); 92 i = len - 1; 93 while (i--) { 94 *buf = (u8)va_arg(args, unsigned int); 95 *buf++ |= 0x100; /* dc=1 */ 96 } 97 va_end(args); 98 ret = par->fbtftops.write(par, par->buf, (len + pad) * sizeof(u16)); 99 if (ret < 0) { 100 dev_err(par->info->device, 101 "write() failed and returned %d\n", ret); 102 return; 103 } 104 } 105 EXPORT_SYMBOL(fbtft_write_reg8_bus9); 106 107 /***************************************************************************** 108 * 109 * int (*write_vmem)(struct fbtft_par *par); 110 * 111 *****************************************************************************/ 112 113 /* 16 bit pixel over 8-bit databus */ 114 int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) 115 { 116 u16 *vmem16; 117 u16 *txbuf16 = par->txbuf.buf; 118 size_t remain; 119 size_t to_copy; 120 size_t tx_array_size; 121 int i; 122 int ret = 0; 123 size_t startbyte_size = 0; 124 125 fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", 126 __func__, offset, len); 127 128 remain = len / 2; 129 vmem16 = (u16 *)(par->info->screen_buffer + offset); 130 131 if (par->gpio.dc != -1) 132 gpio_set_value(par->gpio.dc, 1); 133 134 /* non buffered write */ 135 if (!par->txbuf.buf) 136 return par->fbtftops.write(par, vmem16, len); 137 138 /* buffered write */ 139 tx_array_size = par->txbuf.len / 2; 140 141 if (par->startbyte) { 142 txbuf16 = par->txbuf.buf + 1; 143 tx_array_size -= 2; 144 *(u8 *)(par->txbuf.buf) = par->startbyte | 0x2; 145 startbyte_size = 1; 146 } 147 148 while (remain) { 149 to_copy = min(tx_array_size, remain); 150 dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", 151 to_copy, remain - to_copy); 152 153 for (i = 0; i < to_copy; i++) 154 txbuf16[i] = cpu_to_be16(vmem16[i]); 155 156 vmem16 = vmem16 + to_copy; 157 ret = par->fbtftops.write(par, par->txbuf.buf, 158 startbyte_size + to_copy * 2); 159 if (ret < 0) 160 return ret; 161 remain -= to_copy; 162 } 163 164 return ret; 165 } 166 EXPORT_SYMBOL(fbtft_write_vmem16_bus8); 167 168 /* 16 bit pixel over 9-bit SPI bus: dc + high byte, dc + low byte */ 169 int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len) 170 { 171 u8 *vmem8; 172 u16 *txbuf16 = par->txbuf.buf; 173 size_t remain; 174 size_t to_copy; 175 size_t tx_array_size; 176 int i; 177 int ret = 0; 178 179 fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", 180 __func__, offset, len); 181 182 if (!par->txbuf.buf) { 183 dev_err(par->info->device, "%s: txbuf.buf is NULL\n", __func__); 184 return -1; 185 } 186 187 remain = len; 188 vmem8 = par->info->screen_buffer + offset; 189 190 tx_array_size = par->txbuf.len / 2; 191 192 while (remain) { 193 to_copy = min(tx_array_size, remain); 194 dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", 195 to_copy, remain - to_copy); 196 197 #ifdef __LITTLE_ENDIAN 198 for (i = 0; i < to_copy; i += 2) { 199 txbuf16[i] = 0x0100 | vmem8[i + 1]; 200 txbuf16[i + 1] = 0x0100 | vmem8[i]; 201 } 202 #else 203 for (i = 0; i < to_copy; i++) 204 txbuf16[i] = 0x0100 | vmem8[i]; 205 #endif 206 vmem8 = vmem8 + to_copy; 207 ret = par->fbtftops.write(par, par->txbuf.buf, to_copy * 2); 208 if (ret < 0) 209 return ret; 210 remain -= to_copy; 211 } 212 213 return ret; 214 } 215 EXPORT_SYMBOL(fbtft_write_vmem16_bus9); 216 217 int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len) 218 { 219 dev_err(par->info->device, "%s: function not implemented\n", __func__); 220 return -1; 221 } 222 EXPORT_SYMBOL(fbtft_write_vmem8_bus8); 223 224 /* 16 bit pixel over 16-bit databus */ 225 int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len) 226 { 227 u16 *vmem16; 228 229 fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", 230 __func__, offset, len); 231 232 vmem16 = (u16 *)(par->info->screen_buffer + offset); 233 234 /* no need for buffered write with 16-bit bus */ 235 return fbtft_write_buf_dc(par, vmem16, len, 1); 236 } 237 EXPORT_SYMBOL(fbtft_write_vmem16_bus16); 238