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