Commit c2a61865 authored by Linus Walleij's avatar Linus Walleij
Browse files

drm/panel: s6e63m0: Switch to DBI abstraction for SPI



The SPI access to s6e63m0 is using the DBI protocol, so switch
to using the elaborate DBI protocol implementation in the DRM
DBI helper library.

Acked-by: default avatarNoralf Trønnes <noralf@tronnes.org>
Reviewed-by: default avatarDouglas Anderson <dianders@chromium.org>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210614181135.1124445-2-linus.walleij@linaro.org
parent 413f52f1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -388,6 +388,7 @@ config DRM_PANEL_SAMSUNG_S6E63M0_SPI
	depends on SPI
	depends on DRM_PANEL_SAMSUNG_S6E63M0
	default DRM_PANEL_SAMSUNG_S6E63M0
	select DRM_MIPI_DBI
	help
	  Say Y here if you want to be able to access the Samsung
	  S6E63M0 panel using SPI.
+6 −4
Original line number Diff line number Diff line
@@ -16,7 +16,8 @@
#define MCS_GLOBAL_PARAM	0xb0
#define S6E63M0_DSI_MAX_CHUNK	15 /* CMD + 15 bytes max */

static int s6e63m0_dsi_dcs_read(struct device *dev, const u8 cmd, u8 *data)
static int s6e63m0_dsi_dcs_read(struct device *dev, void *trsp,
				const u8 cmd, u8 *data)
{
	struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
	int ret;
@@ -32,7 +33,8 @@ static int s6e63m0_dsi_dcs_read(struct device *dev, const u8 cmd, u8 *data)
	return 0;
}

