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/
This commit is contained in:
parent
4c8e84b887
commit
b7b23e4476
5 changed files with 124 additions and 70 deletions
|
@ -324,13 +324,22 @@ config DRM_PANEL_SAMSUNG_S6E63J0X03
|
||||||
select VIDEOMODE_HELPERS
|
select VIDEOMODE_HELPERS
|
||||||
|
|
||||||
config DRM_PANEL_SAMSUNG_S6E63M0
|
config DRM_PANEL_SAMSUNG_S6E63M0
|
||||||
tristate "Samsung S6E63M0 RGB/SPI panel"
|
tristate "Samsung S6E63M0 RGB panel"
|
||||||
depends on OF
|
depends on OF
|
||||||
depends on SPI
|
|
||||||
depends on BACKLIGHT_CLASS_DEVICE
|
depends on BACKLIGHT_CLASS_DEVICE
|
||||||
help
|
help
|
||||||
Say Y here if you want to enable support for Samsung S6E63M0
|
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
|
config DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01
|
||||||
tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller"
|
tristate "Samsung AMS452EF01 panel with S6E88A0 DSI video mode controller"
|
||||||
|
|
|
@ -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_S6E3HA2) += panel-samsung-s6e3ha2.o
|
||||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.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) += 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_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o
|
||||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
|
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
|
||||||
obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
|
obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o
|
||||||
|
|
89
drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c
Normal file
89
drivers/gpu/drm/panel/panel-samsung-s6e63m0-spi.c
Normal file
|
@ -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");
|
|
@ -16,10 +16,11 @@
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/spi/spi.h>
|
|
||||||
|
|
||||||
#include <video/mipi_display.h>
|
#include <video/mipi_display.h>
|
||||||
|
|
||||||
|
#include "panel-samsung-s6e63m0.h"
|
||||||
|
|
||||||
/* Manufacturer Command Set */
|
/* Manufacturer Command Set */
|
||||||
#define MCS_ELVSS_ON 0xb1
|
#define MCS_ELVSS_ON 0xb1
|
||||||
#define MCS_MIECTL1 0xc0
|
#define MCS_MIECTL1 0xc0
|
||||||
|
@ -33,8 +34,6 @@
|
||||||
#define NUM_GAMMA_LEVELS 11
|
#define NUM_GAMMA_LEVELS 11
|
||||||
#define GAMMA_TABLE_COUNT 23
|
#define GAMMA_TABLE_COUNT 23
|
||||||
|
|
||||||
#define DATA_MASK 0x100
|
|
||||||
|
|
||||||
#define MAX_BRIGHTNESS (NUM_GAMMA_LEVELS - 1)
|
#define MAX_BRIGHTNESS (NUM_GAMMA_LEVELS - 1)
|
||||||
|
|
||||||
/* array of gamma tables for gamma value 2.2 */
|
/* 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 s6e63m0 {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
int (*dcs_write)(struct device *dev, const u8 *data, size_t len);
|
||||||
struct drm_panel panel;
|
struct drm_panel panel;
|
||||||
struct backlight_device *bl_dev;
|
struct backlight_device *bl_dev;
|
||||||
|
|
||||||
|
@ -134,42 +134,12 @@ static int s6e63m0_clear_error(struct s6e63m0 *ctx)
|
||||||
return ret;
|
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)
|
static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (ctx->error < 0 || len == 0)
|
if (ctx->error < 0 || len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data);
|
ctx->error = ctx->dcs_write(ctx->dev, data, len);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
|
#define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
|
||||||
|
@ -429,9 +399,9 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx)
|
||||||
return ret;
|
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;
|
struct s6e63m0 *ctx;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -439,7 +409,8 @@ static int s6e63m0_probe(struct spi_device *spi)
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spi_set_drvdata(spi, ctx);
|
ctx->dcs_write = dcs_write;
|
||||||
|
dev_set_drvdata(dev, ctx);
|
||||||
|
|
||||||
ctx->dev = dev;
|
ctx->dev = dev;
|
||||||
ctx->enabled = false;
|
ctx->enabled = false;
|
||||||
|
@ -460,14 +431,6 @@ static int s6e63m0_probe(struct spi_device *spi)
|
||||||
return PTR_ERR(ctx->reset_gpio);
|
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_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
|
||||||
DRM_MODE_CONNECTOR_DPI);
|
DRM_MODE_CONNECTOR_DPI);
|
||||||
|
|
||||||
|
@ -479,32 +442,14 @@ static int s6e63m0_probe(struct spi_device *spi)
|
||||||
|
|
||||||
return 0;
|
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);
|
drm_panel_remove(&ctx->panel);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(s6e63m0_remove);
|
||||||
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");
|
|
||||||
|
|
10
drivers/gpu/drm/panel/panel-samsung-s6e63m0.h
Normal file
10
drivers/gpu/drm/panel/panel-samsung-s6e63m0.h
Normal file
|
@ -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 */
|
Loading…
Add table
Reference in a new issue