linux/drivers/gpu/drm/panel/panel-sitronix-st7703.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Driver for panels based on Sitronix ST7703 controller, souch as:
   4 *
   5 * - Rocktech jh057n00900 5.5" MIPI-DSI panel
   6 *
   7 * Copyright (C) Purism SPC 2019
   8 */
   9
  10#include <linux/debugfs.h>
  11#include <linux/delay.h>
  12#include <linux/gpio/consumer.h>
  13#include <linux/media-bus-format.h>
  14#include <linux/mod_devicetable.h>
  15#include <linux/module.h>
  16#include <linux/of_device.h>
  17#include <linux/regulator/consumer.h>
  18
  19#include <video/display_timing.h>
  20#include <video/mipi_display.h>
  21
  22#include <drm/drm_mipi_dsi.h>
  23#include <drm/drm_modes.h>
  24#include <drm/drm_panel.h>
  25
  26#define DRV_NAME "panel-sitronix-st7703"
  27
  28/* Manufacturer specific Commands send via DSI */
  29#define ST7703_CMD_ALL_PIXEL_OFF 0x22
  30#define ST7703_CMD_ALL_PIXEL_ON  0x23
  31#define ST7703_CMD_SETDISP       0xB2
  32#define ST7703_CMD_SETRGBIF      0xB3
  33#define ST7703_CMD_SETCYC        0xB4
  34#define ST7703_CMD_SETBGP        0xB5
  35#define ST7703_CMD_SETVCOM       0xB6
  36#define ST7703_CMD_SETOTP        0xB7
  37#define ST7703_CMD_SETPOWER_EXT  0xB8
  38#define ST7703_CMD_SETEXTC       0xB9
  39#define ST7703_CMD_SETMIPI       0xBA
  40#define ST7703_CMD_SETVDC        0xBC
  41#define ST7703_CMD_UNKNOWN_BF    0xBF
  42#define ST7703_CMD_SETSCR        0xC0
  43#define ST7703_CMD_SETPOWER      0xC1
  44#define ST7703_CMD_SETPANEL      0xCC
  45#define ST7703_CMD_UNKNOWN_C6    0xC6
  46#define ST7703_CMD_SETGAMMA      0xE0
  47#define ST7703_CMD_SETEQ         0xE3
  48#define ST7703_CMD_SETGIP1       0xE9
  49#define ST7703_CMD_SETGIP2       0xEA
  50
  51struct st7703 {
  52        struct device *dev;
  53        struct drm_panel panel;
  54        struct gpio_desc *reset_gpio;
  55        struct regulator *vcc;
  56        struct regulator *iovcc;
  57        bool prepared;
  58
  59        struct dentry *debugfs;
  60        const struct st7703_panel_desc *desc;
  61};
  62
  63struct st7703_panel_desc {
  64        const struct drm_display_mode *mode;
  65        unsigned int lanes;
  66        unsigned long mode_flags;
  67        enum mipi_dsi_pixel_format format;
  68        int (*init_sequence)(struct st7703 *ctx);
  69};
  70
  71static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
  72{
  73        return container_of(panel, struct st7703, panel);
  74}
  75
  76#define dsi_generic_write_seq(dsi, seq...) do {                         \
  77                static const u8 d[] = { seq };                          \
  78                int ret;                                                \
  79                ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));    \
  80                if (ret < 0)                                            \
  81                        return ret;                                     \
  82        } while (0)
  83
  84static int jh057n_init_sequence(struct st7703 *ctx)
  85{
  86        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  87
  88        /*
  89         * Init sequence was supplied by the panel vendor. Most of the commands
  90         * resemble the ST7703 but the number of parameters often don't match
  91         * so it's likely a clone.
  92         */
  93        dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
  94                              0xF1, 0x12, 0x83);
  95        dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
  96                              0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
  97                              0x00, 0x00);
  98        dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
  99                              0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
 100                              0x00);
 101        dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
 102        dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
 103        dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
 104        dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
 105        dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
 106                              0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
 107                              0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
 108        dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
 109        msleep(20);
 110
 111        dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
 112        dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
 113        dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
 114                              0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
 115                              0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
 116                              0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
 117                              0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
 118                              0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
 119                              0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
 120                              0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 121                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
 122        dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
 123                              0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 124                              0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
 125                              0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
 126                              0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
 127                              0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
 128                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 129                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
 130                              0xA5, 0x00, 0x00, 0x00, 0x00);
 131        dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
 132                              0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
 133                              0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
 134                              0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
 135                              0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
 136                              0x11, 0x18);
 137
 138        return 0;
 139}
 140
 141static const struct drm_display_mode jh057n00900_mode = {
 142        .hdisplay    = 720,
 143        .hsync_start = 720 + 90,
 144        .hsync_end   = 720 + 90 + 20,
 145        .htotal      = 720 + 90 + 20 + 20,
 146        .vdisplay    = 1440,
 147        .vsync_start = 1440 + 20,
 148        .vsync_end   = 1440 + 20 + 4,
 149        .vtotal      = 1440 + 20 + 4 + 12,
 150        .clock       = 75276,
 151        .flags       = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 152        .width_mm    = 65,
 153        .height_mm   = 130,
 154};
 155
 156static const struct st7703_panel_desc jh057n00900_panel_desc = {
 157        .mode = &jh057n00900_mode,
 158        .lanes = 4,
 159        .mode_flags = MIPI_DSI_MODE_VIDEO |
 160                MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
 161        .format = MIPI_DSI_FMT_RGB888,
 162        .init_sequence = jh057n_init_sequence,
 163};
 164
 165#define dsi_dcs_write_seq(dsi, cmd, seq...) do {                        \
 166                static const u8 d[] = { seq };                          \
 167                int ret;                                                \
 168                ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d));   \
 169                if (ret < 0)                                            \
 170                        return ret;                                     \
 171        } while (0)
 172
 173
 174static int xbd599_init_sequence(struct st7703 *ctx)
 175{
 176        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 177
 178        /*
 179         * Init sequence was supplied by the panel vendor.
 180         */
 181
 182        /* Magic sequence to unlock user commands below. */
 183        dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
 184
 185        dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
 186                          0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
 187                          0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
 188                          0x05, /* IHSRX = x6 (Low High Speed driving ability) */
 189                          0xF9, /* TX_CLK_SEL = fDSICLK/16 */
 190                          0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
 191                          0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
 192                          /* The rest is undocumented in ST7703 datasheet */
 193                          0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 194                          0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
 195                          0x4F, 0x11, 0x00, 0x00, 0x37);
 196
 197        dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
 198                          0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
 199                          0x22, /* DT = 15ms XDK_ECP = x2 */
 200                          0x20, /* PFM_DC_DIV = /1 */
 201                          0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
 202
 203        /* RGB I/F porch timing */
 204        dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
 205                          0x10, /* VBP_RGB_GEN */
 206                          0x10, /* VFP_RGB_GEN */
 207                          0x05, /* DE_BP_RGB_GEN */
 208                          0x05, /* DE_FP_RGB_GEN */
 209                          /* The rest is undocumented in ST7703 datasheet */
 210                          0x03, 0xFF,
 211                          0x00, 0x00,
 212                          0x00, 0x00);
 213
 214        /* Source driving settings. */
 215        dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
 216                          0x73, /* N_POPON */
 217                          0x73, /* N_NOPON */
 218                          0x50, /* I_POPON */
 219                          0x50, /* I_NOPON */
 220                          0x00, /* SCR[31,24] */
 221                          0xC0, /* SCR[23,16] */
 222                          0x08, /* SCR[15,8] */
 223                          0x70, /* SCR[7,0] */
 224                          0x00  /* Undocumented */);
 225
 226        /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
 227        dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
 228
 229        /*
 230         * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
 231         * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
 232         */
 233        dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
 234
 235        /* Zig-Zag Type C column inversion. */
 236        dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
 237
 238        /* Set display resolution. */
 239        dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
 240                          0xF0, /* NL = 240 */
 241                          0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
 242                                 * RESO_SEL = 720RGB
 243                                 */
 244                          0xF0  /* WHITE_GND_EN = 1 (GND),
 245                                 * WHITE_FRAME_SEL = 7 frames,
 246                                 * ISC = 0 frames
 247                                 */);
 248
 249        dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
 250                          0x00, /* PNOEQ */
 251                          0x00, /* NNOEQ */
 252                          0x0B, /* PEQGND */
 253                          0x0B, /* NEQGND */
 254                          0x10, /* PEQVCI */
 255                          0x10, /* NEQVCI */
 256                          0x00, /* PEQVCI1 */
 257                          0x00, /* NEQVCI1 */
 258                          0x00, /* reserved */
 259                          0x00, /* reserved */
 260                          0xFF, /* reserved */
 261                          0x00, /* reserved */
 262                          0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
 263                          0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
 264                                 * VEDIO_NO_CHECK_EN = 0
 265                                 * ESD_WHITE_GND_EN = 0
 266                                 * ESD_DET_TIME_SEL = 0 frames
 267                                 */);
 268
 269        /* Undocumented command. */
 270        dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
 271
 272        dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
 273                          0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
 274                          0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
 275                          0x32, /* VRP  */
 276                          0x32, /* VRN */
 277                          0x77, /* reserved */
 278                          0xF1, /* APS = 1 (small),
 279                                 * VGL_DET_EN = 1, VGH_DET_EN = 1,
 280                                 * VGL_TURBO = 1, VGH_TURBO = 1
 281                                 */
 282                          0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
 283                          0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
 284                          0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
 285                          0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
 286                          0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
 287                          0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
 288
 289        /* Reference voltage. */
 290        dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
 291                          0x07, /* VREF_SEL = 4.2V */
 292                          0x07  /* NVREF_SEL = 4.2V */);
 293        msleep(20);
 294
 295        dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
 296                          0x2C, /* VCOMDC_F = -0.67V */
 297                          0x2C  /* VCOMDC_B = -0.67V */);
 298
 299        /* Undocumented command. */
 300        dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
 301
 302        /* This command is to set forward GIP timing. */
 303        dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
 304                          0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
 305                          0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
 306                          0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
 307                          0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
 308                          0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
 309                          0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
 310                          0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 311                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
 312
 313        /* This command is to set backward GIP timing. */
 314        dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
 315                          0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 316                          0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
 317                          0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
 318                          0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
 319                          0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
 320                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 321                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
 322                          0xA5, 0x00, 0x00, 0x00, 0x00);
 323
 324        /* Adjust the gamma characteristics of the panel. */
 325        dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
 326                          0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
 327                          0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
 328                          0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
 329                          0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
 330                          0x12, 0x18);
 331
 332        return 0;
 333}
 334
 335static const struct drm_display_mode xbd599_mode = {
 336        .hdisplay    = 720,
 337        .hsync_start = 720 + 40,
 338        .hsync_end   = 720 + 40 + 40,
 339        .htotal      = 720 + 40 + 40 + 40,
 340        .vdisplay    = 1440,
 341        .vsync_start = 1440 + 18,
 342        .vsync_end   = 1440 + 18 + 10,
 343        .vtotal      = 1440 + 18 + 10 + 17,
 344        .clock       = 69000,
 345        .flags       = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 346        .width_mm    = 68,
 347        .height_mm   = 136,
 348};
 349
 350static const struct st7703_panel_desc xbd599_desc = {
 351        .mode = &xbd599_mode,
 352        .lanes = 4,
 353        .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
 354        .format = MIPI_DSI_FMT_RGB888,
 355        .init_sequence = xbd599_init_sequence,
 356};
 357
 358static int st7703_enable(struct drm_panel *panel)
 359{
 360        struct st7703 *ctx = panel_to_st7703(panel);
 361        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 362        int ret;
 363
 364        ret = ctx->desc->init_sequence(ctx);
 365        if (ret < 0) {
 366                dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
 367                return ret;
 368        }
 369
 370        msleep(20);
 371
 372        ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
 373        if (ret < 0) {
 374                dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
 375                return ret;
 376        }
 377
 378        /* Panel is operational 120 msec after reset */
 379        msleep(60);
 380
 381        ret = mipi_dsi_dcs_set_display_on(dsi);
 382        if (ret)
 383                return ret;
 384
 385        dev_dbg(ctx->dev, "Panel init sequence done\n");
 386
 387        return 0;
 388}
 389
 390static int st7703_disable(struct drm_panel *panel)
 391{
 392        struct st7703 *ctx = panel_to_st7703(panel);
 393        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 394        int ret;
 395
 396        ret = mipi_dsi_dcs_set_display_off(dsi);
 397        if (ret < 0)
 398                dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
 399
 400        ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
 401        if (ret < 0)
 402                dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
 403
 404        return 0;
 405}
 406
 407static int st7703_unprepare(struct drm_panel *panel)
 408{
 409        struct st7703 *ctx = panel_to_st7703(panel);
 410
 411        if (!ctx->prepared)
 412                return 0;
 413
 414        gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 415        regulator_disable(ctx->iovcc);
 416        regulator_disable(ctx->vcc);
 417        ctx->prepared = false;
 418
 419        return 0;
 420}
 421
 422static int st7703_prepare(struct drm_panel *panel)
 423{
 424        struct st7703 *ctx = panel_to_st7703(panel);
 425        int ret;
 426
 427        if (ctx->prepared)
 428                return 0;
 429
 430        dev_dbg(ctx->dev, "Resetting the panel\n");
 431        ret = regulator_enable(ctx->vcc);
 432        if (ret < 0) {
 433                dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
 434                return ret;
 435        }
 436        ret = regulator_enable(ctx->iovcc);
 437        if (ret < 0) {
 438                dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
 439                goto disable_vcc;
 440        }
 441
 442        gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 443        usleep_range(20, 40);
 444        gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 445        msleep(20);
 446
 447        ctx->prepared = true;
 448
 449        return 0;
 450
 451disable_vcc:
 452        regulator_disable(ctx->vcc);
 453        return ret;
 454}
 455
 456static int st7703_get_modes(struct drm_panel *panel,
 457                            struct drm_connector *connector)
 458{
 459        struct st7703 *ctx = panel_to_st7703(panel);
 460        struct drm_display_mode *mode;
 461
 462        mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
 463        if (!mode) {
 464                dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
 465                        ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
 466                        drm_mode_vrefresh(ctx->desc->mode));
 467                return -ENOMEM;
 468        }
 469
 470        drm_mode_set_name(mode);
 471
 472        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 473        connector->display_info.width_mm = mode->width_mm;
 474        connector->display_info.height_mm = mode->height_mm;
 475        drm_mode_probed_add(connector, mode);
 476
 477        return 1;
 478}
 479
 480static const struct drm_panel_funcs st7703_drm_funcs = {
 481        .disable   = st7703_disable,
 482        .unprepare = st7703_unprepare,
 483        .prepare   = st7703_prepare,
 484        .enable    = st7703_enable,
 485        .get_modes = st7703_get_modes,
 486};
 487
 488static int allpixelson_set(void *data, u64 val)
 489{
 490        struct st7703 *ctx = data;
 491        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 492
 493        dev_dbg(ctx->dev, "Setting all pixels on\n");
 494        dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
 495        msleep(val * 1000);
 496        /* Reset the panel to get video back */
 497        drm_panel_disable(&ctx->panel);
 498        drm_panel_unprepare(&ctx->panel);
 499        drm_panel_prepare(&ctx->panel);
 500        drm_panel_enable(&ctx->panel);
 501
 502        return 0;
 503}
 504
 505DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
 506                        allpixelson_set, "%llu\n");
 507
 508static void st7703_debugfs_init(struct st7703 *ctx)
 509{
 510        ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
 511
 512        debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
 513                            &allpixelson_fops);
 514}
 515
 516static void st7703_debugfs_remove(struct st7703 *ctx)
 517{
 518        debugfs_remove_recursive(ctx->debugfs);
 519        ctx->debugfs = NULL;
 520}
 521
 522static int st7703_probe(struct mipi_dsi_device *dsi)
 523{
 524        struct device *dev = &dsi->dev;
 525        struct st7703 *ctx;
 526        int ret;
 527
 528        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 529        if (!ctx)
 530                return -ENOMEM;
 531
 532        ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
 533        if (IS_ERR(ctx->reset_gpio))
 534                return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
 535
 536        mipi_dsi_set_drvdata(dsi, ctx);
 537
 538        ctx->dev = dev;
 539        ctx->desc = of_device_get_match_data(dev);
 540
 541        dsi->mode_flags = ctx->desc->mode_flags;
 542        dsi->format = ctx->desc->format;
 543        dsi->lanes = ctx->desc->lanes;
 544
 545        ctx->vcc = devm_regulator_get(dev, "vcc");
 546        if (IS_ERR(ctx->vcc))
 547                return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
 548
 549        ctx->iovcc = devm_regulator_get(dev, "iovcc");
 550        if (IS_ERR(ctx->iovcc))
 551                return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
 552                                     "Failed to request iovcc regulator\n");
 553
 554        drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
 555                       DRM_MODE_CONNECTOR_DSI);
 556
 557        ret = drm_panel_of_backlight(&ctx->panel);
 558        if (ret)
 559                return ret;
 560
 561        drm_panel_add(&ctx->panel);
 562
 563        ret = mipi_dsi_attach(dsi);
 564        if (ret < 0) {
 565                dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
 566                drm_panel_remove(&ctx->panel);
 567                return ret;
 568        }
 569
 570        dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
 571                 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
 572                 drm_mode_vrefresh(ctx->desc->mode),
 573                 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
 574
 575        st7703_debugfs_init(ctx);
 576        return 0;
 577}
 578
 579static void st7703_shutdown(struct mipi_dsi_device *dsi)
 580{
 581        struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
 582        int ret;
 583
 584        ret = drm_panel_unprepare(&ctx->panel);
 585        if (ret < 0)
 586                dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
 587
 588        ret = drm_panel_disable(&ctx->panel);
 589        if (ret < 0)
 590                dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
 591}
 592
 593static int st7703_remove(struct mipi_dsi_device *dsi)
 594{
 595        struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
 596        int ret;
 597
 598        st7703_shutdown(dsi);
 599
 600        ret = mipi_dsi_detach(dsi);
 601        if (ret < 0)
 602                dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
 603
 604        drm_panel_remove(&ctx->panel);
 605
 606        st7703_debugfs_remove(ctx);
 607
 608        return 0;
 609}
 610
 611static const struct of_device_id st7703_of_match[] = {
 612        { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
 613        { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
 614        { /* sentinel */ }
 615};
 616MODULE_DEVICE_TABLE(of, st7703_of_match);
 617
 618static struct mipi_dsi_driver st7703_driver = {
 619        .probe  = st7703_probe,
 620        .remove = st7703_remove,
 621        .shutdown = st7703_shutdown,
 622        .driver = {
 623                .name = DRV_NAME,
 624                .of_match_table = st7703_of_match,
 625        },
 626};
 627module_mipi_dsi_driver(st7703_driver);
 628
 629MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
 630MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
 631MODULE_LICENSE("GPL v2");
 632