1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2017-2018, Bootlin
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/delay.h>
7*4882a593Smuzhiyun #include <linux/device.h>
8*4882a593Smuzhiyun #include <linux/err.h>
9*4882a593Smuzhiyun #include <linux/errno.h>
10*4882a593Smuzhiyun #include <linux/fb.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of_device.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
16*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <drm/drm_mipi_dsi.h>
19*4882a593Smuzhiyun #include <drm/drm_modes.h>
20*4882a593Smuzhiyun #include <drm/drm_panel.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <video/mipi_display.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun enum ili9881c_op {
25*4882a593Smuzhiyun ILI9881C_SWITCH_PAGE,
26*4882a593Smuzhiyun ILI9881C_COMMAND,
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun struct ili9881c_instr {
30*4882a593Smuzhiyun enum ili9881c_op op;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun union arg {
33*4882a593Smuzhiyun struct cmd {
34*4882a593Smuzhiyun u8 cmd;
35*4882a593Smuzhiyun u8 data;
36*4882a593Smuzhiyun } cmd;
37*4882a593Smuzhiyun u8 page;
38*4882a593Smuzhiyun } arg;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun struct ili9881c_desc {
42*4882a593Smuzhiyun const struct ili9881c_instr *init;
43*4882a593Smuzhiyun const size_t init_length;
44*4882a593Smuzhiyun const struct drm_display_mode *mode;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun struct ili9881c {
48*4882a593Smuzhiyun struct drm_panel panel;
49*4882a593Smuzhiyun struct mipi_dsi_device *dsi;
50*4882a593Smuzhiyun const struct ili9881c_desc *desc;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun struct regulator *power;
53*4882a593Smuzhiyun struct gpio_desc *reset;
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #define ILI9881C_SWITCH_PAGE_INSTR(_page) \
57*4882a593Smuzhiyun { \
58*4882a593Smuzhiyun .op = ILI9881C_SWITCH_PAGE, \
59*4882a593Smuzhiyun .arg = { \
60*4882a593Smuzhiyun .page = (_page), \
61*4882a593Smuzhiyun }, \
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun #define ILI9881C_COMMAND_INSTR(_cmd, _data) \
65*4882a593Smuzhiyun { \
66*4882a593Smuzhiyun .op = ILI9881C_COMMAND, \
67*4882a593Smuzhiyun .arg = { \
68*4882a593Smuzhiyun .cmd = { \
69*4882a593Smuzhiyun .cmd = (_cmd), \
70*4882a593Smuzhiyun .data = (_data), \
71*4882a593Smuzhiyun }, \
72*4882a593Smuzhiyun }, \
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun static const struct ili9881c_instr lhr050h41_init[] = {
76*4882a593Smuzhiyun ILI9881C_SWITCH_PAGE_INSTR(3),
77*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x01, 0x00),
78*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x02, 0x00),
79*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x03, 0x73),
80*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x04, 0x03),
81*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x05, 0x00),
82*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x06, 0x06),
83*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x07, 0x06),
84*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x08, 0x00),
85*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x09, 0x18),
86*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0a, 0x04),
87*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0b, 0x00),
88*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0c, 0x02),
89*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0d, 0x03),
90*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0e, 0x00),
91*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0f, 0x25),
92*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x10, 0x25),
93*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x11, 0x00),
94*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x12, 0x00),
95*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x13, 0x00),
96*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x14, 0x00),
97*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x15, 0x00),
98*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x16, 0x0C),
99*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x17, 0x00),
100*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x18, 0x00),
101*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x19, 0x00),
102*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1a, 0x00),
103*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1b, 0x00),
104*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1c, 0x00),
105*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1d, 0x00),
106*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1e, 0xC0),
107*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1f, 0x80),
108*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x20, 0x04),
109*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x21, 0x01),
110*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x22, 0x00),
111*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x23, 0x00),
112*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x24, 0x00),
113*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x25, 0x00),
114*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x26, 0x00),
115*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x27, 0x00),
116*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x28, 0x33),
117*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x29, 0x03),
118*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2a, 0x00),
119*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2b, 0x00),
120*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2c, 0x00),
121*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2d, 0x00),
122*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2e, 0x00),
123*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2f, 0x00),
124*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x30, 0x00),
125*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x31, 0x00),
126*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x32, 0x00),
127*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x33, 0x00),
128*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x34, 0x04),
129*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x35, 0x00),
130*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x36, 0x00),
131*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x37, 0x00),
132*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x38, 0x3C),
133*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x39, 0x00),
134*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3a, 0x00),
135*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3b, 0x00),
136*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3c, 0x00),
137*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3d, 0x00),
138*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3e, 0x00),
139*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3f, 0x00),
140*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x40, 0x00),
141*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x41, 0x00),
142*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x42, 0x00),
143*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x43, 0x00),
144*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x44, 0x00),
145*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x50, 0x01),
146*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x51, 0x23),
147*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x52, 0x45),
148*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x53, 0x67),
149*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x54, 0x89),
150*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x55, 0xab),
151*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x56, 0x01),
152*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x57, 0x23),
153*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x58, 0x45),
154*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x59, 0x67),
155*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5a, 0x89),
156*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5b, 0xab),
157*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5c, 0xcd),
158*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5d, 0xef),
159*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5e, 0x11),
160*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5f, 0x02),
161*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x60, 0x02),
162*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x61, 0x02),
163*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x62, 0x02),
164*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x63, 0x02),
165*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x64, 0x02),
166*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x65, 0x02),
167*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x66, 0x02),
168*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x67, 0x02),
169*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x68, 0x02),
170*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x69, 0x02),
171*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6a, 0x0C),
172*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6b, 0x02),
173*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6c, 0x0F),
174*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6d, 0x0E),
175*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6e, 0x0D),
176*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6f, 0x06),
177*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x70, 0x07),
178*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x71, 0x02),
179*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x72, 0x02),
180*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x73, 0x02),
181*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x74, 0x02),
182*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x75, 0x02),
183*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x76, 0x02),
184*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x77, 0x02),
185*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x78, 0x02),
186*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x79, 0x02),
187*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7a, 0x02),
188*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7b, 0x02),
189*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7c, 0x02),
190*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7d, 0x02),
191*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7e, 0x02),
192*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7f, 0x02),
193*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x80, 0x0C),
194*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x81, 0x02),
195*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x82, 0x0F),
196*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x83, 0x0E),
197*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x84, 0x0D),
198*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x85, 0x06),
199*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x86, 0x07),
200*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x87, 0x02),
201*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x88, 0x02),
202*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x89, 0x02),
203*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x8A, 0x02),
204*4882a593Smuzhiyun ILI9881C_SWITCH_PAGE_INSTR(4),
205*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6C, 0x15),
206*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6E, 0x22),
207*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6F, 0x33),
208*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3A, 0xA4),
209*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x8D, 0x0D),
210*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x87, 0xBA),
211*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x26, 0x76),
212*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
213*4882a593Smuzhiyun ILI9881C_SWITCH_PAGE_INSTR(1),
214*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x22, 0x0A),
215*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x53, 0xDC),
216*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x55, 0xA7),
217*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x50, 0x78),
218*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x51, 0x78),
219*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x31, 0x02),
220*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x60, 0x14),
221*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA0, 0x2A),
222*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA1, 0x39),
223*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA2, 0x46),
224*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA3, 0x0e),
225*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA4, 0x12),
226*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA5, 0x25),
227*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA6, 0x19),
228*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA7, 0x1d),
229*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA8, 0xa6),
230*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA9, 0x1C),
231*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAA, 0x29),
232*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAB, 0x85),
233*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAC, 0x1C),
234*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAD, 0x1B),
235*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAE, 0x51),
236*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAF, 0x22),
237*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB0, 0x2d),
238*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB1, 0x4f),
239*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB2, 0x59),
240*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB3, 0x3F),
241*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC0, 0x2A),
242*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC1, 0x3a),
243*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC2, 0x45),
244*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC3, 0x0e),
245*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC4, 0x11),
246*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC5, 0x24),
247*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC6, 0x1a),
248*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC7, 0x1c),
249*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC8, 0xaa),
250*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC9, 0x1C),
251*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCA, 0x29),
252*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCB, 0x96),
253*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCC, 0x1C),
254*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCD, 0x1B),
255*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCE, 0x51),
256*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCF, 0x22),
257*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD0, 0x2b),
258*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD1, 0x4b),
259*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD2, 0x59),
260*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD3, 0x3F),
261*4882a593Smuzhiyun };
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun static const struct ili9881c_instr k101_im2byl02_init[] = {
264*4882a593Smuzhiyun ILI9881C_SWITCH_PAGE_INSTR(3),
265*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x01, 0x00),
266*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x02, 0x00),
267*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x03, 0x73),
268*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x04, 0x00),
269*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x05, 0x00),
270*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x06, 0x08),
271*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x07, 0x00),
272*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x08, 0x00),
273*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x09, 0x00),
274*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0A, 0x01),
275*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0B, 0x01),
276*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0C, 0x00),
277*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0D, 0x01),
278*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0E, 0x01),
279*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x0F, 0x00),
280*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x10, 0x00),
281*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x11, 0x00),
282*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x12, 0x00),
283*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x13, 0x00),
284*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x14, 0x00),
285*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x15, 0x00),
286*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x16, 0x00),
287*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x17, 0x00),
288*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x18, 0x00),
289*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x19, 0x00),
290*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1A, 0x00),
291*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1B, 0x00),
292*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1C, 0x00),
293*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1D, 0x00),
294*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1E, 0x40),
295*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x1F, 0xC0),
296*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x20, 0x06),
297*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x21, 0x01),
298*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x22, 0x06),
299*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x23, 0x01),
300*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x24, 0x88),
301*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x25, 0x88),
302*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x26, 0x00),
303*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x27, 0x00),
304*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x28, 0x3B),
305*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x29, 0x03),
306*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2A, 0x00),
307*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2B, 0x00),
308*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2C, 0x00),
309*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2D, 0x00),
310*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2E, 0x00),
311*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x2F, 0x00),
312*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x30, 0x00),
313*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x31, 0x00),
314*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x32, 0x00),
315*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x33, 0x00),
316*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x34, 0x00), /* GPWR1/2 non overlap time 2.62us */
317*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x35, 0x00),
318*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x36, 0x00),
319*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x37, 0x00),
320*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x38, 0x00),
321*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x39, 0x00),
322*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3A, 0x00),
323*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3B, 0x00),
324*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3C, 0x00),
325*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3D, 0x00),
326*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3E, 0x00),
327*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3F, 0x00),
328*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x40, 0x00),
329*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x41, 0x00),
330*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x42, 0x00),
331*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x43, 0x00),
332*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x44, 0x00),
333*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x50, 0x01),
334*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x51, 0x23),
335*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x52, 0x45),
336*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x53, 0x67),
337*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x54, 0x89),
338*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x55, 0xAB),
339*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x56, 0x01),
340*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x57, 0x23),
341*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x58, 0x45),
342*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x59, 0x67),
343*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5A, 0x89),
344*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5B, 0xAB),
345*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5C, 0xCD),
346*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5D, 0xEF),
347*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5E, 0x00),
348*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x5F, 0x01),
349*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x60, 0x01),
350*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x61, 0x06),
351*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x62, 0x06),
352*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x63, 0x07),
353*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x64, 0x07),
354*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x65, 0x00),
355*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x66, 0x00),
356*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x67, 0x02),
357*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x68, 0x02),
358*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x69, 0x05),
359*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6A, 0x05),
360*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6B, 0x02),
361*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6C, 0x0D),
362*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6D, 0x0D),
363*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6E, 0x0C),
364*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6F, 0x0C),
365*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x70, 0x0F),
366*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x71, 0x0F),
367*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x72, 0x0E),
368*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x73, 0x0E),
369*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x74, 0x02),
370*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x75, 0x01),
371*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x76, 0x01),
372*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x77, 0x06),
373*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x78, 0x06),
374*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x79, 0x07),
375*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7A, 0x07),
376*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7B, 0x00),
377*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7C, 0x00),
378*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7D, 0x02),
379*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7E, 0x02),
380*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x7F, 0x05),
381*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x80, 0x05),
382*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x81, 0x02),
383*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x82, 0x0D),
384*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x83, 0x0D),
385*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x84, 0x0C),
386*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x85, 0x0C),
387*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x86, 0x0F),
388*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x87, 0x0F),
389*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x88, 0x0E),
390*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x89, 0x0E),
391*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x8A, 0x02),
392*4882a593Smuzhiyun ILI9881C_SWITCH_PAGE_INSTR(4),
393*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3B, 0xC0), /* ILI4003D sel */
394*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6C, 0x15), /* Set VCORE voltage = 1.5V */
395*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6E, 0x2A), /* di_pwr_reg=0 for power mode 2A, VGH clamp 18V */
396*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x6F, 0x33), /* pumping ratio VGH=5x VGL=-3x */
397*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x8D, 0x1B), /* VGL clamp -10V */
398*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x87, 0xBA), /* ESD */
399*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x3A, 0x24), /* POWER SAVING */
400*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x26, 0x76),
401*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
402*4882a593Smuzhiyun ILI9881C_SWITCH_PAGE_INSTR(1),
403*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x22, 0x0A), /* BGR, SS */
404*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x31, 0x00), /* Zigzag type3 inversion */
405*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x40, 0x53), /* ILI4003D sel */
406*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x43, 0x66),
407*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x53, 0x4C),
408*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x50, 0x87),
409*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x51, 0x82),
410*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x60, 0x15),
411*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x61, 0x01),
412*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x62, 0x0C),
413*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0x63, 0x00),
414*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA0, 0x00),
415*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA1, 0x13), /* VP251 */
416*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA2, 0x23), /* VP247 */
417*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA3, 0x14), /* VP243 */
418*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA4, 0x16), /* VP239 */
419*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA5, 0x29), /* VP231 */
420*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA6, 0x1E), /* VP219 */
421*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA7, 0x1D), /* VP203 */
422*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA8, 0x86), /* VP175 */
423*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xA9, 0x1E), /* VP144 */
424*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAA, 0x29), /* VP111 */
425*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAB, 0x74), /* VP80 */
426*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAC, 0x19), /* VP52 */
427*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAD, 0x17), /* VP36 */
428*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAE, 0x4B), /* VP24 */
429*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xAF, 0x20), /* VP16 */
430*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB0, 0x26), /* VP12 */
431*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB1, 0x4C), /* VP8 */
432*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB2, 0x5D), /* VP4 */
433*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xB3, 0x3F), /* VP0 */
434*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC0, 0x00), /* VN255 GAMMA N */
435*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC1, 0x13), /* VN251 */
436*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC2, 0x23), /* VN247 */
437*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC3, 0x14), /* VN243 */
438*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC4, 0x16), /* VN239 */
439*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC5, 0x29), /* VN231 */
440*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC6, 0x1E), /* VN219 */
441*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC7, 0x1D), /* VN203 */
442*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC8, 0x86), /* VN175 */
443*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xC9, 0x1E), /* VN144 */
444*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCA, 0x29), /* VN111 */
445*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCB, 0x74), /* VN80 */
446*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCC, 0x19), /* VN52 */
447*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCD, 0x17), /* VN36 */
448*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCE, 0x4B), /* VN24 */
449*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xCF, 0x20), /* VN16 */
450*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD0, 0x26), /* VN12 */
451*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD1, 0x4C), /* VN8 */
452*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD2, 0x5D), /* VN4 */
453*4882a593Smuzhiyun ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */
454*4882a593Smuzhiyun };
455*4882a593Smuzhiyun
panel_to_ili9881c(struct drm_panel * panel)456*4882a593Smuzhiyun static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun return container_of(panel, struct ili9881c, panel);
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /*
462*4882a593Smuzhiyun * The panel seems to accept some private DCS commands that map
463*4882a593Smuzhiyun * directly to registers.
464*4882a593Smuzhiyun *
465*4882a593Smuzhiyun * It is organised by page, with each page having its own set of
466*4882a593Smuzhiyun * registers, and the first page looks like it's holding the standard
467*4882a593Smuzhiyun * DCS commands.
468*4882a593Smuzhiyun *
469*4882a593Smuzhiyun * So before any attempt at sending a command or data, we have to be
470*4882a593Smuzhiyun * sure if we're in the right page or not.
471*4882a593Smuzhiyun */
ili9881c_switch_page(struct ili9881c * ctx,u8 page)472*4882a593Smuzhiyun static int ili9881c_switch_page(struct ili9881c *ctx, u8 page)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun u8 buf[4] = { 0xff, 0x98, 0x81, page };
475*4882a593Smuzhiyun int ret;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
478*4882a593Smuzhiyun if (ret < 0)
479*4882a593Smuzhiyun return ret;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun return 0;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
ili9881c_send_cmd_data(struct ili9881c * ctx,u8 cmd,u8 data)484*4882a593Smuzhiyun static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun u8 buf[2] = { cmd, data };
487*4882a593Smuzhiyun int ret;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
490*4882a593Smuzhiyun if (ret < 0)
491*4882a593Smuzhiyun return ret;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun return 0;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
ili9881c_prepare(struct drm_panel * panel)496*4882a593Smuzhiyun static int ili9881c_prepare(struct drm_panel *panel)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun struct ili9881c *ctx = panel_to_ili9881c(panel);
499*4882a593Smuzhiyun unsigned int i;
500*4882a593Smuzhiyun int ret;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* Power the panel */
503*4882a593Smuzhiyun ret = regulator_enable(ctx->power);
504*4882a593Smuzhiyun if (ret)
505*4882a593Smuzhiyun return ret;
506*4882a593Smuzhiyun msleep(5);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun /* And reset it */
509*4882a593Smuzhiyun gpiod_set_value(ctx->reset, 1);
510*4882a593Smuzhiyun msleep(20);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun gpiod_set_value(ctx->reset, 0);
513*4882a593Smuzhiyun msleep(20);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun for (i = 0; i < ctx->desc->init_length; i++) {
516*4882a593Smuzhiyun const struct ili9881c_instr *instr = &ctx->desc->init[i];
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (instr->op == ILI9881C_SWITCH_PAGE)
519*4882a593Smuzhiyun ret = ili9881c_switch_page(ctx, instr->arg.page);
520*4882a593Smuzhiyun else if (instr->op == ILI9881C_COMMAND)
521*4882a593Smuzhiyun ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd,
522*4882a593Smuzhiyun instr->arg.cmd.data);
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun if (ret)
525*4882a593Smuzhiyun return ret;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun ret = ili9881c_switch_page(ctx, 0);
529*4882a593Smuzhiyun if (ret)
530*4882a593Smuzhiyun return ret;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
533*4882a593Smuzhiyun if (ret)
534*4882a593Smuzhiyun return ret;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
537*4882a593Smuzhiyun if (ret)
538*4882a593Smuzhiyun return ret;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun return 0;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
ili9881c_enable(struct drm_panel * panel)543*4882a593Smuzhiyun static int ili9881c_enable(struct drm_panel *panel)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun struct ili9881c *ctx = panel_to_ili9881c(panel);
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun msleep(120);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun mipi_dsi_dcs_set_display_on(ctx->dsi);
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun return 0;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
ili9881c_disable(struct drm_panel * panel)554*4882a593Smuzhiyun static int ili9881c_disable(struct drm_panel *panel)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun struct ili9881c *ctx = panel_to_ili9881c(panel);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun return mipi_dsi_dcs_set_display_off(ctx->dsi);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
ili9881c_unprepare(struct drm_panel * panel)561*4882a593Smuzhiyun static int ili9881c_unprepare(struct drm_panel *panel)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun struct ili9881c *ctx = panel_to_ili9881c(panel);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
566*4882a593Smuzhiyun regulator_disable(ctx->power);
567*4882a593Smuzhiyun gpiod_set_value(ctx->reset, 1);
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun return 0;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun static const struct drm_display_mode lhr050h41_default_mode = {
573*4882a593Smuzhiyun .clock = 62000,
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun .hdisplay = 720,
576*4882a593Smuzhiyun .hsync_start = 720 + 10,
577*4882a593Smuzhiyun .hsync_end = 720 + 10 + 20,
578*4882a593Smuzhiyun .htotal = 720 + 10 + 20 + 30,
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun .vdisplay = 1280,
581*4882a593Smuzhiyun .vsync_start = 1280 + 10,
582*4882a593Smuzhiyun .vsync_end = 1280 + 10 + 10,
583*4882a593Smuzhiyun .vtotal = 1280 + 10 + 10 + 20,
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun .width_mm = 62,
586*4882a593Smuzhiyun .height_mm = 110,
587*4882a593Smuzhiyun };
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun static const struct drm_display_mode k101_im2byl02_default_mode = {
590*4882a593Smuzhiyun .clock = 69700,
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun .hdisplay = 800,
593*4882a593Smuzhiyun .hsync_start = 800 + 52,
594*4882a593Smuzhiyun .hsync_end = 800 + 52 + 8,
595*4882a593Smuzhiyun .htotal = 800 + 52 + 8 + 48,
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun .vdisplay = 1280,
598*4882a593Smuzhiyun .vsync_start = 1280 + 16,
599*4882a593Smuzhiyun .vsync_end = 1280 + 16 + 6,
600*4882a593Smuzhiyun .vtotal = 1280 + 16 + 6 + 15,
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun .width_mm = 135,
603*4882a593Smuzhiyun .height_mm = 217,
604*4882a593Smuzhiyun };
605*4882a593Smuzhiyun
ili9881c_get_modes(struct drm_panel * panel,struct drm_connector * connector)606*4882a593Smuzhiyun static int ili9881c_get_modes(struct drm_panel *panel,
607*4882a593Smuzhiyun struct drm_connector *connector)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun struct ili9881c *ctx = panel_to_ili9881c(panel);
610*4882a593Smuzhiyun struct drm_display_mode *mode;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
613*4882a593Smuzhiyun if (!mode) {
614*4882a593Smuzhiyun dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
615*4882a593Smuzhiyun ctx->desc->mode->hdisplay,
616*4882a593Smuzhiyun ctx->desc->mode->vdisplay,
617*4882a593Smuzhiyun drm_mode_vrefresh(ctx->desc->mode));
618*4882a593Smuzhiyun return -ENOMEM;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun drm_mode_set_name(mode);
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
624*4882a593Smuzhiyun drm_mode_probed_add(connector, mode);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun connector->display_info.width_mm = mode->width_mm;
627*4882a593Smuzhiyun connector->display_info.height_mm = mode->height_mm;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun return 1;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun static const struct drm_panel_funcs ili9881c_funcs = {
633*4882a593Smuzhiyun .prepare = ili9881c_prepare,
634*4882a593Smuzhiyun .unprepare = ili9881c_unprepare,
635*4882a593Smuzhiyun .enable = ili9881c_enable,
636*4882a593Smuzhiyun .disable = ili9881c_disable,
637*4882a593Smuzhiyun .get_modes = ili9881c_get_modes,
638*4882a593Smuzhiyun };
639*4882a593Smuzhiyun
ili9881c_dsi_probe(struct mipi_dsi_device * dsi)640*4882a593Smuzhiyun static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun struct ili9881c *ctx;
643*4882a593Smuzhiyun int ret;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
646*4882a593Smuzhiyun if (!ctx)
647*4882a593Smuzhiyun return -ENOMEM;
648*4882a593Smuzhiyun mipi_dsi_set_drvdata(dsi, ctx);
649*4882a593Smuzhiyun ctx->dsi = dsi;
650*4882a593Smuzhiyun ctx->desc = of_device_get_match_data(&dsi->dev);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs,
653*4882a593Smuzhiyun DRM_MODE_CONNECTOR_DSI);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun ctx->power = devm_regulator_get(&dsi->dev, "power");
656*4882a593Smuzhiyun if (IS_ERR(ctx->power)) {
657*4882a593Smuzhiyun dev_err(&dsi->dev, "Couldn't get our power regulator\n");
658*4882a593Smuzhiyun return PTR_ERR(ctx->power);
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
662*4882a593Smuzhiyun if (IS_ERR(ctx->reset)) {
663*4882a593Smuzhiyun dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
664*4882a593Smuzhiyun return PTR_ERR(ctx->reset);
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun ret = drm_panel_of_backlight(&ctx->panel);
668*4882a593Smuzhiyun if (ret)
669*4882a593Smuzhiyun return ret;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun drm_panel_add(&ctx->panel);
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
674*4882a593Smuzhiyun dsi->format = MIPI_DSI_FMT_RGB888;
675*4882a593Smuzhiyun dsi->lanes = 4;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun return mipi_dsi_attach(dsi);
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
ili9881c_dsi_remove(struct mipi_dsi_device * dsi)680*4882a593Smuzhiyun static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun struct ili9881c *ctx = mipi_dsi_get_drvdata(dsi);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun mipi_dsi_detach(dsi);
685*4882a593Smuzhiyun drm_panel_remove(&ctx->panel);
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun return 0;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun static const struct ili9881c_desc lhr050h41_desc = {
691*4882a593Smuzhiyun .init = lhr050h41_init,
692*4882a593Smuzhiyun .init_length = ARRAY_SIZE(lhr050h41_init),
693*4882a593Smuzhiyun .mode = &lhr050h41_default_mode,
694*4882a593Smuzhiyun };
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun static const struct ili9881c_desc k101_im2byl02_desc = {
697*4882a593Smuzhiyun .init = k101_im2byl02_init,
698*4882a593Smuzhiyun .init_length = ARRAY_SIZE(k101_im2byl02_init),
699*4882a593Smuzhiyun .mode = &k101_im2byl02_default_mode,
700*4882a593Smuzhiyun };
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun static const struct of_device_id ili9881c_of_match[] = {
703*4882a593Smuzhiyun { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc },
704*4882a593Smuzhiyun { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc },
705*4882a593Smuzhiyun { }
706*4882a593Smuzhiyun };
707*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, ili9881c_of_match);
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun static struct mipi_dsi_driver ili9881c_dsi_driver = {
710*4882a593Smuzhiyun .probe = ili9881c_dsi_probe,
711*4882a593Smuzhiyun .remove = ili9881c_dsi_remove,
712*4882a593Smuzhiyun .driver = {
713*4882a593Smuzhiyun .name = "ili9881c-dsi",
714*4882a593Smuzhiyun .of_match_table = ili9881c_of_match,
715*4882a593Smuzhiyun },
716*4882a593Smuzhiyun };
717*4882a593Smuzhiyun module_mipi_dsi_driver(ili9881c_dsi_driver);
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
720*4882a593Smuzhiyun MODULE_DESCRIPTION("Ilitek ILI9881C Controller Driver");
721*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
722