1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2019 Theobroma Systems Design und Consulting GmbH 4 * 5 * base on panel-kingdisplay-kd097d04.c 6 * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd 7 */ 8 9 #include <linux/backlight.h> 10 #include <linux/delay.h> 11 #include <linux/gpio/consumer.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/of_device.h> 15 #include <linux/regulator/consumer.h> 16 17 #include <video/mipi_display.h> 18 19 #include <drm/drm_crtc.h> 20 #include <drm/drm_device.h> 21 #include <drm/drm_mipi_dsi.h> 22 #include <drm/drm_modes.h> 23 #include <drm/drm_panel.h> 24 25 struct ltk500hd1829_cmd { 26 char cmd; 27 char data; 28 }; 29 30 struct ltk500hd1829_desc { 31 const struct drm_display_mode *mode; 32 const struct ltk500hd1829_cmd *init; 33 unsigned int num_init; 34 }; 35 36 struct ltk500hd1829 { 37 struct device *dev; 38 struct drm_panel panel; 39 struct gpio_desc *reset_gpio; 40 struct regulator *vcc; 41 struct regulator *iovcc; 42 const struct ltk500hd1829_desc *panel_desc; 43 bool prepared; 44 }; 45 46 static const struct ltk500hd1829_cmd ltk101b4029w_init[] = { 47 /* Page0 */ 48 { 0xE0, 0x00 }, 49 /* PASSWORD */ 50 { 0xE1, 0x93 }, 51 { 0xE2, 0x65 }, 52 { 0xE3, 0xF8 }, 53 { 0x80, 0x03 }, /* 0X03:4-LANE; 0X02:3-LANE; 0X01:2-LANE */ 54 /* Page1 */ 55 { 0xE0, 0x01 }, 56 /* Set VCOM */ 57 { 0x00, 0x00 }, 58 { 0x01, 0x6F }, 59 /* Set Gamma Power, VGMP,VGMN,VGSP,VGSN */ 60 { 0x17, 0x00 }, 61 { 0x18, 0xAF }, /* 4.3V */ 62 { 0x19, 0x01 }, /* 0.3V */ 63 { 0x1A, 0x00 }, 64 { 0x1B, 0xAF }, /* 4.3V */ 65 { 0x1C, 0x01 }, /* 0.3V */ 66 /* Set Gate Power */ 67 { 0x1F, 0x3E }, /* VGH_R = 15V */ 68 { 0x20, 0x28 }, /* VGL_R = -12V */ 69 { 0x21, 0x28 }, /* VGL_R2 = -12V */ 70 { 0x22, 0x7E }, 71 /* SETPANEL */ 72 { 0x35, 0x26 }, 73 { 0x37, 0x09 }, 74 /* SET RGBCYC */ 75 { 0x38, 0x04 }, 76 { 0x39, 0x00 }, 77 { 0x3A, 0x01 }, 78 { 0x3C, 0x7C }, 79 { 0x3D, 0xFF }, 80 { 0x3E, 0xFF }, 81 { 0x3F, 0x7F }, 82 /* Set TCON */ 83 { 0x40, 0x06 }, /* RSO = 800 RGB */ 84 { 0x41, 0xA0 }, /* LN = 640->1280 line */ 85 { 0x42, 0x81 }, 86 { 0x43, 0x08 }, /* VFP = 8 */ 87 { 0x44, 0x0B }, /* VBP = 12 */ 88 { 0x45, 0x28 }, /* HBP = 40 */ 89 /* power voltage */ 90 { 0x55, 0x0F }, /* DCDCM = 0001, JD PWR_IC */ 91 { 0x57, 0x69 }, 92 { 0x59, 0x0A }, /* VCL = -2.9V */ 93 { 0x5A, 0x28 }, /* VGH = 15V */ 94 { 0x5B, 0x14 }, /* VGL = -11V */ 95 /* Gamma */ 96 { 0x5D, 0x7C }, 97 { 0x5E, 0x65 }, 98 { 0x5F, 0x55 }, 99 { 0x60, 0x47 }, 100 { 0x61, 0x43 }, 101 { 0x62, 0x32 }, 102 { 0x63, 0x34 }, 103 { 0x64, 0x1C }, 104 { 0x65, 0x33 }, 105 { 0x66, 0x31 }, 106 { 0x67, 0x30 }, 107 { 0x68, 0x4E }, 108 { 0x69, 0x3C }, 109 { 0x6A, 0x44 }, 110 { 0x6B, 0x35 }, 111 { 0x6C, 0x31 }, 112 { 0x6D, 0x23 }, 113 { 0x6E, 0x11 }, 114 { 0x6F, 0x00 }, 115 { 0x70, 0x7C }, 116 { 0x71, 0x65 }, 117 { 0x72, 0x55 }, 118 { 0x73, 0x47 }, 119 { 0x74, 0x43 }, 120 { 0x75, 0x32 }, 121 { 0x76, 0x34 }, 122 { 0x77, 0x1C }, 123 { 0x78, 0x33 }, 124 { 0x79, 0x31 }, 125 { 0x7A, 0x30 }, 126 { 0x7B, 0x4E }, 127 { 0x7C, 0x3C }, 128 { 0x7D, 0x44 }, 129 { 0x7E, 0x35 }, 130 { 0x7F, 0x31 }, 131 { 0x80, 0x23 }, 132 { 0x81, 0x11 }, 133 { 0x82, 0x00 }, 134 /* Page2, for GIP */ 135 { 0xE0, 0x02 }, 136 /* GIP_L Pin mapping */ 137 { 0x00, 0x1E }, 138 { 0x01, 0x1E }, 139 { 0x02, 0x41 }, 140 { 0x03, 0x41 }, 141 { 0x04, 0x43 }, 142 { 0x05, 0x43 }, 143 { 0x06, 0x1F }, 144 { 0x07, 0x1F }, 145 { 0x08, 0x35 }, 146 { 0x09, 0x1F }, 147 { 0x0A, 0x15 }, 148 { 0x0B, 0x15 }, 149 { 0x0C, 0x1F }, 150 { 0x0D, 0x47 }, 151 { 0x0E, 0x47 }, 152 { 0x0F, 0x45 }, 153 { 0x10, 0x45 }, 154 { 0x11, 0x4B }, 155 { 0x12, 0x4B }, 156 { 0x13, 0x49 }, 157 { 0x14, 0x49 }, 158 { 0x15, 0x1F }, 159 /* GIP_R Pin mapping */ 160 { 0x16, 0x1E }, 161 { 0x17, 0x1E }, 162 { 0x18, 0x40 }, 163 { 0x19, 0x40 }, 164 { 0x1A, 0x42 }, 165 { 0x1B, 0x42 }, 166 { 0x1C, 0x1F }, 167 { 0x1D, 0x1F }, 168 { 0x1E, 0x35 }, 169 { 0x1F, 0x1F }, 170 { 0x20, 0x15 }, 171 { 0x21, 0x15 }, 172 { 0x22, 0x1f }, 173 { 0x23, 0x46 }, 174 { 0x24, 0x46 }, 175 { 0x25, 0x44 }, 176 { 0x26, 0x44 }, 177 { 0x27, 0x4A }, 178 { 0x28, 0x4A }, 179 { 0x29, 0x48 }, 180 { 0x2A, 0x48 }, 181 { 0x2B, 0x1F }, 182 /* GIP Timing */ 183 { 0x58, 0x40 }, 184 { 0x5B, 0x30 }, 185 { 0x5C, 0x03 }, 186 { 0x5D, 0x30 }, 187 { 0x5E, 0x01 }, 188 { 0x5F, 0x02 }, 189 { 0x63, 0x14 }, 190 { 0x64, 0x6A }, 191 { 0x67, 0x73 }, 192 { 0x68, 0x05 }, 193 { 0x69, 0x14 }, 194 { 0x6A, 0x6A }, 195 { 0x6B, 0x08 }, 196 { 0x6C, 0x00 }, 197 { 0x6D, 0x00 }, 198 { 0x6E, 0x00 }, 199 { 0x6F, 0x88 }, 200 { 0x77, 0xDD }, 201 { 0x79, 0x0E }, 202 { 0x7A, 0x03 }, 203 { 0x7D, 0x14 }, 204 { 0x7E, 0x6A }, 205 /* Page4 */ 206 { 0xE0, 0x04 }, 207 { 0x09, 0x11 }, 208 { 0x0E, 0x48 }, 209 { 0x2B, 0x2B }, 210 { 0x2D, 0x03 }, 211 { 0x2E, 0x44 }, 212 /* Page0 */ 213 { 0xE0, 0x00 }, 214 { 0xE6, 0x02 }, 215 { 0xE7, 0x0C }, 216 }; 217 218 static const struct drm_display_mode ltk101b4029w_mode = { 219 .hdisplay = 800, 220 .hsync_start = 800 + 18, 221 .hsync_end = 800 + 18 + 18, 222 .htotal = 800 + 18 + 18 + 18, 223 .vdisplay = 1280, 224 .vsync_start = 1280 + 24, 225 .vsync_end = 1280 + 24 + 4, 226 .vtotal = 1280 + 24 + 4 + 8, 227 .clock = 67330, 228 .width_mm = 136, 229 .height_mm = 218, 230 }; 231 232 static const struct ltk500hd1829_desc ltk101b4029w_data = { 233 .mode = <k101b4029w_mode, 234 .init = ltk101b4029w_init, 235 .num_init = ARRAY_SIZE(ltk101b4029w_init), 236 }; 237 238 /* 239 * There is no description in the Reference Manual about these commands. 240 * We received them from the vendor, so just use them as is. 241 */ 242 static const struct ltk500hd1829_cmd ltk500hd1829_init[] = { 243 { 0xE0, 0x00 }, 244 { 0xE1, 0x93 }, 245 { 0xE2, 0x65 }, 246 { 0xE3, 0xF8 }, 247 { 0x80, 0x03 }, 248 { 0xE0, 0x04 }, 249 { 0x2D, 0x03 }, 250 { 0xE0, 0x01 }, 251 { 0x00, 0x00 }, 252 { 0x01, 0xB6 }, 253 { 0x03, 0x00 }, 254 { 0x04, 0xC5 }, 255 { 0x17, 0x00 }, 256 { 0x18, 0xBF }, 257 { 0x19, 0x01 }, 258 { 0x1A, 0x00 }, 259 { 0x1B, 0xBF }, 260 { 0x1C, 0x01 }, 261 { 0x1F, 0x7C }, 262 { 0x20, 0x26 }, 263 { 0x21, 0x26 }, 264 { 0x22, 0x4E }, 265 { 0x37, 0x09 }, 266 { 0x38, 0x04 }, 267 { 0x39, 0x08 }, 268 { 0x3A, 0x1F }, 269 { 0x3B, 0x1F }, 270 { 0x3C, 0x78 }, 271 { 0x3D, 0xFF }, 272 { 0x3E, 0xFF }, 273 { 0x3F, 0x00 }, 274 { 0x40, 0x04 }, 275 { 0x41, 0xA0 }, 276 { 0x43, 0x0F }, 277 { 0x44, 0x0A }, 278 { 0x45, 0x24 }, 279 { 0x55, 0x01 }, 280 { 0x56, 0x01 }, 281 { 0x57, 0xA5 }, 282 { 0x58, 0x0A }, 283 { 0x59, 0x4A }, 284 { 0x5A, 0x38 }, 285 { 0x5B, 0x10 }, 286 { 0x5C, 0x19 }, 287 { 0x5D, 0x7C }, 288 { 0x5E, 0x64 }, 289 { 0x5F, 0x54 }, 290 { 0x60, 0x48 }, 291 { 0x61, 0x44 }, 292 { 0x62, 0x35 }, 293 { 0x63, 0x3A }, 294 { 0x64, 0x24 }, 295 { 0x65, 0x3B }, 296 { 0x66, 0x39 }, 297 { 0x67, 0x37 }, 298 { 0x68, 0x56 }, 299 { 0x69, 0x41 }, 300 { 0x6A, 0x47 }, 301 { 0x6B, 0x2F }, 302 { 0x6C, 0x23 }, 303 { 0x6D, 0x13 }, 304 { 0x6E, 0x02 }, 305 { 0x6F, 0x08 }, 306 { 0x70, 0x7C }, 307 { 0x71, 0x64 }, 308 { 0x72, 0x54 }, 309 { 0x73, 0x48 }, 310 { 0x74, 0x44 }, 311 { 0x75, 0x35 }, 312 { 0x76, 0x3A }, 313 { 0x77, 0x22 }, 314 { 0x78, 0x3B }, 315 { 0x79, 0x39 }, 316 { 0x7A, 0x38 }, 317 { 0x7B, 0x52 }, 318 { 0x7C, 0x41 }, 319 { 0x7D, 0x47 }, 320 { 0x7E, 0x2F }, 321 { 0x7F, 0x23 }, 322 { 0x80, 0x13 }, 323 { 0x81, 0x02 }, 324 { 0x82, 0x08 }, 325 { 0xE0, 0x02 }, 326 { 0x00, 0x57 }, 327 { 0x01, 0x77 }, 328 { 0x02, 0x44 }, 329 { 0x03, 0x46 }, 330 { 0x04, 0x48 }, 331 { 0x05, 0x4A }, 332 { 0x06, 0x4C }, 333 { 0x07, 0x4E }, 334 { 0x08, 0x50 }, 335 { 0x09, 0x55 }, 336 { 0x0A, 0x52 }, 337 { 0x0B, 0x55 }, 338 { 0x0C, 0x55 }, 339 { 0x0D, 0x55 }, 340 { 0x0E, 0x55 }, 341 { 0x0F, 0x55 }, 342 { 0x10, 0x55 }, 343 { 0x11, 0x55 }, 344 { 0x12, 0x55 }, 345 { 0x13, 0x40 }, 346 { 0x14, 0x55 }, 347 { 0x15, 0x55 }, 348 { 0x16, 0x57 }, 349 { 0x17, 0x77 }, 350 { 0x18, 0x45 }, 351 { 0x19, 0x47 }, 352 { 0x1A, 0x49 }, 353 { 0x1B, 0x4B }, 354 { 0x1C, 0x4D }, 355 { 0x1D, 0x4F }, 356 { 0x1E, 0x51 }, 357 { 0x1F, 0x55 }, 358 { 0x20, 0x53 }, 359 { 0x21, 0x55 }, 360 { 0x22, 0x55 }, 361 { 0x23, 0x55 }, 362 { 0x24, 0x55 }, 363 { 0x25, 0x55 }, 364 { 0x26, 0x55 }, 365 { 0x27, 0x55 }, 366 { 0x28, 0x55 }, 367 { 0x29, 0x41 }, 368 { 0x2A, 0x55 }, 369 { 0x2B, 0x55 }, 370 { 0x2C, 0x57 }, 371 { 0x2D, 0x77 }, 372 { 0x2E, 0x4F }, 373 { 0x2F, 0x4D }, 374 { 0x30, 0x4B }, 375 { 0x31, 0x49 }, 376 { 0x32, 0x47 }, 377 { 0x33, 0x45 }, 378 { 0x34, 0x41 }, 379 { 0x35, 0x55 }, 380 { 0x36, 0x53 }, 381 { 0x37, 0x55 }, 382 { 0x38, 0x55 }, 383 { 0x39, 0x55 }, 384 { 0x3A, 0x55 }, 385 { 0x3B, 0x55 }, 386 { 0x3C, 0x55 }, 387 { 0x3D, 0x55 }, 388 { 0x3E, 0x55 }, 389 { 0x3F, 0x51 }, 390 { 0x40, 0x55 }, 391 { 0x41, 0x55 }, 392 { 0x42, 0x57 }, 393 { 0x43, 0x77 }, 394 { 0x44, 0x4E }, 395 { 0x45, 0x4C }, 396 { 0x46, 0x4A }, 397 { 0x47, 0x48 }, 398 { 0x48, 0x46 }, 399 { 0x49, 0x44 }, 400 { 0x4A, 0x40 }, 401 { 0x4B, 0x55 }, 402 { 0x4C, 0x52 }, 403 { 0x4D, 0x55 }, 404 { 0x4E, 0x55 }, 405 { 0x4F, 0x55 }, 406 { 0x50, 0x55 }, 407 { 0x51, 0x55 }, 408 { 0x52, 0x55 }, 409 { 0x53, 0x55 }, 410 { 0x54, 0x55 }, 411 { 0x55, 0x50 }, 412 { 0x56, 0x55 }, 413 { 0x57, 0x55 }, 414 { 0x58, 0x40 }, 415 { 0x59, 0x00 }, 416 { 0x5A, 0x00 }, 417 { 0x5B, 0x10 }, 418 { 0x5C, 0x09 }, 419 { 0x5D, 0x30 }, 420 { 0x5E, 0x01 }, 421 { 0x5F, 0x02 }, 422 { 0x60, 0x30 }, 423 { 0x61, 0x03 }, 424 { 0x62, 0x04 }, 425 { 0x63, 0x06 }, 426 { 0x64, 0x6A }, 427 { 0x65, 0x75 }, 428 { 0x66, 0x0F }, 429 { 0x67, 0xB3 }, 430 { 0x68, 0x0B }, 431 { 0x69, 0x06 }, 432 { 0x6A, 0x6A }, 433 { 0x6B, 0x10 }, 434 { 0x6C, 0x00 }, 435 { 0x6D, 0x04 }, 436 { 0x6E, 0x04 }, 437 { 0x6F, 0x88 }, 438 { 0x70, 0x00 }, 439 { 0x71, 0x00 }, 440 { 0x72, 0x06 }, 441 { 0x73, 0x7B }, 442 { 0x74, 0x00 }, 443 { 0x75, 0xBC }, 444 { 0x76, 0x00 }, 445 { 0x77, 0x05 }, 446 { 0x78, 0x2E }, 447 { 0x79, 0x00 }, 448 { 0x7A, 0x00 }, 449 { 0x7B, 0x00 }, 450 { 0x7C, 0x00 }, 451 { 0x7D, 0x03 }, 452 { 0x7E, 0x7B }, 453 { 0xE0, 0x04 }, 454 { 0x09, 0x10 }, 455 { 0x2B, 0x2B }, 456 { 0x2E, 0x44 }, 457 { 0xE0, 0x00 }, 458 { 0xE6, 0x02 }, 459 { 0xE7, 0x02 }, 460 { 0x35, 0x00 }, 461 }; 462 463 static const struct drm_display_mode ltk500hd1829_mode = { 464 .hdisplay = 720, 465 .hsync_start = 720 + 50, 466 .hsync_end = 720 + 50 + 50, 467 .htotal = 720 + 50 + 50 + 50, 468 .vdisplay = 1280, 469 .vsync_start = 1280 + 30, 470 .vsync_end = 1280 + 30 + 4, 471 .vtotal = 1280 + 30 + 4 + 12, 472 .clock = 69217, 473 .width_mm = 62, 474 .height_mm = 110, 475 }; 476 477 static const struct ltk500hd1829_desc ltk500hd1829_data = { 478 .mode = <k500hd1829_mode, 479 .init = ltk500hd1829_init, 480 .num_init = ARRAY_SIZE(ltk500hd1829_init), 481 }; 482 483 static inline 484 struct ltk500hd1829 *panel_to_ltk500hd1829(struct drm_panel *panel) 485 { 486 return container_of(panel, struct ltk500hd1829, panel); 487 } 488 489 static int ltk500hd1829_unprepare(struct drm_panel *panel) 490 { 491 struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel); 492 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 493 int ret; 494 495 if (!ctx->prepared) 496 return 0; 497 498 ret = mipi_dsi_dcs_set_display_off(dsi); 499 if (ret < 0) 500 dev_err(panel->dev, "failed to set display off: %d\n", ret); 501 502 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 503 if (ret < 0) { 504 dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); 505 } 506 507 /* 120ms to enter sleep mode */ 508 msleep(120); 509 510 regulator_disable(ctx->iovcc); 511 regulator_disable(ctx->vcc); 512 513 ctx->prepared = false; 514 515 return 0; 516 } 517 518 static int ltk500hd1829_prepare(struct drm_panel *panel) 519 { 520 struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel); 521 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 522 unsigned int i; 523 int ret; 524 525 if (ctx->prepared) 526 return 0; 527 528 ret = regulator_enable(ctx->vcc); 529 if (ret < 0) { 530 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); 531 return ret; 532 } 533 ret = regulator_enable(ctx->iovcc); 534 if (ret < 0) { 535 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); 536 goto disable_vcc; 537 } 538 539 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 540 /* tRW: 10us */ 541 usleep_range(10, 20); 542 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 543 544 /* tRT: >= 5ms */ 545 usleep_range(5000, 6000); 546 547 for (i = 0; i < ctx->panel_desc->num_init; i++) { 548 ret = mipi_dsi_generic_write(dsi, &ctx->panel_desc->init[i], 549 sizeof(struct ltk500hd1829_cmd)); 550 if (ret < 0) { 551 dev_err(panel->dev, "failed to write init cmds: %d\n", ret); 552 goto disable_iovcc; 553 } 554 } 555 556 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 557 if (ret < 0) { 558 dev_err(panel->dev, "failed to exit sleep mode: %d\n", ret); 559 goto disable_iovcc; 560 } 561 562 /* 120ms to exit sleep mode */ 563 msleep(120); 564 565 ret = mipi_dsi_dcs_set_display_on(dsi); 566 if (ret < 0) { 567 dev_err(panel->dev, "failed to set display on: %d\n", ret); 568 goto disable_iovcc; 569 } 570 571 ctx->prepared = true; 572 573 return 0; 574 575 disable_iovcc: 576 regulator_disable(ctx->iovcc); 577 disable_vcc: 578 regulator_disable(ctx->vcc); 579 return ret; 580 } 581 582 static int ltk500hd1829_get_modes(struct drm_panel *panel, 583 struct drm_connector *connector) 584 { 585 struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel); 586 struct drm_display_mode *mode; 587 588 mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode); 589 if (!mode) { 590 dev_err(ctx->dev, "failed to add mode %ux%u@%u\n", 591 ctx->panel_desc->mode->hdisplay, ctx->panel_desc->mode->vdisplay, 592 drm_mode_vrefresh(ctx->panel_desc->mode)); 593 return -ENOMEM; 594 } 595 596 drm_mode_set_name(mode); 597 598 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 599 connector->display_info.width_mm = mode->width_mm; 600 connector->display_info.height_mm = mode->height_mm; 601 drm_mode_probed_add(connector, mode); 602 603 return 1; 604 } 605 606 static const struct drm_panel_funcs ltk500hd1829_funcs = { 607 .unprepare = ltk500hd1829_unprepare, 608 .prepare = ltk500hd1829_prepare, 609 .get_modes = ltk500hd1829_get_modes, 610 }; 611 612 static int ltk500hd1829_probe(struct mipi_dsi_device *dsi) 613 { 614 struct ltk500hd1829 *ctx; 615 struct device *dev = &dsi->dev; 616 int ret; 617 618 ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); 619 if (!ctx) 620 return -ENOMEM; 621 622 ctx->panel_desc = of_device_get_match_data(dev); 623 if (!ctx->panel_desc) 624 return -EINVAL; 625 626 ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 627 if (IS_ERR(ctx->reset_gpio)) { 628 dev_err(dev, "cannot get reset gpio\n"); 629 return PTR_ERR(ctx->reset_gpio); 630 } 631 632 ctx->vcc = devm_regulator_get(dev, "vcc"); 633 if (IS_ERR(ctx->vcc)) { 634 ret = PTR_ERR(ctx->vcc); 635 if (ret != -EPROBE_DEFER) 636 dev_err(dev, "Failed to request vcc regulator: %d\n", ret); 637 return ret; 638 } 639 640 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 641 if (IS_ERR(ctx->iovcc)) { 642 ret = PTR_ERR(ctx->iovcc); 643 if (ret != -EPROBE_DEFER) 644 dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); 645 return ret; 646 } 647 648 mipi_dsi_set_drvdata(dsi, ctx); 649 650 ctx->dev = dev; 651 652 dsi->lanes = 4; 653 dsi->format = MIPI_DSI_FMT_RGB888; 654 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 655 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; 656 657 drm_panel_init(&ctx->panel, &dsi->dev, <k500hd1829_funcs, 658 DRM_MODE_CONNECTOR_DSI); 659 660 ret = drm_panel_of_backlight(&ctx->panel); 661 if (ret) 662 return ret; 663 664 drm_panel_add(&ctx->panel); 665 666 ret = mipi_dsi_attach(dsi); 667 if (ret < 0) { 668 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); 669 drm_panel_remove(&ctx->panel); 670 return ret; 671 } 672 673 return 0; 674 } 675 676 static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi) 677 { 678 struct ltk500hd1829 *ctx = mipi_dsi_get_drvdata(dsi); 679 int ret; 680 681 ret = drm_panel_unprepare(&ctx->panel); 682 if (ret < 0) 683 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); 684 685 ret = drm_panel_disable(&ctx->panel); 686 if (ret < 0) 687 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); 688 } 689 690 static void ltk500hd1829_remove(struct mipi_dsi_device *dsi) 691 { 692 struct ltk500hd1829 *ctx = mipi_dsi_get_drvdata(dsi); 693 int ret; 694 695 ltk500hd1829_shutdown(dsi); 696 697 ret = mipi_dsi_detach(dsi); 698 if (ret < 0) 699 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); 700 701 drm_panel_remove(&ctx->panel); 702 } 703 704 static const struct of_device_id ltk500hd1829_of_match[] = { 705 { 706 .compatible = "leadtek,ltk101b4029w", 707 .data = <k101b4029w_data, 708 }, 709 { 710 .compatible = "leadtek,ltk500hd1829", 711 .data = <k500hd1829_data, 712 }, 713 { /* sentinel */ } 714 }; 715 MODULE_DEVICE_TABLE(of, ltk500hd1829_of_match); 716 717 static struct mipi_dsi_driver ltk500hd1829_driver = { 718 .driver = { 719 .name = "panel-leadtek-ltk500hd1829", 720 .of_match_table = ltk500hd1829_of_match, 721 }, 722 .probe = ltk500hd1829_probe, 723 .remove = ltk500hd1829_remove, 724 .shutdown = ltk500hd1829_shutdown, 725 }; 726 module_mipi_dsi_driver(ltk500hd1829_driver); 727 728 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>"); 729 MODULE_DESCRIPTION("Leadtek LTK500HD1829 panel driver"); 730 MODULE_LICENSE("GPL v2"); 731