]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
drm/panel: st7701: Add support for SPI for configuration
authorHironori KIKUCHI <kikuchan98@gmail.com>
Sun, 4 Aug 2024 06:14:48 +0000 (15:14 +0900)
committerNeil Armstrong <neil.armstrong@linaro.org>
Mon, 19 Aug 2024 15:49:31 +0000 (17:49 +0200)
The ST7701 supports not only MIPI DSI, but also SPI as an interface
for configuration. To support a panel connected via SPI with an RGB
parallel interface, add support for SPI using MIPI DBI helpers.

Signed-off-by: Hironori KIKUCHI <kikuchan98@gmail.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Reviewed-by: Jessica Zhang <quic_jesszhan@quicinc.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://lore.kernel.org/r/20240804061503.881283-5-kikuchan98@gmail.com
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20240804061503.881283-5-kikuchan98@gmail.com
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/panel-sitronix-st7701.c

index 9f49b0189d3b836a121243bfb2051ea902e8269e..5d83ddc06ece118594ae4bb709a5a1e1f69dde47 100644 (file)
@@ -784,7 +784,8 @@ config DRM_PANEL_SHARP_LS060T1SX01
 config DRM_PANEL_SITRONIX_ST7701
        tristate "Sitronix ST7701 panel driver"
        depends on OF
-       depends on DRM_MIPI_DSI
+       depends on SPI || DRM_MIPI_DSI
+       select DRM_MIPI_DBI if SPI
        depends on BACKLIGHT_CLASS_DEVICE
        help
          Say Y here if you want to enable support for the Sitronix
index a0644f7a4c8b6b7f257b6b009c5a1341d193eed8..9e83a760a8ab4d819fb9e7c05328dbbf9c8baed4 100644 (file)
@@ -4,6 +4,7 @@
  * Author: Jagan Teki <jagan@amarulasolutions.com>
  */
 
+#include <drm/drm_mipi_dbi.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_panel.h>
@@ -14,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
 
 #include <video/mipi_display.h>
 
@@ -130,12 +132,16 @@ struct st7701_panel_desc {
 struct st7701 {
        struct drm_panel panel;
        struct mipi_dsi_device *dsi;
+       struct mipi_dbi dbi;
        const struct st7701_panel_desc *desc;
 
        struct regulator_bulk_data supplies[2];
        struct gpio_desc *reset;
        unsigned int sleep_delay;
        enum drm_panel_orientation orientation;
+
+       int (*write_command)(struct st7701 *st7701, u8 cmd, const u8 *seq,
+                            size_t len);
 };
 
 static inline struct st7701 *panel_to_st7701(struct drm_panel *panel)
@@ -143,16 +149,22 @@ static inline struct st7701 *panel_to_st7701(struct drm_panel *panel)
        return container_of(panel, struct st7701, panel);
 }
 
-static inline int st7701_dsi_write(struct st7701 *st7701, const void *seq,
-                                  size_t len)
+static int st7701_dsi_write(struct st7701 *st7701, u8 cmd, const u8 *seq,
+                           size_t len)
+{
+       return mipi_dsi_dcs_write(st7701->dsi, cmd, seq, len);
+}
+
+static int st7701_dbi_write(struct st7701 *st7701, u8 cmd, const u8 *seq,
+                           size_t len)
 {
-       return mipi_dsi_dcs_write_buffer(st7701->dsi, seq, len);
+       return mipi_dbi_command_stackbuf(&st7701->dbi, cmd, seq, len);
 }
 
