]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/fbtft/fbtft_device.c
Staging: fbtft: Switch to the gpio descriptor interface
[linux.git] / drivers / staging / fbtft / fbtft_device.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *
4  * Copyright (C) 2013, Noralf Tronnes
5  */
6
7 #define pr_fmt(fmt) "fbtft_device: " fmt
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/spi/spi.h>
13 #include <video/mipi_display.h>
14
15 #include "fbtft.h"
16
17 #define MAX_GPIOS 32
18
19 static struct spi_device *spi_device;
20 static struct platform_device *p_device;
21
22 static char *name;
23 module_param(name, charp, 0000);
24 MODULE_PARM_DESC(name,
25                  "Devicename (required). name=list => list all supported devices.");
26
27 static unsigned int rotate;
28 module_param(rotate, uint, 0000);
29 MODULE_PARM_DESC(rotate,
30                  "Angle to rotate display counter clockwise: 0, 90, 180, 270");
31
32 static unsigned int busnum;
33 module_param(busnum, uint, 0000);
34 MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
35
36 static unsigned int cs;
37 module_param(cs, uint, 0000);
38 MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
39
40 static unsigned int speed;
41 module_param(speed, uint, 0000);
42 MODULE_PARM_DESC(speed, "SPI speed (override device default)");
43
44 static int mode = -1;
45 module_param(mode, int, 0000);
46 MODULE_PARM_DESC(mode, "SPI mode (override device default)");
47
48 static unsigned int fps;
49 module_param(fps, uint, 0000);
50 MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
51
52 static char *gamma;
53 module_param(gamma, charp, 0000);
54 MODULE_PARM_DESC(gamma,
55                  "String representation of Gamma Curve(s). Driver specific.");
56
57 static int txbuflen;
58 module_param(txbuflen, int, 0000);
59 MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)");
60
61 static int bgr = -1;
62 module_param(bgr, int, 0000);
63 MODULE_PARM_DESC(bgr,
64                  "BGR bit (supported by some drivers).");
65
66 static unsigned int startbyte;
67 module_param(startbyte, uint, 0000);
68 MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays.");
69
70 static bool custom;
71 module_param(custom, bool, 0000);
72 MODULE_PARM_DESC(custom, "Add a custom display device. Use speed= argument to make it a SPI device, else platform_device");
73
74 static unsigned int width;
75 module_param(width, uint, 0000);
76 MODULE_PARM_DESC(width, "Display width, used with the custom argument");
77
78 static unsigned int height;
79 module_param(height, uint, 0000);
80 MODULE_PARM_DESC(height, "Display height, used with the custom argument");
81
82 static unsigned int buswidth = 8;
83 module_param(buswidth, uint, 0000);
84 MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument");
85
86 static s16 init[FBTFT_MAX_INIT_SEQUENCE];
87 static int init_num;
88 module_param_array(init, short, &init_num, 0000);
89 MODULE_PARM_DESC(init, "Init sequence, used with the custom argument");
90
91 static unsigned long debug;
92 module_param(debug, ulong, 0000);
93 MODULE_PARM_DESC(debug,
94                  "level: 0-7 (the remaining 29 bits is for advanced usage)");
95
96 static unsigned int verbose = 3;
97 module_param(verbose, uint, 0000);
98 MODULE_PARM_DESC(verbose,
99                  "0 silent, >1 show devices, >2 show devices before (default=3)");
100
101 struct fbtft_device_display {
102         char *name;
103         struct spi_board_info *spi;
104         struct platform_device *pdev;
105 };
106
107 static void fbtft_device_pdev_release(struct device *dev);
108
109 static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len);
110 static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
111                                               int xs, int ys, int xe, int ye);
112
113 #define ADAFRUIT18_GAMMA \
114                 "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \
115                 "03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"
116
117 #define CBERRY28_GAMMA \
118                 "D0 00 14 15 13 2C 42 43 4E 09 16 14 18 21\n" \
119                 "D0 00 14 15 13 0B 43 55 53 0C 17 14 23 20"
120
121 static const s16 cberry28_init_sequence[] = {
122         /* turn off sleep mode */
123         -1, MIPI_DCS_EXIT_SLEEP_MODE,
124         -2, 120,
125
126         /* set pixel format to RGB-565 */
127         -1, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT,
128
129         -1, 0xB2, 0x0C, 0x0C, 0x00, 0x33, 0x33,
130
131         /*
132          * VGH = 13.26V
133          * VGL = -10.43V
134          */
135         -1, 0xB7, 0x35,
136
137         /*
138          * VDV and VRH register values come from command write
139          * (instead of NVM)
140          */
141         -1, 0xC2, 0x01, 0xFF,
142
143         /*
144          * VAP =  4.7V + (VCOM + VCOM offset + 0.5 * VDV)
145          * VAN = -4.7V + (VCOM + VCOM offset + 0.5 * VDV)
146          */
147         -1, 0xC3, 0x17,
148
149         /* VDV = 0V */
150         -1, 0xC4, 0x20,
151
152         /* VCOM = 0.675V */
153         -1, 0xBB, 0x17,
154
155         /* VCOM offset = 0V */
156         -1, 0xC5, 0x20,
157
158         /*
159          * AVDD = 6.8V
160          * AVCL = -4.8V
161          * VDS = 2.3V
162          */
163         -1, 0xD0, 0xA4, 0xA1,
164
165         -1, MIPI_DCS_SET_DISPLAY_ON,
166
167         -3,
168 };
169
170 static const s16 hy28b_init_sequence[] = {
171         -1, 0x00e7, 0x0010, -1, 0x0000, 0x0001,
172         -1, 0x0001, 0x0100, -1, 0x0002, 0x0700,
173         -1, 0x0003, 0x1030, -1, 0x0004, 0x0000,
174         -1, 0x0008, 0x0207, -1, 0x0009, 0x0000,
175         -1, 0x000a, 0x0000, -1, 0x000c, 0x0001,
176         -1, 0x000d, 0x0000, -1, 0x000f, 0x0000,
177         -1, 0x0010, 0x0000, -1, 0x0011, 0x0007,
178         -1, 0x0012, 0x0000, -1, 0x0013, 0x0000,
179         -2, 50, -1, 0x0010, 0x1590, -1, 0x0011,
180         0x0227, -2, 50, -1, 0x0012, 0x009c, -2, 50,
181         -1, 0x0013, 0x1900, -1, 0x0029, 0x0023,
182         -1, 0x002b, 0x000e, -2, 50,
183         -1, 0x0020, 0x0000, -1, 0x0021, 0x0000,
184         -2, 50, -1, 0x0050, 0x0000,
185         -1, 0x0051, 0x00ef, -1, 0x0052, 0x0000,
186         -1, 0x0053, 0x013f, -1, 0x0060, 0xa700,
187         -1, 0x0061, 0x0001, -1, 0x006a, 0x0000,
188         -1, 0x0080, 0x0000, -1, 0x0081, 0x0000,
189         -1, 0x0082, 0x0000, -1, 0x0083, 0x0000,
190         -1, 0x0084, 0x0000, -1, 0x0085, 0x0000,
191         -1, 0x0090, 0x0010, -1, 0x0092, 0x0000,
192         -1, 0x0093, 0x0003, -1, 0x0095, 0x0110,
193         -1, 0x0097, 0x0000, -1, 0x0098, 0x0000,
194         -1, 0x0007, 0x0133, -1, 0x0020, 0x0000,
195         -1, 0x0021, 0x0000, -2, 100, -3 };
196
197 #define HY28B_GAMMA \
198         "04 1F 4 7 7 0 7 7 6 0\n" \
199         "0F 00 1 7 4 0 0 0 6 7"
200
201 static const s16 pitft_init_sequence[] = {
202         -1, MIPI_DCS_SOFT_RESET,
203         -2, 5,
204         -1, MIPI_DCS_SET_DISPLAY_OFF,
205         -1, 0xEF, 0x03, 0x80, 0x02,
206         -1, 0xCF, 0x00, 0xC1, 0x30,
207         -1, 0xED, 0x64, 0x03, 0x12, 0x81,
208         -1, 0xE8, 0x85, 0x00, 0x78,
209         -1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
210         -1, 0xF7, 0x20,
211         -1, 0xEA, 0x00, 0x00,
212         -1, 0xC0, 0x23,
213         -1, 0xC1, 0x10,
214         -1, 0xC5, 0x3E, 0x28,
215         -1, 0xC7, 0x86,
216         -1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
217         -1, 0xB1, 0x00, 0x18,
218         -1, 0xB6, 0x08, 0x82, 0x27,
219         -1, 0xF2, 0x00,
220         -1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
221         -1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
222                 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
223         -1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
224                 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
225         -1, MIPI_DCS_EXIT_SLEEP_MODE,
226         -2, 100,
227         -1, MIPI_DCS_SET_DISPLAY_ON,
228         -2, 20,
229         -3
230 };
231
232 static const s16 waveshare32b_init_sequence[] = {
233         -1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
234         -1, 0xCF, 0x00, 0xC1, 0x30,
235         -1, 0xE8, 0x85, 0x00, 0x78,
236         -1, 0xEA, 0x00, 0x00,
237         -1, 0xED, 0x64, 0x03, 0x12, 0x81,
238         -1, 0xF7, 0x20,
239         -1, 0xC0, 0x23,
240         -1, 0xC1, 0x10,
241         -1, 0xC5, 0x3E, 0x28,
242         -1, 0xC7, 0x86,
243         -1, MIPI_DCS_SET_ADDRESS_MODE, 0x28,
244         -1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
245         -1, 0xB1, 0x00, 0x18,
246         -1, 0xB6, 0x08, 0x82, 0x27,
247         -1, 0xF2, 0x00,
248         -1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
249         -1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
250                 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
251         -1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
252                 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
253         -1, MIPI_DCS_EXIT_SLEEP_MODE,
254         -2, 120,
255         -1, MIPI_DCS_SET_DISPLAY_ON,
256         -1, MIPI_DCS_WRITE_MEMORY_START,
257         -3
258 };
259
260 #define PIOLED_GAMMA    "0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 " \
261                         "2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 " \
262                         "3 3 3 4 4 4 4 4 4 4 4 4 4 4 4"
263
264 /* Supported displays in alphabetical order */
265 static struct fbtft_device_display displays[] = {
266         {
267                 .name = "adafruit18",
268                 .spi = &(struct spi_board_info) {
269                         .modalias = "fb_st7735r",
270                         .max_speed_hz = 32000000,
271                         .mode = SPI_MODE_0,
272                         .platform_data = &(struct fbtft_platform_data) {
273                                 .display = {
274                                         .buswidth = 8,
275                                         .backlight = 1,
276                                 },
277                                 .gamma = ADAFRUIT18_GAMMA,
278                         }
279                 }
280         }, {
281                 .name = "adafruit18_green",
282                 .spi = &(struct spi_board_info) {
283                         .modalias = "fb_st7735r",
284                         .max_speed_hz = 4000000,
285                         .mode = SPI_MODE_0,
286                         .platform_data = &(struct fbtft_platform_data) {
287                                 .display = {
288                                         .buswidth = 8,
289                                         .backlight = 1,
290                                         .fbtftops.set_addr_win =
291                                             adafruit18_green_tab_set_addr_win,
292                                 },
293                                 .bgr = true,
294                                 .gamma = ADAFRUIT18_GAMMA,
295                         }
296                 }
297         }, {
298                 .name = "adafruit22",
299                 .spi = &(struct spi_board_info) {
300                         .modalias = "fb_hx8340bn",
301                         .max_speed_hz = 32000000,
302                         .mode = SPI_MODE_0,
303                         .platform_data = &(struct fbtft_platform_data) {
304                                 .display = {
305                                         .buswidth = 9,
306                                         .backlight = 1,
307                                 },
308                                 .bgr = true,
309                         }
310                 }
311         }, {
312                 .name = "adafruit22a",
313                 .spi = &(struct spi_board_info) {
314                         .modalias = "fb_ili9340",
315                         .max_speed_hz = 32000000,
316                         .mode = SPI_MODE_0,
317                         .platform_data = &(struct fbtft_platform_data) {
318                                 .display = {
319                                         .buswidth = 8,
320                                         .backlight = 1,
321                                 },
322                                 .bgr = true,
323                         }
324                 }
325         }, {
326                 .name = "adafruit28",
327                 .spi = &(struct spi_board_info) {
328                         .modalias = "fb_ili9341",
329                         .max_speed_hz = 32000000,
330                         .mode = SPI_MODE_0,
331                         .platform_data = &(struct fbtft_platform_data) {
332                                 .display = {
333                                         .buswidth = 8,
334                                         .backlight = 1,
335                                 },
336                                 .bgr = true,
337                         }
338                 }
339         }, {
340                 .name = "adafruit13m",
341                 .spi = &(struct spi_board_info) {
342                         .modalias = "fb_ssd1306",
343                         .max_speed_hz = 16000000,
344                         .mode = SPI_MODE_0,
345                         .platform_data = &(struct fbtft_platform_data) {
346                                 .display = {
347                                         .buswidth = 8,
348                                 },
349                         }
350                 }
351         }, {
352                 .name = "admatec_c-berry28",
353                 .spi = &(struct spi_board_info) {
354                         .modalias = "fb_st7789v",
355                         .max_speed_hz = 48000000,
356                         .mode = SPI_MODE_0,
357                         .platform_data = &(struct fbtft_platform_data) {
358                                 .display = {
359                                         .buswidth = 8,
360                                         .backlight = 1,
361                                         .init_sequence = cberry28_init_sequence,
362                                 },
363                                 .gamma = CBERRY28_GAMMA,
364                         }
365                 }
366         }, {
367                 .name = "agm1264k-fl",
368                 .pdev = &(struct platform_device) {
369                         .name = "fb_agm1264k-fl",
370                         .id = 0,
371                         .dev = {
372                         .release = fbtft_device_pdev_release,
373                         .platform_data = &(struct fbtft_platform_data) {
374                                 .display = {
375                                         .buswidth = 8,
376                                         .backlight = FBTFT_ONBOARD_BACKLIGHT,
377                                 },
378                         },
379                         }
380                 }
381         }, {
382                 .name = "dogs102",
383                 .spi = &(struct spi_board_info) {
384                         .modalias = "fb_uc1701",
385                         .max_speed_hz = 8000000,
386                         .mode = SPI_MODE_0,
387                         .platform_data = &(struct fbtft_platform_data) {
388                                 .display = {
389                                         .buswidth = 8,
390                                 },
391                                 .bgr = true,
392                         }
393                 }
394         }, {
395                 .name = "er_tftm050_2",
396                 .spi = &(struct spi_board_info) {
397                         .modalias = "fb_ra8875",
398                         .max_speed_hz = 5000000,
399                         .mode = SPI_MODE_3,
400                         .platform_data = &(struct fbtft_platform_data) {
401                                 .display = {
402                                         .buswidth = 8,
403                                         .backlight = 1,
404                                         .width = 480,
405                                         .height = 272,
406                                 },
407                                 .bgr = true,
408                         }
409                 }
410         }, {
411                 .name = "er_tftm070_5",
412                 .spi = &(struct spi_board_info) {
413                         .modalias = "fb_ra8875",
414                         .max_speed_hz = 5000000,
415                         .mode = SPI_MODE_3,
416                         .platform_data = &(struct fbtft_platform_data) {
417                                 .display = {
418                                         .buswidth = 8,
419                                         .backlight = 1,
420                                         .width = 800,
421                                         .height = 480,
422                                 },
423                                 .bgr = true,
424                         }
425                 }
426         }, {
427                 .name = "ew24ha0",
428                 .spi = &(struct spi_board_info) {
429                         .modalias = "fb_uc1611",
430                         .max_speed_hz = 32000000,
431                         .mode = SPI_MODE_3,
432                         .platform_data = &(struct fbtft_platform_data) {
433                                 .display = {
434                                         .buswidth = 8,
435                                 },
436                         }
437                 }
438         }, {
439                 .name = "ew24ha0_9bit",
440                 .spi = &(struct spi_board_info) {
441                         .modalias = "fb_uc1611",
442                         .max_speed_hz = 32000000,
443                         .mode = SPI_MODE_3,
444                         .platform_data = &(struct fbtft_platform_data) {
445                                 .display = {
446                                         .buswidth = 9,
447                                 },
448                         }
449                 }
450         }, {
451                 .name = "flexfb",
452                 .spi = &(struct spi_board_info) {
453                         .modalias = "flexfb",
454                         .max_speed_hz = 32000000,
455                         .mode = SPI_MODE_0,
456                 }
457         }, {
458                 .name = "flexpfb",
459                 .pdev = &(struct platform_device) {
460                         .name = "flexpfb",
461                         .id = 0,
462                         .dev = {
463                         .release = fbtft_device_pdev_release,
464                         }
465                 }
466         }, {
467                 .name = "freetronicsoled128",
468                 .spi = &(struct spi_board_info) {
469                         .modalias = "fb_ssd1351",
470                         .max_speed_hz = 20000000,
471                         .mode = SPI_MODE_0,
472                         .platform_data = &(struct fbtft_platform_data) {
473                                 .display = {
474                                         .buswidth = 8,
475                                         .backlight = FBTFT_ONBOARD_BACKLIGHT,
476                                 },
477                                 .bgr = true,
478                         }
479                 }
480         }, {
481                 .name = "hx8353d",
482                 .spi = &(struct spi_board_info) {
483                         .modalias = "fb_hx8353d",
484                         .max_speed_hz = 16000000,
485                         .mode = SPI_MODE_0,
486                         .platform_data = &(struct fbtft_platform_data) {
487                                 .display = {
488                                         .buswidth = 8,
489                                         .backlight = 1,
490                                 },
491                         }
492                 }
493         }, {
494                 .name = "hy28a",
495                 .spi = &(struct spi_board_info) {
496                         .modalias = "fb_ili9320",
497                         .max_speed_hz = 32000000,
498                         .mode = SPI_MODE_3,
499                         .platform_data = &(struct fbtft_platform_data) {
500                                 .display = {
501                                         .buswidth = 8,
502                                         .backlight = 1,
503                                 },
504                                 .startbyte = 0x70,
505                                 .bgr = true,
506                         }
507                 }
508         }, {
509                 .name = "hy28b",
510                 .spi = &(struct spi_board_info) {
511                         .modalias = "fb_ili9325",
512                         .max_speed_hz = 48000000,
513                         .mode = SPI_MODE_3,
514                         .platform_data = &(struct fbtft_platform_data) {
515                                 .display = {
516                                         .buswidth = 8,
517                                         .backlight = 1,
518                                         .init_sequence = hy28b_init_sequence,
519                                 },
520                                 .startbyte = 0x70,
521                                 .bgr = true,
522                                 .fps = 50,
523                                 .gamma = HY28B_GAMMA,
524                         }
525                 }
526         }, {
527                 .name = "ili9481",
528                 .spi = &(struct spi_board_info) {
529                         .modalias = "fb_ili9481",
530                         .max_speed_hz = 32000000,
531                         .mode = SPI_MODE_0,
532                         .platform_data = &(struct fbtft_platform_data) {
533                                 .display = {
534                                         .regwidth = 16,
535                                         .buswidth = 8,
536                                         .backlight = 1,
537                                 },
538                                 .bgr = true,
539                         }
540                 }
541         }, {
542                 .name = "itdb24",
543                 .pdev = &(struct platform_device) {
544                         .name = "fb_s6d1121",
545                         .id = 0,
546                         .dev = {
547                         .release = fbtft_device_pdev_release,
548                         .platform_data = &(struct fbtft_platform_data) {
549                                 .display = {
550                                         .buswidth = 8,
551                                         .backlight = 1,
552                                 },
553                                 .bgr = false,
554                         },
555                         }
556                 }
557         }, {
558                 .name = "itdb28",
559                 .pdev = &(struct platform_device) {
560                         .name = "fb_ili9325",
561                         .id = 0,
562                         .dev = {
563                         .release = fbtft_device_pdev_release,
564                         .platform_data = &(struct fbtft_platform_data) {
565                                 .display = {
566                                         .buswidth = 8,
567                                         .backlight = 1,
568                                 },
569                                 .bgr = true,
570                         },
571                         }
572                 }
573         }, {
574                 .name = "itdb28_spi",
575                 .spi = &(struct spi_board_info) {
576                         .modalias = "fb_ili9325",
577                         .max_speed_hz = 32000000,
578                         .mode = SPI_MODE_0,
579                         .platform_data = &(struct fbtft_platform_data) {
580                                 .display = {
581                                         .buswidth = 8,
582                                         .backlight = 1,
583                                 },
584                                 .bgr = true,
585                         }
586                 }
587         }, {
588                 .name = "mi0283qt-2",
589                 .spi = &(struct spi_board_info) {
590                         .modalias = "fb_hx8347d",
591                         .max_speed_hz = 32000000,
592                         .mode = SPI_MODE_0,
593                         .platform_data = &(struct fbtft_platform_data) {
594                                 .display = {
595                                         .buswidth = 8,
596                                         .backlight = 1,
597                                 },
598                                 .startbyte = 0x70,
599                                 .bgr = true,
600                         }
601                 }
602         }, {
603                 .name = "mi0283qt-9a",
604                 .spi = &(struct spi_board_info) {
605                         .modalias = "fb_ili9341",
606                         .max_speed_hz = 32000000,
607                         .mode = SPI_MODE_0,
608                         .platform_data = &(struct fbtft_platform_data) {
609                                 .display = {
610                                         .buswidth = 9,
611                                         .backlight = 1,
612                                 },
613                                 .bgr = true,
614                         }
615                 }
616         }, {
617                 .name = "mi0283qt-v2",
618                 .spi = &(struct spi_board_info) {
619                         .modalias = "fb_watterott",
620                         .max_speed_hz = 4000000,
621                         .mode = SPI_MODE_3,
622                         .platform_data = &(struct fbtft_platform_data) {
623                         }
624                 }
625         }, {
626                 .name = "nokia3310",
627                 .spi = &(struct spi_board_info) {
628                         .modalias = "fb_pcd8544",
629                         .max_speed_hz = 400000,
630                         .mode = SPI_MODE_0,
631                         .platform_data = &(struct fbtft_platform_data) {
632                                 .display = {
633                                         .buswidth = 8,
634                                 },
635                         }
636                 }
637         }, {
638                 .name = "nokia3310a",
639                 .spi = &(struct spi_board_info) {
640                         .modalias = "fb_tls8204",
641                         .max_speed_hz = 1000000,
642                         .mode = SPI_MODE_0,
643                         .platform_data = &(struct fbtft_platform_data) {
644                                 .display = {
645                                         .buswidth = 8,
646                                 },
647                         }
648                 }
649         }, {
650                 .name = "nokia5110",
651                 .spi = &(struct spi_board_info) {
652                         .modalias = "fb_ili9163",
653                         .max_speed_hz = 12000000,
654                         .mode = SPI_MODE_0,
655                         .platform_data = &(struct fbtft_platform_data) {
656                                 .display = {
657                                         .buswidth = 8,
658                                         .backlight = 1,
659                                 },
660                                 .bgr = true,
661                         }
662                 }
663         }, {
664                 .name = "piscreen",
665                 .spi = &(struct spi_board_info) {
666                         .modalias = "fb_ili9486",
667                         .max_speed_hz = 32000000,
668                         .mode = SPI_MODE_0,
669                         .platform_data = &(struct fbtft_platform_data) {
670                                 .display = {
671                                         .regwidth = 16,
672                                         .buswidth = 8,
673                                         .backlight = 1,
674                                 },
675                                 .bgr = true,
676                         }
677                 }
678         }, {
679                 .name = "pitft",
680                 .spi = &(struct spi_board_info) {
681                         .modalias = "fb_ili9340",
682                         .max_speed_hz = 32000000,
683                         .mode = SPI_MODE_0,
684                         .chip_select = 0,
685                         .platform_data = &(struct fbtft_platform_data) {
686                                 .display = {
687                                         .buswidth = 8,
688                                         .backlight = 1,
689                                         .init_sequence = pitft_init_sequence,
690                                 },
691                                 .bgr = true,
692                         }
693                 }
694         }, {
695                 .name = "pioled",
696                 .spi = &(struct spi_board_info) {
697                         .modalias = "fb_ssd1351",
698                         .max_speed_hz = 20000000,
699                         .mode = SPI_MODE_0,
700                         .platform_data = &(struct fbtft_platform_data) {
701                                 .display = {
702                                         .buswidth = 8,
703                                 },
704                                 .bgr = true,
705                                 .gamma = PIOLED_GAMMA
706                         }
707                 }
708         }, {
709                 .name = "rpi-display",
710                 .spi = &(struct spi_board_info) {
711                         .modalias = "fb_ili9341",
712                         .max_speed_hz = 32000000,
713                         .mode = SPI_MODE_0,
714                         .platform_data = &(struct fbtft_platform_data) {
715                                 .display = {
716                                         .buswidth = 8,
717                                         .backlight = 1,
718                                 },
719                                 .bgr = true,
720                         }
721                 }
722         }, {
723                 .name = "s6d02a1",
724                 .spi = &(struct spi_board_info) {
725                         .modalias = "fb_s6d02a1",
726                         .max_speed_hz = 32000000,
727                         .mode = SPI_MODE_0,
728                         .platform_data = &(struct fbtft_platform_data) {
729                                 .display = {
730                                         .buswidth = 8,
731                                         .backlight = 1,
732                                 },
733                                 .bgr = true,
734                         }
735                 }
736         }, {
737                 .name = "sainsmart18",
738                 .spi = &(struct spi_board_info) {
739                         .modalias = "fb_st7735r",
740                         .max_speed_hz = 32000000,
741                         .mode = SPI_MODE_0,
742                         .platform_data = &(struct fbtft_platform_data) {
743                                 .display = {
744                                         .buswidth = 8,
745                                 },
746                         }
747                 }
748         }, {
749                 .name = "sainsmart32",
750                 .pdev = &(struct platform_device) {
751                         .name = "fb_ssd1289",
752                         .id = 0,
753                         .dev = {
754                         .release = fbtft_device_pdev_release,
755                         .platform_data = &(struct fbtft_platform_data) {
756                                 .display = {
757                                         .buswidth = 16,
758                                         .txbuflen = -2, /* disable buffer */
759                                         .backlight = 1,
760                                         .fbtftops.write = write_gpio16_wr_slow,
761                                 },
762                                 .bgr = true,
763                         },
764                 },
765                 }
766         }, {
767                 .name = "sainsmart32_fast",
768                 .pdev = &(struct platform_device) {
769                         .name = "fb_ssd1289",
770                         .id = 0,
771                         .dev = {
772                         .release = fbtft_device_pdev_release,
773                         .platform_data = &(struct fbtft_platform_data) {
774                                 .display = {
775                                         .buswidth = 16,
776                                         .txbuflen = -2, /* disable buffer */
777                                         .backlight = 1,
778                                 },
779                                 .bgr = true,
780                         },
781                 },
782                 }
783         }, {
784                 .name = "sainsmart32_latched",
785                 .pdev = &(struct platform_device) {
786                         .name = "fb_ssd1289",
787                         .id = 0,
788                         .dev = {
789                         .release = fbtft_device_pdev_release,
790                         .platform_data = &(struct fbtft_platform_data) {
791                                 .display = {
792                                         .buswidth = 16,
793                                         .txbuflen = -2, /* disable buffer */
794                                         .backlight = 1,
795                                         .fbtftops.write =
796                                                 fbtft_write_gpio16_wr_latched,
797                                 },
798                                 .bgr = true,
799                         },
800                 },
801                 }
802         }, {
803                 .name = "sainsmart32_spi",
804                 .spi = &(struct spi_board_info) {
805                         .modalias = "fb_ssd1289",
806                         .max_speed_hz = 16000000,
807                         .mode = SPI_MODE_0,
808                         .platform_data = &(struct fbtft_platform_data) {
809                                 .display = {
810                                         .buswidth = 8,
811                                         .backlight = 1,
812                                 },
813                                 .bgr = true,
814                         }
815                 }
816         }, {
817                 .name = "spidev",
818                 .spi = &(struct spi_board_info) {
819                         .modalias = "spidev",
820                         .max_speed_hz = 500000,
821                         .bus_num = 0,
822                         .chip_select = 0,
823                         .mode = SPI_MODE_0,
824                         .platform_data = &(struct fbtft_platform_data) {
825                         }
826                 }
827         }, {
828                 .name = "ssd1331",
829                 .spi = &(struct spi_board_info) {
830                         .modalias = "fb_ssd1331",
831                         .max_speed_hz = 20000000,
832                         .mode = SPI_MODE_3,
833                         .platform_data = &(struct fbtft_platform_data) {
834                                 .display = {
835                                         .buswidth = 8,
836                                 },
837                         }
838                 }
839         }, {
840                 .name = "tinylcd35",
841                 .spi = &(struct spi_board_info) {
842                         .modalias = "fb_tinylcd",
843                         .max_speed_hz = 32000000,
844                         .mode = SPI_MODE_0,
845                         .platform_data = &(struct fbtft_platform_data) {
846                                 .display = {
847                                         .buswidth = 8,
848                                         .backlight = 1,
849                                 },
850                                 .bgr = true,
851                         }
852                 }
853         }, {
854                 .name = "tm022hdh26",
855                 .spi = &(struct spi_board_info) {
856                         .modalias = "fb_ili9341",
857                         .max_speed_hz = 32000000,
858                         .mode = SPI_MODE_0,
859                         .platform_data = &(struct fbtft_platform_data) {
860                                 .display = {
861                                         .buswidth = 8,
862                                         .backlight = 1,
863                                 },
864                                 .bgr = true,
865                         }
866                 }
867         }, {
868                 .name = "tontec35_9481", /* boards before 02 July 2014 */
869                 .spi = &(struct spi_board_info) {
870                         .modalias = "fb_ili9481",
871                         .max_speed_hz = 128000000,
872                         .mode = SPI_MODE_3,
873                         .platform_data = &(struct fbtft_platform_data) {
874                                 .display = {
875                                         .buswidth = 8,
876                                         .backlight = 1,
877                                 },
878                                 .bgr = true,
879                         }
880                 }
881         }, {
882                 .name = "tontec35_9486", /* boards after 02 July 2014 */
883                 .spi = &(struct spi_board_info) {
884                         .modalias = "fb_ili9486",
885                         .max_speed_hz = 128000000,
886                         .mode = SPI_MODE_3,
887                         .platform_data = &(struct fbtft_platform_data) {
888                                 .display = {
889                                         .buswidth = 8,
890                                         .backlight = 1,
891                                 },
892                                 .bgr = true,
893                         }
894                 }
895         }, {
896                 .name = "upd161704",
897                 .spi = &(struct spi_board_info) {
898                         .modalias = "fb_upd161704",
899                         .max_speed_hz = 32000000,
900                         .mode = SPI_MODE_0,
901                         .platform_data = &(struct fbtft_platform_data) {
902                                 .display = {
903                                         .buswidth = 8,
904                                 },
905                         }
906                 }
907         }, {
908                 .name = "waveshare32b",
909                 .spi = &(struct spi_board_info) {
910                         .modalias = "fb_ili9340",
911                         .max_speed_hz = 48000000,
912                         .mode = SPI_MODE_0,
913                         .platform_data = &(struct fbtft_platform_data) {
914                                 .display = {
915                                         .buswidth = 8,
916                                         .backlight = 1,
917                                         .init_sequence =
918                                                 waveshare32b_init_sequence,
919                                 },
920                                 .bgr = true,
921                         }
922                 }
923         }, {
924                 .name = "waveshare22",
925                 .spi = &(struct spi_board_info) {
926                         .modalias = "fb_bd663474",
927                         .max_speed_hz = 32000000,
928                         .mode = SPI_MODE_3,
929                         .platform_data = &(struct fbtft_platform_data) {
930                                 .display = {
931                                         .buswidth = 8,
932                                 },
933                         }
934                 }
935         }, {
936                 /* This should be the last item.
937                  * Used with the custom argument
938                  */
939                 .name = "",
940                 .spi = &(struct spi_board_info) {
941                         .modalias = "",
942                         .max_speed_hz = 0,
943                         .mode = SPI_MODE_0,
944                         .platform_data = &(struct fbtft_platform_data) {
945                         }
946                 },
947                 .pdev = &(struct platform_device) {
948                         .name = "",
949                         .id = 0,
950                         .dev = {
951                                 .release = fbtft_device_pdev_release,
952                                 .platform_data = &(struct fbtft_platform_data) {
953                                 },
954                         },
955                 },
956         }
957 };
958
959 static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
960 {
961         u16 data;
962         int i;
963 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
964         static u16 prev_data;
965 #endif
966
967         fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
968                           "%s(len=%d): ", __func__, len);
969
970         while (len) {
971                 data = *(u16 *)buf;
972
973                 /* Start writing by pulling down /WR */
974                 gpiod_set_value(par->gpio.wr, 0);
975
976                 /* Set data */
977 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
978                 if (data == prev_data) {
979                         gpiod_set_value(par->gpio.wr, 0); /* used as delay */
980                 } else {
981                         for (i = 0; i < 16; i++) {
982                                 if ((data & 1) != (prev_data & 1))
983                                         gpiod_set_value(par->gpio.db[i],
984                                                         data & 1);
985                                 data >>= 1;
986                                 prev_data >>= 1;
987                         }
988                 }
989 #else
990                 for (i = 0; i < 16; i++) {
991                         gpiod_set_value(par->gpio.db[i], data & 1);
992                         data >>= 1;
993                 }
994 #endif
995
996                 /* Pullup /WR */
997                 gpiod_set_value(par->gpio.wr, 1);
998
999 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
1000                 prev_data = *(u16 *)buf;
1001 #endif
1002                 buf += 2;
1003                 len -= 2;
1004         }
1005
1006         return 0;
1007 }
1008
1009 static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
1010                                               int xs, int ys, int xe, int ye)
1011 {
1012         write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2);
1013         write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1);
1014         write_reg(par, 0x2C);
1015 }
1016
1017 static void fbtft_device_pdev_release(struct device *dev)
1018 {
1019 /* Needed to silence this message:
1020  * Device 'xxx' does not have a release() function,
1021  * it is broken and must be fixed
1022  */
1023 }
1024
1025 static int spi_device_found(struct device *dev, void *data)
1026 {
1027         struct spi_device *spi = to_spi_device(dev);
1028
1029         dev_info(dev, "%s %s %dkHz %d bits mode=0x%02X\n", spi->modalias,
1030                  dev_name(dev), spi->max_speed_hz / 1000, spi->bits_per_word,
1031                  spi->mode);
1032
1033         return 0;
1034 }
1035
1036 static void pr_spi_devices(void)
1037 {
1038         pr_debug("SPI devices registered:\n");
1039         bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found);
1040 }
1041
1042 static int p_device_found(struct device *dev, void *data)
1043 {
1044         struct platform_device
1045         *pdev = to_platform_device(dev);
1046
1047         if (strstr(pdev->name, "fb"))
1048                 dev_info(dev, "%s id=%d pdata? %s\n", pdev->name, pdev->id,
1049                          pdev->dev.platform_data ? "yes" : "no");
1050
1051         return 0;
1052 }
1053
1054 static void pr_p_devices(void)
1055 {
1056         pr_debug("'fb' Platform devices registered:\n");
1057         bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found);
1058 }
1059
1060 #ifdef MODULE
1061 static void fbtft_device_spi_delete(struct spi_master *master, unsigned int cs)
1062 {
1063         struct device *dev;
1064         char str[32];
1065
1066         snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
1067
1068         dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
1069         if (dev) {
1070                 if (verbose)
1071                         dev_info(dev, "Deleting %s\n", str);
1072                 device_del(dev);
1073         }
1074 }
1075
1076 static int fbtft_device_spi_device_register(struct spi_board_info *spi)
1077 {
1078         struct spi_master *master;
1079
1080         master = spi_busnum_to_master(spi->bus_num);
1081         if (!master) {
1082                 pr_err("spi_busnum_to_master(%d) returned NULL\n",
1083                        spi->bus_num);
1084                 return -EINVAL;
1085         }
1086         /* make sure it's available */
1087         fbtft_device_spi_delete(master, spi->chip_select);
1088         spi_device = spi_new_device(master, spi);
1089         put_device(&master->dev);
1090         if (!spi_device) {
1091                 dev_err(&master->dev, "spi_new_device() returned NULL\n");
1092                 return -EPERM;
1093         }
1094         return 0;
1095 }
1096 #else
1097 static int fbtft_device_spi_device_register(struct spi_board_info *spi)
1098 {
1099         return spi_register_board_info(spi, 1);
1100 }
1101 #endif
1102
1103 static int __init fbtft_device_init(void)
1104 {
1105         struct spi_board_info *spi = NULL;
1106         struct fbtft_platform_data *pdata;
1107         bool found = false;
1108         int i = 0;
1109         int ret = 0;
1110
1111         if (!name) {
1112 #ifdef MODULE
1113                 pr_err("missing module parameter: 'name'\n");
1114                 return -EINVAL;
1115 #else
1116                 return 0;
1117 #endif
1118         }
1119
1120         if (init_num > FBTFT_MAX_INIT_SEQUENCE) {
1121                 pr_err("init parameter: exceeded max array size: %d\n",
1122                        FBTFT_MAX_INIT_SEQUENCE);
1123                 return -EINVAL;
1124         }
1125
1126         if (verbose > 2) {
1127                 pr_spi_devices(); /* print list of registered SPI devices */
1128                 pr_p_devices(); /* print list of 'fb' platform devices */
1129         }
1130
1131         pr_debug("name='%s', busnum=%d, cs=%d\n", name, busnum, cs);
1132
1133         if (rotate > 0 && rotate < 4) {
1134                 rotate = (4 - rotate) * 90;
1135                 pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n",
1136                         rotate);
1137         }
1138         if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) {
1139                 pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n",
1140                         rotate);
1141                 rotate = 0;
1142         }
1143
1144         /* name=list lists all supported displays */
1145         if (strcmp(name, "list") == 0) {
1146                 pr_info("Supported displays:\n");
1147
1148                 for (i = 0; i < ARRAY_SIZE(displays); i++)
1149                         pr_info("%s\n", displays[i].name);
1150                 return -ECANCELED;
1151         }
1152
1153         if (custom) {
1154                 i = ARRAY_SIZE(displays) - 1;
1155                 displays[i].name = name;
1156                 if (speed == 0) {
1157                         displays[i].pdev->name = name;
1158                         displays[i].spi = NULL;
1159                 } else {
1160                         size_t len;
1161
1162                         len = strlcpy(displays[i].spi->modalias, name,
1163                                       SPI_NAME_SIZE);
1164                         if (len >= SPI_NAME_SIZE)
1165                                 pr_warn("modalias (name) truncated to: %s\n",
1166                                         displays[i].spi->modalias);
1167                         displays[i].pdev = NULL;
1168                 }
1169         }
1170
1171         for (i = 0; i < ARRAY_SIZE(displays); i++) {
1172                 if (strncmp(name, displays[i].name, SPI_NAME_SIZE) == 0) {
1173                         if (displays[i].spi) {
1174                                 spi = displays[i].spi;
1175                                 spi->chip_select = cs;
1176                                 spi->bus_num = busnum;
1177                                 if (speed)
1178                                         spi->max_speed_hz = speed;
1179                                 if (mode != -1)
1180                                         spi->mode = mode;
1181                                 pdata = (void *)spi->platform_data;
1182                         } else if (displays[i].pdev) {
1183                                 p_device = displays[i].pdev;
1184                                 pdata = p_device->dev.platform_data;
1185                         } else {
1186                                 pr_err("broken displays array\n");
1187                                 return -EINVAL;
1188                         }
1189
1190                         pdata->rotate = rotate;
1191                         if (bgr == 0)
1192                                 pdata->bgr = false;
1193                         else if (bgr == 1)
1194                                 pdata->bgr = true;
1195                         if (startbyte)
1196                                 pdata->startbyte = startbyte;
1197                         if (gamma)
1198                                 pdata->gamma = gamma;
1199                         pdata->display.debug = debug;
1200                         if (fps)
1201                                 pdata->fps = fps;
1202                         if (txbuflen)
1203                                 pdata->txbuflen = txbuflen;
1204                         if (init_num)
1205                                 pdata->display.init_sequence = init;
1206                         if (custom) {
1207                                 pdata->display.width = width;
1208                                 pdata->display.height = height;
1209                                 pdata->display.buswidth = buswidth;
1210                                 pdata->display.backlight = 1;
1211                         }
1212
1213                         if (displays[i].spi) {
1214                                 ret = fbtft_device_spi_device_register(spi);
1215                                 if (ret) {
1216                                         pr_err("failed to register SPI device\n");
1217                                         return ret;
1218                                 }
1219                         } else {
1220                                 ret = platform_device_register(p_device);
1221                                 if (ret < 0) {
1222                                         pr_err("platform_device_register() returned %d\n",
1223                                                ret);
1224                                         return ret;
1225                                 }
1226                         }
1227                         found = true;
1228                         break;
1229                 }
1230         }
1231
1232         if (!found) {
1233                 pr_err("display not supported: '%s'\n", name);
1234                 return -EINVAL;
1235         }
1236
1237         if (spi_device && (verbose > 1))
1238                 pr_spi_devices();
1239         if (p_device && (verbose > 1))
1240                 pr_p_devices();
1241
1242         return 0;
1243 }
1244
1245 static void __exit fbtft_device_exit(void)
1246 {
1247         if (spi_device) {
1248                 device_del(&spi_device->dev);
1249                 kfree(spi_device);
1250         }
1251
1252         if (p_device)
1253                 platform_device_unregister(p_device);
1254 }
1255
1256 arch_initcall(fbtft_device_init);
1257 module_exit(fbtft_device_exit);
1258
1259 MODULE_DESCRIPTION("Add a FBTFT device.");
1260 MODULE_AUTHOR("Noralf Tronnes");
1261 MODULE_LICENSE("GPL");