.. | .. |
---|
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 { |
---|
.. | .. |
---|
266 | 277 | dev_err(dev, "failed to write dcs cmd: %d\n", err); |
---|
267 | 278 | |
---|
268 | 279 | if (cmd->header.delay) |
---|
269 | | - msleep(cmd->header.delay); |
---|
| 280 | + usleep_range(cmd->header.delay * 1000, cmd->header.delay * 1000 + 100); |
---|
| 281 | + } |
---|
| 282 | + |
---|
| 283 | + return 0; |
---|
| 284 | +} |
---|
| 285 | + |
---|
| 286 | +static int panel_simple_xfer_spi_cmd_seq(struct panel_simple *panel, struct panel_cmd_seq *cmds) |
---|
| 287 | +{ |
---|
| 288 | + int i; |
---|
| 289 | + int ret; |
---|
| 290 | + |
---|
| 291 | + if (!cmds) |
---|
| 292 | + return -EINVAL; |
---|
| 293 | + |
---|
| 294 | + for (i = 0; i < cmds->cmd_cnt; i++) { |
---|
| 295 | + struct panel_cmd_desc *cmd = &cmds->cmds[i]; |
---|
| 296 | + |
---|
| 297 | + ret = panel->desc->spi_write(panel->base.dev, cmd->payload, |
---|
| 298 | + cmd->header.payload_length, cmd->header.data_type); |
---|
| 299 | + if (ret) |
---|
| 300 | + return ret; |
---|
| 301 | + |
---|
| 302 | + if (cmd->header.delay) |
---|
| 303 | + usleep_range(cmd->header.delay * 1000, cmd->header.delay * 1000 + 100); |
---|
270 | 304 | } |
---|
271 | 305 | |
---|
272 | 306 | return 0; |
---|
.. | .. |
---|
444 | 478 | return 0; |
---|
445 | 479 | |
---|
446 | 480 | if (p->desc->delay.disable) |
---|
447 | | - msleep(p->desc->delay.disable); |
---|
| 481 | + usleep_range(p->desc->delay.disable * 1000, p->desc->delay.disable * 1000 + 100); |
---|
448 | 482 | |
---|
449 | 483 | p->enabled = false; |
---|
450 | 484 | |
---|
.. | .. |
---|
458 | 492 | if (!p->prepared) |
---|
459 | 493 | return 0; |
---|
460 | 494 | |
---|
461 | | - if (p->desc->exit_seq) |
---|
462 | | - if (p->dsi) |
---|
463 | | - panel_simple_xfer_dsi_cmd_seq(p, p->desc->exit_seq); |
---|
| 495 | + if (p->desc->exit_seq) { |
---|
| 496 | + if (p->desc->cmd_type == CMD_TYPE_SPI) { |
---|
| 497 | + if (panel_simple_xfer_spi_cmd_seq(p, p->desc->exit_seq)) { |
---|
| 498 | + dev_err(panel->dev, "failed to send exit spi cmds seq\n"); |
---|
| 499 | + return -EINVAL; |
---|
| 500 | + } |
---|
| 501 | + } else { |
---|
| 502 | + if (p->dsi) |
---|
| 503 | + panel_simple_xfer_dsi_cmd_seq(p, p->desc->exit_seq); |
---|
| 504 | + } |
---|
| 505 | + } |
---|
464 | 506 | |
---|
465 | 507 | gpiod_direction_output(p->reset_gpio, 1); |
---|
466 | 508 | gpiod_direction_output(p->enable_gpio, 0); |
---|
.. | .. |
---|
468 | 510 | panel_simple_regulator_disable(p); |
---|
469 | 511 | |
---|
470 | 512 | if (p->desc->delay.unprepare) |
---|
471 | | - msleep(p->desc->delay.unprepare); |
---|
| 513 | + usleep_range(p->desc->delay.unprepare * 1000, p->desc->delay.unprepare * 1000 + 100); |
---|
472 | 514 | |
---|
473 | 515 | p->prepared = false; |
---|
474 | 516 | |
---|
.. | .. |
---|
522 | 564 | if (p->no_hpd) |
---|
523 | 565 | delay += p->desc->delay.hpd_absent_delay; |
---|
524 | 566 | if (delay) |
---|
525 | | - msleep(delay); |
---|
| 567 | + usleep_range(delay * 1000, delay * 1000 + 100); |
---|
526 | 568 | |
---|
527 | 569 | if (p->hpd_gpio) { |
---|
528 | 570 | if (IS_ERR(p->hpd_gpio)) { |
---|
.. | .. |
---|
547 | 589 | gpiod_direction_output(p->reset_gpio, 1); |
---|
548 | 590 | |
---|
549 | 591 | if (p->desc->delay.reset) |
---|
550 | | - msleep(p->desc->delay.reset); |
---|
| 592 | + usleep_range(p->desc->delay.reset * 1000, p->desc->delay.reset * 1000 + 100); |
---|
551 | 593 | |
---|
552 | 594 | gpiod_direction_output(p->reset_gpio, 0); |
---|
553 | 595 | |
---|
554 | 596 | if (p->desc->delay.init) |
---|
555 | | - msleep(p->desc->delay.init); |
---|
| 597 | + usleep_range(p->desc->delay.init * 1000, p->desc->delay.init * 1000 + 100); |
---|
556 | 598 | |
---|
557 | | - if (p->desc->init_seq) |
---|
558 | | - if (p->dsi) |
---|
559 | | - panel_simple_xfer_dsi_cmd_seq(p, p->desc->init_seq); |
---|
| 599 | + if (p->desc->init_seq) { |
---|
| 600 | + if (p->desc->cmd_type == CMD_TYPE_SPI) { |
---|
| 601 | + if (panel_simple_xfer_spi_cmd_seq(p, p->desc->init_seq)) { |
---|
| 602 | + dev_err(panel->dev, "failed to send init spi cmds seq\n"); |
---|
| 603 | + return -EINVAL; |
---|
| 604 | + } |
---|
| 605 | + } else { |
---|
| 606 | + if (p->dsi) |
---|
| 607 | + panel_simple_xfer_dsi_cmd_seq(p, p->desc->init_seq); |
---|
| 608 | + } |
---|
| 609 | + } |
---|
560 | 610 | |
---|
561 | 611 | p->prepared = true; |
---|
562 | 612 | |
---|
.. | .. |
---|
571 | 621 | return 0; |
---|
572 | 622 | |
---|
573 | 623 | if (p->desc->delay.enable) |
---|
574 | | - msleep(p->desc->delay.enable); |
---|
| 624 | + usleep_range(p->desc->delay.enable * 1000, p->desc->delay.enable * 1000 + 100); |
---|
575 | 625 | |
---|
576 | 626 | p->enabled = true; |
---|
577 | 627 | |
---|
.. | .. |
---|
5109 | 5159 | .shutdown = panel_simple_dsi_shutdown, |
---|
5110 | 5160 | }; |
---|
5111 | 5161 | |
---|
| 5162 | +static int panel_simple_spi_read(struct device *dev, const u8 cmd, u8 *data) |
---|
| 5163 | +{ |
---|
| 5164 | + return 0; |
---|
| 5165 | +} |
---|
| 5166 | + |
---|
| 5167 | +static int panel_simple_spi_write_word(struct device *dev, u16 data) |
---|
| 5168 | +{ |
---|
| 5169 | + struct spi_device *spi = to_spi_device(dev); |
---|
| 5170 | + struct spi_transfer xfer = { |
---|
| 5171 | + .len = 2, |
---|
| 5172 | + .tx_buf = &data, |
---|
| 5173 | + }; |
---|
| 5174 | + struct spi_message msg; |
---|
| 5175 | + |
---|
| 5176 | + spi_message_init(&msg); |
---|
| 5177 | + spi_message_add_tail(&xfer, &msg); |
---|
| 5178 | + |
---|
| 5179 | + return spi_sync(spi, &msg); |
---|
| 5180 | +} |
---|
| 5181 | + |
---|
| 5182 | +static int panel_simple_spi_write(struct device *dev, const u8 *data, size_t len, u8 type) |
---|
| 5183 | +{ |
---|
| 5184 | + int ret = 0; |
---|
| 5185 | + int i; |
---|
| 5186 | + u16 mask = type ? 0x100 : 0; |
---|
| 5187 | + |
---|
| 5188 | + for (i = 0; i < len; i++) { |
---|
| 5189 | + ret = panel_simple_spi_write_word(dev, *data | mask); |
---|
| 5190 | + if (ret) { |
---|
| 5191 | + dev_err(dev, "failed to write spi seq: %*ph\n", (int)len, data); |
---|
| 5192 | + return ret; |
---|
| 5193 | + } |
---|
| 5194 | + data++; |
---|
| 5195 | + } |
---|
| 5196 | + |
---|
| 5197 | + return ret; |
---|
| 5198 | +} |
---|
| 5199 | + |
---|
| 5200 | +static const struct of_device_id panel_simple_spi_of_match[] = { |
---|
| 5201 | + { .compatible = "simple-panel-spi", .data = NULL }, |
---|
| 5202 | + { /* sentinel */ } |
---|
| 5203 | +}; |
---|
| 5204 | +MODULE_DEVICE_TABLE(of, panel_simple_spi_of_match); |
---|
| 5205 | + |
---|
| 5206 | +static int panel_simple_spi_probe(struct spi_device *spi) |
---|
| 5207 | +{ |
---|
| 5208 | + struct device *dev = &spi->dev; |
---|
| 5209 | + const struct of_device_id *id; |
---|
| 5210 | + const struct panel_desc *desc; |
---|
| 5211 | + struct panel_desc *d; |
---|
| 5212 | + int ret; |
---|
| 5213 | + |
---|
| 5214 | + id = of_match_node(panel_simple_spi_of_match, dev->of_node); |
---|
| 5215 | + if (!id) |
---|
| 5216 | + return -ENODEV; |
---|
| 5217 | + |
---|
| 5218 | + if (!id->data) { |
---|
| 5219 | + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); |
---|
| 5220 | + if (!d) |
---|
| 5221 | + return -ENOMEM; |
---|
| 5222 | + |
---|
| 5223 | + ret = panel_simple_of_get_desc_data(dev, d); |
---|
| 5224 | + if (ret) { |
---|
| 5225 | + dev_err(dev, "failed to get desc data: %d\n", ret); |
---|
| 5226 | + return ret; |
---|
| 5227 | + } |
---|
| 5228 | + |
---|
| 5229 | + d->spi_write = panel_simple_spi_write; |
---|
| 5230 | + d->spi_read = panel_simple_spi_read; |
---|
| 5231 | + d->cmd_type = CMD_TYPE_SPI; |
---|
| 5232 | + } |
---|
| 5233 | + desc = id->data ? id->data : d; |
---|
| 5234 | + |
---|
| 5235 | + /* |
---|
| 5236 | + * Set spi to 3 lines and 9bits/word mode. |
---|
| 5237 | + */ |
---|
| 5238 | + spi->bits_per_word = 9; |
---|
| 5239 | + spi->mode = SPI_MODE_3; |
---|
| 5240 | + ret = spi_setup(spi); |
---|
| 5241 | + if (ret < 0) { |
---|
| 5242 | + dev_err(dev, "spi setup failed.\n"); |
---|
| 5243 | + return ret; |
---|
| 5244 | + } |
---|
| 5245 | + |
---|
| 5246 | + return panel_simple_probe(dev, desc); |
---|
| 5247 | +} |
---|
| 5248 | + |
---|
| 5249 | +static int panel_simple_spi_remove(struct spi_device *spi) |
---|
| 5250 | +{ |
---|
| 5251 | + return panel_simple_remove(&spi->dev); |
---|
| 5252 | +} |
---|
| 5253 | + |
---|
| 5254 | +static void panel_simple_spi_shutdown(struct spi_device *spi) |
---|
| 5255 | +{ |
---|
| 5256 | + panel_simple_shutdown(&spi->dev); |
---|
| 5257 | +} |
---|
| 5258 | + |
---|
| 5259 | +static struct spi_driver panel_simple_spi_driver = { |
---|
| 5260 | + .driver = { |
---|
| 5261 | + .name = "panel-simple-spi", |
---|
| 5262 | + .of_match_table = panel_simple_spi_of_match, |
---|
| 5263 | + }, |
---|
| 5264 | + .probe = panel_simple_spi_probe, |
---|
| 5265 | + .remove = panel_simple_spi_remove, |
---|
| 5266 | + .shutdown = panel_simple_spi_shutdown, |
---|
| 5267 | +}; |
---|
| 5268 | + |
---|
5112 | 5269 | static int __init panel_simple_init(void) |
---|
5113 | 5270 | { |
---|
5114 | 5271 | int err; |
---|
.. | .. |
---|
5116 | 5273 | err = platform_driver_register(&panel_simple_platform_driver); |
---|
5117 | 5274 | if (err < 0) |
---|
5118 | 5275 | return err; |
---|
| 5276 | + |
---|
| 5277 | + if (IS_ENABLED(CONFIG_SPI_MASTER)) { |
---|
| 5278 | + err = spi_register_driver(&panel_simple_spi_driver); |
---|
| 5279 | + if (err < 0) |
---|
| 5280 | + return err; |
---|
| 5281 | + } |
---|
5119 | 5282 | |
---|
5120 | 5283 | if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { |
---|
5121 | 5284 | err = mipi_dsi_driver_register(&panel_simple_dsi_driver); |
---|
.. | .. |
---|
5132 | 5295 | if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) |
---|
5133 | 5296 | mipi_dsi_driver_unregister(&panel_simple_dsi_driver); |
---|
5134 | 5297 | |
---|
| 5298 | + if (IS_ENABLED(CONFIG_SPI_MASTER)) |
---|
| 5299 | + spi_unregister_driver(&panel_simple_spi_driver); |
---|
| 5300 | + |
---|
5135 | 5301 | platform_driver_unregister(&panel_simple_platform_driver); |
---|
5136 | 5302 | } |
---|
5137 | 5303 | module_exit(panel_simple_exit); |
---|