.. | .. |
---|
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); |
---|