From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 08:20:59 +0000 Subject: [PATCH] kernel_5.10 no rt --- kernel/drivers/gpu/drm/panel/panel-simple.c | 192 ++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 179 insertions(+), 13 deletions(-) diff --git a/kernel/drivers/gpu/drm/panel/panel-simple.c b/kernel/drivers/gpu/drm/panel/panel-simple.c index 5f4ce17..5d8a58b 100644 --- a/kernel/drivers/gpu/drm/panel/panel-simple.c +++ b/kernel/drivers/gpu/drm/panel/panel-simple.c @@ -28,6 +28,7 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> #include <video/display_timing.h> #include <video/mipi_display.h> @@ -41,6 +42,11 @@ #include <drm/drm_dsc.h> #include "panel-simple.h" + +enum panel_simple_cmd_type { + CMD_TYPE_DEFAULT, + CMD_TYPE_SPI +}; struct panel_cmd_header { u8 data_type; @@ -124,6 +130,11 @@ struct panel_cmd_seq *init_seq; struct panel_cmd_seq *exit_seq; + + enum panel_simple_cmd_type cmd_type; + + int (*spi_read)(struct device *dev, const u8 cmd, u8 *val); + int (*spi_write)(struct device *dev, const u8 *data, size_t len, u8 type); }; struct panel_simple { @@ -266,7 +277,30 @@ dev_err(dev, "failed to write dcs cmd: %d\n", err); if (cmd->header.delay) - msleep(cmd->header.delay); + usleep_range(cmd->header.delay * 1000, cmd->header.delay * 1000 + 100); + } + + return 0; +} + +static int panel_simple_xfer_spi_cmd_seq(struct panel_simple *panel, struct panel_cmd_seq *cmds) +{ + int i; + int ret; + + if (!cmds) + return -EINVAL; + + for (i = 0; i < cmds->cmd_cnt; i++) { + struct panel_cmd_desc *cmd = &cmds->cmds[i]; + + ret = panel->desc->spi_write(panel->base.dev, cmd->payload, + cmd->header.payload_length, cmd->header.data_type); + if (ret) + return ret; + + if (cmd->header.delay) + usleep_range(cmd->header.delay * 1000, cmd->header.delay * 1000 + 100); } return 0; @@ -444,7 +478,7 @@ return 0; if (p->desc->delay.disable) - msleep(p->desc->delay.disable); + usleep_range(p->desc->delay.disable * 1000, p->desc->delay.disable * 1000 + 100); p->enabled = false; @@ -458,9 +492,17 @@ if (!p->prepared) return 0; - if (p->desc->exit_seq) - if (p->dsi) - panel_simple_xfer_dsi_cmd_seq(p, p->desc->exit_seq); + if (p->desc->exit_seq) { + if (p->desc->cmd_type == CMD_TYPE_SPI) { + if (panel_simple_xfer_spi_cmd_seq(p, p->desc->exit_seq)) { + dev_err(panel->dev, "failed to send exit spi cmds seq\n"); + return -EINVAL; + } + } else { + if (p->dsi) + panel_simple_xfer_dsi_cmd_seq(p, p->desc->exit_seq); + } + } gpiod_direction_output(p->reset_gpio, 1); gpiod_direction_output(p->enable_gpio, 0); @@ -468,7 +510,7 @@ panel_simple_regulator_disable(p); if (p->desc->delay.unprepare) - msleep(p->desc->delay.unprepare); + usleep_range(p->desc->delay.unprepare * 1000, p->desc->delay.unprepare * 1000 + 100); p->prepared = false; @@ -522,7 +564,7 @@ if (p->no_hpd) delay += p->desc->delay.hpd_absent_delay; if (delay) - msleep(delay); + usleep_range(delay * 1000, delay * 1000 + 100); if (p->hpd_gpio) { if (IS_ERR(p->hpd_gpio)) { @@ -547,16 +589,24 @@ gpiod_direction_output(p->reset_gpio, 1); if (p->desc->delay.reset) - msleep(p->desc->delay.reset); + usleep_range(p->desc->delay.reset * 1000, p->desc->delay.reset * 1000 + 100); gpiod_direction_output(p->reset_gpio, 0); if (p->desc->delay.init) - msleep(p->desc->delay.init); + usleep_range(p->desc->delay.init * 1000, p->desc->delay.init * 1000 + 100); - if (p->desc->init_seq) - if (p->dsi) - panel_simple_xfer_dsi_cmd_seq(p, p->desc->init_seq); + if (p->desc->init_seq) { + if (p->desc->cmd_type == CMD_TYPE_SPI) { + if (panel_simple_xfer_spi_cmd_seq(p, p->desc->init_seq)) { + dev_err(panel->dev, "failed to send init spi cmds seq\n"); + return -EINVAL; + } + } else { + if (p->dsi) + panel_simple_xfer_dsi_cmd_seq(p, p->desc->init_seq); + } + } p->prepared = true; @@ -571,7 +621,7 @@ return 0; if (p->desc->delay.enable) - msleep(p->desc->delay.enable); + usleep_range(p->desc->delay.enable * 1000, p->desc->delay.enable * 1000 + 100); p->enabled = true; @@ -5109,6 +5159,113 @@ .shutdown = panel_simple_dsi_shutdown, }; +static int panel_simple_spi_read(struct device *dev, const u8 cmd, u8 *data) +{ + return 0; +} + +static int panel_simple_spi_write_word(struct device *dev, u16 data) +{ + struct spi_device *spi = to_spi_device(dev); + struct spi_transfer xfer = { + .len = 2, + .tx_buf = &data, + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(spi, &msg); +} + +static int panel_simple_spi_write(struct device *dev, const u8 *data, size_t len, u8 type) +{ + int ret = 0; + int i; + u16 mask = type ? 0x100 : 0; + + for (i = 0; i < len; i++) { + ret = panel_simple_spi_write_word(dev, *data | mask); + if (ret) { + dev_err(dev, "failed to write spi seq: %*ph\n", (int)len, data); + return ret; + } + data++; + } + + return ret; +} + +static const struct of_device_id panel_simple_spi_of_match[] = { + { .compatible = "simple-panel-spi", .data = NULL }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, panel_simple_spi_of_match); + +static int panel_simple_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + const struct of_device_id *id; + const struct panel_desc *desc; + struct panel_desc *d; + int ret; + + id = of_match_node(panel_simple_spi_of_match, dev->of_node); + if (!id) + return -ENODEV; + + if (!id->data) { + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + ret = panel_simple_of_get_desc_data(dev, d); + if (ret) { + dev_err(dev, "failed to get desc data: %d\n", ret); + return ret; + } + + d->spi_write = panel_simple_spi_write; + d->spi_read = panel_simple_spi_read; + d->cmd_type = CMD_TYPE_SPI; + } + desc = id->data ? id->data : d; + + /* + * Set spi to 3 lines and 9bits/word mode. + */ + spi->bits_per_word = 9; + spi->mode = SPI_MODE_3; + ret = spi_setup(spi); + if (ret < 0) { + dev_err(dev, "spi setup failed.\n"); + return ret; + } + + return panel_simple_probe(dev, desc); +} + +static int panel_simple_spi_remove(struct spi_device *spi) +{ + return panel_simple_remove(&spi->dev); +} + +static void panel_simple_spi_shutdown(struct spi_device *spi) +{ + panel_simple_shutdown(&spi->dev); +} + +static struct spi_driver panel_simple_spi_driver = { + .driver = { + .name = "panel-simple-spi", + .of_match_table = panel_simple_spi_of_match, + }, + .probe = panel_simple_spi_probe, + .remove = panel_simple_spi_remove, + .shutdown = panel_simple_spi_shutdown, +}; + static int __init panel_simple_init(void) { int err; @@ -5116,6 +5273,12 @@ err = platform_driver_register(&panel_simple_platform_driver); if (err < 0) return err; + + if (IS_ENABLED(CONFIG_SPI_MASTER)) { + err = spi_register_driver(&panel_simple_spi_driver); + if (err < 0) + return err; + } if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { err = mipi_dsi_driver_register(&panel_simple_dsi_driver); @@ -5132,6 +5295,9 @@ if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) mipi_dsi_driver_unregister(&panel_simple_dsi_driver); + if (IS_ENABLED(CONFIG_SPI_MASTER)) + spi_unregister_driver(&panel_simple_spi_driver); + platform_driver_unregister(&panel_simple_platform_driver); } module_exit(panel_simple_exit); -- Gitblit v1.6.2