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);
237