]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/fbtft/fbtft-io.c
Merge tag 'gcc-plugins-v4.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.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         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                 *(u64 *)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);