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