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