static int s6e63m0_dsi_dcs_write(struct device *dev, const u8 *data, size_t len)
static int s6e63m0_dsi_dcs_write(struct device *dev, void *trsp,
				 const u8 *data, size_t len)
{
	struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
	const u8 *seqp = data;
@@ -99,8 +101,8 @@ static int s6e63m0_dsi_probe(struct mipi_dsi_device *dsi)
	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
		MIPI_DSI_MODE_VIDEO_BURST;

	ret = s6e63m0_probe(dev, s6e63m0_dsi_dcs_read, s6e63m0_dsi_dcs_write,
			    true);
	ret = s6e63m0_probe(dev, NULL, s6e63m0_dsi_dcs_read,
			    s6e63m0_dsi_dcs_write, true);
	if (ret)
		return ret;

+31 −52
Original line number Diff line number Diff line
@@ -5,62 +5,38 @@
#include <linux/spi/spi.h>
#include <linux/delay.h>

#include <drm/drm_mipi_dbi.h>
#include <drm/drm_print.h>

#include "panel-samsung-s6e63m0.h"

#define DATA_MASK	0x100
static const u8 s6e63m0_dbi_read_commands[] = {
	MCS_READ_ID1,
	MCS_READ_ID2,
	MCS_READ_ID3,
	0, /* sentinel */
};

static int s6e63m0_spi_dcs_read(struct device *dev, const u8 cmd, u8 *data)
static int s6e63m0_spi_dcs_read(struct device *dev, void *trsp,
				const u8 cmd, u8 *data)
{
	struct spi_device *spi = to_spi_device(dev);
	u16 buf[1];
	u16 rbuf[1];
	struct mipi_dbi *dbi = trsp;
	int ret;

	/* SPI buffers are always in CPU order */
	buf[0] = (u16)cmd;
	ret = spi_write_then_read(spi, buf, 2, rbuf, 2);
	dev_dbg(dev, "READ CMD: %04x RET: %04x\n", buf[0], rbuf[0]);
	if (!ret)
		/* These high 8 bits of the 9 contains the readout */
		*data = (rbuf[0] & 0x1ff) >> 1;
	ret = mipi_dbi_command_read(dbi, cmd, data);
	if (ret)
		dev_err(dev, "error on DBI read command %02x\n", cmd);

	return ret;
}

static int s6e63m0_spi_write_word(struct device *dev, u16 data)
{
	struct spi_device *spi = to_spi_device(dev);

	/* SPI buffers are always in CPU order */
	return spi_write(spi, &data, 2);
}

static int s6e63m0_spi_dcs_write(struct device *dev, const u8 *data, size_t len)
static int s6e63m0_spi_dcs_write(struct device *dev, void *trsp,
				 const u8 *data, size_t len)
{
	int ret = 0;

	dev_dbg(dev, "SPI writing dcs seq: %*ph\n", (int)len, data);

	/*
	 * This sends 9 bits with the first bit (bit 8) set to 0
	 * This indicates that this is a command. Anything after the
	 * command is data.
	 */
	ret = s6e63m0_spi_write_word(dev, *data);

	while (!ret && --len) {
		++data;
		/* This sends 9 bits with the first bit (bit 8) set to 1 */
		ret = s6e63m0_spi_write_word(dev, *data | DATA_MASK);
	}

	if (ret) {
		dev_err(dev, "SPI error %d writing dcs seq: %*ph\n", ret,
			(int)len, data);
	}
	struct mipi_dbi *dbi = trsp;
	int ret;

	ret = mipi_dbi_command_stackbuf(dbi, data[0], (data + 1), (len - 1));
	usleep_range(300, 310);

	return ret;
@@ -69,18 +45,21 @@ static int s6e63m0_spi_dcs_write(struct device *dev, const u8 *data, size_t len)
static int s6e63m0_spi_probe(struct spi_device *spi)
{
	struct device *dev = &spi->dev;
	struct mipi_dbi *dbi;
	int ret;

	spi->bits_per_word = 9;
	/* Preserve e.g. SPI_3WIRE setting */
	spi->mode |= SPI_MODE_3;
	ret = spi_setup(spi);
	if (ret < 0) {
		dev_err(dev, "spi setup failed.\n");
		return ret;
	}
	return s6e63m0_probe(dev, s6e63m0_spi_dcs_read, s6e63m0_spi_dcs_write,
			     false);
	dbi = devm_kzalloc(dev, sizeof(*dbi), GFP_KERNEL);
	if (!dbi)
		return -ENOMEM;

	ret = mipi_dbi_spi_init(spi, dbi, NULL);
	if (ret)
		return dev_err_probe(dev, ret, "MIPI DBI init failed\n");
	/* Register our custom MCS read commands */
	dbi->read_commands = s6e63m0_dbi_read_commands;

	return s6e63m0_probe(dev, dbi, s6e63m0_spi_dcs_read,
			     s6e63m0_spi_dcs_write, false);
}

static int s6e63m0_spi_remove(struct spi_device *spi)
+9 −32
Original line number Diff line number Diff line
@@ -22,31 +22,6 @@

#include "panel-samsung-s6e63m0.h"

/* Manufacturer Command Set */
#define MCS_ELVSS_ON		0xb1
#define MCS_TEMP_SWIRE		0xb2
#define MCS_PENTILE_1		0xb3
#define MCS_PENTILE_2		0xb4
#define MCS_GAMMA_DELTA_Y_RED	0xb5
#define MCS_GAMMA_DELTA_X_RED	0xb6
#define MCS_GAMMA_DELTA_Y_GREEN	0xb7
#define MCS_GAMMA_DELTA_X_GREEN	0xb8
#define MCS_GAMMA_DELTA_Y_BLUE	0xb9
#define MCS_GAMMA_DELTA_X_BLUE	0xba
#define MCS_MIECTL1		0xc0
#define MCS_BCMODE		0xc1
#define MCS_ERROR_CHECK		0xd5
#define MCS_READ_ID1		0xda
#define MCS_READ_ID2		0xdb
#define MCS_READ_ID3		0xdc
#define MCS_LEVEL_2_KEY		0xf0
#define MCS_MTP_KEY		0xf1
#define MCS_DISCTL		0xf2
#define MCS_SRCCTL		0xf6
#define MCS_IFCTL		0xf7
#define MCS_PANELCTL		0xf8
#define MCS_PGAMMACTL		0xfa

#define S6E63M0_LCD_ID_VALUE_M2		0xA4
#define S6E63M0_LCD_ID_VALUE_SM2	0xB4
#define S6E63M0_LCD_ID_VALUE_SM2_1	0xB6
@@ -283,8 +258,9 @@ static u8 const s6e63m0_elvss_per_gamma[NUM_GAMMA_LEVELS] = {

struct s6e63m0 {
	struct device *dev;
	int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val);
	int (*dcs_write)(struct device *dev, const u8 *data, size_t len);
	void *transport_data;
	int (*dcs_read)(struct device *dev, void *trsp, const u8 cmd, u8 *val);
	int (*dcs_write)(struct device *dev, void *trsp, const u8 *data, size_t len);
	struct drm_panel panel;
	struct backlight_device *bl_dev;
	u8 lcd_type;
@@ -340,7 +316,7 @@ static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data)
	if (ctx->error < 0)
		return;

	ctx->error = ctx->dcs_read(ctx->dev, cmd, data);
	ctx->error = ctx->dcs_read(ctx->dev, ctx->transport_data, cmd, data);
}

static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
@@ -348,7 +324,7 @@ static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
	if (ctx->error < 0 || len == 0)
		return;

	ctx->error = ctx->dcs_write(ctx->dev, data, len);
	ctx->error = ctx->dcs_write(ctx->dev, ctx->transport_data, data, len);
}

