brintos

brintos / linux-shallow public Read only

0
0
Text · 5.2 KiB · de1904a Raw
237 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 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-bit33 * @par: Driver data34 * @buf: Buffer to write35 * @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 optimization128 * only one driver can use the optimized version at a time129 */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_GPIO135	static u8 prev_data;136#endif137 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_GPIO149		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#else161		for (i = 0; i < 8; i++) {162			gpiod_set_value(par->gpio.db[i], data & 1);163			data >>= 1;164		}165#endif166 167		/* Pullup /WR */168		gpiod_set_value(par->gpio.wr, 0);169 170#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO171		prev_data = *(u8 *)buf;172#endif173		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_GPIO185	static u16 prev_data;186#endif187 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_GPIO199		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#else211		for (i = 0; i < 16; i++) {212			gpiod_set_value(par->gpio.db[i], data & 1);213			data >>= 1;214		}215#endif216 217		/* Pullup /WR */218		gpiod_set_value(par->gpio.wr, 0);219 220#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO221		prev_data = *(u16 *)buf;222#endif223		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);237