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