Merge tag 'icc-5.10-rc2' of https://git.linaro.org/people/georgi.djakov/linux into...
[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
20 #include <video/mipi_display.h>
21
22 #include "panel-samsung-s6e63m0.h"
23
24 /* Manufacturer Command Set */
25 #define MCS_ELVSS_ON                0xb1
26 #define MCS_MIECTL1                0xc0
27 #define MCS_BCMODE                              0xc1
28 #define MCS_ERROR_CHECK         0xd5
29 #define MCS_READ_ID1            0xda
30 #define MCS_READ_ID2            0xdb
31 #define MCS_READ_ID3            0xdc
32 #define MCS_LEVEL_2_KEY         0xf0
33 #define MCS_MTP_KEY             0xf1
34 #define MCS_DISCTL   0xf2
35 #define MCS_SRCCTL           0xf6
36 #define MCS_IFCTL                       0xf7
37 #define MCS_PANELCTL         0xF8
38 #define MCS_PGAMMACTL                   0xfa
39
40 #define S6E63M0_LCD_ID_VALUE_M2         0xA4
41 #define S6E63M0_LCD_ID_VALUE_SM2        0xB4
42 #define S6E63M0_LCD_ID_VALUE_SM2_1      0xB6
43
44 #define NUM_GAMMA_LEVELS             11
45 #define GAMMA_TABLE_COUNT           23
46
47 #define MAX_BRIGHTNESS              (NUM_GAMMA_LEVELS - 1)
48
49 /* array of gamma tables for gamma value 2.2 */
50 static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = {
51         { MCS_PGAMMACTL, 0x00,
52           0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8,
53           0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7,
54           0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 },
55         { MCS_PGAMMACTL, 0x00,
56           0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0,
57           0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF,
58           0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 },
59         { MCS_PGAMMACTL, 0x00,
60           0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF,
61           0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC,
62           0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D },
63         { MCS_PGAMMACTL, 0x00,
64           0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC,
65           0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9,
66           0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E },
67         { MCS_PGAMMACTL, 0x00,
68           0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB,
69           0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8,
70           0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB },
71         { MCS_PGAMMACTL, 0x00,
72           0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA,
73           0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6,
74           0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA },
75         { MCS_PGAMMACTL, 0x00,
76           0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8,
77           0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4,
78           0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 },
79         { MCS_PGAMMACTL, 0x00,
80           0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9,
81           0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3,
82           0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA },
83         { MCS_PGAMMACTL, 0x00,
84           0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6,
85           0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2,
86           0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 },
87         { MCS_PGAMMACTL, 0x00,
88           0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6,
89           0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1,
90           0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 },
91         { MCS_PGAMMACTL, 0x00,
92           0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6,
93           0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0,
94           0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb },
95 };
96
97 struct s6e63m0 {
98         struct device *dev;
99         int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val);
100         int (*dcs_write)(struct device *dev, const u8 *data, size_t len);
101         struct drm_panel panel;
102         struct backlight_device *bl_dev;
103         u8 lcd_type;
104
105         struct regulator_bulk_data supplies[2];
106         struct gpio_desc *reset_gpio;
107
108         bool prepared;
109         bool enabled;
110
111         /*
112          * This field is tested by functions directly accessing bus before
113          * transfer, transfer is skipped if it is set. In case of transfer
114          * failure or unexpected response the field is set to error value.
115          * Such construct allows to eliminate many checks in higher level
116          * functions.
117          */
118         int error;
119 };
120
121 static const struct drm_display_mode default_mode = {
122         .clock          = 25628,
123         .hdisplay       = 480,
124         .hsync_start    = 480 + 16,
125         .hsync_end      = 480 + 16 + 2,
126         .htotal         = 480 + 16 + 2 + 16,
127         .vdisplay       = 800,
128         .vsync_start    = 800 + 28,
129         .vsync_end      = 800 + 28 + 2,
130         .vtotal         = 800 + 28 + 2 + 1,
131         .width_mm       = 53,
132         .height_mm      = 89,
133         .flags          = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
134 };
135
136 static inline struct s6e63m0 *panel_to_s6e63m0(struct drm_panel *panel)
137 {
138         return container_of(panel, struct s6e63m0, panel);
139 }
140
141 static int s6e63m0_clear_error(struct s6e63m0 *ctx)
142 {
143         int ret = ctx->error;
144
145         ctx->error = 0;
146         return ret;
147 }
148
149 static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data)
150 {
151         if (ctx->error < 0)
152                 return;
153
154         ctx->error = ctx->dcs_read(ctx->dev, cmd, data);
155 }
156
157 static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
158 {
159         if (ctx->error < 0 || len == 0)
160                 return;
161
162         ctx->error = ctx->dcs_write(ctx->dev, data, len);
163 }
164
165 #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
166         ({ \
167                 static const u8 d[] = { seq }; \
168                 s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \
169         })
170
171 static int s6e63m0_check_lcd_type(struct s6e63m0 *ctx)
172 {
173         u8 id1, id2, id3;
174         int ret;
175
176         s6e63m0_dcs_read(ctx, MCS_READ_ID1, &id1);
177         s6e63m0_dcs_read(ctx, MCS_READ_ID2, &id2);
178         s6e63m0_dcs_read(ctx, MCS_READ_ID3, &id3);
179
180         ret = s6e63m0_clear_error(ctx);
181         if (ret) {
182                 dev_err(ctx->dev, "error checking LCD type (%d)\n", ret);
183                 ctx->lcd_type = 0x00;
184                 return ret;
185         }
186
187         dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
188
189         /* We attempt to detect what panel is mounted on the controller */
190         switch (id2) {
191         case S6E63M0_LCD_ID_VALUE_M2:
192                 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI M2\n");
193                 break;
194         case S6E63M0_LCD_ID_VALUE_SM2:
195         case S6E63M0_LCD_ID_VALUE_SM2_1:
196                 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI SM2\n");
197                 break;
198         default:
199                 dev_info(ctx->dev, "unknown LCD panel type %02x\n", id2);
200                 break;
201         }
202
203         ctx->lcd_type = id2;
204
205         return 0;
206 }
207
208 static void s6e63m0_init(struct s6e63m0 *ctx)
209 {
210         s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
211                                      0x01, 0x27, 0x27, 0x07, 0x07, 0x54, 0x9f,
212                                      0x63, 0x86, 0x1a, 0x33, 0x0d, 0x00, 0x00);
213
214         s6e63m0_dcs_write_seq_static(ctx, MCS_DISCTL,
215                                      0x02, 0x03, 0x1c, 0x10, 0x10);
216         s6e63m0_dcs_write_seq_static(ctx, MCS_IFCTL,
217                                      0x03, 0x00, 0x00);
218
219         s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
220                                      0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33,
221                                      0xb6, 0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1,
222                                      0xc1, 0xb7, 0x00, 0x9c, 0x00, 0x9f, 0x00,
223                                      0xd6);
224         s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
225                                      0x01);
226
227         s6e63m0_dcs_write_seq_static(ctx, MCS_SRCCTL,
228                                      0x00, 0x8c, 0x07);
229         s6e63m0_dcs_write_seq_static(ctx, 0xb3,
230                                      0xc);
231
232         s6e63m0_dcs_write_seq_static(ctx, 0xb5,
233                                      0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
234                                      0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
235                                      0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
236                                      0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
237                                      0x21, 0x20, 0x1e, 0x1e);
238
239         s6e63m0_dcs_write_seq_static(ctx, 0xb6,
240                                      0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
241                                      0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
242                                      0x66, 0x66);
243
244         s6e63m0_dcs_write_seq_static(ctx, 0xb7,
245                                      0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
246                                      0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
247                                      0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
248                                      0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
249                                      0x21, 0x20, 0x1e, 0x1e, 0x00, 0x00, 0x11,
250                                      0x22, 0x33, 0x44, 0x44, 0x44, 0x55, 0x55,
251                                      0x66, 0x66, 0x66, 0x66, 0x66, 0x66);
252
253         s6e63m0_dcs_write_seq_static(ctx, 0xb9,
254                                      0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
255                                      0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
256                                      0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
257                                      0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
258                                      0x21, 0x20, 0x1e, 0x1e);
259
260         s6e63m0_dcs_write_seq_static(ctx, 0xba,
261                                      0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
262                                      0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
263                                      0x66, 0x66);
264
265         s6e63m0_dcs_write_seq_static(ctx, MCS_BCMODE,
266                                      0x4d, 0x96, 0x1d, 0x00, 0x00, 0x01, 0xdf,
267                                      0x00, 0x00, 0x03, 0x1f, 0x00, 0x00, 0x00,
268                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06,
269                                      0x09, 0x0d, 0x0f, 0x12, 0x15, 0x18);
270
271         s6e63m0_dcs_write_seq_static(ctx, 0xb2,
272                                      0x10, 0x10, 0x0b, 0x05);
273
274         s6e63m0_dcs_write_seq_static(ctx, MCS_MIECTL1,
275                                      0x01);
276
277         s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON,
278                                      0x0b);
279 }
280
281 static int s6e63m0_power_on(struct s6e63m0 *ctx)
282 {
283         int ret;
284
285         ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
286         if (ret < 0)
287                 return ret;
288
289         msleep(25);
290
291         /* Be sure to send a reset pulse */
292         gpiod_set_value(ctx->reset_gpio, 1);
293         msleep(5);
294         gpiod_set_value(ctx->reset_gpio, 0);
295         msleep(120);
296
297         return 0;
298 }
299
300 static int s6e63m0_power_off(struct s6e63m0 *ctx)
301 {
302         int ret;
303
304         gpiod_set_value(ctx->reset_gpio, 1);
305         msleep(120);
306
307         ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
308         if (ret < 0)
309                 return ret;
310
311         return 0;
312 }
313
314 static int s6e63m0_disable(struct drm_panel *panel)
315 {
316         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
317
318         if (!ctx->enabled)
319                 return 0;
320
321         backlight_disable(ctx->bl_dev);
322
323         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
324         msleep(10);
325         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
326         msleep(120);
327
328         ctx->enabled = false;
329
330         return 0;
331 }
332
333 static int s6e63m0_unprepare(struct drm_panel *panel)
334 {
335         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
336         int ret;
337
338         if (!ctx->prepared)
339                 return 0;
340
341         s6e63m0_clear_error(ctx);
342
343         ret = s6e63m0_power_off(ctx);
344         if (ret < 0)
345                 return ret;
346
347         ctx->prepared = false;
348
349         return 0;
350 }
351
352 static int s6e63m0_prepare(struct drm_panel *panel)
353 {
354         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
355         int ret;
356
357         if (ctx->prepared)
358                 return 0;
359
360         ret = s6e63m0_power_on(ctx);
361         if (ret < 0)
362                 return ret;
363
364         /* Magic to unlock level 2 control of the display */
365         s6e63m0_dcs_write_seq_static(ctx, MCS_LEVEL_2_KEY, 0x5a, 0x5a);
366         /* Magic to unlock MTP reading */
367         s6e63m0_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a);
368
369         ret = s6e63m0_check_lcd_type(ctx);
370         if (ret < 0)
371                 return ret;
372
373         s6e63m0_init(ctx);
374
375         ret = s6e63m0_clear_error(ctx);
376
377         if (ret < 0)
378                 s6e63m0_unprepare(panel);
379
380         ctx->prepared = true;
381
382         return ret;
383 }
384
385 static int s6e63m0_enable(struct drm_panel *panel)
386 {
387         struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
388
389         if (ctx->enabled)
390                 return 0;
391
392         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
393         msleep(120);
394         s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
395         msleep(10);
396
397         s6e63m0_dcs_write_seq_static(ctx, MCS_ERROR_CHECK,
398                                      0xE7, 0x14, 0x60, 0x17, 0x0A, 0x49, 0xC3,
399                                      0x8F, 0x19, 0x64, 0x91, 0x84, 0x76, 0x20,
400                                      0x0F, 0x00);
401
402         backlight_enable(ctx->bl_dev);
403
404         ctx->enabled = true;
405
406         return 0;
407 }
408
409 static int s6e63m0_get_modes(struct drm_panel *panel,
410                              struct drm_connector *connector)
411 {
412         struct drm_display_mode *mode;
413
414         mode = drm_mode_duplicate(connector->dev, &default_mode);
415         if (!mode) {
416                 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
417                         default_mode.hdisplay, default_mode.vdisplay,
418                         drm_mode_vrefresh(&default_mode));
419                 return -ENOMEM;
420         }
421
422         drm_mode_set_name(mode);
423
424         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
425         drm_mode_probed_add(connector, mode);
426
427         return 1;
428 }
429
430 static const struct drm_panel_funcs s6e63m0_drm_funcs = {
431         .disable        = s6e63m0_disable,
432         .unprepare      = s6e63m0_unprepare,
433         .prepare        = s6e63m0_prepare,
434         .enable         = s6e63m0_enable,
435         .get_modes      = s6e63m0_get_modes,
436 };
437
438 static int s6e63m0_set_brightness(struct backlight_device *bd)
439 {
440         struct s6e63m0 *ctx = bl_get_data(bd);
441
442         int brightness = bd->props.brightness;
443
444         /* disable and set new gamma */
445         s6e63m0_dcs_write(ctx, s6e63m0_gamma_22[brightness],
446                           ARRAY_SIZE(s6e63m0_gamma_22[brightness]));
447
448         /* update gamma table. */
449         s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 0x01);
450
451         return s6e63m0_clear_error(ctx);
452 }
453
454 static const struct backlight_ops s6e63m0_backlight_ops = {
455         .update_status  = s6e63m0_set_brightness,
456 };
457
458 static int s6e63m0_backlight_register(struct s6e63m0 *ctx)
459 {
460         struct backlight_properties props = {
461                 .type           = BACKLIGHT_RAW,
462                 .brightness     = MAX_BRIGHTNESS,
463                 .max_brightness = MAX_BRIGHTNESS
464         };
465         struct device *dev = ctx->dev;
466         int ret = 0;
467
468         ctx->bl_dev = devm_backlight_device_register(dev, "panel", dev, ctx,
469                                                      &s6e63m0_backlight_ops,
470                                                      &props);
471         if (IS_ERR(ctx->bl_dev)) {
472                 ret = PTR_ERR(ctx->bl_dev);
473                 dev_err(dev, "error registering backlight device (%d)\n", ret);
474         }
475
476         return ret;
477 }
478
479 int s6e63m0_probe(struct device *dev,
480                   int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
481                   int (*dcs_write)(struct device *dev, const u8 *data, size_t len),
482                   bool dsi_mode)
483 {
484         struct s6e63m0 *ctx;
485         int ret;
486
487         ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL);
488         if (!ctx)
489                 return -ENOMEM;
490
491         ctx->dcs_read = dcs_read;
492         ctx->dcs_write = dcs_write;
493         dev_set_drvdata(dev, ctx);
494
495         ctx->dev = dev;
496         ctx->enabled = false;
497         ctx->prepared = false;
498
499         ctx->supplies[0].supply = "vdd3";
500         ctx->supplies[1].supply = "vci";
501         ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
502                                       ctx->supplies);
503         if (ret < 0) {
504                 dev_err(dev, "failed to get regulators: %d\n", ret);
505                 return ret;
506         }
507
508         ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
509         if (IS_ERR(ctx->reset_gpio)) {
510                 dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio));
511                 return PTR_ERR(ctx->reset_gpio);
512         }
513
514         drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
515                        dsi_mode ? DRM_MODE_CONNECTOR_DSI :
516                        DRM_MODE_CONNECTOR_DPI);
517
518         ret = s6e63m0_backlight_register(ctx);
519         if (ret < 0)
520                 return ret;
521
522         drm_panel_add(&ctx->panel);
523
524         return 0;
525 }
526 EXPORT_SYMBOL_GPL(s6e63m0_probe);
527
528 int s6e63m0_remove(struct device *dev)
529 {
530         struct s6e63m0 *ctx = dev_get_drvdata(dev);
531
532         drm_panel_remove(&ctx->panel);
533
534         return 0;
535 }
536 EXPORT_SYMBOL_GPL(s6e63m0_remove);
537
538 MODULE_AUTHOR("PaweÅ‚ Chmiel <pawel.mikolaj.chmiel@gmail.com>");
539 MODULE_DESCRIPTION("s6e63m0 LCD Driver");
540 MODULE_LICENSE("GPL v2");