12349183dSNeil Armstrong // SPDX-License-Identifier: GPL-2.0-only
22349183dSNeil Armstrong // Copyright (c) 2023, Linaro Limited
32349183dSNeil Armstrong
42349183dSNeil Armstrong #include <linux/backlight.h>
52349183dSNeil Armstrong #include <linux/delay.h>
62349183dSNeil Armstrong #include <linux/gpio/consumer.h>
72349183dSNeil Armstrong #include <linux/regulator/consumer.h>
82349183dSNeil Armstrong #include <linux/module.h>
92349183dSNeil Armstrong #include <linux/of.h>
102349183dSNeil Armstrong
112349183dSNeil Armstrong #include <drm/display/drm_dsc.h>
122349183dSNeil Armstrong #include <drm/drm_mipi_dsi.h>
132349183dSNeil Armstrong #include <drm/drm_modes.h>
142349183dSNeil Armstrong #include <drm/drm_panel.h>
152349183dSNeil Armstrong
162349183dSNeil Armstrong #include <video/mipi_display.h>
172349183dSNeil Armstrong
182349183dSNeil Armstrong struct visionox_vtdr6130 {
192349183dSNeil Armstrong struct drm_panel panel;
202349183dSNeil Armstrong struct mipi_dsi_device *dsi;
212349183dSNeil Armstrong struct gpio_desc *reset_gpio;
222349183dSNeil Armstrong struct regulator_bulk_data supplies[3];
232349183dSNeil Armstrong bool prepared;
242349183dSNeil Armstrong };
252349183dSNeil Armstrong
to_visionox_vtdr6130(struct drm_panel * panel)262349183dSNeil Armstrong static inline struct visionox_vtdr6130 *to_visionox_vtdr6130(struct drm_panel *panel)
272349183dSNeil Armstrong {
282349183dSNeil Armstrong return container_of(panel, struct visionox_vtdr6130, panel);
292349183dSNeil Armstrong }
302349183dSNeil Armstrong
visionox_vtdr6130_reset(struct visionox_vtdr6130 * ctx)312349183dSNeil Armstrong static void visionox_vtdr6130_reset(struct visionox_vtdr6130 *ctx)
322349183dSNeil Armstrong {
332349183dSNeil Armstrong gpiod_set_value_cansleep(ctx->reset_gpio, 0);
342349183dSNeil Armstrong usleep_range(10000, 11000);
352349183dSNeil Armstrong gpiod_set_value_cansleep(ctx->reset_gpio, 1);
362349183dSNeil Armstrong usleep_range(10000, 11000);
372349183dSNeil Armstrong gpiod_set_value_cansleep(ctx->reset_gpio, 0);
382349183dSNeil Armstrong usleep_range(10000, 11000);
392349183dSNeil Armstrong }
402349183dSNeil Armstrong
visionox_vtdr6130_on(struct visionox_vtdr6130 * ctx)412349183dSNeil Armstrong static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx)
422349183dSNeil Armstrong {
432349183dSNeil Armstrong struct mipi_dsi_device *dsi = ctx->dsi;
442349183dSNeil Armstrong struct device *dev = &dsi->dev;
452349183dSNeil Armstrong int ret;
462349183dSNeil Armstrong
472349183dSNeil Armstrong dsi->mode_flags |= MIPI_DSI_MODE_LPM;
482349183dSNeil Armstrong
492349183dSNeil Armstrong ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
502349183dSNeil Armstrong if (ret)
512349183dSNeil Armstrong return ret;
522349183dSNeil Armstrong
532349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
542349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00, 0x00);
552349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x59, 0x09);
562349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x6c, 0x01);
572349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x00);
582349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x6f, 0x01);
592349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x70,
602349183dSNeil Armstrong 0x12, 0x00, 0x00, 0xab, 0x30, 0x80, 0x09, 0x60, 0x04,
612349183dSNeil Armstrong 0x38, 0x00, 0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
622349183dSNeil Armstrong 0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00, 0x07, 0x00,
632349183dSNeil Armstrong 0x0c, 0x02, 0x77, 0x02, 0x8b, 0x18, 0x00, 0x10, 0xf0,
642349183dSNeil Armstrong 0x07, 0x10, 0x20, 0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e,
652349183dSNeil Armstrong 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77,
662349183dSNeil Armstrong 0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02, 0x22, 0x00, 0x2a,
672349183dSNeil Armstrong 0x40, 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
682349183dSNeil Armstrong 0x3b, 0x38, 0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b,
692349183dSNeil Armstrong 0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74, 0x00, 0x00,
702349183dSNeil Armstrong 0x00, 0x00, 0x00, 0x00);
712349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x10);
722349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xb1,
732349183dSNeil Armstrong 0x01, 0x38, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x01, 0x66,
742349183dSNeil Armstrong 0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14,
752349183dSNeil Armstrong 0x05, 0xcc, 0x00);
762349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x13);
772349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xce,
782349183dSNeil Armstrong 0x09, 0x11, 0x09, 0x11, 0x08, 0xc1, 0x07, 0xfa, 0x05,
792349183dSNeil Armstrong 0xa4, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c,
802349183dSNeil Armstrong 0x00, 0x0c, 0x04, 0x00, 0x35);
812349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x14);
822349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x03, 0x33);
832349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xb4,
842349183dSNeil Armstrong 0x00, 0x33, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
852349183dSNeil Armstrong 0x3e, 0x00, 0x00);
862349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xb5,
872349183dSNeil Armstrong 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x01);
882349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0x00, 0x08, 0x09, 0x09, 0x09);
892349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xbc,
902349183dSNeil Armstrong 0x10, 0x00, 0x00, 0x06, 0x11, 0x09, 0x3b, 0x09, 0x47,
912349183dSNeil Armstrong 0x09, 0x47, 0x00);
922349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xbe,
932349183dSNeil Armstrong 0x10, 0x10, 0x00, 0x08, 0x22, 0x09, 0x19, 0x09, 0x25,
942349183dSNeil Armstrong 0x09, 0x25, 0x00);
952349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x80);
962349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x65, 0x14);
972349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xfa, 0x08, 0x08, 0x08);
982349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x81);
992349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x65, 0x05);
1002349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf3, 0x0f);
1012349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x00);
1022349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x82);
1032349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf9, 0x00);
1042349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xff, 0x51, 0x83);
1052349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x65, 0x04);
1062349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf8, 0x00);
1072349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
1082349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0x65, 0x01);
1092349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xf4, 0x9a);
1102349183dSNeil Armstrong mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
1112349183dSNeil Armstrong
1122349183dSNeil Armstrong ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
1132349183dSNeil Armstrong if (ret < 0) {
1142349183dSNeil Armstrong dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
1152349183dSNeil Armstrong return ret;
1162349183dSNeil Armstrong }
1172349183dSNeil Armstrong msleep(120);
1182349183dSNeil Armstrong
1192349183dSNeil Armstrong ret = mipi_dsi_dcs_set_display_on(dsi);
1202349183dSNeil Armstrong if (ret < 0) {
1212349183dSNeil Armstrong dev_err(dev, "Failed to set display on: %d\n", ret);
1222349183dSNeil Armstrong return ret;
1232349183dSNeil Armstrong }
1242349183dSNeil Armstrong msleep(20);
1252349183dSNeil Armstrong
1262349183dSNeil Armstrong return 0;
1272349183dSNeil Armstrong }
1282349183dSNeil Armstrong
visionox_vtdr6130_off(struct visionox_vtdr6130 * ctx)1292349183dSNeil Armstrong static int visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx)
1302349183dSNeil Armstrong {
1312349183dSNeil Armstrong struct mipi_dsi_device *dsi = ctx->dsi;
1322349183dSNeil Armstrong struct device *dev = &dsi->dev;
1332349183dSNeil Armstrong int ret;
1342349183dSNeil Armstrong
1352349183dSNeil Armstrong dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
1362349183dSNeil Armstrong
1372349183dSNeil Armstrong ret = mipi_dsi_dcs_set_display_off(dsi);
1382349183dSNeil Armstrong if (ret < 0) {
1392349183dSNeil Armstrong dev_err(dev, "Failed to set display off: %d\n", ret);
1402349183dSNeil Armstrong return ret;
1412349183dSNeil Armstrong }
1422349183dSNeil Armstrong msleep(20);
1432349183dSNeil Armstrong
1442349183dSNeil Armstrong ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
1452349183dSNeil Armstrong if (ret < 0) {
1462349183dSNeil Armstrong dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
1472349183dSNeil Armstrong return ret;
1482349183dSNeil Armstrong }
1492349183dSNeil Armstrong msleep(120);
1502349183dSNeil Armstrong
1512349183dSNeil Armstrong return 0;
1522349183dSNeil Armstrong }
1532349183dSNeil Armstrong
visionox_vtdr6130_prepare(struct drm_panel * panel)1542349183dSNeil Armstrong static int visionox_vtdr6130_prepare(struct drm_panel *panel)
1552349183dSNeil Armstrong {
1562349183dSNeil Armstrong struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
1572349183dSNeil Armstrong struct device *dev = &ctx->dsi->dev;
1582349183dSNeil Armstrong int ret;
1592349183dSNeil Armstrong
1602349183dSNeil Armstrong if (ctx->prepared)
1612349183dSNeil Armstrong return 0;
1622349183dSNeil Armstrong
1632349183dSNeil Armstrong ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies),
1642349183dSNeil Armstrong ctx->supplies);
1652349183dSNeil Armstrong if (ret < 0)
1662349183dSNeil Armstrong return ret;
1672349183dSNeil Armstrong
1682349183dSNeil Armstrong visionox_vtdr6130_reset(ctx);
1692349183dSNeil Armstrong
1702349183dSNeil Armstrong ret = visionox_vtdr6130_on(ctx);
1712349183dSNeil Armstrong if (ret < 0) {
1722349183dSNeil Armstrong dev_err(dev, "Failed to initialize panel: %d\n", ret);
1732349183dSNeil Armstrong gpiod_set_value_cansleep(ctx->reset_gpio, 1);
1742349183dSNeil Armstrong regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
1752349183dSNeil Armstrong return ret;
1762349183dSNeil Armstrong }
1772349183dSNeil Armstrong
1782349183dSNeil Armstrong ctx->prepared = true;
1792349183dSNeil Armstrong return 0;
1802349183dSNeil Armstrong }
1812349183dSNeil Armstrong
visionox_vtdr6130_unprepare(struct drm_panel * panel)1822349183dSNeil Armstrong static int visionox_vtdr6130_unprepare(struct drm_panel *panel)
1832349183dSNeil Armstrong {
1842349183dSNeil Armstrong struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
1852349183dSNeil Armstrong struct device *dev = &ctx->dsi->dev;
1862349183dSNeil Armstrong int ret;
1872349183dSNeil Armstrong
1882349183dSNeil Armstrong if (!ctx->prepared)
1892349183dSNeil Armstrong return 0;
1902349183dSNeil Armstrong
1912349183dSNeil Armstrong ret = visionox_vtdr6130_off(ctx);
1922349183dSNeil Armstrong if (ret < 0)
1932349183dSNeil Armstrong dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
1942349183dSNeil Armstrong
1952349183dSNeil Armstrong gpiod_set_value_cansleep(ctx->reset_gpio, 1);
1962349183dSNeil Armstrong
1972349183dSNeil Armstrong regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
1982349183dSNeil Armstrong
1992349183dSNeil Armstrong ctx->prepared = false;
2002349183dSNeil Armstrong return 0;
2012349183dSNeil Armstrong }
2022349183dSNeil Armstrong
2032349183dSNeil Armstrong static const struct drm_display_mode visionox_vtdr6130_mode = {
2042349183dSNeil Armstrong .clock = (1080 + 20 + 2 + 20) * (2400 + 20 + 2 + 18) * 144 / 1000,
2052349183dSNeil Armstrong .hdisplay = 1080,
2062349183dSNeil Armstrong .hsync_start = 1080 + 20,
2072349183dSNeil Armstrong .hsync_end = 1080 + 20 + 2,
2082349183dSNeil Armstrong .htotal = 1080 + 20 + 2 + 20,
2092349183dSNeil Armstrong .vdisplay = 2400,
2102349183dSNeil Armstrong .vsync_start = 2400 + 20,
2112349183dSNeil Armstrong .vsync_end = 2400 + 20 + 2,
2122349183dSNeil Armstrong .vtotal = 2400 + 20 + 2 + 18,
2132349183dSNeil Armstrong .width_mm = 71,
2142349183dSNeil Armstrong .height_mm = 157,
2152349183dSNeil Armstrong };
2162349183dSNeil Armstrong
visionox_vtdr6130_get_modes(struct drm_panel * panel,struct drm_connector * connector)2172349183dSNeil Armstrong static int visionox_vtdr6130_get_modes(struct drm_panel *panel,
2182349183dSNeil Armstrong struct drm_connector *connector)
2192349183dSNeil Armstrong {
2202349183dSNeil Armstrong struct drm_display_mode *mode;
2212349183dSNeil Armstrong
2222349183dSNeil Armstrong mode = drm_mode_duplicate(connector->dev, &visionox_vtdr6130_mode);
2232349183dSNeil Armstrong if (!mode)
2242349183dSNeil Armstrong return -ENOMEM;
2252349183dSNeil Armstrong
2262349183dSNeil Armstrong drm_mode_set_name(mode);
2272349183dSNeil Armstrong
2282349183dSNeil Armstrong mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
2292349183dSNeil Armstrong connector->display_info.width_mm = mode->width_mm;
2302349183dSNeil Armstrong connector->display_info.height_mm = mode->height_mm;
2312349183dSNeil Armstrong drm_mode_probed_add(connector, mode);
2322349183dSNeil Armstrong
2332349183dSNeil Armstrong return 1;
2342349183dSNeil Armstrong }
2352349183dSNeil Armstrong
2362349183dSNeil Armstrong static const struct drm_panel_funcs visionox_vtdr6130_panel_funcs = {
2372349183dSNeil Armstrong .prepare = visionox_vtdr6130_prepare,
2382349183dSNeil Armstrong .unprepare = visionox_vtdr6130_unprepare,
2392349183dSNeil Armstrong .get_modes = visionox_vtdr6130_get_modes,
2402349183dSNeil Armstrong };
2412349183dSNeil Armstrong
visionox_vtdr6130_bl_update_status(struct backlight_device * bl)2422349183dSNeil Armstrong static int visionox_vtdr6130_bl_update_status(struct backlight_device *bl)
2432349183dSNeil Armstrong {
2442349183dSNeil Armstrong struct mipi_dsi_device *dsi = bl_get_data(bl);
2452349183dSNeil Armstrong u16 brightness = backlight_get_brightness(bl);
2462349183dSNeil Armstrong
247*ebd05c0eSNeil Armstrong return mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
2482349183dSNeil Armstrong }
2492349183dSNeil Armstrong
2502349183dSNeil Armstrong static const struct backlight_ops visionox_vtdr6130_bl_ops = {
2512349183dSNeil Armstrong .update_status = visionox_vtdr6130_bl_update_status,
2522349183dSNeil Armstrong };
2532349183dSNeil Armstrong
2542349183dSNeil Armstrong static struct backlight_device *
visionox_vtdr6130_create_backlight(struct mipi_dsi_device * dsi)2552349183dSNeil Armstrong visionox_vtdr6130_create_backlight(struct mipi_dsi_device *dsi)
2562349183dSNeil Armstrong {
2572349183dSNeil Armstrong struct device *dev = &dsi->dev;
2582349183dSNeil Armstrong const struct backlight_properties props = {
2592349183dSNeil Armstrong .type = BACKLIGHT_RAW,
2602349183dSNeil Armstrong .brightness = 4095,
2612349183dSNeil Armstrong .max_brightness = 4095,
2622349183dSNeil Armstrong };
2632349183dSNeil Armstrong
2642349183dSNeil Armstrong return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
2652349183dSNeil Armstrong &visionox_vtdr6130_bl_ops, &props);
2662349183dSNeil Armstrong }
2672349183dSNeil Armstrong
visionox_vtdr6130_probe(struct mipi_dsi_device * dsi)2682349183dSNeil Armstrong static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
2692349183dSNeil Armstrong {
2702349183dSNeil Armstrong struct device *dev = &dsi->dev;
2712349183dSNeil Armstrong struct visionox_vtdr6130 *ctx;
2722349183dSNeil Armstrong int ret;
2732349183dSNeil Armstrong
2742349183dSNeil Armstrong ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
2752349183dSNeil Armstrong if (!ctx)
2762349183dSNeil Armstrong return -ENOMEM;
2772349183dSNeil Armstrong
2782349183dSNeil Armstrong ctx->supplies[0].supply = "vddio";
2792349183dSNeil Armstrong ctx->supplies[1].supply = "vci";
2802349183dSNeil Armstrong ctx->supplies[2].supply = "vdd";
2812349183dSNeil Armstrong
2822349183dSNeil Armstrong ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies),
2832349183dSNeil Armstrong ctx->supplies);
2842349183dSNeil Armstrong if (ret < 0)
2852349183dSNeil Armstrong return ret;
2862349183dSNeil Armstrong
2872349183dSNeil Armstrong ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
2882349183dSNeil Armstrong if (IS_ERR(ctx->reset_gpio))
2892349183dSNeil Armstrong return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
2902349183dSNeil Armstrong "Failed to get reset-gpios\n");
2912349183dSNeil Armstrong
2922349183dSNeil Armstrong ctx->dsi = dsi;
2932349183dSNeil Armstrong mipi_dsi_set_drvdata(dsi, ctx);
2942349183dSNeil Armstrong
2952349183dSNeil Armstrong dsi->lanes = 4;
2962349183dSNeil Armstrong dsi->format = MIPI_DSI_FMT_RGB888;
2972349183dSNeil Armstrong dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
2982349183dSNeil Armstrong MIPI_DSI_CLOCK_NON_CONTINUOUS;
2992349183dSNeil Armstrong
3002349183dSNeil Armstrong drm_panel_init(&ctx->panel, dev, &visionox_vtdr6130_panel_funcs,
3012349183dSNeil Armstrong DRM_MODE_CONNECTOR_DSI);
3022349183dSNeil Armstrong
3032349183dSNeil Armstrong ctx->panel.backlight = visionox_vtdr6130_create_backlight(dsi);
3042349183dSNeil Armstrong if (IS_ERR(ctx->panel.backlight))
3052349183dSNeil Armstrong return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
3062349183dSNeil Armstrong "Failed to create backlight\n");
3072349183dSNeil Armstrong
3082349183dSNeil Armstrong drm_panel_add(&ctx->panel);
3092349183dSNeil Armstrong
3102349183dSNeil Armstrong ret = mipi_dsi_attach(dsi);
3112349183dSNeil Armstrong if (ret < 0) {
3122349183dSNeil Armstrong dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
3132349183dSNeil Armstrong drm_panel_remove(&ctx->panel);
3142349183dSNeil Armstrong return ret;
3152349183dSNeil Armstrong }
3162349183dSNeil Armstrong
3172349183dSNeil Armstrong return 0;
3182349183dSNeil Armstrong }
3192349183dSNeil Armstrong
visionox_vtdr6130_remove(struct mipi_dsi_device * dsi)3202349183dSNeil Armstrong static void visionox_vtdr6130_remove(struct mipi_dsi_device *dsi)
3212349183dSNeil Armstrong {
3222349183dSNeil Armstrong struct visionox_vtdr6130 *ctx = mipi_dsi_get_drvdata(dsi);
3232349183dSNeil Armstrong int ret;
3242349183dSNeil Armstrong
3252349183dSNeil Armstrong ret = mipi_dsi_detach(dsi);
3262349183dSNeil Armstrong if (ret < 0)
3272349183dSNeil Armstrong dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
3282349183dSNeil Armstrong
3292349183dSNeil Armstrong drm_panel_remove(&ctx->panel);
3302349183dSNeil Armstrong }
3312349183dSNeil Armstrong
3322349183dSNeil Armstrong static const struct of_device_id visionox_vtdr6130_of_match[] = {
3332349183dSNeil Armstrong { .compatible = "visionox,vtdr6130" },
3342349183dSNeil Armstrong { /* sentinel */ }
3352349183dSNeil Armstrong };
3362349183dSNeil Armstrong MODULE_DEVICE_TABLE(of, visionox_vtdr6130_of_match);
3372349183dSNeil Armstrong
3382349183dSNeil Armstrong static struct mipi_dsi_driver visionox_vtdr6130_driver = {
3392349183dSNeil Armstrong .probe = visionox_vtdr6130_probe,
3402349183dSNeil Armstrong .remove = visionox_vtdr6130_remove,
3412349183dSNeil Armstrong .driver = {
3422349183dSNeil Armstrong .name = "panel-visionox-vtdr6130",
3432349183dSNeil Armstrong .of_match_table = visionox_vtdr6130_of_match,
3442349183dSNeil Armstrong },
3452349183dSNeil Armstrong };
3462349183dSNeil Armstrong module_mipi_dsi_driver(visionox_vtdr6130_driver);
3472349183dSNeil Armstrong
3482349183dSNeil Armstrong MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
3492349183dSNeil Armstrong MODULE_DESCRIPTION("Panel driver for the Visionox VTDR6130 AMOLED DSI panel");
3502349183dSNeil Armstrong MODULE_LICENSE("GPL");
351