This panel can be accessed using both SPI and DSI. To make it possible to probe and use the device also from a DSI bus, first break out the SPI support to its own file. Since all the panel driver does is write DCS commands to the panel, we pass a DCS write function to probe() from each subdriver. We make the Kconfig entry for SPI mode default so all current users will continue to work. Cc: Stephan Gerhold <stephan@xxxxxxxxxxx> Cc: Paweł Chmiel <pawel.mikolaj.chmiel@xxxxxxxxx> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> --- drivers/gpu/drm/panel/Kconfig | 15 +++- drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-samsung-s6e63m0-spi.c | 89 +++++++++++++++++++ drivers/gpu/drm/panel/panel-samsung-s6e63m0.c | 80 +++-------------- drivers/gpu/drm/panel/panel-samsung-s6e63m0.h | 10 +++ 5 files changed, 124 insertions(+), 71 deletions(-) create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e63m0.h diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 39055c1f0e2f..96e1548e475f 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -326,13 +326,22 @@ config DRM_PANEL_SAMSUNG_S6E63J0X03 select VIDEOMODE_HELPERS config DRM_PANEL_SAMSUNG_S6E63M0 - tristate "Samsung S6E63M0 RGB/SPI panel" + tristate "Samsung S6E63M0 RGB panel" depends on OF - depends on SPI depends on BACKLIGHT_CLASS_DEVICE help Say Y here if you want to enable support for Samsung S6E63M0 - AMOLED LCD panel. + AMOLED LCD panel. This panel can be accessed using SPI or + DSI. + +config DRM_PANEL_SAMSUNG_S6E63M0_SPI + tristate "Samsung S6E63M0 RGB SPI interface" + depends on SPI + depends on DRM_PANEL_SAMSUNG_S6E63M0 + default DRM_PANEL_SAMSUNG_S6E63M0 + help + Say Y here if you want to be able to access the Samsung + S6E63M0 panel using SPI. config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller" diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index de74f282c433..9cf71adfa794 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_SPI) += panel-samsung-s6e63m0-spi.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c new file mode 100644 index 000000000000..4082fbd75b79 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/delay.h> + +#include <drm/drm_print.h> + +#include "panel-samsung-s6e63m0.h" + +#define DATA_MASK 0x100 + +static int s6e63m0_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 s6e63m0_spi_dcs_write(struct device *dev, const u8 *data, size_t len) +{ + int ret = 0; + + DRM_DEV_DEBUG(dev, "SPI writing dcs seq: %*ph\n", (int)len, data); + ret = s6e63m0_spi_write_word(dev, *data); + + while (!ret && --len) { + ++data; + ret = s6e63m0_spi_write_word(dev, *data | DATA_MASK); + } + + if (ret) { + DRM_DEV_ERROR(dev, "SPI error %d writing dcs seq: %*ph\n", ret, + (int)len, data); + } + + usleep_range(300, 310); + + return ret; +} + +static int s6e63m0_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + int ret; + + spi->bits_per_word = 9; + spi->mode = SPI_MODE_3; + ret = spi_setup(spi); + if (ret < 0) { + DRM_DEV_ERROR(dev, "spi setup failed.\n"); + return ret; + } + return s6e63m0_probe(dev, s6e63m0_spi_dcs_write); +} + +static int s6e63m0_spi_remove(struct spi_device *spi) +{ + return s6e63m0_remove(&spi->dev); +} + +static const struct of_device_id s6e63m0_spi_of_match[] = { + { .compatible = "samsung,s6e63m0" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, s6e63m0_spi_of_match); + +static struct spi_driver s6e63m0_spi_driver = { + .probe = s6e63m0_spi_probe, + .remove = s6e63m0_spi_remove, + .driver = { + .name = "panel-samsung-s6e63m0", + .of_match_table = s6e63m0_spi_of_match, + }, +}; +module_spi_driver(s6e63m0_spi_driver); + +MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@xxxxxxxxx>"); +MODULE_DESCRIPTION("s6e63m0 LCD SPI Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c index a5f76eb4fa25..610676ef8a75 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -17,10 +17,11 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/regulator/consumer.h> -#include <linux/spi/spi.h> #include <video/mipi_display.h> +#include "panel-samsung-s6e63m0.h" + /* Manufacturer Command Set */ #define MCS_ELVSS_ON 0xb1 #define MCS_MIECTL1 0xc0 @@ -34,8 +35,6 @@ #define NUM_GAMMA_LEVELS 11 #define GAMMA_TABLE_COUNT 23 -#define DATA_MASK 0x100 - #define MAX_BRIGHTNESS (NUM_GAMMA_LEVELS - 1) /* array of gamma tables for gamma value 2.2 */ @@ -88,6 +87,7 @@ static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = { struct s6e63m0 { struct device *dev; + int (*dcs_write)(struct device *dev, const u8 *data, size_t len); struct drm_panel panel; struct backlight_device *bl_dev; @@ -136,43 +136,12 @@ static int s6e63m0_clear_error(struct s6e63m0 *ctx) return ret; } -static int s6e63m0_spi_write_word(struct s6e63m0 *ctx, u16 data) -{ - struct spi_device *spi = to_spi_device(ctx->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 void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len) { - int ret = 0; - if (ctx->error < 0 || len == 0) return; - DRM_DEV_DEBUG(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); - ret = s6e63m0_spi_write_word(ctx, *data); - - while (!ret && --len) { - ++data; - ret = s6e63m0_spi_write_word(ctx, *data | DATA_MASK); - } - - if (ret) { - DRM_DEV_ERROR(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, - (int)len, data); - ctx->error = ret; - } - - usleep_range(300, 310); + ctx->error = ctx->dcs_write(ctx->dev, data, len); } #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \ @@ -433,9 +402,9 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx) return ret; } -static int s6e63m0_probe(struct spi_device *spi) +int s6e63m0_probe(struct device *dev, + int (*dcs_write)(struct device *dev, const u8 *data, size_t len)) { - struct device *dev = &spi->dev; struct s6e63m0 *ctx; int ret; @@ -443,7 +412,8 @@ static int s6e63m0_probe(struct spi_device *spi) if (!ctx) return -ENOMEM; - spi_set_drvdata(spi, ctx); + ctx->dcs_write = dcs_write; + dev_set_drvdata(dev, ctx); ctx->dev = dev; ctx->enabled = false; @@ -465,14 +435,6 @@ static int s6e63m0_probe(struct spi_device *spi) return PTR_ERR(ctx->reset_gpio); } - spi->bits_per_word = 9; - spi->mode = SPI_MODE_3; - ret = spi_setup(spi); - if (ret < 0) { - DRM_DEV_ERROR(dev, "spi setup failed.\n"); - return ret; - } - drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs, DRM_MODE_CONNECTOR_DPI); @@ -482,32 +444,14 @@ static int s6e63m0_probe(struct spi_device *spi) return drm_panel_add(&ctx->panel); } +EXPORT_SYMBOL_GPL(s6e63m0_probe); -static int s6e63m0_remove(struct spi_device *spi) +int s6e63m0_remove(struct device *dev) { - struct s6e63m0 *ctx = spi_get_drvdata(spi); + struct s6e63m0 *ctx = dev_get_drvdata(dev); drm_panel_remove(&ctx->panel); return 0; } - -static const struct of_device_id s6e63m0_of_match[] = { - { .compatible = "samsung,s6e63m0" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, s6e63m0_of_match); - -static struct spi_driver s6e63m0_driver = { - .probe = s6e63m0_probe, - .remove = s6e63m0_remove, - .driver = { - .name = "panel-samsung-s6e63m0", - .of_match_table = s6e63m0_of_match, - }, -}; -module_spi_driver(s6e63m0_driver); - -MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@xxxxxxxxx>"); -MODULE_DESCRIPTION("s6e63m0 LCD Driver"); -MODULE_LICENSE("GPL v2"); +EXPORT_SYMBOL_GPL(s6e63m0_remove); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h new file mode 100644 index 000000000000..44e31f39f211 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _PANEL_SAMSUNG_S6E63M0_H +#define _PANEL_SAMSUNG_S6E63M0_H + +int s6e63m0_probe(struct device *dev, + int (*dcs_write)(struct device *dev, const u8 *data, size_t len)); +int s6e63m0_remove(struct device *dev); + +#endif /* _PANEL_SAMSUNG_S6E63M0_H */ -- 2.26.2 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel