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
8int 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: &m);
26 spi_message_add_tail(t: &t, m: &m);
27 return spi_sync(spi: par->spi, message: &m);
28}
29EXPORT_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 */
40int 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(spi: par->spi, buf: par->extra, len: size + added);
82}
83EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
84
85int 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: &m);
117 spi_message_add_tail(t: &t, m: &m);
118 ret = spi_sync(spi: par->spi, message: &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}
124EXPORT_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 */
130int 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(desc: par->gpio.wr, value: 1);
146
147 /* Set data */
148#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
149 if (data == prev_data) {
150 gpiod_set_value(desc: par->gpio.wr, value: 1); /* used as delay */
151 } else {
152 for (i = 0; i < 8; i++) {
153 if ((data & 1) != (prev_data & 1))
154 gpiod_set_value(desc: par->gpio.db[i],
155 value: 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(desc: par->gpio.wr, value: 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}
178EXPORT_SYMBOL(fbtft_write_gpio8_wr);
179
180int 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(desc: par->gpio.wr, value: 1);
196
197 /* Set data */
198#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
199 if (data == prev_data) {
200 gpiod_set_value(desc: par->gpio.wr, value: 1); /* used as delay */
201 } else {
202 for (i = 0; i < 16; i++) {
203 if ((data & 1) != (prev_data & 1))
204 gpiod_set_value(desc: par->gpio.db[i],
205 value: 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(desc: par->gpio.wr, value: 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}
229EXPORT_SYMBOL(fbtft_write_gpio16_wr);
230
231int 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}
236EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);
237

source code of linux/drivers/staging/fbtft/fbtft-io.c