Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for panels based on Sitronix ST7703 controller, souch as:
0004  *
0005  * - Rocktech jh057n00900 5.5" MIPI-DSI panel
0006  *
0007  * Copyright (C) Purism SPC 2019
0008  */
0009 
0010 #include <linux/debugfs.h>
0011 #include <linux/delay.h>
0012 #include <linux/gpio/consumer.h>
0013 #include <linux/media-bus-format.h>
0014 #include <linux/mod_devicetable.h>
0015 #include <linux/module.h>
0016 #include <linux/of_device.h>
0017 #include <linux/regulator/consumer.h>
0018 
0019 #include <video/display_timing.h>
0020 #include <video/mipi_display.h>
0021 
0022 #include <drm/drm_mipi_dsi.h>
0023 #include <drm/drm_modes.h>
0024 #include <drm/drm_panel.h>
0025 
0026 #define DRV_NAME "panel-sitronix-st7703"
0027 
0028 /* Manufacturer specific Commands send via DSI */
0029 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
0030 #define ST7703_CMD_ALL_PIXEL_ON  0x23
0031 #define ST7703_CMD_SETDISP   0xB2
0032 #define ST7703_CMD_SETRGBIF  0xB3
0033 #define ST7703_CMD_SETCYC    0xB4
0034 #define ST7703_CMD_SETBGP    0xB5
0035 #define ST7703_CMD_SETVCOM   0xB6
0036 #define ST7703_CMD_SETOTP    0xB7
0037 #define ST7703_CMD_SETPOWER_EXT  0xB8
0038 #define ST7703_CMD_SETEXTC   0xB9
0039 #define ST7703_CMD_SETMIPI   0xBA
0040 #define ST7703_CMD_SETVDC    0xBC
0041 #define ST7703_CMD_UNKNOWN_BF    0xBF
0042 #define ST7703_CMD_SETSCR    0xC0
0043 #define ST7703_CMD_SETPOWER  0xC1
0044 #define ST7703_CMD_SETPANEL  0xCC
0045 #define ST7703_CMD_UNKNOWN_C6    0xC6
0046 #define ST7703_CMD_SETGAMMA  0xE0
0047 #define ST7703_CMD_SETEQ     0xE3
0048 #define ST7703_CMD_SETGIP1   0xE9
0049 #define ST7703_CMD_SETGIP2   0xEA
0050 
0051 struct st7703 {
0052     struct device *dev;
0053     struct drm_panel panel;
0054     struct gpio_desc *reset_gpio;
0055     struct regulator *vcc;
0056     struct regulator *iovcc;
0057     bool prepared;
0058 
0059     struct dentry *debugfs;
0060     const struct st7703_panel_desc *desc;
0061 };
0062 
0063 struct st7703_panel_desc {
0064     const struct drm_display_mode *mode;
0065     unsigned int lanes;
0066     unsigned long mode_flags;
0067     enum mipi_dsi_pixel_format format;
0068     int (*init_sequence)(struct st7703 *ctx);
0069 };
0070 
0071 static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
0072 {
0073     return container_of(panel, struct st7703, panel);
0074 }
0075 
0076 #define dsi_generic_write_seq(dsi, seq...) do {             \
0077         static const u8 d[] = { seq };              \
0078         int ret;                        \
0079         ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));    \
0080         if (ret < 0)                        \
0081             return ret;                 \
0082     } while (0)
0083 
0084 static int jh057n_init_sequence(struct st7703 *ctx)
0085 {
0086     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0087 
0088     /*
0089      * Init sequence was supplied by the panel vendor. Most of the commands
0090      * resemble the ST7703 but the number of parameters often don't match
0091      * so it's likely a clone.
0092      */
0093     dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
0094                   0xF1, 0x12, 0x83);
0095     dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
0096                   0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
0097                   0x00, 0x00);
0098     dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
0099                   0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
0100                   0x00);
0101     dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
0102     dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
0103     dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
0104     dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
0105     dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
0106                   0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
0107                   0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
0108     dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
0109     msleep(20);
0110 
0111     dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
0112     dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
0113     dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
0114                   0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
0115                   0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0116                   0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0117                   0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0118                   0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0119                   0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0120                   0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0121                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
0122     dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
0123                   0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0124                   0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0125                   0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0126                   0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0127                   0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0128                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0129                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
0130                   0xA5, 0x00, 0x00, 0x00, 0x00);
0131     dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
0132                   0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
0133                   0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
0134                   0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
0135                   0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
0136                   0x11, 0x18);
0137 
0138     return 0;
0139 }
0140 
0141 static const struct drm_display_mode jh057n00900_mode = {
0142     .hdisplay    = 720,
0143     .hsync_start = 720 + 90,
0144     .hsync_end   = 720 + 90 + 20,
0145     .htotal      = 720 + 90 + 20 + 20,
0146     .vdisplay    = 1440,
0147     .vsync_start = 1440 + 20,
0148     .vsync_end   = 1440 + 20 + 4,
0149     .vtotal      = 1440 + 20 + 4 + 12,
0150     .clock       = 75276,
0151     .flags       = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
0152     .width_mm    = 65,
0153     .height_mm   = 130,
0154 };
0155 
0156 static const struct st7703_panel_desc jh057n00900_panel_desc = {
0157     .mode = &jh057n00900_mode,
0158     .lanes = 4,
0159     .mode_flags = MIPI_DSI_MODE_VIDEO |
0160         MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
0161     .format = MIPI_DSI_FMT_RGB888,
0162     .init_sequence = jh057n_init_sequence,
0163 };
0164 
0165 #define dsi_dcs_write_seq(dsi, cmd, seq...) do {            \
0166         static const u8 d[] = { seq };              \
0167         int ret;                        \
0168         ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d));   \
0169         if (ret < 0)                        \
0170             return ret;                 \
0171     } while (0)
0172 
0173 
0174 static int xbd599_init_sequence(struct st7703 *ctx)
0175 {
0176     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0177 
0178     /*
0179      * Init sequence was supplied by the panel vendor.
0180      */
0181 
0182     /* Magic sequence to unlock user commands below. */
0183     dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
0184 
0185     dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
0186               0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
0187               0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
0188               0x05, /* IHSRX = x6 (Low High Speed driving ability) */
0189               0xF9, /* TX_CLK_SEL = fDSICLK/16 */
0190               0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
0191               0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
0192               /* The rest is undocumented in ST7703 datasheet */
0193               0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0194               0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
0195               0x4F, 0x11, 0x00, 0x00, 0x37);
0196 
0197     dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
0198               0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
0199               0x22, /* DT = 15ms XDK_ECP = x2 */
0200               0x20, /* PFM_DC_DIV = /1 */
0201               0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
0202 
0203     /* RGB I/F porch timing */
0204     dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
0205               0x10, /* VBP_RGB_GEN */
0206               0x10, /* VFP_RGB_GEN */
0207               0x05, /* DE_BP_RGB_GEN */
0208               0x05, /* DE_FP_RGB_GEN */
0209               /* The rest is undocumented in ST7703 datasheet */
0210               0x03, 0xFF,
0211               0x00, 0x00,
0212               0x00, 0x00);
0213 
0214     /* Source driving settings. */
0215     dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
0216               0x73, /* N_POPON */
0217               0x73, /* N_NOPON */
0218               0x50, /* I_POPON */
0219               0x50, /* I_NOPON */
0220               0x00, /* SCR[31,24] */
0221               0xC0, /* SCR[23,16] */
0222               0x08, /* SCR[15,8] */
0223               0x70, /* SCR[7,0] */
0224               0x00  /* Undocumented */);
0225 
0226     /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
0227     dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
0228 
0229     /*
0230      * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
0231      * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
0232      */
0233     dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
0234 
0235     /* Zig-Zag Type C column inversion. */
0236     dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
0237 
0238     /* Set display resolution. */
0239     dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
0240               0xF0, /* NL = 240 */
0241               0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
0242                  * RESO_SEL = 720RGB
0243                  */
0244               0xF0  /* WHITE_GND_EN = 1 (GND),
0245                  * WHITE_FRAME_SEL = 7 frames,
0246                  * ISC = 0 frames
0247                  */);
0248 
0249     dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
0250               0x00, /* PNOEQ */
0251               0x00, /* NNOEQ */
0252               0x0B, /* PEQGND */
0253               0x0B, /* NEQGND */
0254               0x10, /* PEQVCI */
0255               0x10, /* NEQVCI */
0256               0x00, /* PEQVCI1 */
0257               0x00, /* NEQVCI1 */
0258               0x00, /* reserved */
0259               0x00, /* reserved */
0260               0xFF, /* reserved */
0261               0x00, /* reserved */
0262               0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
0263               0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
0264                  * VEDIO_NO_CHECK_EN = 0
0265                  * ESD_WHITE_GND_EN = 0
0266                  * ESD_DET_TIME_SEL = 0 frames
0267                  */);
0268 
0269     /* Undocumented command. */
0270     dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
0271 
0272     dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
0273               0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
0274               0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
0275               0x32, /* VRP  */
0276               0x32, /* VRN */
0277               0x77, /* reserved */
0278               0xF1, /* APS = 1 (small),
0279                  * VGL_DET_EN = 1, VGH_DET_EN = 1,
0280                  * VGL_TURBO = 1, VGH_TURBO = 1
0281                  */
0282               0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
0283               0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
0284               0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
0285               0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
0286               0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
0287               0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
0288 
0289     /* Reference voltage. */
0290     dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
0291               0x07, /* VREF_SEL = 4.2V */
0292               0x07  /* NVREF_SEL = 4.2V */);
0293     msleep(20);
0294 
0295     dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
0296               0x2C, /* VCOMDC_F = -0.67V */
0297               0x2C  /* VCOMDC_B = -0.67V */);
0298 
0299     /* Undocumented command. */
0300     dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
0301 
0302     /* This command is to set forward GIP timing. */
0303     dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
0304               0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
0305               0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0306               0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0307               0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0308               0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0309               0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0310               0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0311               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
0312 
0313     /* This command is to set backward GIP timing. */
0314     dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
0315               0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0316               0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0317               0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0318               0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0319               0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0320               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0321               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
0322               0xA5, 0x00, 0x00, 0x00, 0x00);
0323 
0324     /* Adjust the gamma characteristics of the panel. */
0325     dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
0326               0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
0327               0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
0328               0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
0329               0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
0330               0x12, 0x18);
0331 
0332     return 0;
0333 }
0334 
0335 static const struct drm_display_mode xbd599_mode = {
0336     .hdisplay    = 720,
0337     .hsync_start = 720 + 40,
0338     .hsync_end   = 720 + 40 + 40,
0339     .htotal      = 720 + 40 + 40 + 40,
0340     .vdisplay    = 1440,
0341     .vsync_start = 1440 + 18,
0342     .vsync_end   = 1440 + 18 + 10,
0343     .vtotal      = 1440 + 18 + 10 + 17,
0344     .clock       = 69000,
0345     .flags       = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
0346     .width_mm    = 68,
0347     .height_mm   = 136,
0348 };
0349 
0350 static const struct st7703_panel_desc xbd599_desc = {
0351     .mode = &xbd599_mode,
0352     .lanes = 4,
0353     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
0354     .format = MIPI_DSI_FMT_RGB888,
0355     .init_sequence = xbd599_init_sequence,
0356 };
0357 
0358 static int st7703_enable(struct drm_panel *panel)
0359 {
0360     struct st7703 *ctx = panel_to_st7703(panel);
0361     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0362     int ret;
0363 
0364     ret = ctx->desc->init_sequence(ctx);
0365     if (ret < 0) {
0366         dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
0367         return ret;
0368     }
0369 
0370     msleep(20);
0371 
0372     ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
0373     if (ret < 0) {
0374         dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
0375         return ret;
0376     }
0377 
0378     /* Panel is operational 120 msec after reset */
0379     msleep(60);
0380 
0381     ret = mipi_dsi_dcs_set_display_on(dsi);
0382     if (ret)
0383         return ret;
0384 
0385     dev_dbg(ctx->dev, "Panel init sequence done\n");
0386 
0387     return 0;
0388 }
0389 
0390 static int st7703_disable(struct drm_panel *panel)
0391 {
0392     struct st7703 *ctx = panel_to_st7703(panel);
0393     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0394     int ret;
0395 
0396     ret = mipi_dsi_dcs_set_display_off(dsi);
0397     if (ret < 0)
0398         dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
0399 
0400     ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
0401     if (ret < 0)
0402         dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
0403 
0404     return 0;
0405 }
0406 
0407 static int st7703_unprepare(struct drm_panel *panel)
0408 {
0409     struct st7703 *ctx = panel_to_st7703(panel);
0410 
0411     if (!ctx->prepared)
0412         return 0;
0413 
0414     gpiod_set_value_cansleep(ctx->reset_gpio, 1);
0415     regulator_disable(ctx->iovcc);
0416     regulator_disable(ctx->vcc);
0417     ctx->prepared = false;
0418 
0419     return 0;
0420 }
0421 
0422 static int st7703_prepare(struct drm_panel *panel)
0423 {
0424     struct st7703 *ctx = panel_to_st7703(panel);
0425     int ret;
0426 
0427     if (ctx->prepared)
0428         return 0;
0429 
0430     dev_dbg(ctx->dev, "Resetting the panel\n");
0431     ret = regulator_enable(ctx->vcc);
0432     if (ret < 0) {
0433         dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
0434         return ret;
0435     }
0436     ret = regulator_enable(ctx->iovcc);
0437     if (ret < 0) {
0438         dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
0439         goto disable_vcc;
0440     }
0441 
0442     gpiod_set_value_cansleep(ctx->reset_gpio, 1);
0443     usleep_range(20, 40);
0444     gpiod_set_value_cansleep(ctx->reset_gpio, 0);
0445     msleep(20);
0446 
0447     ctx->prepared = true;
0448 
0449     return 0;
0450 
0451 disable_vcc:
0452     regulator_disable(ctx->vcc);
0453     return ret;
0454 }
0455 
0456 static const u32 mantix_bus_formats[] = {
0457     MEDIA_BUS_FMT_RGB888_1X24,
0458 };
0459 
0460 static int st7703_get_modes(struct drm_panel *panel,
0461                 struct drm_connector *connector)
0462 {
0463     struct st7703 *ctx = panel_to_st7703(panel);
0464     struct drm_display_mode *mode;
0465 
0466     mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
0467     if (!mode) {
0468         dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
0469             ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
0470             drm_mode_vrefresh(ctx->desc->mode));
0471         return -ENOMEM;
0472     }
0473 
0474     drm_mode_set_name(mode);
0475 
0476     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0477     connector->display_info.width_mm = mode->width_mm;
0478     connector->display_info.height_mm = mode->height_mm;
0479     drm_mode_probed_add(connector, mode);
0480 
0481     drm_display_info_set_bus_formats(&connector->display_info,
0482                      mantix_bus_formats,
0483                      ARRAY_SIZE(mantix_bus_formats));
0484 
0485     return 1;
0486 }
0487 
0488 static const struct drm_panel_funcs st7703_drm_funcs = {
0489     .disable   = st7703_disable,
0490     .unprepare = st7703_unprepare,
0491     .prepare   = st7703_prepare,
0492     .enable    = st7703_enable,
0493     .get_modes = st7703_get_modes,
0494 };
0495 
0496 static int allpixelson_set(void *data, u64 val)
0497 {
0498     struct st7703 *ctx = data;
0499     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0500 
0501     dev_dbg(ctx->dev, "Setting all pixels on\n");
0502     dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
0503     msleep(val * 1000);
0504     /* Reset the panel to get video back */
0505     drm_panel_disable(&ctx->panel);
0506     drm_panel_unprepare(&ctx->panel);
0507     drm_panel_prepare(&ctx->panel);
0508     drm_panel_enable(&ctx->panel);
0509 
0510     return 0;
0511 }
0512 
0513 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
0514             allpixelson_set, "%llu\n");
0515 
0516 static void st7703_debugfs_init(struct st7703 *ctx)
0517 {
0518     ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
0519 
0520     debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
0521                 &allpixelson_fops);
0522 }
0523 
0524 static void st7703_debugfs_remove(struct st7703 *ctx)
0525 {
0526     debugfs_remove_recursive(ctx->debugfs);
0527     ctx->debugfs = NULL;
0528 }
0529 
0530 static int st7703_probe(struct mipi_dsi_device *dsi)
0531 {
0532     struct device *dev = &dsi->dev;
0533     struct st7703 *ctx;
0534     int ret;
0535 
0536     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0537     if (!ctx)
0538         return -ENOMEM;
0539 
0540     ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
0541     if (IS_ERR(ctx->reset_gpio))
0542         return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
0543 
0544     mipi_dsi_set_drvdata(dsi, ctx);
0545 
0546     ctx->dev = dev;
0547     ctx->desc = of_device_get_match_data(dev);
0548 
0549     dsi->mode_flags = ctx->desc->mode_flags;
0550     dsi->format = ctx->desc->format;
0551     dsi->lanes = ctx->desc->lanes;
0552 
0553     ctx->vcc = devm_regulator_get(dev, "vcc");
0554     if (IS_ERR(ctx->vcc))
0555         return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
0556 
0557     ctx->iovcc = devm_regulator_get(dev, "iovcc");
0558     if (IS_ERR(ctx->iovcc))
0559         return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
0560                      "Failed to request iovcc regulator\n");
0561 
0562     drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
0563                DRM_MODE_CONNECTOR_DSI);
0564 
0565     ret = drm_panel_of_backlight(&ctx->panel);
0566     if (ret)
0567         return ret;
0568 
0569     drm_panel_add(&ctx->panel);
0570 
0571     ret = mipi_dsi_attach(dsi);
0572     if (ret < 0) {
0573         dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
0574         drm_panel_remove(&ctx->panel);
0575         return ret;
0576     }
0577 
0578     dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
0579          ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
0580          drm_mode_vrefresh(ctx->desc->mode),
0581          mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
0582 
0583     st7703_debugfs_init(ctx);
0584     return 0;
0585 }
0586 
0587 static void st7703_shutdown(struct mipi_dsi_device *dsi)
0588 {
0589     struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
0590     int ret;
0591 
0592     ret = drm_panel_unprepare(&ctx->panel);
0593     if (ret < 0)
0594         dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
0595 
0596     ret = drm_panel_disable(&ctx->panel);
0597     if (ret < 0)
0598         dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
0599 }
0600 
0601 static int st7703_remove(struct mipi_dsi_device *dsi)
0602 {
0603     struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
0604     int ret;
0605 
0606     st7703_shutdown(dsi);
0607 
0608     ret = mipi_dsi_detach(dsi);
0609     if (ret < 0)
0610         dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
0611 
0612     drm_panel_remove(&ctx->panel);
0613 
0614     st7703_debugfs_remove(ctx);
0615 
0616     return 0;
0617 }
0618 
0619 static const struct of_device_id st7703_of_match[] = {
0620     { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
0621     { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
0622     { /* sentinel */ }
0623 };
0624 MODULE_DEVICE_TABLE(of, st7703_of_match);
0625 
0626 static struct mipi_dsi_driver st7703_driver = {
0627     .probe  = st7703_probe,
0628     .remove = st7703_remove,
0629     .shutdown = st7703_shutdown,
0630     .driver = {
0631         .name = DRV_NAME,
0632         .of_match_table = st7703_of_match,
0633     },
0634 };
0635 module_mipi_dsi_driver(st7703_driver);
0636 
0637 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
0638 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
0639 MODULE_LICENSE("GPL v2");