Merge tag 'drm-misc-next-2019-10-09-2' of git://anongit.freedesktop.org/drm/drm-misc...
[linux-2.6-microblaze.git] / drivers / gpu / drm / panel / panel-samsung-s6e63j0x03.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * MIPI-DSI based S6E63J0X03 AMOLED lcd 1.63 inch panel driver.
4  *
5  * Copyright (c) 2014-2017 Samsung Electronics Co., Ltd
6  *
7  * Inki Dae <inki.dae@samsung.com>
8  * Hoegeun Kwon <hoegeun.kwon@samsung.com>
9  */
10
11 #include <linux/backlight.h>
12 #include <linux/delay.h>
13 #include <linux/gpio/consumer.h>
14 #include <linux/module.h>
15 #include <linux/regulator/consumer.h>
16
17 #include <video/mipi_display.h>
18
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 #include <drm/drm_print.h>
23
24 #define MCS_LEVEL2_KEY          0xf0
25 #define MCS_MTP_KEY             0xf1
26 #define MCS_MTP_SET3            0xd4
27
28 #define MAX_BRIGHTNESS          100
29 #define DEFAULT_BRIGHTNESS      80
30
31 #define NUM_GAMMA_STEPS         9
32 #define GAMMA_CMD_CNT           28
33
34 #define FIRST_COLUMN 20
35
36 struct s6e63j0x03 {
37         struct device *dev;
38         struct drm_panel panel;
39         struct backlight_device *bl_dev;
40
41         struct regulator_bulk_data supplies[2];
42         struct gpio_desc *reset_gpio;
43 };
44
45 static const struct drm_display_mode default_mode = {
46         .clock = 4649,
47         .hdisplay = 320,
48         .hsync_start = 320 + 1,
49         .hsync_end = 320 + 1 + 1,
50         .htotal = 320 + 1 + 1 + 1,
51         .vdisplay = 320,
52         .vsync_start = 320 + 150,
53         .vsync_end = 320 + 150 + 1,
54         .vtotal = 320 + 150 + 1 + 2,
55         .vrefresh = 30,
56         .flags = 0,
57 };
58
59 static const unsigned char gamma_tbl[NUM_GAMMA_STEPS][GAMMA_CMD_CNT] = {
60         {       /* Gamma 10 */
61                 MCS_MTP_SET3,
62                 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x52, 0x6b, 0x6f, 0x26,
63                 0x28, 0x2d, 0x28, 0x26, 0x27, 0x33, 0x34, 0x32, 0x36, 0x36,
64                 0x35, 0x00, 0xab, 0x00, 0xae, 0x00, 0xbf
65         },
66         {       /* gamma 30 */
67                 MCS_MTP_SET3,
68                 0x00, 0x00, 0x00, 0x70, 0x7f, 0x7f, 0x4e, 0x64, 0x69, 0x26,
69                 0x27, 0x2a, 0x28, 0x29, 0x27, 0x31, 0x32, 0x31, 0x35, 0x34,
70                 0x35, 0x00, 0xc4, 0x00, 0xca, 0x00, 0xdc
71         },
72         {       /* gamma 60 */
73                 MCS_MTP_SET3,
74                 0x00, 0x00, 0x00, 0x65, 0x7b, 0x7d, 0x5f, 0x67, 0x68, 0x2a,
75                 0x28, 0x29, 0x28, 0x2a, 0x27, 0x31, 0x2f, 0x30, 0x34, 0x33,
76                 0x34, 0x00, 0xd9, 0x00, 0xe4, 0x00, 0xf5
77         },
78         {       /* gamma 90 */
79                 MCS_MTP_SET3,
80                 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x71, 0x67, 0x6a, 0x6c, 0x29,
81                 0x28, 0x28, 0x28, 0x29, 0x27, 0x30, 0x2e, 0x30, 0x32, 0x31,
82                 0x31, 0x00, 0xea, 0x00, 0xf6, 0x01, 0x09
83         },
84         {       /* gamma 120 */
85                 MCS_MTP_SET3,
86                 0x00, 0x00, 0x00, 0x3d, 0x66, 0x68, 0x69, 0x69, 0x69, 0x28,
87                 0x28, 0x27, 0x28, 0x28, 0x27, 0x30, 0x2e, 0x2f, 0x31, 0x31,
88                 0x30, 0x00, 0xf9, 0x01, 0x05, 0x01, 0x1b
89         },
90         {       /* gamma 150 */
91                 MCS_MTP_SET3,
92                 0x00, 0x00, 0x00, 0x31, 0x51, 0x53, 0x66, 0x66, 0x67, 0x28,
93                 0x29, 0x27, 0x28, 0x27, 0x27, 0x2e, 0x2d, 0x2e, 0x31, 0x31,
94                 0x30, 0x01, 0x04, 0x01, 0x11, 0x01, 0x29
95         },
96         {       /* gamma 200 */
97                 MCS_MTP_SET3,
98                 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x51, 0x67, 0x65, 0x65, 0x29,
99                 0x2a, 0x28, 0x27, 0x25, 0x26, 0x2d, 0x2c, 0x2c, 0x30, 0x30,
100                 0x30, 0x01, 0x14, 0x01, 0x23, 0x01, 0x3b
101         },
102         {       /* gamma 240 */
103                 MCS_MTP_SET3,
104                 0x00, 0x00, 0x00, 0x2c, 0x4d, 0x50, 0x65, 0x63, 0x64, 0x2a,
105                 0x2c, 0x29, 0x26, 0x24, 0x25, 0x2c, 0x2b, 0x2b, 0x30, 0x30,
106                 0x30, 0x01, 0x1e, 0x01, 0x2f, 0x01, 0x47
107         },
108         {       /* gamma 300 */
109                 MCS_MTP_SET3,
110                 0x00, 0x00, 0x00, 0x38, 0x61, 0x64, 0x65, 0x63, 0x64, 0x28,
111                 0x2a, 0x27, 0x26, 0x23, 0x25, 0x2b, 0x2b, 0x2a, 0x30, 0x2f,
112                 0x30, 0x01, 0x2d, 0x01, 0x3f, 0x01, 0x57
113         }
114 };
115
116 static inline struct s6e63j0x03 *panel_to_s6e63j0x03(struct drm_panel *panel)
117 {
118         return container_of(panel, struct s6e63j0x03, panel);
119 }
120
121 static inline ssize_t s6e63j0x03_dcs_write_seq(struct s6e63j0x03 *ctx,
122                                         const void *seq, size_t len)
123 {
124         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
125
126         return mipi_dsi_dcs_write_buffer(dsi, seq, len);
127 }
128
129 #define s6e63j0x03_dcs_write_seq_static(ctx, seq...)                    \
130         ({                                                              \
131                 static const u8 d[] = { seq };                          \
132                 s6e63j0x03_dcs_write_seq(ctx, d, ARRAY_SIZE(d));        \
133         })
134
135 static inline int s6e63j0x03_enable_lv2_command(struct s6e63j0x03 *ctx)
136 {
137         return s6e63j0x03_dcs_write_seq_static(ctx, MCS_LEVEL2_KEY, 0x5a, 0x5a);
138 }
139
140 static inline int s6e63j0x03_apply_mtp_key(struct s6e63j0x03 *ctx, bool on)
141 {
142         if (on)
143                 return s6e63j0x03_dcs_write_seq_static(ctx,
144                                 MCS_MTP_KEY, 0x5a, 0x5a);
145
146         return s6e63j0x03_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0xa5, 0xa5);
147 }
148
149 static int s6e63j0x03_power_on(struct s6e63j0x03 *ctx)
150 {
151         int ret;
152
153         ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
154         if (ret < 0)
155                 return ret;
156
157         msleep(30);
158
159         gpiod_set_value(ctx->reset_gpio, 1);
160         usleep_range(1000, 2000);
161         gpiod_set_value(ctx->reset_gpio, 0);
162         usleep_range(5000, 6000);
163
164         return 0;
165 }
166
167 static int s6e63j0x03_power_off(struct s6e63j0x03 *ctx)
168 {
169         return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
170 }
171
172 static unsigned int s6e63j0x03_get_brightness_index(unsigned int brightness)
173 {
174         unsigned int index;
175
176         index = brightness / (MAX_BRIGHTNESS / NUM_GAMMA_STEPS);
177
178         if (index >= NUM_GAMMA_STEPS)
179                 index = NUM_GAMMA_STEPS - 1;
180
181         return index;
182 }
183
184 static int s6e63j0x03_update_gamma(struct s6e63j0x03 *ctx,
185                                         unsigned int brightness)
186 {
187         struct backlight_device *bl_dev = ctx->bl_dev;
188         unsigned int index = s6e63j0x03_get_brightness_index(brightness);
189         int ret;
190
191         ret = s6e63j0x03_apply_mtp_key(ctx, true);
192         if (ret < 0)
193                 return ret;
194
195         ret = s6e63j0x03_dcs_write_seq(ctx, gamma_tbl[index], GAMMA_CMD_CNT);
196         if (ret < 0)
197                 return ret;
198
199         ret = s6e63j0x03_apply_mtp_key(ctx, false);
200         if (ret < 0)
201                 return ret;
202
203         bl_dev->props.brightness = brightness;
204
205         return 0;
206 }
207
208 static int s6e63j0x03_set_brightness(struct backlight_device *bl_dev)
209 {
210         struct s6e63j0x03 *ctx = bl_get_data(bl_dev);
211         unsigned int brightness = bl_dev->props.brightness;
212
213         return s6e63j0x03_update_gamma(ctx, brightness);
214 }
215
216 static const struct backlight_ops s6e63j0x03_bl_ops = {
217         .update_status = s6e63j0x03_set_brightness,
218 };
219
220 static int s6e63j0x03_disable(struct drm_panel *panel)
221 {
222         struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel);
223         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
224         int ret;
225
226         ret = mipi_dsi_dcs_set_display_off(dsi);
227         if (ret < 0)
228                 return ret;
229
230         ctx->bl_dev->props.power = FB_BLANK_NORMAL;
231
232         ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
233         if (ret < 0)
234                 return ret;
235
236         msleep(120);
237
238         return 0;
239 }
240
241 static int s6e63j0x03_unprepare(struct drm_panel *panel)
242 {
243         struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel);
244         int ret;
245
246         ret = s6e63j0x03_power_off(ctx);
247         if (ret < 0)
248                 return ret;
249
250         ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
251
252         return 0;
253 }
254
255 static int s6e63j0x03_panel_init(struct s6e63j0x03 *ctx)
256 {
257         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
258         int ret;
259
260         ret = s6e63j0x03_enable_lv2_command(ctx);
261         if (ret < 0)
262                 return ret;
263
264         ret = s6e63j0x03_apply_mtp_key(ctx, true);
265         if (ret < 0)
266                 return ret;
267
268         /* set porch adjustment */
269         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf2, 0x1c, 0x28);
270         if (ret < 0)
271                 return ret;
272
273         /* set frame freq */
274         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb5, 0x00, 0x02, 0x00);
275         if (ret < 0)
276                 return ret;
277
278         /* set caset, paset */
279         ret = mipi_dsi_dcs_set_column_address(dsi, FIRST_COLUMN,
280                 default_mode.hdisplay - 1 + FIRST_COLUMN);
281         if (ret < 0)
282                 return ret;
283
284         ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1);
285         if (ret < 0)
286                 return ret;
287
288         /* set ltps timming 0, 1 */
289         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf8, 0x08, 0x08, 0x08, 0x17,
290                 0x00, 0x2a, 0x02, 0x26, 0x00, 0x00, 0x02, 0x00, 0x00);
291         if (ret < 0)
292                 return ret;
293
294         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf7, 0x02);
295         if (ret < 0)
296                 return ret;
297
298         /* set param pos te_edge */
299         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb0, 0x01);
300         if (ret < 0)
301                 return ret;
302
303         /* set te rising edge */
304         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xe2, 0x0f);
305         if (ret < 0)
306                 return ret;
307
308         /* set param pos default */
309         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb0, 0x00);
310         if (ret < 0)
311                 return ret;
312
313         ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
314         if (ret < 0)
315                 return ret;
316
317         ret = s6e63j0x03_apply_mtp_key(ctx, false);
318         if (ret < 0)
319                 return ret;
320
321         return 0;
322 }
323
324 static int s6e63j0x03_prepare(struct drm_panel *panel)
325 {
326         struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel);
327         int ret;
328
329         ret = s6e63j0x03_power_on(ctx);
330         if (ret < 0)
331                 return ret;
332
333         ret = s6e63j0x03_panel_init(ctx);
334         if (ret < 0)
335                 goto err;
336
337         ctx->bl_dev->props.power = FB_BLANK_NORMAL;
338
339         return 0;
340
341 err:
342         s6e63j0x03_power_off(ctx);
343         return ret;
344 }
345
346 static int s6e63j0x03_enable(struct drm_panel *panel)
347 {
348         struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel);
349         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
350         int ret;
351
352         msleep(120);
353
354         ret = s6e63j0x03_apply_mtp_key(ctx, true);
355         if (ret < 0)
356                 return ret;
357
358         /* set elvss_cond */
359         ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb1, 0x00, 0x09);
360         if (ret < 0)
361                 return ret;
362
363         /* set pos */
364         ret = s6e63j0x03_dcs_write_seq_static(ctx,
365                 MIPI_DCS_SET_ADDRESS_MODE, 0x40);
366         if (ret < 0)
367                 return ret;
368
369         /* set default white brightness */
370         ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x00ff);
371         if (ret < 0)
372                 return ret;
373
374         /* set white ctrl */
375         ret = s6e63j0x03_dcs_write_seq_static(ctx,
376                 MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
377         if (ret < 0)
378                 return ret;
379
380         /* set acl off */
381         ret = s6e63j0x03_dcs_write_seq_static(ctx,
382                 MIPI_DCS_WRITE_POWER_SAVE, 0x00);
383         if (ret < 0)
384                 return ret;
385
386         ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
387         if (ret < 0)
388                 return ret;
389
390         ret = s6e63j0x03_apply_mtp_key(ctx, false);
391         if (ret < 0)
392                 return ret;
393
394         ret = mipi_dsi_dcs_set_display_on(dsi);
395         if (ret < 0)
396                 return ret;
397
398         ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
399
400         return 0;
401 }
402
403 static int s6e63j0x03_get_modes(struct drm_panel *panel)
404 {
405         struct drm_connector *connector = panel->connector;
406         struct drm_display_mode *mode;
407
408         mode = drm_mode_duplicate(panel->drm, &default_mode);
409         if (!mode) {
410                 DRM_ERROR("failed to add mode %ux%ux@%u\n",
411                         default_mode.hdisplay, default_mode.vdisplay,
412                         default_mode.vrefresh);
413                 return -ENOMEM;
414         }
415
416         drm_mode_set_name(mode);
417
418         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
419         drm_mode_probed_add(connector, mode);
420
421         connector->display_info.width_mm = 29;
422         connector->display_info.height_mm = 29;
423
424         return 1;
425 }
426
427 static const struct drm_panel_funcs s6e63j0x03_funcs = {
428         .disable = s6e63j0x03_disable,
429         .unprepare = s6e63j0x03_unprepare,
430         .prepare = s6e63j0x03_prepare,
431         .enable = s6e63j0x03_enable,
432         .get_modes = s6e63j0x03_get_modes,
433 };
434
435 static int s6e63j0x03_probe(struct mipi_dsi_device *dsi)
436 {
437         struct device *dev = &dsi->dev;
438         struct s6e63j0x03 *ctx;
439         int ret;
440
441         ctx = devm_kzalloc(dev, sizeof(struct s6e63j0x03), GFP_KERNEL);
442         if (!ctx)
443                 return -ENOMEM;
444
445         mipi_dsi_set_drvdata(dsi, ctx);
446
447         ctx->dev = dev;
448
449         dsi->lanes = 1;
450         dsi->format = MIPI_DSI_FMT_RGB888;
451         dsi->mode_flags = MIPI_DSI_MODE_EOT_PACKET;
452
453         ctx->supplies[0].supply = "vdd3";
454         ctx->supplies[1].supply = "vci";
455         ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
456                                       ctx->supplies);
457         if (ret < 0) {
458                 dev_err(dev, "failed to get regulators: %d\n", ret);
459                 return ret;
460         }
461
462         ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
463         if (IS_ERR(ctx->reset_gpio)) {
464                 dev_err(dev, "cannot get reset-gpio: %ld\n",
465                                 PTR_ERR(ctx->reset_gpio));
466                 return PTR_ERR(ctx->reset_gpio);
467         }
468
469         drm_panel_init(&ctx->panel, dev, &s6e63j0x03_funcs,
470                        DRM_MODE_CONNECTOR_DSI);
471
472         ctx->bl_dev = backlight_device_register("s6e63j0x03", dev, ctx,
473                                                 &s6e63j0x03_bl_ops, NULL);
474         if (IS_ERR(ctx->bl_dev)) {
475                 dev_err(dev, "failed to register backlight device\n");
476                 return PTR_ERR(ctx->bl_dev);
477         }
478
479         ctx->bl_dev->props.max_brightness = MAX_BRIGHTNESS;
480         ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS;
481         ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
482
483         ret = drm_panel_add(&ctx->panel);
484         if (ret < 0)
485                 goto unregister_backlight;
486
487         ret = mipi_dsi_attach(dsi);
488         if (ret < 0)
489                 goto remove_panel;
490
491         return ret;
492
493 remove_panel:
494         drm_panel_remove(&ctx->panel);
495
496 unregister_backlight:
497         backlight_device_unregister(ctx->bl_dev);
498
499         return ret;
500 }
501
502 static int s6e63j0x03_remove(struct mipi_dsi_device *dsi)
503 {
504         struct s6e63j0x03 *ctx = mipi_dsi_get_drvdata(dsi);
505
506         mipi_dsi_detach(dsi);
507         drm_panel_remove(&ctx->panel);
508
509         backlight_device_unregister(ctx->bl_dev);
510
511         return 0;
512 }
513
514 static const struct of_device_id s6e63j0x03_of_match[] = {
515         { .compatible = "samsung,s6e63j0x03" },
516         { }
517 };
518 MODULE_DEVICE_TABLE(of, s6e63j0x03_of_match);
519
520 static struct mipi_dsi_driver s6e63j0x03_driver = {
521         .probe = s6e63j0x03_probe,
522         .remove = s6e63j0x03_remove,
523         .driver = {
524                 .name = "panel_samsung_s6e63j0x03",
525                 .of_match_table = s6e63j0x03_of_match,
526         },
527 };
528 module_mipi_dsi_driver(s6e63j0x03_driver);
529
530 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
531 MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>");
532 MODULE_DESCRIPTION("MIPI-DSI based s6e63j0x03 AMOLED LCD Panel Driver");
533 MODULE_LICENSE("GPL v2");