xref: /openbmc/linux/drivers/staging/fbtft/fbtft-io.c (revision ba61bb17)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/export.h>
3 #include <linux/errno.h>
4 #include <linux/gpio.h>
5 #include <linux/spi/spi.h>
6 #include "fbtft.h"
7 
8 int 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=%d): ", __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 }
29 EXPORT_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  */
40 int 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=%d): ", __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 }
83 EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
84 
85 int 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=%d) txbuf => ", __func__, len);
113 	}
114 
115 	spi_message_init(&m);
116 	spi_message_add_tail(&t, &m);
117 	ret = spi_sync(par->spi, &m);
118 	fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len,
119 		"%s(len=%d) buf <= ", __func__, len);
120 
121 	return ret;
122 }
123 EXPORT_SYMBOL(fbtft_read_spi);
124 
125 /*
126  * Optimized use of gpiolib is twice as fast as no optimization
127  * only one driver can use the optimized version at a time
128  */
129 int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
130 {
131 	u8 data;
132 	int i;
133 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
134 	static u8 prev_data;
135 #endif
136 
137 	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
138 		"%s(len=%d): ", __func__, len);
139 
140 	while (len--) {
141 		data = *(u8 *)buf;
142 
143 		/* Start writing by pulling down /WR */
144 		gpio_set_value(par->gpio.wr, 0);
145 
146 		/* Set data */
147 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
148 		if (data == prev_data) {
149 			gpio_set_value(par->gpio.wr, 0); /* used as delay */
150 		} else {
151 			for (i = 0; i < 8; i++) {
152 				if ((data & 1) != (prev_data & 1))
153 					gpio_set_value(par->gpio.db[i],
154 								data & 1);
155 				data >>= 1;
156 				prev_data >>= 1;
157 			}
158 		}
159 #else
160 		for (i = 0; i < 8; i++) {
161 			gpio_set_value(par->gpio.db[i], data & 1);
162 			data >>= 1;
163 		}
164 #endif
165 
166 		/* Pullup /WR */
167 		gpio_set_value(par->gpio.wr, 1);
168 
169 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
170 		prev_data = *(u8 *)buf;
171 #endif
172 		buf++;
173 	}
174 
175 	return 0;
176 }
177 EXPORT_SYMBOL(fbtft_write_gpio8_wr);
178 
179 int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
180 {
181 	u16 data;
182 	int i;
183 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
184 	static u16 prev_data;
185 #endif
186 
187 	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
188 		"%s(len=%d): ", __func__, len);
189 
190 	while (len) {
191 		data = *(u16 *)buf;
192 
193 		/* Start writing by pulling down /WR */
194 		gpio_set_value(par->gpio.wr, 0);
195 
196 		/* Set data */
197 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
198 		if (data == prev_data) {
199 			gpio_set_value(par->gpio.wr, 0); /* used as delay */
200 		} else {
201 			for (i = 0; i < 16; i++) {
202 				if ((data & 1) != (prev_data & 1))
203 					gpio_set_value(par->gpio.db[i],
204 								data & 1);
205 				data >>= 1;
206 				prev_data >>= 1;
207 			}
208 		}
209 #else
210 		for (i = 0; i < 16; i++) {
211 			gpio_set_value(par->gpio.db[i], data & 1);
212 			data >>= 1;
213 		}
214 #endif
215 
216 		/* Pullup /WR */
217 		gpio_set_value(par->gpio.wr, 1);
218 
219 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
220 		prev_data = *(u16 *)buf;
221 #endif
222 		buf += 2;
223 		len -= 2;
224 	}
225 
226 	return 0;
227 }
228 EXPORT_SYMBOL(fbtft_write_gpio16_wr);
229 
230 int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len)
231 {
232 	dev_err(par->info->device, "%s: function not implemented\n", __func__);
233 	return -1;
234 }
235 EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);
236