1 // SPDX-License-Identifier: GPL-2.0
3 * Xinpeng xpp055c272 5.5" MIPI-DSI panel driver
4 * Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH
8 * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
9 * Copyright (C) Purism SPC 2019
12 #include <drm/drm_mipi_dsi.h>
13 #include <drm/drm_modes.h>
14 #include <drm/drm_panel.h>
16 #include <video/display_timing.h>
17 #include <video/mipi_display.h>
19 #include <linux/delay.h>
20 #include <linux/gpio/consumer.h>
21 #include <linux/media-bus-format.h>
22 #include <linux/module.h>
24 #include <linux/regulator/consumer.h>
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
51 struct drm_panel panel;
52 struct gpio_desc *reset_gpio;
53 struct regulator *vci;
54 struct regulator *iovcc;
57 static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel)
59 return container_of(panel, struct xpp055c272, panel);
62 static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
64 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
65 struct device *dev = ctx->dev;
68 * Init sequence was supplied by the panel vendor without much
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,
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,
82 mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETSCR,
83 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
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,
97 mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
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,
128 dev_dbg(dev, "Panel init sequence done\n");
132 static int xpp055c272_unprepare(struct drm_panel *panel)
134 struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
135 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
138 ret = mipi_dsi_dcs_set_display_off(dsi);
140 dev_err(ctx->dev, "failed to set display off: %d\n", ret);
142 mipi_dsi_dcs_enter_sleep_mode(dsi);
144 dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
148 regulator_disable(ctx->iovcc);
149 regulator_disable(ctx->vci);
154 static int xpp055c272_prepare(struct drm_panel *panel)
156 struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
157 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
160 dev_dbg(ctx->dev, "Resetting the panel\n");
161 ret = regulator_enable(ctx->vci);
163 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
166 ret = regulator_enable(ctx->iovcc);
168 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
172 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
174 usleep_range(10, 20);
175 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
180 ret = xpp055c272_init_sequence(ctx);
182 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
186 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
188 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
195 ret = mipi_dsi_dcs_set_display_on(dsi);
197 dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
206 regulator_disable(ctx->iovcc);
208 regulator_disable(ctx->vci);
212 static const struct drm_display_mode default_mode = {
214 .hsync_start = 720 + 40,
215 .hsync_end = 720 + 40 + 10,
216 .htotal = 720 + 40 + 10 + 40,
218 .vsync_start = 1280 + 22,
219 .vsync_end = 1280 + 22 + 4,
220 .vtotal = 1280 + 22 + 4 + 11,
226 static int xpp055c272_get_modes(struct drm_panel *panel,
227 struct drm_connector *connector)
229 struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
230 struct drm_display_mode *mode;
232 mode = drm_mode_duplicate(connector->dev, &default_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));
240 drm_mode_set_name(mode);
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);
250 static const struct drm_panel_funcs xpp055c272_funcs = {
251 .unprepare = xpp055c272_unprepare,
252 .prepare = xpp055c272_prepare,
253 .get_modes = xpp055c272_get_modes,
256 static int xpp055c272_probe(struct mipi_dsi_device *dsi)
258 struct device *dev = &dsi->dev;
259 struct xpp055c272 *ctx;
262 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
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");
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");
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");
281 mipi_dsi_set_drvdata(dsi, ctx);
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;
290 drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs,
291 DRM_MODE_CONNECTOR_DSI);
293 ret = drm_panel_of_backlight(&ctx->panel);
297 drm_panel_add(&ctx->panel);
299 ret = mipi_dsi_attach(dsi);
301 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
302 drm_panel_remove(&ctx->panel);
309 static void xpp055c272_remove(struct mipi_dsi_device *dsi)
311 struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
314 ret = mipi_dsi_detach(dsi);
316 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
318 drm_panel_remove(&ctx->panel);
321 static const struct of_device_id xpp055c272_of_match[] = {
322 { .compatible = "xinpeng,xpp055c272" },
325 MODULE_DEVICE_TABLE(of, xpp055c272_of_match);
327 static struct mipi_dsi_driver xpp055c272_driver = {
329 .name = "panel-xinpeng-xpp055c272",
330 .of_match_table = xpp055c272_of_match,
332 .probe = xpp055c272_probe,
333 .remove = xpp055c272_remove,
335 module_mipi_dsi_driver(xpp055c272_driver);
338 MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel");
339 MODULE_LICENSE("GPL v2");