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