1#include <linux/export.h>
2#include <linux/errno.h>
3#include <linux/gpio.h>
4#include <linux/spi/spi.h>
5#include "fbtft.h"
6
7int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
8{
9	struct spi_transfer t = {
10		.tx_buf = buf,
11		.len = len,
12	};
13	struct spi_message m;
14
15	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
16		"%s(len=%d): ", __func__, len);
17
18	if (!par->spi) {
19		dev_err(par->info->device,
20			"%s: par->spi is unexpectedly NULL\n", __func__);
21		return -1;
22	}
23
24	spi_message_init(&m);
25	if (par->txbuf.dma && buf == par->txbuf.buf) {
26		t.tx_dma = par->txbuf.dma;
27		m.is_dma_mapped = 1;
28	}
29	spi_message_add_tail(&t, &m);
30	return spi_sync(par->spi, &m);
31}
32EXPORT_SYMBOL(fbtft_write_spi);
33
34/**
35 * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit
36 * @par: Driver data
37 * @buf: Buffer to write
38 * @len: Length of buffer (must be divisible by 8)
39 *
40 * When 9-bit SPI is not available, this function can be used to emulate that.
41 * par->extra must hold a transformation buffer used for transfer.
42 */
43int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len)
44{
45	u16 *src = buf;
46	u8 *dst = par->extra;
47	size_t size = len / 2;
48	size_t added = 0;
49	int bits, i, j;
50	u64 val, dc, tmp;
51
52	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
53		"%s(len=%d): ", __func__, len);
54
55	if (!par->extra) {
56		dev_err(par->info->device, "%s: error: par->extra is NULL\n",
57			__func__);
58		return -EINVAL;
59	}
60	if ((len % 8) != 0) {
61		dev_err(par->info->device,
62			"error: len=%zu must be divisible by 8\n", len);
63		return -EINVAL;
64	}
65
66	for (i = 0; i < size; i += 8) {
67		tmp = 0;
68		bits = 63;
69		for (j = 0; j < 7; j++) {
70			dc = (*src & 0x0100) ? 1 : 0;
71			val = *src & 0x00FF;
72			tmp |= dc << bits;
73			bits -= 8;
74			tmp |= val << bits--;
75			src++;
76		}
77		tmp |= ((*src & 0x0100) ? 1 : 0);
78		*(u64 *)dst = cpu_to_be64(tmp);
79		dst += 8;
80		*dst++ = (u8)(*src++ & 0x00FF);
81		added++;
82	}
83
84	return spi_write(par->spi, par->extra, size + added);
85}
86EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
87
88int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len)
89{
90	int ret;
91	u8 txbuf[32] = { 0, };
92	struct spi_transfer	t = {
93			.speed_hz = 2000000,
94			.rx_buf		= buf,
95			.len		= len,
96		};
97	struct spi_message	m;
98
99	if (!par->spi) {
100		dev_err(par->info->device,
101			"%s: par->spi is unexpectedly NULL\n", __func__);
102		return -ENODEV;
103	}
104
105	if (par->startbyte) {
106		if (len > 32) {
107			dev_err(par->info->device,
108				"len=%zu can't be larger than 32 when using 'startbyte'\n",
109				len);
110			return -EINVAL;
111		}
112		txbuf[0] = par->startbyte | 0x3;
113		t.tx_buf = txbuf;
114		fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8,
115			txbuf, len, "%s(len=%d) txbuf => ", __func__, len);
116	}
117
118	spi_message_init(&m);
119	spi_message_add_tail(&t, &m);
120	ret = spi_sync(par->spi, &m);
121	fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len,
122		"%s(len=%d) buf <= ", __func__, len);
123
124	return ret;
125}
126EXPORT_SYMBOL(fbtft_read_spi);
127
128/*
129 * Optimized use of gpiolib is twice as fast as no optimization
130 * only one driver can use the optimized version at a time
131 */
132int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
133{
134	u8 data;
135	int i;
136#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
137	static u8 prev_data;
138#endif
139
140	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
141		"%s(len=%d): ", __func__, len);
142
143	while (len--) {
144		data = *(u8 *) buf;
145
146		/* Start writing by pulling down /WR */
147		gpio_set_value(par->gpio.wr, 0);
148
149		/* Set data */
150#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
151		if (data == prev_data) {
152			gpio_set_value(par->gpio.wr, 0); /* used as delay */
153		} else {
154			for (i = 0; i < 8; i++) {
155				if ((data & 1) != (prev_data & 1))
156					gpio_set_value(par->gpio.db[i],
157								data & 1);
158				data >>= 1;
159				prev_data >>= 1;
160			}
161		}
162#else
163		for (i = 0; i < 8; i++) {
164			gpio_set_value(par->gpio.db[i], data & 1);
165			data >>= 1;
166		}
167#endif
168
169		/* Pullup /WR */
170		gpio_set_value(par->gpio.wr, 1);
171
172#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
173		prev_data = *(u8 *) buf;
174#endif
175		buf++;
176	}
177
178	return 0;
179}
180EXPORT_SYMBOL(fbtft_write_gpio8_wr);
181
182int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
183{
184	u16 data;
185	int i;
186#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
187	static u16 prev_data;
188#endif
189
190	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
191		"%s(len=%d): ", __func__, len);
192
193	while (len) {
194		data = *(u16 *) buf;
195
196		/* Start writing by pulling down /WR */
197		gpio_set_value(par->gpio.wr, 0);
198
199		/* Set data */
200#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
201		if (data == prev_data) {
202			gpio_set_value(par->gpio.wr, 0); /* used as delay */
203		} else {
204			for (i = 0; i < 16; i++) {
205				if ((data & 1) != (prev_data & 1))
206					gpio_set_value(par->gpio.db[i],
207								data & 1);
208				data >>= 1;
209				prev_data >>= 1;
210			}
211		}
212#else
213		for (i = 0; i < 16; i++) {
214			gpio_set_value(par->gpio.db[i], data & 1);
215			data >>= 1;
216		}
217#endif
218
219		/* Pullup /WR */
220		gpio_set_value(par->gpio.wr, 1);
221
222#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
223		prev_data = *(u16 *) buf;
224#endif
225		buf += 2;
226		len -= 2;
227	}
228
229	return 0;
230}
231EXPORT_SYMBOL(fbtft_write_gpio16_wr);
232
233int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len)
234{
235	dev_err(par->info->device, "%s: function not implemented\n", __func__);
236	return -1;
237}
238EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);
239