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 <heiko.stuebner@theobroma-systems.com>"); 396 MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel"); 397 MODULE_LICENSE("GPL v2"); 398