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