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