File Index
Files and directories
Sign in
FILE

fbtft-io.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/fbtft/fbtft-io.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#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-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=%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 optimization
128 * only one driver can use the optimized version at a time
129 */
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_GPIO
135	static u8 prev_data;
136#endif
137
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_GPIO
149		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#else
161		for (i = 0; i < 8; i++) {
162			gpiod_set_value(par->gpio.db[i], data & 1);
163			data >>= 1;
164		}
165#endif
166
167		/* Pullup /WR */
168		gpiod_set_value(par->gpio.wr, 0);
169
170#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
171		prev_data = *(u8 *)buf;
172#endif
173		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_GPIO
185	static u16 prev_data;
186#endif
187
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_GPIO
199		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#else
211		for (i = 0; i < 16; i++) {
212			gpiod_set_value(par->gpio.db[i], data & 1);
213			data >>= 1;
214		}
215#endif
216
217		/* Pullup /WR */
218		gpiod_set_value(par->gpio.wr, 0);
219
220#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
221		prev_data = *(u16 *)buf;
222#endif
223		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);
~/ Read-only file preview.