1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Novatek NT35510 panel driver |
4 | * Copyright (C) 2020 Linus Walleij <linus.walleij@linaro.org> |
5 | * Based on code by Robert Teather (C) 2012 Samsung |
6 | * |
7 | * This display driver (and I refer to the physical component NT35510, |
8 | * not this Linux kernel software driver) can handle: |
9 | * 480x864, 480x854, 480x800, 480x720 and 480x640 pixel displays. |
10 | * It has 480x840x24bit SRAM embedded for storing a frame. |
11 | * When powered on the display is by default in 480x800 mode. |
12 | * |
13 | * The actual panels using this component have different names, but |
14 | * the code needed to set up and configure the panel will be similar, |
15 | * so they should all use the NT35510 driver with appropriate configuration |
16 | * per-panel, e.g. for physical size. |
17 | * |
18 | * This driver is for the DSI interface to panels using the NT35510. |
19 | * |
20 | * The NT35510 can also use an RGB (DPI) interface combined with an |
21 | * I2C or SPI interface for setting up the NT35510. If this is needed |
22 | * this panel driver should be refactored to also support that use |
23 | * case. |
24 | */ |
25 | #include <linux/backlight.h> |
26 | #include <linux/bitops.h> |
27 | #include <linux/gpio/consumer.h> |
28 | #include <linux/module.h> |
29 | #include <linux/of.h> |
30 | #include <linux/regmap.h> |
31 | #include <linux/regulator/consumer.h> |
32 | |
33 | #include <video/mipi_display.h> |
34 | |
35 | #include <drm/drm_mipi_dsi.h> |
36 | #include <drm/drm_modes.h> |
37 | #include <drm/drm_panel.h> |
38 | |
39 | #define NT35510_CMD_CORRECT_GAMMA BIT(0) |
40 | #define NT35510_CMD_CONTROL_DISPLAY BIT(1) |
41 | |
42 | #define MCS_CMD_MAUCCTR 0xF0 /* Manufacturer command enable */ |
43 | #define MCS_CMD_READ_ID1 0xDA |
44 | #define MCS_CMD_READ_ID2 0xDB |
45 | #define MCS_CMD_READ_ID3 0xDC |
46 | #define MCS_CMD_MTP_READ_SETTING 0xF8 /* Uncertain about name */ |
47 | #define MCS_CMD_MTP_READ_PARAM 0xFF /* Uncertain about name */ |
48 | |
49 | /* |
50 | * These manufacturer commands are available after we enable manufacturer |
51 | * command set (MCS) for page 0. |
52 | */ |
53 | #define NT35510_P0_DOPCTR 0xB1 |
54 | #define NT35510_P0_SDHDTCTR 0xB6 |
55 | #define NT35510_P0_GSEQCTR 0xB7 |
56 | #define NT35510_P0_SDEQCTR 0xB8 |
57 | #define NT35510_P0_SDVPCTR 0xBA |
58 | #define NT35510_P0_DPFRCTR1 0xBD |
59 | #define NT35510_P0_DPFRCTR2 0xBE |
60 | #define NT35510_P0_DPFRCTR3 0xBF |
61 | #define NT35510_P0_DPMCTR12 0xCC |
62 | |
63 | #define NT35510_P0_DOPCTR_LEN 2 |
64 | #define NT35510_P0_GSEQCTR_LEN 2 |
65 | #define NT35510_P0_SDEQCTR_LEN 4 |
66 | #define NT35510_P0_SDVPCTR_LEN 1 |
67 | #define NT35510_P0_DPFRCTR1_LEN 5 |
68 | #define NT35510_P0_DPFRCTR2_LEN 5 |
69 | #define NT35510_P0_DPFRCTR3_LEN 5 |
70 | #define NT35510_P0_DPMCTR12_LEN 3 |
71 | |
72 | #define NT35510_DOPCTR_0_RAMKP BIT(7) /* Contents kept in sleep */ |
73 | #define NT35510_DOPCTR_0_DSITE BIT(6) /* Enable TE signal */ |
74 | #define NT35510_DOPCTR_0_DSIG BIT(5) /* Enable generic read/write */ |
75 | #define NT35510_DOPCTR_0_DSIM BIT(4) /* Enable video mode on DSI */ |
76 | #define NT35510_DOPCTR_0_EOTP BIT(3) /* Support EoTP */ |
77 | #define NT35510_DOPCTR_0_N565 BIT(2) /* RGB or BGR pixel format */ |
78 | #define NT35510_DOPCTR_1_TW_PWR_SEL BIT(4) /* TE power selector */ |
79 | #define NT35510_DOPCTR_1_CRGB BIT(3) /* RGB or BGR byte order */ |
80 | #define NT35510_DOPCTR_1_CTB BIT(2) /* Vertical scanning direction */ |
81 | #define NT35510_DOPCTR_1_CRL BIT(1) /* Source driver data shift */ |
82 | #define NT35510_P0_SDVPCTR_PRG BIT(2) /* 0 = normal operation, 1 = VGLO */ |
83 | #define NT35510_P0_SDVPCTR_AVDD 0 /* source driver output = AVDD */ |
84 | #define NT35510_P0_SDVPCTR_OFFCOL 1 /* source driver output = off color */ |
85 | #define NT35510_P0_SDVPCTR_AVSS 2 /* source driver output = AVSS */ |
86 | #define NT35510_P0_SDVPCTR_HI_Z 3 /* source driver output = High impedance */ |
87 | |
88 | /* |
89 | * These manufacturer commands are available after we enable manufacturer |
90 | * command set (MCS) for page 1. |
91 | */ |
92 | #define NT35510_P1_SETAVDD 0xB0 |
93 | #define NT35510_P1_SETAVEE 0xB1 |
94 | #define NT35510_P1_SETVCL 0xB2 |
95 | #define NT35510_P1_SETVGH 0xB3 |
96 | #define NT35510_P1_SETVRGH 0xB4 |
97 | #define NT35510_P1_SETVGL 0xB5 |
98 | #define NT35510_P1_BT1CTR 0xB6 |
99 | #define NT35510_P1_BT2CTR 0xB7 |
100 | #define NT35510_P1_BT3CTR 0xB8 |
101 | #define NT35510_P1_BT4CTR 0xB9 /* VGH boosting times/freq */ |
102 | #define NT35510_P1_BT5CTR 0xBA |
103 | #define NT35510_P1_PFMCTR 0xBB |
104 | #define NT35510_P1_SETVGP 0xBC |
105 | #define NT35510_P1_SETVGN 0xBD |
106 | #define NT35510_P1_SETVCMOFF 0xBE |
107 | #define NT35510_P1_VGHCTR 0xBF /* VGH output ctrl */ |
108 | #define NT35510_P1_SET_GAMMA_RED_POS 0xD1 |
109 | #define NT35510_P1_SET_GAMMA_GREEN_POS 0xD2 |
110 | #define NT35510_P1_SET_GAMMA_BLUE_POS 0xD3 |
111 | #define NT35510_P1_SET_GAMMA_RED_NEG 0xD4 |
112 | #define NT35510_P1_SET_GAMMA_GREEN_NEG 0xD5 |
113 | #define NT35510_P1_SET_GAMMA_BLUE_NEG 0xD6 |
114 | |
115 | /* AVDD and AVEE setting 3 bytes */ |
116 | #define NT35510_P1_AVDD_LEN 3 |
117 | #define NT35510_P1_AVEE_LEN 3 |
118 | #define NT35510_P1_VCL_LEN 3 |
119 | #define NT35510_P1_VGH_LEN 3 |
120 | #define NT35510_P1_VGL_LEN 3 |
121 | #define NT35510_P1_VGP_LEN 3 |
122 | #define NT35510_P1_VGN_LEN 3 |
123 | #define NT35510_P1_VCMOFF_LEN 2 |
124 | /* BT1CTR thru BT5CTR setting 3 bytes */ |
125 | #define NT35510_P1_BT1CTR_LEN 3 |
126 | #define NT35510_P1_BT2CTR_LEN 3 |
127 | #define NT35510_P1_BT3CTR_LEN 3 |
128 | #define NT35510_P1_BT4CTR_LEN 3 |
129 | #define NT35510_P1_BT5CTR_LEN 3 |
130 | /* 52 gamma parameters times two per color: positive and negative */ |
131 | #define NT35510_P1_GAMMA_LEN 52 |
132 | |
133 | #define NT35510_WRCTRLD_BCTRL BIT(5) |
134 | #define NT35510_WRCTRLD_A BIT(4) |
135 | #define NT35510_WRCTRLD_DD BIT(3) |
136 | #define NT35510_WRCTRLD_BL BIT(2) |
137 | #define NT35510_WRCTRLD_DB BIT(1) |
138 | #define NT35510_WRCTRLD_G BIT(0) |
139 | |
140 | #define NT35510_WRCABC_OFF 0 |
141 | #define NT35510_WRCABC_UI_MODE 1 |
142 | #define NT35510_WRCABC_STILL_MODE 2 |
143 | #define NT35510_WRCABC_MOVING_MODE 3 |
144 | |
145 | /** |
146 | * struct nt35510_config - the display-specific NT35510 configuration |
147 | * |
148 | * Some of the settings provide an array of bytes, A, B C which mean: |
149 | * A = normal / idle off mode |
150 | * B = idle on mode |
151 | * C = partial / idle off mode |
152 | * |
153 | * Gamma correction arrays are 10bit numbers, two consecutive bytes |
154 | * makes out one point on the gamma correction curve. The points are |
155 | * not linearly placed along the X axis, we get points 0, 1, 3, 5 |
156 | * 7, 11, 15, 23, 31, 47, 63, 95, 127, 128, 160, 192, 208, 224, 232, |
157 | * 240, 244, 248, 250, 252, 254, 255. The voltages tuples form |
158 | * V0, V1, V3 ... V255, with 0x0000 being the lowest voltage and |
159 | * 0x03FF being the highest voltage. |
160 | * |
161 | * Each value must be strictly higher than the previous value forming |
162 | * a rising curve like this: |
163 | * |
164 | * ^ |
165 | * | V255 |
166 | * | V254 |
167 | * | .... |
168 | * | V5 |
169 | * | V3 |
170 | * | V1 |
171 | * | V0 |
172 | * +-------------------------------------------> |
173 | * |
174 | * The details about all settings can be found in the NT35510 Application |
175 | * Note. |
176 | */ |
177 | struct nt35510_config { |
178 | /** |
179 | * @width_mm: physical panel width [mm] |
180 | */ |
181 | u32 width_mm; |
182 | /** |
183 | * @height_mm: physical panel height [mm] |
184 | */ |
185 | u32 height_mm; |
186 | /** |
187 | * @mode: the display mode. This is only relevant outside the panel |
188 | * in video mode: in command mode this is configuring the internal |
189 | * timing in the display controller. |
190 | */ |
191 | const struct drm_display_mode mode; |
192 | /** |
193 | * @mode_flags: DSI operation mode related flags |
194 | */ |
195 | unsigned long mode_flags; |
196 | /** |
197 | * @cmds: enable DSI commands |
198 | */ |
199 | u32 cmds; |
200 | /** |
201 | * @avdd: setting for AVDD ranging from 0x00 = 6.5V to 0x14 = 4.5V |
202 | * in 0.1V steps the default is 0x05 which means 6.0V |
203 | */ |
204 | u8 avdd[NT35510_P1_AVDD_LEN]; |
205 | /** |
206 | * @bt1ctr: setting for boost power control for the AVDD step-up |
207 | * circuit (1) |
208 | * bits 0..2 in the lower nibble controls PCK, the booster clock |
209 | * frequency for the step-up circuit: |
210 | * 0 = Hsync/32 |
211 | * 1 = Hsync/16 |
212 | * 2 = Hsync/8 |
213 | * 3 = Hsync/4 |
214 | * 4 = Hsync/2 |
215 | * 5 = Hsync |
216 | * 6 = Hsync x 2 |
217 | * 7 = Hsync x 4 |
218 | * bits 4..6 in the upper nibble controls BTP, the boosting |
219 | * amplification for the step-up circuit: |
220 | * 0 = Disable |
221 | * 1 = 1.5 x VDDB |
222 | * 2 = 1.66 x VDDB |
223 | * 3 = 2 x VDDB |
224 | * 4 = 2.5 x VDDB |
225 | * 5 = 3 x VDDB |
226 | * The defaults are 4 and 4 yielding 0x44 |
227 | */ |
228 | u8 bt1ctr[NT35510_P1_BT1CTR_LEN]; |
229 | /** |
230 | * @avee: setting for AVEE ranging from 0x00 = -6.5V to 0x14 = -4.5V |
231 | * in 0.1V steps the default is 0x05 which means -6.0V |
232 | */ |
233 | u8 avee[NT35510_P1_AVEE_LEN]; |
234 | /** |
235 | * @bt2ctr: setting for boost power control for the AVEE step-up |
236 | * circuit (2) |
237 | * bits 0..2 in the lower nibble controls NCK, the booster clock |
238 | * frequency, the values are the same as for PCK in @bt1ctr. |
239 | * bits 4..5 in the upper nibble controls BTN, the boosting |
240 | * amplification for the step-up circuit. |
241 | * 0 = Disable |
242 | * 1 = -1.5 x VDDB |
243 | * 2 = -2 x VDDB |
244 | * 3 = -2.5 x VDDB |
245 | * 4 = -3 x VDDB |
246 | * The defaults are 4 and 3 yielding 0x34 |
247 | */ |
248 | u8 bt2ctr[NT35510_P1_BT2CTR_LEN]; |
249 | /** |
250 | * @vcl: setting for VCL ranging from 0x00 = -2.5V to 0x11 = -4.0V |
251 | * in 1V steps, the default is 0x00 which means -2.5V |
252 | */ |
253 | u8 vcl[NT35510_P1_VCL_LEN]; |
254 | /** |
255 | * @bt3ctr: setting for boost power control for the VCL step-up |
256 | * circuit (3) |
257 | * bits 0..2 in the lower nibble controls CLCK, the booster clock |
258 | * frequency, the values are the same as for PCK in @bt1ctr. |
259 | * bits 4..5 in the upper nibble controls BTCL, the boosting |
260 | * amplification for the step-up circuit. |
261 | * 0 = Disable |
262 | * 1 = -0.5 x VDDB |
263 | * 2 = -1 x VDDB |
264 | * 3 = -2 x VDDB |
265 | * The defaults are 4 and 2 yielding 0x24 |
266 | */ |
267 | u8 bt3ctr[NT35510_P1_BT3CTR_LEN]; |
268 | /** |
269 | * @vgh: setting for VGH ranging from 0x00 = 7.0V to 0x0B = 18.0V |
270 | * in 1V steps, the default is 0x08 which means 15V |
271 | */ |
272 | u8 vgh[NT35510_P1_VGH_LEN]; |
273 | /** |
274 | * @bt4ctr: setting for boost power control for the VGH step-up |
275 | * circuit (4) |
276 | * bits 0..2 in the lower nibble controls HCK, the booster clock |
277 | * frequency, the values are the same as for PCK in @bt1ctr. |
278 | * bits 4..5 in the upper nibble controls BTH, the boosting |
279 | * amplification for the step-up circuit. |
280 | * 0 = AVDD + VDDB |
281 | * 1 = AVDD - AVEE |
282 | * 2 = AVDD - AVEE + VDDB |
283 | * 3 = AVDD x 2 - AVEE |
284 | * The defaults are 4 and 3 yielding 0x34 |
285 | */ |
286 | u8 bt4ctr[NT35510_P1_BT4CTR_LEN]; |
287 | /** |
288 | * @vgl: setting for VGL ranging from 0x00 = -2V to 0x0f = -15V in |
289 | * 1V steps, the default is 0x08 which means -10V |
290 | */ |
291 | u8 vgl[NT35510_P1_VGL_LEN]; |
292 | /** |
293 | * @bt5ctr: setting for boost power control for the VGL step-up |
294 | * circuit (5) |
295 | * bits 0..2 in the lower nibble controls LCK, the booster clock |
296 | * frequency, the values are the same as for PCK in @bt1ctr. |
297 | * bits 4..5 in the upper nibble controls BTL, the boosting |
298 | * amplification for the step-up circuit. |
299 | * 0 = AVEE + VCL |
300 | * 1 = AVEE - AVDD |
301 | * 2 = AVEE + VCL - AVDD |
302 | * 3 = AVEE x 2 - AVDD |
303 | * The defaults are 3 and 2 yielding 0x32 |
304 | */ |
305 | u8 bt5ctr[NT35510_P1_BT5CTR_LEN]; |
306 | /** |
307 | * @vgp: setting for VGP, the positive gamma divider voltages |
308 | * VGMP the high voltage and VGSP the low voltage. |
309 | * The first byte contains bit 8 of VGMP and VGSP in bits 4 and 0 |
310 | * The second byte contains bit 0..7 of VGMP |
311 | * The third byte contains bit 0..7 of VGSP |
312 | * VGMP 0x00 = 3.0V .. 0x108 = 6.3V in steps of 12.5mV |
313 | * VGSP 0x00 = 0V .. 0x111 = 3.7V in steps of 12.5mV |
314 | */ |
315 | u8 vgp[NT35510_P1_VGP_LEN]; |
316 | /** |
317 | * @vgn: setting for VGN, the negative gamma divider voltages, |
318 | * same layout of bytes as @vgp. |
319 | */ |
320 | u8 vgn[NT35510_P1_VGN_LEN]; |
321 | /** |
322 | * @vcmoff: setting the DC VCOM offset voltage |
323 | * The first byte contains bit 8 of VCM in bit 0 and VCMOFFSEL in bit 4. |
324 | * The second byte contains bits 0..7 of VCM. |
325 | * VCMOFFSEL the common voltage offset mode. |
326 | * VCMOFFSEL 0x00 = VCOM .. 0x01 Gamma. |
327 | * The default is 0x00. |
328 | * VCM the VCOM output voltage (VCMOFFSEL = 0) or the internal register |
329 | * offset for gamma voltage (VCMOFFSEL = 1). |
330 | * VCM 0x00 = 0V/0 .. 0x118 = 3.5V/280 in steps of 12.5mV/1step |
331 | * The default is 0x00 = 0V/0. |
332 | */ |
333 | u8 vcmoff[NT35510_P1_VCMOFF_LEN]; |
334 | /** |
335 | * @dopctr: setting optional control for display |
336 | * ERR bits 0..1 in the first byte is the ERR pin output signal setting. |
337 | * 0 = Disable, ERR pin output low |
338 | * 1 = ERR pin output CRC error only |
339 | * 2 = ERR pin output ECC error only |
340 | * 3 = ERR pin output CRC and ECC error |
341 | * The default is 0. |
342 | * N565 bit 2 in the first byte is the 16-bit/pixel format selection. |
343 | * 0 = R[4:0] + G[5:3] & G[2:0] + B[4:0] |
344 | * 1 = G[2:0] + R[4:0] & B[4:0] + G[5:3] |
345 | * The default is 0. |
346 | * DIS_EoTP_HS bit 3 in the first byte is "DSI protocol violation" error |
347 | * reporting. |
348 | * 0 = reporting when error |
349 | * 1 = not reporting when error |
350 | * DSIM bit 4 in the first byte is the video mode data type enable |
351 | * 0 = Video mode data type disable |
352 | * 1 = Video mode data type enable |
353 | * The default is 0. |
354 | * DSIG bit 5 int the first byte is the generic r/w data type enable |
355 | * 0 = Generic r/w disable |
356 | * 1 = Generic r/w enable |
357 | * The default is 0. |
358 | * DSITE bit 6 in the first byte is TE line enable |
359 | * 0 = TE line is disabled |
360 | * 1 = TE line is enabled |
361 | * The default is 0. |
362 | * RAMKP bit 7 in the first byte is the frame memory keep/loss in |
363 | * sleep-in mode |
364 | * 0 = contents loss in sleep-in |
365 | * 1 = contents keep in sleep-in |
366 | * The default is 0. |
367 | * CRL bit 1 in the second byte is the source driver data shift |
368 | * direction selection. This bit is XOR operation with bit RSMX |
369 | * of 3600h command. |
370 | * 0 (RMSX = 0) = S1 -> S1440 |
371 | * 0 (RMSX = 1) = S1440 -> S1 |
372 | * 1 (RMSX = 0) = S1440 -> S1 |
373 | * 1 (RMSX = 1) = S1 -> S1440 |
374 | * The default is 0. |
375 | * CTB bit 2 in the second byte is the vertical scanning direction |
376 | * selection for gate control signals. This bit is XOR operation |
377 | * with bit ML of 3600h command. |
378 | * 0 (ML = 0) = Forward (top -> bottom) |
379 | * 0 (ML = 1) = Reverse (bottom -> top) |
380 | * 1 (ML = 0) = Reverse (bottom -> top) |
381 | * 1 (ML = 1) = Forward (top -> bottom) |
382 | * The default is 0. |
383 | * CRGB bit 3 in the second byte is RGB-BGR order selection. This |
384 | * bit is XOR operation with bit RGB of 3600h command. |
385 | * 0 (RGB = 0) = RGB/Normal |
386 | * 0 (RGB = 1) = BGR/RB swap |
387 | * 1 (RGB = 0) = BGR/RB swap |
388 | * 1 (RGB = 1) = RGB/Normal |
389 | * The default is 0. |
390 | * TE_PWR_SEL bit 4 in the second byte is the TE output voltage |
391 | * level selection (only valid when DSTB_SEL = 0 or DSTB_SEL = 1, |
392 | * VSEL = High and VDDI = 1.665~3.3V). |
393 | * 0 = TE output voltage level is VDDI |
394 | * 1 = TE output voltage level is VDDA |
395 | * The default is 0. |
396 | */ |
397 | u8 dopctr[NT35510_P0_DOPCTR_LEN]; |
398 | /** |
399 | * @madctl: Memory data access control |
400 | * RSMY bit 0 is flip vertical. Flips the display image top to down. |
401 | * RSMX bit 1 is flip horizontal. Flips the display image left to right. |
402 | * MH bit 2 is the horizontal refresh order. |
403 | * RGB bit 3 is the RGB-BGR order. |
404 | * 0 = RGB color sequence |
405 | * 1 = BGR color sequence |
406 | * ML bit 4 is the vertical refresh order. |
407 | * MV bit 5 is the row/column exchange. |
408 | * MX bit 6 is the column address order. |
409 | * MY bit 7 is the row address order. |
410 | */ |
411 | u8 madctl; |
412 | /** |
413 | * @sdhdtctr: source output data hold time |
414 | * 0x00..0x3F = 0..31.5us in steps of 0.5us |
415 | * The default is 0x05 = 2.5us. |
416 | */ |
417 | u8 sdhdtctr; |
418 | /** |
419 | * @gseqctr: EQ control for gate signals |
420 | * GFEQ_XX[3:0]: time setting of EQ step for falling edge in steps |
421 | * of 0.5us. |
422 | * The default is 0x07 = 3.5us |
423 | * GREQ_XX[7:4]: time setting of EQ step for rising edge in steps |
424 | * of 0.5us. |
425 | * The default is 0x07 = 3.5us |
426 | */ |
427 | u8 gseqctr[NT35510_P0_GSEQCTR_LEN]; |
428 | /** |
429 | * @sdeqctr: Source driver control settings, first byte is |
430 | * 0 for mode 1 and 1 for mode 2. Mode 1 uses two steps and |
431 | * mode 2 uses three steps meaning EQS3 is not used in mode |
432 | * 1. Mode 2 is default. The last three parameters are EQS1, EQS2 |
433 | * and EQS3, setting the rise time for each equalizer step: |
434 | * 0x00 = 0.0 us to 0x0f = 7.5 us in steps of 0.5us. The default |
435 | * is 0x07 = 3.5 us. |
436 | */ |
437 | u8 sdeqctr[NT35510_P0_SDEQCTR_LEN]; |
438 | /** |
439 | * @sdvpctr: power/voltage behaviour during vertical porch time |
440 | */ |
441 | u8 sdvpctr; |
442 | /** |
443 | * @t1: the number of pixel clocks on one scanline, range |
444 | * 0x100 (258 ticks) .. 0x3FF (1024 ticks) so the value + 1 |
445 | * clock ticks. |
446 | */ |
447 | u16 t1; |
448 | /** |
449 | * @vbp: vertical back porch toward the PANEL note: not toward |
450 | * the DSI host; these are separate interfaces, in from DSI host |
451 | * and out to the panel. |
452 | */ |
453 | u8 vbp; |
454 | /** |
455 | * @vfp: vertical front porch toward the PANEL. |
456 | */ |
457 | u8 vfp; |
458 | /** |
459 | * @psel: pixel clock divisor: 0 = 1, 1 = 2, 2 = 4, 3 = 8. |
460 | */ |
461 | u8 psel; |
462 | /** |
463 | * @dpmctr12: Display timing control 12 |
464 | * Byte 1 bit 4 selects LVGL voltage level: 0 = VGLX, 1 = VGL_REG |
465 | * Byte 1 bit 1 selects gate signal mode: 0 = non-overlap, 1 = overlap |
466 | * Byte 1 bit 0 selects output signal control R/L swap, 0 = normal |
467 | * 1 = swap all O->E, L->R |
468 | * Byte 2 is CLW delay clock for CK O/E and CKB O/E signals: |
469 | * 0x00 = 0us .. 0xFF = 12.75us in 0.05us steps |
470 | * Byte 3 is FTI_H0 delay time for STP O/E signals: |
471 | * 0x00 = 0us .. 0xFF = 12.75us in 0.05us steps |
472 | */ |
473 | u8 dpmctr12[NT35510_P0_DPMCTR12_LEN]; |
474 | /** |
475 | * @gamma_corr_pos_r: Red gamma correction parameters, positive |
476 | */ |
477 | u8 gamma_corr_pos_r[NT35510_P1_GAMMA_LEN]; |
478 | /** |
479 | * @gamma_corr_pos_g: Green gamma correction parameters, positive |
480 | */ |
481 | u8 gamma_corr_pos_g[NT35510_P1_GAMMA_LEN]; |
482 | /** |
483 | * @gamma_corr_pos_b: Blue gamma correction parameters, positive |
484 | */ |
485 | u8 gamma_corr_pos_b[NT35510_P1_GAMMA_LEN]; |
486 | /** |
487 | * @gamma_corr_neg_r: Red gamma correction parameters, negative |
488 | */ |
489 | u8 gamma_corr_neg_r[NT35510_P1_GAMMA_LEN]; |
490 | /** |
491 | * @gamma_corr_neg_g: Green gamma correction parameters, negative |
492 | */ |
493 | u8 gamma_corr_neg_g[NT35510_P1_GAMMA_LEN]; |
494 | /** |
495 | * @gamma_corr_neg_b: Blue gamma correction parameters, negative |
496 | */ |
497 | u8 gamma_corr_neg_b[NT35510_P1_GAMMA_LEN]; |
498 | /** |
499 | * @wrdisbv: write display brightness |
500 | * 0x00 value means the lowest brightness and 0xff value means |
501 | * the highest brightness. |
502 | * The default is 0x00. |
503 | */ |
504 | u8 wrdisbv; |
505 | /** |
506 | * @wrctrld: write control display |
507 | * G bit 0 selects gamma curve: 0 = Manual, 1 = Automatic |
508 | * DB bit 1 selects display brightness: 0 = Manual, 1 = Automatic |
509 | * BL bit 2 controls backlight control: 0 = Off, 1 = On |
510 | * DD bit 3 controls display dimming: 0 = Off, 1 = On |
511 | * A bit 4 controls LABC block: 0 = Off, 1 = On |
512 | * BCTRL bit 5 controls brightness block: 0 = Off, 1 = On |
513 | */ |
514 | u8 wrctrld; |
515 | /** |
516 | * @wrcabc: write content adaptive brightness control |
517 | * There is possible to use 4 different modes for content adaptive |
518 | * image functionality: |
519 | * 0: Off |
520 | * 1: User Interface Image (UI-Mode) |
521 | * 2: Still Picture Image (Still-Mode) |
522 | * 3: Moving Picture Image (Moving-Mode) |
523 | * The default is 0 |
524 | */ |
525 | u8 wrcabc; |
526 | /** |
527 | * @wrcabcmb: write CABC minimum brightness |
528 | * Set the minimum brightness value of the display for CABC |
529 | * function. |
530 | * 0x00 value means the lowest brightness for CABC and 0xff |
531 | * value means the highest brightness for CABC. |
532 | * The default is 0x00. |
533 | */ |
534 | u8 wrcabcmb; |
535 | }; |
536 | |
537 | /** |
538 | * struct nt35510 - state container for the NT35510 panel |
539 | */ |
540 | struct nt35510 { |
541 | /** |
542 | * @dev: the container device |
543 | */ |
544 | struct device *dev; |
545 | /** |
546 | * @conf: the specific panel configuration, as the NT35510 |
547 | * can be combined with many physical panels, they can have |
548 | * different physical dimensions and gamma correction etc, |
549 | * so this is stored in the config. |
550 | */ |
551 | const struct nt35510_config *conf; |
552 | /** |
553 | * @panel: the DRM panel object for the instance |
554 | */ |
555 | struct drm_panel panel; |
556 | /** |
557 | * @supplies: regulators supplying the panel |
558 | */ |
559 | struct regulator_bulk_data supplies[2]; |
560 | /** |
561 | * @reset_gpio: the reset line |
562 | */ |
563 | struct gpio_desc *reset_gpio; |
564 | }; |
565 | |
566 | /* Manufacturer command has strictly this byte sequence */ |
567 | static const u8 nt35510_mauc_mtp_read_param[] = { 0xAA, 0x55, 0x25, 0x01 }; |
568 | static const u8 nt35510_mauc_mtp_read_setting[] = { 0x01, 0x02, 0x00, 0x20, |
569 | 0x33, 0x13, 0x00, 0x40, |
570 | 0x00, 0x00, 0x23, 0x02 }; |
571 | static const u8 nt35510_mauc_select_page_0[] = { 0x55, 0xAA, 0x52, 0x08, 0x00 }; |
572 | static const u8 nt35510_mauc_select_page_1[] = { 0x55, 0xAA, 0x52, 0x08, 0x01 }; |
573 | static const u8 nt35510_vgh_on[] = { 0x01 }; |
574 | |
575 | static inline struct nt35510 *panel_to_nt35510(struct drm_panel *panel) |
576 | { |
577 | return container_of(panel, struct nt35510, panel); |
578 | } |
579 | |
580 | #define NT35510_ROTATE_0_SETTING 0x02 |
581 | #define NT35510_ROTATE_180_SETTING 0x00 |
582 | |
583 | static int nt35510_send_long(struct nt35510 *nt, struct mipi_dsi_device *dsi, |
584 | u8 cmd, u8 cmdlen, const u8 *seq) |
585 | { |
586 | const u8 *seqp = seq; |
587 | int cmdwritten = 0; |
588 | int chunk = cmdlen; |
589 | int ret; |
590 | |
591 | if (chunk > 15) |
592 | chunk = 15; |
593 | ret = mipi_dsi_dcs_write(dsi, cmd, data: seqp, len: chunk); |
594 | if (ret < 0) { |
595 | dev_err(nt->dev, "error sending DCS command seq cmd %02x\n" , cmd); |
596 | return ret; |
597 | } |
598 | cmdwritten += chunk; |
599 | seqp += chunk; |
600 | |
601 | while (cmdwritten < cmdlen) { |
602 | chunk = cmdlen - cmdwritten; |
603 | if (chunk > 15) |
604 | chunk = 15; |
605 | ret = mipi_dsi_generic_write(dsi, payload: seqp, size: chunk); |
606 | if (ret < 0) { |
607 | dev_err(nt->dev, "error sending generic write seq %02x\n" , cmd); |
608 | return ret; |
609 | } |
610 | cmdwritten += chunk; |
611 | seqp += chunk; |
612 | } |
613 | dev_dbg(nt->dev, "sent command %02x %02x bytes\n" , cmd, cmdlen); |
614 | return 0; |
615 | } |
616 | |
617 | static int nt35510_read_id(struct nt35510 *nt) |
618 | { |
619 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); |
620 | u8 id1, id2, id3; |
621 | int ret; |
622 | |
623 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID1, data: &id1, len: 1); |
624 | if (ret < 0) { |
625 | dev_err(nt->dev, "could not read MTP ID1\n" ); |
626 | return ret; |
627 | } |
628 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID2, data: &id2, len: 1); |
629 | if (ret < 0) { |
630 | dev_err(nt->dev, "could not read MTP ID2\n" ); |
631 | return ret; |
632 | } |
633 | ret = mipi_dsi_dcs_read(dsi, MCS_CMD_READ_ID3, data: &id3, len: 1); |
634 | if (ret < 0) { |
635 | dev_err(nt->dev, "could not read MTP ID3\n" ); |
636 | return ret; |
637 | } |
638 | |
639 | /* |
640 | * Multi-Time Programmable (?) memory contains manufacturer |
641 | * ID (e.g. Hydis 0x55), driver ID (e.g. NT35510 0xc0) and |
642 | * version. |
643 | */ |
644 | dev_info(nt->dev, "MTP ID manufacturer: %02x version: %02x driver: %02x\n" , id1, id2, id3); |
645 | |
646 | return 0; |
647 | } |
648 | |
649 | /** |
650 | * nt35510_setup_power() - set up power config in page 1 |
651 | * @nt: the display instance to set up |
652 | */ |
653 | static int nt35510_setup_power(struct nt35510 *nt) |
654 | { |
655 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); |
656 | int ret; |
657 | |
658 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETAVDD, |
659 | NT35510_P1_AVDD_LEN, |
660 | seq: nt->conf->avdd); |
661 | if (ret) |
662 | return ret; |
663 | ret = nt35510_send_long(nt, dsi, NT35510_P1_BT1CTR, |
664 | NT35510_P1_BT1CTR_LEN, |
665 | seq: nt->conf->bt1ctr); |
666 | if (ret) |
667 | return ret; |
668 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETAVEE, |
669 | NT35510_P1_AVEE_LEN, |
670 | seq: nt->conf->avee); |
671 | if (ret) |
672 | return ret; |
673 | ret = nt35510_send_long(nt, dsi, NT35510_P1_BT2CTR, |
674 | NT35510_P1_BT2CTR_LEN, |
675 | seq: nt->conf->bt2ctr); |
676 | if (ret) |
677 | return ret; |
678 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCL, |
679 | NT35510_P1_VCL_LEN, |
680 | seq: nt->conf->vcl); |
681 | if (ret) |
682 | return ret; |
683 | ret = nt35510_send_long(nt, dsi, NT35510_P1_BT3CTR, |
684 | NT35510_P1_BT3CTR_LEN, |
685 | seq: nt->conf->bt3ctr); |
686 | if (ret) |
687 | return ret; |
688 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGH, |
689 | NT35510_P1_VGH_LEN, |
690 | seq: nt->conf->vgh); |
691 | if (ret) |
692 | return ret; |
693 | ret = nt35510_send_long(nt, dsi, NT35510_P1_BT4CTR, |
694 | NT35510_P1_BT4CTR_LEN, |
695 | seq: nt->conf->bt4ctr); |
696 | if (ret) |
697 | return ret; |
698 | ret = nt35510_send_long(nt, dsi, NT35510_P1_VGHCTR, |
699 | ARRAY_SIZE(nt35510_vgh_on), |
700 | seq: nt35510_vgh_on); |
701 | if (ret) |
702 | return ret; |
703 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGL, |
704 | NT35510_P1_VGL_LEN, |
705 | seq: nt->conf->vgl); |
706 | if (ret) |
707 | return ret; |
708 | ret = nt35510_send_long(nt, dsi, NT35510_P1_BT5CTR, |
709 | NT35510_P1_BT5CTR_LEN, |
710 | seq: nt->conf->bt5ctr); |
711 | if (ret) |
712 | return ret; |
713 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGP, |
714 | NT35510_P1_VGP_LEN, |
715 | seq: nt->conf->vgp); |
716 | if (ret) |
717 | return ret; |
718 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVGN, |
719 | NT35510_P1_VGN_LEN, |
720 | seq: nt->conf->vgn); |
721 | if (ret) |
722 | return ret; |
723 | |
724 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SETVCMOFF, |
725 | NT35510_P1_VCMOFF_LEN, |
726 | seq: nt->conf->vcmoff); |
727 | if (ret) |
728 | return ret; |
729 | |
730 | /* Typically 10 ms */ |
731 | usleep_range(min: 10000, max: 20000); |
732 | |
733 | return 0; |
734 | } |
735 | |
736 | /** |
737 | * nt35510_setup_display() - set up display config in page 0 |
738 | * @nt: the display instance to set up |
739 | */ |
740 | static int nt35510_setup_display(struct nt35510 *nt) |
741 | { |
742 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); |
743 | const struct nt35510_config *conf = nt->conf; |
744 | u8 dpfrctr[NT35510_P0_DPFRCTR1_LEN]; |
745 | int ret; |
746 | |
747 | ret = nt35510_send_long(nt, dsi, NT35510_P0_DOPCTR, |
748 | NT35510_P0_DOPCTR_LEN, |
749 | seq: conf->dopctr); |
750 | if (ret) |
751 | return ret; |
752 | |
753 | ret = mipi_dsi_dcs_write(dsi, cmd: MIPI_DCS_SET_ADDRESS_MODE, data: &conf->madctl, |
754 | len: sizeof(conf->madctl)); |
755 | if (ret < 0) |
756 | return ret; |
757 | |
758 | ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDHDTCTR, data: &conf->sdhdtctr, |
759 | len: sizeof(conf->sdhdtctr)); |
760 | if (ret < 0) |
761 | return ret; |
762 | |
763 | ret = nt35510_send_long(nt, dsi, NT35510_P0_GSEQCTR, |
764 | NT35510_P0_GSEQCTR_LEN, |
765 | seq: conf->gseqctr); |
766 | if (ret) |
767 | return ret; |
768 | |
769 | ret = nt35510_send_long(nt, dsi, NT35510_P0_SDEQCTR, |
770 | NT35510_P0_SDEQCTR_LEN, |
771 | seq: conf->sdeqctr); |
772 | if (ret) |
773 | return ret; |
774 | |
775 | ret = mipi_dsi_dcs_write(dsi, NT35510_P0_SDVPCTR, |
776 | data: &conf->sdvpctr, len: 1); |
777 | if (ret < 0) |
778 | return ret; |
779 | |
780 | /* |
781 | * Display timing control for active and idle off mode: |
782 | * the first byte contains |
783 | * the two high bits of T1A and second byte the low 8 bits, and |
784 | * the valid range is 0x100 (257) to 0x3ff (1023) representing |
785 | * 258..1024 (+1) pixel clock ticks for one scanline. At 20MHz pixel |
786 | * clock this covers the range of 12.90us .. 51.20us in steps of |
787 | * 0.05us, the default is 0x184 (388) representing 389 ticks. |
788 | * The third byte is VBPDA, vertical back porch display active |
789 | * and the fourth VFPDA, vertical front porch display active, |
790 | * both given in number of scanlines in the range 0x02..0xff |
791 | * for 2..255 scanlines. The fifth byte is 2 bits selecting |
792 | * PSEL for active and idle off mode, how much the 20MHz clock |
793 | * is divided by 0..3. This needs to be adjusted to get the right |
794 | * frame rate. |
795 | */ |
796 | dpfrctr[0] = (conf->t1 >> 8) & 0xFF; |
797 | dpfrctr[1] = conf->t1 & 0xFF; |
798 | /* Vertical back porch */ |
799 | dpfrctr[2] = conf->vbp; |
800 | /* Vertical front porch */ |
801 | dpfrctr[3] = conf->vfp; |
802 | dpfrctr[4] = conf->psel; |
803 | ret = nt35510_send_long(nt, dsi, NT35510_P0_DPFRCTR1, |
804 | NT35510_P0_DPFRCTR1_LEN, |
805 | seq: dpfrctr); |
806 | if (ret) |
807 | return ret; |
808 | /* For idle and partial idle off mode we decrease front porch by one */ |
809 | dpfrctr[3]--; |
810 | ret = nt35510_send_long(nt, dsi, NT35510_P0_DPFRCTR2, |
811 | NT35510_P0_DPFRCTR2_LEN, |
812 | seq: dpfrctr); |
813 | if (ret) |
814 | return ret; |
815 | ret = nt35510_send_long(nt, dsi, NT35510_P0_DPFRCTR3, |
816 | NT35510_P0_DPFRCTR3_LEN, |
817 | seq: dpfrctr); |
818 | if (ret) |
819 | return ret; |
820 | |
821 | /* Enable TE on vblank */ |
822 | ret = mipi_dsi_dcs_set_tear_on(dsi, mode: MIPI_DSI_DCS_TEAR_MODE_VBLANK); |
823 | if (ret) |
824 | return ret; |
825 | |
826 | /* Turn on the pads? */ |
827 | ret = nt35510_send_long(nt, dsi, NT35510_P0_DPMCTR12, |
828 | NT35510_P0_DPMCTR12_LEN, |
829 | seq: conf->dpmctr12); |
830 | if (ret) |
831 | return ret; |
832 | |
833 | return 0; |
834 | } |
835 | |
836 | static int nt35510_set_brightness(struct backlight_device *bl) |
837 | { |
838 | struct nt35510 *nt = bl_get_data(bl_dev: bl); |
839 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); |
840 | u8 brightness = bl->props.brightness; |
841 | int ret; |
842 | |
843 | dev_dbg(nt->dev, "set brightness %d\n" , brightness); |
844 | ret = mipi_dsi_dcs_write(dsi, cmd: MIPI_DCS_SET_DISPLAY_BRIGHTNESS, |
845 | data: &brightness, |
846 | len: sizeof(brightness)); |
847 | if (ret < 0) |
848 | return ret; |
849 | |
850 | return 0; |
851 | } |
852 | |
853 | static const struct backlight_ops nt35510_bl_ops = { |
854 | .update_status = nt35510_set_brightness, |
855 | }; |
856 | |
857 | /* |
858 | * This power-on sequence |
859 | */ |
860 | static int nt35510_power_on(struct nt35510 *nt) |
861 | { |
862 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); |
863 | int ret; |
864 | |
865 | ret = regulator_bulk_enable(ARRAY_SIZE(nt->supplies), consumers: nt->supplies); |
866 | if (ret < 0) { |
867 | dev_err(nt->dev, "unable to enable regulators\n" ); |
868 | return ret; |
869 | } |
870 | |
871 | /* Toggle RESET in accordance with datasheet page 370 */ |
872 | if (nt->reset_gpio) { |
873 | gpiod_set_value(desc: nt->reset_gpio, value: 1); |
874 | /* Active min 10 us according to datasheet, let's say 20 */ |
875 | usleep_range(min: 20, max: 1000); |
876 | gpiod_set_value(desc: nt->reset_gpio, value: 0); |
877 | /* |
878 | * 5 ms during sleep mode, 120 ms during sleep out mode |
879 | * according to datasheet, let's use 120-140 ms. |
880 | */ |
881 | usleep_range(min: 120000, max: 140000); |
882 | } |
883 | |
884 | ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_PARAM, |
885 | ARRAY_SIZE(nt35510_mauc_mtp_read_param), |
886 | seq: nt35510_mauc_mtp_read_param); |
887 | if (ret) |
888 | return ret; |
889 | |
890 | ret = nt35510_send_long(nt, dsi, MCS_CMD_MTP_READ_SETTING, |
891 | ARRAY_SIZE(nt35510_mauc_mtp_read_setting), |
892 | seq: nt35510_mauc_mtp_read_setting); |
893 | if (ret) |
894 | return ret; |
895 | |
896 | nt35510_read_id(nt); |
897 | |
898 | /* Set up stuff in manufacturer control, page 1 */ |
899 | ret = nt35510_send_long(nt, dsi, MCS_CMD_MAUCCTR, |
900 | ARRAY_SIZE(nt35510_mauc_select_page_1), |
901 | seq: nt35510_mauc_select_page_1); |
902 | if (ret) |
903 | return ret; |
904 | |
905 | ret = nt35510_setup_power(nt); |
906 | if (ret) |
907 | return ret; |
908 | |
909 | if (nt->conf->cmds & NT35510_CMD_CORRECT_GAMMA) { |
910 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_POS, |
911 | NT35510_P1_GAMMA_LEN, |
912 | seq: nt->conf->gamma_corr_pos_r); |
913 | if (ret) |
914 | return ret; |
915 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_POS, |
916 | NT35510_P1_GAMMA_LEN, |
917 | seq: nt->conf->gamma_corr_pos_g); |
918 | if (ret) |
919 | return ret; |
920 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_POS, |
921 | NT35510_P1_GAMMA_LEN, |
922 | seq: nt->conf->gamma_corr_pos_b); |
923 | if (ret) |
924 | return ret; |
925 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_RED_NEG, |
926 | NT35510_P1_GAMMA_LEN, |
927 | seq: nt->conf->gamma_corr_neg_r); |
928 | if (ret) |
929 | return ret; |
930 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_GREEN_NEG, |
931 | NT35510_P1_GAMMA_LEN, |
932 | seq: nt->conf->gamma_corr_neg_g); |
933 | if (ret) |
934 | return ret; |
935 | ret = nt35510_send_long(nt, dsi, NT35510_P1_SET_GAMMA_BLUE_NEG, |
936 | NT35510_P1_GAMMA_LEN, |
937 | seq: nt->conf->gamma_corr_neg_b); |
938 | if (ret) |
939 | return ret; |
940 | } |
941 | |
942 | /* Set up stuff in manufacturer control, page 0 */ |
943 | ret = nt35510_send_long(nt, dsi, MCS_CMD_MAUCCTR, |
944 | ARRAY_SIZE(nt35510_mauc_select_page_0), |
945 | seq: nt35510_mauc_select_page_0); |
946 | if (ret) |
947 | return ret; |
948 | |
949 | ret = nt35510_setup_display(nt); |
950 | if (ret) |
951 | return ret; |
952 | |
953 | return 0; |
954 | } |
955 | |
956 | static int nt35510_power_off(struct nt35510 *nt) |
957 | { |
958 | int ret; |
959 | |
960 | ret = regulator_bulk_disable(ARRAY_SIZE(nt->supplies), consumers: nt->supplies); |
961 | if (ret) |
962 | return ret; |
963 | |
964 | if (nt->reset_gpio) |
965 | gpiod_set_value(desc: nt->reset_gpio, value: 1); |
966 | |
967 | return 0; |
968 | } |
969 | |
970 | static int nt35510_unprepare(struct drm_panel *panel) |
971 | { |
972 | struct nt35510 *nt = panel_to_nt35510(panel); |
973 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); |
974 | int ret; |
975 | |
976 | ret = mipi_dsi_dcs_set_display_off(dsi); |
977 | if (ret) { |
978 | dev_err(nt->dev, "failed to turn display off (%d)\n" , ret); |
979 | return ret; |
980 | } |
981 | usleep_range(min: 10000, max: 20000); |
982 | |
983 | /* Enter sleep mode */ |
984 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); |
985 | if (ret) { |
986 | dev_err(nt->dev, "failed to enter sleep mode (%d)\n" , ret); |
987 | return ret; |
988 | } |
989 | |
990 | /* Wait 4 frames, how much is that 5ms in the vendor driver */ |
991 | usleep_range(min: 5000, max: 10000); |
992 | |
993 | ret = nt35510_power_off(nt); |
994 | if (ret) |
995 | return ret; |
996 | |
997 | return 0; |
998 | } |
999 | |
1000 | static int nt35510_prepare(struct drm_panel *panel) |
1001 | { |
1002 | struct nt35510 *nt = panel_to_nt35510(panel); |
1003 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); |
1004 | int ret; |
1005 | |
1006 | ret = nt35510_power_on(nt); |
1007 | if (ret) |
1008 | return ret; |
1009 | |
1010 | /* Exit sleep mode */ |
1011 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
1012 | if (ret) { |
1013 | dev_err(nt->dev, "failed to exit sleep mode (%d)\n" , ret); |
1014 | return ret; |
1015 | } |
1016 | /* Up to 120 ms */ |
1017 | usleep_range(min: 120000, max: 150000); |
1018 | |
1019 | if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) { |
1020 | ret = mipi_dsi_dcs_write(dsi, cmd: MIPI_DCS_WRITE_CONTROL_DISPLAY, |
1021 | data: &nt->conf->wrctrld, |
1022 | len: sizeof(nt->conf->wrctrld)); |
1023 | if (ret < 0) |
1024 | return ret; |
1025 | |
1026 | ret = mipi_dsi_dcs_write(dsi, cmd: MIPI_DCS_WRITE_POWER_SAVE, |
1027 | data: &nt->conf->wrcabc, |
1028 | len: sizeof(nt->conf->wrcabc)); |
1029 | if (ret < 0) |
1030 | return ret; |
1031 | |
1032 | ret = mipi_dsi_dcs_write(dsi, cmd: MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, |
1033 | data: &nt->conf->wrcabcmb, |
1034 | len: sizeof(nt->conf->wrcabcmb)); |
1035 | if (ret < 0) |
1036 | return ret; |
1037 | } |
1038 | |
1039 | ret = mipi_dsi_dcs_set_display_on(dsi); |
1040 | if (ret) { |
1041 | dev_err(nt->dev, "failed to turn display on (%d)\n" , ret); |
1042 | return ret; |
1043 | } |
1044 | /* Some 10 ms */ |
1045 | usleep_range(min: 10000, max: 20000); |
1046 | |
1047 | return 0; |
1048 | } |
1049 | |
1050 | static int nt35510_get_modes(struct drm_panel *panel, |
1051 | struct drm_connector *connector) |
1052 | { |
1053 | struct nt35510 *nt = panel_to_nt35510(panel); |
1054 | struct drm_display_mode *mode; |
1055 | struct drm_display_info *info; |
1056 | |
1057 | info = &connector->display_info; |
1058 | info->width_mm = nt->conf->width_mm; |
1059 | info->height_mm = nt->conf->height_mm; |
1060 | mode = drm_mode_duplicate(dev: connector->dev, mode: &nt->conf->mode); |
1061 | if (!mode) { |
1062 | dev_err(panel->dev, "bad mode or failed to add mode\n" ); |
1063 | return -EINVAL; |
1064 | } |
1065 | drm_mode_set_name(mode); |
1066 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; |
1067 | |
1068 | mode->width_mm = nt->conf->width_mm; |
1069 | mode->height_mm = nt->conf->height_mm; |
1070 | drm_mode_probed_add(connector, mode); |
1071 | |
1072 | return 1; /* Number of modes */ |
1073 | } |
1074 | |
1075 | static const struct drm_panel_funcs nt35510_drm_funcs = { |
1076 | .unprepare = nt35510_unprepare, |
1077 | .prepare = nt35510_prepare, |
1078 | .get_modes = nt35510_get_modes, |
1079 | }; |
1080 | |
1081 | static int nt35510_probe(struct mipi_dsi_device *dsi) |
1082 | { |
1083 | struct device *dev = &dsi->dev; |
1084 | struct nt35510 *nt; |
1085 | int ret; |
1086 | |
1087 | nt = devm_kzalloc(dev, size: sizeof(struct nt35510), GFP_KERNEL); |
1088 | if (!nt) |
1089 | return -ENOMEM; |
1090 | mipi_dsi_set_drvdata(dsi, data: nt); |
1091 | nt->dev = dev; |
1092 | |
1093 | dsi->lanes = 2; |
1094 | dsi->format = MIPI_DSI_FMT_RGB888; |
1095 | /* |
1096 | * Datasheet suggests max HS rate for NT35510 is 250 MHz |
1097 | * (period time 4ns, see figure 7.6.4 page 365) and max LP rate is |
1098 | * 20 MHz (period time 50ns, see figure 7.6.6. page 366). |
1099 | * However these frequencies appear in source code for the Hydis |
1100 | * HVA40WV1 panel and setting up the LP frequency makes the panel |
1101 | * not work. |
1102 | * |
1103 | * TODO: if other panels prove to be closer to the datasheet, |
1104 | * maybe make this a per-panel config in struct nt35510_config? |
1105 | */ |
1106 | dsi->hs_rate = 349440000; |
1107 | dsi->lp_rate = 9600000; |
1108 | |
1109 | /* |
1110 | * Every new incarnation of this display must have a unique |
1111 | * data entry for the system in this driver. |
1112 | */ |
1113 | nt->conf = of_device_get_match_data(dev); |
1114 | if (!nt->conf) { |
1115 | dev_err(dev, "missing device configuration\n" ); |
1116 | return -ENODEV; |
1117 | } |
1118 | |
1119 | dsi->mode_flags = nt->conf->mode_flags; |
1120 | |
1121 | nt->supplies[0].supply = "vdd" ; /* 2.3-4.8 V */ |
1122 | nt->supplies[1].supply = "vddi" ; /* 1.65-3.3V */ |
1123 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->supplies), |
1124 | consumers: nt->supplies); |
1125 | if (ret < 0) |
1126 | return ret; |
1127 | ret = regulator_set_voltage(regulator: nt->supplies[0].consumer, |
1128 | min_uV: 2300000, max_uV: 4800000); |
1129 | if (ret) |
1130 | return ret; |
1131 | ret = regulator_set_voltage(regulator: nt->supplies[1].consumer, |
1132 | min_uV: 1650000, max_uV: 3300000); |
1133 | if (ret) |
1134 | return ret; |
1135 | |
1136 | nt->reset_gpio = devm_gpiod_get_optional(dev, con_id: "reset" , flags: GPIOD_OUT_HIGH); |
1137 | if (IS_ERR(ptr: nt->reset_gpio)) { |
1138 | dev_err(dev, "error getting RESET GPIO\n" ); |
1139 | return PTR_ERR(ptr: nt->reset_gpio); |
1140 | } |
1141 | |
1142 | drm_panel_init(panel: &nt->panel, dev, funcs: &nt35510_drm_funcs, |
1143 | DRM_MODE_CONNECTOR_DSI); |
1144 | |
1145 | /* |
1146 | * First, try to locate an external backlight (such as on GPIO) |
1147 | * if this fails, assume we will want to use the internal backlight |
1148 | * control. |
1149 | */ |
1150 | ret = drm_panel_of_backlight(panel: &nt->panel); |
1151 | if (ret) { |
1152 | dev_err(dev, "error getting external backlight %d\n" , ret); |
1153 | return ret; |
1154 | } |
1155 | if (!nt->panel.backlight) { |
1156 | struct backlight_device *bl; |
1157 | |
1158 | bl = devm_backlight_device_register(dev, name: "nt35510" , parent: dev, devdata: nt, |
1159 | ops: &nt35510_bl_ops, NULL); |
1160 | if (IS_ERR(ptr: bl)) { |
1161 | dev_err(dev, "failed to register backlight device\n" ); |
1162 | return PTR_ERR(ptr: bl); |
1163 | } |
1164 | bl->props.max_brightness = 255; |
1165 | if (nt->conf->cmds & NT35510_CMD_CONTROL_DISPLAY) |
1166 | bl->props.brightness = nt->conf->wrdisbv; |
1167 | else |
1168 | bl->props.brightness = 255; |
1169 | bl->props.power = FB_BLANK_POWERDOWN; |
1170 | nt->panel.backlight = bl; |
1171 | } |
1172 | |
1173 | drm_panel_add(panel: &nt->panel); |
1174 | |
1175 | ret = mipi_dsi_attach(dsi); |
1176 | if (ret < 0) |
1177 | drm_panel_remove(panel: &nt->panel); |
1178 | |
1179 | return 0; |
1180 | } |
1181 | |
1182 | static void nt35510_remove(struct mipi_dsi_device *dsi) |
1183 | { |
1184 | struct nt35510 *nt = mipi_dsi_get_drvdata(dsi); |
1185 | int ret; |
1186 | |
1187 | mipi_dsi_detach(dsi); |
1188 | /* Power off */ |
1189 | ret = nt35510_power_off(nt); |
1190 | if (ret) |
1191 | dev_err(&dsi->dev, "Failed to power off\n" ); |
1192 | |
1193 | drm_panel_remove(panel: &nt->panel); |
1194 | } |
1195 | |
1196 | /* |
1197 | * These gamma correction values are 10bit tuples, so only bits 0 and 1 is |
1198 | * ever used in the first byte. They form a positive and negative gamma |
1199 | * correction curve for each color, values must be strictly higher for each |
1200 | * step on the curve. As can be seen these default curves goes from 0x0001 |
1201 | * to 0x03FE. |
1202 | */ |
1203 | #define NT35510_GAMMA_POS_DEFAULT 0x00, 0x01, 0x00, 0x43, 0x00, \ |
1204 | 0x6B, 0x00, 0x87, 0x00, 0xA3, 0x00, 0xCE, 0x00, 0xF1, 0x01, \ |
1205 | 0x27, 0x01, 0x53, 0x01, 0x98, 0x01, 0xCE, 0x02, 0x22, 0x02, \ |
1206 | 0x83, 0x02, 0x78, 0x02, 0x9E, 0x02, 0xDD, 0x03, 0x00, 0x03, \ |
1207 | 0x2E, 0x03, 0x54, 0x03, 0x7F, 0x03, 0x95, 0x03, 0xB3, 0x03, \ |
1208 | 0xC2, 0x03, 0xE1, 0x03, 0xF1, 0x03, 0xFE |
1209 | |
1210 | #define NT35510_GAMMA_NEG_DEFAULT 0x00, 0x01, 0x00, 0x43, 0x00, \ |
1211 | 0x6B, 0x00, 0x87, 0x00, 0xA3, 0x00, 0xCE, 0x00, 0xF1, 0x01, \ |
1212 | 0x27, 0x01, 0x53, 0x01, 0x98, 0x01, 0xCE, 0x02, 0x22, 0x02, \ |
1213 | 0x43, 0x02, 0x50, 0x02, 0x9E, 0x02, 0xDD, 0x03, 0x00, 0x03, \ |
1214 | 0x2E, 0x03, 0x54, 0x03, 0x7F, 0x03, 0x95, 0x03, 0xB3, 0x03, \ |
1215 | 0xC2, 0x03, 0xE1, 0x03, 0xF1, 0x03, 0xFE |
1216 | |
1217 | /* |
1218 | * The Hydis HVA40WV1 panel |
1219 | */ |
1220 | static const struct nt35510_config nt35510_hydis_hva40wv1 = { |
1221 | .width_mm = 52, |
1222 | .height_mm = 86, |
1223 | /** |
1224 | * As the Hydis panel is used in command mode, the porches etc |
1225 | * are settings programmed internally into the NT35510 controller |
1226 | * and generated toward the physical display. As the panel is not |
1227 | * used in video mode, these are not really exposed to the DSI |
1228 | * host. |
1229 | * |
1230 | * Display frame rate control: |
1231 | * Frame rate = (20 MHz / 1) / (389 * (7 + 50 + 800)) ~= 60 Hz |
1232 | */ |
1233 | .mode = { |
1234 | /* The internal pixel clock of the NT35510 is 20 MHz */ |
1235 | .clock = 20000, |
1236 | .hdisplay = 480, |
1237 | .hsync_start = 480 + 2, /* HFP = 2 */ |
1238 | .hsync_end = 480 + 2 + 0, /* HSync = 0 */ |
1239 | .htotal = 480 + 2 + 0 + 5, /* HBP = 5 */ |
1240 | .vdisplay = 800, |
1241 | .vsync_start = 800 + 2, /* VFP = 2 */ |
1242 | .vsync_end = 800 + 2 + 0, /* VSync = 0 */ |
1243 | .vtotal = 800 + 2 + 0 + 5, /* VBP = 5 */ |
1244 | .flags = 0, |
1245 | }, |
1246 | .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS, |
1247 | .cmds = NT35510_CMD_CORRECT_GAMMA, |
1248 | /* 0x09: AVDD = 5.6V */ |
1249 | .avdd = { 0x09, 0x09, 0x09 }, |
1250 | /* 0x34: PCK = Hsync/2, BTP = 2 x VDDB */ |
1251 | .bt1ctr = { 0x34, 0x34, 0x34 }, |
1252 | /* 0x09: AVEE = -5.6V */ |
1253 | .avee = { 0x09, 0x09, 0x09 }, |
1254 | /* 0x24: NCK = Hsync/2, BTN = -2 x VDDB */ |
1255 | .bt2ctr = { 0x24, 0x24, 0x24 }, |
1256 | /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -2.5V */ |
1257 | .vcl = { 0x00, 0x00, 0x00 }, |
1258 | /* 0x24: CLCK = Hsync/2, BTN = -1 x VDDB */ |
1259 | .bt3ctr = { 0x24, 0x24, 0x24 }, |
1260 | /* 0x05 = 12V */ |
1261 | .vgh = { 0x05, 0x05, 0x05 }, |
1262 | /* 0x24: NCKA = Hsync/2, VGH = 2 x AVDD - AVEE */ |
1263 | .bt4ctr = { 0x24, 0x24, 0x24 }, |
1264 | /* 0x0B = -13V */ |
1265 | .vgl = { 0x0B, 0x0B, 0x0B }, |
1266 | /* 0x24: LCKA = Hsync, VGL = AVDD + VCL - AVDD */ |
1267 | .bt5ctr = { 0x24, 0x24, 0x24 }, |
1268 | /* VGMP: 0x0A3 = 5.0375V, VGSP = 0V */ |
1269 | .vgp = { 0x00, 0xA3, 0x00 }, |
1270 | /* VGMP: 0x0A3 = 5.0375V, VGSP = 0V */ |
1271 | .vgn = { 0x00, 0xA3, 0x00 }, |
1272 | /* VCMOFFSEL = VCOM voltage offset mode, VCM = 0V */ |
1273 | .vcmoff = { 0x00, 0x00 }, |
1274 | /* Enable TE, EoTP and RGB pixel format */ |
1275 | .dopctr = { NT35510_DOPCTR_0_DSITE | NT35510_DOPCTR_0_EOTP | |
1276 | NT35510_DOPCTR_0_N565, NT35510_DOPCTR_1_CTB }, |
1277 | .madctl = NT35510_ROTATE_0_SETTING, |
1278 | /* 0x0A: SDT = 5 us */ |
1279 | .sdhdtctr = 0x0A, |
1280 | /* EQ control for gate signals, 0x00 = 0 us */ |
1281 | .gseqctr = { 0x00, 0x00 }, |
1282 | /* SDEQCTR: source driver EQ mode 2, 2.5 us rise time on each step */ |
1283 | .sdeqctr = { 0x01, 0x05, 0x05, 0x05 }, |
1284 | /* SDVPCTR: Normal operation off color during v porch */ |
1285 | .sdvpctr = 0x01, |
1286 | /* T1: number of pixel clocks on one scanline: 0x184 = 389 clocks */ |
1287 | .t1 = 0x0184, |
1288 | /* VBP: vertical back porch toward the panel */ |
1289 | .vbp = 7, |
1290 | /* VFP: vertical front porch toward the panel */ |
1291 | .vfp = 50, |
1292 | /* PSEL: divide pixel clock 20MHz with 1 (no clock downscaling) */ |
1293 | .psel = 0, |
1294 | /* DPTMCTR12: 0x03: LVGL = VGLX, overlap mode, swap R->L O->E */ |
1295 | .dpmctr12 = { 0x03, 0x00, 0x00, }, |
1296 | /* Default gamma correction values */ |
1297 | .gamma_corr_pos_r = { NT35510_GAMMA_POS_DEFAULT }, |
1298 | .gamma_corr_pos_g = { NT35510_GAMMA_POS_DEFAULT }, |
1299 | .gamma_corr_pos_b = { NT35510_GAMMA_POS_DEFAULT }, |
1300 | .gamma_corr_neg_r = { NT35510_GAMMA_NEG_DEFAULT }, |
1301 | .gamma_corr_neg_g = { NT35510_GAMMA_NEG_DEFAULT }, |
1302 | .gamma_corr_neg_b = { NT35510_GAMMA_NEG_DEFAULT }, |
1303 | }; |
1304 | |
1305 | static const struct nt35510_config nt35510_frida_frd400b25025 = { |
1306 | .width_mm = 52, |
1307 | .height_mm = 86, |
1308 | .mode = { |
1309 | .clock = 23000, |
1310 | .hdisplay = 480, |
1311 | .hsync_start = 480 + 34, /* HFP = 34 */ |
1312 | .hsync_end = 480 + 34 + 2, /* HSync = 2 */ |
1313 | .htotal = 480 + 34 + 2 + 34, /* HBP = 34 */ |
1314 | .vdisplay = 800, |
1315 | .vsync_start = 800 + 15, /* VFP = 15 */ |
1316 | .vsync_end = 800 + 15 + 12, /* VSync = 12 */ |
1317 | .vtotal = 800 + 15 + 12 + 15, /* VBP = 15 */ |
1318 | .flags = 0, |
1319 | }, |
1320 | .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | |
1321 | MIPI_DSI_MODE_LPM, |
1322 | .cmds = NT35510_CMD_CONTROL_DISPLAY, |
1323 | /* 0x03: AVDD = 6.2V */ |
1324 | .avdd = { 0x03, 0x03, 0x03 }, |
1325 | /* 0x46: PCK = 2 x Hsync, BTP = 2.5 x VDDB */ |
1326 | .bt1ctr = { 0x46, 0x46, 0x46 }, |
1327 | /* 0x03: AVEE = -6.2V */ |
1328 | .avee = { 0x03, 0x03, 0x03 }, |
1329 | /* 0x36: PCK = 2 x Hsync, BTP = 2 x VDDB */ |
1330 | .bt2ctr = { 0x36, 0x36, 0x36 }, |
1331 | /* VBCLA: -2.5V, VBCLB: -2.5V, VBCLC: -3.5V */ |
1332 | .vcl = { 0x00, 0x00, 0x02 }, |
1333 | /* 0x26: CLCK = 2 x Hsync, BTN = -1 x VDDB */ |
1334 | .bt3ctr = { 0x26, 0x26, 0x26 }, |
1335 | /* 0x09 = 16V */ |
1336 | .vgh = { 0x09, 0x09, 0x09 }, |
1337 | /* 0x36: HCK = 2 x Hsync, VGH = 2 x AVDD - AVEE */ |
1338 | .bt4ctr = { 0x36, 0x36, 0x36 }, |
1339 | /* 0x08 = -10V */ |
1340 | .vgl = { 0x08, 0x08, 0x08 }, |
1341 | /* 0x26: LCK = 2 x Hsync, VGL = AVDD + VCL - AVDD */ |
1342 | .bt5ctr = { 0x26, 0x26, 0x26 }, |
1343 | /* VGMP: 0x080 = 4.6V, VGSP = 0V */ |
1344 | .vgp = { 0x00, 0x80, 0x00 }, |
1345 | /* VGMP: 0x080 = 4.6V, VGSP = 0V */ |
1346 | .vgn = { 0x00, 0x80, 0x00 }, |
1347 | /* VCMOFFSEL = VCOM voltage offset mode, VCM = -1V */ |
1348 | .vcmoff = { 0x00, 0x50 }, |
1349 | .dopctr = { NT35510_DOPCTR_0_RAMKP | NT35510_DOPCTR_0_DSITE | |
1350 | NT35510_DOPCTR_0_DSIG | NT35510_DOPCTR_0_DSIM | |
1351 | NT35510_DOPCTR_0_EOTP | NT35510_DOPCTR_0_N565, 0 }, |
1352 | .madctl = NT35510_ROTATE_180_SETTING, |
1353 | /* 0x03: SDT = 1.5 us */ |
1354 | .sdhdtctr = 0x03, |
1355 | /* EQ control for gate signals, 0x00 = 0 us */ |
1356 | .gseqctr = { 0x00, 0x00 }, |
1357 | /* SDEQCTR: source driver EQ mode 2, 1 us rise time on each step */ |
1358 | .sdeqctr = { 0x01, 0x02, 0x02, 0x02 }, |
1359 | /* SDVPCTR: Normal operation off color during v porch */ |
1360 | .sdvpctr = 0x01, |
1361 | /* T1: number of pixel clocks on one scanline: 0x184 = 389 clocks */ |
1362 | .t1 = 0x0184, |
1363 | /* VBP: vertical back porch toward the panel */ |
1364 | .vbp = 0x1C, |
1365 | /* VFP: vertical front porch toward the panel */ |
1366 | .vfp = 0x1C, |
1367 | /* PSEL: divide pixel clock 23MHz with 1 (no clock downscaling) */ |
1368 | .psel = 0, |
1369 | /* DPTMCTR12: 0x03: LVGL = VGLX, overlap mode, swap R->L O->E */ |
1370 | .dpmctr12 = { 0x03, 0x00, 0x00, }, |
1371 | /* write display brightness */ |
1372 | .wrdisbv = 0x7f, |
1373 | /* write control display */ |
1374 | .wrctrld = NT35510_WRCTRLD_BCTRL | NT35510_WRCTRLD_DD | |
1375 | NT35510_WRCTRLD_BL, |
1376 | /* write content adaptive brightness control */ |
1377 | .wrcabc = NT35510_WRCABC_STILL_MODE, |
1378 | /* write CABC minimum brightness */ |
1379 | .wrcabcmb = 0xff, |
1380 | }; |
1381 | |
1382 | static const struct of_device_id nt35510_of_match[] = { |
1383 | { |
1384 | .compatible = "frida,frd400b25025" , |
1385 | .data = &nt35510_frida_frd400b25025, |
1386 | }, |
1387 | { |
1388 | .compatible = "hydis,hva40wv1" , |
1389 | .data = &nt35510_hydis_hva40wv1, |
1390 | }, |
1391 | { } |
1392 | }; |
1393 | MODULE_DEVICE_TABLE(of, nt35510_of_match); |
1394 | |
1395 | static struct mipi_dsi_driver nt35510_driver = { |
1396 | .probe = nt35510_probe, |
1397 | .remove = nt35510_remove, |
1398 | .driver = { |
1399 | .name = "panel-novatek-nt35510" , |
1400 | .of_match_table = nt35510_of_match, |
1401 | }, |
1402 | }; |
1403 | module_mipi_dsi_driver(nt35510_driver); |
1404 | |
1405 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>" ); |
1406 | MODULE_DESCRIPTION("NT35510-based panel driver" ); |
1407 | MODULE_LICENSE("GPL v2" ); |
1408 | |