linux/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
   4 */
   5
   6#include <linux/backlight.h>
   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#include <drm/drm_print.h>
  21
  22struct kingdisplay_panel {
  23        struct drm_panel base;
  24        struct mipi_dsi_device *link;
  25
  26        struct backlight_device *backlight;
  27        struct regulator *supply;
  28        struct gpio_desc *enable_gpio;
  29
  30        bool prepared;
  31        bool enabled;
  32};
  33
  34struct kingdisplay_panel_cmd {
  35        char cmd;
  36        char data;
  37};
  38
  39/*
  40 * According to the discussion on
  41 * https://review.coreboot.org/#/c/coreboot/+/22472/
  42 * the panel init array is not part of the panels datasheet but instead
  43 * just came in this form from the panel vendor.
  44 */
  45static const struct kingdisplay_panel_cmd init_code[] = {
  46        /* voltage setting */
  47        { 0xB0, 0x00 },
  48        { 0xB2, 0x02 },
  49        { 0xB3, 0x11 },
  50        { 0xB4, 0x00 },
  51        { 0xB6, 0x80 },
  52        /* VCOM disable */
  53        { 0xB7, 0x02 },
  54        { 0xB8, 0x80 },
  55        { 0xBA, 0x43 },
  56        /* VCOM setting */
  57        { 0xBB, 0x53 },
  58        /* VSP setting */
  59        { 0xBC, 0x0A },
  60        /* VSN setting */
  61        { 0xBD, 0x4A },
  62        /* VGH setting */
  63        { 0xBE, 0x2F },
  64        /* VGL setting */
  65        { 0xBF, 0x1A },
  66        { 0xF0, 0x39 },
  67        { 0xF1, 0x22 },
  68        /* Gamma setting */
  69        { 0xB0, 0x02 },
  70        { 0xC0, 0x00 },
  71        { 0xC1, 0x01 },
  72        { 0xC2, 0x0B },
  73        { 0xC3, 0x15 },
  74        { 0xC4, 0x22 },
  75        { 0xC5, 0x11 },
  76        { 0xC6, 0x15 },
  77        { 0xC7, 0x19 },
  78        { 0xC8, 0x1A },
  79        { 0xC9, 0x16 },
  80        { 0xCA, 0x18 },
  81        { 0xCB, 0x13 },
  82        { 0xCC, 0x18 },
  83        { 0xCD, 0x13 },
  84        { 0xCE, 0x1C },
  85        { 0xCF, 0x19 },
  86        { 0xD0, 0x21 },
  87        { 0xD1, 0x2C },
  88        { 0xD2, 0x2F },
  89        { 0xD3, 0x30 },
  90        { 0xD4, 0x19 },
  91        { 0xD5, 0x1F },
  92        { 0xD6, 0x00 },
  93        { 0xD7, 0x01 },
  94        { 0xD8, 0x0B },
  95        { 0xD9, 0x15 },
  96        { 0xDA, 0x22 },
  97        { 0xDB, 0x11 },
  98        { 0xDC, 0x15 },
  99        { 0xDD, 0x19 },
 100        { 0xDE, 0x1A },
 101        { 0xDF, 0x16 },
 102        { 0xE0, 0x18 },
 103        { 0xE1, 0x13 },
 104        { 0xE2, 0x18 },
 105        { 0xE3, 0x13 },
 106        { 0xE4, 0x1C },
 107        { 0xE5, 0x19 },
 108        { 0xE6, 0x21 },
 109        { 0xE7, 0x2C },
 110        { 0xE8, 0x2F },
 111        { 0xE9, 0x30 },
 112        { 0xEA, 0x19 },
 113        { 0xEB, 0x1F },
 114        /* GOA MUX setting */
 115        { 0xB0, 0x01 },
 116        { 0xC0, 0x10 },
 117        { 0xC1, 0x0F },
 118        { 0xC2, 0x0E },
 119        { 0xC3, 0x0D },
 120        { 0xC4, 0x0C },
 121        { 0xC5, 0x0B },
 122        { 0xC6, 0x0A },
 123        { 0xC7, 0x09 },
 124        { 0xC8, 0x08 },
 125        { 0xC9, 0x07 },
 126        { 0xCA, 0x06 },
 127        { 0xCB, 0x05 },
 128        { 0xCC, 0x00 },
 129        { 0xCD, 0x01 },
 130        { 0xCE, 0x02 },
 131        { 0xCF, 0x03 },
 132        { 0xD0, 0x04 },
 133        { 0xD6, 0x10 },
 134        { 0xD7, 0x0F },
 135        { 0xD8, 0x0E },
 136        { 0xD9, 0x0D },
 137        { 0xDA, 0x0C },
 138        { 0xDB, 0x0B },
 139        { 0xDC, 0x0A },
 140        { 0xDD, 0x09 },
 141        { 0xDE, 0x08 },
 142        { 0xDF, 0x07 },
 143        { 0xE0, 0x06 },
 144        { 0xE1, 0x05 },
 145        { 0xE2, 0x00 },
 146        { 0xE3, 0x01 },
 147        { 0xE4, 0x02 },
 148        { 0xE5, 0x03 },
 149        { 0xE6, 0x04 },
 150        { 0xE7, 0x00 },
 151        { 0xEC, 0xC0 },
 152        /* GOA timing setting */
 153        { 0xB0, 0x03 },
 154        { 0xC0, 0x01 },
 155        { 0xC2, 0x6F },
 156        { 0xC3, 0x6F },
 157        { 0xC5, 0x36 },
 158        { 0xC8, 0x08 },
 159        { 0xC9, 0x04 },
 160        { 0xCA, 0x41 },
 161        { 0xCC, 0x43 },
 162        { 0xCF, 0x60 },
 163        { 0xD2, 0x04 },
 164        { 0xD3, 0x04 },
 165        { 0xD4, 0x03 },
 166        { 0xD5, 0x02 },
 167        { 0xD6, 0x01 },
 168        { 0xD7, 0x00 },
 169        { 0xDB, 0x01 },
 170        { 0xDE, 0x36 },
 171        { 0xE6, 0x6F },
 172        { 0xE7, 0x6F },
 173        /* GOE setting */
 174        { 0xB0, 0x06 },
 175        { 0xB8, 0xA5 },
 176        { 0xC0, 0xA5 },
 177        { 0xD5, 0x3F },
 178};
 179
 180static inline
 181struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
 182{
 183        return container_of(panel, struct kingdisplay_panel, base);
 184}
 185
 186static int kingdisplay_panel_disable(struct drm_panel *panel)
 187{
 188        struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
 189        int err;
 190
 191        if (!kingdisplay->enabled)
 192                return 0;
 193
 194        backlight_disable(kingdisplay->backlight);
 195
 196        err = mipi_dsi_dcs_set_display_off(kingdisplay->link);
 197        if (err < 0)
 198                DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
 199                              err);
 200
 201        kingdisplay->enabled = false;
 202
 203        return 0;
 204}
 205
 206static int kingdisplay_panel_unprepare(struct drm_panel *panel)
 207{
 208        struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
 209        int err;
 210
 211        if (!kingdisplay->prepared)
 212                return 0;
 213
 214        err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link);
 215        if (err < 0) {
 216                DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
 217                              err);
 218                return err;
 219        }
 220
 221        /* T15: 120ms */
 222        msleep(120);
 223
 224        gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
 225
 226        err = regulator_disable(kingdisplay->supply);
 227        if (err < 0)
 228                return err;
 229
 230        kingdisplay->prepared = false;
 231
 232        return 0;
 233}
 234
 235static int kingdisplay_panel_prepare(struct drm_panel *panel)
 236{
 237        struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
 238        int err, regulator_err;
 239        unsigned int i;
 240
 241        if (kingdisplay->prepared)
 242                return 0;
 243
 244        gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
 245
 246        err = regulator_enable(kingdisplay->supply);
 247        if (err < 0)
 248                return err;
 249
 250        /* T2: 15ms */
 251        usleep_range(15000, 16000);
 252
 253        gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
 254
 255        /* T4: 15ms */
 256        usleep_range(15000, 16000);
 257
 258        for (i = 0; i < ARRAY_SIZE(init_code); i++) {
 259                err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i],
 260                                        sizeof(struct kingdisplay_panel_cmd));
 261                if (err < 0) {
 262                        DRM_DEV_ERROR(panel->dev, "failed write init cmds: %d\n",
 263                                      err);
 264                        goto poweroff;
 265                }
 266        }
 267
 268        err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link);
 269        if (err < 0) {
 270                DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
 271                              err);
 272                goto poweroff;
 273        }
 274
 275        /* T6: 120ms */
 276        msleep(120);
 277
 278        err = mipi_dsi_dcs_set_display_on(kingdisplay->link);
 279        if (err < 0) {
 280                DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
 281                              err);
 282                goto poweroff;
 283        }
 284
 285        /* T7: 10ms */
 286        usleep_range(10000, 11000);
 287
 288        kingdisplay->prepared = true;
 289
 290        return 0;
 291
 292poweroff:
 293        gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
 294
 295        regulator_err = regulator_disable(kingdisplay->supply);
 296        if (regulator_err)
 297                DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n",
 298                              regulator_err);
 299
 300        return err;
 301}
 302
 303static int kingdisplay_panel_enable(struct drm_panel *panel)
 304{
 305        struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
 306        int ret;
 307
 308        if (kingdisplay->enabled)
 309                return 0;
 310
 311        ret = backlight_enable(kingdisplay->backlight);
 312        if (ret) {
 313                DRM_DEV_ERROR(panel->drm->dev,
 314                              "Failed to enable backlight %d\n", ret);
 315                return ret;
 316        }
 317
 318        kingdisplay->enabled = true;
 319
 320        return 0;
 321}
 322
 323static const struct drm_display_mode default_mode = {
 324        .clock = 229000,
 325        .hdisplay = 1536,
 326        .hsync_start = 1536 + 100,
 327        .hsync_end = 1536 + 100 + 24,
 328        .htotal = 1536 + 100 + 24 + 100,
 329        .vdisplay = 2048,
 330        .vsync_start = 2048 + 95,
 331        .vsync_end = 2048 + 95 + 2,
 332        .vtotal = 2048 + 95 + 2 + 23,
 333        .vrefresh = 60,
 334};
 335
 336static int kingdisplay_panel_get_modes(struct drm_panel *panel)
 337{
 338        struct drm_display_mode *mode;
 339
 340        mode = drm_mode_duplicate(panel->drm, &default_mode);
 341        if (!mode) {
 342                DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
 343                              default_mode.hdisplay, default_mode.vdisplay,
 344                              default_mode.vrefresh);
 345                return -ENOMEM;
 346        }
 347
 348        drm_mode_set_name(mode);
 349
 350        drm_mode_probed_add(panel->connector, mode);
 351
 352        panel->connector->display_info.width_mm = 147;
 353        panel->connector->display_info.height_mm = 196;
 354        panel->connector->display_info.bpc = 8;
 355
 356        return 1;
 357}
 358
 359static const struct drm_panel_funcs kingdisplay_panel_funcs = {
 360        .disable = kingdisplay_panel_disable,
 361        .unprepare = kingdisplay_panel_unprepare,
 362        .prepare = kingdisplay_panel_prepare,
 363        .enable = kingdisplay_panel_enable,
 364        .get_modes = kingdisplay_panel_get_modes,
 365};
 366
 367static const struct of_device_id kingdisplay_of_match[] = {
 368        { .compatible = "kingdisplay,kd097d04", },
 369        { }
 370};
 371MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
 372
 373static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
 374{
 375        struct device *dev = &kingdisplay->link->dev;
 376        int err;
 377
 378        kingdisplay->supply = devm_regulator_get(dev, "power");
 379        if (IS_ERR(kingdisplay->supply))
 380                return PTR_ERR(kingdisplay->supply);
 381
 382        kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable",
 383                                                           GPIOD_OUT_HIGH);
 384        if (IS_ERR(kingdisplay->enable_gpio)) {
 385                err = PTR_ERR(kingdisplay->enable_gpio);
 386                dev_dbg(dev, "failed to get enable gpio: %d\n", err);
 387                kingdisplay->enable_gpio = NULL;
 388        }
 389
 390        kingdisplay->backlight = devm_of_find_backlight(dev);
 391        if (IS_ERR(kingdisplay->backlight))
 392                return PTR_ERR(kingdisplay->backlight);
 393
 394        drm_panel_init(&kingdisplay->base);
 395        kingdisplay->base.funcs = &kingdisplay_panel_funcs;
 396        kingdisplay->base.dev = &kingdisplay->link->dev;
 397
 398        return drm_panel_add(&kingdisplay->base);
 399}
 400
 401static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
 402{
 403        drm_panel_remove(&kingdisplay->base);
 404}
 405
 406static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
 407{
 408        struct kingdisplay_panel *kingdisplay;
 409        int err;
 410
 411        dsi->lanes = 4;
 412        dsi->format = MIPI_DSI_FMT_RGB888;
 413        dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
 414                          MIPI_DSI_MODE_LPM;
 415
 416        kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
 417        if (!kingdisplay)
 418                return -ENOMEM;
 419
 420        mipi_dsi_set_drvdata(dsi, kingdisplay);
 421        kingdisplay->link = dsi;
 422
 423        err = kingdisplay_panel_add(kingdisplay);
 424        if (err < 0)
 425                return err;
 426
 427        return mipi_dsi_attach(dsi);
 428}
 429
 430static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
 431{
 432        struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
 433        int err;
 434
 435        err = kingdisplay_panel_unprepare(&kingdisplay->base);
 436        if (err < 0)
 437                DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
 438                              err);
 439
 440        err = kingdisplay_panel_disable(&kingdisplay->base);
 441        if (err < 0)
 442                DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n", err);
 443
 444        err = mipi_dsi_detach(dsi);
 445        if (err < 0)
 446                DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
 447                              err);
 448
 449        kingdisplay_panel_del(kingdisplay);
 450
 451        return 0;
 452}
 453
 454static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)
 455{
 456        struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
 457
 458        kingdisplay_panel_unprepare(&kingdisplay->base);
 459        kingdisplay_panel_disable(&kingdisplay->base);
 460}
 461
 462static struct mipi_dsi_driver kingdisplay_panel_driver = {
 463        .driver = {
 464                .name = "panel-kingdisplay-kd097d04",
 465                .of_match_table = kingdisplay_of_match,
 466        },
 467        .probe = kingdisplay_panel_probe,
 468        .remove = kingdisplay_panel_remove,
 469        .shutdown = kingdisplay_panel_shutdown,
 470};
 471module_mipi_dsi_driver(kingdisplay_panel_driver);
 472
 473MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
 474MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
 475MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
 476MODULE_LICENSE("GPL v2");
 477