12a994cbeSNickey Yang // SPDX-License-Identifier: GPL-2.0+ 22a994cbeSNickey Yang /* 32a994cbeSNickey Yang * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd 42a994cbeSNickey Yang */ 52a994cbeSNickey Yang 6cb23eae3SSam Ravnborg #include <linux/delay.h> 72a994cbeSNickey Yang #include <linux/gpio/consumer.h> 82a994cbeSNickey Yang #include <linux/module.h> 92a994cbeSNickey Yang #include <linux/of.h> 102a994cbeSNickey Yang #include <linux/regulator/consumer.h> 112a994cbeSNickey Yang 122a994cbeSNickey Yang #include <video/mipi_display.h> 132a994cbeSNickey Yang 14cb23eae3SSam Ravnborg #include <drm/drm_crtc.h> 15cb23eae3SSam Ravnborg #include <drm/drm_device.h> 16cb23eae3SSam Ravnborg #include <drm/drm_mipi_dsi.h> 17cb23eae3SSam Ravnborg #include <drm/drm_modes.h> 18cb23eae3SSam Ravnborg #include <drm/drm_panel.h> 19cb23eae3SSam Ravnborg 202a994cbeSNickey Yang struct kingdisplay_panel { 212a994cbeSNickey Yang struct drm_panel base; 222a994cbeSNickey Yang struct mipi_dsi_device *link; 232a994cbeSNickey Yang 242a994cbeSNickey Yang struct regulator *supply; 252a994cbeSNickey Yang struct gpio_desc *enable_gpio; 262a994cbeSNickey Yang 272a994cbeSNickey Yang bool prepared; 282a994cbeSNickey Yang bool enabled; 292a994cbeSNickey Yang }; 302a994cbeSNickey Yang 312a994cbeSNickey Yang struct kingdisplay_panel_cmd { 322a994cbeSNickey Yang char cmd; 332a994cbeSNickey Yang char data; 342a994cbeSNickey Yang }; 352a994cbeSNickey Yang 362a994cbeSNickey Yang /* 372a994cbeSNickey Yang * According to the discussion on 382a994cbeSNickey Yang * https://review.coreboot.org/#/c/coreboot/+/22472/ 392a994cbeSNickey Yang * the panel init array is not part of the panels datasheet but instead 402a994cbeSNickey Yang * just came in this form from the panel vendor. 412a994cbeSNickey Yang */ 422a994cbeSNickey Yang static const struct kingdisplay_panel_cmd init_code[] = { 432a994cbeSNickey Yang /* voltage setting */ 442a994cbeSNickey Yang { 0xB0, 0x00 }, 452a994cbeSNickey Yang { 0xB2, 0x02 }, 462a994cbeSNickey Yang { 0xB3, 0x11 }, 472a994cbeSNickey Yang { 0xB4, 0x00 }, 482a994cbeSNickey Yang { 0xB6, 0x80 }, 492a994cbeSNickey Yang /* VCOM disable */ 502a994cbeSNickey Yang { 0xB7, 0x02 }, 512a994cbeSNickey Yang { 0xB8, 0x80 }, 522a994cbeSNickey Yang { 0xBA, 0x43 }, 532a994cbeSNickey Yang /* VCOM setting */ 542a994cbeSNickey Yang { 0xBB, 0x53 }, 552a994cbeSNickey Yang /* VSP setting */ 562a994cbeSNickey Yang { 0xBC, 0x0A }, 572a994cbeSNickey Yang /* VSN setting */ 582a994cbeSNickey Yang { 0xBD, 0x4A }, 592a994cbeSNickey Yang /* VGH setting */ 602a994cbeSNickey Yang { 0xBE, 0x2F }, 612a994cbeSNickey Yang /* VGL setting */ 622a994cbeSNickey Yang { 0xBF, 0x1A }, 632a994cbeSNickey Yang { 0xF0, 0x39 }, 642a994cbeSNickey Yang { 0xF1, 0x22 }, 652a994cbeSNickey Yang /* Gamma setting */ 662a994cbeSNickey Yang { 0xB0, 0x02 }, 672a994cbeSNickey Yang { 0xC0, 0x00 }, 682a994cbeSNickey Yang { 0xC1, 0x01 }, 692a994cbeSNickey Yang { 0xC2, 0x0B }, 702a994cbeSNickey Yang { 0xC3, 0x15 }, 712a994cbeSNickey Yang { 0xC4, 0x22 }, 722a994cbeSNickey Yang { 0xC5, 0x11 }, 732a994cbeSNickey Yang { 0xC6, 0x15 }, 742a994cbeSNickey Yang { 0xC7, 0x19 }, 752a994cbeSNickey Yang { 0xC8, 0x1A }, 762a994cbeSNickey Yang { 0xC9, 0x16 }, 772a994cbeSNickey Yang { 0xCA, 0x18 }, 782a994cbeSNickey Yang { 0xCB, 0x13 }, 792a994cbeSNickey Yang { 0xCC, 0x18 }, 802a994cbeSNickey Yang { 0xCD, 0x13 }, 812a994cbeSNickey Yang { 0xCE, 0x1C }, 822a994cbeSNickey Yang { 0xCF, 0x19 }, 832a994cbeSNickey Yang { 0xD0, 0x21 }, 842a994cbeSNickey Yang { 0xD1, 0x2C }, 852a994cbeSNickey Yang { 0xD2, 0x2F }, 862a994cbeSNickey Yang { 0xD3, 0x30 }, 872a994cbeSNickey Yang { 0xD4, 0x19 }, 882a994cbeSNickey Yang { 0xD5, 0x1F }, 892a994cbeSNickey Yang { 0xD6, 0x00 }, 902a994cbeSNickey Yang { 0xD7, 0x01 }, 912a994cbeSNickey Yang { 0xD8, 0x0B }, 922a994cbeSNickey Yang { 0xD9, 0x15 }, 932a994cbeSNickey Yang { 0xDA, 0x22 }, 942a994cbeSNickey Yang { 0xDB, 0x11 }, 952a994cbeSNickey Yang { 0xDC, 0x15 }, 962a994cbeSNickey Yang { 0xDD, 0x19 }, 972a994cbeSNickey Yang { 0xDE, 0x1A }, 982a994cbeSNickey Yang { 0xDF, 0x16 }, 992a994cbeSNickey Yang { 0xE0, 0x18 }, 1002a994cbeSNickey Yang { 0xE1, 0x13 }, 1012a994cbeSNickey Yang { 0xE2, 0x18 }, 1022a994cbeSNickey Yang { 0xE3, 0x13 }, 1032a994cbeSNickey Yang { 0xE4, 0x1C }, 1042a994cbeSNickey Yang { 0xE5, 0x19 }, 1052a994cbeSNickey Yang { 0xE6, 0x21 }, 1062a994cbeSNickey Yang { 0xE7, 0x2C }, 1072a994cbeSNickey Yang { 0xE8, 0x2F }, 1082a994cbeSNickey Yang { 0xE9, 0x30 }, 1092a994cbeSNickey Yang { 0xEA, 0x19 }, 1102a994cbeSNickey Yang { 0xEB, 0x1F }, 1112a994cbeSNickey Yang /* GOA MUX setting */ 1122a994cbeSNickey Yang { 0xB0, 0x01 }, 1132a994cbeSNickey Yang { 0xC0, 0x10 }, 1142a994cbeSNickey Yang { 0xC1, 0x0F }, 1152a994cbeSNickey Yang { 0xC2, 0x0E }, 1162a994cbeSNickey Yang { 0xC3, 0x0D }, 1172a994cbeSNickey Yang { 0xC4, 0x0C }, 1182a994cbeSNickey Yang { 0xC5, 0x0B }, 1192a994cbeSNickey Yang { 0xC6, 0x0A }, 1202a994cbeSNickey Yang { 0xC7, 0x09 }, 1212a994cbeSNickey Yang { 0xC8, 0x08 }, 1222a994cbeSNickey Yang { 0xC9, 0x07 }, 1232a994cbeSNickey Yang { 0xCA, 0x06 }, 1242a994cbeSNickey Yang { 0xCB, 0x05 }, 1252a994cbeSNickey Yang { 0xCC, 0x00 }, 1262a994cbeSNickey Yang { 0xCD, 0x01 }, 1272a994cbeSNickey Yang { 0xCE, 0x02 }, 1282a994cbeSNickey Yang { 0xCF, 0x03 }, 1292a994cbeSNickey Yang { 0xD0, 0x04 }, 1302a994cbeSNickey Yang { 0xD6, 0x10 }, 1312a994cbeSNickey Yang { 0xD7, 0x0F }, 1322a994cbeSNickey Yang { 0xD8, 0x0E }, 1332a994cbeSNickey Yang { 0xD9, 0x0D }, 1342a994cbeSNickey Yang { 0xDA, 0x0C }, 1352a994cbeSNickey Yang { 0xDB, 0x0B }, 1362a994cbeSNickey Yang { 0xDC, 0x0A }, 1372a994cbeSNickey Yang { 0xDD, 0x09 }, 1382a994cbeSNickey Yang { 0xDE, 0x08 }, 1392a994cbeSNickey Yang { 0xDF, 0x07 }, 1402a994cbeSNickey Yang { 0xE0, 0x06 }, 1412a994cbeSNickey Yang { 0xE1, 0x05 }, 1422a994cbeSNickey Yang { 0xE2, 0x00 }, 1432a994cbeSNickey Yang { 0xE3, 0x01 }, 1442a994cbeSNickey Yang { 0xE4, 0x02 }, 1452a994cbeSNickey Yang { 0xE5, 0x03 }, 1462a994cbeSNickey Yang { 0xE6, 0x04 }, 1472a994cbeSNickey Yang { 0xE7, 0x00 }, 1482a994cbeSNickey Yang { 0xEC, 0xC0 }, 1492a994cbeSNickey Yang /* GOA timing setting */ 1502a994cbeSNickey Yang { 0xB0, 0x03 }, 1512a994cbeSNickey Yang { 0xC0, 0x01 }, 1522a994cbeSNickey Yang { 0xC2, 0x6F }, 1532a994cbeSNickey Yang { 0xC3, 0x6F }, 1542a994cbeSNickey Yang { 0xC5, 0x36 }, 1552a994cbeSNickey Yang { 0xC8, 0x08 }, 1562a994cbeSNickey Yang { 0xC9, 0x04 }, 1572a994cbeSNickey Yang { 0xCA, 0x41 }, 1582a994cbeSNickey Yang { 0xCC, 0x43 }, 1592a994cbeSNickey Yang { 0xCF, 0x60 }, 1602a994cbeSNickey Yang { 0xD2, 0x04 }, 1612a994cbeSNickey Yang { 0xD3, 0x04 }, 1622a994cbeSNickey Yang { 0xD4, 0x03 }, 1632a994cbeSNickey Yang { 0xD5, 0x02 }, 1642a994cbeSNickey Yang { 0xD6, 0x01 }, 1652a994cbeSNickey Yang { 0xD7, 0x00 }, 1662a994cbeSNickey Yang { 0xDB, 0x01 }, 1672a994cbeSNickey Yang { 0xDE, 0x36 }, 1682a994cbeSNickey Yang { 0xE6, 0x6F }, 1692a994cbeSNickey Yang { 0xE7, 0x6F }, 1702a994cbeSNickey Yang /* GOE setting */ 1712a994cbeSNickey Yang { 0xB0, 0x06 }, 1722a994cbeSNickey Yang { 0xB8, 0xA5 }, 1732a994cbeSNickey Yang { 0xC0, 0xA5 }, 1742a994cbeSNickey Yang { 0xD5, 0x3F }, 1752a994cbeSNickey Yang }; 1762a994cbeSNickey Yang 1772a994cbeSNickey Yang static inline 1782a994cbeSNickey Yang struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel) 1792a994cbeSNickey Yang { 1802a994cbeSNickey Yang return container_of(panel, struct kingdisplay_panel, base); 1812a994cbeSNickey Yang } 1822a994cbeSNickey Yang 1832a994cbeSNickey Yang static int kingdisplay_panel_disable(struct drm_panel *panel) 1842a994cbeSNickey Yang { 1852a994cbeSNickey Yang struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 1862a994cbeSNickey Yang int err; 1872a994cbeSNickey Yang 1882a994cbeSNickey Yang if (!kingdisplay->enabled) 1892a994cbeSNickey Yang return 0; 1902a994cbeSNickey Yang 1912a994cbeSNickey Yang err = mipi_dsi_dcs_set_display_off(kingdisplay->link); 1922a994cbeSNickey Yang if (err < 0) 193*a25b6b27SSam Ravnborg dev_err(panel->dev, "failed to set display off: %d\n", err); 1942a994cbeSNickey Yang 1952a994cbeSNickey Yang kingdisplay->enabled = false; 1962a994cbeSNickey Yang 1972a994cbeSNickey Yang return 0; 1982a994cbeSNickey Yang } 1992a994cbeSNickey Yang 2002a994cbeSNickey Yang static int kingdisplay_panel_unprepare(struct drm_panel *panel) 2012a994cbeSNickey Yang { 2022a994cbeSNickey Yang struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 2032a994cbeSNickey Yang int err; 2042a994cbeSNickey Yang 2052a994cbeSNickey Yang if (!kingdisplay->prepared) 2062a994cbeSNickey Yang return 0; 2072a994cbeSNickey Yang 2082a994cbeSNickey Yang err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link); 2092a994cbeSNickey Yang if (err < 0) { 210*a25b6b27SSam Ravnborg dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); 2112a994cbeSNickey Yang return err; 2122a994cbeSNickey Yang } 2132a994cbeSNickey Yang 2142a994cbeSNickey Yang /* T15: 120ms */ 2152a994cbeSNickey Yang msleep(120); 2162a994cbeSNickey Yang 2172a994cbeSNickey Yang gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 2182a994cbeSNickey Yang 2192a994cbeSNickey Yang err = regulator_disable(kingdisplay->supply); 2202a994cbeSNickey Yang if (err < 0) 2212a994cbeSNickey Yang return err; 2222a994cbeSNickey Yang 2232a994cbeSNickey Yang kingdisplay->prepared = false; 2242a994cbeSNickey Yang 2252a994cbeSNickey Yang return 0; 2262a994cbeSNickey Yang } 2272a994cbeSNickey Yang 2282a994cbeSNickey Yang static int kingdisplay_panel_prepare(struct drm_panel *panel) 2292a994cbeSNickey Yang { 2302a994cbeSNickey Yang struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 2312a994cbeSNickey Yang int err, regulator_err; 2322a994cbeSNickey Yang unsigned int i; 2332a994cbeSNickey Yang 2342a994cbeSNickey Yang if (kingdisplay->prepared) 2352a994cbeSNickey Yang return 0; 2362a994cbeSNickey Yang 2372a994cbeSNickey Yang gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 2382a994cbeSNickey Yang 2392a994cbeSNickey Yang err = regulator_enable(kingdisplay->supply); 2402a994cbeSNickey Yang if (err < 0) 2412a994cbeSNickey Yang return err; 2422a994cbeSNickey Yang 2432a994cbeSNickey Yang /* T2: 15ms */ 2442a994cbeSNickey Yang usleep_range(15000, 16000); 2452a994cbeSNickey Yang 2462a994cbeSNickey Yang gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1); 2472a994cbeSNickey Yang 2482a994cbeSNickey Yang /* T4: 15ms */ 2492a994cbeSNickey Yang usleep_range(15000, 16000); 2502a994cbeSNickey Yang 2512a994cbeSNickey Yang for (i = 0; i < ARRAY_SIZE(init_code); i++) { 2522a994cbeSNickey Yang err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i], 2532a994cbeSNickey Yang sizeof(struct kingdisplay_panel_cmd)); 2542a994cbeSNickey Yang if (err < 0) { 255*a25b6b27SSam Ravnborg dev_err(panel->dev, "failed write init cmds: %d\n", err); 2562a994cbeSNickey Yang goto poweroff; 2572a994cbeSNickey Yang } 2582a994cbeSNickey Yang } 2592a994cbeSNickey Yang 2602a994cbeSNickey Yang err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link); 2612a994cbeSNickey Yang if (err < 0) { 262*a25b6b27SSam Ravnborg dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 2632a994cbeSNickey Yang goto poweroff; 2642a994cbeSNickey Yang } 2652a994cbeSNickey Yang 2662a994cbeSNickey Yang /* T6: 120ms */ 2672a994cbeSNickey Yang msleep(120); 2682a994cbeSNickey Yang 2692a994cbeSNickey Yang err = mipi_dsi_dcs_set_display_on(kingdisplay->link); 2702a994cbeSNickey Yang if (err < 0) { 271*a25b6b27SSam Ravnborg dev_err(panel->dev, "failed to set display on: %d\n", err); 2722a994cbeSNickey Yang goto poweroff; 2732a994cbeSNickey Yang } 2742a994cbeSNickey Yang 2752a994cbeSNickey Yang /* T7: 10ms */ 2762a994cbeSNickey Yang usleep_range(10000, 11000); 2772a994cbeSNickey Yang 2782a994cbeSNickey Yang kingdisplay->prepared = true; 2792a994cbeSNickey Yang 2802a994cbeSNickey Yang return 0; 2812a994cbeSNickey Yang 2822a994cbeSNickey Yang poweroff: 2832a994cbeSNickey Yang gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 2842a994cbeSNickey Yang 2852a994cbeSNickey Yang regulator_err = regulator_disable(kingdisplay->supply); 2862a994cbeSNickey Yang if (regulator_err) 287*a25b6b27SSam Ravnborg dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err); 2882a994cbeSNickey Yang 2892a994cbeSNickey Yang return err; 2902a994cbeSNickey Yang } 2912a994cbeSNickey Yang 2922a994cbeSNickey Yang static int kingdisplay_panel_enable(struct drm_panel *panel) 2932a994cbeSNickey Yang { 2942a994cbeSNickey Yang struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 2952a994cbeSNickey Yang 2962a994cbeSNickey Yang if (kingdisplay->enabled) 2972a994cbeSNickey Yang return 0; 2982a994cbeSNickey Yang 2992a994cbeSNickey Yang kingdisplay->enabled = true; 3002a994cbeSNickey Yang 3012a994cbeSNickey Yang return 0; 3022a994cbeSNickey Yang } 3032a994cbeSNickey Yang 3042a994cbeSNickey Yang static const struct drm_display_mode default_mode = { 3052a994cbeSNickey Yang .clock = 229000, 3062a994cbeSNickey Yang .hdisplay = 1536, 3072a994cbeSNickey Yang .hsync_start = 1536 + 100, 3082a994cbeSNickey Yang .hsync_end = 1536 + 100 + 24, 3092a994cbeSNickey Yang .htotal = 1536 + 100 + 24 + 100, 3102a994cbeSNickey Yang .vdisplay = 2048, 3112a994cbeSNickey Yang .vsync_start = 2048 + 95, 3122a994cbeSNickey Yang .vsync_end = 2048 + 95 + 2, 3132a994cbeSNickey Yang .vtotal = 2048 + 95 + 2 + 23, 3142a994cbeSNickey Yang }; 3152a994cbeSNickey Yang 3160ce8ddd8SSam Ravnborg static int kingdisplay_panel_get_modes(struct drm_panel *panel, 3170ce8ddd8SSam Ravnborg struct drm_connector *connector) 3182a994cbeSNickey Yang { 3192a994cbeSNickey Yang struct drm_display_mode *mode; 3202a994cbeSNickey Yang 321aa6c4364SSam Ravnborg mode = drm_mode_duplicate(connector->dev, &default_mode); 3222a994cbeSNickey Yang if (!mode) { 323*a25b6b27SSam Ravnborg dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 3242a994cbeSNickey Yang default_mode.hdisplay, default_mode.vdisplay, 3250425662fSVille Syrjälä drm_mode_vrefresh(&default_mode)); 3262a994cbeSNickey Yang return -ENOMEM; 3272a994cbeSNickey Yang } 3282a994cbeSNickey Yang 3292a994cbeSNickey Yang drm_mode_set_name(mode); 3302a994cbeSNickey Yang 3310ce8ddd8SSam Ravnborg drm_mode_probed_add(connector, mode); 3322a994cbeSNickey Yang 3330ce8ddd8SSam Ravnborg connector->display_info.width_mm = 147; 3340ce8ddd8SSam Ravnborg connector->display_info.height_mm = 196; 3350ce8ddd8SSam Ravnborg connector->display_info.bpc = 8; 3362a994cbeSNickey Yang 3372a994cbeSNickey Yang return 1; 3382a994cbeSNickey Yang } 3392a994cbeSNickey Yang 3402a994cbeSNickey Yang static const struct drm_panel_funcs kingdisplay_panel_funcs = { 3412a994cbeSNickey Yang .disable = kingdisplay_panel_disable, 3422a994cbeSNickey Yang .unprepare = kingdisplay_panel_unprepare, 3432a994cbeSNickey Yang .prepare = kingdisplay_panel_prepare, 3442a994cbeSNickey Yang .enable = kingdisplay_panel_enable, 3452a994cbeSNickey Yang .get_modes = kingdisplay_panel_get_modes, 3462a994cbeSNickey Yang }; 3472a994cbeSNickey Yang 3482a994cbeSNickey Yang static const struct of_device_id kingdisplay_of_match[] = { 3492a994cbeSNickey Yang { .compatible = "kingdisplay,kd097d04", }, 3502a994cbeSNickey Yang { } 3512a994cbeSNickey Yang }; 3522a994cbeSNickey Yang MODULE_DEVICE_TABLE(of, kingdisplay_of_match); 3532a994cbeSNickey Yang 3542a994cbeSNickey Yang static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay) 3552a994cbeSNickey Yang { 3562a994cbeSNickey Yang struct device *dev = &kingdisplay->link->dev; 3572a994cbeSNickey Yang int err; 3582a994cbeSNickey Yang 3592a994cbeSNickey Yang kingdisplay->supply = devm_regulator_get(dev, "power"); 3602a994cbeSNickey Yang if (IS_ERR(kingdisplay->supply)) 3612a994cbeSNickey Yang return PTR_ERR(kingdisplay->supply); 3622a994cbeSNickey Yang 3632a994cbeSNickey Yang kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable", 3642a994cbeSNickey Yang GPIOD_OUT_HIGH); 3652a994cbeSNickey Yang if (IS_ERR(kingdisplay->enable_gpio)) { 3662a994cbeSNickey Yang err = PTR_ERR(kingdisplay->enable_gpio); 3672a994cbeSNickey Yang dev_dbg(dev, "failed to get enable gpio: %d\n", err); 3682a994cbeSNickey Yang kingdisplay->enable_gpio = NULL; 3692a994cbeSNickey Yang } 3702a994cbeSNickey Yang 3716dbe0c4bSLaurent Pinchart drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev, 3729a2654c0SLaurent Pinchart &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI); 3732a994cbeSNickey Yang 3745fd14f28SSam Ravnborg err = drm_panel_of_backlight(&kingdisplay->base); 3755fd14f28SSam Ravnborg if (err) 3765fd14f28SSam Ravnborg return err; 3775fd14f28SSam Ravnborg 378c3ee8c65SBernard Zhao drm_panel_add(&kingdisplay->base); 379c3ee8c65SBernard Zhao 380c3ee8c65SBernard Zhao return 0; 3812a994cbeSNickey Yang } 3822a994cbeSNickey Yang 3832a994cbeSNickey Yang static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay) 3842a994cbeSNickey Yang { 3852a994cbeSNickey Yang drm_panel_remove(&kingdisplay->base); 3862a994cbeSNickey Yang } 3872a994cbeSNickey Yang 3882a994cbeSNickey Yang static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi) 3892a994cbeSNickey Yang { 3902a994cbeSNickey Yang struct kingdisplay_panel *kingdisplay; 3912a994cbeSNickey Yang int err; 3922a994cbeSNickey Yang 3932a994cbeSNickey Yang dsi->lanes = 4; 3942a994cbeSNickey Yang dsi->format = MIPI_DSI_FMT_RGB888; 3952a994cbeSNickey Yang dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 3962a994cbeSNickey Yang MIPI_DSI_MODE_LPM; 3972a994cbeSNickey Yang 3982a994cbeSNickey Yang kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL); 3992a994cbeSNickey Yang if (!kingdisplay) 4002a994cbeSNickey Yang return -ENOMEM; 4012a994cbeSNickey Yang 4022a994cbeSNickey Yang mipi_dsi_set_drvdata(dsi, kingdisplay); 4032a994cbeSNickey Yang kingdisplay->link = dsi; 4042a994cbeSNickey Yang 4052a994cbeSNickey Yang err = kingdisplay_panel_add(kingdisplay); 4062a994cbeSNickey Yang if (err < 0) 4072a994cbeSNickey Yang return err; 4082a994cbeSNickey Yang 4092a994cbeSNickey Yang return mipi_dsi_attach(dsi); 4102a994cbeSNickey Yang } 4112a994cbeSNickey Yang 4122a994cbeSNickey Yang static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi) 4132a994cbeSNickey Yang { 4142a994cbeSNickey Yang struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi); 4152a994cbeSNickey Yang int err; 4162a994cbeSNickey Yang 4175fd14f28SSam Ravnborg err = drm_panel_unprepare(&kingdisplay->base); 4182a994cbeSNickey Yang if (err < 0) 419*a25b6b27SSam Ravnborg dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); 4202a994cbeSNickey Yang 4215fd14f28SSam Ravnborg err = drm_panel_disable(&kingdisplay->base); 4222a994cbeSNickey Yang if (err < 0) 423*a25b6b27SSam Ravnborg dev_err(&dsi->dev, "failed to disable panel: %d\n", err); 4242a994cbeSNickey Yang 4252a994cbeSNickey Yang err = mipi_dsi_detach(dsi); 4262a994cbeSNickey Yang if (err < 0) 427*a25b6b27SSam Ravnborg dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); 4282a994cbeSNickey Yang 4292a994cbeSNickey Yang kingdisplay_panel_del(kingdisplay); 4302a994cbeSNickey Yang 4312a994cbeSNickey Yang return 0; 4322a994cbeSNickey Yang } 4332a994cbeSNickey Yang 4342a994cbeSNickey Yang static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi) 4352a994cbeSNickey Yang { 4362a994cbeSNickey Yang struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi); 4372a994cbeSNickey Yang 4385fd14f28SSam Ravnborg drm_panel_unprepare(&kingdisplay->base); 4395fd14f28SSam Ravnborg drm_panel_disable(&kingdisplay->base); 4402a994cbeSNickey Yang } 4412a994cbeSNickey Yang 4422a994cbeSNickey Yang static struct mipi_dsi_driver kingdisplay_panel_driver = { 4432a994cbeSNickey Yang .driver = { 4442a994cbeSNickey Yang .name = "panel-kingdisplay-kd097d04", 4452a994cbeSNickey Yang .of_match_table = kingdisplay_of_match, 4462a994cbeSNickey Yang }, 4472a994cbeSNickey Yang .probe = kingdisplay_panel_probe, 4482a994cbeSNickey Yang .remove = kingdisplay_panel_remove, 4492a994cbeSNickey Yang .shutdown = kingdisplay_panel_shutdown, 4502a994cbeSNickey Yang }; 4512a994cbeSNickey Yang module_mipi_dsi_driver(kingdisplay_panel_driver); 4522a994cbeSNickey Yang 4532a994cbeSNickey Yang MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); 4542a994cbeSNickey Yang MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>"); 4552a994cbeSNickey Yang MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver"); 4562a994cbeSNickey Yang MODULE_LICENSE("GPL v2"); 457