xref: /openbmc/linux/drivers/staging/fbtft/fbtft-io.c (revision 8e694cd2)
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 	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 }
32 EXPORT_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  */
43 int 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 }
86 EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
87 
88 int 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 }
126 EXPORT_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  */
132 int 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 }
180 EXPORT_SYMBOL(fbtft_write_gpio8_wr);
181 
182 int 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 }
231 EXPORT_SYMBOL(fbtft_write_gpio16_wr);
232 
233 int 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 }
238 EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);
239