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