Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/panel: Add driver for JDI LPM102A188A

The JDI LPM102A188A is a 2560x1800 IPS panel found in the Google Pixel C.
This driver is based on the downstream GPLv2 driver released by Google
written by Sean Paul [1], which was then adapted to the newer kernel APIs.

[1]: https://android.googlesource.com/kernel/tegra/+/refs/heads/android-tegra-dragon-3.18-oreo/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c

Signed-off-by: Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230807133307.27456-3-diogo.ivo@tecnico.ulisboa.pt

authored by

Diogo Ivo and committed by
Neil Armstrong
25205087 a913a739

+563
+11
drivers/gpu/drm/panel/Kconfig
··· 244 244 The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses 245 245 24 bit per pixel. 246 246 247 + config DRM_PANEL_JDI_LPM102A188A 248 + tristate "JDI LPM102A188A DSI panel" 249 + depends on OF && GPIOLIB 250 + depends on DRM_MIPI_DSI 251 + depends on BACKLIGHT_CLASS_DEVICE 252 + help 253 + Say Y here if you want to enable support for JDI LPM102A188A DSI 254 + command mode panel as found in Google Pixel C devices. 255 + The panel has a 2560×1800 resolution. It provides a MIPI DSI interface 256 + to the host. 257 + 247 258 config DRM_PANEL_JDI_R63452 248 259 tristate "JDI R63452 Full HD DSI panel" 249 260 depends on OF
+1
drivers/gpu/drm/panel/Makefile
··· 22 22 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o 23 23 obj-$(CONFIG_DRM_PANEL_JADARD_JD9365DA_H3) += panel-jadard-jd9365da-h3.o 24 24 obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o 25 + obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += panel-jdi-lpm102a188a.o 25 26 obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o 26 27 obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o 27 28 obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
+551
drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2014 Google, Inc. 4 + * 5 + * Copyright (C) 2022 Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt> 6 + * 7 + * Adapted from the downstream Pixel C driver written by Sean Paul 8 + */ 9 + 10 + #include <linux/backlight.h> 11 + #include <linux/delay.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/regulator/consumer.h> 16 + 17 + #include <video/mipi_display.h> 18 + 19 + #include <drm/drm_crtc.h> 20 + #include <drm/drm_mipi_dsi.h> 21 + #include <drm/drm_panel.h> 22 + 23 + #define MCS_CMD_ACS_PROT 0xB0 24 + #define MCS_CMD_ACS_PROT_OFF (0 << 0) 25 + 26 + #define MCS_PWR_CTRL_FUNC 0xD0 27 + #define MCS_PWR_CTRL_PARAM1_DEFAULT (2 << 0) 28 + #define MCS_PWR_CTRL_PARAM1_VGH_210_DIV (1 << 4) 29 + #define MCS_PWR_CTRL_PARAM1_VGH_240_DIV (2 << 4) 30 + #define MCS_PWR_CTRL_PARAM1_VGH_280_DIV (3 << 4) 31 + #define MCS_PWR_CTRL_PARAM1_VGH_330_DIV (4 << 4) 32 + #define MCS_PWR_CTRL_PARAM1_VGH_410_DIV (5 << 4) 33 + #define MCS_PWR_CTRL_PARAM2_DEFAULT (9 << 4) 34 + #define MCS_PWR_CTRL_PARAM2_VGL_210_DIV (1 << 0) 35 + #define MCS_PWR_CTRL_PARAM2_VGL_240_DIV (2 << 0) 36 + #define MCS_PWR_CTRL_PARAM2_VGL_280_DIV (3 << 0) 37 + #define MCS_PWR_CTRL_PARAM2_VGL_330_DIV (4 << 0) 38 + #define MCS_PWR_CTRL_PARAM2_VGL_410_DIV (5 << 0) 39 + 40 + struct jdi_panel { 41 + struct drm_panel base; 42 + struct mipi_dsi_device *link1; 43 + struct mipi_dsi_device *link2; 44 + 45 + struct regulator *supply; 46 + struct regulator *ddi_supply; 47 + struct backlight_device *backlight; 48 + 49 + struct gpio_desc *enable_gpio; 50 + struct gpio_desc *reset_gpio; 51 + 52 + const struct drm_display_mode *mode; 53 + }; 54 + 55 + static inline struct jdi_panel *to_panel_jdi(struct drm_panel *panel) 56 + { 57 + return container_of(panel, struct jdi_panel, base); 58 + } 59 + 60 + static void jdi_wait_frames(struct jdi_panel *jdi, unsigned int frames) 61 + { 62 + unsigned int refresh = drm_mode_vrefresh(jdi->mode); 63 + 64 + if (WARN_ON(frames > refresh)) 65 + return; 66 + 67 + msleep(1000 / (refresh / frames)); 68 + } 69 + 70 + static int jdi_panel_disable(struct drm_panel *panel) 71 + { 72 + struct jdi_panel *jdi = to_panel_jdi(panel); 73 + 74 + backlight_disable(jdi->backlight); 75 + 76 + jdi_wait_frames(jdi, 2); 77 + 78 + return 0; 79 + } 80 + 81 + static int jdi_panel_unprepare(struct drm_panel *panel) 82 + { 83 + struct jdi_panel *jdi = to_panel_jdi(panel); 84 + int ret; 85 + 86 + ret = mipi_dsi_dcs_set_display_off(jdi->link1); 87 + if (ret < 0) 88 + dev_err(panel->dev, "failed to set display off: %d\n", ret); 89 + 90 + ret = mipi_dsi_dcs_set_display_off(jdi->link2); 91 + if (ret < 0) 92 + dev_err(panel->dev, "failed to set display off: %d\n", ret); 93 + 94 + /* Specified by JDI @ 50ms, subject to change */ 95 + msleep(50); 96 + 97 + ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link1); 98 + if (ret < 0) 99 + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); 100 + ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link2); 101 + if (ret < 0) 102 + dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); 103 + 104 + /* Specified by JDI @ 150ms, subject to change */ 105 + msleep(150); 106 + 107 + gpiod_set_value(jdi->reset_gpio, 1); 108 + 109 + /* T4 = 1ms */ 110 + usleep_range(1000, 3000); 111 + 112 + gpiod_set_value(jdi->enable_gpio, 0); 113 + 114 + /* T5 = 2ms */ 115 + usleep_range(2000, 4000); 116 + 117 + regulator_disable(jdi->ddi_supply); 118 + 119 + /* T6 = 2ms plus some time to discharge capacitors */ 120 + usleep_range(7000, 9000); 121 + 122 + regulator_disable(jdi->supply); 123 + /* Specified by JDI @ 20ms, subject to change */ 124 + msleep(20); 125 + 126 + return ret; 127 + } 128 + 129 + static int jdi_setup_symmetrical_split(struct mipi_dsi_device *left, 130 + struct mipi_dsi_device *right, 131 + const struct drm_display_mode *mode) 132 + { 133 + int err; 134 + 135 + err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1); 136 + if (err < 0) { 137 + dev_err(&left->dev, "failed to set column address: %d\n", err); 138 + return err; 139 + } 140 + 141 + err = mipi_dsi_dcs_set_column_address(right, 0, mode->hdisplay / 2 - 1); 142 + if (err < 0) { 143 + dev_err(&right->dev, "failed to set column address: %d\n", err); 144 + return err; 145 + } 146 + 147 + err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1); 148 + if (err < 0) { 149 + dev_err(&left->dev, "failed to set page address: %d\n", err); 150 + return err; 151 + } 152 + 153 + err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1); 154 + if (err < 0) { 155 + dev_err(&right->dev, "failed to set page address: %d\n", err); 156 + return err; 157 + } 158 + 159 + return 0; 160 + } 161 + 162 + static int jdi_write_dcdc_registers(struct jdi_panel *jdi) 163 + { 164 + /* Clear the manufacturer command access protection */ 165 + mipi_dsi_generic_write_seq(jdi->link1, MCS_CMD_ACS_PROT, 166 + MCS_CMD_ACS_PROT_OFF); 167 + mipi_dsi_generic_write_seq(jdi->link2, MCS_CMD_ACS_PROT, 168 + MCS_CMD_ACS_PROT_OFF); 169 + /* 170 + * Change the VGH/VGL divide rations to move the noise generated by the 171 + * TCONN. This should hopefully avoid interaction with the backlight 172 + * controller. 173 + */ 174 + mipi_dsi_generic_write_seq(jdi->link1, MCS_PWR_CTRL_FUNC, 175 + MCS_PWR_CTRL_PARAM1_VGH_330_DIV | 176 + MCS_PWR_CTRL_PARAM1_DEFAULT, 177 + MCS_PWR_CTRL_PARAM2_VGL_410_DIV | 178 + MCS_PWR_CTRL_PARAM2_DEFAULT); 179 + 180 + mipi_dsi_generic_write_seq(jdi->link2, MCS_PWR_CTRL_FUNC, 181 + MCS_PWR_CTRL_PARAM1_VGH_330_DIV | 182 + MCS_PWR_CTRL_PARAM1_DEFAULT, 183 + MCS_PWR_CTRL_PARAM2_VGL_410_DIV | 184 + MCS_PWR_CTRL_PARAM2_DEFAULT); 185 + 186 + return 0; 187 + } 188 + 189 + static int jdi_panel_prepare(struct drm_panel *panel) 190 + { 191 + struct jdi_panel *jdi = to_panel_jdi(panel); 192 + int err; 193 + 194 + /* Disable backlight to avoid showing random pixels 195 + * with a conservative delay for it to take effect. 196 + */ 197 + backlight_disable(jdi->backlight); 198 + jdi_wait_frames(jdi, 3); 199 + 200 + jdi->link1->mode_flags |= MIPI_DSI_MODE_LPM; 201 + jdi->link2->mode_flags |= MIPI_DSI_MODE_LPM; 202 + 203 + err = regulator_enable(jdi->supply); 204 + if (err < 0) { 205 + dev_err(panel->dev, "failed to enable supply: %d\n", err); 206 + return err; 207 + } 208 + /* T1 = 2ms */ 209 + usleep_range(2000, 4000); 210 + 211 + err = regulator_enable(jdi->ddi_supply); 212 + if (err < 0) { 213 + dev_err(panel->dev, "failed to enable ddi_supply: %d\n", err); 214 + goto supply_off; 215 + } 216 + /* T2 = 1ms */ 217 + usleep_range(1000, 3000); 218 + 219 + gpiod_set_value(jdi->enable_gpio, 1); 220 + /* T3 = 10ms */ 221 + usleep_range(10000, 15000); 222 + 223 + gpiod_set_value(jdi->reset_gpio, 0); 224 + /* Specified by JDI @ 3ms, subject to change */ 225 + usleep_range(3000, 5000); 226 + 227 + /* 228 + * TODO: The device supports both left-right and even-odd split 229 + * configurations, but this driver currently supports only the left- 230 + * right split. To support a different mode a mechanism needs to be 231 + * put in place to communicate the configuration back to the DSI host 232 + * controller. 233 + */ 234 + err = jdi_setup_symmetrical_split(jdi->link1, jdi->link2, 235 + jdi->mode); 236 + if (err < 0) { 237 + dev_err(panel->dev, "failed to set up symmetrical split: %d\n", 238 + err); 239 + goto poweroff; 240 + } 241 + 242 + err = mipi_dsi_dcs_set_tear_scanline(jdi->link1, 243 + jdi->mode->vdisplay - 16); 244 + if (err < 0) { 245 + dev_err(panel->dev, "failed to set tear scanline: %d\n", err); 246 + goto poweroff; 247 + } 248 + 249 + err = mipi_dsi_dcs_set_tear_scanline(jdi->link2, 250 + jdi->mode->vdisplay - 16); 251 + if (err < 0) { 252 + dev_err(panel->dev, "failed to set tear scanline: %d\n", err); 253 + goto poweroff; 254 + } 255 + 256 + err = mipi_dsi_dcs_set_tear_on(jdi->link1, 257 + MIPI_DSI_DCS_TEAR_MODE_VBLANK); 258 + if (err < 0) { 259 + dev_err(panel->dev, "failed to set tear on: %d\n", err); 260 + goto poweroff; 261 + } 262 + 263 + err = mipi_dsi_dcs_set_tear_on(jdi->link2, 264 + MIPI_DSI_DCS_TEAR_MODE_VBLANK); 265 + if (err < 0) { 266 + dev_err(panel->dev, "failed to set tear on: %d\n", err); 267 + goto poweroff; 268 + } 269 + 270 + err = mipi_dsi_dcs_set_pixel_format(jdi->link1, MIPI_DCS_PIXEL_FMT_24BIT); 271 + if (err < 0) { 272 + dev_err(panel->dev, "failed to set pixel format: %d\n", err); 273 + goto poweroff; 274 + } 275 + 276 + err = mipi_dsi_dcs_set_pixel_format(jdi->link2, MIPI_DCS_PIXEL_FMT_24BIT); 277 + if (err < 0) { 278 + dev_err(panel->dev, "failed to set pixel format: %d\n", err); 279 + goto poweroff; 280 + } 281 + 282 + err = mipi_dsi_dcs_exit_sleep_mode(jdi->link1); 283 + if (err < 0) { 284 + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 285 + goto poweroff; 286 + } 287 + 288 + err = mipi_dsi_dcs_exit_sleep_mode(jdi->link2); 289 + if (err < 0) { 290 + dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 291 + goto poweroff; 292 + } 293 + 294 + err = jdi_write_dcdc_registers(jdi); 295 + if (err < 0) { 296 + dev_err(panel->dev, "failed to write dcdc registers: %d\n", err); 297 + goto poweroff; 298 + } 299 + /* 300 + * We need to wait 150ms between mipi_dsi_dcs_exit_sleep_mode() and 301 + * mipi_dsi_dcs_set_display_on(). 302 + */ 303 + msleep(150); 304 + 305 + err = mipi_dsi_dcs_set_display_on(jdi->link1); 306 + if (err < 0) { 307 + dev_err(panel->dev, "failed to set display on: %d\n", err); 308 + goto poweroff; 309 + } 310 + 311 + err = mipi_dsi_dcs_set_display_on(jdi->link2); 312 + if (err < 0) { 313 + dev_err(panel->dev, "failed to set display on: %d\n", err); 314 + goto poweroff; 315 + } 316 + 317 + jdi->link1->mode_flags &= ~MIPI_DSI_MODE_LPM; 318 + jdi->link2->mode_flags &= ~MIPI_DSI_MODE_LPM; 319 + 320 + return 0; 321 + 322 + poweroff: 323 + regulator_disable(jdi->ddi_supply); 324 + 325 + /* T6 = 2ms plus some time to discharge capacitors */ 326 + usleep_range(7000, 9000); 327 + supply_off: 328 + regulator_disable(jdi->supply); 329 + /* Specified by JDI @ 20ms, subject to change */ 330 + msleep(20); 331 + 332 + return err; 333 + } 334 + 335 + static int jdi_panel_enable(struct drm_panel *panel) 336 + { 337 + struct jdi_panel *jdi = to_panel_jdi(panel); 338 + 339 + /* 340 + * Ensure we send image data before turning the backlight 341 + * on, to avoid the display showing random pixels. 342 + */ 343 + jdi_wait_frames(jdi, 3); 344 + 345 + backlight_enable(jdi->backlight); 346 + 347 + return 0; 348 + } 349 + 350 + static const struct drm_display_mode default_mode = { 351 + .clock = (2560 + 80 + 80 + 80) * (1800 + 4 + 4 + 4) * 60 / 1000, 352 + .hdisplay = 2560, 353 + .hsync_start = 2560 + 80, 354 + .hsync_end = 2560 + 80 + 80, 355 + .htotal = 2560 + 80 + 80 + 80, 356 + .vdisplay = 1800, 357 + .vsync_start = 1800 + 4, 358 + .vsync_end = 1800 + 4 + 4, 359 + .vtotal = 1800 + 4 + 4 + 4, 360 + .flags = 0, 361 + }; 362 + 363 + static int jdi_panel_get_modes(struct drm_panel *panel, 364 + struct drm_connector *connector) 365 + { 366 + struct drm_display_mode *mode; 367 + struct jdi_panel *jdi = to_panel_jdi(panel); 368 + struct device *dev = &jdi->link1->dev; 369 + 370 + mode = drm_mode_duplicate(connector->dev, &default_mode); 371 + if (!mode) { 372 + dev_err(dev, "failed to add mode %ux%ux@%u\n", 373 + default_mode.hdisplay, default_mode.vdisplay, 374 + drm_mode_vrefresh(&default_mode)); 375 + return -ENOMEM; 376 + } 377 + 378 + drm_mode_set_name(mode); 379 + 380 + drm_mode_probed_add(connector, mode); 381 + 382 + connector->display_info.width_mm = 211; 383 + connector->display_info.height_mm = 148; 384 + connector->display_info.bpc = 8; 385 + 386 + return 1; 387 + } 388 + 389 + static const struct drm_panel_funcs jdi_panel_funcs = { 390 + .prepare = jdi_panel_prepare, 391 + .enable = jdi_panel_enable, 392 + .disable = jdi_panel_disable, 393 + .unprepare = jdi_panel_unprepare, 394 + .get_modes = jdi_panel_get_modes, 395 + }; 396 + 397 + static const struct of_device_id jdi_of_match[] = { 398 + { .compatible = "jdi,lpm102a188a", }, 399 + { } 400 + }; 401 + MODULE_DEVICE_TABLE(of, jdi_of_match); 402 + 403 + static int jdi_panel_add(struct jdi_panel *jdi) 404 + { 405 + struct device *dev = &jdi->link1->dev; 406 + 407 + jdi->mode = &default_mode; 408 + 409 + jdi->supply = devm_regulator_get(dev, "power"); 410 + if (IS_ERR(jdi->supply)) 411 + return dev_err_probe(dev, PTR_ERR(jdi->supply), 412 + "failed to get power regulator\n"); 413 + 414 + jdi->ddi_supply = devm_regulator_get(dev, "ddi"); 415 + if (IS_ERR(jdi->ddi_supply)) 416 + return dev_err_probe(dev, PTR_ERR(jdi->ddi_supply), 417 + "failed to get ddi regulator\n"); 418 + 419 + jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 420 + if (IS_ERR(jdi->reset_gpio)) 421 + return dev_err_probe(dev, PTR_ERR(jdi->reset_gpio), 422 + "failed to get reset gpio\n"); 423 + /* T4 = 1ms */ 424 + usleep_range(1000, 3000); 425 + 426 + jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 427 + if (IS_ERR(jdi->enable_gpio)) 428 + return dev_err_probe(dev, PTR_ERR(jdi->enable_gpio), 429 + "failed to get enable gpio\n"); 430 + /* T5 = 2ms */ 431 + usleep_range(2000, 4000); 432 + 433 + jdi->backlight = devm_of_find_backlight(dev); 434 + if (IS_ERR(jdi->backlight)) 435 + return dev_err_probe(dev, PTR_ERR(jdi->backlight), 436 + "failed to create backlight\n"); 437 + 438 + drm_panel_init(&jdi->base, &jdi->link1->dev, &jdi_panel_funcs, 439 + DRM_MODE_CONNECTOR_DSI); 440 + 441 + drm_panel_add(&jdi->base); 442 + 443 + return 0; 444 + } 445 + 446 + static void jdi_panel_del(struct jdi_panel *jdi) 447 + { 448 + if (jdi->base.dev) 449 + drm_panel_remove(&jdi->base); 450 + 451 + if (jdi->link2) 452 + put_device(&jdi->link2->dev); 453 + } 454 + 455 + static int jdi_panel_dsi_probe(struct mipi_dsi_device *dsi) 456 + { 457 + struct mipi_dsi_device *secondary = NULL; 458 + struct jdi_panel *jdi; 459 + struct device_node *np; 460 + int err; 461 + 462 + dsi->lanes = 4; 463 + dsi->format = MIPI_DSI_FMT_RGB888; 464 + dsi->mode_flags = 0; 465 + 466 + /* Find DSI-LINK1 */ 467 + np = of_parse_phandle(dsi->dev.of_node, "link2", 0); 468 + if (np) { 469 + secondary = of_find_mipi_dsi_device_by_node(np); 470 + of_node_put(np); 471 + 472 + if (!secondary) 473 + return -EPROBE_DEFER; 474 + } 475 + 476 + /* register a panel for only the DSI-LINK1 interface */ 477 + if (secondary) { 478 + jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL); 479 + if (!jdi) { 480 + put_device(&secondary->dev); 481 + return -ENOMEM; 482 + } 483 + 484 + mipi_dsi_set_drvdata(dsi, jdi); 485 + 486 + jdi->link1 = dsi; 487 + jdi->link2 = secondary; 488 + 489 + err = jdi_panel_add(jdi); 490 + if (err < 0) { 491 + put_device(&secondary->dev); 492 + return err; 493 + } 494 + } 495 + 496 + err = mipi_dsi_attach(dsi); 497 + if (err < 0) { 498 + if (secondary) 499 + jdi_panel_del(jdi); 500 + 501 + return err; 502 + } 503 + 504 + return 0; 505 + } 506 + 507 + static void jdi_panel_dsi_remove(struct mipi_dsi_device *dsi) 508 + { 509 + struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); 510 + int err; 511 + 512 + /* only detach from host for the DSI-LINK2 interface */ 513 + if (!jdi) 514 + mipi_dsi_detach(dsi); 515 + 516 + err = jdi_panel_disable(&jdi->base); 517 + if (err < 0) 518 + dev_err(&dsi->dev, "failed to disable panel: %d\n", err); 519 + 520 + err = mipi_dsi_detach(dsi); 521 + if (err < 0) 522 + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); 523 + 524 + jdi_panel_del(jdi); 525 + } 526 + 527 + static void jdi_panel_dsi_shutdown(struct mipi_dsi_device *dsi) 528 + { 529 + struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); 530 + 531 + if (!jdi) 532 + return; 533 + 534 + jdi_panel_disable(&jdi->base); 535 + } 536 + 537 + static struct mipi_dsi_driver jdi_panel_dsi_driver = { 538 + .driver = { 539 + .name = "panel-jdi-lpm102a188a", 540 + .of_match_table = jdi_of_match, 541 + }, 542 + .probe = jdi_panel_dsi_probe, 543 + .remove = jdi_panel_dsi_remove, 544 + .shutdown = jdi_panel_dsi_shutdown, 545 + }; 546 + module_mipi_dsi_driver(jdi_panel_dsi_driver); 547 + 548 + MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>"); 549 + MODULE_AUTHOR("Diogo Ivo <diogo.ivo@tecnico.ulisboa.pt>"); 550 + MODULE_DESCRIPTION("DRM Driver for JDI LPM102A188A DSI panel, command mode"); 551 + MODULE_LICENSE("GPL");