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