| .. | .. |
|---|
| 28 | 28 | #include <linux/of_platform.h> |
|---|
| 29 | 29 | #include <linux/platform_device.h> |
|---|
| 30 | 30 | #include <linux/regulator/consumer.h> |
|---|
| 31 | +#include <linux/spi/spi.h> |
|---|
| 31 | 32 | |
|---|
| 32 | 33 | #include <video/display_timing.h> |
|---|
| 33 | 34 | #include <video/mipi_display.h> |
|---|
| .. | .. |
|---|
| 41 | 42 | #include <drm/drm_dsc.h> |
|---|
| 42 | 43 | |
|---|
| 43 | 44 | #include "panel-simple.h" |
|---|
| 45 | + |
|---|
| 46 | +enum panel_simple_cmd_type { |
|---|
| 47 | + CMD_TYPE_DEFAULT, |
|---|
| 48 | + CMD_TYPE_SPI |
|---|
| 49 | +}; |
|---|
| 44 | 50 | |
|---|
| 45 | 51 | struct panel_cmd_header { |
|---|
| 46 | 52 | u8 data_type; |
|---|
| .. | .. |
|---|
| 124 | 130 | |
|---|
| 125 | 131 | struct panel_cmd_seq *init_seq; |
|---|
| 126 | 132 | struct panel_cmd_seq *exit_seq; |
|---|
| 133 | + |
|---|
| 134 | + enum panel_simple_cmd_type cmd_type; |
|---|
| 135 | + |
|---|
| 136 | + int (*spi_read)(struct device *dev, const u8 cmd, u8 *val); |
|---|
| 137 | + int (*spi_write)(struct device *dev, const u8 *data, size_t len, u8 type); |
|---|
| 127 | 138 | }; |
|---|
| 128 | 139 | |
|---|
| 129 | 140 | struct panel_simple { |
|---|
| .. | .. |
|---|
| 148 | 159 | struct drm_dsc_picture_parameter_set *pps; |
|---|
| 149 | 160 | enum drm_panel_orientation orientation; |
|---|
| 150 | 161 | }; |
|---|
| 162 | + |
|---|
| 163 | +static inline void panel_simple_msleep(unsigned int msecs) |
|---|
| 164 | +{ |
|---|
| 165 | + usleep_range(msecs * 1000, msecs * 1000 + 100); |
|---|
| 166 | +} |
|---|
| 151 | 167 | |
|---|
| 152 | 168 | static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) |
|---|
| 153 | 169 | { |
|---|
| .. | .. |
|---|
| 266 | 282 | dev_err(dev, "failed to write dcs cmd: %d\n", err); |
|---|
| 267 | 283 | |
|---|
| 268 | 284 | if (cmd->header.delay) |
|---|
| 269 | | - msleep(cmd->header.delay); |
|---|
| 285 | + panel_simple_msleep(cmd->header.delay); |
|---|
| 286 | + } |
|---|
| 287 | + |
|---|
| 288 | + return 0; |
|---|
| 289 | +} |
|---|
| 290 | + |
|---|
| 291 | +static int panel_simple_xfer_spi_cmd_seq(struct panel_simple *panel, struct panel_cmd_seq *cmds) |
|---|
| 292 | +{ |
|---|
| 293 | + int i; |
|---|
| 294 | + int ret; |
|---|
| 295 | + |
|---|
| 296 | + if (!cmds) |
|---|
| 297 | + return -EINVAL; |
|---|
| 298 | + |
|---|
| 299 | + for (i = 0; i < cmds->cmd_cnt; i++) { |
|---|
| 300 | + struct panel_cmd_desc *cmd = &cmds->cmds[i]; |
|---|
| 301 | + |
|---|
| 302 | + ret = panel->desc->spi_write(panel->base.dev, cmd->payload, |
|---|
| 303 | + cmd->header.payload_length, cmd->header.data_type); |
|---|
| 304 | + if (ret) |
|---|
| 305 | + return ret; |
|---|
| 306 | + |
|---|
| 307 | + if (cmd->header.delay) |
|---|
| 308 | + panel_simple_msleep(cmd->header.delay); |
|---|
| 270 | 309 | } |
|---|
| 271 | 310 | |
|---|
| 272 | 311 | return 0; |
|---|
| .. | .. |
|---|
| 444 | 483 | return 0; |
|---|
| 445 | 484 | |
|---|
| 446 | 485 | if (p->desc->delay.disable) |
|---|
| 447 | | - msleep(p->desc->delay.disable); |
|---|
| 486 | + panel_simple_msleep(p->desc->delay.disable); |
|---|
| 448 | 487 | |
|---|
| 449 | 488 | p->enabled = false; |
|---|
| 450 | 489 | |
|---|
| .. | .. |
|---|
| 458 | 497 | if (!p->prepared) |
|---|
| 459 | 498 | return 0; |
|---|
| 460 | 499 | |
|---|
| 461 | | - if (p->desc->exit_seq) |
|---|
| 462 | | - if (p->dsi) |
|---|
| 463 | | - panel_simple_xfer_dsi_cmd_seq(p, p->desc->exit_seq); |
|---|
| 500 | + if (p->desc->exit_seq) { |
|---|
| 501 | + if (p->desc->cmd_type == CMD_TYPE_SPI) { |
|---|
| 502 | + if (panel_simple_xfer_spi_cmd_seq(p, p->desc->exit_seq)) { |
|---|
| 503 | + dev_err(panel->dev, "failed to send exit spi cmds seq\n"); |
|---|
| 504 | + return -EINVAL; |
|---|
| 505 | + } |
|---|
| 506 | + } else { |
|---|
| 507 | + if (p->dsi) |
|---|
| 508 | + panel_simple_xfer_dsi_cmd_seq(p, p->desc->exit_seq); |
|---|
| 509 | + } |
|---|
| 510 | + } |
|---|
| 464 | 511 | |
|---|
| 465 | 512 | gpiod_direction_output(p->reset_gpio, 1); |
|---|
| 466 | 513 | gpiod_direction_output(p->enable_gpio, 0); |
|---|
| .. | .. |
|---|
| 468 | 515 | panel_simple_regulator_disable(p); |
|---|
| 469 | 516 | |
|---|
| 470 | 517 | if (p->desc->delay.unprepare) |
|---|
| 471 | | - msleep(p->desc->delay.unprepare); |
|---|
| 518 | + panel_simple_msleep(p->desc->delay.unprepare); |
|---|
| 472 | 519 | |
|---|
| 473 | 520 | p->prepared = false; |
|---|
| 474 | 521 | |
|---|
| .. | .. |
|---|
| 522 | 569 | if (p->no_hpd) |
|---|
| 523 | 570 | delay += p->desc->delay.hpd_absent_delay; |
|---|
| 524 | 571 | if (delay) |
|---|
| 525 | | - msleep(delay); |
|---|
| 572 | + panel_simple_msleep(delay); |
|---|
| 526 | 573 | |
|---|
| 527 | 574 | if (p->hpd_gpio) { |
|---|
| 528 | 575 | if (IS_ERR(p->hpd_gpio)) { |
|---|
| .. | .. |
|---|
| 547 | 594 | gpiod_direction_output(p->reset_gpio, 1); |
|---|
| 548 | 595 | |
|---|
| 549 | 596 | if (p->desc->delay.reset) |
|---|
| 550 | | - msleep(p->desc->delay.reset); |
|---|
| 597 | + panel_simple_msleep(p->desc->delay.reset); |
|---|
| 551 | 598 | |
|---|
| 552 | 599 | gpiod_direction_output(p->reset_gpio, 0); |
|---|
| 553 | 600 | |
|---|
| 554 | 601 | if (p->desc->delay.init) |
|---|
| 555 | | - msleep(p->desc->delay.init); |
|---|
| 602 | + panel_simple_msleep(p->desc->delay.init); |
|---|
| 556 | 603 | |
|---|
| 557 | | - if (p->desc->init_seq) |
|---|
| 558 | | - if (p->dsi) |
|---|
| 559 | | - panel_simple_xfer_dsi_cmd_seq(p, p->desc->init_seq); |
|---|
| 604 | + if (p->desc->init_seq) { |
|---|
| 605 | + if (p->desc->cmd_type == CMD_TYPE_SPI) { |
|---|
| 606 | + if (panel_simple_xfer_spi_cmd_seq(p, p->desc->init_seq)) { |
|---|
| 607 | + dev_err(panel->dev, "failed to send init spi cmds seq\n"); |
|---|
| 608 | + return -EINVAL; |
|---|
| 609 | + } |
|---|
| 610 | + } else { |
|---|
| 611 | + if (p->dsi) |
|---|
| 612 | + panel_simple_xfer_dsi_cmd_seq(p, p->desc->init_seq); |
|---|
| 613 | + } |
|---|
| 614 | + } |
|---|
| 560 | 615 | |
|---|
| 561 | 616 | p->prepared = true; |
|---|
| 562 | 617 | |
|---|
| .. | .. |
|---|
| 571 | 626 | return 0; |
|---|
| 572 | 627 | |
|---|
| 573 | 628 | if (p->desc->delay.enable) |
|---|
| 574 | | - msleep(p->desc->delay.enable); |
|---|
| 629 | + panel_simple_msleep(p->desc->delay.enable); |
|---|
| 575 | 630 | |
|---|
| 576 | 631 | p->enabled = true; |
|---|
| 577 | 632 | |
|---|
| .. | .. |
|---|
| 992 | 1047 | .num_modes = 1, |
|---|
| 993 | 1048 | .bpc = 8, |
|---|
| 994 | 1049 | .size = { |
|---|
| 995 | | - .width = 105, |
|---|
| 996 | | - .height = 67, |
|---|
| 1050 | + .width = 99, |
|---|
| 1051 | + .height = 58, |
|---|
| 997 | 1052 | }, |
|---|
| 998 | 1053 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
|---|
| 999 | 1054 | }; |
|---|
| .. | .. |
|---|
| 1298 | 1353 | }, |
|---|
| 1299 | 1354 | }; |
|---|
| 1300 | 1355 | |
|---|
| 1301 | | -static const struct drm_display_mode auo_g121ean01_mode = { |
|---|
| 1302 | | - .clock = 66700, |
|---|
| 1303 | | - .hdisplay = 1280, |
|---|
| 1304 | | - .hsync_start = 1280 + 58, |
|---|
| 1305 | | - .hsync_end = 1280 + 58 + 8, |
|---|
| 1306 | | - .htotal = 1280 + 58 + 8 + 70, |
|---|
| 1307 | | - .vdisplay = 800, |
|---|
| 1308 | | - .vsync_start = 800 + 6, |
|---|
| 1309 | | - .vsync_end = 800 + 6 + 4, |
|---|
| 1310 | | - .vtotal = 800 + 6 + 4 + 10, |
|---|
| 1356 | +static const struct display_timing auo_g121ean01_timing = { |
|---|
| 1357 | + .pixelclock = { 60000000, 74400000, 90000000 }, |
|---|
| 1358 | + .hactive = { 1280, 1280, 1280 }, |
|---|
| 1359 | + .hfront_porch = { 20, 50, 100 }, |
|---|
| 1360 | + .hback_porch = { 20, 50, 100 }, |
|---|
| 1361 | + .hsync_len = { 30, 100, 200 }, |
|---|
| 1362 | + .vactive = { 800, 800, 800 }, |
|---|
| 1363 | + .vfront_porch = { 2, 10, 25 }, |
|---|
| 1364 | + .vback_porch = { 2, 10, 25 }, |
|---|
| 1365 | + .vsync_len = { 4, 18, 50 }, |
|---|
| 1311 | 1366 | }; |
|---|
| 1312 | 1367 | |
|---|
| 1313 | 1368 | static const struct panel_desc auo_g121ean01 = { |
|---|
| 1314 | | - .modes = &auo_g121ean01_mode, |
|---|
| 1315 | | - .num_modes = 1, |
|---|
| 1369 | + .timings = &auo_g121ean01_timing, |
|---|
| 1370 | + .num_timings = 1, |
|---|
| 1316 | 1371 | .bpc = 8, |
|---|
| 1317 | 1372 | .size = { |
|---|
| 1318 | 1373 | .width = 261, |
|---|
| .. | .. |
|---|
| 1488 | 1543 | .delay = { |
|---|
| 1489 | 1544 | .disable = 5, |
|---|
| 1490 | 1545 | .unprepare = 1000, |
|---|
| 1491 | | - } |
|---|
| 1546 | + }, |
|---|
| 1547 | + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, |
|---|
| 1548 | + .connector_type = DRM_MODE_CONNECTOR_LVDS, |
|---|
| 1492 | 1549 | }; |
|---|
| 1493 | 1550 | |
|---|
| 1494 | 1551 | static const struct drm_display_mode avic_tm070ddh03_mode = { |
|---|
| .. | .. |
|---|
| 2379 | 2436 | .height = 54, |
|---|
| 2380 | 2437 | }, |
|---|
| 2381 | 2438 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
|---|
| 2439 | + .connector_type = DRM_MODE_CONNECTOR_DPI, |
|---|
| 2382 | 2440 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
|---|
| 2383 | 2441 | }; |
|---|
| 2384 | 2442 | |
|---|
| .. | .. |
|---|
| 3440 | 3498 | .vsync_start = 480 + 49, |
|---|
| 3441 | 3499 | .vsync_end = 480 + 49 + 2, |
|---|
| 3442 | 3500 | .vtotal = 480 + 49 + 2 + 22, |
|---|
| 3501 | + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, |
|---|
| 3443 | 3502 | }; |
|---|
| 3444 | 3503 | |
|---|
| 3445 | 3504 | static const struct panel_desc powertip_ph800480t013_idf02 = { |
|---|
| .. | .. |
|---|
| 5109 | 5168 | .shutdown = panel_simple_dsi_shutdown, |
|---|
| 5110 | 5169 | }; |
|---|
| 5111 | 5170 | |
|---|
| 5171 | +static int panel_simple_spi_read(struct device *dev, const u8 cmd, u8 *data) |
|---|
| 5172 | +{ |
|---|
| 5173 | + return 0; |
|---|
| 5174 | +} |
|---|
| 5175 | + |
|---|
| 5176 | +static int panel_simple_spi_write_word(struct device *dev, u16 data) |
|---|
| 5177 | +{ |
|---|
| 5178 | + struct spi_device *spi = to_spi_device(dev); |
|---|
| 5179 | + struct spi_transfer xfer = { |
|---|
| 5180 | + .len = 2, |
|---|
| 5181 | + .tx_buf = &data, |
|---|
| 5182 | + }; |
|---|
| 5183 | + struct spi_message msg; |
|---|
| 5184 | + |
|---|
| 5185 | + spi_message_init(&msg); |
|---|
| 5186 | + spi_message_add_tail(&xfer, &msg); |
|---|
| 5187 | + |
|---|
| 5188 | + return spi_sync(spi, &msg); |
|---|
| 5189 | +} |
|---|
| 5190 | + |
|---|
| 5191 | +static int panel_simple_spi_write(struct device *dev, const u8 *data, size_t len, u8 type) |
|---|
| 5192 | +{ |
|---|
| 5193 | + int ret = 0; |
|---|
| 5194 | + int i; |
|---|
| 5195 | + u16 mask = type ? 0x100 : 0; |
|---|
| 5196 | + |
|---|
| 5197 | + for (i = 0; i < len; i++) { |
|---|
| 5198 | + ret = panel_simple_spi_write_word(dev, *data | mask); |
|---|
| 5199 | + if (ret) { |
|---|
| 5200 | + dev_err(dev, "failed to write spi seq: %*ph\n", (int)len, data); |
|---|
| 5201 | + return ret; |
|---|
| 5202 | + } |
|---|
| 5203 | + data++; |
|---|
| 5204 | + } |
|---|
| 5205 | + |
|---|
| 5206 | + return ret; |
|---|
| 5207 | +} |
|---|
| 5208 | + |
|---|
| 5209 | +static const struct of_device_id panel_simple_spi_of_match[] = { |
|---|
| 5210 | + { .compatible = "simple-panel-spi", .data = NULL }, |
|---|
| 5211 | + { /* sentinel */ } |
|---|
| 5212 | +}; |
|---|
| 5213 | +MODULE_DEVICE_TABLE(of, panel_simple_spi_of_match); |
|---|
| 5214 | + |
|---|
| 5215 | +static int panel_simple_spi_probe(struct spi_device *spi) |
|---|
| 5216 | +{ |
|---|
| 5217 | + struct device *dev = &spi->dev; |
|---|
| 5218 | + const struct of_device_id *id; |
|---|
| 5219 | + const struct panel_desc *desc; |
|---|
| 5220 | + struct panel_desc *d; |
|---|
| 5221 | + int ret; |
|---|
| 5222 | + |
|---|
| 5223 | + id = of_match_node(panel_simple_spi_of_match, dev->of_node); |
|---|
| 5224 | + if (!id) |
|---|
| 5225 | + return -ENODEV; |
|---|
| 5226 | + |
|---|
| 5227 | + if (!id->data) { |
|---|
| 5228 | + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); |
|---|
| 5229 | + if (!d) |
|---|
| 5230 | + return -ENOMEM; |
|---|
| 5231 | + |
|---|
| 5232 | + ret = panel_simple_of_get_desc_data(dev, d); |
|---|
| 5233 | + if (ret) { |
|---|
| 5234 | + dev_err(dev, "failed to get desc data: %d\n", ret); |
|---|
| 5235 | + return ret; |
|---|
| 5236 | + } |
|---|
| 5237 | + |
|---|
| 5238 | + d->spi_write = panel_simple_spi_write; |
|---|
| 5239 | + d->spi_read = panel_simple_spi_read; |
|---|
| 5240 | + d->cmd_type = CMD_TYPE_SPI; |
|---|
| 5241 | + } |
|---|
| 5242 | + desc = id->data ? id->data : d; |
|---|
| 5243 | + |
|---|
| 5244 | + /* |
|---|
| 5245 | + * Set spi to 3 lines and 9bits/word mode. |
|---|
| 5246 | + */ |
|---|
| 5247 | + spi->bits_per_word = 9; |
|---|
| 5248 | + spi->mode = SPI_MODE_3; |
|---|
| 5249 | + ret = spi_setup(spi); |
|---|
| 5250 | + if (ret < 0) { |
|---|
| 5251 | + dev_err(dev, "spi setup failed.\n"); |
|---|
| 5252 | + return ret; |
|---|
| 5253 | + } |
|---|
| 5254 | + |
|---|
| 5255 | + return panel_simple_probe(dev, desc); |
|---|
| 5256 | +} |
|---|
| 5257 | + |
|---|
| 5258 | +static int panel_simple_spi_remove(struct spi_device *spi) |
|---|
| 5259 | +{ |
|---|
| 5260 | + return panel_simple_remove(&spi->dev); |
|---|
| 5261 | +} |
|---|
| 5262 | + |
|---|
| 5263 | +static void panel_simple_spi_shutdown(struct spi_device *spi) |
|---|
| 5264 | +{ |
|---|
| 5265 | + panel_simple_shutdown(&spi->dev); |
|---|
| 5266 | +} |
|---|
| 5267 | + |
|---|
| 5268 | +static struct spi_driver panel_simple_spi_driver = { |
|---|
| 5269 | + .driver = { |
|---|
| 5270 | + .name = "panel-simple-spi", |
|---|
| 5271 | + .of_match_table = panel_simple_spi_of_match, |
|---|
| 5272 | + }, |
|---|
| 5273 | + .probe = panel_simple_spi_probe, |
|---|
| 5274 | + .remove = panel_simple_spi_remove, |
|---|
| 5275 | + .shutdown = panel_simple_spi_shutdown, |
|---|
| 5276 | +}; |
|---|
| 5277 | + |
|---|
| 5112 | 5278 | static int __init panel_simple_init(void) |
|---|
| 5113 | 5279 | { |
|---|
| 5114 | 5280 | int err; |
|---|
| .. | .. |
|---|
| 5116 | 5282 | err = platform_driver_register(&panel_simple_platform_driver); |
|---|
| 5117 | 5283 | if (err < 0) |
|---|
| 5118 | 5284 | return err; |
|---|
| 5285 | + |
|---|
| 5286 | + if (IS_ENABLED(CONFIG_SPI_MASTER)) { |
|---|
| 5287 | + err = spi_register_driver(&panel_simple_spi_driver); |
|---|
| 5288 | + if (err < 0) |
|---|
| 5289 | + return err; |
|---|
| 5290 | + } |
|---|
| 5119 | 5291 | |
|---|
| 5120 | 5292 | if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { |
|---|
| 5121 | 5293 | err = mipi_dsi_driver_register(&panel_simple_dsi_driver); |
|---|
| .. | .. |
|---|
| 5132 | 5304 | if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) |
|---|
| 5133 | 5305 | mipi_dsi_driver_unregister(&panel_simple_dsi_driver); |
|---|
| 5134 | 5306 | |
|---|
| 5307 | + if (IS_ENABLED(CONFIG_SPI_MASTER)) |
|---|
| 5308 | + spi_unregister_driver(&panel_simple_spi_driver); |
|---|
| 5309 | + |
|---|
| 5135 | 5310 | platform_driver_unregister(&panel_simple_platform_driver); |
|---|
| 5136 | 5311 | } |
|---|
| 5137 | 5312 | module_exit(panel_simple_exit); |
|---|