#define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
@@ -713,9 +689,9 @@ static int s6e63m0_backlight_register(struct s6e63m0 *ctx, u32 max_brightness)
	return ret;
}

int s6e63m0_probe(struct device *dev,
		  int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
		  int (*dcs_write)(struct device *dev, const u8 *data, size_t len),
int s6e63m0_probe(struct device *dev, void *trsp,
		  int (*dcs_read)(struct device *dev, void *trsp, const u8 cmd, u8 *val),
		  int (*dcs_write)(struct device *dev, void *trsp, const u8 *data, size_t len),
		  bool dsi_mode)
{
	struct s6e63m0 *ctx;
@@ -726,6 +702,7 @@ int s6e63m0_probe(struct device *dev,
	if (!ctx)
		return -ENOMEM;

	ctx->transport_data = trsp;
	ctx->dsi_mode = dsi_mode;
	ctx->dcs_read = dcs_read;
	ctx->dcs_write = dcs_write;
+30 −3
Original line number Diff line number Diff line
@@ -3,9 +3,36 @@
#ifndef _PANEL_SAMSUNG_S6E63M0_H
#define _PANEL_SAMSUNG_S6E63M0_H

int s6e63m0_probe(struct device *dev,
		  int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
		  int (*dcs_write)(struct device *dev, const u8 *data,
/* Manufacturer Command Set */
#define MCS_ELVSS_ON		0xb1
#define MCS_TEMP_SWIRE		0xb2
#define MCS_PENTILE_1		0xb3
#define MCS_PENTILE_2		0xb4
#define MCS_GAMMA_DELTA_Y_RED	0xb5
#define MCS_GAMMA_DELTA_X_RED	0xb6
#define MCS_GAMMA_DELTA_Y_GREEN	0xb7
#define MCS_GAMMA_DELTA_X_GREEN	0xb8
#define MCS_GAMMA_DELTA_Y_BLUE	0xb9
#define MCS_GAMMA_DELTA_X_BLUE	0xba
#define MCS_MIECTL1		0xc0
#define MCS_BCMODE		0xc1
#define MCS_ERROR_CHECK		0xd5
#define MCS_READ_ID1		0xda
#define MCS_READ_ID2		0xdb
#define MCS_READ_ID3		0xdc
#define MCS_LEVEL_2_KEY		0xf0
#define MCS_MTP_KEY		0xf1
#define MCS_DISCTL		0xf2
#define MCS_SRCCTL		0xf6
#define MCS_IFCTL		0xf7
#define MCS_PANELCTL		0xf8
#define MCS_PGAMMACTL		0xfa

int s6e63m0_probe(struct device *dev, void *trsp,
		  int (*dcs_read)(struct device *dev, void *trsp,
				  const u8 cmd, u8 *val),
		  int (*dcs_write)(struct device *dev, void *trsp,
				   const u8 *data,
				   size_t len),
		  bool dsi_mode);
int s6e63m0_remove(struct device *dev);