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