drivers: display: ili9342c display driver
This driver implement basic functions of ili9342c controller
which comes mostly with IPS displays.
Signed-off-by: Mohamed ElShahawi <ExtremeGTX@hotmail.com>
diff --git a/CODEOWNERS b/CODEOWNERS
index ab587e7..edda445 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -256,6 +256,7 @@
/drivers/counter/*esp32* @sylvioalves
/drivers/crypto/*nrf_ecb* @maciekfabia @anangl
/drivers/display/*rm68200* @mmahadevan108
+/drivers/display/display_ili9342c.* @extremegtx
/drivers/dac/ @martinjaeger
/drivers/dai/ @juimonen @marcinszkudlinski @abonislawski
/drivers/dai/intel/ @juimonen @marcinszkudlinski @abonislawski
diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt
index 82b51b5..4e7bcd0 100644
--- a/drivers/display/CMakeLists.txt
+++ b/drivers/display/CMakeLists.txt
@@ -10,6 +10,7 @@
zephyr_library_sources_ifdef(CONFIG_ILI9XXX display_ili9xxx.c)
zephyr_library_sources_ifdef(CONFIG_ILI9340 display_ili9340.c)
zephyr_library_sources_ifdef(CONFIG_ILI9341 display_ili9341.c)
+zephyr_library_sources_ifdef(CONFIG_ILI9342C display_ili9342c.c)
zephyr_library_sources_ifdef(CONFIG_ILI9488 display_ili9488.c)
zephyr_library_sources_ifdef(CONFIG_LS0XX ls0xx.c)
zephyr_library_sources_ifdef(CONFIG_MAX7219 display_max7219.c)
diff --git a/drivers/display/Kconfig.ili9xxx b/drivers/display/Kconfig.ili9xxx
index ec3f6ab..0ae8492 100644
--- a/drivers/display/Kconfig.ili9xxx
+++ b/drivers/display/Kconfig.ili9xxx
@@ -28,6 +28,15 @@
help
Enable driver for ILI9341 display driver.
+config ILI9342C
+ bool "ILI9342C display driver"
+ default y
+ depends on DT_HAS_ILITEK_ILI9342C_ENABLED
+ select SPI
+ select ILI9XXX
+ help
+ Enable driver for ILI9342C display driver.
+
config ILI9488
bool "ILI9488 display driver"
default y
diff --git a/drivers/display/display_ili9342c.c b/drivers/display/display_ili9342c.c
new file mode 100644
index 0000000..c394b30
--- /dev/null
+++ b/drivers/display/display_ili9342c.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2020 Teslabs Engineering S.L.
+ * Copyright (c) 2021 Krivorot Oleg <krivorot.oleg@gmail.com>
+ * Copyright (c) 2022 Konstantinos Papadopoulos <kostas.papadopulos@gmail.com>
+ * Copyright (c) 2022 Mohamed ElShahawi <ExtremeGTX@hotmail.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "display_ili9342c.h"
+#include "display_ili9xxx.h"
+
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(display_ili9342c, CONFIG_DISPLAY_LOG_LEVEL);
+
+int ili9342c_regs_init(const struct device *dev)
+{
+ const struct ili9xxx_config *config = dev->config;
+ const struct ili9342c_regs *regs = config->regs;
+ int r;
+
+ /* some commands require that SETEXTC be set first before it becomes enabled. */
+ LOG_HEXDUMP_DBG(regs->setextc, ILI9342C_SETEXTC_LEN, "SETEXTC");
+ r = ili9xxx_transmit(dev, ILI9342C_SETEXTC, regs->setextc,
+ ILI9342C_SETEXTC_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->gamset, ILI9342C_GAMSET_LEN, "GAMSET");
+ r = ili9xxx_transmit(dev, ILI9342C_GAMSET, regs->gamset,
+ ILI9342C_GAMSET_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->ifmode, ILI9342C_IFMODE_LEN, "IFMODE");
+ r = ili9xxx_transmit(dev, ILI9342C_IFMODE, regs->ifmode,
+ ILI9342C_IFMODE_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->frmctr1, ILI9342C_FRMCTR1_LEN, "FRMCTR1");
+ r = ili9xxx_transmit(dev, ILI9342C_FRMCTR1, regs->frmctr1,
+ ILI9342C_FRMCTR1_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->invtr, ILI9342C_INVTR_LEN, "INVTR");
+ r = ili9xxx_transmit(dev, ILI9342C_INVTR, regs->invtr,
+ ILI9342C_INVTR_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->disctrl, ILI9342C_DISCTRL_LEN, "DISCTRL");
+ r = ili9xxx_transmit(dev, ILI9342C_DISCTRL, regs->disctrl,
+ ILI9342C_DISCTRL_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->etmod, ILI9342C_ETMOD_LEN, "ETMOD");
+ r = ili9xxx_transmit(dev, ILI9342C_ETMOD, regs->etmod,
+ ILI9342C_ETMOD_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->pwctrl1, ILI9342C_PWCTRL1_LEN, "PWCTRL1");
+ r = ili9xxx_transmit(dev, ILI9342C_PWCTRL1, regs->pwctrl1,
+ ILI9342C_PWCTRL1_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->pwctrl2, ILI9342C_PWCTRL2_LEN, "PWCTRL2");
+ r = ili9xxx_transmit(dev, ILI9342C_PWCTRL2, regs->pwctrl2,
+ ILI9342C_PWCTRL2_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->pwctrl3, ILI9342C_PWCTRL3_LEN, "PWCTRL3");
+ r = ili9xxx_transmit(dev, ILI9342C_PWCTRL3, regs->pwctrl3,
+ ILI9342C_PWCTRL3_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->vmctrl1, ILI9342C_VMCTRL1_LEN, "VMCTRL1");
+ r = ili9xxx_transmit(dev, ILI9342C_VMCTRL1, regs->vmctrl1,
+ ILI9342C_VMCTRL1_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->pgamctrl, ILI9342C_PGAMCTRL_LEN, "PGAMCTRL");
+ r = ili9xxx_transmit(dev, ILI9342C_PGAMCTRL, regs->pgamctrl,
+ ILI9342C_PGAMCTRL_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->ngamctrl, ILI9342C_NGAMCTRL_LEN, "NGAMCTRL");
+ r = ili9xxx_transmit(dev, ILI9342C_NGAMCTRL, regs->ngamctrl,
+ ILI9342C_NGAMCTRL_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ LOG_HEXDUMP_DBG(regs->ifctl, ILI9342C_IFCTL_LEN, "IFCTL");
+ r = ili9xxx_transmit(dev, ILI9342C_IFCTL, regs->ifctl,
+ ILI9342C_IFCTL_LEN);
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
+}
diff --git a/drivers/display/display_ili9342c.h b/drivers/display/display_ili9342c.h
new file mode 100644
index 0000000..c5cc8fb
--- /dev/null
+++ b/drivers/display/display_ili9342c.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020 Teslabs Engineering S.L.
+ * Copyright (c) 2021 Krivorot Oleg <krivorot.oleg@gmail.com>
+ * Copyright (c) 2022 Konstantinos Papadopoulos <kostas.papadopulos@gmail.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9342C_H_
+#define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9342C_H_
+
+#include <zephyr/device.h>
+
+/* Commands/registers. */
+#define ILI9342C_GAMSET 0x26
+#define ILI9342C_IFMODE 0xB0
+#define ILI9342C_FRMCTR1 0xB1
+#define ILI9342C_INVTR 0xB4
+#define ILI9342C_DISCTRL 0xB6
+#define ILI9342C_ETMOD 0xB7
+#define ILI9342C_PWCTRL1 0xC0
+#define ILI9342C_PWCTRL2 0xC1
+#define ILI9342C_PWCTRL3 0xC2
+#define ILI9342C_VMCTRL1 0xC5
+#define ILI9342C_SETEXTC 0xC8
+#define ILI9342C_PGAMCTRL 0xE0
+#define ILI9342C_NGAMCTRL 0xE1
+#define ILI9342C_IFCTL 0xF6
+
+/* Commands/registers length. */
+#define ILI9342C_GAMSET_LEN 1U
+#define ILI9342C_IFMODE_LEN 1U
+#define ILI9342C_FRMCTR1_LEN 2U
+#define ILI9342C_INVTR_LEN 1U
+#define ILI9342C_DISCTRL_LEN 4U
+#define ILI9342C_ETMOD_LEN 1U
+#define ILI9342C_PWCTRL1_LEN 2U
+#define ILI9342C_PWCTRL2_LEN 1U
+#define ILI9342C_PWCTRL3_LEN 1U
+#define ILI9342C_VMCTRL1_LEN 1U
+#define ILI9342C_SETEXTC_LEN 3U
+#define ILI9342C_PGAMCTRL_LEN 15U
+#define ILI9342C_NGAMCTRL_LEN 15U
+#define ILI9342C_IFCTL_LEN 3U
+
+/** X resolution (pixels). */
+#define ILI9342c_X_RES 320U
+/** Y resolution (pixels). */
+#define ILI9342c_Y_RES 240U
+
+/** ILI9342C registers to be initialized. */
+struct ili9342c_regs {
+ uint8_t gamset[ILI9342C_GAMSET_LEN];
+ uint8_t ifmode[ILI9342C_IFMODE_LEN];
+ uint8_t frmctr1[ILI9342C_FRMCTR1_LEN];
+ uint8_t invtr[ILI9342C_INVTR_LEN];
+ uint8_t disctrl[ILI9342C_DISCTRL_LEN];
+ uint8_t etmod[ILI9342C_ETMOD_LEN];
+ uint8_t pwctrl1[ILI9342C_PWCTRL1_LEN];
+ uint8_t pwctrl2[ILI9342C_PWCTRL2_LEN];
+ uint8_t pwctrl3[ILI9342C_PWCTRL3_LEN];
+ uint8_t vmctrl1[ILI9342C_VMCTRL1_LEN];
+ uint8_t setextc[ILI9342C_SETEXTC_LEN];
+ uint8_t pgamctrl[ILI9342C_PGAMCTRL_LEN];
+ uint8_t ngamctrl[ILI9342C_NGAMCTRL_LEN];
+ uint8_t ifctl[ILI9342C_IFCTL_LEN];
+};
+
+/* Initializer macro for ILI9342C registers. */
+#define ILI9342c_REGS_INIT(n) \
+ static const struct ili9342c_regs ili9xxx_regs_##n = { \
+ .gamset = DT_PROP(DT_INST(n, ilitek_ili9342c), gamset), \
+ .ifmode = DT_PROP(DT_INST(n, ilitek_ili9342c), ifmode), \
+ .frmctr1 = DT_PROP(DT_INST(n, ilitek_ili9342c), frmctr1), \
+ .invtr = DT_PROP(DT_INST(n, ilitek_ili9342c), invtr), \
+ .disctrl = DT_PROP(DT_INST(n, ilitek_ili9342c), disctrl), \
+ .etmod = DT_PROP(DT_INST(n, ilitek_ili9342c), etmod), \
+ .pwctrl1 = DT_PROP(DT_INST(n, ilitek_ili9342c), pwctrl1), \
+ .pwctrl2 = DT_PROP(DT_INST(n, ilitek_ili9342c), pwctrl2), \
+ .pwctrl3 = DT_PROP(DT_INST(n, ilitek_ili9342c), pwctrl3), \
+ .vmctrl1 = DT_PROP(DT_INST(n, ilitek_ili9342c), vmctrl1), \
+ .setextc = {0xFF, 0x93, 0x42}, \
+ .pgamctrl = DT_PROP(DT_INST(n, ilitek_ili9342c), pgamctrl), \
+ .ngamctrl = DT_PROP(DT_INST(n, ilitek_ili9342c), ngamctrl), \
+ .ifctl = DT_PROP(DT_INST(n, ilitek_ili9342c), ifctl), \
+ };
+
+/**
+ * @brief Initialize ILI9342C registers with DT values.
+ *
+ * @param dev ILI9342C device instance
+ * @return 0 on success, errno otherwise.
+ */
+int ili9342c_regs_init(const struct device *dev);
+
+#endif /* ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9342C_H_ */
diff --git a/drivers/display/display_ili9xxx.c b/drivers/display/display_ili9xxx.c
index abfaa27..c66ea98 100644
--- a/drivers/display/display_ili9xxx.c
+++ b/drivers/display/display_ili9xxx.c
@@ -244,20 +244,32 @@
static int ili9xxx_set_orientation(const struct device *dev,
const enum display_orientation orientation)
{
+ const struct ili9xxx_config *config = dev->config;
struct ili9xxx_data *data = dev->data;
int r;
uint8_t tx_data = ILI9XXX_MADCTL_BGR;
-
- if (orientation == DISPLAY_ORIENTATION_NORMAL) {
- tx_data |= ILI9XXX_MADCTL_MX;
- } else if (orientation == DISPLAY_ORIENTATION_ROTATED_90) {
- tx_data |= ILI9XXX_MADCTL_MV;
- } else if (orientation == DISPLAY_ORIENTATION_ROTATED_180) {
- tx_data |= ILI9XXX_MADCTL_MY;
- } else if (orientation == DISPLAY_ORIENTATION_ROTATED_270) {
- tx_data |= ILI9XXX_MADCTL_MV | ILI9XXX_MADCTL_MX |
- ILI9XXX_MADCTL_MY;
+ if (config->quirks->cmd_set == CMD_SET_1) {
+ if (orientation == DISPLAY_ORIENTATION_NORMAL) {
+ tx_data |= ILI9XXX_MADCTL_MX;
+ } else if (orientation == DISPLAY_ORIENTATION_ROTATED_90) {
+ tx_data |= ILI9XXX_MADCTL_MV;
+ } else if (orientation == DISPLAY_ORIENTATION_ROTATED_180) {
+ tx_data |= ILI9XXX_MADCTL_MY;
+ } else if (orientation == DISPLAY_ORIENTATION_ROTATED_270) {
+ tx_data |= ILI9XXX_MADCTL_MV | ILI9XXX_MADCTL_MX |
+ ILI9XXX_MADCTL_MY;
+ }
+ } else if (config->quirks->cmd_set == CMD_SET_2) {
+ if (orientation == DISPLAY_ORIENTATION_NORMAL) {
+ /* Do nothing */
+ } else if (orientation == DISPLAY_ORIENTATION_ROTATED_90) {
+ tx_data |= ILI9XXX_MADCTL_MV | ILI9XXX_MADCTL_MY;
+ } else if (orientation == DISPLAY_ORIENTATION_ROTATED_180) {
+ tx_data |= ILI9XXX_MADCTL_MY | ILI9XXX_MADCTL_MX;
+ } else if (orientation == DISPLAY_ORIENTATION_ROTATED_270) {
+ tx_data |= ILI9XXX_MADCTL_MV | ILI9XXX_MADCTL_MX;
+ }
}
r = ili9xxx_transmit(dev, ILI9XXX_MADCTL, &tx_data, 1U);
@@ -420,12 +432,37 @@
.set_orientation = ili9xxx_set_orientation,
};
+#ifdef CONFIG_ILI9340
+static const struct ili9xxx_quirks ili9340_quirks = {
+ .cmd_set = CMD_SET_1,
+};
+#endif
+
+#ifdef CONFIG_ILI9341
+static const struct ili9xxx_quirks ili9341_quirks = {
+ .cmd_set = CMD_SET_1,
+};
+#endif
+
+#ifdef CONFIG_ILI9342C
+static const struct ili9xxx_quirks ili9342c_quirks = {
+ .cmd_set = CMD_SET_2,
+};
+#endif
+
+#ifdef CONFIG_ILI9488
+static const struct ili9xxx_quirks ili9488_quirks = {
+ .cmd_set = CMD_SET_1,
+};
+#endif
+
#define INST_DT_ILI9XXX(n, t) DT_INST(n, ilitek_ili##t)
#define ILI9XXX_INIT(n, t) \
ILI##t##_REGS_INIT(n); \
\
static const struct ili9xxx_config ili9xxx_config_##n = { \
+ .quirks = &ili##t##_quirks, \
.spi = SPI_DT_SPEC_GET(INST_DT_ILI9XXX(n, t), \
SPI_OP_MODE_MASTER | SPI_WORD_SET(8), \
0), \
@@ -462,6 +499,11 @@
DT_INST_FOREACH_ILI9XXX_STATUS_OKAY(9341);
#endif
+#ifdef CONFIG_ILI9342C
+#include "display_ili9342c.h"
+DT_INST_FOREACH_ILI9XXX_STATUS_OKAY(9342c);
+#endif
+
#ifdef CONFIG_ILI9488
#include "display_ili9488.h"
DT_INST_FOREACH_ILI9XXX_STATUS_OKAY(9488);
diff --git a/drivers/display/display_ili9xxx.h b/drivers/display/display_ili9xxx.h
index 3f3fe86..2cd6da9 100644
--- a/drivers/display/display_ili9xxx.h
+++ b/drivers/display/display_ili9xxx.h
@@ -54,7 +54,18 @@
/** Reset wait time (ms), ref 15.4 of ILI9XXX manual. */
#define ILI9XXX_RESET_WAIT_TIME 5
+enum madctl_cmd_set {
+ CMD_SET_1, /* Default for most of ILI9xxx display controllers */
+ CMD_SET_2, /* Used by ILI9342c */
+};
+
+struct ili9xxx_quirks {
+ enum madctl_cmd_set cmd_set;
+};
+
struct ili9xxx_config {
+ const struct ili9xxx_quirks *quirks;
+
struct spi_dt_spec spi;
struct gpio_dt_spec cmd_data;
struct gpio_dt_spec reset;
diff --git a/dts/bindings/display/ilitek,ili9342c.yaml b/dts/bindings/display/ilitek,ili9342c.yaml
new file mode 100644
index 0000000..37cf599
--- /dev/null
+++ b/dts/bindings/display/ilitek,ili9342c.yaml
@@ -0,0 +1,124 @@
+# Copyright (c) 2018, Jan Van Winkel <jan.van_winkel@dxplore.eu>
+# Copyright (c) 2020, Teslabs Engineering S.L.
+# Copyright (c) 2021, Krivorot Oleg <krivorot.oleg@gmail.com>
+# Copyright (c) 2022, Konstantinos Papadopulos <kostas.papadopulos@gmail.com>
+# SPDX-License-Identifier: Apache-2.0
+
+description: ILI9342C 320x240 display controller
+
+compatible: "ilitek,ili9342c"
+
+include: ilitek,ili9xxx-common.yaml
+
+properties:
+ gamset:
+ type: uint8-array
+ default: [0x01]
+ description:
+ select the desired Gamma curve for the current display.
+ A maximum of 4 fixed gamma curves canbe selected.
+
+ ifmode:
+ type: uint8-array
+ default: [0x40]
+ description:
+ RGB interface signal control (IFMOD) register value.
+
+ invtr:
+ type: uint8-array
+ default: [0x00]
+ description:
+ Display Inversion Control (INVTR) register value.
+
+ frmctr1:
+ type: uint8-array
+ default: [0x00, 0x1c]
+ description:
+ Frame rate control (in normal mode / full colors) (FRMCTR1) register value.
+
+ disctrl:
+ type: uint8-array
+ default: [0x0a, 0x80, 0x1d, 0x04]
+ description:
+ Display function control (DISCTRL) register value. Note that changing
+ default SS bit value (0) may interfere with display rotation.
+
+ etmod:
+ type: uint8-array
+ default: [0x07]
+ description:
+ Entry Mode set (ETMOD)
+
+ pwctrl1:
+ type: uint8-array
+ default: [0x9, 0x9]
+ description:
+ Power control 1 (PWCTRL1) register values.
+
+ pwctrl2:
+ type: uint8-array
+ default: [0x00]
+ description:
+ Power control 2 (PWCTRL2) register values.
+
+ pwctrl3:
+ type: uint8-array
+ default: [0xB2]
+ description:
+ Power control 3 (PWCTRL3) register values.
+
+ vmctrl1:
+ type: uint8-array
+ default: [0xf2]
+ description:
+ VCOM control 1 (VMCTRL1) register values.
+
+ pgamctrl:
+ type: uint8-array
+ default: [
+ 0x00,
+ 0x05,
+ 0x08,
+ 0x04,
+ 0x13,
+ 0x0A,
+ 0x34,
+ 0x8A,
+ 0x46,
+ 0x07,
+ 0x0E,
+ 0x0A,
+ 0x1B,
+ 0x1D,
+ 0x0F
+ ]
+ description:
+ Positive gamma correction (PGAMCTRL) register values.
+
+ ngamctrl:
+ type: uint8-array
+ default: [
+ 0x00,
+ 0x22,
+ 0x25,
+ 0x04,
+ 0x0F,
+ 0x06,
+ 0x38,
+ 0x56,
+ 0x4B,
+ 0x05,
+ 0x0C,
+ 0x0A,
+ 0x37,
+ 0x3A,
+ 0x0F
+ ]
+ description:
+ Negative gamma correction (NGAMCTRL) register values.
+
+ ifctl:
+ type: uint8-array
+ default: [0x01, 0x00, 0x00]
+ description:
+ Interface control (IFCTL) register value.