diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2020-08-10 00:51:01 +0300 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2020-09-05 02:21:48 +0300 |
commit | b7b23e4476872d80b7d70cd24e158a0505fdad5f (patch) | |
tree | cd7e72a8bdb2ed9bec4976e75692a0d90cb3cd4f /drivers/gpu/drm/panel | |
parent | 4c8e84b8876dc726a7e5327b3113d75423c46728 (diff) | |
download | linux-b7b23e4476872d80b7d70cd24e158a0505fdad5f.tar.xz |
drm/panel: s6e63m0: Break out SPI transport
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.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Tested-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>
Acked-by: Paul Cercueil <paul@crapouillou.net>
Link: https://patchwork.freedesktop.org/patch/384873/
Diffstat (limited to 'drivers/gpu/drm/panel')
-rw-r--r-- | drivers/gpu/drm/panel/Kconfig | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c | 89 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-samsung-s6e63m0.c | 79 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-samsung-s6e63m0.h | 10 |
5 files changed, 124 insertions, 70 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 8d97d07c5871..f8d61e6addc3 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -324,13 +324,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 15a4e7752951..63f53bd88649 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@gmail.com>"); +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 2cc772fdc456..64d95201a7d4 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0.c @@ -16,10 +16,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 @@ -33,8 +34,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 */ @@ -87,6 +86,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; @@ -134,42 +134,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; - dev_dbg(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) { - dev_err(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 ...) \ @@ -429,9 +399,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; @@ -439,7 +409,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; @@ -460,14 +431,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) { - dev_err(dev, "spi setup failed.\n"); - return ret; - } - drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs, DRM_MODE_CONNECTOR_DPI); @@ -479,32 +442,14 @@ static int s6e63m0_probe(struct spi_device *spi) return 0; } +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@gmail.com>"); -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 */ |