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 unsigned long mode_flags; 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 ltk050h3148w_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, 0xb9, 0xff, 0x83, 0x94); 257 mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x50, 0x15, 0x75, 0x09, 0x32, 0x44, 258 0x71, 0x31, 0x55, 0x2f); 259 mipi_dsi_dcs_write_seq(dsi, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 260 mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x88); 261 mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x80, 0x64, 0x10, 0x07); 262 mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x05, 0x70, 0x05, 0x70, 0x01, 0x70, 263 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, 0x01, 0x74, 264 0x01, 0x74, 0x01, 0x74, 0x01, 0x0c, 0x86); 265 mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x00, 0x00, 0x07, 0x07, 0x40, 0x1e, 266 0x08, 0x00, 0x32, 0x10, 0x08, 0x00, 0x08, 0x54, 267 0x15, 0x10, 0x05, 0x04, 0x02, 0x12, 0x10, 0x05, 268 0x07, 0x33, 0x34, 0x0c, 0x0c, 0x37, 0x10, 0x07, 269 0x17, 0x11, 0x40); 270 mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 271 0x1a, 0x1a, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 272 0x02, 0x03, 0x20, 0x21, 0x18, 0x18, 0x22, 0x23, 273 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 274 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 275 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 276 mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 277 0x1a, 0x1a, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 278 0x05, 0x04, 0x23, 0x22, 0x18, 0x18, 0x21, 0x20, 279 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 280 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 281 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 282 mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x00, 0x03, 0x09, 0x11, 0x11, 0x14, 283 0x18, 0x16, 0x2e, 0x3d, 0x4d, 0x4d, 0x58, 0x6c, 284 0x72, 0x78, 0x88, 0x8b, 0x86, 0xa4, 0xb2, 0x58, 285 0x55, 0x59, 0x5b, 0x5d, 0x60, 0x64, 0x7f, 0x00, 286 0x03, 0x09, 0x0f, 0x11, 0x14, 0x18, 0x16, 0x2e, 287 0x3d, 0x4d, 0x4d, 0x58, 0x6d, 0x73, 0x78, 0x88, 288 0x8b, 0x87, 0xa5, 0xb2, 0x58, 0x55, 0x58, 0x5b, 289 0x5d, 0x61, 0x65, 0x7f); 290 mipi_dsi_dcs_write_seq(dsi, 0xcc, 0x0b); 291 mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x1f, 0x31); 292 mipi_dsi_dcs_write_seq(dsi, 0xb6, 0xc4, 0xc4); 293 mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x01); 294 mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00); 295 mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x00); 296 mipi_dsi_dcs_write_seq(dsi, 0xc6, 0xef); 297 mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x02); 298 299 ret = mipi_dsi_dcs_set_tear_on(dsi, 1); 300 if (ret < 0) { 301 dev_err(ctx->dev, "failed to set tear on: %d\n", ret); 302 return ret; 303 } 304 305 msleep(60); 306 307 return 0; 308 } 309 310 static const struct drm_display_mode ltk050h3148w_mode = { 311 .hdisplay = 720, 312 .hsync_start = 720 + 12, 313 .hsync_end = 720 + 12 + 6, 314 .htotal = 720 + 12 + 6 + 24, 315 .vdisplay = 1280, 316 .vsync_start = 1280 + 9, 317 .vsync_end = 1280 + 9 + 2, 318 .vtotal = 1280 + 9 + 2 + 16, 319 .clock = 59756, 320 .width_mm = 62, 321 .height_mm = 110, 322 }; 323 324 static const struct ltk050h3146w_desc ltk050h3148w_data = { 325 .mode = <k050h3148w_mode, 326 .init = ltk050h3148w_init_sequence, 327 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 328 MIPI_DSI_MODE_VIDEO_BURST, 329 }; 330 331 static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) 332 { 333 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 334 int ret; 335 336 /* 337 * Init sequence was supplied by the panel vendor without much 338 * documentation. 339 */ 340 mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8); 341 mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06, 342 0x01); 343 mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5); 344 mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5); 345 mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00); 346 347 mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07); 348 mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f, 349 0x28, 0x04, 0xcc, 0xcc, 0xcc); 350 mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04); 351 mipi_dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2); 352 mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03); 353 mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12); 354 mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80, 355 0x80); 356 mipi_dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f, 357 0x16, 0x00, 0x00); 358 mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50, 359 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f, 360 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67, 361 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55, 362 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08); 363 mipi_dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a, 364 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f, 365 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 366 mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b, 367 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f, 368 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 369 mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05, 370 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f, 371 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 372 mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04, 373 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f, 374 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 375 mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20, 376 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03, 377 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08); 378 mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00, 379 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05, 380 0x21, 0x00, 0x60); 381 mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00); 382 mipi_dsi_dcs_write_seq(dsi, 0xde, 0x02); 383 mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c); 384 mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04); 385 mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x11); 386 mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37); 387 mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84); 388 mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00); 389 390 ret = mipi_dsi_dcs_set_tear_on(dsi, 1); 391 if (ret < 0) { 392 dev_err(ctx->dev, "failed to set tear on: %d\n", ret); 393 return ret; 394 } 395 396 msleep(60); 397 398 return 0; 399 } 400 401 static const struct drm_display_mode ltk050h3146w_mode = { 402 .hdisplay = 720, 403 .hsync_start = 720 + 42, 404 .hsync_end = 720 + 42 + 8, 405 .htotal = 720 + 42 + 8 + 42, 406 .vdisplay = 1280, 407 .vsync_start = 1280 + 12, 408 .vsync_end = 1280 + 12 + 4, 409 .vtotal = 1280 + 12 + 4 + 18, 410 .clock = 64018, 411 .width_mm = 62, 412 .height_mm = 110, 413 }; 414 415 static const struct ltk050h3146w_desc ltk050h3146w_data = { 416 .mode = <k050h3146w_mode, 417 .init = ltk050h3146w_init_sequence, 418 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 419 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, 420 }; 421 422 static int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page) 423 { 424 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 425 u8 d[3] = { 0x98, 0x81, page }; 426 427 return mipi_dsi_dcs_write(dsi, 0xff, d, ARRAY_SIZE(d)); 428 } 429 430 static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page, 431 const struct ltk050h3146w_cmd *cmds, 432 int num) 433 { 434 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 435 int i, ret; 436 437 ret = ltk050h3146w_a2_select_page(ctx, page); 438 if (ret < 0) { 439 dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret); 440 return ret; 441 } 442 443 for (i = 0; i < num; i++) { 444 ret = mipi_dsi_generic_write(dsi, &cmds[i], 445 sizeof(struct ltk050h3146w_cmd)); 446 if (ret < 0) { 447 dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret); 448 return ret; 449 } 450 } 451 452 return 0; 453 } 454 455 static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx) 456 { 457 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 458 int ret; 459 460 /* 461 * Init sequence was supplied by the panel vendor without much 462 * documentation. 463 */ 464 ret = ltk050h3146w_a2_write_page(ctx, 3, page3_cmds, 465 ARRAY_SIZE(page3_cmds)); 466 if (ret < 0) 467 return ret; 468 469 ret = ltk050h3146w_a2_write_page(ctx, 4, page4_cmds, 470 ARRAY_SIZE(page4_cmds)); 471 if (ret < 0) 472 return ret; 473 474 ret = ltk050h3146w_a2_write_page(ctx, 1, page1_cmds, 475 ARRAY_SIZE(page1_cmds)); 476 if (ret < 0) 477 return ret; 478 479 ret = ltk050h3146w_a2_select_page(ctx, 0); 480 if (ret < 0) { 481 dev_err(ctx->dev, "failed to select page 0: %d\n", ret); 482 return ret; 483 } 484 485 /* vendor code called this without param, where there should be one */ 486 ret = mipi_dsi_dcs_set_tear_on(dsi, 0); 487 if (ret < 0) { 488 dev_err(ctx->dev, "failed to set tear on: %d\n", ret); 489 return ret; 490 } 491 492 msleep(60); 493 494 return 0; 495 } 496 497 static const struct drm_display_mode ltk050h3146w_a2_mode = { 498 .hdisplay = 720, 499 .hsync_start = 720 + 42, 500 .hsync_end = 720 + 42 + 10, 501 .htotal = 720 + 42 + 10 + 60, 502 .vdisplay = 1280, 503 .vsync_start = 1280 + 18, 504 .vsync_end = 1280 + 18 + 4, 505 .vtotal = 1280 + 18 + 4 + 12, 506 .clock = 65595, 507 .width_mm = 62, 508 .height_mm = 110, 509 }; 510 511 static const struct ltk050h3146w_desc ltk050h3146w_a2_data = { 512 .mode = <k050h3146w_a2_mode, 513 .init = ltk050h3146w_a2_init_sequence, 514 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 515 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, 516 }; 517 518 static int ltk050h3146w_unprepare(struct drm_panel *panel) 519 { 520 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 521 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 522 int ret; 523 524 if (!ctx->prepared) 525 return 0; 526 527 ret = mipi_dsi_dcs_set_display_off(dsi); 528 if (ret < 0) { 529 dev_err(ctx->dev, "failed to set display off: %d\n", ret); 530 return ret; 531 } 532 533 mipi_dsi_dcs_enter_sleep_mode(dsi); 534 if (ret < 0) { 535 dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret); 536 return ret; 537 } 538 539 regulator_disable(ctx->iovcc); 540 regulator_disable(ctx->vci); 541 542 ctx->prepared = false; 543 544 return 0; 545 } 546 547 static int ltk050h3146w_prepare(struct drm_panel *panel) 548 { 549 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 550 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 551 int ret; 552 553 if (ctx->prepared) 554 return 0; 555 556 dev_dbg(ctx->dev, "Resetting the panel\n"); 557 ret = regulator_enable(ctx->vci); 558 if (ret < 0) { 559 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret); 560 return ret; 561 } 562 ret = regulator_enable(ctx->iovcc); 563 if (ret < 0) { 564 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); 565 goto disable_vci; 566 } 567 568 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 569 usleep_range(5000, 6000); 570 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 571 msleep(20); 572 573 ret = ctx->panel_desc->init(ctx); 574 if (ret < 0) { 575 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); 576 goto disable_iovcc; 577 } 578 579 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 580 if (ret < 0) { 581 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); 582 goto disable_iovcc; 583 } 584 585 /* T9: 120ms */ 586 msleep(120); 587 588 ret = mipi_dsi_dcs_set_display_on(dsi); 589 if (ret < 0) { 590 dev_err(ctx->dev, "Failed to set display on: %d\n", ret); 591 goto disable_iovcc; 592 } 593 594 msleep(50); 595 596 ctx->prepared = true; 597 598 return 0; 599 600 disable_iovcc: 601 regulator_disable(ctx->iovcc); 602 disable_vci: 603 regulator_disable(ctx->vci); 604 return ret; 605 } 606 607 static int ltk050h3146w_get_modes(struct drm_panel *panel, 608 struct drm_connector *connector) 609 { 610 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel); 611 struct drm_display_mode *mode; 612 613 mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode); 614 if (!mode) 615 return -ENOMEM; 616 617 drm_mode_set_name(mode); 618 619 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 620 connector->display_info.width_mm = mode->width_mm; 621 connector->display_info.height_mm = mode->height_mm; 622 drm_mode_probed_add(connector, mode); 623 624 return 1; 625 } 626 627 static const struct drm_panel_funcs ltk050h3146w_funcs = { 628 .unprepare = ltk050h3146w_unprepare, 629 .prepare = ltk050h3146w_prepare, 630 .get_modes = ltk050h3146w_get_modes, 631 }; 632 633 static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) 634 { 635 struct device *dev = &dsi->dev; 636 struct ltk050h3146w *ctx; 637 int ret; 638 639 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 640 if (!ctx) 641 return -ENOMEM; 642 643 ctx->panel_desc = of_device_get_match_data(dev); 644 if (!ctx->panel_desc) 645 return -EINVAL; 646 647 ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 648 if (IS_ERR(ctx->reset_gpio)) 649 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n"); 650 651 ctx->vci = devm_regulator_get(dev, "vci"); 652 if (IS_ERR(ctx->vci)) 653 return dev_err_probe(dev, PTR_ERR(ctx->vci), "Failed to request vci regulator\n"); 654 655 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 656 if (IS_ERR(ctx->iovcc)) 657 return dev_err_probe(dev, PTR_ERR(ctx->iovcc), 658 "Failed to request iovcc regulator\n"); 659 660 mipi_dsi_set_drvdata(dsi, ctx); 661 662 ctx->dev = dev; 663 664 dsi->lanes = 4; 665 dsi->format = MIPI_DSI_FMT_RGB888; 666 dsi->mode_flags = ctx->panel_desc->mode_flags; 667 668 drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs, 669 DRM_MODE_CONNECTOR_DSI); 670 671 ret = drm_panel_of_backlight(&ctx->panel); 672 if (ret) 673 return ret; 674 675 drm_panel_add(&ctx->panel); 676 677 ret = mipi_dsi_attach(dsi); 678 if (ret < 0) { 679 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret); 680 drm_panel_remove(&ctx->panel); 681 return ret; 682 } 683 684 return 0; 685 } 686 687 static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi) 688 { 689 struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi); 690 int ret; 691 692 ret = drm_panel_unprepare(&ctx->panel); 693 if (ret < 0) 694 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); 695 696 ret = drm_panel_disable(&ctx->panel); 697 if (ret < 0) 698 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); 699 } 700 701 static void ltk050h3146w_remove(struct mipi_dsi_device *dsi) 702 { 703 struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi); 704 int ret; 705 706 ltk050h3146w_shutdown(dsi); 707 708 ret = mipi_dsi_detach(dsi); 709 if (ret < 0) 710 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 711 712 drm_panel_remove(&ctx->panel); 713 } 714 715 static const struct of_device_id ltk050h3146w_of_match[] = { 716 { 717 .compatible = "leadtek,ltk050h3146w", 718 .data = <k050h3146w_data, 719 }, 720 { 721 .compatible = "leadtek,ltk050h3146w-a2", 722 .data = <k050h3146w_a2_data, 723 }, 724 { 725 .compatible = "leadtek,ltk050h3148w", 726 .data = <k050h3148w_data, 727 }, 728 { /* sentinel */ } 729 }; 730 MODULE_DEVICE_TABLE(of, ltk050h3146w_of_match); 731 732 static struct mipi_dsi_driver ltk050h3146w_driver = { 733 .driver = { 734 .name = "panel-leadtek-ltk050h3146w", 735 .of_match_table = ltk050h3146w_of_match, 736 }, 737 .probe = ltk050h3146w_probe, 738 .remove = ltk050h3146w_remove, 739 .shutdown = ltk050h3146w_shutdown, 740 }; 741 module_mipi_dsi_driver(ltk050h3146w_driver); 742 743 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>"); 744 MODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel"); 745 MODULE_LICENSE("GPL v2"); 746