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 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 288 "cannot get reset gpio\n"); 289 290 ctx->vci = devm_regulator_get(dev, "vci"); 291 if (IS_ERR(ctx->vci)) 292 return dev_err_probe(dev, PTR_ERR(ctx->vci), 293 "Failed to request vci regulator\n"); 294 295 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 296 if (IS_ERR(ctx->iovcc)) 297 return dev_err_probe(dev, PTR_ERR(ctx->iovcc), 298 "Failed to request iovcc regulator\n"); 299 300 mipi_dsi_set_drvdata(dsi, ctx); 301 302 ctx->dev = dev; 303 304 dsi->lanes = 4; 305 dsi->format = MIPI_DSI_FMT_RGB888; 306 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 307 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; 308 309 drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs, 310 DRM_MODE_CONNECTOR_DSI); 311 312 ret = drm_panel_of_backlight(&ctx->panel); 313 if (ret) 314 return ret; 315 316 drm_panel_add(&ctx->panel); 317 318 ret = mipi_dsi_attach(dsi); 319 if (ret < 0) { 320 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); 321 drm_panel_remove(&ctx->panel); 322 return ret; 323 } 324 325 return 0; 326 } 327 328 static void xpp055c272_shutdown(struct mipi_dsi_device *dsi) 329 { 330 struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi); 331 int ret; 332 333 ret = drm_panel_unprepare(&ctx->panel); 334 if (ret < 0) 335 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); 336 337 ret = drm_panel_disable(&ctx->panel); 338 if (ret < 0) 339 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); 340 } 341 342 static int xpp055c272_remove(struct mipi_dsi_device *dsi) 343 { 344 struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi); 345 int ret; 346 347 xpp055c272_shutdown(dsi); 348 349 ret = mipi_dsi_detach(dsi); 350 if (ret < 0) 351 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 352 353 drm_panel_remove(&ctx->panel); 354 355 return 0; 356 } 357 358 static const struct of_device_id xpp055c272_of_match[] = { 359 { .compatible = "xinpeng,xpp055c272" }, 360 { /* sentinel */ } 361 }; 362 MODULE_DEVICE_TABLE(of, xpp055c272_of_match); 363 364 static struct mipi_dsi_driver xpp055c272_driver = { 365 .driver = { 366 .name = "panel-xinpeng-xpp055c272", 367 .of_match_table = xpp055c272_of_match, 368 }, 369 .probe = xpp055c272_probe, 370 .remove = xpp055c272_remove, 371 .shutdown = xpp055c272_shutdown, 372 }; 373 module_mipi_dsi_driver(xpp055c272_driver); 374 375 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>"); 376 MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel"); 377 MODULE_LICENSE("GPL v2"); 378