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 * @dsi_ctx: context for mipi_dsi functions 104 * @nt: Main driver structure 105 * @page: Page number (0-7) 106 */ 107 static void nt35950_set_cmd2_page(struct mipi_dsi_multi_context *dsi_ctx, 108 struct nt35950 *nt, u8 page) 109 { 110 const u8 mauc_cmd2_page[] = { MCS_CMD_MAUCCTR, 0x55, 0xaa, 0x52, 111 0x08, page }; 112 113 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, mauc_cmd2_page, 114 ARRAY_SIZE(mauc_cmd2_page)); 115 if (!dsi_ctx->accum_err) 116 nt->last_page = page; 117 } 118 119 /* 120 * nt35950_set_data_compression - Set data compression mode 121 * @dsi_ctx: context for mipi_dsi functions 122 * @nt: Main driver structure 123 * @comp_mode: Compression mode 124 */ 125 static void nt35950_set_data_compression(struct mipi_dsi_multi_context *dsi_ctx, 126 struct nt35950 *nt, u8 comp_mode) 127 { 128 u8 cmd_data_compression[] = { MCS_PARAM_DATA_COMPRESSION, comp_mode }; 129 u8 cmd_vesa_dsc_on[] = { MCS_PARAM_VESA_DSC_ON, !!comp_mode }; 130 u8 cmd_vesa_dsc_setting[] = { MCS_PARAM_VESA_DSC_SETTING, 0x03 }; 131 u8 last_page = nt->last_page; 132 133 /* Set CMD2 Page 0 if we're not there yet */ 134 if (last_page != 0) 135 nt35950_set_cmd2_page(dsi_ctx, nt, 0); 136 137 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_data_compression, 138 ARRAY_SIZE(cmd_data_compression)); 139 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_on, 140 ARRAY_SIZE(cmd_vesa_dsc_on)); 141 142 /* Set the vesa dsc setting on Page 4 */ 143 nt35950_set_cmd2_page(dsi_ctx, nt, 4); 144 145 /* Display Stream Compression setting, always 0x03 */ 146 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_setting, 147 ARRAY_SIZE(cmd_vesa_dsc_setting)); 148 149 /* Get back to the previously set page */ 150 nt35950_set_cmd2_page(dsi_ctx, nt, last_page); 151 } 152 153 /* 154 * nt35950_set_scaler - Enable/disable resolution upscaling 155 * @dsi_ctx: context for mipi_dsi functions 156 * @scale_up: Scale up function control 157 */ 158 static void nt35950_set_scaler(struct mipi_dsi_multi_context *dsi_ctx, 159 u8 scale_up) 160 { 161 u8 cmd_scaler[] = { MCS_PARAM_SCALER_FUNCTION, scale_up }; 162 163 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler, 164 ARRAY_SIZE(cmd_scaler)); 165 } 166 167 /* 168 * nt35950_set_scale_mode - Resolution upscaling mode 169 * @dsi_ctx: context for mipi_dsi functions 170 * @mode: Scaler mode (MCS_DATA_COMPRESSION_*) 171 */ 172 static void nt35950_set_scale_mode(struct mipi_dsi_multi_context *dsi_ctx, 173 u8 mode) 174 { 175 u8 cmd_scaler[] = { MCS_PARAM_SCALEUP_MODE, mode }; 176 177 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler, 178 ARRAY_SIZE(cmd_scaler)); 179 } 180 181 /* 182 * nt35950_inject_black_image - Display a completely black image 183 * @dsi_ctx: context for mipi_dsi functions 184 * 185 * After IC setup, the attached panel may show random data 186 * due to driveric behavior changes (resolution, compression, 187 * scaling, etc). This function, called after parameters setup, 188 * makes the driver ic to output a completely black image to 189 * the display. 190 * It makes sense to push a black image before sending the sleep-out 191 * and display-on commands. 192 */ 193 static void nt35950_inject_black_image(struct mipi_dsi_multi_context *dsi_ctx) 194 { 195 const u8 cmd0_black_img[] = { 0x6f, 0x01 }; 196 const u8 cmd1_black_img[] = { 0xf3, 0x10 }; 197 u8 cmd_test[] = { 0xff, 0xaa, 0x55, 0xa5, 0x80 }; 198 199 /* Enable test command */ 200 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test)); 201 202 /* Send a black image */ 203 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd0_black_img, 204 ARRAY_SIZE(cmd0_black_img)); 205 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd1_black_img, 206 ARRAY_SIZE(cmd1_black_img)); 207 208 /* Disable test command */ 209 cmd_test[ARRAY_SIZE(cmd_test) - 1] = 0x00; 210 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test)); 211 } 212 213 /* 214 * nt35950_set_dispout - Set Display Output register parameters 215 * @nt: Main driver structure 216 * @dsi_ctx: context for mipi_dsi functions 217 */ 218 static void nt35950_set_dispout(struct mipi_dsi_multi_context *dsi_ctx, 219 struct nt35950 *nt) 220 { 221 u8 cmd_dispout[] = { MCS_PARAM_DISP_OUTPUT_CTRL, 0x00 }; 222 const struct nt35950_panel_mode *mode_data = nt->desc->mode_data; 223 224 if (mode_data[nt->cur_mode].is_video_mode) 225 cmd_dispout[1] |= MCS_DISP_OUT_VIDEO_MODE; 226 if (mode_data[nt->cur_mode].enable_sram) 227 cmd_dispout[1] |= MCS_DISP_OUT_SRAM_EN; 228 229 mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_dispout, 230 ARRAY_SIZE(cmd_dispout)); 231 } 232 233 static int nt35950_get_current_mode(struct nt35950 *nt) 234 { 235 struct drm_connector *connector = nt->connector; 236 struct drm_crtc_state *crtc_state; 237 int i; 238 239 /* Return the default (first) mode if no info available yet */ 240 if (!connector->state || !connector->state->crtc) 241 return 0; 242 243 crtc_state = connector->state->crtc->state; 244 245 for (i = 0; i < nt->desc->num_modes; i++) { 246 if (drm_mode_match(&crtc_state->mode, 247 &nt->desc->mode_data[i].mode, 248 DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_CLOCK)) 249 return i; 250 } 251 252 return 0; 253 } 254 255 static int nt35950_on(struct nt35950 *nt) 256 { 257 const struct nt35950_panel_mode *mode_data = nt->desc->mode_data; 258 struct mipi_dsi_device *dsi = nt->dsi[0]; 259 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 260 261 nt->cur_mode = nt35950_get_current_mode(nt); 262 nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM; 263 nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; 264 265 nt35950_set_cmd2_page(&dsi_ctx, nt, 0); 266 nt35950_set_data_compression(&dsi_ctx, nt, mode_data[nt->cur_mode].compression); 267 nt35950_set_scale_mode(&dsi_ctx, mode_data[nt->cur_mode].scaler_mode); 268 nt35950_set_scaler(&dsi_ctx, mode_data[nt->cur_mode].scaler_on); 269 nt35950_set_dispout(&dsi_ctx, nt); 270 271 mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 272 mipi_dsi_dcs_set_tear_scanline_multi(&dsi_ctx, 0); 273 274 /* CMD2 Page 1 */ 275 nt35950_set_cmd2_page(&dsi_ctx, nt, 1); 276 277 /* Unknown command */ 278 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x88, 0x88); 279 280 /* CMD2 Page 7 */ 281 nt35950_set_cmd2_page(&dsi_ctx, nt, 7); 282 283 /* Enable SubPixel Rendering */ 284 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_EN, 0x01); 285 286 /* SPR Mode: YYG Rainbow-RGB */ 287 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_MODE, 288 MCS_SPR_MODE_YYG_RAINBOW_RGB); 289 290 /* CMD3 */ 291 nt35950_inject_black_image(&dsi_ctx); 292 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 293 mipi_dsi_msleep(&dsi_ctx, 120); 294 295 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 296 mipi_dsi_msleep(&dsi_ctx, 120); 297 298 if (dsi_ctx.accum_err) 299 return dsi_ctx.accum_err; 300 301 nt->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM; 302 nt->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM; 303 304 return 0; 305 } 306 307 static void nt35950_off(struct nt35950 *nt) 308 { 309 struct mipi_dsi_device *dsi = nt->dsi[0]; 310 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 311 312 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 313 mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000); 314 315 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 316 mipi_dsi_msleep(&dsi_ctx, 150); 317 318 nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM; 319 nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; 320 } 321 322 static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev) 323 { 324 int ret; 325 326 nt->vregs[0].supply = "vddio"; 327 nt->vregs[1].supply = "avdd"; 328 nt->vregs[2].supply = "avee"; 329 nt->vregs[3].supply = "dvdd"; 330 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(nt->vregs), 331 nt->vregs); 332 if (ret < 0) 333 return ret; 334 335 ret = regulator_is_supported_voltage(nt->vregs[0].consumer, 336 1750000, 1950000); 337 if (!ret) 338 return -EINVAL; 339 ret = regulator_is_supported_voltage(nt->vregs[1].consumer, 340 5200000, 5900000); 341 if (!ret) 342 return -EINVAL; 343 /* AVEE is negative: -5.90V to -5.20V */ 344 ret = regulator_is_supported_voltage(nt->vregs[2].consumer, 345 5200000, 5900000); 346 if (!ret) 347 return -EINVAL; 348 349 ret = regulator_is_supported_voltage(nt->vregs[3].consumer, 350 1300000, 1400000); 351 if (!ret) 352 return -EINVAL; 353 354 return 0; 355 } 356 357 static int nt35950_prepare(struct drm_panel *panel) 358 { 359 struct nt35950 *nt = to_nt35950(panel); 360 int ret; 361 362 ret = regulator_enable(nt->vregs[0].consumer); 363 if (ret) 364 return ret; 365 usleep_range(2000, 5000); 366 367 ret = regulator_enable(nt->vregs[3].consumer); 368 if (ret) 369 goto end; 370 usleep_range(15000, 18000); 371 372 ret = regulator_enable(nt->vregs[1].consumer); 373 if (ret) 374 goto end; 375 376 ret = regulator_enable(nt->vregs[2].consumer); 377 if (ret) 378 goto end; 379 usleep_range(12000, 13000); 380 381 nt35950_reset(nt); 382 383 ret = nt35950_on(nt); 384 385 end: 386 if (ret < 0) { 387 regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs); 388 return ret; 389 } 390 391 return 0; 392 } 393 394 static int nt35950_unprepare(struct drm_panel *panel) 395 { 396 struct nt35950 *nt = to_nt35950(panel); 397 398 nt35950_off(nt); 399 400 gpiod_set_value_cansleep(nt->reset_gpio, 0); 401 regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs); 402 403 return 0; 404 } 405 406 static int nt35950_get_modes(struct drm_panel *panel, 407 struct drm_connector *connector) 408 { 409 struct nt35950 *nt = to_nt35950(panel); 410 int i; 411 412 for (i = 0; i < nt->desc->num_modes; i++) { 413 struct drm_display_mode *mode; 414 415 mode = drm_mode_duplicate(connector->dev, 416 &nt->desc->mode_data[i].mode); 417 if (!mode) 418 return -ENOMEM; 419 420 drm_mode_set_name(mode); 421 422 mode->type |= DRM_MODE_TYPE_DRIVER; 423 if (nt->desc->num_modes == 1) 424 mode->type |= DRM_MODE_TYPE_PREFERRED; 425 426 drm_mode_probed_add(connector, mode); 427 } 428 429 connector->display_info.bpc = 8; 430 connector->display_info.height_mm = nt->desc->mode_data[0].mode.height_mm; 431 connector->display_info.width_mm = nt->desc->mode_data[0].mode.width_mm; 432 nt->connector = connector; 433 434 return nt->desc->num_modes; 435 } 436 437 static const struct drm_panel_funcs nt35950_panel_funcs = { 438 .prepare = nt35950_prepare, 439 .unprepare = nt35950_unprepare, 440 .get_modes = nt35950_get_modes, 441 }; 442 443 static int nt35950_probe(struct mipi_dsi_device *dsi) 444 { 445 struct device *dev = &dsi->dev; 446 struct device_node *dsi_r; 447 struct mipi_dsi_host *dsi_r_host; 448 struct nt35950 *nt; 449 const struct mipi_dsi_device_info *info; 450 int i, num_dsis = 1, ret; 451 452 nt = devm_kzalloc(dev, sizeof(*nt), GFP_KERNEL); 453 if (!nt) 454 return -ENOMEM; 455 456 ret = nt35950_sharp_init_vregs(nt, dev); 457 if (ret) 458 return dev_err_probe(dev, ret, "Regulator init failure.\n"); 459 460 nt->desc = of_device_get_match_data(dev); 461 if (!nt->desc) 462 return -ENODEV; 463 464 nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); 465 if (IS_ERR(nt->reset_gpio)) { 466 return dev_err_probe(dev, PTR_ERR(nt->reset_gpio), 467 "Failed to get reset gpio\n"); 468 } 469 470 /* If the panel is connected on two DSIs then DSI0 left, DSI1 right */ 471 if (nt->desc->is_dual_dsi) { 472 info = &nt->desc->dsi_info; 473 dsi_r = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); 474 if (!dsi_r) { 475 dev_err(dev, "Cannot get secondary DSI node.\n"); 476 return -ENODEV; 477 } 478 dsi_r_host = of_find_mipi_dsi_host_by_node(dsi_r); 479 of_node_put(dsi_r); 480 if (!dsi_r_host) 481 return dev_err_probe(dev, -EPROBE_DEFER, "Cannot get secondary DSI host\n"); 482 483 nt->dsi[1] = mipi_dsi_device_register_full(dsi_r_host, info); 484 if (!nt->dsi[1]) { 485 dev_err(dev, "Cannot get secondary DSI node\n"); 486 return -ENODEV; 487 } 488 num_dsis++; 489 } 490 491 nt->dsi[0] = dsi; 492 mipi_dsi_set_drvdata(dsi, nt); 493 494 drm_panel_init(&nt->panel, dev, &nt35950_panel_funcs, 495 DRM_MODE_CONNECTOR_DSI); 496 497 ret = drm_panel_of_backlight(&nt->panel); 498 if (ret) { 499 if (num_dsis == 2) 500 mipi_dsi_device_unregister(nt->dsi[1]); 501 502 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 503 } 504 505 drm_panel_add(&nt->panel); 506 507 for (i = 0; i < num_dsis; i++) { 508 nt->dsi[i]->lanes = nt->desc->num_lanes; 509 nt->dsi[i]->format = MIPI_DSI_FMT_RGB888; 510 511 nt->dsi[i]->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS | 512 MIPI_DSI_MODE_LPM; 513 514 if (nt->desc->mode_data[0].is_video_mode) 515 nt->dsi[i]->mode_flags |= MIPI_DSI_MODE_VIDEO; 516 517 ret = mipi_dsi_attach(nt->dsi[i]); 518 if (ret < 0) { 519 /* If we fail to attach to either host, we're done */ 520 if (num_dsis == 2) 521 mipi_dsi_device_unregister(nt->dsi[1]); 522 523 return dev_err_probe(dev, ret, 524 "Cannot attach to DSI%d host.\n", i); 525 } 526 } 527 528 /* Make sure to set RESX LOW before starting the power-on sequence */ 529 gpiod_set_value_cansleep(nt->reset_gpio, 0); 530 return 0; 531 } 532 533 static void nt35950_remove(struct mipi_dsi_device *dsi) 534 { 535 struct nt35950 *nt = mipi_dsi_get_drvdata(dsi); 536 int ret; 537 538 ret = mipi_dsi_detach(nt->dsi[0]); 539 if (ret < 0) 540 dev_err(&dsi->dev, 541 "Failed to detach from DSI0 host: %d\n", ret); 542 543 if (nt->dsi[1]) { 544 ret = mipi_dsi_detach(nt->dsi[1]); 545 if (ret < 0) 546 dev_err(&dsi->dev, 547 "Failed to detach from DSI1 host: %d\n", ret); 548 mipi_dsi_device_unregister(nt->dsi[1]); 549 } 550 551 drm_panel_remove(&nt->panel); 552 } 553 554 static const struct nt35950_panel_mode sharp_ls055d1sx04_modes[] = { 555 { 556 /* 1920x1080 60Hz no compression */ 557 .mode = { 558 .clock = 214537, 559 .hdisplay = 1080, 560 .hsync_start = 1080 + 400, 561 .hsync_end = 1080 + 400 + 40, 562 .htotal = 1080 + 400 + 40 + 300, 563 .vdisplay = 1920, 564 .vsync_start = 1920 + 12, 565 .vsync_end = 1920 + 12 + 2, 566 .vtotal = 1920 + 12 + 2 + 10, 567 .width_mm = 68, 568 .height_mm = 121, 569 }, 570 .compression = MCS_DATA_COMPRESSION_NONE, 571 .enable_sram = true, 572 .is_video_mode = false, 573 .scaler_on = 1, 574 .scaler_mode = MCS_SCALEUP_DUPLICATE, 575 }, 576 /* TODO: Add 2160x3840 60Hz when DSC is supported */ 577 }; 578 579 static const struct nt35950_panel_desc sharp_ls055d1sx04 = { 580 .model_name = "Sharp LS055D1SX04", 581 .dsi_info = { 582 .type = "LS055D1SX04", 583 .channel = 0, 584 .node = NULL, 585 }, 586 .mode_data = sharp_ls055d1sx04_modes, 587 .num_modes = ARRAY_SIZE(sharp_ls055d1sx04_modes), 588 .is_dual_dsi = true, 589 .num_lanes = 4, 590 }; 591 592 static const struct of_device_id nt35950_of_match[] = { 593 { .compatible = "sharp,ls055d1sx04", .data = &sharp_ls055d1sx04 }, 594 { } 595 }; 596 MODULE_DEVICE_TABLE(of, nt35950_of_match); 597 598 static struct mipi_dsi_driver nt35950_driver = { 599 .probe = nt35950_probe, 600 .remove = nt35950_remove, 601 .driver = { 602 .name = "panel-novatek-nt35950", 603 .of_match_table = nt35950_of_match, 604 }, 605 }; 606 module_mipi_dsi_driver(nt35950_driver); 607 608 MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>"); 609 MODULE_DESCRIPTION("Novatek NT35950 DriverIC panels driver"); 610 MODULE_LICENSE("GPL v2"); 611