Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux-2.6-microblaze.git] / drivers / gpu / drm / panel / panel-samsung-s6e63m0.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * S6E63M0 AMOLED LCD drm_panel driver.
4  *
5  * Copyright (C) 2019 PaweÅ‚ Chmiel <pawel.mikolaj.chmiel@gmail.com>
6  * Derived from drivers/gpu/drm/panel-samsung-ld9040.c
7  *
8  * Andrzej Hajda <a.hajda@samsung.com>
9  */
10
11 #include <drm/drm_modes.h>
12 #include <drm/drm_panel.h>
13
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/module.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/media-bus-format.h>
20
21 #include <video/mipi_display.h>
22
23 #include "panel-samsung-s6e63m0.h"
24
25 /* Manufacturer Command Set */
26 #define MCS_ELVSS_ON            0xb1
27 #define MCS_TEMP_SWIRE          0xb2
28 #define MCS_PENTILE_1           0xb3
29 #define MCS_PENTILE_2           0xb4
30 #define MCS_GAMMA_DELTA_Y_RED   0xb5
31 #define MCS_GAMMA_DELTA_X_RED   0xb6
32 #define MCS_GAMMA_DELTA_Y_GREEN 0xb7
33 #define MCS_GAMMA_DELTA_X_GREEN 0xb8
34 #define MCS_GAMMA_DELTA_Y_BLUE  0xb9
35 #define MCS_GAMMA_DELTA_X_BLUE  0xba
36 #define MCS_MIECTL1             0xc0
37 #define MCS_BCMODE              0xc1
38 #define MCS_ERROR_CHECK         0xd5
39 #define MCS_READ_ID1            0xda
40 #define MCS_READ_ID2            0xdb
41 #define MCS_READ_ID3            0xdc
42 #define MCS_LEVEL_2_KEY         0xf0
43 #define MCS_MTP_KEY             0xf1
44 #define MCS_DISCTL              0xf2
45 #define MCS_SRCCTL              0xf6
46 #define MCS_IFCTL               0xf7
47 #define MCS_PANELCTL            0xf8
48 #define MCS_PGAMMACTL           0xfa
49
50 #define S6E63M0_LCD_ID_VALUE_M2         0xA4
51 #define S6E63M0_LCD_ID_VALUE_SM2        0xB4
52 #define S6E63M0_LCD_ID_VALUE_SM2_1      0xB6
53
54 #define NUM_GAMMA_LEVELS        28
55 #define GAMMA_TABLE_COUNT       23
56
57 #define MAX_BRIGHTNESS          (NUM_GAMMA_LEVELS - 1)
58
59 /* array of gamma tables for gamma value 2.2 */
60 static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = {
61         /* 30 cd */
62         { MCS_PGAMMACTL, 0x02,
63           0x18, 0x08, 0x24, 0xA1, 0x51, 0x7B, 0xCE,
64           0xCB, 0xC2, 0xC7, 0xCB, 0xBC, 0xDA, 0xDD,
65           0xD3, 0x00, 0x53, 0x00, 0x52, 0x00, 0x6F, },
66         /* 40 cd */
67         { MCS_PGAMMACTL, 0x02,
68           0x18, 0x08, 0x24, 0x97, 0x58, 0x71, 0xCC,
69           0xCB, 0xC0, 0xC5, 0xC9, 0xBA, 0xD9, 0xDC,
70           0xD1, 0x00, 0x5B, 0x00, 0x5A, 0x00, 0x7A, },
71         /* 50 cd */
72         { MCS_PGAMMACTL, 0x02,
73           0x18, 0x08, 0x24, 0x96, 0x58, 0x72, 0xCB,
74           0xCA, 0xBF, 0xC6, 0xC9, 0xBA, 0xD6, 0xD9,
75           0xCD, 0x00, 0x61, 0x00, 0x61, 0x00, 0x83, },
76         /* 60 cd */
77         { MCS_PGAMMACTL, 0x02,
78           0x18, 0x08, 0x24, 0x91, 0x5E, 0x6E, 0xC9,
79           0xC9, 0xBD, 0xC4, 0xC9, 0xB8, 0xD3, 0xD7,
80           0xCA, 0x00, 0x69, 0x00, 0x67, 0x00, 0x8D, },
81         /* 70 cd */
82         { MCS_PGAMMACTL, 0x02,
83           0x18, 0x08, 0x24, 0x8E, 0x62, 0x6B, 0xC7,
84           0xC9, 0xBB, 0xC3, 0xC7, 0xB7, 0xD3, 0xD7,
85           0xCA, 0x00, 0x6E, 0x00, 0x6C, 0x00, 0x94, },
86         /* 80 cd */
87         { MCS_PGAMMACTL, 0x02,
88           0x18, 0x08, 0x24, 0x89, 0x68, 0x65, 0xC9,
89           0xC9, 0xBC, 0xC1, 0xC5, 0xB6, 0xD2, 0xD5,
90           0xC9, 0x00, 0x73, 0x00, 0x72, 0x00, 0x9A, },
91         /* 90 cd */
92         { MCS_PGAMMACTL, 0x02,
93           0x18, 0x08, 0x24, 0x89, 0x69, 0x64, 0xC7,
94           0xC8, 0xBB, 0xC0, 0xC5, 0xB4, 0xD2, 0xD5,
95           0xC9, 0x00, 0x77, 0x00, 0x76, 0x00, 0xA0, },
96         /* 100 cd */
97         { MCS_PGAMMACTL, 0x02,
98           0x18, 0x08, 0x24, 0x86, 0x69, 0x60, 0xC6,
99           0xC8, 0xBA, 0xBF, 0xC4, 0xB4, 0xD0, 0xD4,
100           0xC6, 0x00, 0x7C, 0x00, 0x7A, 0x00, 0xA7, },
101         /* 110 cd */
102         { MCS_PGAMMACTL, 0x02,
103           0x18, 0x08, 0x24, 0x86, 0x6A, 0x60, 0xC5,
104           0xC7, 0xBA, 0xBD, 0xC3, 0xB2, 0xD0, 0xD4,
105           0xC5, 0x00, 0x80, 0x00, 0x7E, 0x00, 0xAD, },
106         /* 120 cd */
107         { MCS_PGAMMACTL, 0x02,
108           0x18, 0x08, 0x24, 0x82, 0x6B, 0x5E, 0xC4,
109           0xC8, 0xB9, 0xBD, 0xC2, 0xB1, 0xCE, 0xD2,
110           0xC4, 0x00, 0x85, 0x00, 0x82, 0x00, 0xB3, },
111         /* 130 cd */
112         { MCS_PGAMMACTL, 0x02,
113           0x18, 0x08, 0x24, 0x8C, 0x6C, 0x60, 0xC3,
114           0xC7, 0xB9, 0xBC, 0xC1, 0xAF, 0xCE, 0xD2,
115           0xC3, 0x00, 0x88, 0x00, 0x86, 0x00, 0xB8, },
116         /* 140 cd */
117         { MCS_PGAMMACTL, 0x02,
118           0x18, 0x08, 0x24, 0x80, 0x6C, 0x5F, 0xC1,
119           0xC6, 0xB7, 0xBC, 0xC1, 0xAE, 0xCD, 0xD0,
120           0xC2, 0x00, 0x8C, 0x00, 0x8A, 0x00, 0xBE, },
121         /* 150 cd */
122         { MCS_PGAMMACTL, 0x02,
123           0x18, 0x08, 0x24, 0x80, 0x6E, 0x5F, 0xC1,
124           0xC6, 0xB6, 0xBC, 0xC0, 0xAE, 0xCC, 0xD0,
125           0xC2, 0x00, 0x8F, 0x00, 0x8D, 0x00, 0xC2, },
126         /* 160 cd */
127         { MCS_PGAMMACTL, 0x02,
128           0x18, 0x08, 0x24, 0x7F, 0x6E, 0x5F, 0xC0,
129           0xC6, 0xB5, 0xBA, 0xBF, 0xAD, 0xCB, 0xCF,
130           0xC0, 0x00, 0x94, 0x00, 0x91, 0x00, 0xC8, },
131         /* 170 cd */
132         { MCS_PGAMMACTL, 0x02,
133           0x18, 0x08, 0x24, 0x7C, 0x6D, 0x5C, 0xC0,
134           0xC6, 0xB4, 0xBB, 0xBE, 0xAD, 0xCA, 0xCF,
135           0xC0, 0x00, 0x96, 0x00, 0x94, 0x00, 0xCC, },
136         /* 180 cd */
137         { MCS_PGAMMACTL, 0x02,
138           0x18, 0x08, 0x24, 0x7B, 0x6D, 0x5B, 0xC0,
139           0xC5, 0xB3, 0xBA, 0xBE, 0xAD, 0xCA, 0xCE,
140           0xBF, 0x00, 0x99, 0x00, 0x97, 0x00, 0xD0, },
141         /* 190 cd */
142         { MCS_PGAMMACTL, 0x02,
143           0x18, 0x08, 0x24, 0x7A, 0x6D, 0x59, 0xC1,
144           0xC5, 0xB4, 0xB8, 0xBD, 0xAC, 0xC9, 0xCE,
145           0xBE, 0x00, 0x9D, 0x00, 0x9A, 0x00, 0xD5, },
146         /* 200 cd */
147         { MCS_PGAMMACTL, 0x02,
148           0x18, 0x08, 0x24, 0x79, 0x6D, 0x58, 0xC1,
149           0xC4, 0xB4, 0xB6, 0xBD, 0xAA, 0xCA, 0xCD,
150           0xBE, 0x00, 0x9F, 0x00, 0x9D, 0x00, 0xD9, },
151         /* 210 cd */
152         { MCS_PGAMMACTL, 0x02,
153           0x18, 0x08, 0x24, 0x79, 0x6D, 0x57, 0xC0,
154           0xC4, 0xB4, 0xB7, 0xBD, 0xAA, 0xC8, 0xCC,
155           0xBD, 0x00, 0xA2, 0x00, 0xA0, 0x00, 0xDD, },
156         /* 220 cd */
157         { MCS_PGAMMACTL, 0x02,
158           0x18, 0x08, 0x24, 0x78, 0x6F, 0x58, 0xBF,
159           0xC4, 0xB3, 0xB5, 0xBB, 0xA9, 0xC8, 0xCC,
160           0xBC, 0x00, 0xA6, 0x00, 0xA3, 0x00, 0xE2, },
161         /* 230 cd */
162         { MCS_PGAMMACTL, 0x02,
163           0x18, 0x08, 0x24, 0x75, 0x6F, 0x56, 0xBF,
164           0xC3, 0xB2, 0xB6, 0xBB, 0xA8, 0xC7, 0xCB,
165           0xBC, 0x00, 0xA8, 0x00, 0xA6, 0x00, 0xE6, },
166         /* 240 cd */
167         { MCS_PGAMMACTL, 0x02,
168           0x18, 0x08, 0x24, 0x76, 0x6F, 0x56, 0xC0,
169           0xC3, 0xB2, 0xB5, 0xBA, 0xA8, 0xC6, 0xCB,
170           0xBB, 0x00, 0xAA, 0x00, 0xA8, 0x00, 0xE9, },
171         /* 250 cd */
172         { MCS_PGAMMACTL, 0x02,
173           0x18, 0x08, 0x24, 0x74, 0x6D, 0x54, 0xBF,
174           0xC3, 0xB2, 0xB4, 0xBA, 0xA7, 0xC6, 0xCA,
175           0xBA, 0x00, 0xAD, 0x00, 0xAB, 0x00, 0xED, },
176         /* 260 cd */
177         { MCS_PGAMMACTL, 0x02,
178           0x18, 0x08, 0x24, 0x74, 0x6E, 0x54, 0xBD,
179           0xC2, 0xB0, 0xB5, 0xBA, 0xA7, 0xC5, 0xC9,
180           0xBA, 0x00, 0xB0, 0x00, 0xAE, 0x00, 0xF1, },
181         /* 270 cd */
182         { MCS_PGAMMACTL, 0x02,
183           0x18, 0x08, 0x24, 0x71, 0x6C, 0x50, 0xBD,
184           0xC3, 0xB0, 0xB4, 0xB8, 0xA6, 0xC6, 0xC9,
185           0xBB, 0x00, 0xB2, 0x00, 0xB1, 0x00, 0xF4, },
186         /* 280 cd */
187         { MCS_PGAMMACTL, 0x02,
188           0x18, 0x08, 0x24, 0x6E, 0x6C, 0x4D, 0xBE,
189           0xC3, 0xB1, 0xB3, 0xB8, 0xA5, 0xC6, 0xC8,
190           0xBB, 0x00, 0xB4, 0x00, 0xB3, 0x00, 0xF7, },
191         /* 290 cd */
192         { MCS_PGAMMACTL, 0x02,
193           0x18, 0x08, 0x24, 0x71, 0x70, 0x50, 0xBD,
194           0xC1, 0xB0, 0xB2, 0xB8, 0xA4, 0xC6, 0xC7,
195           0xBB, 0x00, 0xB6, 0x00, 0xB6, 0x00, 0xFA, },
196         /* 300 cd */
197         { MCS_PGAMMACTL, 0x02,
198           0x18, 0x08, 0x24, 0x70, 0x6E, 0x4E, 0xBC,
199           0xC0, 0xAF, 0xB3, 0xB8, 0xA5, 0xC5, 0xC7,
200           0xBB, 0x00, 0xB9, 0x00, 0xB8, 0x00, 0xFC, },
201 };
202
203 #define NUM_ACL_LEVELS 7
204 #define ACL_TABLE_COUNT 28
205
206 static u8 const s6e63m0_acl[NUM_ACL_LEVELS][ACL_TABLE_COUNT] = {
207         /* NULL ACL */
208         { MCS_BCMODE,
209           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212           0x00, 0x00, 0x00 },
213         /* 40P ACL */
214         { MCS_BCMODE,
215           0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
216           0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
217           0x01, 0x06, 0x0C, 0x11, 0x16, 0x1C, 0x21, 0x26,
218           0x2B, 0x31, 0x36 },
219         /* 43P ACL */
220         { MCS_BCMODE,
221           0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
222           0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
223           0x01, 0x07, 0x0C, 0x12, 0x18, 0x1E, 0x23, 0x29,
224           0x2F, 0x34, 0x3A },
225         /* 45P ACL */
226         { MCS_BCMODE,
227           0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
228           0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
229           0x01, 0x07, 0x0D, 0x13, 0x19, 0x1F, 0x25, 0x2B,
230           0x31, 0x37, 0x3D },
231         /* 47P ACL */
232         { MCS_BCMODE,
233           0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
234           0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
235           0x01, 0x07, 0x0E, 0x14, 0x1B, 0x21, 0x27, 0x2E,
236           0x34, 0x3B, 0x41 },
237         /* 48P ACL */
238         { MCS_BCMODE,
239           0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
240           0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
241           0x01, 0x08, 0x0E, 0x15, 0x1B, 0x22, 0x29, 0x2F,
242           0x36, 0x3C, 0x43 },
243         /* 50P ACL */
244         { MCS_BCMODE,
245           0x4D, 0x96, 0x1D, 0x00, 0x00, 0x01, 0xDF, 0x00,
246           0x00, 0x03, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
247           0x01, 0x08, 0x0F, 0x16, 0x1D, 0x24, 0x2A, 0x31,
248           0x38, 0x3F, 0x46 },
249 };
250
251 /* This tells us which ACL level goes with which gamma */
252 static u8 const s6e63m0_acl_per_gamma[NUM_GAMMA_LEVELS] = {
253         /* 30 - 60 cd: ACL off/NULL */
254         0, 0, 0, 0,
255         /* 70 - 250 cd: 40P ACL */
256         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
257         /* 260 - 300 cd: 50P ACL */
258         6, 6, 6, 6, 6,
259 };
260
261 /* The ELVSS backlight regulator has 5 levels */
262 #define S6E63M0_ELVSS_LEVELS 5
263
264 static u8 const s6e63m0_elvss_offsets[S6E63M0_ELVSS_LEVELS] = {
265         0x00,   /* not set */
266         0x0D,   /* 30 cd - 100 cd */
267         0x09,   /* 110 cd - 160 cd */
268         0x07,   /* 170 cd - 200 cd */
269         0x00,   /* 210 cd - 300 cd */
270 };
271
272 /* This tells us which ELVSS level goes with which gamma */
273 static u8 const s6e63m0_elvss_per_gamma[NUM_GAMMA_LEVELS] = {
274         /* 30 - 100 cd */
275         1, 1, 1, 1, 1, 1, 1, 1,
276         /* 110 - 160 cd */
277         2, 2, 2, 2, 2, 2,
278         /* 170 - 200 cd */
279         3, 3, 3, 3,
280         /* 210 - 300 cd */
281         4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
282 };
283
284 struct s6e63m0 {
285         struct device *dev;
286         int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val);
287         int (*dcs_write)(struct device *dev, const u8 *data, size_t len);
288         struct drm_panel panel;
289         struct backlight_device *bl_dev;
290         u8 lcd_type;
291         u8 elvss_pulse;
292         bool dsi_mode;
293
294         struct regulator_bulk_data supplies[2];
295         struct gpio_desc *reset_gpio;
296
297         bool prepared;
298         bool enabled;
299
300         /*
301          * This field is tested by functions directly accessing bus before
302          * transfer, transfer is skipped if it is set. In case of transfer
303          * failure or unexpected response the field is set to error value.
304          * Such construct allows to eliminate many checks in higher level
305          * functions.
306          */
307         int error;
308 };
309
310 static const struct drm_display_mode default_mode = {
311         .clock          = 25628,
312         .hdisplay       = 480,
313         .hsync_start    = 480 + 16,
314         .hsync_end      = 480 + 16 + 2,
315         .htotal         = 480 + 16 + 2 + 16,
316         .vdisplay       = 800,
317         .vsync_start    = 800 + 28,
318         .vsync_end      = 800 + 28 + 2,
319         .vtotal         = 800 + 28 + 2 + 1,
320         .width_mm       = 53,
321         .height_mm      = 89,
322         .flags          = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
323 };
324
325 static inline struct s6e63m0 *panel_to_s6e63m0(struct drm_panel *panel)
326 {
327         return container_of(panel, struct s6e63m0, panel);
328 }
329
330 static int s6e63m0_clear_error(struct s6e63m0 *ctx)
331 {
332         int ret = ctx->error;
333
334         ctx->error = 0;
335         return ret;
336 }
337
338 static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data)
339 {
340         if (ctx->error < 0)
341                 return;
342
343         ctx->error = ctx->dcs_read(ctx->dev, cmd, data);
344 }
345
346 static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
347 {
348         if (ctx->error < 0 || len == 0)
349                 return;
350
351         ctx->error = ctx->dcs_write(ctx->dev, data, len);
352 }
353
354 #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
355         ({ \
356                 static const u8 d[] = { seq }; \
357                 s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \
358         })
359
360 static int s6e63m0_check_lcd_type(struct s6e63m0 *ctx)
361 {
362         u8 id1, id2, id3;
363         int ret;
364
365         s6e63m0_dcs_read(ctx, MCS_READ_ID1, &id1);
366         s6e63m0_dcs_read(ctx, MCS_READ_ID2, &id2);
367         s6e63m0_dcs_read(ctx, MCS_READ_ID3, &id3);
368
369         ret = s6e63m0_clear_error(ctx);
370         if (ret) {
371                 dev_err(ctx->dev, "error checking LCD type (%d)\n", ret);
372                 ctx->lcd_type = 0x00;
373                 return ret;
374         }
375
376         dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
377
378         /*
379          * We attempt to detect what panel is mounted on the controller.
380          * The third ID byte represents the desired ELVSS pulse for
381          * some displays.
382          */
383         switch (id2) {
384         case S6E63M0_LCD_ID_VALUE_M2:
385                 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI M2\n");
386                 ctx->elvss_pulse = id3;
387                 break;
388         case S6E63M0_LCD_ID_VALUE_SM2:
389         case S6E63M0_LCD_ID_VALUE_SM2_1:
390                 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI SM2\n");
391                 ctx->elvss_pulse = id3;
392                 break;
393         default:
394                 dev_info(ctx->dev, "unknown LCD panel type %02x\n", id2);
395                 /* Default ELVSS pulse level */
396                 ctx->elvss_pulse = 0x16;
397                 break;
398         }
399
400         ctx->lcd_type = id2;
401
402         return 0;
403 }
404
405 static void s6e63m0_init(struct s6e63m0 *ctx)
406 {
407         /*
408          * We do not know why there is a difference in the DSI mode.
409          * (No datasheet.)
410          *
411          * In the vendor driver this sequence is called
412          * "SEQ_PANEL_CONDITION_SET" or "DCS_CMD_SEQ_PANEL_COND_SET".
413          */
414         if (ctx->dsi_mode)
415                 s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
416                                              0x01, 0x2c, 0x2c, 0x07, 0x07, 0x5f, 0xb3,
417                                              0x6d, 0x97, 0x1d, 0x3a, 0x0f, 0x00, 0x00);
418         else
419                 s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
420                                              0x01, 0x27, 0x27, 0x07, 0x07, 0x54, 0x9f,
421                                              0x63, 0x8f, 0x1a, 0x33, 0x0d, 0x00, 0x00);
422
423         s6e63m0_dcs_write_seq_static(ctx, MCS_DISCTL,
424                                      0x02, 0x03, 0x1c, 0x10, 0x10);
425         s6e63m0_dcs_write_seq_static(ctx, MCS_IFCTL,
426                                      0x03, 0x00, 0x00);
427
428         s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
429                                      0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33,
430                                      0xb6, 0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1,
431                                      0xc1, 0xb7, 0x00, 0x9c, 0x00, 0x9f, 0x00,
432                                      0xd6);
433         s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
434                                      0x01);
435
436         s6e63m0_dcs_write_seq_static(ctx, MCS_SRCCTL,
437                                      0x00, 0x8e, 0x07);
438         s6e63m0_dcs_write_seq_static(ctx, MCS_PENTILE_1, 0x6c);
439
440         s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_Y_RED,
441                                      0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
442                                      0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
443                                      0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
444                                      0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
445                                      0x21, 0x20, 0x1e, 0x1e);
446
447         s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_X_RED,
448                                      0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
449                                      0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
450                                      0x66, 0x66);
451
452         s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_Y_GREEN,
453                                      0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
454                                      0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
455                                      0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
456                                      0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
457                                      0x21, 0x20, 0x1e, 0x1e);
458
459         s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_X_GREEN,
460                                      0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
461                                      0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
462                                      0x66, 0x66);
463
464         s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_Y_BLUE,
465                                      0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
466                                      0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
467                                      0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
468                                      0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
469                                      0x21, 0x20, 0x1e, 0x1e);
470
471         s6e63m0_dcs_write_seq_static(ctx, MCS_GAMMA_DELTA_X_BLUE,
472                                      0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
473                                      0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
474                                      0x66, 0x66);
475
476         s6e63m0_dcs_write_seq_static(ctx, MCS_BCMODE,
477                                      0x4d, 0x96, 0x1d, 0x00, 0x00, 0x01, 0xdf,
478                                      0x00, 0x00, 0x03, 0x1f, 0x00, 0x00, 0x00,
479                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06,
480                                      0x09, 0x0d, 0x0f, 0x12, 0x15, 0x18);
481
482         s6e63m0_dcs_write_seq_static(ctx, MCS_TEMP_SWIRE,
483                                      0x10, 0x10, 0x0b, 0x05);
484
485         s6e63m0_dcs_write_seq_static(ctx, MCS_MIECTL1,
486                                      0x01);
487
488         s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON,
489                                      0x0b);
490 }
491
492 static int s6e63m0_power_on(struct s6e63m0 *ctx)
493 {
494         int ret;
495
496         ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
497         if (ret < 0)
498                 return ret;
499
500         msleep(25);
501
502         /* Be sure to send a reset pulse */
503         gpiod_set_value(ctx->reset_gpio, 1);
504         msleep(5);
505         gpiod_set_value(ctx->reset_gpio, 0);
506         msleep(120);
507
508         return 0;
509 }
510
511 static int s6e63m0_power_off(struct s6e63m0 *ctx)
512 {
513         int ret;
514
515         gpiod_set_value(ctx->reset_gpio, 1);
516         msleep(120);
517
518         ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
519         if (ret < 0)
520                 return ret;
521
522         return 0;
523 }
524
525 static int s6e63m0_disable(struct drm_panel *panel)
526 {
527         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
528
529         if (!ctx->enabled)
530                 return 0;
531
532         backlight_disable(ctx->bl_dev);
533
534         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
535         msleep(10);
536         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
537         msleep(120);
538
539         ctx->enabled = false;
540
541         return 0;
542 }
543
544 static int s6e63m0_unprepare(struct drm_panel *panel)
545 {
546         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
547         int ret;
548
549         if (!ctx->prepared)
550                 return 0;
551
552         s6e63m0_clear_error(ctx);
553
554         ret = s6e63m0_power_off(ctx);
555         if (ret < 0)
556                 return ret;
557
558         ctx->prepared = false;
559
560         return 0;
561 }
562
563 static int s6e63m0_prepare(struct drm_panel *panel)
564 {
565         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
566         int ret;
567
568         if (ctx->prepared)
569                 return 0;
570
571         ret = s6e63m0_power_on(ctx);
572         if (ret < 0)
573                 return ret;
574
575         /* Magic to unlock level 2 control of the display */
576         s6e63m0_dcs_write_seq_static(ctx, MCS_LEVEL_2_KEY, 0x5a, 0x5a);
577         /* Magic to unlock MTP reading */
578         s6e63m0_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a);
579
580         ret = s6e63m0_check_lcd_type(ctx);
581         if (ret < 0)
582                 return ret;
583
584         s6e63m0_init(ctx);
585
586         ret = s6e63m0_clear_error(ctx);
587
588         if (ret < 0)
589                 s6e63m0_unprepare(panel);
590
591         ctx->prepared = true;
592
593         return ret;
594 }
595
596 static int s6e63m0_enable(struct drm_panel *panel)
597 {
598         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
599
600         if (ctx->enabled)
601                 return 0;
602
603         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
604         msleep(120);
605         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
606         msleep(10);
607
608         s6e63m0_dcs_write_seq_static(ctx, MCS_ERROR_CHECK,
609                                      0xE7, 0x14, 0x60, 0x17, 0x0A, 0x49, 0xC3,
610                                      0x8F, 0x19, 0x64, 0x91, 0x84, 0x76, 0x20,
611                                      0x0F, 0x00);
612
613         backlight_enable(ctx->bl_dev);
614
615         ctx->enabled = true;
616
617         return 0;
618 }
619
620 static int s6e63m0_get_modes(struct drm_panel *panel,
621                              struct drm_connector *connector)
622 {
623         struct drm_display_mode *mode;
624         static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
625
626         mode = drm_mode_duplicate(connector->dev, &default_mode);
627         if (!mode) {
628                 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
629                         default_mode.hdisplay, default_mode.vdisplay,
630                         drm_mode_vrefresh(&default_mode));
631                 return -ENOMEM;
632         }
633
634         connector->display_info.width_mm = mode->width_mm;
635         connector->display_info.height_mm = mode->height_mm;
636         drm_display_info_set_bus_formats(&connector->display_info,
637                                          &bus_format, 1);
638         connector->display_info.bus_flags = DRM_BUS_FLAG_DE_LOW |
639                 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
640
641         drm_mode_set_name(mode);
642
643         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
644         drm_mode_probed_add(connector, mode);
645
646         return 1;
647 }
648
649 static const struct drm_panel_funcs s6e63m0_drm_funcs = {
650         .disable        = s6e63m0_disable,
651         .unprepare      = s6e63m0_unprepare,
652         .prepare        = s6e63m0_prepare,
653         .enable         = s6e63m0_enable,
654         .get_modes      = s6e63m0_get_modes,
655 };
656
657 static int s6e63m0_set_brightness(struct backlight_device *bd)
658 {
659         struct s6e63m0 *ctx = bl_get_data(bd);
660         int brightness = bd->props.brightness;
661         u8 elvss_val;
662         u8 elvss_cmd_set[5];
663         int i;
664
665         /* Adjust ELVSS to candela level */
666         i = s6e63m0_elvss_per_gamma[brightness];
667         elvss_val = ctx->elvss_pulse + s6e63m0_elvss_offsets[i];
668         if (elvss_val > 0x1f)
669                 elvss_val = 0x1f;
670         elvss_cmd_set[0] = MCS_TEMP_SWIRE;
671         elvss_cmd_set[1] = elvss_val;
672         elvss_cmd_set[2] = elvss_val;
673         elvss_cmd_set[3] = elvss_val;
674         elvss_cmd_set[4] = elvss_val;
675         s6e63m0_dcs_write(ctx, elvss_cmd_set, 5);
676
677         /* Update the ACL per gamma value */
678         i = s6e63m0_acl_per_gamma[brightness];
679         s6e63m0_dcs_write(ctx, s6e63m0_acl[i],
680                           ARRAY_SIZE(s6e63m0_acl[i]));
681
682         /* Update gamma table */
683         s6e63m0_dcs_write(ctx, s6e63m0_gamma_22[brightness],
684                           ARRAY_SIZE(s6e63m0_gamma_22[brightness]));
685         s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 0x03);
686
687
688         return s6e63m0_clear_error(ctx);
689 }
690
691 static const struct backlight_ops s6e63m0_backlight_ops = {
692         .update_status  = s6e63m0_set_brightness,
693 };
694
695 static int s6e63m0_backlight_register(struct s6e63m0 *ctx, u32 max_brightness)
696 {
697         struct backlight_properties props = {
698                 .type           = BACKLIGHT_RAW,
699                 .brightness     = max_brightness,
700                 .max_brightness = max_brightness,
701         };
702         struct device *dev = ctx->dev;
703         int ret = 0;
704
705         ctx->bl_dev = devm_backlight_device_register(dev, "panel", dev, ctx,
706                                                      &s6e63m0_backlight_ops,
707                                                      &props);
708         if (IS_ERR(ctx->bl_dev)) {
709                 ret = PTR_ERR(ctx->bl_dev);
710                 dev_err(dev, "error registering backlight device (%d)\n", ret);
711         }
712
713         return ret;
714 }
715
716 int s6e63m0_probe(struct device *dev,
717                   int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
718                   int (*dcs_write)(struct device *dev, const u8 *data, size_t len),
719                   bool dsi_mode)
720 {
721         struct s6e63m0 *ctx;
722         u32 max_brightness;
723         int ret;
724
725         ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL);
726         if (!ctx)
727                 return -ENOMEM;
728
729         ctx->dsi_mode = dsi_mode;
730         ctx->dcs_read = dcs_read;
731         ctx->dcs_write = dcs_write;
732         dev_set_drvdata(dev, ctx);
733
734         ctx->dev = dev;
735         ctx->enabled = false;
736         ctx->prepared = false;
737
738         ret = device_property_read_u32(dev, "max-brightness", &max_brightness);
739         if (ret)
740                 max_brightness = MAX_BRIGHTNESS;
741         if (max_brightness > MAX_BRIGHTNESS) {
742                 dev_err(dev, "illegal max brightness specified\n");
743                 max_brightness = MAX_BRIGHTNESS;
744         }
745
746         ctx->supplies[0].supply = "vdd3";
747         ctx->supplies[1].supply = "vci";
748         ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
749                                       ctx->supplies);
750         if (ret < 0) {
751                 dev_err(dev, "failed to get regulators: %d\n", ret);
752                 return ret;
753         }
754
755         ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
756         if (IS_ERR(ctx->reset_gpio)) {
757                 dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio));
758                 return PTR_ERR(ctx->reset_gpio);
759         }
760
761         drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
762                        dsi_mode ? DRM_MODE_CONNECTOR_DSI :
763                        DRM_MODE_CONNECTOR_DPI);
764
765         ret = s6e63m0_backlight_register(ctx, max_brightness);
766         if (ret < 0)
767                 return ret;
768
769         drm_panel_add(&ctx->panel);
770
771         return 0;
772 }
773 EXPORT_SYMBOL_GPL(s6e63m0_probe);
774
775 int s6e63m0_remove(struct device *dev)
776 {
777         struct s6e63m0 *ctx = dev_get_drvdata(dev);
778
779         drm_panel_remove(&ctx->panel);
780
781         return 0;
782 }
783 EXPORT_SYMBOL_GPL(s6e63m0_remove);
784
785 MODULE_AUTHOR("PaweÅ‚ Chmiel <pawel.mikolaj.chmiel@gmail.com>");
786 MODULE_DESCRIPTION("s6e63m0 LCD Driver");
787 MODULE_LICENSE("GPL v2");