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