linux/drivers/gpu/drm/panel/panel-khadas-ts050.c
<<
>>
Prefs
   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
  21struct 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
  33struct khadas_ts050_panel_cmd {
  34        u8 cmd;
  35        u8 data;
  36};
  37
  38/* Only the CMD1 User Command set is documented */
  39static 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, 0x05}, /* RGBMIPICTRL: VSYNC back porch = 5 */
 572        {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */
 573};
 574
 575static inline
 576struct khadas_ts050_panel *to_khadas_ts050_panel(struct drm_panel *panel)
 577{
 578        return container_of(panel, struct khadas_ts050_panel, base);
 579}
 580
 581static 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
 656poweroff:
 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
 665static 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
 691static 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
 700static 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
 719static const struct drm_display_mode default_mode = {
 720        .clock = 120000,
 721        .hdisplay = 1088,
 722        .hsync_start = 1088 + 104,
 723        .hsync_end = 1088 + 104 + 4,
 724        .htotal = 1088 + 104 + 4 + 127,
 725        .vdisplay = 1920,
 726        .vsync_start = 1920 + 4,
 727        .vsync_end = 1920 + 4 + 2,
 728        .vtotal = 1920 + 4 + 2 + 3,
 729        .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 730};
 731
 732static 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
 756static 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
 764static const struct of_device_id khadas_ts050_of_match[] = {
 765        { .compatible = "khadas,ts050", },
 766        { /* sentinel */ }
 767};
 768MODULE_DEVICE_TABLE(of, khadas_ts050_of_match);
 769
 770static 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
 804static 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
 833static int 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        return 0;
 847}
 848
 849static void khadas_ts050_panel_shutdown(struct mipi_dsi_device *dsi)
 850{
 851        struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
 852
 853        drm_panel_disable(&khadas_ts050->base);
 854        drm_panel_unprepare(&khadas_ts050->base);
 855}
 856
 857static struct mipi_dsi_driver khadas_ts050_panel_driver = {
 858        .driver = {
 859                .name = "panel-khadas-ts050",
 860                .of_match_table = khadas_ts050_of_match,
 861        },
 862        .probe = khadas_ts050_panel_probe,
 863        .remove = khadas_ts050_panel_remove,
 864        .shutdown = khadas_ts050_panel_shutdown,
 865};
 866module_mipi_dsi_driver(khadas_ts050_panel_driver);
 867
 868MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
 869MODULE_DESCRIPTION("Khadas TS050 panel driver");
 870MODULE_LICENSE("GPL v2");
 871