1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/delay.h>
18#include <video/mipi_display.h>
19
20#include "fbtft.h"
21
22#define DRVNAME "fb_ili9341"
23#define WIDTH 240
24#define HEIGHT 320
25#define TXBUFLEN (4 * PAGE_SIZE)
26#define DEFAULT_GAMMA "1F 1A 18 0A 0F 06 45 87 32 0A 07 02 07 05 00\n" \
27 "00 25 27 05 10 09 3A 78 4D 05 18 0D 38 3A 1F"
28
29static int init_display(struct fbtft_par *par)
30{
31 par->fbtftops.reset(par);
32
33
34 write_reg(par, MIPI_DCS_SOFT_RESET);
35 mdelay(5);
36 write_reg(par, MIPI_DCS_SET_DISPLAY_OFF);
37
38 write_reg(par, 0xCF, 0x00, 0x83, 0x30);
39 write_reg(par, 0xED, 0x64, 0x03, 0x12, 0x81);
40 write_reg(par, 0xE8, 0x85, 0x01, 0x79);
41 write_reg(par, 0xCB, 0x39, 0X2C, 0x00, 0x34, 0x02);
42 write_reg(par, 0xF7, 0x20);
43 write_reg(par, 0xEA, 0x00, 0x00);
44
45 write_reg(par, 0xC0, 0x26);
46 write_reg(par, 0xC1, 0x11);
47
48 write_reg(par, 0xC5, 0x35, 0x3E);
49 write_reg(par, 0xC7, 0xBE);
50
51 write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
52
53 write_reg(par, 0xB1, 0x00, 0x1B);
54
55
56 write_reg(par, MIPI_DCS_SET_GAMMA_CURVE, 0x01);
57
58 write_reg(par, 0xB7, 0x07);
59 write_reg(par, 0xB6, 0x0A, 0x82, 0x27, 0x00);
60 write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
61 mdelay(100);
62 write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
63 mdelay(20);
64
65 return 0;
66}
67
68static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
69{
70 write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
71 (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
72
73 write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
74 (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF);
75
76 write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
77}
78
79#define MEM_Y BIT(7)
80#define MEM_X BIT(6)
81#define MEM_V BIT(5)
82#define MEM_L BIT(4)
83#define MEM_H BIT(2)
84#define MEM_BGR (3)
85static int set_var(struct fbtft_par *par)
86{
87 switch (par->info->var.rotate) {
88 case 0:
89 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
90 MEM_X | (par->bgr << MEM_BGR));
91 break;
92 case 270:
93 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
94 MEM_V | MEM_L | (par->bgr << MEM_BGR));
95 break;
96 case 180:
97 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
98 MEM_Y | (par->bgr << MEM_BGR));
99 break;
100 case 90:
101 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
102 MEM_Y | MEM_X | MEM_V | (par->bgr << MEM_BGR));
103 break;
104 }
105
106 return 0;
107}
108
109
110
111
112
113
114#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
115static int set_gamma(struct fbtft_par *par, u32 *curves)
116{
117 int i;
118
119 for (i = 0; i < par->gamma.num_curves; i++)
120 write_reg(par, 0xE0 + i,
121 CURVE(i, 0), CURVE(i, 1), CURVE(i, 2),
122 CURVE(i, 3), CURVE(i, 4), CURVE(i, 5),
123 CURVE(i, 6), CURVE(i, 7), CURVE(i, 8),
124 CURVE(i, 9), CURVE(i, 10), CURVE(i, 11),
125 CURVE(i, 12), CURVE(i, 13), CURVE(i, 14));
126
127 return 0;
128}
129
130#undef CURVE
131
132static struct fbtft_display display = {
133 .regwidth = 8,
134 .width = WIDTH,
135 .height = HEIGHT,
136 .txbuflen = TXBUFLEN,
137 .gamma_num = 2,
138 .gamma_len = 15,
139 .gamma = DEFAULT_GAMMA,
140 .fbtftops = {
141 .init_display = init_display,
142 .set_addr_win = set_addr_win,
143 .set_var = set_var,
144 .set_gamma = set_gamma,
145 },
146};
147
148FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9341", &display);
149
150MODULE_ALIAS("spi:" DRVNAME);
151MODULE_ALIAS("platform:" DRVNAME);
152MODULE_ALIAS("spi:ili9341");
153MODULE_ALIAS("platform:ili9341");
154
155MODULE_DESCRIPTION("FB driver for the ILI9341 LCD display controller");
156MODULE_AUTHOR("Christian Vogelgsang");
157MODULE_LICENSE("GPL");
158