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 <daniel.degrasse@nxp.com>
This commit is contained in:
Daniel DeGrasse 2024-06-05 11:52:28 -05:00 committed by Alberto Escolar
parent 25cdda10e1
commit 9fdaf43e79
6 changed files with 157 additions and 198 deletions

View file

@ -8,23 +8,28 @@
/ { / {
chosen { chosen {
zephyr,display = &uc8176_waveshare_epaper_gdew042t2-p; zephyr,display = &uc8176_waveshare_epaper_gdew042t2_p;
}; };
};
&arduino_spi { 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 */
write-only;
#address-cells = <1>;
#size-cells = <0>;
/* /*
* GoodDisplay GDEW042T2 with fast partial refresh. Based on * GoodDisplay GDEW042T2 with fast partial refresh. Based on
* configuration from GoodDisplay's Arduino example. * configuration from GoodDisplay's Arduino example.
*/ */
uc8176_waveshare_epaper_gdew042t2-p: uc8176@0 { uc8176_waveshare_epaper_gdew042t2_p: uc8176@0 {
compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176"; compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176";
spi-max-frequency = <4000000>; mipi-max-frequency = <4000000>;
reg = <0>; reg = <0>;
width = <400>; width = <400>;
height = <300>; height = <300>;
dc-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */
reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */
busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */
softstart = [ 17 17 17 ]; softstart = [ 17 17 17 ];
@ -91,4 +96,5 @@
]; ];
}; };
}; };
};
}; };

View file

@ -9,17 +9,22 @@
chosen { chosen {
zephyr,display = &uc8176_waveshare_epaper_gdew042t2; zephyr,display = &uc8176_waveshare_epaper_gdew042t2;
}; };
};
&arduino_spi { 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 */
write-only;
#address-cells = <1>;
#size-cells = <0>;
uc8176_waveshare_epaper_gdew042t2: uc8176@0 { uc8176_waveshare_epaper_gdew042t2: uc8176@0 {
compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176"; compatible = "gooddisplay,gdew042t2", "ultrachip,uc8176";
spi-max-frequency = <4000000>; mipi-max-frequency = <4000000>;
reg = <0>; reg = <0>;
width = <400>; width = <400>;
height = <300>; height = <300>;
dc-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */
reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */
busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */
softstart = [17 17 17]; softstart = [17 17 17];
@ -30,4 +35,5 @@
tcon = <0x22>; tcon = <0x22>;
}; };
}; };
};
}; };

View file

@ -10,17 +10,22 @@
chosen { chosen {
zephyr,display = &uc8179_waveshare_epaper_gdew075t7; zephyr,display = &uc8179_waveshare_epaper_gdew075t7;
}; };
};
&arduino_spi { 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 */
write-only;
#address-cells = <1>;
#size-cells = <0>;
uc8179_waveshare_epaper_gdew075t7: uc8179@0 { uc8179_waveshare_epaper_gdew075t7: uc8179@0 {
compatible = "gooddisplay,gdew075t7", "ultrachip,uc8179"; compatible = "gooddisplay,gdew075t7", "ultrachip,uc8179";
spi-max-frequency = <4000000>; mipi-max-frequency = <4000000>;
reg = <0>; reg = <0>;
width = <800>; width = <800>;
height = <480>; height = <480>;
dc-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */
reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */
busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ busy-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */
softstart = [17 17 17 17]; softstart = [17 17 17 17];
@ -31,4 +36,5 @@
tcon = <0x22>; tcon = <0x22>;
}; };
}; };
};
}; };

View file

