Merge tag 'mips_6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[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 static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
64 {
65         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
66         struct device *dev = ctx->dev;
67
68         /*
69          * Init sequence was supplied by the panel vendor without much
70          * documentation.
71          */
72         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
73         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETMIPI,
74                                0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
75                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
76                                0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
77                                0x00, 0x00, 0x37);
78         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
79         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
80         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
81                                0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
82                                0x00, 0x00);
83         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETSCR,
84                                0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
85                                0x00);
86         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
87         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
88         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
89         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
90         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETEQ,
91                                0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
92                                0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
93         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPOWER,
94                                0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
95                                0x67, 0x77, 0x33, 0x33);
96         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
97                                0xff, 0x01, 0xff);
98         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
99         msleep(20);
100
101         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
102         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGIP1,
103                                0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
104                                0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
105                                0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
106                                0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
107                                0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
108                                0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
109                                0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
110                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
111         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGIP2,
112                                0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
113                                0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
114                                0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
115                                0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
116                                0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
117                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
119                                0xa0, 0x00, 0x00, 0x00, 0x00);
120         mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
121                                0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
122                                0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
123                                0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
124                                0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
125                                0x11, 0x18);
126
127         msleep(60);
128
129         dev_dbg(dev, "Panel init sequence done\n");
130         return 0;
131 }
132
133 static int xpp055c272_unprepare(struct drm_panel *panel)
134 {
135         struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
136         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
137         int ret;
138
139         if (!ctx->prepared)
140                 return 0;
141
142         ret = mipi_dsi_dcs_set_display_off(dsi);
143         if (ret < 0)
144                 dev_err(ctx->dev, "failed to set display off: %d\n", ret);
145
146         mipi_dsi_dcs_enter_sleep_mode(dsi);
147         if (ret < 0) {
148                 dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
149                 return ret;
150         }
151
152         regulator_disable(ctx->iovcc);
153         regulator_disable(ctx->vci);
154
155         ctx->prepared = false;
156
157         return 0;
158 }
159
160 static int xpp055c272_prepare(struct drm_panel *panel)
161 {
162         struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
163         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
164         int ret;
165
166         if (ctx->prepared)
167                 return 0;
168
169         dev_dbg(ctx->dev, "Resetting the panel\n");
170         ret = regulator_enable(ctx->vci);
171         if (ret < 0) {
172                 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
173                 return ret;
174         }
175         ret = regulator_enable(ctx->iovcc);
176         if (ret < 0) {
177                 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
178                 goto disable_vci;
179         }
180
181         gpiod_set_value_cansleep(ctx->reset_gpio, 1);
182         /* T6: 10us */
183         usleep_range(10, 20);
184         gpiod_set_value_cansleep(ctx->reset_gpio, 0);
185
186         /* T8: 20ms */
187         msleep(20);
188
189         ret = xpp055c272_init_sequence(ctx);
190         if (ret < 0) {
191                 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
192                 goto disable_iovcc;
193         }
194
195         ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
196         if (ret < 0) {
197                 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
198                 goto disable_iovcc;
199         }
200
201         /* T9: 120ms */
202         msleep(120);
203
204         ret = mipi_dsi_dcs_set_display_on(dsi);
205         if (ret < 0) {
206                 dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
207                 goto disable_iovcc;
208         }
209
210         msleep(50);
211
212         ctx->prepared = true;
213
214         return 0;
215
216 disable_iovcc:
217         regulator_disable(ctx->iovcc);
218 disable_vci:
219         regulator_disable(ctx->vci);
220         return ret;
221 }
222
223 static const struct drm_display_mode default_mode = {
224         .hdisplay       = 720,
225         .hsync_start    = 720 + 40,
226         .hsync_end      = 720 + 40 + 10,
227         .htotal         = 720 + 40 + 10 + 40,
228         .vdisplay       = 1280,
229         .vsync_start    = 1280 + 22,
230         .vsync_end      = 1280 + 22 + 4,
231         .vtotal         = 1280 + 22 + 4 + 11,
232         .clock          = 64000,
233         .width_mm       = 68,
234         .height_mm      = 121,
235 };
236
237 static int xpp055c272_get_modes(struct drm_panel *panel,
238                                 struct drm_connector *connector)
239 {
240         struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
241         struct drm_display_mode *mode;
242
243         mode = drm_mode_duplicate(connector->dev, &default_mode);
244         if (!mode) {
245                 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
246                         default_mode.hdisplay, default_mode.vdisplay,
247                         drm_mode_vrefresh(&default_mode));
248                 return -ENOMEM;
249         }
250
251         drm_mode_set_name(mode);
252
253         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
254         connector->display_info.width_mm = mode->width_mm;
255         connector->display_info.height_mm = mode->height_mm;
256         drm_mode_probed_add(connector, mode);
257
258         return 1;
259 }
260
261 static const struct drm_panel_funcs xpp055c272_funcs = {
262         .unprepare      = xpp055c272_unprepare,
263         .prepare        = xpp055c272_prepare,
264         .get_modes      = xpp055c272_get_modes,
265 };
266
267 static int xpp055c272_probe(struct mipi_dsi_device *dsi)
268 {
269         struct device *dev = &dsi->dev;
270         struct xpp055c272 *ctx;
271         int ret;
272
273         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
274         if (!ctx)
275                 return -ENOMEM;
276
277         ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
278         if (IS_ERR(ctx->reset_gpio))
279                 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
280                                      "cannot get reset gpio\n");
281
282         ctx->vci = devm_regulator_get(dev, "vci");
283         if (IS_ERR(ctx->vci))
284                 return dev_err_probe(dev, PTR_ERR(ctx->vci),
285                                      "Failed to request vci regulator\n");
286
287         ctx->iovcc = devm_regulator_get(dev, "iovcc");
288         if (IS_ERR(ctx->iovcc))
289                 return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
290                                      "Failed to request iovcc regulator\n");
291
292         mipi_dsi_set_drvdata(dsi, ctx);
293
294         ctx->dev = dev;
295
296         dsi->lanes = 4;
297         dsi->format = MIPI_DSI_FMT_RGB888;
298         dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
299                           MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
300
301         drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs,
302                        DRM_MODE_CONNECTOR_DSI);
303
304         ret = drm_panel_of_backlight(&ctx->panel);
305         if (ret)
306                 return ret;
307
308         drm_panel_add(&ctx->panel);
309
310         ret = mipi_dsi_attach(dsi);
311         if (ret < 0) {
312                 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
313                 drm_panel_remove(&ctx->panel);
314                 return ret;
315         }
316
317         return 0;
318 }
319
320 static void xpp055c272_shutdown(struct mipi_dsi_device *dsi)
321 {
322         struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
323         int ret;
324
325         ret = drm_panel_unprepare(&ctx->panel);
326         if (ret < 0)
327                 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
328
329         ret = drm_panel_disable(&ctx->panel);
330         if (ret < 0)
331                 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
332 }
333
334 static void xpp055c272_remove(struct mipi_dsi_device *dsi)
335 {
336         struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
337         int ret;
338
339         xpp055c272_shutdown(dsi);
340
341         ret = mipi_dsi_detach(dsi);
342         if (ret < 0)
343                 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
344
345         drm_panel_remove(&ctx->panel);
346 }
347
348 static const struct of_device_id xpp055c272_of_match[] = {
349         { .compatible = "xinpeng,xpp055c272" },
350         { /* sentinel */ }
351 };
352 MODULE_DEVICE_TABLE(of, xpp055c272_of_match);
353
354 static struct mipi_dsi_driver xpp055c272_driver = {
355         .driver = {
356                 .name = "panel-xinpeng-xpp055c272",
357                 .of_match_table = xpp055c272_of_match,
358         },
359         .probe  = xpp055c272_probe,
360         .remove = xpp055c272_remove,
361         .shutdown = xpp055c272_shutdown,
362 };
363 module_mipi_dsi_driver(xpp055c272_driver);
364
365 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
366 MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel");
367 MODULE_LICENSE("GPL v2");