1338 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2019, Amarula Solutions.4 * Author: Jagan Teki <jagan@amarulasolutions.com>5 */6 7#include <drm/drm_mipi_dbi.h>8#include <drm/drm_mipi_dsi.h>9#include <drm/drm_modes.h>10#include <drm/drm_panel.h>11 12#include <linux/bitfield.h>13#include <linux/gpio/consumer.h>14#include <linux/delay.h>15#include <linux/module.h>16#include <linux/of.h>17#include <linux/regulator/consumer.h>18#include <linux/spi/spi.h>19 20#include <video/mipi_display.h>21 22/* Command2 BKx selection command */23#define ST7701_CMD2BKX_SEL 0xFF24#define ST7701_CMD1 025#define ST7701_CMD2 BIT(4)26#define ST7701_CMD2BK_MASK GENMASK(3, 0)27 28/* Command2, BK0 commands */29#define ST7701_CMD2_BK0_PVGAMCTRL 0xB0 /* Positive Voltage Gamma Control */30#define ST7701_CMD2_BK0_NVGAMCTRL 0xB1 /* Negative Voltage Gamma Control */31#define ST7701_CMD2_BK0_LNESET 0xC0 /* Display Line setting */32#define ST7701_CMD2_BK0_PORCTRL 0xC1 /* Porch control */33#define ST7701_CMD2_BK0_INVSEL 0xC2 /* Inversion selection, Frame Rate Control */34 35/* Command2, BK1 commands */36#define ST7701_CMD2_BK1_VRHS 0xB0 /* Vop amplitude setting */37#define ST7701_CMD2_BK1_VCOM 0xB1 /* VCOM amplitude setting */38#define ST7701_CMD2_BK1_VGHSS 0xB2 /* VGH Voltage setting */39#define ST7701_CMD2_BK1_TESTCMD 0xB3 /* TEST Command Setting */40#define ST7701_CMD2_BK1_VGLS 0xB5 /* VGL Voltage setting */41#define ST7701_CMD2_BK1_PWCTLR1 0xB7 /* Power Control 1 */42#define ST7701_CMD2_BK1_PWCTLR2 0xB8 /* Power Control 2 */43#define ST7701_CMD2_BK1_SPD1 0xC1 /* Source pre_drive timing set1 */44#define ST7701_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */45#define ST7701_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */46 47/* Command2, BK0 bytes */48#define ST7701_CMD2_BK0_GAMCTRL_AJ_MASK GENMASK(7, 6)49#define ST7701_CMD2_BK0_GAMCTRL_VC0_MASK GENMASK(3, 0)50#define ST7701_CMD2_BK0_GAMCTRL_VC4_MASK GENMASK(5, 0)51#define ST7701_CMD2_BK0_GAMCTRL_VC8_MASK GENMASK(5, 0)52#define ST7701_CMD2_BK0_GAMCTRL_VC16_MASK GENMASK(4, 0)53#define ST7701_CMD2_BK0_GAMCTRL_VC24_MASK GENMASK(4, 0)54#define ST7701_CMD2_BK0_GAMCTRL_VC52_MASK GENMASK(3, 0)55#define ST7701_CMD2_BK0_GAMCTRL_VC80_MASK GENMASK(5, 0)56#define ST7701_CMD2_BK0_GAMCTRL_VC108_MASK GENMASK(3, 0)57#define ST7701_CMD2_BK0_GAMCTRL_VC147_MASK GENMASK(3, 0)58#define ST7701_CMD2_BK0_GAMCTRL_VC175_MASK GENMASK(5, 0)59#define ST7701_CMD2_BK0_GAMCTRL_VC203_MASK GENMASK(3, 0)60#define ST7701_CMD2_BK0_GAMCTRL_VC231_MASK GENMASK(4, 0)61#define ST7701_CMD2_BK0_GAMCTRL_VC239_MASK GENMASK(4, 0)62#define ST7701_CMD2_BK0_GAMCTRL_VC247_MASK GENMASK(5, 0)63#define ST7701_CMD2_BK0_GAMCTRL_VC251_MASK GENMASK(5, 0)64#define ST7701_CMD2_BK0_GAMCTRL_VC255_MASK GENMASK(4, 0)65#define ST7701_CMD2_BK0_LNESET_LINE_MASK GENMASK(6, 0)66#define ST7701_CMD2_BK0_LNESET_LDE_EN BIT(7)67#define ST7701_CMD2_BK0_LNESET_LINEDELTA GENMASK(1, 0)68#define ST7701_CMD2_BK0_PORCTRL_VBP_MASK GENMASK(7, 0)69#define ST7701_CMD2_BK0_PORCTRL_VFP_MASK GENMASK(7, 0)70#define ST7701_CMD2_BK0_INVSEL_ONES_MASK GENMASK(5, 4)71#define ST7701_CMD2_BK0_INVSEL_NLINV_MASK GENMASK(2, 0)72#define ST7701_CMD2_BK0_INVSEL_RTNI_MASK GENMASK(4, 0)73 74/* Command2, BK1 bytes */75#define ST7701_CMD2_BK1_VRHA_MASK GENMASK(7, 0)76#define ST7701_CMD2_BK1_VCOM_MASK GENMASK(7, 0)77#define ST7701_CMD2_BK1_VGHSS_MASK GENMASK(3, 0)78#define ST7701_CMD2_BK1_TESTCMD_VAL BIT(7)79#define ST7701_CMD2_BK1_VGLS_ONES BIT(6)80#define ST7701_CMD2_BK1_VGLS_MASK GENMASK(3, 0)81#define ST7701_CMD2_BK1_PWRCTRL1_AP_MASK GENMASK(7, 6)82#define ST7701_CMD2_BK1_PWRCTRL1_APIS_MASK GENMASK(3, 2)83#define ST7701_CMD2_BK1_PWRCTRL1_APOS_MASK GENMASK(1, 0)84#define ST7701_CMD2_BK1_PWRCTRL2_AVDD_MASK GENMASK(5, 4)85#define ST7701_CMD2_BK1_PWRCTRL2_AVCL_MASK GENMASK(1, 0)86#define ST7701_CMD2_BK1_SPD1_ONES_MASK GENMASK(6, 4)87#define ST7701_CMD2_BK1_SPD1_T2D_MASK GENMASK(3, 0)88#define ST7701_CMD2_BK1_SPD2_ONES_MASK GENMASK(6, 4)89#define ST7701_CMD2_BK1_SPD2_T3D_MASK GENMASK(3, 0)90#define ST7701_CMD2_BK1_MIPISET1_ONES BIT(7)91#define ST7701_CMD2_BK1_MIPISET1_EOT_EN BIT(3)92 93#define CFIELD_PREP(_mask, _val) \94 (((typeof(_mask))(_val) << (__builtin_ffsll(_mask) - 1)) & (_mask))95 96enum op_bias {97 OP_BIAS_OFF = 0,98 OP_BIAS_MIN,99 OP_BIAS_MIDDLE,100 OP_BIAS_MAX101};102 103struct st7701;104 105struct st7701_panel_desc {106 const struct drm_display_mode *mode;107 unsigned int lanes;108 enum mipi_dsi_pixel_format format;109 unsigned int panel_sleep_delay;110 111 /* TFT matrix driver configuration, panel specific. */112 const u8 pv_gamma[16]; /* Positive voltage gamma control */113 const u8 nv_gamma[16]; /* Negative voltage gamma control */114 const u8 nlinv; /* Inversion selection */115 const u32 vop_uv; /* Vop in uV */116 const u32 vcom_uv; /* Vcom in uV */117 const u16 vgh_mv; /* Vgh in mV */118 const s16 vgl_mv; /* Vgl in mV */119 const u16 avdd_mv; /* Avdd in mV */120 const s16 avcl_mv; /* Avcl in mV */121 const enum op_bias gamma_op_bias;122 const enum op_bias input_op_bias;123 const enum op_bias output_op_bias;124 const u16 t2d_ns; /* T2D in ns */125 const u16 t3d_ns; /* T3D in ns */126 const bool eot_en;127 128 /* GIP sequence, fully custom and undocumented. */129 void (*gip_sequence)(struct st7701 *st7701);130};131 132struct st7701 {133 struct drm_panel panel;134 struct mipi_dsi_device *dsi;135 struct mipi_dbi dbi;136 const struct st7701_panel_desc *desc;137 138 struct regulator_bulk_data supplies[2];139 struct gpio_desc *reset;140 unsigned int sleep_delay;141 enum drm_panel_orientation orientation;142 143 int (*write_command)(struct st7701 *st7701, u8 cmd, const u8 *seq,144 size_t len);145};146 147static inline struct st7701 *panel_to_st7701(struct drm_panel *panel)148{149 return container_of(panel, struct st7701, panel);150}151 152static int st7701_dsi_write(struct st7701 *st7701, u8 cmd, const u8 *seq,153 size_t len)154{155 return mipi_dsi_dcs_write(st7701->dsi, cmd, seq, len);156}157 158static int st7701_dbi_write(struct st7701 *st7701, u8 cmd, const u8 *seq,159 size_t len)160{161 return mipi_dbi_command_stackbuf(&st7701->dbi, cmd, seq, len);162}163 164#define ST7701_WRITE(st7701, cmd, seq...) \165 { \166 const u8 d[] = { seq }; \167 st7701->write_command(st7701, cmd, d, ARRAY_SIZE(d)); \168 }169 170static u8 st7701_vgls_map(struct st7701 *st7701)171{172 const struct st7701_panel_desc *desc = st7701->desc;173 struct {174 s32 vgl;175 u8 val;176 } map[16] = {177 { -7060, 0x0 }, { -7470, 0x1 },178 { -7910, 0x2 }, { -8140, 0x3 },179 { -8650, 0x4 }, { -8920, 0x5 },180 { -9210, 0x6 }, { -9510, 0x7 },181 { -9830, 0x8 }, { -10170, 0x9 },182 { -10530, 0xa }, { -10910, 0xb },183 { -11310, 0xc }, { -11730, 0xd },184 { -12200, 0xe }, { -12690, 0xf }185 };186 int i;187 188 for (i = 0; i < ARRAY_SIZE(map); i++)189 if (desc->vgl_mv == map[i].vgl)190 return map[i].val;191 192 return 0;193}194 195static void st7701_switch_cmd_bkx(struct st7701 *st7701, bool cmd2, u8 bkx)196{197 u8 val;198 199 if (cmd2)200 val = ST7701_CMD2 | FIELD_PREP(ST7701_CMD2BK_MASK, bkx);201 else202 val = ST7701_CMD1;203 204 ST7701_WRITE(st7701, ST7701_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, val);205}206 207static void st7701_init_sequence(struct st7701 *st7701)208{209 const struct st7701_panel_desc *desc = st7701->desc;210 const struct drm_display_mode *mode = desc->mode;211 const u8 linecount8 = mode->vdisplay / 8;212 const u8 linecountrem2 = (mode->vdisplay % 8) / 2;213 214 ST7701_WRITE(st7701, MIPI_DCS_SOFT_RESET, 0x00);215 216 /* We need to wait 5ms before sending new commands */217 msleep(5);218 219 ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE, 0x00);220 221 msleep(st7701->sleep_delay);222 223 /* Command2, BK0 */224 st7701_switch_cmd_bkx(st7701, true, 0);225 226 st7701->write_command(st7701, ST7701_CMD2_BK0_PVGAMCTRL, desc->pv_gamma,227 ARRAY_SIZE(desc->pv_gamma));228 st7701->write_command(st7701, ST7701_CMD2_BK0_NVGAMCTRL, desc->nv_gamma,229 ARRAY_SIZE(desc->nv_gamma));230 /*231 * Vertical line count configuration:232 * Line[6:0]: select number of vertical lines of the TFT matrix in233 * multiples of 8 lines234 * LDE_EN: enable sub-8-line granularity line count235 * Line_delta[1:0]: add 0/2/4/6 extra lines to line count selected236 * using Line[6:0]237 *238 * Total number of vertical lines:239 * LN = ((Line[6:0] + 1) * 8) + (LDE_EN ? Line_delta[1:0] * 2 : 0)240 */241 ST7701_WRITE(st7701, ST7701_CMD2_BK0_LNESET,242 FIELD_PREP(ST7701_CMD2_BK0_LNESET_LINE_MASK, linecount8 - 1) |243 (linecountrem2 ? ST7701_CMD2_BK0_LNESET_LDE_EN : 0),244 FIELD_PREP(ST7701_CMD2_BK0_LNESET_LINEDELTA, linecountrem2));245 ST7701_WRITE(st7701, ST7701_CMD2_BK0_PORCTRL,246 FIELD_PREP(ST7701_CMD2_BK0_PORCTRL_VBP_MASK,247 mode->vtotal - mode->vsync_end),248 FIELD_PREP(ST7701_CMD2_BK0_PORCTRL_VFP_MASK,249 mode->vsync_start - mode->vdisplay));250 /*251 * Horizontal pixel count configuration:252 * PCLK = 512 + (RTNI[4:0] * 16)253 * The PCLK is number of pixel clock per line, which matches254 * mode htotal. The minimum is 512 PCLK.255 */256 ST7701_WRITE(st7701, ST7701_CMD2_BK0_INVSEL,257 ST7701_CMD2_BK0_INVSEL_ONES_MASK |258 FIELD_PREP(ST7701_CMD2_BK0_INVSEL_NLINV_MASK, desc->nlinv),259 FIELD_PREP(ST7701_CMD2_BK0_INVSEL_RTNI_MASK,260 (clamp((u32)mode->htotal, 512U, 1008U) - 512) / 16));261 262 /* Command2, BK1 */263 st7701_switch_cmd_bkx(st7701, true, 1);264 265 /* Vop = 3.5375V + (VRHA[7:0] * 0.0125V) */266 ST7701_WRITE(st7701, ST7701_CMD2_BK1_VRHS,267 FIELD_PREP(ST7701_CMD2_BK1_VRHA_MASK,268 DIV_ROUND_CLOSEST(desc->vop_uv - 3537500, 12500)));269 270 /* Vcom = 0.1V + (VCOM[7:0] * 0.0125V) */271 ST7701_WRITE(st7701, ST7701_CMD2_BK1_VCOM,272 FIELD_PREP(ST7701_CMD2_BK1_VCOM_MASK,273 DIV_ROUND_CLOSEST(desc->vcom_uv - 100000, 12500)));274 275 /* Vgh = 11.5V + (VGHSS[7:0] * 0.5V) */276 ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGHSS,277 FIELD_PREP(ST7701_CMD2_BK1_VGHSS_MASK,278 DIV_ROUND_CLOSEST(clamp(desc->vgh_mv,279 (u16)11500,280 (u16)17000) - 11500,281 500)));282 283 ST7701_WRITE(st7701, ST7701_CMD2_BK1_TESTCMD, ST7701_CMD2_BK1_TESTCMD_VAL);284 285 /* Vgl is non-linear */286 ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGLS,287 ST7701_CMD2_BK1_VGLS_ONES |288 FIELD_PREP(ST7701_CMD2_BK1_VGLS_MASK, st7701_vgls_map(st7701)));289 290 ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR1,291 FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL1_AP_MASK,292 desc->gamma_op_bias) |293 FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL1_APIS_MASK,294 desc->input_op_bias) |295 FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL1_APOS_MASK,296 desc->output_op_bias));297 298 /* Avdd = 6.2V + (AVDD[1:0] * 0.2V) , Avcl = -4.4V - (AVCL[1:0] * 0.2V) */299 ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR2,300 FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL2_AVDD_MASK,301 DIV_ROUND_CLOSEST(desc->avdd_mv - 6200, 200)) |302 FIELD_PREP(ST7701_CMD2_BK1_PWRCTRL2_AVCL_MASK,303 DIV_ROUND_CLOSEST(-4400 - desc->avcl_mv, 200)));304 305 /* T2D = 0.2us * T2D[3:0] */306 ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD1,307 ST7701_CMD2_BK1_SPD1_ONES_MASK |308 FIELD_PREP(ST7701_CMD2_BK1_SPD1_T2D_MASK,309 DIV_ROUND_CLOSEST(desc->t2d_ns, 200)));310 311 /* T3D = 4us + (0.8us * T3D[3:0]) */312 ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD2,313 ST7701_CMD2_BK1_SPD2_ONES_MASK |314 FIELD_PREP(ST7701_CMD2_BK1_SPD2_T3D_MASK,315 DIV_ROUND_CLOSEST(desc->t3d_ns - 4000, 800)));316 317 ST7701_WRITE(st7701, ST7701_CMD2_BK1_MIPISET1,318 ST7701_CMD2_BK1_MIPISET1_ONES |319 (desc->eot_en ? ST7701_CMD2_BK1_MIPISET1_EOT_EN : 0));320}321 322static void ts8550b_gip_sequence(struct st7701 *st7701)323{324 /**325 * ST7701_SPEC_V1.2 is unable to provide enough information above this326 * specific command sequence, so grab the same from vendor BSP driver.327 */328 ST7701_WRITE(st7701, 0xE0, 0x00, 0x00, 0x02);329 ST7701_WRITE(st7701, 0xE1, 0x0B, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x0E,330 0x00, 0x00, 0x44, 0x44);331 ST7701_WRITE(st7701, 0xE2, 0x33, 0x33, 0x44, 0x44, 0x64, 0x00, 0x66,332 0x00, 0x65, 0x00, 0x67, 0x00, 0x00);333 ST7701_WRITE(st7701, 0xE3, 0x00, 0x00, 0x33, 0x33);334 ST7701_WRITE(st7701, 0xE4, 0x44, 0x44);335 ST7701_WRITE(st7701, 0xE5, 0x0C, 0x78, 0x3C, 0xA0, 0x0E, 0x78, 0x3C,336 0xA0, 0x10, 0x78, 0x3C, 0xA0, 0x12, 0x78, 0x3C, 0xA0);337 ST7701_WRITE(st7701, 0xE6, 0x00, 0x00, 0x33, 0x33);338 ST7701_WRITE(st7701, 0xE7, 0x44, 0x44);339 ST7701_WRITE(st7701, 0xE8, 0x0D, 0x78, 0x3C, 0xA0, 0x0F, 0x78, 0x3C,340 0xA0, 0x11, 0x78, 0x3C, 0xA0, 0x13, 0x78, 0x3C, 0xA0);341 ST7701_WRITE(st7701, 0xEB, 0x02, 0x02, 0x39, 0x39, 0xEE, 0x44, 0x00);342 ST7701_WRITE(st7701, 0xEC, 0x00, 0x00);343 ST7701_WRITE(st7701, 0xED, 0xFF, 0xF1, 0x04, 0x56, 0x72, 0x3F, 0xFF,344 0xFF, 0xFF, 0xFF, 0xF3, 0x27, 0x65, 0x40, 0x1F, 0xFF);345}346 347static void dmt028vghmcmi_1a_gip_sequence(struct st7701 *st7701)348{349 ST7701_WRITE(st7701, 0xEE, 0x42);350 ST7701_WRITE(st7701, 0xE0, 0x00, 0x00, 0x02);351 352 ST7701_WRITE(st7701, 0xE1,353 0x04, 0xA0, 0x06, 0xA0,354 0x05, 0xA0, 0x07, 0xA0,355 0x00, 0x44, 0x44);356 ST7701_WRITE(st7701, 0xE2,357 0x00, 0x00, 0x00, 0x00,358 0x00, 0x00, 0x00, 0x00,359 0x00, 0x00, 0x00, 0x00);360 ST7701_WRITE(st7701, 0xE3,361 0x00, 0x00, 0x22, 0x22);362 ST7701_WRITE(st7701, 0xE4, 0x44, 0x44);363 ST7701_WRITE(st7701, 0xE5,364 0x0C, 0x90, 0xA0, 0xA0,365 0x0E, 0x92, 0xA0, 0xA0,366 0x08, 0x8C, 0xA0, 0xA0,367 0x0A, 0x8E, 0xA0, 0xA0);368 ST7701_WRITE(st7701, 0xE6,369 0x00, 0x00, 0x22, 0x22);370 ST7701_WRITE(st7701, 0xE7, 0x44, 0x44);371 ST7701_WRITE(st7701, 0xE8,372 0x0D, 0x91, 0xA0, 0xA0,373 0x0F, 0x93, 0xA0, 0xA0,374 0x09, 0x8D, 0xA0, 0xA0,375 0x0B, 0x8F, 0xA0, 0xA0);376 ST7701_WRITE(st7701, 0xEB,377 0x00, 0x00, 0xE4, 0xE4,378 0x44, 0x00, 0x00);379 ST7701_WRITE(st7701, 0xED,380 0xFF, 0xF5, 0x47, 0x6F,381 0x0B, 0xA1, 0xAB, 0xFF,382 0xFF, 0xBA, 0x1A, 0xB0,383 0xF6, 0x74, 0x5F, 0xFF);384 ST7701_WRITE(st7701, 0xEF,385 0x08, 0x08, 0x08, 0x40,386 0x3F, 0x64);387 388 st7701_switch_cmd_bkx(st7701, false, 0);389 390 st7701_switch_cmd_bkx(st7701, true, 3);391 ST7701_WRITE(st7701, 0xE6, 0x7C);392 ST7701_WRITE(st7701, 0xE8, 0x00, 0x0E);393 394 st7701_switch_cmd_bkx(st7701, false, 0);395 ST7701_WRITE(st7701, 0x11);396 msleep(120);397 398 st7701_switch_cmd_bkx(st7701, true, 3);399 ST7701_WRITE(st7701, 0xE8, 0x00, 0x0C);400 msleep(10);401 ST7701_WRITE(st7701, 0xE8, 0x00, 0x00);402 403 st7701_switch_cmd_bkx(st7701, false, 0);404 ST7701_WRITE(st7701, 0x11);405 msleep(120);406 ST7701_WRITE(st7701, 0xE8, 0x00, 0x00);407 408 st7701_switch_cmd_bkx(st7701, false, 0);409 410 ST7701_WRITE(st7701, 0x3A, 0x70);411}412 413static void kd50t048a_gip_sequence(struct st7701 *st7701)414{415 /**416 * ST7701_SPEC_V1.2 is unable to provide enough information above this417 * specific command sequence, so grab the same from vendor BSP driver.418 */419 ST7701_WRITE(st7701, 0xE0, 0x00, 0x00, 0x02);420 ST7701_WRITE(st7701, 0xE1, 0x08, 0x00, 0x0A, 0x00, 0x07, 0x00, 0x09,421 0x00, 0x00, 0x33, 0x33);422 ST7701_WRITE(st7701, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);424 ST7701_WRITE(st7701, 0xE3, 0x00, 0x00, 0x33, 0x33);425 ST7701_WRITE(st7701, 0xE4, 0x44, 0x44);426 ST7701_WRITE(st7701, 0xE5, 0x0E, 0x60, 0xA0, 0xA0, 0x10, 0x60, 0xA0,427 0xA0, 0x0A, 0x60, 0xA0, 0xA0, 0x0C, 0x60, 0xA0, 0xA0);428 ST7701_WRITE(st7701, 0xE6, 0x00, 0x00, 0x33, 0x33);429 ST7701_WRITE(st7701, 0xE7, 0x44, 0x44);430 ST7701_WRITE(st7701, 0xE8, 0x0D, 0x60, 0xA0, 0xA0, 0x0F, 0x60, 0xA0,431 0xA0, 0x09, 0x60, 0xA0, 0xA0, 0x0B, 0x60, 0xA0, 0xA0);432 ST7701_WRITE(st7701, 0xEB, 0x02, 0x01, 0xE4, 0xE4, 0x44, 0x00, 0x40);433 ST7701_WRITE(st7701, 0xEC, 0x02, 0x01);434 ST7701_WRITE(st7701, 0xED, 0xAB, 0x89, 0x76, 0x54, 0x01, 0xFF, 0xFF,435 0xFF, 0xFF, 0xFF, 0xFF, 0x10, 0x45, 0x67, 0x98, 0xBA);436}437 438static void rg_arc_gip_sequence(struct st7701 *st7701)439{440 st7701_switch_cmd_bkx(st7701, true, 3);441 ST7701_WRITE(st7701, 0xEF, 0x08);442 st7701_switch_cmd_bkx(st7701, true, 0);443 ST7701_WRITE(st7701, 0xC7, 0x04);444 ST7701_WRITE(st7701, 0xCC, 0x38);445 st7701_switch_cmd_bkx(st7701, true, 1);446 ST7701_WRITE(st7701, 0xB9, 0x10);447 ST7701_WRITE(st7701, 0xBC, 0x03);448 ST7701_WRITE(st7701, 0xC0, 0x89);449 ST7701_WRITE(st7701, 0xE0, 0x00, 0x00, 0x02);450 ST7701_WRITE(st7701, 0xE1, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,451 0x00, 0x00, 0x20, 0x20);452 ST7701_WRITE(st7701, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);454 ST7701_WRITE(st7701, 0xE3, 0x00, 0x00, 0x33, 0x00);455 ST7701_WRITE(st7701, 0xE4, 0x22, 0x00);456 ST7701_WRITE(st7701, 0xE5, 0x04, 0x5C, 0xA0, 0xA0, 0x06, 0x5C, 0xA0,457 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);458 ST7701_WRITE(st7701, 0xE6, 0x00, 0x00, 0x33, 0x00);459 ST7701_WRITE(st7701, 0xE7, 0x22, 0x00);460 ST7701_WRITE(st7701, 0xE8, 0x05, 0x5C, 0xA0, 0xA0, 0x07, 0x5C, 0xA0,461 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);462 ST7701_WRITE(st7701, 0xEB, 0x02, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00);463 ST7701_WRITE(st7701, 0xEC, 0x00, 0x00);464 ST7701_WRITE(st7701, 0xED, 0xFA, 0x45, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF,465 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB0, 0x54, 0xAF);466 ST7701_WRITE(st7701, 0xEF, 0x08, 0x08, 0x08, 0x45, 0x3F, 0x54);467 st7701_switch_cmd_bkx(st7701, false, 0);468 ST7701_WRITE(st7701, MIPI_DCS_SET_ADDRESS_MODE, 0x17);469 ST7701_WRITE(st7701, MIPI_DCS_SET_PIXEL_FORMAT, 0x77);470 ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE, 0x00);471 msleep(120);472}473 474static void rg28xx_gip_sequence(struct st7701 *st7701)475{476 st7701_switch_cmd_bkx(st7701, true, 3);477 ST7701_WRITE(st7701, 0xEF, 0x08);478 479 st7701_switch_cmd_bkx(st7701, true, 0);480 ST7701_WRITE(st7701, 0xC3, 0x02, 0x10, 0x02);481 ST7701_WRITE(st7701, 0xC7, 0x04);482 ST7701_WRITE(st7701, 0xCC, 0x10);483 484 st7701_switch_cmd_bkx(st7701, true, 1);485 ST7701_WRITE(st7701, 0xEE, 0x42);486 ST7701_WRITE(st7701, 0xE0, 0x00, 0x00, 0x02);487 488 ST7701_WRITE(st7701, 0xE1, 0x04, 0xA0, 0x06, 0xA0, 0x05, 0xA0, 0x07, 0xA0,489 0x00, 0x44, 0x44);490 ST7701_WRITE(st7701, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,491 0x00, 0x00, 0x00, 0x00);492 ST7701_WRITE(st7701, 0xE3, 0x00, 0x00, 0x22, 0x22);493 ST7701_WRITE(st7701, 0xE4, 0x44, 0x44);494 ST7701_WRITE(st7701, 0xE5, 0x0C, 0x90, 0xA0, 0xA0, 0x0E, 0x92, 0xA0, 0xA0,495 0x08, 0x8C, 0xA0, 0xA0, 0x0A, 0x8E, 0xA0, 0xA0);496 ST7701_WRITE(st7701, 0xE6, 0x00, 0x00, 0x22, 0x22);497 ST7701_WRITE(st7701, 0xE7, 0x44, 0x44);498 ST7701_WRITE(st7701, 0xE8, 0x0D, 0x91, 0xA0, 0xA0, 0x0F, 0x93, 0xA0, 0xA0,499 0x09, 0x8D, 0xA0, 0xA0, 0x0B, 0x8F, 0xA0, 0xA0);500 ST7701_WRITE(st7701, 0xEB, 0x00, 0x00, 0xE4, 0xE4, 0x44, 0x00, 0x40);501 ST7701_WRITE(st7701, 0xED, 0xFF, 0xF5, 0x47, 0x6F, 0x0B, 0xA1, 0xBA, 0xFF,502 0xFF, 0xAB, 0x1A, 0xB0, 0xF6, 0x74, 0x5F, 0xFF);503 ST7701_WRITE(st7701, 0xEF, 0x08, 0x08, 0x08, 0x45, 0x3F, 0x54);504 505 st7701_switch_cmd_bkx(st7701, false, 0);506 507 st7701_switch_cmd_bkx(st7701, true, 3);508 ST7701_WRITE(st7701, 0xE6, 0x16);509 ST7701_WRITE(st7701, 0xE8, 0x00, 0x0E);510 511 st7701_switch_cmd_bkx(st7701, false, 0);512 ST7701_WRITE(st7701, MIPI_DCS_SET_ADDRESS_MODE, 0x10);513 ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE);514 msleep(120);515 516 st7701_switch_cmd_bkx(st7701, true, 3);517 ST7701_WRITE(st7701, 0xE8, 0x00, 0x0C);518 msleep(10);519 ST7701_WRITE(st7701, 0xE8, 0x00, 0x00);520 st7701_switch_cmd_bkx(st7701, false, 0);521}522 523static int st7701_prepare(struct drm_panel *panel)524{525 struct st7701 *st7701 = panel_to_st7701(panel);526 int ret;527 528 gpiod_set_value(st7701->reset, 0);529 530 ret = regulator_bulk_enable(ARRAY_SIZE(st7701->supplies),531 st7701->supplies);532 if (ret < 0)533 return ret;534 msleep(20);535 536 gpiod_set_value(st7701->reset, 1);537 msleep(150);538 539 st7701_init_sequence(st7701);540 541 if (st7701->desc->gip_sequence)542 st7701->desc->gip_sequence(st7701);543 544 /* Disable Command2 */545 st7701_switch_cmd_bkx(st7701, false, 0);546 547 return 0;548}549 550static int st7701_enable(struct drm_panel *panel)551{552 struct st7701 *st7701 = panel_to_st7701(panel);553 554 ST7701_WRITE(st7701, MIPI_DCS_SET_DISPLAY_ON, 0x00);555 556 return 0;557}558 559static int st7701_disable(struct drm_panel *panel)560{561 struct st7701 *st7701 = panel_to_st7701(panel);562 563 ST7701_WRITE(st7701, MIPI_DCS_SET_DISPLAY_OFF, 0x00);564 565 return 0;566}567 568static int st7701_unprepare(struct drm_panel *panel)569{570 struct st7701 *st7701 = panel_to_st7701(panel);571 572 ST7701_WRITE(st7701, MIPI_DCS_ENTER_SLEEP_MODE, 0x00);573 574 msleep(st7701->sleep_delay);575 576 gpiod_set_value(st7701->reset, 0);577 578 /**579 * During the Resetting period, the display will be blanked580 * (The display is entering blanking sequence, which maximum581 * time is 120 ms, when Reset Starts in Sleep Out –mode. The582 * display remains the blank state in Sleep In –mode.) and583 * then return to Default condition for Hardware Reset.584 *585 * So we need wait sleep_delay time to make sure reset completed.586 */587 msleep(st7701->sleep_delay);588 589 regulator_bulk_disable(ARRAY_SIZE(st7701->supplies), st7701->supplies);590 591 return 0;592}593 594static int st7701_get_modes(struct drm_panel *panel,595 struct drm_connector *connector)596{597 struct st7701 *st7701 = panel_to_st7701(panel);598 const struct drm_display_mode *desc_mode = st7701->desc->mode;599 struct drm_display_mode *mode;600 601 mode = drm_mode_duplicate(connector->dev, desc_mode);602 if (!mode) {603 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",604 desc_mode->hdisplay, desc_mode->vdisplay,605 drm_mode_vrefresh(desc_mode));606 return -ENOMEM;607 }608 609 drm_mode_set_name(mode);610 drm_mode_probed_add(connector, mode);611 612 connector->display_info.width_mm = desc_mode->width_mm;613 connector->display_info.height_mm = desc_mode->height_mm;614 615 /*616 * TODO: Remove once all drm drivers call617 * drm_connector_set_orientation_from_panel()618 */619 drm_connector_set_panel_orientation(connector, st7701->orientation);620 621 return 1;622}623 624static enum drm_panel_orientation st7701_get_orientation(struct drm_panel *panel)625{626 struct st7701 *st7701 = panel_to_st7701(panel);627 628 return st7701->orientation;629}630 631static const struct drm_panel_funcs st7701_funcs = {632 .disable = st7701_disable,633 .unprepare = st7701_unprepare,634 .prepare = st7701_prepare,635 .enable = st7701_enable,636 .get_modes = st7701_get_modes,637 .get_orientation = st7701_get_orientation,638};639 640static const struct drm_display_mode ts8550b_mode = {641 .clock = 27500,642 643 .hdisplay = 480,644 .hsync_start = 480 + 38,645 .hsync_end = 480 + 38 + 12,646 .htotal = 480 + 38 + 12 + 12,647 648 .vdisplay = 854,649 .vsync_start = 854 + 18,650 .vsync_end = 854 + 18 + 8,651 .vtotal = 854 + 18 + 8 + 4,652 653 .width_mm = 69,654 .height_mm = 139,655 656 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,657};658 659static const struct st7701_panel_desc ts8550b_desc = {660 .mode = &ts8550b_mode,661 .lanes = 2,662 .format = MIPI_DSI_FMT_RGB888,663 .panel_sleep_delay = 80, /* panel need extra 80ms for sleep out cmd */664 665 .pv_gamma = {666 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |667 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),668 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |669 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0xe),670 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |671 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x15),672 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xf),673 674 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |675 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),676 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x8),677 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8),678 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),679 680 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8),681 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x23),682 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),683 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |684 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x13),685 686 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x12),687 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |688 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2b),689 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |690 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x34),691 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |692 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)693 },694 .nv_gamma = {695 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |696 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),697 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |698 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0xe),699 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x2) |700 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x15),701 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xf),702 703 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |704 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x13),705 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x7),706 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x9),707 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),708 709 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8),710 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x22),711 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),712 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |713 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x10),714 715 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),716 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |717 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c),718 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |719 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x34),720 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |721 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)722 },723 .nlinv = 7,724 .vop_uv = 4400000,725 .vcom_uv = 337500,726 .vgh_mv = 15000,727 .vgl_mv = -9510,728 .avdd_mv = 6600,729 .avcl_mv = -4400,730 .gamma_op_bias = OP_BIAS_MAX,731 .input_op_bias = OP_BIAS_MIN,732 .output_op_bias = OP_BIAS_MIN,733 .t2d_ns = 1600,734 .t3d_ns = 10400,735 .eot_en = true,736 .gip_sequence = ts8550b_gip_sequence,737};738 739static const struct drm_display_mode dmt028vghmcmi_1a_mode = {740 .clock = 22325,741 742 .hdisplay = 480,743 .hsync_start = 480 + 40,744 .hsync_end = 480 + 40 + 4,745 .htotal = 480 + 40 + 4 + 20,746 747 .vdisplay = 640,748 .vsync_start = 640 + 2,749 .vsync_end = 640 + 2 + 40,750 .vtotal = 640 + 2 + 40 + 16,751 752 .width_mm = 56,753 .height_mm = 78,754 755 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,756 757 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,758};759 760static const struct st7701_panel_desc dmt028vghmcmi_1a_desc = {761 .mode = &dmt028vghmcmi_1a_mode,762 .lanes = 2,763 .format = MIPI_DSI_FMT_RGB888,764 .panel_sleep_delay = 5, /* panel need extra 5ms for sleep out cmd */765 766 .pv_gamma = {767 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |768 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),769 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |770 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x10),771 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |772 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x17),773 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),774 775 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |776 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),777 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6),778 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x5),779 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),780 781 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),782 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x1f),783 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),784 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |785 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),786 787 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),788 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |789 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x29),790 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |791 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x30),792 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |793 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)794 },795 .nv_gamma = {796 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |797 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),798 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |799 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0xd),800 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |801 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x14),802 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xe),803 804 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |805 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),806 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6),807 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x4),808 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),809 810 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8),811 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x20),812 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x5),813 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |814 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x13),815 816 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x13),817 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |818 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x26),819 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |820 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x30),821 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |822 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)823 },824 .nlinv = 1,825 .vop_uv = 4800000,826 .vcom_uv = 1650000,827 .vgh_mv = 15000,828 .vgl_mv = -10170,829 .avdd_mv = 6600,830 .avcl_mv = -4400,831 .gamma_op_bias = OP_BIAS_MIDDLE,832 .input_op_bias = OP_BIAS_MIN,833 .output_op_bias = OP_BIAS_MIN,834 .t2d_ns = 1600,835 .t3d_ns = 10400,836 .eot_en = true,837 .gip_sequence = dmt028vghmcmi_1a_gip_sequence,838};839 840static const struct drm_display_mode kd50t048a_mode = {841 .clock = 27500,842 843 .hdisplay = 480,844 .hsync_start = 480 + 2,845 .hsync_end = 480 + 2 + 10,846 .htotal = 480 + 2 + 10 + 2,847 848 .vdisplay = 854,849 .vsync_start = 854 + 2,850 .vsync_end = 854 + 2 + 2,851 .vtotal = 854 + 2 + 2 + 17,852 853 .width_mm = 69,854 .height_mm = 139,855 856 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,857};858 859static const struct st7701_panel_desc kd50t048a_desc = {860 .mode = &kd50t048a_mode,861 .lanes = 2,862 .format = MIPI_DSI_FMT_RGB888,863 .panel_sleep_delay = 0,864 865 .pv_gamma = {866 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |867 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),868 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |869 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0xd),870 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |871 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x14),872 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),873 874 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |875 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10),876 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),877 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x2),878 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),879 880 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8),881 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x1e),882 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x5),883 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |884 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x13),885 886 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x11),887 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 2) |888 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x23),889 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |890 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x29),891 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |892 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x18)893 },894 .nv_gamma = {895 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |896 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),897 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |898 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0xc),899 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |900 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x14),901 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xc),902 903 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |904 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10),905 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5),906 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x3),907 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),908 909 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),910 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x20),911 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x5),912 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |913 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x13),914 915 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x11),916 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 2) |917 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x24),918 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |919 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x29),920 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |921 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x18)922 },923 .nlinv = 1,924 .vop_uv = 4887500,925 .vcom_uv = 937500,926 .vgh_mv = 15000,927 .vgl_mv = -9510,928 .avdd_mv = 6600,929 .avcl_mv = -4400,930 .gamma_op_bias = OP_BIAS_MIDDLE,931 .input_op_bias = OP_BIAS_MIN,932 .output_op_bias = OP_BIAS_MIN,933 .t2d_ns = 1600,934 .t3d_ns = 10400,935 .eot_en = true,936 .gip_sequence = kd50t048a_gip_sequence,937};938 939static const struct drm_display_mode rg_arc_mode = {940 .clock = 25600,941 942 .hdisplay = 480,943 .hsync_start = 480 + 60,944 .hsync_end = 480 + 60 + 42,945 .htotal = 480 + 60 + 42 + 60,946 947 .vdisplay = 640,948 .vsync_start = 640 + 10,949 .vsync_end = 640 + 10 + 4,950 .vtotal = 640 + 10 + 4 + 16,951 952 .width_mm = 63,953 .height_mm = 84,954 955 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,956};957 958static const struct st7701_panel_desc rg_arc_desc = {959 .mode = &rg_arc_mode,960 .lanes = 2,961 .format = MIPI_DSI_FMT_RGB888,962 .panel_sleep_delay = 80,963 964 .pv_gamma = {965 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x01) |966 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),967 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |968 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x16),969 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |970 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1d),971 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0x0e),972 973 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |974 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x12),975 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x06),976 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x0c),977 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x0a),978 979 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x09),980 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x25),981 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x00),982 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |983 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x03),984 985 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x00),986 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |987 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x3f),988 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |989 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x3f),990 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |991 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1c)992 },993 .nv_gamma = {994 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x01) |995 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),996 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |997 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x16),998 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |999 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1e),1000 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0x0e),1001 1002 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1003 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),1004 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x06),1005 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x0c),1006 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x08),1007 1008 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x09),1009 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x26),1010 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x00),1011 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1012 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x15),1013 1014 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x00),1015 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1016 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x3f),1017 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1018 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x3f),1019 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1020 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1c)1021 },1022 .nlinv = 0,1023 .vop_uv = 4500000,1024 .vcom_uv = 762500,1025 .vgh_mv = 15000,1026 .vgl_mv = -9510,1027 .avdd_mv = 6600,1028 .avcl_mv = -4400,1029 .gamma_op_bias = OP_BIAS_MIDDLE,1030 .input_op_bias = OP_BIAS_MIN,1031 .output_op_bias = OP_BIAS_MIN,1032 .t2d_ns = 1600,1033 .t3d_ns = 10400,1034 .eot_en = true,1035 .gip_sequence = rg_arc_gip_sequence,1036};1037 1038static const struct drm_display_mode rg28xx_mode = {1039 .clock = 22325,1040 1041 .hdisplay = 480,1042 .hsync_start = 480 + 40,1043 .hsync_end = 480 + 40 + 4,1044 .htotal = 480 + 40 + 4 + 20,1045 1046 .vdisplay = 640,1047 .vsync_start = 640 + 2,1048 .vsync_end = 640 + 2 + 40,1049 .vtotal = 640 + 2 + 40 + 16,1050 1051 .width_mm = 44,1052 .height_mm = 58,1053 1054 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,1055 1056 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,1057};1058 1059static const struct st7701_panel_desc rg28xx_desc = {1060 .mode = &rg28xx_mode,1061 1062 .panel_sleep_delay = 80,1063 1064 .pv_gamma = {1065 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1066 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),1067 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1068 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x10),1069 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1070 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x17),1071 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd),1072 1073 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1074 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),1075 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6),1076 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x5),1077 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),1078 1079 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7),1080 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x1f),1081 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4),1082 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1083 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11),1084 1085 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe),1086 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1087 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x29),1088 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1089 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x30),1090 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1091 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)1092 },1093 .nv_gamma = {1094 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1095 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0),1096 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1097 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0xd),1098 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1099 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x14),1100 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xe),1101 1102 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1103 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11),1104 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6),1105 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x4),1106 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8),1107 1108 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8),1109 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x20),1110 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x5),1111 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1112 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x13),1113 1114 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0x13),1115 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1116 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x26),1117 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1118 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x30),1119 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) |1120 CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f)1121 },1122 .nlinv = 7,1123 .vop_uv = 4800000,1124 .vcom_uv = 1512500,1125 .vgh_mv = 15000,1126 .vgl_mv = -11730,1127 .avdd_mv = 6600,1128 .avcl_mv = -4400,1129 .gamma_op_bias = OP_BIAS_MIDDLE,1130 .input_op_bias = OP_BIAS_MIN,1131 .output_op_bias = OP_BIAS_MIN,1132 .t2d_ns = 1600,1133 .t3d_ns = 10400,1134 .eot_en = true,1135 .gip_sequence = rg28xx_gip_sequence,1136};1137 1138static void st7701_cleanup(void *data)1139{1140 struct st7701 *st7701 = (struct st7701 *)data;1141 1142 drm_panel_remove(&st7701->panel);1143 drm_panel_disable(&st7701->panel);1144 drm_panel_unprepare(&st7701->panel);1145}1146 1147static int st7701_probe(struct device *dev, int connector_type)1148{1149 const struct st7701_panel_desc *desc;1150 struct st7701 *st7701;1151 int ret;1152 1153 st7701 = devm_kzalloc(dev, sizeof(*st7701), GFP_KERNEL);1154 if (!st7701)1155 return -ENOMEM;1156 1157 desc = of_device_get_match_data(dev);1158 if (!desc)1159 return -ENODEV;1160 1161 st7701->supplies[0].supply = "VCC";1162 st7701->supplies[1].supply = "IOVCC";1163 1164 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st7701->supplies),1165 st7701->supplies);1166 if (ret < 0)1167 return ret;1168 1169 st7701->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);1170 if (IS_ERR(st7701->reset)) {1171 dev_err(dev, "Couldn't get our reset GPIO\n");1172 return PTR_ERR(st7701->reset);1173 }1174 1175 ret = of_drm_get_panel_orientation(dev->of_node, &st7701->orientation);1176 if (ret < 0)1177 return dev_err_probe(dev, ret, "Failed to get orientation\n");1178 1179 drm_panel_init(&st7701->panel, dev, &st7701_funcs, connector_type);1180 1181 /**1182 * Once sleep out has been issued, ST7701 IC required to wait 120ms1183 * before initiating new commands.1184 *1185 * On top of that some panels might need an extra delay to wait, so1186 * add panel specific delay for those cases. As now this panel specific1187 * delay information is referenced from those panel BSP driver, example1188 * ts8550b and there is no valid documentation for that.1189 */1190 st7701->sleep_delay = 120 + desc->panel_sleep_delay;1191 1192 ret = drm_panel_of_backlight(&st7701->panel);1193 if (ret)1194 return ret;1195 1196 drm_panel_add(&st7701->panel);1197 1198 dev_set_drvdata(dev, st7701);1199 st7701->desc = desc;1200 1201 return devm_add_action_or_reset(dev, st7701_cleanup, st7701);1202}1203 1204static int st7701_dsi_probe(struct mipi_dsi_device *dsi)1205{1206 struct st7701 *st7701;1207 int err;1208 1209 err = st7701_probe(&dsi->dev, DRM_MODE_CONNECTOR_DSI);1210 if (err)1211 return err;1212 1213 st7701 = dev_get_drvdata(&dsi->dev);1214 st7701->dsi = dsi;1215 st7701->write_command = st7701_dsi_write;1216 1217 if (!st7701->desc->lanes)1218 return dev_err_probe(&dsi->dev, -EINVAL, "This panel is not for MIPI DSI\n");1219 1220 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |1221 MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS;1222 dsi->format = st7701->desc->format;1223 dsi->lanes = st7701->desc->lanes;1224 1225 err = mipi_dsi_attach(dsi);1226 if (err)1227 return dev_err_probe(&dsi->dev, err, "Failed to init MIPI DSI\n");1228 1229 return 0;1230}1231 1232static int st7701_spi_probe(struct spi_device *spi)1233{1234 struct st7701 *st7701;1235 struct gpio_desc *dc;1236 int err;1237 1238 err = st7701_probe(&spi->dev, DRM_MODE_CONNECTOR_DPI);1239 if (err)1240 return err;1241 1242 st7701 = dev_get_drvdata(&spi->dev);1243 st7701->write_command = st7701_dbi_write;1244 1245 dc = devm_gpiod_get_optional(&spi->dev, "dc", GPIOD_OUT_LOW);1246 if (IS_ERR(dc))1247 return dev_err_probe(&spi->dev, PTR_ERR(dc), "Failed to get GPIO for D/CX\n");1248 1249 err = mipi_dbi_spi_init(spi, &st7701->dbi, dc);1250 if (err)1251 return dev_err_probe(&spi->dev, err, "Failed to init MIPI DBI\n");1252 st7701->dbi.read_commands = NULL;1253 1254 return 0;1255}1256 1257static void st7701_dsi_remove(struct mipi_dsi_device *dsi)1258{1259 mipi_dsi_detach(dsi);1260}1261 1262static const struct of_device_id st7701_dsi_of_match[] = {1263 { .compatible = "anbernic,rg-arc-panel", .data = &rg_arc_desc },1264 { .compatible = "densitron,dmt028vghmcmi-1a", .data = &dmt028vghmcmi_1a_desc },1265 { .compatible = "elida,kd50t048a", .data = &kd50t048a_desc },1266 { .compatible = "techstar,ts8550b", .data = &ts8550b_desc },1267 { }1268};1269MODULE_DEVICE_TABLE(of, st7701_dsi_of_match);1270 1271static const struct of_device_id st7701_spi_of_match[] = {1272 { .compatible = "anbernic,rg28xx-panel", .data = &rg28xx_desc },1273 { /* sentinel */ }1274};1275MODULE_DEVICE_TABLE(of, st7701_spi_of_match);1276 1277static const struct spi_device_id st7701_spi_ids[] = {1278 { "rg28xx-panel" },1279 { /* sentinel */ }1280};1281MODULE_DEVICE_TABLE(spi, st7701_spi_ids);1282 1283static struct mipi_dsi_driver st7701_dsi_driver = {1284 .probe = st7701_dsi_probe,1285 .remove = st7701_dsi_remove,1286 .driver = {1287 .name = "st7701",1288 .of_match_table = st7701_dsi_of_match,1289 },1290};1291 1292static struct spi_driver st7701_spi_driver = {1293 .probe = st7701_spi_probe,1294 .id_table = st7701_spi_ids,1295 .driver = {1296 .name = "st7701",1297 .of_match_table = st7701_spi_of_match,1298 },1299};1300 1301static int __init st7701_driver_init(void)1302{1303 int err;1304 1305 if (IS_ENABLED(CONFIG_SPI)) {1306 err = spi_register_driver(&st7701_spi_driver);1307 if (err)1308 return err;1309 }1310 1311 if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {1312 err = mipi_dsi_driver_register(&st7701_dsi_driver);1313 if (err) {1314 if (IS_ENABLED(CONFIG_SPI))1315 spi_unregister_driver(&st7701_spi_driver);1316 return err;1317 }1318 }1319 1320 return 0;1321}1322module_init(st7701_driver_init);1323 1324static void __exit st7701_driver_exit(void)1325{1326 if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))1327 mipi_dsi_driver_unregister(&st7701_dsi_driver);1328 1329 if (IS_ENABLED(CONFIG_SPI))1330 spi_unregister_driver(&st7701_spi_driver);1331}1332module_exit(st7701_driver_exit);1333 1334MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");1335MODULE_AUTHOR("Hironori KIKUCHI <kikuchan98@gmail.com>");1336MODULE_DESCRIPTION("Sitronix ST7701 LCD Panel Driver");1337MODULE_LICENSE("GPL");1338