@ -7,6 +7,6 @@ config UC81XX
bool "UltraChip UC81xx compatible display controller driver" bool "UltraChip UC81xx compatible display controller driver"
default y default y
depends on DT_HAS_ULTRACHIP_UC8175_ENABLED || DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED depends on DT_HAS_ULTRACHIP_UC8175_ENABLED || DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED
select SPI select MIPI_DBI
help help
Enable driver for UC81xx compatible controller. Enable driver for UC81xx compatible controller.

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2022 Andreas Sandberg * Copyright (c) 2022 Andreas Sandberg
* Copyright (c) 2020 PHYTEC Messtechnik GmbH * Copyright (c) 2020 PHYTEC Messtechnik GmbH
* Copyright 2024 NXP
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -10,7 +11,7 @@
#include <zephyr/init.h> #include <zephyr/init.h>
#include <zephyr/drivers/display.h> #include <zephyr/drivers/display.h>
#include <zephyr/drivers/gpio.h> #include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h> #include <zephyr/drivers/mipi_dbi.h>
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include "uc81xx_regs.h" #include "uc81xx_regs.h"
@ -75,10 +76,9 @@ struct uc81xx_quirks {
struct uc81xx_config { struct uc81xx_config {
const struct uc81xx_quirks *quirks; const struct uc81xx_quirks *quirks;
struct spi_dt_spec bus; const struct device *mipi_dev;
struct gpio_dt_spec dc_gpio; const struct mipi_dbi_config dbi_config;
struct gpio_dt_spec busy_gpio; struct gpio_dt_spec busy_gpio;
struct gpio_dt_spec reset_gpio;
uint16_t height; uint16_t height;
uint16_t width; 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 uint8_t *data, size_t len)
{ {
const struct uc81xx_config *config = dev->config; 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; int err;
uc81xx_busy_wait(dev); uc81xx_busy_wait(dev);
err = gpio_pin_set_dt(&config->dc_gpio, 1); err = mipi_dbi_command_write(config->mipi_dev, &config->dbi_config,
if (err < 0) { cmd, data, len);
return err; mipi_dbi_release(config->mipi_dev, &config->dbi_config);
}
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);
return err; return err;
} }
@ -151,43 +125,42 @@ static inline int uc81xx_write_cmd_pattern(const struct device *dev,
uint8_t pattern, size_t len) uint8_t pattern, size_t len)
{ {
const struct uc81xx_config *config = dev->config; const struct uc81xx_config *config = dev->config;
struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)}; struct display_buffer_descriptor mipi_desc;
struct spi_buf_set buf_set = {.buffers = &buf, .count = 1};
int err; int err;
uint8_t data[64]; uint8_t data[64];
uc81xx_busy_wait(dev); 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) { if (err < 0) {
return err; return err;
} }
err = spi_write_dt(&config->bus, &buf_set); /*
if (err < 0) { * MIPI display write API requires a display buffer descriptor.
goto spi_out; * Create one that describes the buffer we are writing
} */
mipi_desc.height = 1;
err = gpio_pin_set_dt(&config->dc_gpio, 0);
if (err < 0) {
goto spi_out;
}
memset(data, pattern, sizeof(data)); memset(data, pattern, sizeof(data));
while (len) { while (len) {
buf.buf = data; mipi_desc.buf_size = mipi_desc.width = mipi_desc.pitch =
buf.len = MIN(len, sizeof(data)); 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) { if (err < 0) {
goto spi_out; goto out;
} }
len -= buf.len; len -= mipi_desc.buf_size;
} }
spi_out: out:
spi_release_dt(&config->bus); mipi_dbi_release(config->mipi_dev, &config->dbi_config);
return err; return err;
} }
@ -544,9 +517,7 @@ static int uc81xx_controller_init(const struct device *dev)
const struct uc81xx_config *config = dev->config; const struct uc81xx_config *config = dev->config;
struct uc81xx_data *data = dev->data; struct uc81xx_data *data = dev->data;
gpio_pin_set_dt(&config->reset_gpio, 1); mipi_dbi_reset(config->mipi_dev, UC81XX_RESET_DELAY);
k_sleep(K_MSEC(UC81XX_RESET_DELAY));
gpio_pin_set_dt(&config->reset_gpio, 0);
k_sleep(K_MSEC(UC81XX_RESET_DELAY)); k_sleep(K_MSEC(UC81XX_RESET_DELAY));
uc81xx_busy_wait(dev); uc81xx_busy_wait(dev);
@ -570,26 +541,11 @@ static int uc81xx_init(const struct device *dev)
LOG_DBG(""); LOG_DBG("");
if (!spi_is_ready_dt(&config->bus)) { if (!device_is_ready(config->mipi_dev)) {
LOG_ERR("SPI bus %s not ready", config->bus.bus->name); LOG_ERR("MIPI device not ready");
return -ENODEV; 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)) { if (!gpio_is_ready_dt(&config->busy_gpio)) {
LOG_ERR("Busy GPIO device not ready"); LOG_ERR("Busy GPIO device not ready");
return -ENODEV; return -ENODEV;
@ -816,12 +772,14 @@ static const struct display_driver_api uc81xx_driver_api = {
\ \
static const struct uc81xx_config uc81xx_cfg_ ## n = { \ static const struct uc81xx_config uc81xx_cfg_ ## n = { \
.quirks = quirks_ptr, \ .quirks = quirks_ptr, \
.bus = SPI_DT_SPEC_GET(n, \ .mipi_dev = DEVICE_DT_GET(DT_PARENT(n)), \
SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \ .dbi_config = { \
SPI_LOCK_ON, \ .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), \ 0), \
.reset_gpio = GPIO_DT_SPEC_GET(n, reset_gpios), \ }, \
.dc_gpio = GPIO_DT_SPEC_GET(n, dc_gpios), \
.busy_gpio = GPIO_DT_SPEC_GET(n, busy_gpios), \ .busy_gpio = GPIO_DT_SPEC_GET(n, busy_gpios), \
\ \
.height = DT_PROP(n, height), \ .height = DT_PROP(n, height), \

View file

@ -1,30 +1,13 @@
# Copyright (c) 2022 Andreas Sandberg # Copyright (c) 2022 Andreas Sandberg
# Copyright (c) 2020, Phytec Messtechnik GmbH # Copyright (c) 2020, Phytec Messtechnik GmbH
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
description: UltraChip UC81xx EPD display controller common properties 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: 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: busy-gpios:
type: phandle-array type: phandle-array
required: true required: true