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