Merge tag 'v5.10-rc1' into spi-5.10
[linux-2.6-microblaze.git] / drivers / gpu / drm / panel / panel-xinpeng-xpp055c272.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xinpeng xpp055c272 5.5" MIPI-DSI panel driver
4  * Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH
5  *
6  * based on
7  *
8  * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
9  * Copyright (C) Purism SPC 2019
10  */
11
12 #include <drm/drm_mipi_dsi.h>
13 #include <drm/drm_modes.h>
14 #include <drm/drm_panel.h>
15
16 #include <video/display_timing.h>
17 #include <video/mipi_display.h>
18
19 #include <linux/delay.h>
20 #include <linux/gpio/consumer.h>
21 #include <linux/media-bus-format.h>
22 #include <linux/module.h>
23 #include <linux/of.h>
24 #include <linux/regulator/consumer.h>
25
26 /* Manufacturer specific Commands send via DSI */
27 #define XPP055C272_CMD_ALL_PIXEL_OFF    0x22
28 #define XPP055C272_CMD_ALL_PIXEL_ON     0x23
29 #define XPP055C272_CMD_SETDISP          0xb2
30 #define XPP055C272_CMD_SETRGBIF         0xb3
31 #define XPP055C272_CMD_SETCYC           0xb4
32 #define XPP055C272_CMD_SETBGP           0xb5
33 #define XPP055C272_CMD_SETVCOM          0xb6
34 #define XPP055C272_CMD_SETOTP           0xb7
35 #define XPP055C272_CMD_SETPOWER_EXT     0xb8
36 #define XPP055C272_CMD_SETEXTC          0xb9
37 #define XPP055C272_CMD_SETMIPI          0xbA
38 #define XPP055C272_CMD_SETVDC           0xbc
39 #define XPP055C272_CMD_SETPCR           0xbf
40 #define XPP055C272_CMD_SETSCR           0xc0
41 #define XPP055C272_CMD_SETPOWER         0xc1
42 #define XPP055C272_CMD_SETECO           0xc6
43 #define XPP055C272_CMD_SETPANEL         0xcc
44 #define XPP055C272_CMD_SETGAMMA         0xe0
45 #define XPP055C272_CMD_SETEQ            0xe3
46 #define XPP055C272_CMD_SETGIP1          0xe9
47 #define XPP055C272_CMD_SETGIP2          0xea
48
49 struct xpp055c272 {
50         struct device *dev;
51         struct drm_panel panel;
52         struct gpio_desc *reset_gpio;
53         struct regulator *vci;
54         struct regulator *iovcc;
55         bool prepared;
56 };
57
58 static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel)
59 {
60         return container_of(panel, struct xpp055c272, panel);
61 }
62
63 #define dsi_generic_write_seq(dsi, cmd, seq...) do {                    \
64                 static const u8 b[] = { cmd, seq };                     \
65                 int ret;                                                \
66                 ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
67                 if (ret < 0)                                            \
68                         return ret;                                     \
69         } while (0)
70
71 static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
72 {
73         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
74         struct device *dev = ctx->dev;
75
76         /*
77          * Init sequence was supplied by the panel vendor without much
78          * documentation.
79          */
80         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
81         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETMIPI,
82                               0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
83                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
84                               0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
85                               0x00, 0x00, 0x37);
86         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
87         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
88         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
89                               0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
90                               0x00, 0x00);
91         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETSCR,
92                               0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
93                               0x00);
94         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
95         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
96         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
97         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
98         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEQ,
99                               0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
100                               0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
101         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER,
102                               0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
103                               0x67, 0x77, 0x33, 0x33);
104         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
105                               0xff, 0x01, 0xff);
106         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
107         msleep(20);
108
109         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
110         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP1,
111                               0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
112                               0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
113                               0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
114                               0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
115                               0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
116                               0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
117                               0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
118                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
119         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP2,
120                               0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
121                               0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
122                               0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
123                               0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
124                               0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
125                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
127                               0xa0, 0x00, 0x00, 0x00, 0x00);
128         dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
129                               0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
130                               0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
131                               0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
132                               0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
133                               0x11, 0x18);
134
135         msleep(60);
136
137         dev_dbg(dev, "Panel init sequence done\n");
138         return 0;
139 }
140
141 static int xpp055c272_unprepare(struct drm_panel *panel)
142 {
143         struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
144         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
145         int ret;
146
147         if (!ctx->prepared)
148                 return 0;
149
150         ret = mipi_dsi_dcs_set_display_off(dsi);
151         if (ret < 0)
152                 dev_err(ctx->dev, "failed to set display off: %d\n", ret);
153
154         mipi_dsi_dcs_enter_sleep_mode(dsi);
155         if (ret < 0) {
156                 dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
157                 return ret;
158         }
159
160         regulator_disable(ctx->iovcc);
161         regulator_disable(ctx->vci);
162
163         ctx->prepared = false;
164
165         return 0;
166 }
167
168 static int xpp055c272_prepare(struct drm_panel *panel)
169 {
170         struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
171         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
172         int ret;
173
174         if (ctx->prepared)
175                 return 0;
176
177         dev_dbg(ctx->dev, "Resetting the panel\n");
178         ret = regulator_enable(ctx->vci);
179         if (ret < 0) {
180                 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
181                 return ret;
182         }
183         ret = regulator_enable(ctx->iovcc);
184         if (ret < 0) {
185                 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
186                 goto disable_vci;
187         }
188
189         gpiod_set_value_cansleep(ctx->reset_gpio, 1);
190         /* T6: 10us */
191         usleep_range(10, 20);
192         gpiod_set_value_cansleep(ctx->reset_gpio, 0);
193
194         /* T8: 20ms */
195         msleep(20);
196
197         ret = xpp055c272_init_sequence(ctx);
198         if (ret < 0) {
199                 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
200                 goto disable_iovcc;
201         }
202
203         ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
204         if (ret < 0) {
205                 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
206                 goto disable_iovcc;
207         }
208
209         /* T9: 120ms */
210         msleep(120);
211
212         ret = mipi_dsi_dcs_set_display_on(dsi);
213         if (ret < 0) {
214                 dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
215                 goto disable_iovcc;
216         }
217
218         msleep(50);
219
220         ctx->prepared = true;
221
222         return 0;
223
224 disable_iovcc:
225         regulator_disable(ctx->iovcc);
226 disable_vci:
227         regulator_disable(ctx->vci);
228         return ret;
229 }
230
231 static const struct drm_display_mode default_mode = {
232         .hdisplay       = 720,
233         .hsync_start    = 720 + 40,
234         .hsync_end      = 720 + 40 + 10,
235         .htotal         = 720 + 40 + 10 + 40,
236         .vdisplay       = 1280,
237         .vsync_start    = 1280 + 22,
238         .vsync_end      = 1280 + 22 + 4,
239         .vtotal         = 1280 + 22 + 4 + 11,
240         .clock          = 64000,
241         .width_mm       = 68,
242         .height_mm      = 121,
243 };
244
245 static int xpp055c272_get_modes(struct drm_panel *panel,
246                                 struct drm_connector *connector)
247 {
248         struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
249         struct drm_display_mode *mode;
250
251         mode = drm_mode_duplicate(connector->dev, &default_mode);
252         if (!mode) {
253                 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
254                         default_mode.hdisplay, default_mode.vdisplay,
255                         drm_mode_vrefresh(&default_mode));
256                 return -ENOMEM;
257         }
258
259         drm_mode_set_name(mode);
260
261         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
262         connector->display_info.width_mm = mode->width_mm;
263         connector->display_info.height_mm = mode->height_mm;
264         drm_mode_probed_add(connector, mode);
265
266         return 1;
267 }
268
269 static const struct drm_panel_funcs xpp055c272_funcs = {
270         .unprepare      = xpp055c272_unprepare,
271         .prepare        = xpp055c272_prepare,
272         .get_modes      = xpp055c272_get_modes,
273 };
274
275 static int xpp055c272_probe(struct mipi_dsi_device *dsi)
276 {
277         struct device *dev = &dsi->dev;
278         struct xpp055c272 *ctx;
279         int ret;
280
281         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
282         if (!ctx)
283                 return -ENOMEM;
284
285         ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
286         if (IS_ERR(ctx->reset_gpio)) {
287                 dev_err(dev, "cannot get reset gpio\n");
288                 return PTR_ERR(ctx->reset_gpio);
289         }
290
291         ctx->vci = devm_regulator_get(dev, "vci");
292         if (IS_ERR(ctx->vci)) {
293                 ret = PTR_ERR(ctx->vci);
294                 if (ret != -EPROBE_DEFER)
295                         dev_err(dev, "Failed to request vci regulator: %d\n", ret);
296                 return ret;
297         }
298
299         ctx->iovcc = devm_regulator_get(dev, "iovcc");
300         if (IS_ERR(ctx->iovcc)) {
301                 ret = PTR_ERR(ctx->iovcc);
302                 if (ret != -EPROBE_DEFER)
303                         dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
304                 return ret;
305         }
306
307         mipi_dsi_set_drvdata(dsi, ctx);
308
309         ctx->dev = dev;
310
311         dsi->lanes = 4;
312         dsi->format = MIPI_DSI_FMT_RGB888;
313         dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
314                           MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET;
315
316         drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs,
317                        DRM_MODE_CONNECTOR_DSI);
318
319         ret = drm_panel_of_backlight(&ctx->panel);
320         if (ret)
321                 return ret;
322
323         drm_panel_add(&ctx->panel);
324
325         ret = mipi_dsi_attach(dsi);
326         if (ret < 0) {
327                 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
328                 drm_panel_remove(&ctx->panel);
329                 return ret;
330         }
331
332         return 0;
333 }
334
335 static void xpp055c272_shutdown(struct mipi_dsi_device *dsi)
336 {
337         struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
338         int ret;
339
340         ret = drm_panel_unprepare(&ctx->panel);
341         if (ret < 0)
342                 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
343
344         ret = drm_panel_disable(&ctx->panel);
345         if (ret < 0)
346                 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
347 }
348
349 static int xpp055c272_remove(struct mipi_dsi_device *dsi)
350 {
351         struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
352         int ret;
353
354         xpp055c272_shutdown(dsi);
355
356         ret = mipi_dsi_detach(dsi);
357         if (ret < 0)
358                 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
359
360         drm_panel_remove(&ctx->panel);
361
362         return 0;
363 }
364
365 static const struct of_device_id xpp055c272_of_match[] = {
366         { .compatible = "xinpeng,xpp055c272" },
367         { /* sentinel */ }
368 };
369 MODULE_DEVICE_TABLE(of, xpp055c272_of_match);
370
371 static struct mipi_dsi_driver xpp055c272_driver = {
372         .driver = {
373                 .name = "panel-xinpeng-xpp055c272",
374                 .of_match_table = xpp055c272_of_match,
375         },
376         .probe  = xpp055c272_probe,
377         .remove = xpp055c272_remove,
378         .shutdown = xpp055c272_shutdown,
379 };
380 module_mipi_dsi_driver(xpp055c272_driver);
381
382 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
383 MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel");
384 MODULE_LICENSE("GPL v2");