This interface supports sending MIPI commands over an SPI bus.
This driver only implements the Type C1 protocol for now.

Signed-off-by: John Watts <cont...@jookia.org>
---
 drivers/video/Kconfig    |  6 ++++
 drivers/video/Makefile   |  1 +
 drivers/video/mipi_dbi.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++
 include/mipi_dbi.h       | 73 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 150 insertions(+)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7808ae7919..e9d069d440 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -157,6 +157,12 @@ config VIDEO_MIPI_DSI
          The MIPI Display Serial Interface (MIPI DSI) defines a high-speed
          serial interface between a host processor and a display module.
 
+config VIDEO_MIPI_DBI
+       bool "Support MIPI DBI interface"
+       help
+         Support MIPI DBI interface for driving a MIPI compatible device
+         over a SPI interface.
+
 config CONSOLE_NORMAL
        bool "Support a simple text console"
        default y
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index f3f70cd04a..ad77c60973 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o
 obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o
 obj-${CONFIG_VIDEO_MESON} += meson/
 obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o
+obj-${CONFIG_VIDEO_MIPI_DBI} += mipi_dbi.o
 obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o
 obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o
 obj-$(CONFIG_VIDEO_NX) += nexell_display.o videomodes.o nexell/
diff --git a/drivers/video/mipi_dbi.c b/drivers/video/mipi_dbi.c
new file mode 100644
index 0000000000..d7457bb6e2
--- /dev/null
+++ b/drivers/video/mipi_dbi.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MIPI DBI Bus support
+ *
+ * Copyright 2024 John Watts <cont...@jookia.org>
+ */
+
+#include <mipi_dbi.h>
+
+int mipi_dbi_spi_init(struct spi_slave *slave, struct mipi_dbi *dbi,
+                     struct gpio_desc *dc)
+{
+       /* D/C GPIO isn't supported yet */
+       if (dc)
+               return -1;
+
+       dbi->spi = slave;
+
+       return 0;
+}
+
+int mipi_dbi_xfer(struct mipi_dbi *dbi, u8 data, int pos, int len)
+{
+       struct spi_slave *spi = dbi->spi;
+       bool is_data = (pos != 0);
+       int flags = 0;
+       u8 buf[2];
+
+       /* Mimic Linux's behaviour of pulling CS active each word */
+       flags |= SPI_XFER_ONCE;
+
+       buf[0] = (is_data ? 0x80 : 0x00) | (data >> 1);
+       buf[1] = ((data & 0x1) << 7);
+
+       return spi_xfer(spi, 9, &buf, NULL, flags);
+}
+
+int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, const u8 *data, size_t 
len)
+{
+       struct spi_slave *spi = dbi->spi;
+       int wordlen;
+       int retval = -1;
+
+       if (spi_claim_bus(spi))
+               return -1;
+
+       wordlen = spi_set_wordlen(spi, 9);
+       if (wordlen == -1)
+               goto done;
+
+       if (mipi_dbi_xfer(dbi, cmd, 0, len) != 0)
+               goto done;
+
+       for (int i = 1; i <= len; ++i) {
+               u8 dat = data[i - 1];
+
+               if (mipi_dbi_xfer(dbi, dat, i, len) != 0)
+                       goto done;
+       }
+
+       retval = 0;
+
+done:
+       if (wordlen != -1)
+               spi_set_wordlen(spi, wordlen);
+
+       spi_release_bus(spi);
+
+       return retval;
+}
diff --git a/include/mipi_dbi.h b/include/mipi_dbi.h
new file mode 100644
index 0000000000..1c0c21ba81
--- /dev/null
+++ b/include/mipi_dbi.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MIPI DBI Bus support
+ *
+ * Copyright 2024 John Watts <cont...@jookia.org>
+ */
+#ifndef MIPI_DBI_H
+#define MIPI_DBI_H
+
+#include <asm/gpio.h>
+#include <mipi_display.h>
+#include <spi.h>
+
+/**
+ * struct mipi_dbi - MIPI DBI bus info
+ *
+ * This contains information about a MIPI DBI bus.
+ * Use mipi_dbi_spi_init to create and initialize this structure.
+ *
+ * @spi:       SPI slave this bus operates on.
+ */
+struct mipi_dbi {
+       struct spi_slave *spi;
+};
+
+/**
+ * mipi_dbi_spi_init - Creates a new MIPI DBI bus
+ *
+ * Creates and sets up a 'struct mipi_dbi' using the provided SPI slave
+ * and optional D/C GPIO.
+ *
+ * @slave:     SPI slave the bus is on
+ * @dbi:       Destination mipi_dbi structure to initialize
+ * @dc:                D/C GPIO (NULL if unused)
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+int mipi_dbi_spi_init(struct spi_slave *slave, struct mipi_dbi *dbi,
+                     struct gpio_desc *dc);
+
+/**
+ * mipi_dbi_command_buf - Sends a command and data over the bus
+ *
+ * Sends a command and any optional data over a bus.
+ *
+ * @dbi:       MIPI DBI bus to use
+ * @cmd:       MIPI DBI command
+ * @data:      Command data (NULL if len is 0)
+ * @len:       Length of data in bytes
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, const u8 *data, size_t 
len);
+
+/**
+ * mipi_dbi_command - Sends a command and data sequence over the bus
+ *
+ * Sends a command and any optional data over a bus.
+ * The data is a variadic sequence.
+ *
+ * @dbi:       MIPI DBI bus to use
+ * @cmd:       MIPI DBI command
+ * @seq:       Command data bytes
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+#define mipi_dbi_command(dbi, cmd, seq...) \
+({ \
+       const u8 data[] = { seq }; \
+       mipi_dbi_command_buf(dbi, cmd, data, ARRAY_SIZE(data)); \
+})
+
+#endif /* MIPI_DBI_H */

-- 
2.45.2

Reply via email to