From 9fdaf43e79331f87b4f1a8bcea21613c9969389b Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 5 Jun 2024 11:52:28 -0500 Subject: [PATCH] drivers: display: uc81xx: convert to MIPI DBI API Convert UC81XX display to use MIPI DBI API, as this display uses a SPI 3/4 wire bus. In tree shields using this driver have also had their devicetrees updated to use the new MIPI DBI SPI driver Signed-off-by: Daniel DeGrasse --- .../waveshare_epaper_gdew042t2-p.overlay | 146 +++++++++--------- .../waveshare_epaper_gdew042t2.overlay | 36 +++-- .../waveshare_epaper_gdew075t7.overlay | 36 +++-- drivers/display/Kconfig.uc81xx | 2 +- drivers/display/uc81xx.c | 114 +++++--------- .../display/ultrachip,uc81xx-common.yaml | 21 +-- 6 files changed, 157 insertions(+), 198 deletions(-) diff --git a/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2-p.overlay b/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2-p.overlay index 35f96d940e2..2a1024ece0d 100644 --- a/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2-p.overlay +++ b/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2-p.overlay @@ -8,87 +8,93 @@ / { chosen { - zephyr,display = &uc8176_waveshare_epaper_gdew042t2-p; + zephyr,display = &uc8176_waveshare_epaper_gdew042t2_p; }; -}; -&arduino_spi { - /* - * GoodDisplay GDEW042T2 with fast partial refresh. Based on - * configuration from GoodDisplay's Arduino example. - */ - uc8176_waveshare_epaper_gdew042t2-p: uc8176@0 { - compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176"; - spi-max-frequency = <4000000>; - reg = <0>; - width = <400>; - height = <300>; - dc-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ + mipi_dbi_waveshare_epaper_gdew042t2-p { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&arduino_spi>; + dc-gpios = <&arduino_header 15 GPIO_ACTIVE_HIGH>; /* D9 */ reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ - busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ + write-only; + #address-cells = <1>; + #size-cells = <0>; - softstart = [ 17 17 17 ]; + /* + * GoodDisplay GDEW042T2 with fast partial refresh. Based on + * configuration from GoodDisplay's Arduino example. + */ + uc8176_waveshare_epaper_gdew042t2_p: uc8176@0 { + compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176"; + mipi-max-frequency = <4000000>; + reg = <0>; + width = <400>; + height = <300>; + busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ - full { - cdi = <0x07>; - }; + softstart = [ 17 17 17 ]; - partial { - pwr = [ 03 02 2b 2b ]; - cdi = <0x07>; - pll = <0x3c>; - vdcs = <0x08>; + full { + cdi = <0x07>; + }; - lutc = [ - 00 01 0E 00 00 01 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 - ]; + partial { + pwr = [ 03 02 2b 2b ]; + cdi = <0x07>; + pll = <0x3c>; + vdcs = <0x08>; - lutww = [ - 00 01 0E 00 00 01 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - ]; + lutc = [ + 00 01 0E 00 00 01 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 + ]; - lutkw = [ - 20 01 0E 00 00 01 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - ]; + lutww = [ + 00 01 0E 00 00 01 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + ]; - lutwk = [ - 10 01 0E 00 00 01 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - ]; + lutkw = [ + 20 01 0E 00 00 01 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + ]; - lutkk = [ - 00 01 0E 00 00 01 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - 00 00 00 00 00 00 - ]; + lutwk = [ + 10 01 0E 00 00 01 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + ]; + + lutkk = [ + 00 01 0E 00 00 01 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + 00 00 00 00 00 00 + ]; + }; }; }; }; diff --git a/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2.overlay b/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2.overlay index 0b8f994c97b..035110ea5dc 100644 --- a/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2.overlay +++ b/boards/shields/waveshare_epaper/waveshare_epaper_gdew042t2.overlay @@ -9,25 +9,31 @@ chosen { zephyr,display = &uc8176_waveshare_epaper_gdew042t2; }; -}; -&arduino_spi { - uc8176_waveshare_epaper_gdew042t2: uc8176@0 { - compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176"; - spi-max-frequency = <4000000>; - reg = <0>; - width = <400>; - height = <300>; - dc-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ + mipi_dbi_waveshare_epaper_gdew042t2 { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&arduino_spi>; + dc-gpios = <&arduino_header 15 GPIO_ACTIVE_HIGH>; /* D9 */ reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ - busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ + write-only; + #address-cells = <1>; + #size-cells = <0>; - softstart = [17 17 17]; + uc8176_waveshare_epaper_gdew042t2: uc8176@0 { + compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176"; + mipi-max-frequency = <4000000>; + reg = <0>; + width = <400>; + height = <300>; + busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ - full { - pwr = [03 00 26 26 09]; - cdi = <0xd7>; - tcon = <0x22>; + softstart = [17 17 17]; + + full { + pwr = [03 00 26 26 09]; + cdi = <0xd7>; + tcon = <0x22>; + }; }; }; }; diff --git a/boards/shields/waveshare_epaper/waveshare_epaper_gdew075t7.overlay b/boards/shields/waveshare_epaper/waveshare_epaper_gdew075t7.overlay index cccee41faaa..8c8cbd9d636 100644 --- a/boards/shields/waveshare_epaper/waveshare_epaper_gdew075t7.overlay +++ b/boards/shields/waveshare_epaper/waveshare_epaper_gdew075t7.overlay @@ -10,25 +10,31 @@ chosen { zephyr,display = &uc8179_waveshare_epaper_gdew075t7; }; -}; -&arduino_spi { - uc8179_waveshare_epaper_gdew075t7: uc8179@0 { - compatible = "gooddisplay,gdew075t7", "ultrachip,uc8179"; - spi-max-frequency = <4000000>; - reg = <0>; - width = <800>; - height = <480>; - dc-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ + mipi_dbi_waveshare_epaper_gdew075t7 { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&arduino_spi>; + dc-gpios = <&arduino_header 15 GPIO_ACTIVE_HIGH>; /* D9 */ reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ - busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ + write-only; + #address-cells = <1>; + #size-cells = <0>; - softstart = [17 17 17 17]; + uc8179_waveshare_epaper_gdew075t7: uc8179@0 { + compatible = "gooddisplay,gdew075t7", "ultrachip,uc8179"; + mipi-max-frequency = <4000000>; + reg = <0>; + width = <800>; + height = <480>; + busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ - full { - pwr = [07 07 3f 3f]; - cdi = <07>; - tcon = <0x22>; + softstart = [17 17 17 17]; + + full { + pwr = [07 07 3f 3f]; + cdi = <07>; + tcon = <0x22>; + }; }; }; }; diff --git a/drivers/display/Kconfig.uc81xx b/drivers/display/Kconfig.uc81xx index 75678d2f663..123b5b3ed6f 100644 --- a/drivers/display/Kconfig.uc81xx +++ b/drivers/display/Kconfig.uc81xx @@ -7,6 +7,6 @@ config UC81XX bool "UltraChip UC81xx compatible display controller driver" default y depends on DT_HAS_ULTRACHIP_UC8175_ENABLED || DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED - select SPI + select MIPI_DBI help Enable driver for UC81xx compatible controller. diff --git a/drivers/display/uc81xx.c b/drivers/display/uc81xx.c index ae0a3bf667c..cac7d1d20c6 100644 --- a/drivers/display/uc81xx.c +++ b/drivers/display/uc81xx.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2022 Andreas Sandberg * Copyright (c) 2020 PHYTEC Messtechnik GmbH + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,7 +11,7 @@ #include #include #include -#include +#include #include #include "uc81xx_regs.h" @@ -75,10 +76,9 @@ struct uc81xx_quirks { struct uc81xx_config { const struct uc81xx_quirks *quirks; - struct spi_dt_spec bus; - struct gpio_dt_spec dc_gpio; + const struct device *mipi_dev; + const struct mipi_dbi_config dbi_config; struct gpio_dt_spec busy_gpio; - struct gpio_dt_spec reset_gpio; uint16_t height; uint16_t width; @@ -110,39 +110,13 @@ static inline int uc81xx_write_cmd(const struct device *dev, uint8_t cmd, const uint8_t *data, size_t len) { const struct uc81xx_config *config = dev->config; - struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)}; - struct spi_buf_set buf_set = {.buffers = &buf, .count = 1}; int err; uc81xx_busy_wait(dev); - err = gpio_pin_set_dt(&config->dc_gpio, 1); - if (err < 0) { - return err; - } - - err = spi_write_dt(&config->bus, &buf_set); - if (err < 0) { - goto spi_out; - } - - if (data != NULL) { - buf.buf = (void *)data; - buf.len = len; - - err = gpio_pin_set_dt(&config->dc_gpio, 0); - if (err < 0) { - goto spi_out; - } - - err = spi_write_dt(&config->bus, &buf_set); - if (err < 0) { - goto spi_out; - } - } - -spi_out: - spi_release_dt(&config->bus); + err = mipi_dbi_command_write(config->mipi_dev, &config->dbi_config, + cmd, data, len); + mipi_dbi_release(config->mipi_dev, &config->dbi_config); return err; } @@ -151,43 +125,42 @@ static inline int uc81xx_write_cmd_pattern(const struct device *dev, uint8_t pattern, size_t len) { const struct uc81xx_config *config = dev->config; - struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)}; - struct spi_buf_set buf_set = {.buffers = &buf, .count = 1}; + struct display_buffer_descriptor mipi_desc; int err; uint8_t data[64]; uc81xx_busy_wait(dev); - err = gpio_pin_set_dt(&config->dc_gpio, 1); + err = mipi_dbi_command_write(config->mipi_dev, &config->dbi_config, + cmd, NULL, 0); if (err < 0) { return err; } - err = spi_write_dt(&config->bus, &buf_set); - if (err < 0) { - goto spi_out; - } - - err = gpio_pin_set_dt(&config->dc_gpio, 0); - if (err < 0) { - goto spi_out; - } + /* + * MIPI display write API requires a display buffer descriptor. + * Create one that describes the buffer we are writing + */ + mipi_desc.height = 1; memset(data, pattern, sizeof(data)); while (len) { - buf.buf = data; - buf.len = MIN(len, sizeof(data)); + mipi_desc.buf_size = mipi_desc.width = mipi_desc.pitch = + MIN(len, sizeof(data)); - err = spi_write_dt(&config->bus, &buf_set); + err = mipi_dbi_write_display(config->mipi_dev, + &config->dbi_config, + data, &mipi_desc, + PIXEL_FORMAT_MONO10); if (err < 0) { - goto spi_out; + goto out; } - len -= buf.len; + len -= mipi_desc.buf_size; } -spi_out: - spi_release_dt(&config->bus); +out: + mipi_dbi_release(config->mipi_dev, &config->dbi_config); return err; } @@ -544,9 +517,7 @@ static int uc81xx_controller_init(const struct device *dev) const struct uc81xx_config *config = dev->config; struct uc81xx_data *data = dev->data; - gpio_pin_set_dt(&config->reset_gpio, 1); - k_sleep(K_MSEC(UC81XX_RESET_DELAY)); - gpio_pin_set_dt(&config->reset_gpio, 0); + mipi_dbi_reset(config->mipi_dev, UC81XX_RESET_DELAY); k_sleep(K_MSEC(UC81XX_RESET_DELAY)); uc81xx_busy_wait(dev); @@ -570,26 +541,11 @@ static int uc81xx_init(const struct device *dev) LOG_DBG(""); - if (!spi_is_ready_dt(&config->bus)) { - LOG_ERR("SPI bus %s not ready", config->bus.bus->name); + if (!device_is_ready(config->mipi_dev)) { + LOG_ERR("MIPI device not ready"); return -ENODEV; } - if (!gpio_is_ready_dt(&config->reset_gpio)) { - LOG_ERR("Reset GPIO device not ready"); - return -ENODEV; - } - - gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); - - if (!gpio_is_ready_dt(&config->dc_gpio)) { - LOG_ERR("DC GPIO device not ready"); - return -ENODEV; - } - - gpio_pin_configure_dt(&config->dc_gpio, GPIO_OUTPUT_INACTIVE); - - if (!gpio_is_ready_dt(&config->busy_gpio)) { LOG_ERR("Busy GPIO device not ready"); return -ENODEV; @@ -816,12 +772,14 @@ static const struct display_driver_api uc81xx_driver_api = { \ static const struct uc81xx_config uc81xx_cfg_ ## n = { \ .quirks = quirks_ptr, \ - .bus = SPI_DT_SPEC_GET(n, \ - SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \ - SPI_LOCK_ON, \ - 0), \ - .reset_gpio = GPIO_DT_SPEC_GET(n, reset_gpios), \ - .dc_gpio = GPIO_DT_SPEC_GET(n, dc_gpios), \ + .mipi_dev = DEVICE_DT_GET(DT_PARENT(n)), \ + .dbi_config = { \ + .mode = MIPI_DBI_MODE_SPI_4WIRE, \ + .config = MIPI_DBI_SPI_CONFIG_DT(n, \ + SPI_OP_MODE_MASTER | \ + SPI_LOCK_ON | SPI_WORD_SET(8), \ + 0), \ + }, \ .busy_gpio = GPIO_DT_SPEC_GET(n, busy_gpios), \ \ .height = DT_PROP(n, height), \ diff --git a/dts/bindings/display/ultrachip,uc81xx-common.yaml b/dts/bindings/display/ultrachip,uc81xx-common.yaml index b2c8a4de35c..20819d8c9fb 100644 --- a/dts/bindings/display/ultrachip,uc81xx-common.yaml +++ b/dts/bindings/display/ultrachip,uc81xx-common.yaml @@ -1,30 +1,13 @@ # Copyright (c) 2022 Andreas Sandberg # Copyright (c) 2020, Phytec Messtechnik GmbH +# Copyright 2024 NXP # SPDX-License-Identifier: Apache-2.0 description: UltraChip UC81xx EPD display controller common properties -include: [spi-device.yaml, display-controller.yaml] +include: [mipi-dbi-spi-device.yaml, display-controller.yaml] properties: - reset-gpios: - type: phandle-array - required: true - description: RESET pin. - - The RESET pin of UC81xx is active low. - If connected directly the MCU pin should be configured - as active low. - - dc-gpios: - type: phandle-array - required: true - description: DC pin. - - The DC pin of UC81xx is active low (transmission command byte). - If connected directly the MCU pin should be configured - as active low. - busy-gpios: type: phandle-array required: true