linux/drivers/gpu/drm/panel/panel-boe-himax8279d.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd
   4 *
   5 * Author: Jerry Han <jerry.han.hq@gmail.com>
   6 *
   7 */
   8
   9#include <linux/delay.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/of.h>
  13#include <linux/of_device.h>
  14
  15#include <linux/gpio/consumer.h>
  16#include <linux/regulator/consumer.h>
  17
  18#include <drm/drm_device.h>
  19#include <drm/drm_mipi_dsi.h>
  20#include <drm/drm_modes.h>
  21#include <drm/drm_panel.h>
  22
  23#include <video/mipi_display.h>
  24
  25struct panel_cmd {
  26        char cmd;
  27        char data;
  28};
  29
  30struct panel_desc {
  31        const struct drm_display_mode *display_mode;
  32        unsigned int bpc;
  33        unsigned int width_mm;
  34        unsigned int height_mm;
  35
  36        unsigned long mode_flags;
  37        enum mipi_dsi_pixel_format format;
  38        unsigned int lanes;
  39        const struct panel_cmd *on_cmds;
  40        unsigned int on_cmds_num;
  41};
  42
  43struct panel_info {
  44        struct drm_panel base;
  45        struct mipi_dsi_device *link;
  46        const struct panel_desc *desc;
  47
  48        struct gpio_desc *enable_gpio;
  49        struct gpio_desc *pp33_gpio;
  50        struct gpio_desc *pp18_gpio;
  51
  52        bool prepared;
  53        bool enabled;
  54};
  55
  56static inline struct panel_info *to_panel_info(struct drm_panel *panel)
  57{
  58        return container_of(panel, struct panel_info, base);
  59}
  60
  61static void disable_gpios(struct panel_info *pinfo)
  62{
  63        gpiod_set_value(pinfo->enable_gpio, 0);
  64        gpiod_set_value(pinfo->pp33_gpio, 0);
  65        gpiod_set_value(pinfo->pp18_gpio, 0);
  66}
  67
  68static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)
  69{
  70        struct panel_info *pinfo = to_panel_info(panel);
  71        unsigned int i = 0;
  72        int err;
  73
  74        for (i = 0; i < pinfo->desc->on_cmds_num; i++) {
  75                err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],
  76                                                sizeof(struct panel_cmd));
  77
  78                if (err < 0)
  79                        return err;
  80        }
  81
  82        return 0;
  83}
  84
  85static int boe_panel_disable(struct drm_panel *panel)
  86{
  87        struct panel_info *pinfo = to_panel_info(panel);
  88        int err;
  89
  90        if (!pinfo->enabled)
  91                return 0;
  92
  93        err = mipi_dsi_dcs_set_display_off(pinfo->link);
  94        if (err < 0) {
  95                dev_err(panel->dev, "failed to set display off: %d\n", err);
  96                return err;
  97        }
  98
  99        pinfo->enabled = false;
 100
 101        return 0;
 102}
 103
 104static int boe_panel_unprepare(struct drm_panel *panel)
 105{
 106        struct panel_info *pinfo = to_panel_info(panel);
 107        int err;
 108
 109        if (!pinfo->prepared)
 110                return 0;
 111
 112        err = mipi_dsi_dcs_set_display_off(pinfo->link);
 113        if (err < 0)
 114                dev_err(panel->dev, "failed to set display off: %d\n", err);
 115
 116        err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);
 117        if (err < 0)
 118                dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
 119
 120        /* sleep_mode_delay: 1ms - 2ms */
 121        usleep_range(1000, 2000);
 122
 123        disable_gpios(pinfo);
 124
 125        pinfo->prepared = false;
 126
 127        return 0;
 128}
 129
 130static int boe_panel_prepare(struct drm_panel *panel)
 131{
 132        struct panel_info *pinfo = to_panel_info(panel);
 133        int err;
 134
 135        if (pinfo->prepared)
 136                return 0;
 137
 138        gpiod_set_value(pinfo->pp18_gpio, 1);
 139        /* T1: 5ms - 6ms */
 140        usleep_range(5000, 6000);
 141        gpiod_set_value(pinfo->pp33_gpio, 1);
 142
 143        /* reset sequence */
 144        /* T2: 14ms - 15ms */
 145        usleep_range(14000, 15000);
 146        gpiod_set_value(pinfo->enable_gpio, 1);
 147
 148        /* T3: 1ms - 2ms */
 149        usleep_range(1000, 2000);
 150        gpiod_set_value(pinfo->enable_gpio, 0);
 151
 152        /* T4: 1ms - 2ms */
 153        usleep_range(1000, 2000);
 154        gpiod_set_value(pinfo->enable_gpio, 1);
 155
 156        /* T5: 5ms - 6ms */
 157        usleep_range(5000, 6000);
 158
 159        /* send init code */
 160        err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
 161        if (err < 0) {
 162                dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
 163                goto poweroff;
 164        }
 165
 166        err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
 167        if (err < 0) {
 168                dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
 169                goto poweroff;
 170        }
 171
 172        /* T6: 120ms - 121ms */
 173        usleep_range(120000, 121000);
 174
 175        err = mipi_dsi_dcs_set_display_on(pinfo->link);
 176        if (err < 0) {
 177                dev_err(panel->dev, "failed to set display on: %d\n", err);
 178                goto poweroff;
 179        }
 180
 181        /* T7: 20ms - 21ms */
 182        usleep_range(20000, 21000);
 183
 184        pinfo->prepared = true;
 185
 186        return 0;
 187
 188poweroff:
 189        disable_gpios(pinfo);
 190        return err;
 191}
 192
 193static int boe_panel_enable(struct drm_panel *panel)
 194{
 195        struct panel_info *pinfo = to_panel_info(panel);
 196        int ret;
 197
 198        if (pinfo->enabled)
 199                return 0;
 200
 201        usleep_range(120000, 121000);
 202
 203        ret = mipi_dsi_dcs_set_display_on(pinfo->link);
 204        if (ret < 0) {
 205                dev_err(panel->dev, "failed to set display on: %d\n", ret);
 206                return ret;
 207        }
 208
 209        pinfo->enabled = true;
 210
 211        return 0;
 212}
 213
 214static int boe_panel_get_modes(struct drm_panel *panel,
 215                               struct drm_connector *connector)
 216{
 217        struct panel_info *pinfo = to_panel_info(panel);
 218        const struct drm_display_mode *m = pinfo->desc->display_mode;
 219        struct drm_display_mode *mode;
 220
 221        mode = drm_mode_duplicate(connector->dev, m);
 222        if (!mode) {
 223                dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
 224                        m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
 225                return -ENOMEM;
 226        }
 227
 228        drm_mode_set_name(mode);
 229
 230        drm_mode_probed_add(connector, mode);
 231
 232        connector->display_info.width_mm = pinfo->desc->width_mm;
 233        connector->display_info.height_mm = pinfo->desc->height_mm;
 234        connector->display_info.bpc = pinfo->desc->bpc;
 235
 236        return 1;
 237}
 238
 239static const struct drm_panel_funcs panel_funcs = {
 240        .disable = boe_panel_disable,
 241        .unprepare = boe_panel_unprepare,
 242        .prepare = boe_panel_prepare,
 243        .enable = boe_panel_enable,
 244        .get_modes = boe_panel_get_modes,
 245};
 246
 247static const struct drm_display_mode default_display_mode = {
 248        .clock = 159420,
 249        .hdisplay = 1200,
 250        .hsync_start = 1200 + 80,
 251        .hsync_end = 1200 + 80 + 60,
 252        .htotal = 1200 + 80 + 60 + 24,
 253        .vdisplay = 1920,
 254        .vsync_start = 1920 + 10,
 255        .vsync_end = 1920 + 10 + 14,
 256        .vtotal = 1920 + 10 + 14 + 4,
 257};
 258
 259/* 8 inch */
 260static const struct panel_cmd boe_himax8279d8p_on_cmds[] = {
 261        { 0xB0, 0x05 },
 262        { 0xB1, 0xE5 },
 263        { 0xB3, 0x52 },
 264        { 0xC0, 0x00 },
 265        { 0xC2, 0x57 },
 266        { 0xD9, 0x85 },
 267        { 0xB0, 0x01 },
 268        { 0xC8, 0x00 },
 269        { 0xC9, 0x00 },
 270        { 0xCC, 0x26 },
 271        { 0xCD, 0x26 },
 272        { 0xDC, 0x00 },
 273        { 0xDD, 0x00 },
 274        { 0xE0, 0x26 },
 275        { 0xE1, 0x26 },
 276        { 0xB0, 0x03 },
 277        { 0xC3, 0x2A },
 278        { 0xE7, 0x2A },
 279        { 0xC5, 0x2A },
 280        { 0xDE, 0x2A },
 281        { 0xBC, 0x02 },
 282        { 0xCB, 0x02 },
 283        { 0xB0, 0x00 },
 284        { 0xB6, 0x03 },
 285        { 0xBA, 0x8B },
 286        { 0xBF, 0x15 },
 287        { 0xC0, 0x18 },
 288        { 0xC2, 0x14 },
 289        { 0xC3, 0x02 },
 290        { 0xC4, 0x14 },
 291        { 0xC5, 0x02 },
 292        { 0xCC, 0x0A },
 293        { 0xB0, 0x06 },
 294        { 0xC0, 0xA5 },
 295        { 0xD5, 0x20 },
 296        { 0xC0, 0x00 },
 297        { 0xB0, 0x02 },
 298        { 0xC0, 0x00 },
 299        { 0xC1, 0x02 },
 300        { 0xC2, 0x06 },
 301        { 0xC3, 0x16 },
 302        { 0xC4, 0x0E },
 303        { 0xC5, 0x18 },
 304        { 0xC6, 0x26 },
 305        { 0xC7, 0x32 },
 306        { 0xC8, 0x3F },
 307        { 0xC9, 0x3F },
 308        { 0xCA, 0x3F },
 309        { 0xCB, 0x3F },
 310        { 0xCC, 0x3D },
 311        { 0xCD, 0x2F },
 312        { 0xCE, 0x2F },
 313        { 0xCF, 0x2F },
 314        { 0xD0, 0x07 },
 315        { 0xD2, 0x00 },
 316        { 0xD3, 0x02 },
 317        { 0xD4, 0x06 },
 318        { 0xD5, 0x12 },
 319        { 0xD6, 0x0A },
 320        { 0xD7, 0x14 },
 321        { 0xD8, 0x22 },
 322        { 0xD9, 0x2E },
 323        { 0xDA, 0x3D },
 324        { 0xDB, 0x3F },
 325        { 0xDC, 0x3F },
 326        { 0xDD, 0x3F },
 327        { 0xDE, 0x3D },
 328        { 0xDF, 0x2F },
 329        { 0xE0, 0x2F },
 330        { 0xE1, 0x2F },
 331        { 0xE2, 0x07 },
 332        { 0xB0, 0x07 },
 333        { 0xB1, 0x18 },
 334        { 0xB2, 0x19 },
 335        { 0xB3, 0x2E },
 336        { 0xB4, 0x52 },
 337        { 0xB5, 0x72 },
 338        { 0xB6, 0x8C },
 339        { 0xB7, 0xBD },
 340        { 0xB8, 0xEB },
 341        { 0xB9, 0x47 },
 342        { 0xBA, 0x96 },
 343        { 0xBB, 0x1E },
 344        { 0xBC, 0x90 },
 345        { 0xBD, 0x93 },
 346        { 0xBE, 0xFA },
 347        { 0xBF, 0x56 },
 348        { 0xC0, 0x8C },
 349        { 0xC1, 0xB7 },
 350        { 0xC2, 0xCC },
 351        { 0xC3, 0xDF },
 352        { 0xC4, 0xE8 },
 353        { 0xC5, 0xF0 },
 354        { 0xC6, 0xF8 },
 355        { 0xC7, 0xFA },
 356        { 0xC8, 0xFC },
 357        { 0xC9, 0x00 },
 358        { 0xCA, 0x00 },
 359        { 0xCB, 0x5A },
 360        { 0xCC, 0xAF },
 361        { 0xCD, 0xFF },
 362        { 0xCE, 0xFF },
 363        { 0xB0, 0x08 },
 364        { 0xB1, 0x04 },
 365        { 0xB2, 0x15 },
 366        { 0xB3, 0x2D },
 367        { 0xB4, 0x51 },
 368        { 0xB5, 0x72 },
 369        { 0xB6, 0x8D },
 370        { 0xB7, 0xBE },
 371        { 0xB8, 0xED },
 372        { 0xB9, 0x4A },
 373        { 0xBA, 0x9A },
 374        { 0xBB, 0x23 },
 375        { 0xBC, 0x95 },
 376        { 0xBD, 0x98 },
 377        { 0xBE, 0xFF },
 378        { 0xBF, 0x59 },
 379        { 0xC0, 0x8E },
 380        { 0xC1, 0xB9 },
 381        { 0xC2, 0xCD },
 382        { 0xC3, 0xDF },
 383        { 0xC4, 0xE8 },
 384        { 0xC5, 0xF0 },
 385        { 0xC6, 0xF8 },
 386        { 0xC7, 0xFA },
 387        { 0xC8, 0xFC },
 388        { 0xC9, 0x00 },
 389        { 0xCA, 0x00 },
 390        { 0xCB, 0x5A },
 391        { 0xCC, 0xAF },
 392        { 0xCD, 0xFF },
 393        { 0xCE, 0xFF },
 394        { 0xB0, 0x09 },
 395        { 0xB1, 0x04 },
 396        { 0xB2, 0x2C },
 397        { 0xB3, 0x36 },
 398        { 0xB4, 0x53 },
 399        { 0xB5, 0x73 },
 400        { 0xB6, 0x8E },
 401        { 0xB7, 0xC0 },
 402        { 0xB8, 0xEF },
 403        { 0xB9, 0x4C },
 404        { 0xBA, 0x9D },
 405        { 0xBB, 0x25 },
 406        { 0xBC, 0x96 },
 407        { 0xBD, 0x9A },
 408        { 0xBE, 0x01 },
 409        { 0xBF, 0x59 },
 410        { 0xC0, 0x8E },
 411        { 0xC1, 0xB9 },
 412        { 0xC2, 0xCD },
 413        { 0xC3, 0xDF },
 414        { 0xC4, 0xE8 },
 415        { 0xC5, 0xF0 },
 416        { 0xC6, 0xF8 },
 417        { 0xC7, 0xFA },
 418        { 0xC8, 0xFC },
 419        { 0xC9, 0x00 },
 420        { 0xCA, 0x00 },
 421        { 0xCB, 0x5A },
 422        { 0xCC, 0xBF },
 423        { 0xCD, 0xFF },
 424        { 0xCE, 0xFF },
 425        { 0xB0, 0x0A },
 426        { 0xB1, 0x18 },
 427        { 0xB2, 0x19 },
 428        { 0xB3, 0x2E },
 429        { 0xB4, 0x52 },
 430        { 0xB5, 0x72 },
 431        { 0xB6, 0x8C },
 432        { 0xB7, 0xBD },
 433        { 0xB8, 0xEB },
 434        { 0xB9, 0x47 },
 435        { 0xBA, 0x96 },
 436        { 0xBB, 0x1E },
 437        { 0xBC, 0x90 },
 438        { 0xBD, 0x93 },
 439        { 0xBE, 0xFA },
 440        { 0xBF, 0x56 },
 441        { 0xC0, 0x8C },
 442        { 0xC1, 0xB7 },
 443        { 0xC2, 0xCC },
 444        { 0xC3, 0xDF },
 445        { 0xC4, 0xE8 },
 446        { 0xC5, 0xF0 },
 447        { 0xC6, 0xF8 },
 448        { 0xC7, 0xFA },
 449        { 0xC8, 0xFC },
 450        { 0xC9, 0x00 },
 451        { 0xCA, 0x00 },
 452        { 0xCB, 0x5A },
 453        { 0xCC, 0xAF },
 454        { 0xCD, 0xFF },
 455        { 0xCE, 0xFF },
 456        { 0xB0, 0x0B },
 457        { 0xB1, 0x04 },
 458        { 0xB2, 0x15 },
 459        { 0xB3, 0x2D },
 460        { 0xB4, 0x51 },
 461        { 0xB5, 0x72 },
 462        { 0xB6, 0x8D },
 463        { 0xB7, 0xBE },
 464        { 0xB8, 0xED },
 465        { 0xB9, 0x4A },
 466        { 0xBA, 0x9A },
 467        { 0xBB, 0x23 },
 468        { 0xBC, 0x95 },
 469        { 0xBD, 0x98 },
 470        { 0xBE, 0xFF },
 471        { 0xBF, 0x59 },
 472        { 0xC0, 0x8E },
 473        { 0xC1, 0xB9 },
 474        { 0xC2, 0xCD },
 475        { 0xC3, 0xDF },
 476        { 0xC4, 0xE8 },
 477        { 0xC5, 0xF0 },
 478        { 0xC6, 0xF8 },
 479        { 0xC7, 0xFA },
 480        { 0xC8, 0xFC },
 481        { 0xC9, 0x00 },
 482        { 0xCA, 0x00 },
 483        { 0xCB, 0x5A },
 484        { 0xCC, 0xAF },
 485        { 0xCD, 0xFF },
 486        { 0xCE, 0xFF },
 487        { 0xB0, 0x0C },
 488        { 0xB1, 0x04 },
 489        { 0xB2, 0x2C },
 490        { 0xB3, 0x36 },
 491        { 0xB4, 0x53 },
 492        { 0xB5, 0x73 },
 493        { 0xB6, 0x8E },
 494        { 0xB7, 0xC0 },
 495        { 0xB8, 0xEF },
 496        { 0xB9, 0x4C },
 497        { 0xBA, 0x9D },
 498        { 0xBB, 0x25 },
 499        { 0xBC, 0x96 },
 500        { 0xBD, 0x9A },
 501        { 0xBE, 0x01 },
 502        { 0xBF, 0x59 },
 503        { 0xC0, 0x8E },
 504        { 0xC1, 0xB9 },
 505        { 0xC2, 0xCD },
 506        { 0xC3, 0xDF },
 507        { 0xC4, 0xE8 },
 508        { 0xC5, 0xF0 },
 509        { 0xC6, 0xF8 },
 510        { 0xC7, 0xFA },
 511        { 0xC8, 0xFC },
 512        { 0xC9, 0x00 },
 513        { 0xCA, 0x00 },
 514        { 0xCB, 0x5A },
 515        { 0xCC, 0xBF },
 516        { 0xCD, 0xFF },
 517        { 0xCE, 0xFF },
 518        { 0xB0, 0x04 },
 519        { 0xB5, 0x02 },
 520        { 0xB6, 0x01 },
 521};
 522
 523static const struct panel_desc boe_himax8279d8p_panel_desc = {
 524        .display_mode = &default_display_mode,
 525        .bpc = 8,
 526        .width_mm = 107,
 527        .height_mm = 172,
 528        .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
 529                        MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
 530        .format = MIPI_DSI_FMT_RGB888,
 531        .lanes = 4,
 532        .on_cmds = boe_himax8279d8p_on_cmds,
 533        .on_cmds_num = 260,
 534};
 535
 536/* 10 inch */
 537static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {
 538        { 0xB0, 0x05 },
 539        { 0xB1, 0xE5 },
 540        { 0xB3, 0x52 },
 541        { 0xB0, 0x00 },
 542        { 0xB6, 0x03 },
 543        { 0xBA, 0x8B },
 544        { 0xBF, 0x1A },
 545        { 0xC0, 0x0F },
 546        { 0xC2, 0x0C },
 547        { 0xC3, 0x02 },
 548        { 0xC4, 0x0C },
 549        { 0xC5, 0x02 },
 550        { 0xB0, 0x01 },
 551        { 0xE0, 0x26 },
 552        { 0xE1, 0x26 },
 553        { 0xDC, 0x00 },
 554        { 0xDD, 0x00 },
 555        { 0xCC, 0x26 },
 556        { 0xCD, 0x26 },
 557        { 0xC8, 0x00 },
 558        { 0xC9, 0x00 },
 559        { 0xD2, 0x03 },
 560        { 0xD3, 0x03 },
 561        { 0xE6, 0x04 },
 562        { 0xE7, 0x04 },
 563        { 0xC4, 0x09 },
 564        { 0xC5, 0x09 },
 565        { 0xD8, 0x0A },
 566        { 0xD9, 0x0A },
 567        { 0xC2, 0x0B },
 568        { 0xC3, 0x0B },
 569        { 0xD6, 0x0C },
 570        { 0xD7, 0x0C },
 571        { 0xC0, 0x05 },
 572        { 0xC1, 0x05 },
 573        { 0xD4, 0x06 },
 574        { 0xD5, 0x06 },
 575        { 0xCA, 0x07 },
 576        { 0xCB, 0x07 },
 577        { 0xDE, 0x08 },
 578        { 0xDF, 0x08 },
 579        { 0xB0, 0x02 },
 580        { 0xC0, 0x00 },
 581        { 0xC1, 0x0D },
 582        { 0xC2, 0x17 },
 583        { 0xC3, 0x26 },
 584        { 0xC4, 0x31 },
 585        { 0xC5, 0x1C },
 586        { 0xC6, 0x2C },
 587        { 0xC7, 0x33 },
 588        { 0xC8, 0x31 },
 589        { 0xC9, 0x37 },
 590        { 0xCA, 0x37 },
 591        { 0xCB, 0x37 },
 592        { 0xCC, 0x39 },
 593        { 0xCD, 0x2E },
 594        { 0xCE, 0x2F },
 595        { 0xCF, 0x2F },
 596        { 0xD0, 0x07 },
 597        { 0xD2, 0x00 },
 598        { 0xD3, 0x0D },
 599        { 0xD4, 0x17 },
 600        { 0xD5, 0x26 },
 601        { 0xD6, 0x31 },
 602        { 0xD7, 0x3F },
 603        { 0xD8, 0x3F },
 604        { 0xD9, 0x3F },
 605        { 0xDA, 0x3F },
 606        { 0xDB, 0x37 },
 607        { 0xDC, 0x37 },
 608        { 0xDD, 0x37 },
 609        { 0xDE, 0x39 },
 610        { 0xDF, 0x2E },
 611        { 0xE0, 0x2F },
 612        { 0xE1, 0x2F },
 613        { 0xE2, 0x07 },
 614        { 0xB0, 0x03 },
 615        { 0xC8, 0x0B },
 616        { 0xC9, 0x07 },
 617        { 0xC3, 0x00 },
 618        { 0xE7, 0x00 },
 619        { 0xC5, 0x2A },
 620        { 0xDE, 0x2A },
 621        { 0xCA, 0x43 },
 622        { 0xC9, 0x07 },
 623        { 0xE4, 0xC0 },
 624        { 0xE5, 0x0D },
 625        { 0xCB, 0x01 },
 626        { 0xBC, 0x01 },
 627        { 0xB0, 0x06 },
 628        { 0xB8, 0xA5 },
 629        { 0xC0, 0xA5 },
 630        { 0xC7, 0x0F },
 631        { 0xD5, 0x32 },
 632        { 0xB8, 0x00 },
 633        { 0xC0, 0x00 },
 634        { 0xBC, 0x00 },
 635        { 0xB0, 0x07 },
 636        { 0xB1, 0x00 },
 637        { 0xB2, 0x05 },
 638        { 0xB3, 0x10 },
 639        { 0xB4, 0x22 },
 640        { 0xB5, 0x36 },
 641        { 0xB6, 0x4A },
 642        { 0xB7, 0x6C },
 643        { 0xB8, 0x9A },
 644        { 0xB9, 0xD7 },
 645        { 0xBA, 0x17 },
 646        { 0xBB, 0x92 },
 647        { 0xBC, 0x15 },
 648        { 0xBD, 0x18 },
 649        { 0xBE, 0x8C },
 650        { 0xBF, 0x00 },
 651        { 0xC0, 0x3A },
 652        { 0xC1, 0x72 },
 653        { 0xC2, 0x8C },
 654        { 0xC3, 0xA5 },
 655        { 0xC4, 0xB1 },
 656        { 0xC5, 0xBE },
 657        { 0xC6, 0xCA },
 658        { 0xC7, 0xD1 },
 659        { 0xC8, 0xD4 },
 660        { 0xC9, 0x00 },
 661        { 0xCA, 0x00 },
 662        { 0xCB, 0x16 },
 663        { 0xCC, 0xAF },
 664        { 0xCD, 0xFF },
 665        { 0xCE, 0xFF },
 666        { 0xB0, 0x08 },
 667        { 0xB1, 0x04 },
 668        { 0xB2, 0x05 },
 669        { 0xB3, 0x11 },
 670        { 0xB4, 0x24 },
 671        { 0xB5, 0x39 },
 672        { 0xB6, 0x4E },
 673        { 0xB7, 0x72 },
 674        { 0xB8, 0xA3 },
 675        { 0xB9, 0xE1 },
 676        { 0xBA, 0x25 },
 677        { 0xBB, 0xA8 },
 678        { 0xBC, 0x2E },
 679        { 0xBD, 0x32 },
 680        { 0xBE, 0xAD },
 681        { 0xBF, 0x28 },
 682        { 0xC0, 0x63 },
 683        { 0xC1, 0x9B },
 684        { 0xC2, 0xB5 },
 685        { 0xC3, 0xCF },
 686        { 0xC4, 0xDB },
 687        { 0xC5, 0xE8 },
 688        { 0xC6, 0xF5 },
 689        { 0xC7, 0xFA },
 690        { 0xC8, 0xFC },
 691        { 0xC9, 0x00 },
 692        { 0xCA, 0x00 },
 693        { 0xCB, 0x16 },
 694        { 0xCC, 0xAF },
 695        { 0xCD, 0xFF },
 696        { 0xCE, 0xFF },
 697        { 0xB0, 0x09 },
 698        { 0xB1, 0x04 },
 699        { 0xB2, 0x04 },
 700        { 0xB3, 0x0F },
 701        { 0xB4, 0x22 },
 702        { 0xB5, 0x37 },
 703        { 0xB6, 0x4D },
 704        { 0xB7, 0x71 },
 705        { 0xB8, 0xA2 },
 706        { 0xB9, 0xE1 },
 707        { 0xBA, 0x26 },
 708        { 0xBB, 0xA9 },
 709        { 0xBC, 0x2F },
 710        { 0xBD, 0x33 },
 711        { 0xBE, 0xAC },
 712        { 0xBF, 0x24 },
 713        { 0xC0, 0x5D },
 714        { 0xC1, 0x94 },
 715        { 0xC2, 0xAC },
 716        { 0xC3, 0xC5 },
 717        { 0xC4, 0xD1 },
 718        { 0xC5, 0xDC },
 719        { 0xC6, 0xE8 },
 720        { 0xC7, 0xED },
 721        { 0xC8, 0xF0 },
 722        { 0xC9, 0x00 },
 723        { 0xCA, 0x00 },
 724        { 0xCB, 0x16 },
 725        { 0xCC, 0xAF },
 726        { 0xCD, 0xFF },
 727        { 0xCE, 0xFF },
 728        { 0xB0, 0x0A },
 729        { 0xB1, 0x00 },
 730        { 0xB2, 0x05 },
 731        { 0xB3, 0x10 },
 732        { 0xB4, 0x22 },
 733        { 0xB5, 0x36 },
 734        { 0xB6, 0x4A },
 735        { 0xB7, 0x6C },
 736        { 0xB8, 0x9A },
 737        { 0xB9, 0xD7 },
 738        { 0xBA, 0x17 },
 739        { 0xBB, 0x92 },
 740        { 0xBC, 0x15 },
 741        { 0xBD, 0x18 },
 742        { 0xBE, 0x8C },
 743        { 0xBF, 0x00 },
 744        { 0xC0, 0x3A },
 745        { 0xC1, 0x72 },
 746        { 0xC2, 0x8C },
 747        { 0xC3, 0xA5 },
 748        { 0xC4, 0xB1 },
 749        { 0xC5, 0xBE },
 750        { 0xC6, 0xCA },
 751        { 0xC7, 0xD1 },
 752        { 0xC8, 0xD4 },
 753        { 0xC9, 0x00 },
 754        { 0xCA, 0x00 },
 755        { 0xCB, 0x16 },
 756        { 0xCC, 0xAF },
 757        { 0xCD, 0xFF },
 758        { 0xCE, 0xFF },
 759        { 0xB0, 0x0B },
 760        { 0xB1, 0x04 },
 761        { 0xB2, 0x05 },
 762        { 0xB3, 0x11 },
 763        { 0xB4, 0x24 },
 764        { 0xB5, 0x39 },
 765        { 0xB6, 0x4E },
 766        { 0xB7, 0x72 },
 767        { 0xB8, 0xA3 },
 768        { 0xB9, 0xE1 },
 769        { 0xBA, 0x25 },
 770        { 0xBB, 0xA8 },
 771        { 0xBC, 0x2E },
 772        { 0xBD, 0x32 },
 773        { 0xBE, 0xAD },
 774        { 0xBF, 0x28 },
 775        { 0xC0, 0x63 },
 776        { 0xC1, 0x9B },
 777        { 0xC2, 0xB5 },
 778        { 0xC3, 0xCF },
 779        { 0xC4, 0xDB },
 780        { 0xC5, 0xE8 },
 781        { 0xC6, 0xF5 },
 782        { 0xC7, 0xFA },
 783        { 0xC8, 0xFC },
 784        { 0xC9, 0x00 },
 785        { 0xCA, 0x00 },
 786        { 0xCB, 0x16 },
 787        { 0xCC, 0xAF },
 788        { 0xCD, 0xFF },
 789        { 0xCE, 0xFF },
 790        { 0xB0, 0x0C },
 791        { 0xB1, 0x04 },
 792        { 0xB2, 0x04 },
 793        { 0xB3, 0x0F },
 794        { 0xB4, 0x22 },
 795        { 0xB5, 0x37 },
 796        { 0xB6, 0x4D },
 797        { 0xB7, 0x71 },
 798        { 0xB8, 0xA2 },
 799        { 0xB9, 0xE1 },
 800        { 0xBA, 0x26 },
 801        { 0xBB, 0xA9 },
 802        { 0xBC, 0x2F },
 803        { 0xBD, 0x33 },
 804        { 0xBE, 0xAC },
 805        { 0xBF, 0x24 },
 806        { 0xC0, 0x5D },
 807        { 0xC1, 0x94 },
 808        { 0xC2, 0xAC },
 809        { 0xC3, 0xC5 },
 810        { 0xC4, 0xD1 },
 811        { 0xC5, 0xDC },
 812        { 0xC6, 0xE8 },
 813        { 0xC7, 0xED },
 814        { 0xC8, 0xF0 },
 815        { 0xC9, 0x00 },
 816        { 0xCA, 0x00 },
 817        { 0xCB, 0x16 },
 818        { 0xCC, 0xAF },
 819        { 0xCD, 0xFF },
 820        { 0xCE, 0xFF },
 821};
 822
 823static const struct panel_desc boe_himax8279d10p_panel_desc = {
 824        .display_mode = &default_display_mode,
 825        .bpc = 8,
 826        .width_mm = 135,
 827        .height_mm = 216,
 828        .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
 829                        MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
 830        .format = MIPI_DSI_FMT_RGB888,
 831        .lanes = 4,
 832        .on_cmds = boe_himax8279d10p_on_cmds,
 833        .on_cmds_num = 283,
 834};
 835
 836static const struct of_device_id panel_of_match[] = {
 837        {
 838                .compatible = "boe,himax8279d8p",
 839                .data = &boe_himax8279d8p_panel_desc,
 840        },
 841        {
 842                .compatible = "boe,himax8279d10p",
 843                .data = &boe_himax8279d10p_panel_desc,
 844        },
 845        {
 846                /* sentinel */
 847        }
 848};
 849MODULE_DEVICE_TABLE(of, panel_of_match);
 850
 851static int panel_add(struct panel_info *pinfo)
 852{
 853        struct device *dev = &pinfo->link->dev;
 854        int ret;
 855
 856        pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH);
 857        if (IS_ERR(pinfo->pp18_gpio)) {
 858                ret = PTR_ERR(pinfo->pp18_gpio);
 859                if (ret != -EPROBE_DEFER)
 860                        dev_err(dev, "failed to get pp18 gpio: %d\n", ret);
 861                return ret;
 862        }
 863
 864        pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH);
 865        if (IS_ERR(pinfo->pp33_gpio)) {
 866                ret = PTR_ERR(pinfo->pp33_gpio);
 867                if (ret != -EPROBE_DEFER)
 868                        dev_err(dev, "failed to get pp33 gpio: %d\n", ret);
 869                return ret;
 870        }
 871
 872        pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
 873        if (IS_ERR(pinfo->enable_gpio)) {
 874                ret = PTR_ERR(pinfo->enable_gpio);
 875                if (ret != -EPROBE_DEFER)
 876                        dev_err(dev, "failed to get enable gpio: %d\n", ret);
 877                return ret;
 878        }
 879
 880        drm_panel_init(&pinfo->base, dev, &panel_funcs,
 881                       DRM_MODE_CONNECTOR_DSI);
 882
 883        ret = drm_panel_of_backlight(&pinfo->base);
 884        if (ret)
 885                return ret;
 886
 887        drm_panel_add(&pinfo->base);
 888
 889        return 0;
 890}
 891
 892static int panel_probe(struct mipi_dsi_device *dsi)
 893{
 894        struct panel_info *pinfo;
 895        const struct panel_desc *desc;
 896        int err;
 897
 898        pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL);
 899        if (!pinfo)
 900                return -ENOMEM;
 901
 902        desc = of_device_get_match_data(&dsi->dev);
 903        dsi->mode_flags = desc->mode_flags;
 904        dsi->format = desc->format;
 905        dsi->lanes = desc->lanes;
 906        pinfo->desc = desc;
 907
 908        pinfo->link = dsi;
 909        mipi_dsi_set_drvdata(dsi, pinfo);
 910
 911        err = panel_add(pinfo);
 912        if (err < 0)
 913                return err;
 914
 915        err = mipi_dsi_attach(dsi);
 916        if (err < 0)
 917                drm_panel_remove(&pinfo->base);
 918
 919        return err;
 920}
 921
 922static int panel_remove(struct mipi_dsi_device *dsi)
 923{
 924        struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
 925        int err;
 926
 927        err = boe_panel_disable(&pinfo->base);
 928        if (err < 0)
 929                dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
 930
 931        err = boe_panel_unprepare(&pinfo->base);
 932        if (err < 0)
 933                dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
 934
 935        err = mipi_dsi_detach(dsi);
 936        if (err < 0)
 937                dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
 938
 939        drm_panel_remove(&pinfo->base);
 940
 941        return 0;
 942}
 943
 944static void panel_shutdown(struct mipi_dsi_device *dsi)
 945{
 946        struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
 947
 948        boe_panel_disable(&pinfo->base);
 949        boe_panel_unprepare(&pinfo->base);
 950}
 951
 952static struct mipi_dsi_driver panel_driver = {
 953        .driver = {
 954                .name = "panel-boe-himax8279d",
 955                .of_match_table = panel_of_match,
 956        },
 957        .probe = panel_probe,
 958        .remove = panel_remove,
 959        .shutdown = panel_shutdown,
 960};
 961module_mipi_dsi_driver(panel_driver);
 962
 963MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>");
 964MODULE_DESCRIPTION("Boe Himax8279d driver");
 965MODULE_LICENSE("GPL v2");
 966