1*3ee01b86STeguh Sobirin // SPDX-License-Identifier: GPL-2.0-only 2*3ee01b86STeguh Sobirin /* 3*3ee01b86STeguh Sobirin * ChipWealth CH13726A MIPI-DSI panel driver 4*3ee01b86STeguh Sobirin * Copyright (c) 2024, Teguh Sobirin <teguh@sobir.in>. 5*3ee01b86STeguh Sobirin */ 6*3ee01b86STeguh Sobirin 7*3ee01b86STeguh Sobirin #include <linux/backlight.h> 8*3ee01b86STeguh Sobirin #include <linux/delay.h> 9*3ee01b86STeguh Sobirin #include <linux/gpio/consumer.h> 10*3ee01b86STeguh Sobirin #include <linux/module.h> 11*3ee01b86STeguh Sobirin #include <linux/of.h> 12*3ee01b86STeguh Sobirin #include <linux/regulator/consumer.h> 13*3ee01b86STeguh Sobirin 14*3ee01b86STeguh Sobirin #include <drm/drm_mipi_dsi.h> 15*3ee01b86STeguh Sobirin #include <drm/drm_modes.h> 16*3ee01b86STeguh Sobirin #include <drm/drm_panel.h> 17*3ee01b86STeguh Sobirin 18*3ee01b86STeguh Sobirin #include <video/mipi_display.h> 19*3ee01b86STeguh Sobirin 20*3ee01b86STeguh Sobirin static const struct regulator_bulk_data ch13726a_supplies[] = { 21*3ee01b86STeguh Sobirin { .supply = "vdd1v2", }, 22*3ee01b86STeguh Sobirin { .supply = "vddio", }, 23*3ee01b86STeguh Sobirin { .supply = "vdd", }, 24*3ee01b86STeguh Sobirin { .supply = "avdd", }, 25*3ee01b86STeguh Sobirin }; 26*3ee01b86STeguh Sobirin 27*3ee01b86STeguh Sobirin struct ch13726a_panel { 28*3ee01b86STeguh Sobirin struct drm_panel panel; 29*3ee01b86STeguh Sobirin struct mipi_dsi_device *dsi; 30*3ee01b86STeguh Sobirin struct regulator_bulk_data *supplies; 31*3ee01b86STeguh Sobirin struct gpio_desc *reset_gpio; 32*3ee01b86STeguh Sobirin struct ch13726a_desc *desc; 33*3ee01b86STeguh Sobirin enum drm_panel_orientation orientation; 34*3ee01b86STeguh Sobirin }; 35*3ee01b86STeguh Sobirin 36*3ee01b86STeguh Sobirin struct ch13726a_desc { 37*3ee01b86STeguh Sobirin unsigned int width_mm; 38*3ee01b86STeguh Sobirin unsigned int height_mm; 39*3ee01b86STeguh Sobirin unsigned int bpc; 40*3ee01b86STeguh Sobirin 41*3ee01b86STeguh Sobirin const struct drm_display_mode *modes; 42*3ee01b86STeguh Sobirin unsigned int num_modes; 43*3ee01b86STeguh Sobirin }; 44*3ee01b86STeguh Sobirin 45*3ee01b86STeguh Sobirin static inline struct ch13726a_panel *to_ch13726a_panel(struct drm_panel *panel) 46*3ee01b86STeguh Sobirin { 47*3ee01b86STeguh Sobirin return container_of(panel, struct ch13726a_panel, panel); 48*3ee01b86STeguh Sobirin } 49*3ee01b86STeguh Sobirin 50*3ee01b86STeguh Sobirin static void ch13726a_reset(struct ch13726a_panel *ctx) 51*3ee01b86STeguh Sobirin { 52*3ee01b86STeguh Sobirin gpiod_set_value_cansleep(ctx->reset_gpio, 0); 53*3ee01b86STeguh Sobirin usleep_range(10000, 11000); 54*3ee01b86STeguh Sobirin gpiod_set_value_cansleep(ctx->reset_gpio, 1); 55*3ee01b86STeguh Sobirin usleep_range(10000, 11000); 56*3ee01b86STeguh Sobirin gpiod_set_value_cansleep(ctx->reset_gpio, 0); 57*3ee01b86STeguh Sobirin usleep_range(10000, 11000); 58*3ee01b86STeguh Sobirin } 59*3ee01b86STeguh Sobirin 60*3ee01b86STeguh Sobirin static int ch13726a_on(struct ch13726a_panel *ctx) 61*3ee01b86STeguh Sobirin { 62*3ee01b86STeguh Sobirin struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 63*3ee01b86STeguh Sobirin 64*3ee01b86STeguh Sobirin ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; 65*3ee01b86STeguh Sobirin 66*3ee01b86STeguh Sobirin mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x50); 67*3ee01b86STeguh Sobirin mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00); 68*3ee01b86STeguh Sobirin 69*3ee01b86STeguh Sobirin mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 70*3ee01b86STeguh Sobirin 71*3ee01b86STeguh Sobirin mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 72*3ee01b86STeguh Sobirin 73*3ee01b86STeguh Sobirin return dsi_ctx.accum_err; 74*3ee01b86STeguh Sobirin } 75*3ee01b86STeguh Sobirin 76*3ee01b86STeguh Sobirin static int ch13726a_disable(struct drm_panel *panel) 77*3ee01b86STeguh Sobirin { 78*3ee01b86STeguh Sobirin struct ch13726a_panel *ctx = to_ch13726a_panel(panel); 79*3ee01b86STeguh Sobirin struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 80*3ee01b86STeguh Sobirin 81*3ee01b86STeguh Sobirin ctx->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 82*3ee01b86STeguh Sobirin 83*3ee01b86STeguh Sobirin mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 84*3ee01b86STeguh Sobirin mipi_dsi_msleep(&dsi_ctx, 50); 85*3ee01b86STeguh Sobirin mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 86*3ee01b86STeguh Sobirin 87*3ee01b86STeguh Sobirin return dsi_ctx.accum_err; 88*3ee01b86STeguh Sobirin } 89*3ee01b86STeguh Sobirin 90*3ee01b86STeguh Sobirin static int ch13726a_prepare(struct drm_panel *panel) 91*3ee01b86STeguh Sobirin { 92*3ee01b86STeguh Sobirin struct ch13726a_panel *ctx = to_ch13726a_panel(panel); 93*3ee01b86STeguh Sobirin struct device *dev = &ctx->dsi->dev; 94*3ee01b86STeguh Sobirin int ret; 95*3ee01b86STeguh Sobirin 96*3ee01b86STeguh Sobirin ret = regulator_bulk_enable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies); 97*3ee01b86STeguh Sobirin if (ret < 0) { 98*3ee01b86STeguh Sobirin dev_err(dev, "Failed to enable regulators: %d\n", ret); 99*3ee01b86STeguh Sobirin return ret; 100*3ee01b86STeguh Sobirin } 101*3ee01b86STeguh Sobirin 102*3ee01b86STeguh Sobirin ch13726a_reset(ctx); 103*3ee01b86STeguh Sobirin 104*3ee01b86STeguh Sobirin ret = ch13726a_on(ctx); 105*3ee01b86STeguh Sobirin if (ret < 0) { 106*3ee01b86STeguh Sobirin dev_err(dev, "Failed to initialize panel: %d\n", ret); 107*3ee01b86STeguh Sobirin gpiod_set_value_cansleep(ctx->reset_gpio, 1); 108*3ee01b86STeguh Sobirin regulator_bulk_disable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies); 109*3ee01b86STeguh Sobirin return ret; 110*3ee01b86STeguh Sobirin } 111*3ee01b86STeguh Sobirin 112*3ee01b86STeguh Sobirin msleep(28); 113*3ee01b86STeguh Sobirin 114*3ee01b86STeguh Sobirin return 0; 115*3ee01b86STeguh Sobirin } 116*3ee01b86STeguh Sobirin 117*3ee01b86STeguh Sobirin static int ch13726a_unprepare(struct drm_panel *panel) 118*3ee01b86STeguh Sobirin { 119*3ee01b86STeguh Sobirin struct ch13726a_panel *ctx = to_ch13726a_panel(panel); 120*3ee01b86STeguh Sobirin 121*3ee01b86STeguh Sobirin gpiod_set_value_cansleep(ctx->reset_gpio, 1); 122*3ee01b86STeguh Sobirin regulator_bulk_disable(ARRAY_SIZE(ch13726a_supplies), ctx->supplies); 123*3ee01b86STeguh Sobirin 124*3ee01b86STeguh Sobirin return 0; 125*3ee01b86STeguh Sobirin } 126*3ee01b86STeguh Sobirin 127*3ee01b86STeguh Sobirin static const struct drm_display_mode thor_bottom_modes[] = { 128*3ee01b86STeguh Sobirin { 129*3ee01b86STeguh Sobirin /* 120Hz */ 130*3ee01b86STeguh Sobirin .clock = (1080 + 28 + 4 + 36) * (1240 + 16 + 4 + 8) * 120 / 1000, 131*3ee01b86STeguh Sobirin .hdisplay = 1080, 132*3ee01b86STeguh Sobirin .hsync_start = 1080 + 28, 133*3ee01b86STeguh Sobirin .hsync_end = 1080 + 28 + 4, 134*3ee01b86STeguh Sobirin .htotal = 1080 + 28 + 4 + 36, 135*3ee01b86STeguh Sobirin .vdisplay = 1240, 136*3ee01b86STeguh Sobirin .vsync_start = 1240 + 16, 137*3ee01b86STeguh Sobirin .vsync_end = 1240 + 16 + 4, 138*3ee01b86STeguh Sobirin .vtotal = 1240 + 16 + 4 + 8, 139*3ee01b86STeguh Sobirin }, 140*3ee01b86STeguh Sobirin { 141*3ee01b86STeguh Sobirin /* 60Hz */ 142*3ee01b86STeguh Sobirin .clock = (1080 + 28 + 4 + 36) * (1240 + 16 + 4 + 8) * 60 / 1000, 143*3ee01b86STeguh Sobirin .hdisplay = 1080, 144*3ee01b86STeguh Sobirin .hsync_start = 1080 + 28, 145*3ee01b86STeguh Sobirin .hsync_end = 1080 + 28 + 4, 146*3ee01b86STeguh Sobirin .htotal = 1080 + 28 + 4 + 36, 147*3ee01b86STeguh Sobirin .vdisplay = 1240, 148*3ee01b86STeguh Sobirin .vsync_start = 1240 + 16, 149*3ee01b86STeguh Sobirin .vsync_end = 1240 + 16 + 4, 150*3ee01b86STeguh Sobirin .vtotal = 1240 + 16 + 4 + 8, 151*3ee01b86STeguh Sobirin } 152*3ee01b86STeguh Sobirin }; 153*3ee01b86STeguh Sobirin 154*3ee01b86STeguh Sobirin static struct ch13726a_desc thor_bottom_desc = { 155*3ee01b86STeguh Sobirin .modes = thor_bottom_modes, 156*3ee01b86STeguh Sobirin .num_modes = ARRAY_SIZE(thor_bottom_modes), 157*3ee01b86STeguh Sobirin .width_mm = 65, 158*3ee01b86STeguh Sobirin .height_mm = 75, 159*3ee01b86STeguh Sobirin .bpc = 8, 160*3ee01b86STeguh Sobirin }; 161*3ee01b86STeguh Sobirin 162*3ee01b86STeguh Sobirin static int ch13726a_get_modes(struct drm_panel *panel, 163*3ee01b86STeguh Sobirin struct drm_connector *connector) 164*3ee01b86STeguh Sobirin { 165*3ee01b86STeguh Sobirin struct ch13726a_panel *ctx = to_ch13726a_panel(panel); 166*3ee01b86STeguh Sobirin 167*3ee01b86STeguh Sobirin for (uint8_t i = 0; i < ctx->desc->num_modes; i++) { 168*3ee01b86STeguh Sobirin const struct drm_display_mode *m = &ctx->desc->modes[i]; 169*3ee01b86STeguh Sobirin struct drm_display_mode *mode; 170*3ee01b86STeguh Sobirin 171*3ee01b86STeguh Sobirin mode = drm_mode_duplicate(connector->dev, m); 172*3ee01b86STeguh Sobirin if (!mode) { 173*3ee01b86STeguh Sobirin dev_err(&ctx->dsi->dev, "failed to add mode %ux%u@%u\n", 174*3ee01b86STeguh Sobirin m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); 175*3ee01b86STeguh Sobirin return -ENOMEM; 176*3ee01b86STeguh Sobirin } 177*3ee01b86STeguh Sobirin 178*3ee01b86STeguh Sobirin mode->type = DRM_MODE_TYPE_DRIVER; 179*3ee01b86STeguh Sobirin if (i == 0) 180*3ee01b86STeguh Sobirin mode->type |= DRM_MODE_TYPE_PREFERRED; 181*3ee01b86STeguh Sobirin 182*3ee01b86STeguh Sobirin drm_mode_set_name(mode); 183*3ee01b86STeguh Sobirin drm_mode_probed_add(connector, mode); 184*3ee01b86STeguh Sobirin } 185*3ee01b86STeguh Sobirin 186*3ee01b86STeguh Sobirin connector->display_info.width_mm = ctx->desc->width_mm; 187*3ee01b86STeguh Sobirin connector->display_info.height_mm = ctx->desc->height_mm; 188*3ee01b86STeguh Sobirin connector->display_info.bpc = ctx->desc->bpc; 189*3ee01b86STeguh Sobirin 190*3ee01b86STeguh Sobirin return ctx->desc->num_modes; 191*3ee01b86STeguh Sobirin } 192*3ee01b86STeguh Sobirin 193*3ee01b86STeguh Sobirin static enum drm_panel_orientation ch13726a_get_orientation(struct drm_panel *panel) 194*3ee01b86STeguh Sobirin { 195*3ee01b86STeguh Sobirin struct ch13726a_panel *ctx = to_ch13726a_panel(panel); 196*3ee01b86STeguh Sobirin 197*3ee01b86STeguh Sobirin return ctx->orientation; 198*3ee01b86STeguh Sobirin } 199*3ee01b86STeguh Sobirin 200*3ee01b86STeguh Sobirin static const struct drm_panel_funcs ch13726a_panel_funcs = { 201*3ee01b86STeguh Sobirin .prepare = ch13726a_prepare, 202*3ee01b86STeguh Sobirin .unprepare = ch13726a_unprepare, 203*3ee01b86STeguh Sobirin .disable = ch13726a_disable, 204*3ee01b86STeguh Sobirin .get_modes = ch13726a_get_modes, 205*3ee01b86STeguh Sobirin .get_orientation = ch13726a_get_orientation, 206*3ee01b86STeguh Sobirin }; 207*3ee01b86STeguh Sobirin 208*3ee01b86STeguh Sobirin static int ch13726a_bl_update_status(struct backlight_device *bl) 209*3ee01b86STeguh Sobirin { 210*3ee01b86STeguh Sobirin struct mipi_dsi_device *dsi = bl_get_data(bl); 211*3ee01b86STeguh Sobirin u16 brightness = backlight_get_brightness(bl); 212*3ee01b86STeguh Sobirin int ret; 213*3ee01b86STeguh Sobirin 214*3ee01b86STeguh Sobirin dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 215*3ee01b86STeguh Sobirin 216*3ee01b86STeguh Sobirin ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness); 217*3ee01b86STeguh Sobirin if (ret < 0) 218*3ee01b86STeguh Sobirin return ret; 219*3ee01b86STeguh Sobirin 220*3ee01b86STeguh Sobirin dsi->mode_flags |= MIPI_DSI_MODE_LPM; 221*3ee01b86STeguh Sobirin 222*3ee01b86STeguh Sobirin return 0; 223*3ee01b86STeguh Sobirin } 224*3ee01b86STeguh Sobirin 225*3ee01b86STeguh Sobirin static const struct backlight_ops ch13726a_bl_ops = { 226*3ee01b86STeguh Sobirin .update_status = ch13726a_bl_update_status, 227*3ee01b86STeguh Sobirin }; 228*3ee01b86STeguh Sobirin 229*3ee01b86STeguh Sobirin static struct backlight_device * 230*3ee01b86STeguh Sobirin ch13726a_create_backlight(struct mipi_dsi_device *dsi) 231*3ee01b86STeguh Sobirin { 232*3ee01b86STeguh Sobirin struct device *dev = &dsi->dev; 233*3ee01b86STeguh Sobirin const struct backlight_properties props = { 234*3ee01b86STeguh Sobirin .type = BACKLIGHT_RAW, 235*3ee01b86STeguh Sobirin .brightness = 255, 236*3ee01b86STeguh Sobirin .max_brightness = 255, 237*3ee01b86STeguh Sobirin }; 238*3ee01b86STeguh Sobirin 239*3ee01b86STeguh Sobirin return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 240*3ee01b86STeguh Sobirin &ch13726a_bl_ops, &props); 241*3ee01b86STeguh Sobirin } 242*3ee01b86STeguh Sobirin 243*3ee01b86STeguh Sobirin static int ch13726a_probe(struct mipi_dsi_device *dsi) 244*3ee01b86STeguh Sobirin { 245*3ee01b86STeguh Sobirin struct device *dev = &dsi->dev; 246*3ee01b86STeguh Sobirin struct ch13726a_panel *ctx; 247*3ee01b86STeguh Sobirin int ret; 248*3ee01b86STeguh Sobirin 249*3ee01b86STeguh Sobirin ctx = devm_drm_panel_alloc(dev, __typeof(*ctx), panel, 250*3ee01b86STeguh Sobirin &ch13726a_panel_funcs, 251*3ee01b86STeguh Sobirin DRM_MODE_CONNECTOR_DSI); 252*3ee01b86STeguh Sobirin if (IS_ERR(ctx)) 253*3ee01b86STeguh Sobirin return PTR_ERR(ctx); 254*3ee01b86STeguh Sobirin 255*3ee01b86STeguh Sobirin ctx->desc = (struct ch13726a_desc *)of_device_get_match_data(dev); 256*3ee01b86STeguh Sobirin if (!ctx->desc) 257*3ee01b86STeguh Sobirin return -ENODEV; 258*3ee01b86STeguh Sobirin 259*3ee01b86STeguh Sobirin ret = devm_regulator_bulk_get_const(dev, 260*3ee01b86STeguh Sobirin ARRAY_SIZE(ch13726a_supplies), 261*3ee01b86STeguh Sobirin ch13726a_supplies, 262*3ee01b86STeguh Sobirin &ctx->supplies); 263*3ee01b86STeguh Sobirin if (ret < 0) 264*3ee01b86STeguh Sobirin return dev_err_probe(dev, ret, "Failed to get regulators\n"); 265*3ee01b86STeguh Sobirin 266*3ee01b86STeguh Sobirin ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 267*3ee01b86STeguh Sobirin if (IS_ERR(ctx->reset_gpio)) 268*3ee01b86STeguh Sobirin return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 269*3ee01b86STeguh Sobirin "Failed to get reset-gpios\n"); 270*3ee01b86STeguh Sobirin 271*3ee01b86STeguh Sobirin ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); 272*3ee01b86STeguh Sobirin if (ret < 0) { 273*3ee01b86STeguh Sobirin dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); 274*3ee01b86STeguh Sobirin return ret; 275*3ee01b86STeguh Sobirin } 276*3ee01b86STeguh Sobirin 277*3ee01b86STeguh Sobirin ctx->dsi = dsi; 278*3ee01b86STeguh Sobirin mipi_dsi_set_drvdata(dsi, ctx); 279*3ee01b86STeguh Sobirin 280*3ee01b86STeguh Sobirin dsi->lanes = 4; 281*3ee01b86STeguh Sobirin dsi->format = MIPI_DSI_FMT_RGB888; 282*3ee01b86STeguh Sobirin dsi->mode_flags = MIPI_DSI_MODE_VIDEO | 283*3ee01b86STeguh Sobirin MIPI_DSI_CLOCK_NON_CONTINUOUS; 284*3ee01b86STeguh Sobirin 285*3ee01b86STeguh Sobirin ctx->panel.prepare_prev_first = true; 286*3ee01b86STeguh Sobirin 287*3ee01b86STeguh Sobirin ctx->panel.backlight = ch13726a_create_backlight(dsi); 288*3ee01b86STeguh Sobirin if (IS_ERR(ctx->panel.backlight)) 289*3ee01b86STeguh Sobirin return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), 290*3ee01b86STeguh Sobirin "Failed to create backlight\n"); 291*3ee01b86STeguh Sobirin 292*3ee01b86STeguh Sobirin drm_panel_add(&ctx->panel); 293*3ee01b86STeguh Sobirin 294*3ee01b86STeguh Sobirin ret = mipi_dsi_attach(dsi); 295*3ee01b86STeguh Sobirin if (ret < 0) { 296*3ee01b86STeguh Sobirin dev_err(dev, "Failed to attach to DSI host: %d\n", ret); 297*3ee01b86STeguh Sobirin drm_panel_remove(&ctx->panel); 298*3ee01b86STeguh Sobirin return ret; 299*3ee01b86STeguh Sobirin } 300*3ee01b86STeguh Sobirin 301*3ee01b86STeguh Sobirin return 0; 302*3ee01b86STeguh Sobirin } 303*3ee01b86STeguh Sobirin 304*3ee01b86STeguh Sobirin static void ch13726a_remove(struct mipi_dsi_device *dsi) 305*3ee01b86STeguh Sobirin { 306*3ee01b86STeguh Sobirin struct ch13726a_panel *ctx = mipi_dsi_get_drvdata(dsi); 307*3ee01b86STeguh Sobirin int ret; 308*3ee01b86STeguh Sobirin 309*3ee01b86STeguh Sobirin ret = mipi_dsi_detach(dsi); 310*3ee01b86STeguh Sobirin if (ret < 0) 311*3ee01b86STeguh Sobirin dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 312*3ee01b86STeguh Sobirin 313*3ee01b86STeguh Sobirin drm_panel_remove(&ctx->panel); 314*3ee01b86STeguh Sobirin } 315*3ee01b86STeguh Sobirin 316*3ee01b86STeguh Sobirin static const struct of_device_id ch13726a_of_match[] = { 317*3ee01b86STeguh Sobirin { .compatible = "ayntec,thor-panel-bottom", .data = &thor_bottom_desc }, 318*3ee01b86STeguh Sobirin { /* sentinel */ } 319*3ee01b86STeguh Sobirin }; 320*3ee01b86STeguh Sobirin MODULE_DEVICE_TABLE(of, ch13726a_of_match); 321*3ee01b86STeguh Sobirin 322*3ee01b86STeguh Sobirin static struct mipi_dsi_driver ch13726a_driver = { 323*3ee01b86STeguh Sobirin .probe = ch13726a_probe, 324*3ee01b86STeguh Sobirin .remove = ch13726a_remove, 325*3ee01b86STeguh Sobirin .driver = { 326*3ee01b86STeguh Sobirin .name = "panel-ch13726a-amoled", 327*3ee01b86STeguh Sobirin .of_match_table = ch13726a_of_match, 328*3ee01b86STeguh Sobirin }, 329*3ee01b86STeguh Sobirin }; 330*3ee01b86STeguh Sobirin module_mipi_dsi_driver(ch13726a_driver); 331*3ee01b86STeguh Sobirin 332*3ee01b86STeguh Sobirin MODULE_DESCRIPTION("DRM driver for CH13726A DSI panels"); 333*3ee01b86STeguh Sobirin MODULE_LICENSE("GPL"); 334