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