-#define ST7701_WRITE(st7701, seq...)                           \
-       {                                                       \
-               const u8 d[] = { seq };                         \
-               st7701_dsi_write(st7701, d, ARRAY_SIZE(d));     \
+#define ST7701_WRITE(st7701, cmd, seq...)                              \
+       {                                                               \
+               const u8 d[] = { seq };                                 \
+               st7701->write_command(st7701, cmd, d, ARRAY_SIZE(d));   \
        }
 
 static u8 st7701_vgls_map(struct st7701 *st7701)
@@ -211,10 +223,10 @@ static void st7701_init_sequence(struct st7701 *st7701)
        /* Command2, BK0 */
        st7701_switch_cmd_bkx(st7701, true, 0);
 
-       mipi_dsi_dcs_write(st7701->dsi, ST7701_CMD2_BK0_PVGAMCTRL,
-                          desc->pv_gamma, ARRAY_SIZE(desc->pv_gamma));
-       mipi_dsi_dcs_write(st7701->dsi, ST7701_CMD2_BK0_NVGAMCTRL,
-                          desc->nv_gamma, ARRAY_SIZE(desc->nv_gamma));
+       st7701->write_command(st7701, ST7701_CMD2_BK0_PVGAMCTRL, desc->pv_gamma,
+                             ARRAY_SIZE(desc->pv_gamma));
+       st7701->write_command(st7701, ST7701_CMD2_BK0_NVGAMCTRL, desc->nv_gamma,
+                             ARRAY_SIZE(desc->nv_gamma));
        /*
         * Vertical line count configuration:
         * Line[6:0]: select number of vertical lines of the TFT matrix in
@@ -1051,6 +1063,10 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
 
        st7701 = dev_get_drvdata(&dsi->dev);
        st7701->dsi = dsi;
+       st7701->write_command = st7701_dsi_write;
+
+       if (!st7701->desc->lanes)
+               return dev_err_probe(&dsi->dev, -EINVAL, "This panel is not for MIPI DSI\n");
 
        dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
                          MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS;
@@ -1064,30 +1080,107 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi)
        return 0;
 }
 
+static int st7701_spi_probe(struct spi_device *spi)
+{
+       struct st7701 *st7701;
+       struct gpio_desc *dc;
+       int err;
+
+       err = st7701_probe(&spi->dev, DRM_MODE_CONNECTOR_DPI);
+       if (err)
+               return err;
+
+       st7701 = dev_get_drvdata(&spi->dev);
+       st7701->write_command = st7701_dbi_write;
+
+       dc = devm_gpiod_get_optional(&spi->dev, "dc", GPIOD_OUT_LOW);
+       if (IS_ERR(dc))
+               return dev_err_probe(&spi->dev, PTR_ERR(dc), "Failed to get GPIO for D/CX\n");
+
+       err = mipi_dbi_spi_init(spi, &st7701->dbi, dc);
+       if (err)
+               return dev_err_probe(&spi->dev, err, "Failed to init MIPI DBI\n");
+       st7701->dbi.read_commands = NULL;
+
+       return 0;
+}
+
 static void st7701_dsi_remove(struct mipi_dsi_device *dsi)
 {
        mipi_dsi_detach(dsi);
 }
 
-static const struct of_device_id st7701_of_match[] = {
+static const struct of_device_id st7701_dsi_of_match[] = {
        { .compatible = "anbernic,rg-arc-panel", .data = &rg_arc_desc },
        { .compatible = "densitron,dmt028vghmcmi-1a", .data = &dmt028vghmcmi_1a_desc },
        { .compatible = "elida,kd50t048a", .data = &kd50t048a_desc },
        { .compatible = "techstar,ts8550b", .data = &ts8550b_desc },
        { }
 };
-MODULE_DEVICE_TABLE(of, st7701_of_match);
+MODULE_DEVICE_TABLE(of, st7701_dsi_of_match);
+
+static const struct of_device_id st7701_spi_of_match[] = {
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, st7701_spi_of_match);
+
+static const struct spi_device_id st7701_spi_ids[] = {
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, st7701_spi_ids);
 
 static struct mipi_dsi_driver st7701_dsi_driver = {
        .probe          = st7701_dsi_probe,
        .remove         = st7701_dsi_remove,
        .driver = {
                .name           = "st7701",
-               .of_match_table = st7701_of_match,
+               .of_match_table = st7701_dsi_of_match,
        },
 };
-module_mipi_dsi_driver(st7701_dsi_driver);
+
+static struct spi_driver st7701_spi_driver = {
+       .probe          = st7701_spi_probe,
+       .id_table       = st7701_spi_ids,
+       .driver = {
+               .name           = "st7701",
+               .of_match_table = st7701_spi_of_match,
+       },
+};
+
+static int __init st7701_driver_init(void)
+{
+       int err;
+
+       if (IS_ENABLED(CONFIG_SPI)) {
+               err = spi_register_driver(&st7701_spi_driver);
+               if (err)
+                       return err;
+       }
+
+       if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
+               err = mipi_dsi_driver_register(&st7701_dsi_driver);
+               if (err) {
+                       if (IS_ENABLED(CONFIG_SPI))
+                               spi_unregister_driver(&st7701_spi_driver);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+module_init(st7701_driver_init);
+
+static void __exit st7701_driver_exit(void)
+{
+       if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+               mipi_dsi_driver_unregister(&st7701_dsi_driver);
+
+       if (IS_ENABLED(CONFIG_SPI))
+               spi_unregister_driver(&st7701_spi_driver);
+}
+module_exit(st7701_driver_exit);
 
 MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
+MODULE_AUTHOR("Hironori KIKUCHI <kikuchan98@gmail.com>");
 MODULE_DESCRIPTION("Sitronix ST7701 LCD Panel Driver");
 MODULE_LICENSE("GPL");