xref: /openbmc/linux/drivers/staging/fbtft/fbtft-io.c (revision ec03c210)
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 
fbtft_write_spi(struct fbtft_par * par,void * buf,size_t len)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=%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 }
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  */
fbtft_write_spi_emulate_9(struct fbtft_par * par,void * buf,size_t len)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=%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 }
83 EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
84 
fbtft_read_spi(struct fbtft_par * par,void * buf,size_t len)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=%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 }
124 EXPORT_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  */
fbtft_write_gpio8_wr(struct fbtft_par * par,void * buf,size_t len)130 int 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 }
178 EXPORT_SYMBOL(fbtft_write_gpio8_wr);
179 
fbtft_write_gpio16_wr(struct fbtft_par * par,void * buf,size_t len)180 int 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 }
229 EXPORT_SYMBOL(fbtft_write_gpio16_wr);
230 
fbtft_write_gpio16_wr_latched(struct fbtft_par * par,void * buf,size_t len)231 int 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 }
236 EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);
237