1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH 4 */ 5 6 #include <linux/delay.h> 7 #include <linux/gpio/consumer.h> 8 #include <linux/media-bus-format.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/of_device.h> 12 #include <linux/regulator/consumer.h> 13 14 #include <video/display_timing.h> 15 #include <video/mipi_display.h> 16 17 #include <drm/drm_mipi_dsi.h> 18 #include <drm/drm_modes.h> 19 #include <drm/drm_panel.h> 20 #include <drm/drm_print.h> 21 22 struct ltk050h3146w_cmd { 23 char cmd; 24 char data; 25 }; 26 27 struct ltk050h3146w; 28 struct ltk050h3146w_desc { 29 const struct drm_display_mode *mode; 30 int (*init)(struct ltk050h3146w *ctx); 31 }; 32 33 struct ltk050h3146w { 34 struct device *dev; 35 struct drm_panel panel; 36 struct gpio_desc *reset_gpio; 37 struct regulator *vci; 38 struct regulator *iovcc; 39 const struct ltk050h3146w_desc *panel_desc; 40 bool prepared; 41 }; 42 43 static const struct ltk050h3146w_cmd page1_cmds[] = { 44 { 0x22, 0x0A }, /* BGR SS GS */ 45 { 0x31, 0x00 }, /* column inversion */ 46 { 0x53, 0xA2 }, /* VCOM1 */ 47 { 0x55, 0xA2 }, /* VCOM2 */ 48 { 0x50, 0x81 }, /* VREG1OUT=5V */ 49 { 0x51, 0x85 }, /* VREG2OUT=-5V */ 50 { 0x62, 0x0D }, /* EQT Time setting */ 51 /* 52 * The vendor init selected page 1 here _again_ 53 * Is this supposed to be page 2? 54 */ 55 { 0xA0, 0x00 }, 56 { 0xA1, 0x1A }, 57 { 0xA2, 0x28 }, 58 { 0xA3, 0x13 }, 59 { 0xA4, 0x16 }, 60 { 0xA5, 0x29 }, 61 { 0xA6, 0x1D }, 62 { 0xA7, 0x1E }, 63 { 0xA8, 0x84 }, 64 { 0xA9, 0x1C }, 65 { 0xAA, 0x28 }, 66 { 0xAB, 0x75 }, 67 { 0xAC, 0x1A }, 68 { 0xAD, 0x19 }, 69 { 0xAE, 0x4D }, 70 { 0xAF, 0x22 }, 71 { 0xB0, 0x28 }, 72 { 0xB1, 0x54 }, 73 { 0xB2, 0x66 }, 74 { 0xB3, 0x39 }, 75 { 0xC0, 0x00 }, 76 { 0xC1, 0x1A }, 77 { 0xC2, 0x28 }, 78 { 0xC3, 0x13 }, 79 { 0xC4, 0x16 }, 80 { 0xC5, 0x29 }, 81 { 0xC6, 0x1D }, 82 { 0xC7, 0x1E }, 83 { 0xC8, 0x84 }, 84 { 0xC9, 0x1C }, 85 { 0xCA, 0x28 }, 86 { 0xCB, 0x75 }, 87 { 0xCC, 0x1A }, 88 { 0xCD, 0x19 }, 89 { 0xCE, 0x4D }, 90 { 0xCF, 0x22 }, 91 { 0xD0, 0x28 }, 92 { 0xD1, 0x54 }, 93 { 0xD2, 0x66 }, 94 { 0xD3, 0x39 }, 95 }; 96 97 static const struct ltk050h3146w_cmd page3_cmds[] = { 98 { 0x01, 0x00 }, 99 { 0x02, 0x00 }, 100 { 0x03, 0x73 }, 101 { 0x04, 0x00 }, 102 { 0x05, 0x00 }, 103 { 0x06, 0x0a }, 104 { 0x07, 0x00 }, 105 { 0x08, 0x00 }, 106 { 0x09, 0x01 }, 107 { 0x0a, 0x00 }, 108 { 0x0b, 0x00 }, 109 { 0x0c, 0x01 }, 110 { 0x0d, 0x00 }, 111 { 0x0e, 0x00 }, 112 { 0x0f, 0x1d }, 113 { 0x10, 0x1d }, 114 { 0x11, 0x00 }, 115 { 0x12, 0x00 }, 116 { 0x13, 0x00 }, 117 { 0x14, 0x00 }, 118 { 0x15, 0x00 }, 119 { 0x16, 0x00 }, 120 { 0x17, 0x00 }, 121 { 0x18, 0x00 }, 122 { 0x19, 0x00 }, 123 { 0x1a, 0x00 }, 124 { 0x1b, 0x00 }, 125 { 0x1c, 0x00 }, 126 { 0x1d, 0x00 }, 127 { 0x1e, 0x40 }, 128 { 0x1f, 0x80 }, 129 { 0x20, 0x06 }, 130 { 0x21, 0x02 }, 131 { 0x22, 0x00 }, 132 { 0x23, 0x00 }, 133 { 0x24, 0x00 }, 134 { 0x25, 0x00 }, 135 { 0x26, 0x00 }, 136 { 0x27, 0x00 }, 137 { 0x28, 0x33 }, 138 { 0x29, 0x03 }, 139 { 0x2a, 0x00 }, 140 { 0x2b, 0x00 }, 141 { 0x2c, 0x00 }, 142 { 0x2d, 0x00 }, 143 { 0x2e, 0x00 }, 144 { 0x2f, 0x00 }, 145 { 0x30, 0x00 }, 146 { 0x31, 0x00 }, 147 { 0x32, 0x00 }, 148 { 0x33, 0x00 }, 149 { 0x34, 0x04 }, 150 { 0x35, 0x00 }, 151 { 0x36, 0x00 }, 152 { 0x37, 0x00 }, 153 { 0x38, 0x3C }, 154 { 0x39, 0x35 }, 155 { 0x3A, 0x01 }, 156 { 0x3B, 0x40 }, 157 { 0x3C, 0x00 }, 158 { 0x3D, 0x01 }, 159 { 0x3E, 0x00 }, 160 { 0x3F, 0x00 }, 161 { 0x40, 0x00 }, 162 { 0x41, 0x88 }, 163 { 0x42, 0x00 }, 164 { 0x43, 0x00 }, 165 { 0x44, 0x1F }, 166 { 0x50, 0x01 }, 167 { 0x51, 0x23 }, 168 { 0x52, 0x45 }, 169 { 0x53, 0x67 }, 170 { 0x54, 0x89 }, 171 { 0x55, 0xab }, 172 { 0x56, 0x01 }, 173 { 0x57, 0x23 }, 174 { 0x58, 0x45 }, 175 { 0x59, 0x67 }, 176 { 0x5a, 0x89 }, 177 { 0x5b, 0xab }, 178 { 0x5c, 0xcd }, 179 { 0x5d, 0xef }, 180 { 0x5e, 0x11 }, 181 { 0x5f, 0x01 }, 182 { 0x60, 0x00 }, 183 { 0x61, 0x15 }, 184 { 0x62, 0x14 }, 185 { 0x63, 0x0E }, 186 { 0x64, 0x0F }, 187 { 0x65, 0x0C }, 188 { 0x66, 0x0D }, 189 { 0x67, 0x06 }, 190 { 0x68, 0x02 }, 191 { 0x69, 0x07 }, 192 { 0x6a, 0x02 }, 193 { 0x6b, 0x02 }, 194 { 0x6c, 0x02 }, 195 { 0x6d, 0x02 }, 196 { 0x6e, 0x02 }, 197 { 0x6f, 0x02 }, 198 { 0x70, 0x02 }, 199 { 0x71, 0x02 }, 200 { 0x72, 0x02 }, 201 { 0x73, 0x02 }, 202 { 0x74, 0x02 }, 203 { 0x75, 0x01 }, 204 { 0x76, 0x00 }, 205 { 0x77, 0x14 }, 206 { 0x78, 0x15 }, 207 { 0x79, 0x0E }, 208 { 0x7a, 0x0F }, 209 { 0x7b, 0x0C }, 210 { 0x7c, 0x0D }, 211 { 0x7d, 0x06 }, 212 { 0x7e, 0x02 }, 213 { 0x7f, 0x07 }, 214 { 0x80, 0x02 }, 215 { 0x81, 0x02 }, 216 { 0x82, 0x02 }, 217 { 0x83, 0x02 }, 218 { 0x84, 0x02 }, 219 { 0x85, 0x02 }, 220 { 0x86, 0x02 }, 221 { 0x87, 0x02 }, 222 { 0x88, 0x02 }, 223 { 0x89, 0x02 }, 224 { 0x8A, 0x02 }, 225 }; 226 227 static const struct ltk050h3146w_cmd page4_cmds[] = { 228 { 0x70, 0x00 }, 229 { 0x71, 0x00 }, 230 { 0x82, 0x0F }, /* VGH_MOD clamp level=15v */ 231 { 0x84, 0x0F }, /* VGH clamp level 15V */ 232 { 0x85, 0x0D }, /* VGL clamp level (-10V) */ 233 { 0x32, 0xAC }, 234 { 0x8C, 0x80 }, 235 { 0x3C, 0xF5 }, 236 { 0xB5, 0x07 }, /* GAMMA OP */ 237 { 0x31, 0x45 }, /* SOURCE OP */ 238 { 0x3A, 0x24 }, /* PS_EN OFF */ 239 { 0x88, 0x33 }, /* LVD */ 240 }; 241 242 static inline 243 struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel) 244 { 245 return container_of(panel, struct ltk050h3146w, panel); 246 } 247 248 #define dsi_dcs_write_seq(dsi, cmd, seq...) do { \ 249 static const u8 d[] = { seq }; \ 250 int ret; \ 251 ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \ 252 if (ret < 0) \ 253 return ret; \ 254 } while (0) 255 256 static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) 257 { 258 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 259 int ret; 260 261 /* 262 * Init sequence was supplied by the panel vendor without much 263 * documentation. 264 */ 265 dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8); 266 dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06, 267 0x01); 268 dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5); 269 dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5); 270 dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00); 271 272 dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07); 273 dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f, 274 0x28, 0x04, 0xcc, 0xcc, 0xcc); 275 dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04); 276 dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2); 277 dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03); 278 dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12); 279 dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80, 280 0x80); 281 dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f, 282 0x16, 0x00, 0x00); 283 dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50, 284 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f, 285 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67, 286 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55, 287 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08); 288 dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a, 289 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f, 290 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 291 dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b, 292 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f, 293 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 294 dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05, 295 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f, 296 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 297 dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04, 298 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f, 299 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 300 dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20, 301 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03, 302 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08); 303 dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00, 304 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05, 305 0x21, 0x00, 0x60); 306 dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00); 307 dsi_dcs_write_seq(dsi, 0xde, 0x02); 308 dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c); 309 dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04); 310 dsi_dcs_write_seq(dsi, 0xc1, 0x11); 311 dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37); 312 dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84); 313 dsi_dcs_write_seq(dsi, 0xde, 0x00); 314 315 ret = mipi_dsi_dcs_set_tear_on(dsi, 1); 316 if (ret < 0) { 317 DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", 318 ret); 319 return ret; 320 } 321 322 msleep(60); 323 324 return 0; 325 } 326 327 static const struct drm_display_mode ltk050h3146w_mode = { 328 .hdisplay = 720, 329 .hsync_start = 720 + 42, 330 .hsync_end = 720 + 42 + 8, 331 .htotal = 720 + 42 + 8 + 42, 332 .vdisplay = 1280, 333 .vsync_start = 1280 + 12, 334 .vsync_end = 1280 + 12 + 4, 335 .vtotal = 1280 + 12 + 4 + 18, 336 .clock = 64018, 337 .width_mm = 62, 338 .height_mm = 110, 339 }; 340 341 static const struct ltk050h3146w_desc ltk050h3146w_data = { 342 .mode = <k050h3146w_mode, 343 .init = ltk050h3146w_init_sequence, 344 }; 345 346 static int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page) 347 { 348 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 349 u8 d[3] = { 0x98, 0x81, page }; 350 351 return mipi_dsi_dcs_write(dsi, 0xff, d, ARRAY_SIZE(d)); 352 } 353 354 static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page, 355 const struct ltk050h3146w_cmd *cmds, 356 int num) 357 { 358 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 359 int i, ret; 360 361 ret = ltk050h3146w_a2_select_page(ctx, page); 362 if (ret < 0) { 363 DRM_DEV_ERROR(ctx->dev, "failed to select page %d: %d\n", 364 page, ret); 365 return ret; 366 } 367 368 for (i = 0; i < num; i++) { 369 ret = mipi_dsi_generic_write(dsi, &cmds[i], 370 sizeof(struct ltk050h3146w_cmd)); 371 if (ret < 0) { 372 DRM_DEV_ERROR(ctx->dev, 373 "failed to write page %d init cmds: %d\n", 374 page, ret); 375 return ret; 376 } 377 } 378 379 return 0; 380 } 381 382 static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx) 383 { 384 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 385 int ret; 386 387 /* 388 * Init sequence was supplied by the panel vendor without much 389 * documentation. 390 */ 391 ret = ltk050h3146w_a2_write_page(ctx, 3, page3_cmds, 392 ARRAY_SIZE(page3_cmds)); 393 if (ret < 0) 394 return ret; 395 396 ret = ltk050h3146w_a2_write_page(ctx, 4, page4_cmds, 397 ARRAY_SIZE(page4_cmds)); 398 if (ret < 0) 399 return ret; 400 401 ret = ltk050h3146w_a2_write_page(ctx, 1, page1_cmds, 402 ARRAY_SIZE(page1_cmds)); 403 if (ret < 0) 404 return ret; 405 406 ret = ltk050h3146w_a2_select_page(ctx, 0); 407 if (ret < 0) { 408 DRM_DEV_ERROR(ctx->dev, "failed to select page 0: %d\n", ret); 409 return ret; 410 } 411 412 /* vendor code called this without param, where there should be one */ 413 ret = mipi_dsi_dcs_set_tear_on(dsi, 0); 414 if (ret < 0) { 415 DRM_DEV_ERROR(ctx->dev, "failed to set tear on: %d\n", 416 ret); 417 return ret; 418 } 419 420 msleep(60); 421 422 return 0; 423 } 424 425 static const struct drm_display_mode ltk050h3146w_a2_mode = { 426 .hdisplay = 720, 427 .hsync_start = 720 + 42, 428 .hsync_end = 720 + 42 + 10, 429 .htotal = 720 + 42 + 10 + 60, 430 .vdisplay = 1280, 431 .vsync_start = 1280 + 18, 432 .vsync_end = 1280 + 18 + 4, 433 .vtotal = 1280 + 18 + 4 + 12, 434 .clock = 65595, 435 .width_mm = 62, 436 .height_mm = 110, 437 }; 438 439 static const struct ltk050h3146w_desc ltk050h3146w_a2_data = { 440 .mode = <k050h3146w_a2_mode, 441 .init = ltk050h3146w_a2_init_sequence, 442 }; 443 444 static int ltk050h3146w_unprepare(struct drm_panel *panel) 445 { 446 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 447 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 448 int ret; 449 450 if (!ctx->prepared) 451 return 0; 452 453 ret = mipi_dsi_dcs_set_display_off(dsi); 454 if (ret < 0) { 455 DRM_DEV_ERROR(ctx->dev, "failed to set display off: %d\n", 456 ret); 457 return ret; 458 } 459 460 mipi_dsi_dcs_enter_sleep_mode(dsi); 461 if (ret < 0) { 462 DRM_DEV_ERROR(ctx->dev, "failed to enter sleep mode: %d\n", 463 ret); 464 return ret; 465 } 466 467 regulator_disable(ctx->iovcc); 468 regulator_disable(ctx->vci); 469 470 ctx->prepared = false; 471 472 return 0; 473 } 474 475 static int ltk050h3146w_prepare(struct drm_panel *panel) 476 { 477 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 478 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 479 int ret; 480 481 if (ctx->prepared) 482 return 0; 483 484 DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); 485 ret = regulator_enable(ctx->vci); 486 if (ret < 0) { 487 DRM_DEV_ERROR(ctx->dev, 488 "Failed to enable vci supply: %d\n", ret); 489 return ret; 490 } 491 ret = regulator_enable(ctx->iovcc); 492 if (ret < 0) { 493 DRM_DEV_ERROR(ctx->dev, 494 "Failed to enable iovcc supply: %d\n", ret); 495 goto disable_vci; 496 } 497 498 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 499 usleep_range(5000, 6000); 500 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 501 msleep(20); 502 503 ret = ctx->panel_desc->init(ctx); 504 if (ret < 0) { 505 DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", 506 ret); 507 goto disable_iovcc; 508 } 509 510 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 511 if (ret < 0) { 512 DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret); 513 goto disable_iovcc; 514 } 515 516 /* T9: 120ms */ 517 msleep(120); 518 519 ret = mipi_dsi_dcs_set_display_on(dsi); 520 if (ret < 0) { 521 DRM_DEV_ERROR(ctx->dev, "Failed to set display on: %d\n", ret); 522 goto disable_iovcc; 523 } 524 525 msleep(50); 526 527 ctx->prepared = true; 528 529 return 0; 530 531 disable_iovcc: 532 regulator_disable(ctx->iovcc); 533 disable_vci: 534 regulator_disable(ctx->vci); 535 return ret; 536 } 537 538 static int ltk050h3146w_get_modes(struct drm_panel *panel, 539 struct drm_connector *connector) 540 { 541 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 542 struct drm_display_mode *mode; 543 544 mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode); 545 if (!mode) 546 return -ENOMEM; 547 548 drm_mode_set_name(mode); 549 550 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 551 connector->display_info.width_mm = mode->width_mm; 552 connector->display_info.height_mm = mode->height_mm; 553 drm_mode_probed_add(connector, mode); 554 555 return 1; 556 } 557 558 static const struct drm_panel_funcs ltk050h3146w_funcs = { 559 .unprepare = ltk050h3146w_unprepare, 560 .prepare = ltk050h3146w_prepare, 561 .get_modes = ltk050h3146w_get_modes, 562 }; 563 564 static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) 565 { 566 struct device *dev = &dsi->dev; 567 struct ltk050h3146w *ctx; 568 int ret; 569 570 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 571 if (!ctx) 572 return -ENOMEM; 573 574 ctx->panel_desc = of_device_get_match_data(dev); 575 if (!ctx->panel_desc) 576 return -EINVAL; 577 578 ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 579 if (IS_ERR(ctx->reset_gpio)) { 580 DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); 581 return PTR_ERR(ctx->reset_gpio); 582 } 583 584 ctx->vci = devm_regulator_get(dev, "vci"); 585 if (IS_ERR(ctx->vci)) { 586 ret = PTR_ERR(ctx->vci); 587 if (ret != -EPROBE_DEFER) 588 DRM_DEV_ERROR(dev, 589 "Failed to request vci regulator: %d\n", 590 ret); 591 return ret; 592 } 593 594 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 595 if (IS_ERR(ctx->iovcc)) { 596 ret = PTR_ERR(ctx->iovcc); 597 if (ret != -EPROBE_DEFER) 598 DRM_DEV_ERROR(dev, 599 "Failed to request iovcc regulator: %d\n", 600 ret); 601 return ret; 602 } 603 604 mipi_dsi_set_drvdata(dsi, ctx); 605 606 ctx->dev = dev; 607 608 dsi->lanes = 4; 609 dsi->format = MIPI_DSI_FMT_RGB888; 610 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 611 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET; 612 613 drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs, 614 DRM_MODE_CONNECTOR_DSI); 615 616 ret = drm_panel_of_backlight(&ctx->panel); 617 if (ret) 618 return ret; 619 620 drm_panel_add(&ctx->panel); 621 622 ret = mipi_dsi_attach(dsi); 623 if (ret < 0) { 624 DRM_DEV_ERROR(dev, "mipi_dsi_attach failed: %d\n", ret); 625 drm_panel_remove(&ctx->panel); 626 return ret; 627 } 628 629 return 0; 630 } 631 632 static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi) 633 { 634 struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi); 635 int ret; 636 637 ret = drm_panel_unprepare(&ctx->panel); 638 if (ret < 0) 639 DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n", 640 ret); 641 642 ret = drm_panel_disable(&ctx->panel); 643 if (ret < 0) 644 DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n", 645 ret); 646 } 647 648 static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) 649 { 650 struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi); 651 int ret; 652 653 ltk050h3146w_shutdown(dsi); 654 655 ret = mipi_dsi_detach(dsi); 656 if (ret < 0) 657 DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n", 658 ret); 659 660 drm_panel_remove(&ctx->panel); 661 662 return 0; 663 } 664 665 static const struct of_device_id ltk050h3146w_of_match[] = { 666 { 667 .compatible = "leadtek,ltk050h3146w", 668 .data = <k050h3146w_data, 669 }, 670 { 671 .compatible = "leadtek,ltk050h3146w-a2", 672 .data = <k050h3146w_a2_data, 673 }, 674 { /* sentinel */ } 675 }; 676 MODULE_DEVICE_TABLE(of, ltk050h3146w_of_match); 677 678 static struct mipi_dsi_driver ltk050h3146w_driver = { 679 .driver = { 680 .name = "panel-leadtek-ltk050h3146w", 681 .of_match_table = ltk050h3146w_of_match, 682 }, 683 .probe = ltk050h3146w_probe, 684 .remove = ltk050h3146w_remove, 685 .shutdown = ltk050h3146w_shutdown, 686 }; 687 module_mipi_dsi_driver(ltk050h3146w_driver); 688 689 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>"); 690 MODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel"); 691 MODULE_LICENSE("GPL v2"); 692