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