1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Novatek NT35950 DriverIC panels driver 4 * 5 * Copyright (c) 2021 AngeloGioacchino Del Regno 6 * <angelogioacchino.delregno@somainline.org> 7 */ 8 #include <linux/delay.h> 9 #include <linux/gpio/consumer.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/of_graph.h> 13 #include <linux/regulator/consumer.h> 14 15 #include <drm/drm_connector.h> 16 #include <drm/drm_crtc.h> 17 #include <drm/drm_mipi_dsi.h> 18 #include <drm/drm_modes.h> 19 #include <drm/drm_panel.h> 20 21 #define MCS_CMD_MAUCCTR 0xf0 /* Manufacturer command enable */ 22 #define MCS_PARAM_SCALER_FUNCTION 0x58 /* Scale-up function */ 23 #define MCS_PARAM_SCALEUP_MODE 0xc9 24 #define MCS_SCALEUP_SIMPLE 0x0 25 #define MCS_SCALEUP_BILINEAR BIT(0) 26 #define MCS_SCALEUP_DUPLICATE (BIT(0) | BIT(4)) 27 28 /* VESA Display Stream Compression param */ 29 #define MCS_PARAM_VESA_DSC_ON 0x03 30 31 /* Data Compression mode */ 32 #define MCS_PARAM_DATA_COMPRESSION 0x90 33 #define MCS_DATA_COMPRESSION_NONE 0x00 34 #define MCS_DATA_COMPRESSION_FBC 0x02 35 #define MCS_DATA_COMPRESSION_DSC 0x03 36 37 /* Display Output control */ 38 #define MCS_PARAM_DISP_OUTPUT_CTRL 0xb4 39 #define MCS_DISP_OUT_SRAM_EN BIT(0) 40 #define MCS_DISP_OUT_VIDEO_MODE BIT(4) 41 42 /* VESA Display Stream Compression setting */ 43 #define MCS_PARAM_VESA_DSC_SETTING 0xc0 44 45 /* SubPixel Rendering (SPR) */ 46 #define MCS_PARAM_SPR_EN 0xe3 47 #define MCS_PARAM_SPR_MODE 0xef 48 #define MCS_SPR_MODE_YYG_RAINBOW_RGB 0x01 49 50 #define NT35950_VREG_MAX 4 51 52 struct nt35950 { 53 struct drm_panel panel; 54 struct drm_connector *connector; 55 struct mipi_dsi_device *dsi[2]; 56 struct regulator_bulk_data vregs[NT35950_VREG_MAX]; 57 struct gpio_desc *reset_gpio; 58 const struct nt35950_panel_desc *desc; 59 60 int cur_mode; 61 u8 last_page; 62 }; 63 64 struct nt35950_panel_mode { 65 const struct drm_display_mode mode; 66 67 bool enable_sram; 68 bool is_video_mode; 69 u8 scaler_on; 70 u8 scaler_mode; 71 u8 compression; 72 u8 spr_en; 73 u8 spr_mode; 74 }; 75 76 struct nt35950_panel_desc { 77 const char *model_name; 78 const struct mipi_dsi_device_info dsi_info; 79 const struct nt35950_panel_mode *mode_data; 80 81 bool is_dual_dsi; 82 u8 num_lanes; 83 u8 num_modes; 84 }; 85 86 static inline struct nt35950 *to_nt35950(struct drm_panel *panel) 87 { 88 return container_of(panel, struct nt35950, panel); 89 } 90 91 static void nt35950_reset(struct nt35950 *nt) 92 { 93 gpiod_set_value_cansleep(nt->reset_gpio, 1); 94 usleep_range(12000, 13000); 95 gpiod_set_value_cansleep(nt->reset_gpio, 0); 96 usleep_range(300, 400); 97 gpiod_set_value_cansleep(nt->reset_gpio, 1); 98 usleep_range(12000, 13000); 99 } 100 101 /* 102 * nt35950_set_cmd2_page - Select manufacturer control (CMD2) page 103 * @nt: Main driver structure 104 * @page: Page number (0-7) 105 * 106 * Return: Number of transferred bytes or negative number on error 107 */ 108 static int nt35950_set_cmd2_page(struct nt35950 *nt, u8 page) 109 { 110 const u8 mauc_cmd2_page[] = { MCS_CMD_MAUCCTR, 0x55, 0xaa, 0x52, 111 0x08, page }; 112 int ret; 113 114 ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], mauc_cmd2_page, 115 ARRAY_SIZE(mauc_cmd2_page)); 116 if (ret < 0) 117 return ret; 118 119 nt->last_page = page; 120 return 0; 121 } 122 123 /* 124 * nt35950_set_data_compression - Set data compression mode 125 * @nt: Main driver structure 126 * @comp_mode: Compression mode 127 * 128 * Return: Number of transferred bytes or negative number on error 129 */ 130 static int nt35950_set_data_compression(struct nt35950 *nt, u8 comp_mode) 131 { 132 u8 cmd_data_compression[] = { MCS_PARAM_DATA_COMPRESSION, comp_mode }; 133 u8 cmd_vesa_dsc_on[] = { MCS_PARAM_VESA_DSC_ON, !!comp_mode }; 134 u8 cmd_vesa_dsc_setting[] = { MCS_PARAM_VESA_DSC_SETTING, 0x03 }; 135 u8 last_page = nt->last_page; 136 int ret; 137 138 /* Set CMD2 Page 0 if we're not there yet */ 139 if (last_page != 0) { 140 ret = nt35950_set_cmd2_page(nt, 0); 141 if (ret < 0) 142 return ret; 143 } 144 145 ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_data_compression, 146 ARRAY_SIZE(cmd_data_compression)); 147 if (ret < 0) 148 return ret; 149 150 ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_on, 151 ARRAY_SIZE(cmd_vesa_dsc_on)); 152 if (ret < 0) 153 return ret; 154 155 /* Set the vesa dsc setting on Page 4 */ 156 ret = nt35950_set_cmd2_page(nt, 4); 157 if (ret < 0) 158 return ret; 159 160 /* Display Stream Compression setting, always 0x03 */ 161 ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_setting, 162 ARRAY_SIZE(cmd_vesa_dsc_setting)); 163 if (ret < 0) 164 return ret; 165 166 /* Get back to the previously set page */ 167 return nt35950_set_cmd2_page(nt, last_page); 168 } 169 170 /* 171 * nt35950_set_scaler - Enable/disable resolution upscaling 172 * @nt: Main driver structure 173 * @scale_up: Scale up function control 174 * 175 * Return: Number of transferred bytes or negative number on error 176 */ 177 static int nt35950_set_scaler(struct nt35950 *nt, u8 scale_up) 178 { 179 u8 cmd_scaler[] = { MCS_PARAM_SCALER_FUNCTION, scale_up }; 180 181 return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler, 182 ARRAY_SIZE(cmd_scaler)); 183 } 184 185 /* 186 * nt35950_set_scale_mode - Resolution upscaling mode 187 * @nt: Main driver structure 188 * @mode: Scaler mode (MCS_DATA_COMPRESSION_*) 189 * 190 * Return: Number of transferred bytes or negative number on error 191 */ 192 static int nt35950_set_scale_mode(struct nt35950 *nt, u8 mode) 193 { 194 u8 cmd_scaler[] = { MCS_PARAM_SCALEUP_MODE, mode }; 195 196 return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler, 197 ARRAY_SIZE(cmd_scaler)); 198 } 199 200 /* 201 * nt35950_inject_black_image - Display a completely black image 202 * @nt: Main driver structure 203 * 204 * After IC setup, the attached panel may show random data 205 * due to driveric behavior changes (resolution, compression, 206 * scaling, etc). This function, called after parameters setup, 207 * makes the driver ic to output a completely black image to 208 * the display. 209 * It makes sense to push a black image before sending the sleep-out 210 * and display-on commands. 211 * 212 * Return: Number of transferred bytes or negative number on error 213 */ 214 static int nt35950_inject_black_image(struct nt35950 *nt) 215 { 216 const u8 cmd0_black_img[] = { 0x6f, 0x01 }; 217 const u8 cmd1_black_img[] = { 0xf3, 0x10 }; 218 u8 cmd_test[] = { 0xff, 0xaa, 0x55, 0xa5, 0x80 }; 219 int ret; 220 221 /* Enable test command */ 222 ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test)); 223 if (ret < 0) 224 return ret; 225 226 /* Send a black image */ 227 ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd0_black_img, 228 ARRAY_SIZE(cmd0_black_img)); 229 if (ret < 0) 230 return ret; 231 ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd1_black_img, 232 ARRAY_SIZE(cmd1_black_img)); 233 if (ret < 0) 234 return ret; 235 236 /* Disable test command */ 237 cmd_test[ARRAY_SIZE(cmd_test) - 1] = 0x00; 238 return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test)); 239 } 240 241 /* 242 * nt35950_set_dispout - Set Display Output register parameters 243 * @nt: Main driver structure 244 * 245 * Return: Number of transferred bytes or negative number on error 246 */ 247 static int nt35950_set_dispout(struct nt35950 *nt) 248 { 249 u8 cmd_dispout[] = { MCS_PARAM_DISP_OUTPUT_CTRL, 0x00 }; 250 const struct nt35950_panel_mode *mode_data = nt->desc->mode_data; 251 252 if (mode_data[nt->cur_mode].is_video_mode) 253 cmd_dispout[1] |= MCS_DISP_OUT_VIDEO_MODE; 254 if (mode_data[nt->cur_mode].enable_sram) 255 cmd_dispout[1] |= MCS_DISP_OUT_SRAM_EN; 256 257 return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_dispout, 258 ARRAY_SIZE(cmd_dispout)); 259 } 260 261 static int nt35950_get_current_mode(struct nt35950 *nt) 262 { 263 struct drm_connector *connector = nt->connector; 264 struct drm_crtc_state *crtc_state; 265 int i; 266 267 /* Return the default (first) mode if no info available yet */ 268 if (!connector->state || !connector->state->crtc) 269 return 0; 270 271 crtc_state = connector->state->crtc->state; 272 273 for (i = 0; i < nt->desc->num_modes; i++) { 274 if (drm_mode_match(&crtc_state->mode, 275 &nt->desc->mode_data[i].mode, 276 DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_CLOCK)) 277 return i; 278 } 279 280 return 0; 281 } 282 283 static int nt35950_on(struct nt35950 *nt) 284 { 285 const struct nt35950_panel_mode *mode_data = nt->desc->mode_data; 286 struct mipi_dsi_device *dsi = nt->dsi[0]; 287 struct device *dev = &dsi->dev; 288 int ret; 289 290 nt->cur_mode = nt35950_get_current_mode(nt); 291 nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM; 292 nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; 293 294 ret = nt35950_set_cmd2_page(nt, 0); 295 if (ret < 0) 296 return ret; 297 298 ret = nt35950_set_data_compression(nt, mode_data[nt->cur_mode].compression); 299 if (ret < 0) 300 return ret; 301 302 ret = nt35950_set_scale_mode(nt, mode_data[nt->cur_mode].scaler_mode); 303 if (ret < 0) 304 return ret; 305 306 ret = nt35950_set_scaler(nt, mode_data[nt->cur_mode].scaler_on); 307 if (ret < 0) 308 return ret; 309 310 ret = nt35950_set_dispout(nt); 311 if (ret < 0) 312 return ret; 313 314 ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 315 if (ret < 0) { 316 dev_err(dev, "Failed to set tear on: %d\n", ret); 317 return ret; 318 } 319 320 ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0); 321 if (ret < 0) { 322 dev_err(dev, "Failed to set tear scanline: %d\n", ret); 323 return ret; 324 } 325 326 /* CMD2 Page 1 */ 327 ret = nt35950_set_cmd2_page(nt, 1); 328 if (ret < 0) 329 return ret; 330 331 /* Unknown command */ 332 mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88); 333 334 /* CMD2 Page 7 */ 335 ret = nt35950_set_cmd2_page(nt, 7); 336 if (ret < 0) 337 return ret; 338 339 /* Enable SubPixel Rendering */ 340 mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01); 341 342 /* SPR Mode: YYG Rainbow-RGB */ 343 mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB); 344 345 /* CMD3 */ 346 ret = nt35950_inject_black_image(nt); 347 if (ret < 0) 348 return ret; 349 350 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 351 if (ret < 0) 352 return ret; 353 msleep(120); 354 355 ret = mipi_dsi_dcs_set_display_on(dsi); 356 if (ret < 0) 357 return ret; 358 msleep(120); 359 360 nt->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM; 361 nt->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM; 362 363 return 0; 364 } 365 366 static int nt35950_off(struct nt35950 *nt) 367 { 368 struct device *dev = &nt->dsi[0]->dev; 369 int ret; 370 371 ret = mipi_dsi_dcs_set_display_off(nt->dsi[0]); 372 if (ret < 0) { 373 dev_err(dev, "Failed to set display off: %d\n", ret); 374 goto set_lpm; 375 } 376 usleep_range(10000, 11000); 377 378 ret = mipi_dsi_dcs_enter_sleep_mode(nt->dsi[0]); 379 if (ret < 0) { 380 dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 381 goto set_lpm; 382 } 383 msleep(150); 384 385 set_lpm: 386 nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM; 387 nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; 388 389 return 0; 390 } 391 392 static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev) 393 { 394 int ret; 395 396 nt->vregs[0].supply = "vddio"; 397 nt->vregs[1].supply = "avdd"; 398 nt->vregs[2].supply = "avee"; 399 nt->vregs[3].supply = "dvdd"; 400 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->vregs), 401 nt->vregs); 402 if (ret < 0) 403 return ret; 404 405 ret = regulator_is_supported_voltage(nt->vregs[0].consumer, 406 1750000, 1950000); 407 if (!ret) 408 return -EINVAL; 409 ret = regulator_is_supported_voltage(nt->vregs[1].consumer, 410 5200000, 5900000); 411 if (!ret) 412 return -EINVAL; 413 /* AVEE is negative: -5.90V to -5.20V */ 414 ret = regulator_is_supported_voltage(nt->vregs[2].consumer, 415 5200000, 5900000); 416 if (!ret) 417 return -EINVAL; 418 419 ret = regulator_is_supported_voltage(nt->vregs[3].consumer, 420 1300000, 1400000); 421 if (!ret) 422 return -EINVAL; 423 424 return 0; 425 } 426 427 static int nt35950_prepare(struct drm_panel *panel) 428 { 429 struct nt35950 *nt = to_nt35950(panel); 430 struct device *dev = &nt->dsi[0]->dev; 431 int ret; 432 433 ret = regulator_enable(nt->vregs[0].consumer); 434 if (ret) 435 return ret; 436 usleep_range(2000, 5000); 437 438 ret = regulator_enable(nt->vregs[3].consumer); 439 if (ret) 440 goto end; 441 usleep_range(15000, 18000); 442 443 ret = regulator_enable(nt->vregs[1].consumer); 444 if (ret) 445 goto end; 446 447 ret = regulator_enable(nt->vregs[2].consumer); 448 if (ret) 449 goto end; 450 usleep_range(12000, 13000); 451 452 nt35950_reset(nt); 453 454 ret = nt35950_on(nt); 455 if (ret < 0) { 456 dev_err(dev, "Failed to initialize panel: %d\n", ret); 457 goto end; 458 } 459 460 end: 461 if (ret < 0) { 462 regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs); 463 return ret; 464 } 465 466 return 0; 467 } 468 469 static int nt35950_unprepare(struct drm_panel *panel) 470 { 471 struct nt35950 *nt = to_nt35950(panel); 472 struct device *dev = &nt->dsi[0]->dev; 473 int ret; 474 475 ret = nt35950_off(nt); 476 if (ret < 0) 477 dev_err(dev, "Failed to deinitialize panel: %d\n", ret); 478 479 gpiod_set_value_cansleep(nt->reset_gpio, 0); 480 regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs); 481 482 return 0; 483 } 484 485 static int nt35950_get_modes(struct drm_panel *panel, 486 struct drm_connector *connector) 487 { 488 struct nt35950 *nt = to_nt35950(panel); 489 int i; 490 491 for (i = 0; i < nt->desc->num_modes; i++) { 492 struct drm_display_mode *mode; 493 494 mode = drm_mode_duplicate(connector->dev, 495 &nt->desc->mode_data[i].mode); 496 if (!mode) 497 return -ENOMEM; 498 499 drm_mode_set_name(mode); 500 501 mode->type |= DRM_MODE_TYPE_DRIVER; 502 if (nt->desc->num_modes == 1) 503 mode->type |= DRM_MODE_TYPE_PREFERRED; 504 505 drm_mode_probed_add(connector, mode); 506 } 507 508 connector->display_info.bpc = 8; 509 connector->display_info.height_mm = nt->desc->mode_data[0].mode.height_mm; 510 connector->display_info.width_mm = nt->desc->mode_data[0].mode.width_mm; 511 nt->connector = connector; 512 513 return nt->desc->num_modes; 514 } 515 516 static const struct drm_panel_funcs nt35950_panel_funcs = { 517 .prepare = nt35950_prepare, 518 .unprepare = nt35950_unprepare, 519 .get_modes = nt35950_get_modes, 520 }; 521 522 static int nt35950_probe(struct mipi_dsi_device *dsi) 523 { 524 struct device *dev = &dsi->dev; 525 struct device_node *dsi_r; 526 struct mipi_dsi_host *dsi_r_host; 527 struct nt35950 *nt; 528 const struct mipi_dsi_device_info *info; 529 int i, num_dsis = 1, ret; 530 531 nt = devm_kzalloc(dev, sizeof(*nt), GFP_KERNEL); 532 if (!nt) 533 return -ENOMEM; 534 535 ret = nt35950_sharp_init_vregs(nt, dev); 536 if (ret) 537 return dev_err_probe(dev, ret, "Regulator init failure.\n"); 538 539 nt->desc = of_device_get_match_data(dev); 540 if (!nt->desc) 541 return -ENODEV; 542 543 nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); 544 if (IS_ERR(nt->reset_gpio)) { 545 return dev_err_probe(dev, PTR_ERR(nt->reset_gpio), 546 "Failed to get reset gpio\n"); 547 } 548 549 /* If the panel is connected on two DSIs then DSI0 left, DSI1 right */ 550 if (nt->desc->is_dual_dsi) { 551 info = &nt->desc->dsi_info; 552 dsi_r = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); 553 if (!dsi_r) { 554 dev_err(dev, "Cannot get secondary DSI node.\n"); 555 return -ENODEV; 556 } 557 dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r); 558 of_node_put(dsi_r); 559 if (!dsi_r_host) { 560 dev_err(dev, "Cannot get secondary DSI host\n"); 561 return -EPROBE_DEFER; 562 } 563 564 nt->dsi[1] = mipi_dsi_device_register_full(dsi_r_host, info); 565 if (!nt->dsi[1]) { 566 dev_err(dev, "Cannot get secondary DSI node\n"); 567 return -ENODEV; 568 } 569 num_dsis++; 570 } 571 572 nt->dsi[0] = dsi; 573 mipi_dsi_set_drvdata(dsi, nt); 574 575 drm_panel_init(&nt->panel, dev, &nt35950_panel_funcs, 576 DRM_MODE_CONNECTOR_DSI); 577 578 ret = drm_panel_of_backlight(&nt->panel); 579 if (ret) { 580 if (num_dsis == 2) 581 mipi_dsi_device_unregister(nt->dsi[1]); 582 583 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 584 } 585 586 drm_panel_add(&nt->panel); 587 588 for (i = 0; i < num_dsis; i++) { 589 nt->dsi[i]->lanes = nt->desc->num_lanes; 590 nt->dsi[i]->format = MIPI_DSI_FMT_RGB888; 591 592 nt->dsi[i]->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS | 593 MIPI_DSI_MODE_LPM; 594 595 if (nt->desc->mode_data[0].is_video_mode) 596 nt->dsi[i]->mode_flags |= MIPI_DSI_MODE_VIDEO; 597 598 ret = mipi_dsi_attach(nt->dsi[i]); 599 if (ret < 0) { 600 /* If we fail to attach to either host, we're done */ 601 if (num_dsis == 2) 602 mipi_dsi_device_unregister(nt->dsi[1]); 603 604 return dev_err_probe(dev, ret, 605 "Cannot attach to DSI%d host.\n", i); 606 } 607 } 608 609 /* Make sure to set RESX LOW before starting the power-on sequence */ 610 gpiod_set_value_cansleep(nt->reset_gpio, 0); 611 return 0; 612 } 613 614 static void nt35950_remove(struct mipi_dsi_device *dsi) 615 { 616 struct nt35950 *nt = mipi_dsi_get_drvdata(dsi); 617 int ret; 618 619 ret = mipi_dsi_detach(nt->dsi[0]); 620 if (ret < 0) 621 dev_err(&dsi->dev, 622 "Failed to detach from DSI0 host: %d\n", ret); 623 624 if (nt->dsi[1]) { 625 ret = mipi_dsi_detach(nt->dsi[1]); 626 if (ret < 0) 627 dev_err(&dsi->dev, 628 "Failed to detach from DSI1 host: %d\n", ret); 629 mipi_dsi_device_unregister(nt->dsi[1]); 630 } 631 632 drm_panel_remove(&nt->panel); 633 } 634 635 static const struct nt35950_panel_mode sharp_ls055d1sx04_modes[] = { 636 { 637 /* 1920x1080 60Hz no compression */ 638 .mode = { 639 .clock = 214537, 640 .hdisplay = 1080, 641 .hsync_start = 1080 + 400, 642 .hsync_end = 1080 + 400 + 40, 643 .htotal = 1080 + 400 + 40 + 300, 644 .vdisplay = 1920, 645 .vsync_start = 1920 + 12, 646 .vsync_end = 1920 + 12 + 2, 647 .vtotal = 1920 + 12 + 2 + 10, 648 .width_mm = 68, 649 .height_mm = 121, 650 }, 651 .compression = MCS_DATA_COMPRESSION_NONE, 652 .enable_sram = true, 653 .is_video_mode = false, 654 .scaler_on = 1, 655 .scaler_mode = MCS_SCALEUP_DUPLICATE, 656 }, 657 /* TODO: Add 2160x3840 60Hz when DSC is supported */ 658 }; 659 660 static const struct nt35950_panel_desc sharp_ls055d1sx04 = { 661 .model_name = "Sharp LS055D1SX04", 662 .dsi_info = { 663 .type = "LS055D1SX04", 664 .channel = 0, 665 .node = NULL, 666 }, 667 .mode_data = sharp_ls055d1sx04_modes, 668 .num_modes = ARRAY_SIZE(sharp_ls055d1sx04_modes), 669 .is_dual_dsi = true, 670 .num_lanes = 4, 671 }; 672 673 static const struct of_device_id nt35950_of_match[] = { 674 { .compatible = "sharp,ls055d1sx04", .data = &sharp_ls055d1sx04 }, 675 { } 676 }; 677 MODULE_DEVICE_TABLE(of, nt35950_of_match); 678 679 static struct mipi_dsi_driver nt35950_driver = { 680 .probe = nt35950_probe, 681 .remove = nt35950_remove, 682 .driver = { 683 .name = "panel-novatek-nt35950", 684 .of_match_table = nt35950_of_match, 685 }, 686 }; 687 module_mipi_dsi_driver(nt35950_driver); 688 689 MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>"); 690 MODULE_DESCRIPTION("Novatek NT35950 DriverIC panels driver"); 691 MODULE_LICENSE("GPL v2"); 692