1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 BayLibre, SAS 4 * Author: Neil Armstrong <narmstrong@baylibre.com> 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/gpio/consumer.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/regulator/consumer.h> 12 13 #include <video/mipi_display.h> 14 15 #include <drm/drm_crtc.h> 16 #include <drm/drm_device.h> 17 #include <drm/drm_mipi_dsi.h> 18 #include <drm/drm_modes.h> 19 #include <drm/drm_panel.h> 20 21 struct khadas_ts050_panel { 22 struct drm_panel base; 23 struct mipi_dsi_device *link; 24 25 struct regulator *supply; 26 struct gpio_desc *reset_gpio; 27 struct gpio_desc *enable_gpio; 28 29 bool prepared; 30 bool enabled; 31 }; 32 33 struct khadas_ts050_panel_cmd { 34 u8 cmd; 35 u8 data; 36 }; 37 38 /* Only the CMD1 User Command set is documented */ 39 static const struct khadas_ts050_panel_cmd init_code[] = { 40 /* Select Unknown CMD Page (Undocumented) */ 41 {0xff, 0xee}, 42 /* Reload CMD1: Don't reload default value to register */ 43 {0xfb, 0x01}, 44 {0x1f, 0x45}, 45 {0x24, 0x4f}, 46 {0x38, 0xc8}, 47 {0x39, 0x27}, 48 {0x1e, 0x77}, 49 {0x1d, 0x0f}, 50 {0x7e, 0x71}, 51 {0x7c, 0x03}, 52 {0xff, 0x00}, 53 {0xfb, 0x01}, 54 {0x35, 0x01}, 55 /* Select CMD2 Page0 (Undocumented) */ 56 {0xff, 0x01}, 57 /* Reload CMD1: Don't reload default value to register */ 58 {0xfb, 0x01}, 59 {0x00, 0x01}, 60 {0x01, 0x55}, 61 {0x02, 0x40}, 62 {0x05, 0x40}, 63 {0x06, 0x4a}, 64 {0x07, 0x24}, 65 {0x08, 0x0c}, 66 {0x0b, 0x7d}, 67 {0x0c, 0x7d}, 68 {0x0e, 0xb0}, 69 {0x0f, 0xae}, 70 {0x11, 0x10}, 71 {0x12, 0x10}, 72 {0x13, 0x03}, 73 {0x14, 0x4a}, 74 {0x15, 0x12}, 75 {0x16, 0x12}, 76 {0x18, 0x00}, 77 {0x19, 0x77}, 78 {0x1a, 0x55}, 79 {0x1b, 0x13}, 80 {0x1c, 0x00}, 81 {0x1d, 0x00}, 82 {0x1e, 0x13}, 83 {0x1f, 0x00}, 84 {0x23, 0x00}, 85 {0x24, 0x00}, 86 {0x25, 0x00}, 87 {0x26, 0x00}, 88 {0x27, 0x00}, 89 {0x28, 0x00}, 90 {0x35, 0x00}, 91 {0x66, 0x00}, 92 {0x58, 0x82}, 93 {0x59, 0x02}, 94 {0x5a, 0x02}, 95 {0x5b, 0x02}, 96 {0x5c, 0x82}, 97 {0x5d, 0x82}, 98 {0x5e, 0x02}, 99 {0x5f, 0x02}, 100 {0x72, 0x31}, 101 /* Select CMD2 Page4 (Undocumented) */ 102 {0xff, 0x05}, 103 /* Reload CMD1: Don't reload default value to register */ 104 {0xfb, 0x01}, 105 {0x00, 0x01}, 106 {0x01, 0x0b}, 107 {0x02, 0x0c}, 108 {0x03, 0x09}, 109 {0x04, 0x0a}, 110 {0x05, 0x00}, 111 {0x06, 0x0f}, 112 {0x07, 0x10}, 113 {0x08, 0x00}, 114 {0x09, 0x00}, 115 {0x0a, 0x00}, 116 {0x0b, 0x00}, 117 {0x0c, 0x00}, 118 {0x0d, 0x13}, 119 {0x0e, 0x15}, 120 {0x0f, 0x17}, 121 {0x10, 0x01}, 122 {0x11, 0x0b}, 123 {0x12, 0x0c}, 124 {0x13, 0x09}, 125 {0x14, 0x0a}, 126 {0x15, 0x00}, 127 {0x16, 0x0f}, 128 {0x17, 0x10}, 129 {0x18, 0x00}, 130 {0x19, 0x00}, 131 {0x1a, 0x00}, 132 {0x1b, 0x00}, 133 {0x1c, 0x00}, 134 {0x1d, 0x13}, 135 {0x1e, 0x15}, 136 {0x1f, 0x17}, 137 {0x20, 0x00}, 138 {0x21, 0x03}, 139 {0x22, 0x01}, 140 {0x23, 0x40}, 141 {0x24, 0x40}, 142 {0x25, 0xed}, 143 {0x29, 0x58}, 144 {0x2a, 0x12}, 145 {0x2b, 0x01}, 146 {0x4b, 0x06}, 147 {0x4c, 0x11}, 148 {0x4d, 0x20}, 149 {0x4e, 0x02}, 150 {0x4f, 0x02}, 151 {0x50, 0x20}, 152 {0x51, 0x61}, 153 {0x52, 0x01}, 154 {0x53, 0x63}, 155 {0x54, 0x77}, 156 {0x55, 0xed}, 157 {0x5b, 0x00}, 158 {0x5c, 0x00}, 159 {0x5d, 0x00}, 160 {0x5e, 0x00}, 161 {0x5f, 0x15}, 162 {0x60, 0x75}, 163 {0x61, 0x00}, 164 {0x62, 0x00}, 165 {0x63, 0x00}, 166 {0x64, 0x00}, 167 {0x65, 0x00}, 168 {0x66, 0x00}, 169 {0x67, 0x00}, 170 {0x68, 0x04}, 171 {0x69, 0x00}, 172 {0x6a, 0x00}, 173 {0x6c, 0x40}, 174 {0x75, 0x01}, 175 {0x76, 0x01}, 176 {0x7a, 0x80}, 177 {0x7b, 0xa3}, 178 {0x7c, 0xd8}, 179 {0x7d, 0x60}, 180 {0x7f, 0x15}, 181 {0x80, 0x81}, 182 {0x83, 0x05}, 183 {0x93, 0x08}, 184 {0x94, 0x10}, 185 {0x8a, 0x00}, 186 {0x9b, 0x0f}, 187 {0xea, 0xff}, 188 {0xec, 0x00}, 189 /* Select CMD2 Page0 (Undocumented) */ 190 {0xff, 0x01}, 191 /* Reload CMD1: Don't reload default value to register */ 192 {0xfb, 0x01}, 193 {0x75, 0x00}, 194 {0x76, 0xdf}, 195 {0x77, 0x00}, 196 {0x78, 0xe4}, 197 {0x79, 0x00}, 198 {0x7a, 0xed}, 199 {0x7b, 0x00}, 200 {0x7c, 0xf6}, 201 {0x7d, 0x00}, 202 {0x7e, 0xff}, 203 {0x7f, 0x01}, 204 {0x80, 0x07}, 205 {0x81, 0x01}, 206 {0x82, 0x10}, 207 {0x83, 0x01}, 208 {0x84, 0x18}, 209 {0x85, 0x01}, 210 {0x86, 0x20}, 211 {0x87, 0x01}, 212 {0x88, 0x3d}, 213 {0x89, 0x01}, 214 {0x8a, 0x56}, 215 {0x8b, 0x01}, 216 {0x8c, 0x84}, 217 {0x8d, 0x01}, 218 {0x8e, 0xab}, 219 {0x8f, 0x01}, 220 {0x90, 0xec}, 221 {0x91, 0x02}, 222 {0x92, 0x22}, 223 {0x93, 0x02}, 224 {0x94, 0x23}, 225 {0x95, 0x02}, 226 {0x96, 0x55}, 227 {0x97, 0x02}, 228 {0x98, 0x8b}, 229 {0x99, 0x02}, 230 {0x9a, 0xaf}, 231 {0x9b, 0x02}, 232 {0x9c, 0xdf}, 233 {0x9d, 0x03}, 234 {0x9e, 0x01}, 235 {0x9f, 0x03}, 236 {0xa0, 0x2c}, 237 {0xa2, 0x03}, 238 {0xa3, 0x39}, 239 {0xa4, 0x03}, 240 {0xa5, 0x47}, 241 {0xa6, 0x03}, 242 {0xa7, 0x56}, 243 {0xa9, 0x03}, 244 {0xaa, 0x66}, 245 {0xab, 0x03}, 246 {0xac, 0x76}, 247 {0xad, 0x03}, 248 {0xae, 0x85}, 249 {0xaf, 0x03}, 250 {0xb0, 0x90}, 251 {0xb1, 0x03}, 252 {0xb2, 0xcb}, 253 {0xb3, 0x00}, 254 {0xb4, 0xdf}, 255 {0xb5, 0x00}, 256 {0xb6, 0xe4}, 257 {0xb7, 0x00}, 258 {0xb8, 0xed}, 259 {0xb9, 0x00}, 260 {0xba, 0xf6}, 261 {0xbb, 0x00}, 262 {0xbc, 0xff}, 263 {0xbd, 0x01}, 264 {0xbe, 0x07}, 265 {0xbf, 0x01}, 266 {0xc0, 0x10}, 267 {0xc1, 0x01}, 268 {0xc2, 0x18}, 269 {0xc3, 0x01}, 270 {0xc4, 0x20}, 271 {0xc5, 0x01}, 272 {0xc6, 0x3d}, 273 {0xc7, 0x01}, 274 {0xc8, 0x56}, 275 {0xc9, 0x01}, 276 {0xca, 0x84}, 277 {0xcb, 0x01}, 278 {0xcc, 0xab}, 279 {0xcd, 0x01}, 280 {0xce, 0xec}, 281 {0xcf, 0x02}, 282 {0xd0, 0x22}, 283 {0xd1, 0x02}, 284 {0xd2, 0x23}, 285 {0xd3, 0x02}, 286 {0xd4, 0x55}, 287 {0xd5, 0x02}, 288 {0xd6, 0x8b}, 289 {0xd7, 0x02}, 290 {0xd8, 0xaf}, 291 {0xd9, 0x02}, 292 {0xda, 0xdf}, 293 {0xdb, 0x03}, 294 {0xdc, 0x01}, 295 {0xdd, 0x03}, 296 {0xde, 0x2c}, 297 {0xdf, 0x03}, 298 {0xe0, 0x39}, 299 {0xe1, 0x03}, 300 {0xe2, 0x47}, 301 {0xe3, 0x03}, 302 {0xe4, 0x56}, 303 {0xe5, 0x03}, 304 {0xe6, 0x66}, 305 {0xe7, 0x03}, 306 {0xe8, 0x76}, 307 {0xe9, 0x03}, 308 {0xea, 0x85}, 309 {0xeb, 0x03}, 310 {0xec, 0x90}, 311 {0xed, 0x03}, 312 {0xee, 0xcb}, 313 {0xef, 0x00}, 314 {0xf0, 0xbb}, 315 {0xf1, 0x00}, 316 {0xf2, 0xc0}, 317 {0xf3, 0x00}, 318 {0xf4, 0xcc}, 319 {0xf5, 0x00}, 320 {0xf6, 0xd6}, 321 {0xf7, 0x00}, 322 {0xf8, 0xe1}, 323 {0xf9, 0x00}, 324 {0xfa, 0xea}, 325 /* Select CMD2 Page2 (Undocumented) */ 326 {0xff, 0x02}, 327 /* Reload CMD1: Don't reload default value to register */ 328 {0xfb, 0x01}, 329 {0x00, 0x00}, 330 {0x01, 0xf4}, 331 {0x02, 0x00}, 332 {0x03, 0xef}, 333 {0x04, 0x01}, 334 {0x05, 0x07}, 335 {0x06, 0x01}, 336 {0x07, 0x28}, 337 {0x08, 0x01}, 338 {0x09, 0x44}, 339 {0x0a, 0x01}, 340 {0x0b, 0x76}, 341 {0x0c, 0x01}, 342 {0x0d, 0xa0}, 343 {0x0e, 0x01}, 344 {0x0f, 0xe7}, 345 {0x10, 0x02}, 346 {0x11, 0x1f}, 347 {0x12, 0x02}, 348 {0x13, 0x22}, 349 {0x14, 0x02}, 350 {0x15, 0x54}, 351 {0x16, 0x02}, 352 {0x17, 0x8b}, 353 {0x18, 0x02}, 354 {0x19, 0xaf}, 355 {0x1a, 0x02}, 356 {0x1b, 0xe0}, 357 {0x1c, 0x03}, 358 {0x1d, 0x01}, 359 {0x1e, 0x03}, 360 {0x1f, 0x2d}, 361 {0x20, 0x03}, 362 {0x21, 0x39}, 363 {0x22, 0x03}, 364 {0x23, 0x47}, 365 {0x24, 0x03}, 366 {0x25, 0x57}, 367 {0x26, 0x03}, 368 {0x27, 0x65}, 369 {0x28, 0x03}, 370 {0x29, 0x77}, 371 {0x2a, 0x03}, 372 {0x2b, 0x85}, 373 {0x2d, 0x03}, 374 {0x2f, 0x8f}, 375 {0x30, 0x03}, 376 {0x31, 0xcb}, 377 {0x32, 0x00}, 378 {0x33, 0xbb}, 379 {0x34, 0x00}, 380 {0x35, 0xc0}, 381 {0x36, 0x00}, 382 {0x37, 0xcc}, 383 {0x38, 0x00}, 384 {0x39, 0xd6}, 385 {0x3a, 0x00}, 386 {0x3b, 0xe1}, 387 {0x3d, 0x00}, 388 {0x3f, 0xea}, 389 {0x40, 0x00}, 390 {0x41, 0xf4}, 391 {0x42, 0x00}, 392 {0x43, 0xfe}, 393 {0x44, 0x01}, 394 {0x45, 0x07}, 395 {0x46, 0x01}, 396 {0x47, 0x28}, 397 {0x48, 0x01}, 398 {0x49, 0x44}, 399 {0x4a, 0x01}, 400 {0x4b, 0x76}, 401 {0x4c, 0x01}, 402 {0x4d, 0xa0}, 403 {0x4e, 0x01}, 404 {0x4f, 0xe7}, 405 {0x50, 0x02}, 406 {0x51, 0x1f}, 407 {0x52, 0x02}, 408 {0x53, 0x22}, 409 {0x54, 0x02}, 410 {0x55, 0x54}, 411 {0x56, 0x02}, 412 {0x58, 0x8b}, 413 {0x59, 0x02}, 414 {0x5a, 0xaf}, 415 {0x5b, 0x02}, 416 {0x5c, 0xe0}, 417 {0x5d, 0x03}, 418 {0x5e, 0x01}, 419 {0x5f, 0x03}, 420 {0x60, 0x2d}, 421 {0x61, 0x03}, 422 {0x62, 0x39}, 423 {0x63, 0x03}, 424 {0x64, 0x47}, 425 {0x65, 0x03}, 426 {0x66, 0x57}, 427 {0x67, 0x03}, 428 {0x68, 0x65}, 429 {0x69, 0x03}, 430 {0x6a, 0x77}, 431 {0x6b, 0x03}, 432 {0x6c, 0x85}, 433 {0x6d, 0x03}, 434 {0x6e, 0x8f}, 435 {0x6f, 0x03}, 436 {0x70, 0xcb}, 437 {0x71, 0x00}, 438 {0x72, 0x00}, 439 {0x73, 0x00}, 440 {0x74, 0x21}, 441 {0x75, 0x00}, 442 {0x76, 0x4c}, 443 {0x77, 0x00}, 444 {0x78, 0x6b}, 445 {0x79, 0x00}, 446 {0x7a, 0x85}, 447 {0x7b, 0x00}, 448 {0x7c, 0x9a}, 449 {0x7d, 0x00}, 450 {0x7e, 0xad}, 451 {0x7f, 0x00}, 452 {0x80, 0xbe}, 453 {0x81, 0x00}, 454 {0x82, 0xcd}, 455 {0x83, 0x01}, 456 {0x84, 0x01}, 457 {0x85, 0x01}, 458 {0x86, 0x29}, 459 {0x87, 0x01}, 460 {0x88, 0x68}, 461 {0x89, 0x01}, 462 {0x8a, 0x98}, 463 {0x8b, 0x01}, 464 {0x8c, 0xe5}, 465 {0x8d, 0x02}, 466 {0x8e, 0x1e}, 467 {0x8f, 0x02}, 468 {0x90, 0x30}, 469 {0x91, 0x02}, 470 {0x92, 0x52}, 471 {0x93, 0x02}, 472 {0x94, 0x88}, 473 {0x95, 0x02}, 474 {0x96, 0xaa}, 475 {0x97, 0x02}, 476 {0x98, 0xd7}, 477 {0x99, 0x02}, 478 {0x9a, 0xf7}, 479 {0x9b, 0x03}, 480 {0x9c, 0x21}, 481 {0x9d, 0x03}, 482 {0x9e, 0x2e}, 483 {0x9f, 0x03}, 484 {0xa0, 0x3d}, 485 {0xa2, 0x03}, 486 {0xa3, 0x4c}, 487 {0xa4, 0x03}, 488 {0xa5, 0x5e}, 489 {0xa6, 0x03}, 490 {0xa7, 0x71}, 491 {0xa9, 0x03}, 492 {0xaa, 0x86}, 493 {0xab, 0x03}, 494 {0xac, 0x94}, 495 {0xad, 0x03}, 496 {0xae, 0xfa}, 497 {0xaf, 0x00}, 498 {0xb0, 0x00}, 499 {0xb1, 0x00}, 500 {0xb2, 0x21}, 501 {0xb3, 0x00}, 502 {0xb4, 0x4c}, 503 {0xb5, 0x00}, 504 {0xb6, 0x6b}, 505 {0xb7, 0x00}, 506 {0xb8, 0x85}, 507 {0xb9, 0x00}, 508 {0xba, 0x9a}, 509 {0xbb, 0x00}, 510 {0xbc, 0xad}, 511 {0xbd, 0x00}, 512 {0xbe, 0xbe}, 513 {0xbf, 0x00}, 514 {0xc0, 0xcd}, 515 {0xc1, 0x01}, 516 {0xc2, 0x01}, 517 {0xc3, 0x01}, 518 {0xc4, 0x29}, 519 {0xc5, 0x01}, 520 {0xc6, 0x68}, 521 {0xc7, 0x01}, 522 {0xc8, 0x98}, 523 {0xc9, 0x01}, 524 {0xca, 0xe5}, 525 {0xcb, 0x02}, 526 {0xcc, 0x1e}, 527 {0xcd, 0x02}, 528 {0xce, 0x20}, 529 {0xcf, 0x02}, 530 {0xd0, 0x52}, 531 {0xd1, 0x02}, 532 {0xd2, 0x88}, 533 {0xd3, 0x02}, 534 {0xd4, 0xaa}, 535 {0xd5, 0x02}, 536 {0xd6, 0xd7}, 537 {0xd7, 0x02}, 538 {0xd8, 0xf7}, 539 {0xd9, 0x03}, 540 {0xda, 0x21}, 541 {0xdb, 0x03}, 542 {0xdc, 0x2e}, 543 {0xdd, 0x03}, 544 {0xde, 0x3d}, 545 {0xdf, 0x03}, 546 {0xe0, 0x4c}, 547 {0xe1, 0x03}, 548 {0xe2, 0x5e}, 549 {0xe3, 0x03}, 550 {0xe4, 0x71}, 551 {0xe5, 0x03}, 552 {0xe6, 0x86}, 553 {0xe7, 0x03}, 554 {0xe8, 0x94}, 555 {0xe9, 0x03}, 556 {0xea, 0xfa}, 557 /* Select CMD2 Page0 (Undocumented) */ 558 {0xff, 0x01}, 559 /* Reload CMD1: Don't reload default value to register */ 560 {0xfb, 0x01}, 561 /* Select CMD2 Page1 (Undocumented) */ 562 {0xff, 0x02}, 563 /* Reload CMD1: Don't reload default value to register */ 564 {0xfb, 0x01}, 565 /* Select CMD2 Page3 (Undocumented) */ 566 {0xff, 0x04}, 567 /* Reload CMD1: Don't reload default value to register */ 568 {0xfb, 0x01}, 569 /* Select CMD1 */ 570 {0xff, 0x00}, 571 {0xd3, 0x22}, /* RGBMIPICTRL: VSYNC back porch = 34 */ 572 {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */ 573 }; 574 575 static inline 576 struct khadas_ts050_panel *to_khadas_ts050_panel(struct drm_panel *panel) 577 { 578 return container_of(panel, struct khadas_ts050_panel, base); 579 } 580 581 static int khadas_ts050_panel_prepare(struct drm_panel *panel) 582 { 583 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel); 584 unsigned int i; 585 int err; 586 587 if (khadas_ts050->prepared) 588 return 0; 589 590 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0); 591 592 err = regulator_enable(khadas_ts050->supply); 593 if (err < 0) 594 return err; 595 596 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 1); 597 598 msleep(60); 599 600 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1); 601 602 usleep_range(10000, 11000); 603 604 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 0); 605 606 /* Select CMD2 page 4 (Undocumented) */ 607 mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x05 }, 1); 608 609 /* Reload CMD1: Don't reload default value to register */ 610 mipi_dsi_dcs_write(khadas_ts050->link, 0xfb, (u8[]){ 0x01 }, 1); 611 612 mipi_dsi_dcs_write(khadas_ts050->link, 0xc5, (u8[]){ 0x01 }, 1); 613 614 msleep(100); 615 616 for (i = 0; i < ARRAY_SIZE(init_code); i++) { 617 err = mipi_dsi_dcs_write(khadas_ts050->link, 618 init_code[i].cmd, 619 &init_code[i].data, 1); 620 if (err < 0) { 621 dev_err(panel->dev, "failed write cmds: %d\n", err); 622 goto poweroff; 623 } 624 } 625 626 err = mipi_dsi_dcs_exit_sleep_mode(khadas_ts050->link); 627 if (err < 0) { 628 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 629 goto poweroff; 630 } 631 632 msleep(120); 633 634 /* Select CMD1 */ 635 mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x00 }, 1); 636 637 err = mipi_dsi_dcs_set_tear_on(khadas_ts050->link, 638 MIPI_DSI_DCS_TEAR_MODE_VBLANK); 639 if (err < 0) { 640 dev_err(panel->dev, "failed to set tear on: %d\n", err); 641 goto poweroff; 642 } 643 644 err = mipi_dsi_dcs_set_display_on(khadas_ts050->link); 645 if (err < 0) { 646 dev_err(panel->dev, "failed to set display on: %d\n", err); 647 goto poweroff; 648 } 649 650 usleep_range(10000, 11000); 651 652 khadas_ts050->prepared = true; 653 654 return 0; 655 656 poweroff: 657 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0); 658 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1); 659 660 regulator_disable(khadas_ts050->supply); 661 662 return err; 663 } 664 665 static int khadas_ts050_panel_unprepare(struct drm_panel *panel) 666 { 667 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel); 668 int err; 669 670 if (!khadas_ts050->prepared) 671 return 0; 672 673 khadas_ts050->prepared = false; 674 675 err = mipi_dsi_dcs_enter_sleep_mode(khadas_ts050->link); 676 if (err < 0) 677 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); 678 679 msleep(150); 680 681 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0); 682 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1); 683 684 err = regulator_disable(khadas_ts050->supply); 685 if (err < 0) 686 return err; 687 688 return 0; 689 } 690 691 static int khadas_ts050_panel_enable(struct drm_panel *panel) 692 { 693 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel); 694 695 khadas_ts050->enabled = true; 696 697 return 0; 698 } 699 700 static int khadas_ts050_panel_disable(struct drm_panel *panel) 701 { 702 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel); 703 int err; 704 705 if (!khadas_ts050->enabled) 706 return 0; 707 708 err = mipi_dsi_dcs_set_display_off(khadas_ts050->link); 709 if (err < 0) 710 dev_err(panel->dev, "failed to set display off: %d\n", err); 711 712 usleep_range(10000, 11000); 713 714 khadas_ts050->enabled = false; 715 716 return 0; 717 } 718 719 static const struct drm_display_mode default_mode = { 720 .clock = 160000, 721 .hdisplay = 1080, 722 .hsync_start = 1080 + 117, 723 .hsync_end = 1080 + 117 + 5, 724 .htotal = 1080 + 117 + 5 + 160, 725 .vdisplay = 1920, 726 .vsync_start = 1920 + 4, 727 .vsync_end = 1920 + 4 + 3, 728 .vtotal = 1920 + 4 + 3 + 31, 729 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 730 }; 731 732 static int khadas_ts050_panel_get_modes(struct drm_panel *panel, 733 struct drm_connector *connector) 734 { 735 struct drm_display_mode *mode; 736 737 mode = drm_mode_duplicate(connector->dev, &default_mode); 738 if (!mode) { 739 dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 740 default_mode.hdisplay, default_mode.vdisplay, 741 drm_mode_vrefresh(&default_mode)); 742 return -ENOMEM; 743 } 744 745 drm_mode_set_name(mode); 746 747 drm_mode_probed_add(connector, mode); 748 749 connector->display_info.width_mm = 64; 750 connector->display_info.height_mm = 118; 751 connector->display_info.bpc = 8; 752 753 return 1; 754 } 755 756 static const struct drm_panel_funcs khadas_ts050_panel_funcs = { 757 .prepare = khadas_ts050_panel_prepare, 758 .unprepare = khadas_ts050_panel_unprepare, 759 .enable = khadas_ts050_panel_enable, 760 .disable = khadas_ts050_panel_disable, 761 .get_modes = khadas_ts050_panel_get_modes, 762 }; 763 764 static const struct of_device_id khadas_ts050_of_match[] = { 765 { .compatible = "khadas,ts050", }, 766 { /* sentinel */ } 767 }; 768 MODULE_DEVICE_TABLE(of, khadas_ts050_of_match); 769 770 static int khadas_ts050_panel_add(struct khadas_ts050_panel *khadas_ts050) 771 { 772 struct device *dev = &khadas_ts050->link->dev; 773 int err; 774 775 khadas_ts050->supply = devm_regulator_get(dev, "power"); 776 if (IS_ERR(khadas_ts050->supply)) 777 return dev_err_probe(dev, PTR_ERR(khadas_ts050->supply), 778 "failed to get power supply"); 779 780 khadas_ts050->reset_gpio = devm_gpiod_get(dev, "reset", 781 GPIOD_OUT_LOW); 782 if (IS_ERR(khadas_ts050->reset_gpio)) 783 return dev_err_probe(dev, PTR_ERR(khadas_ts050->reset_gpio), 784 "failed to get reset gpio"); 785 786 khadas_ts050->enable_gpio = devm_gpiod_get(dev, "enable", 787 GPIOD_OUT_HIGH); 788 if (IS_ERR(khadas_ts050->enable_gpio)) 789 return dev_err_probe(dev, PTR_ERR(khadas_ts050->enable_gpio), 790 "failed to get enable gpio"); 791 792 drm_panel_init(&khadas_ts050->base, &khadas_ts050->link->dev, 793 &khadas_ts050_panel_funcs, DRM_MODE_CONNECTOR_DSI); 794 795 err = drm_panel_of_backlight(&khadas_ts050->base); 796 if (err) 797 return err; 798 799 drm_panel_add(&khadas_ts050->base); 800 801 return 0; 802 } 803 804 static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) 805 { 806 struct khadas_ts050_panel *khadas_ts050; 807 int err; 808 809 dsi->lanes = 4; 810 dsi->format = MIPI_DSI_FMT_RGB888; 811 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 812 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; 813 814 khadas_ts050 = devm_kzalloc(&dsi->dev, sizeof(*khadas_ts050), 815 GFP_KERNEL); 816 if (!khadas_ts050) 817 return -ENOMEM; 818 819 mipi_dsi_set_drvdata(dsi, khadas_ts050); 820 khadas_ts050->link = dsi; 821 822 err = khadas_ts050_panel_add(khadas_ts050); 823 if (err < 0) 824 return err; 825 826 err = mipi_dsi_attach(dsi); 827 if (err) 828 drm_panel_remove(&khadas_ts050->base); 829 830 return err; 831 } 832 833 static void khadas_ts050_panel_remove(struct mipi_dsi_device *dsi) 834 { 835 struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi); 836 int err; 837 838 err = mipi_dsi_detach(dsi); 839 if (err < 0) 840 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); 841 842 drm_panel_remove(&khadas_ts050->base); 843 drm_panel_disable(&khadas_ts050->base); 844 drm_panel_unprepare(&khadas_ts050->base); 845 } 846 847 static void khadas_ts050_panel_shutdown(struct mipi_dsi_device *dsi) 848 { 849 struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi); 850 851 drm_panel_disable(&khadas_ts050->base); 852 drm_panel_unprepare(&khadas_ts050->base); 853 } 854 855 static struct mipi_dsi_driver khadas_ts050_panel_driver = { 856 .driver = { 857 .name = "panel-khadas-ts050", 858 .of_match_table = khadas_ts050_of_match, 859 }, 860 .probe = khadas_ts050_panel_probe, 861 .remove = khadas_ts050_panel_remove, 862 .shutdown = khadas_ts050_panel_shutdown, 863 }; 864 module_mipi_dsi_driver(khadas_ts050_panel_driver); 865 866 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 867 MODULE_DESCRIPTION("Khadas TS050 panel driver"); 868 MODULE_LICENSE("GPL v2"); 869