drivers: display: ssd16xx: convert to MIPI DBI API

Convert SSD16XX display driver to use MIPI DBI API. This commit also
updates in tree board devicetrees to include the emulated MIPI DBI SPI
driver.

Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
This commit is contained in:
Daniel DeGrasse 2024-06-07 14:48:50 -05:00 committed by Anas Nashif
parent 2690cacf65
commit 8d2dc2f9ef
10 changed files with 337 additions and 396 deletions

View file

@ -46,24 +46,21 @@
pwm-led3 = &back_pwm_led;
watchdog0 = &wdt0;
};
};
&spi1 {
compatible = "nordic,nrf-spi";
status = "okay";
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&spi1>;
reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
dc-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
ssd16xx: ssd16xxfb@0 {
compatible = "gooddisplay,gdeh0213b1", "solomon,ssd1673";
spi-max-frequency = <4000000>;
mipi-max-frequency = <4000000>;
reg = <0>;
width = <250>;
height = <122>;
reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
dc-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
busy-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
full {
@ -96,4 +93,15 @@
];
};
};
};
};
&spi1 {
compatible = "nordic,nrf-spi";
status = "okay";
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
};

View file

@ -27,24 +27,21 @@
aliases {
watchdog0 = &wdt0;
};
};
&spi1 {
compatible = "nordic,nrf-spi";
status = "okay";
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&spi1>;
reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
dc-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
ssd16xx: ssd16xxfb@0 {
compatible = "gooddisplay,gdeh0213b72", "solomon,ssd1675a";
spi-max-frequency = <4000000>;
mipi-max-frequency = <4000000>;
reg = <0>;
width = <250>;
height = <122>;
reset-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
dc-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
busy-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
full {
@ -114,4 +111,15 @@
];
};
};
};
};
&spi1 {
compatible = "nordic,nrf-spi";
status = "okay";
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
};

View file

@ -10,17 +10,21 @@
chosen {
zephyr,display = &ssd16xx_waveshare_epaper_gdeh0154a07;
};
};
&arduino_spi {
mipi_dbi_waveshare_epaper_gdeh0154a07 {
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 */
#address-cells = <1>;
#size-cells = <0>;
ssd16xx_waveshare_epaper_gdeh0154a07: ssd16xxfb@0 {
compatible = "gooddisplay,gdeh0154a07", "solomon,ssd1681";
spi-max-frequency = <4000000>;
mipi-max-frequency = <4000000>;
reg = <0>;
width = <200>;
height = <200>;
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_HIGH>; /* D7 */
tssv = <0x80>;
@ -33,4 +37,5 @@
border-waveform = <0x3c>;
};
};
};
};

View file

@ -10,17 +10,21 @@
chosen {
zephyr,display = &ssd16xx_waveshare_epaper_gdeh0213b1;
};
};
&arduino_spi {
mipi_dbi_waveshare_epaper_gdeh0213b1 {
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 */
#address-cells = <1>;
#size-cells = <0>;
ssd16xx_waveshare_epaper_gdeh0213b1: ssd16xxfb@0 {
compatible = "gooddisplay,gdeh0213b1", "solomon,ssd1673";
spi-max-frequency = <4000000>;
mipi-max-frequency = <4000000>;
reg = <0>;
width = <250>;
height = <120>;
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_HIGH>; /* D7 */
full {
@ -53,4 +57,5 @@
];
};
};
};
};

View file

@ -10,17 +10,21 @@
chosen {
zephyr,display = &ssd16xx_waveshare_epaper_gdeh0213b72;
};
};
&arduino_spi {
mipi_dbi_waveshare_epaper_gdeh0213b72 {
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 */
#address-cells = <1>;
#size-cells = <0>;
ssd16xx_waveshare_epaper_gdeh0213b72: ssd16xxfb@0 {
compatible = "gooddisplay,gdeh0213b72", "solomon,ssd1675a";
spi-max-frequency = <4000000>;
mipi-max-frequency = <4000000>;
reg = <0>;
width = <250>;
height = <120>;
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_HIGH>; /* D7 */
full {
@ -69,4 +73,5 @@
];
};
};
};
};

View file

@ -10,17 +10,21 @@
chosen {
zephyr,display = &ssd16xx_waveshare_epaper_gdeh029a1;
};
};
&arduino_spi {
mipi_dbi_waveshare_epaper_gdeh029a1 {
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 */
#address-cells = <1>;
#size-cells = <0>;
ssd16xx_waveshare_epaper_gdeh029a1: ssd16xxfb@0 {
compatible = "gooddisplay,gdeh029a1", "solomon,ssd1608";
spi-max-frequency = <4000000>;
mipi-max-frequency = <4000000>;
reg = <0>;
width = <296>;
height = <128>;
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_HIGH>; /* D7 */
softstart = [d7 d6 9d];
@ -51,4 +55,5 @@
];
};
};
};
};

View file

@ -10,17 +10,21 @@
chosen {
zephyr,display = &ssd16xx_waveshare_epaper_gdey0213b74;
};
};
&arduino_spi {
mipi_dbi_waveshare_epaper_gdey0213b74 {
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 */
#address-cells = <1>;
#size-cells = <0>;
ssd16xx_waveshare_epaper_gdey0213b74: ssd16xxfb@0 {
compatible = "gooddisplay,gdey0213b74", "solomon,ssd1680";
spi-max-frequency = <4000000>;
mipi-max-frequency = <4000000>;
reg = <0>;
width = <250>;
height = <122>;
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_HIGH>; /* D7 */
tssv = <0x80>;
@ -33,4 +37,5 @@
border-waveform = <0x3c>;
};
};
};
};

View file

@ -12,6 +12,6 @@ config SSD16XX
DT_HAS_SOLOMON_SSD1675A_ENABLED || \
DT_HAS_SOLOMON_SSD1680_ENABLED || \
DT_HAS_SOLOMON_SSD1681_ENABLED
select SPI
select MIPI_DBI
help
Enable driver for SSD16XX compatible controller.

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2022 Andreas Sandberg
* Copyright (c) 2018-2020 PHYTEC Messtechnik GmbH
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -14,7 +15,7 @@ LOG_MODULE_REGISTER(ssd16xx);
#include <zephyr/drivers/display.h>
#include <zephyr/init.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/mipi_dbi.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/display/ssd16xx.h>
@ -90,10 +91,9 @@ struct ssd16xx_profile {
};
struct ssd16xx_config {
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;
const struct ssd16xx_quirks *quirks;
@ -126,39 +126,13 @@ static inline int ssd16xx_write_cmd(const struct device *dev, uint8_t cmd,
const uint8_t *data, size_t len)
{
const struct ssd16xx_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 = 0;
int err;
ssd16xx_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;
}
@ -173,9 +147,6 @@ static inline int ssd16xx_read_cmd(const struct device *dev, uint8_t cmd,
{
const struct ssd16xx_config *config = dev->config;
const struct ssd16xx_data *dev_data = dev->data;
struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)};
struct spi_buf_set buf_set = {.buffers = &buf, .count = 1};
int err = 0;
if (!dev_data->read_supported) {
return -ENOTSUP;
@ -183,34 +154,8 @@ static inline int ssd16xx_read_cmd(const struct device *dev, uint8_t cmd,
ssd16xx_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 = data;
buf.len = len;
err = gpio_pin_set_dt(&config->dc_gpio, 0);
if (err < 0) {
goto spi_out;
}
err = spi_read_dt(&config->bus, &buf_set);
if (err < 0) {
goto spi_out;
}
}
spi_out:
spi_release_dt(&config->bus);
return err;
return mipi_dbi_command_read(config->mipi_dev, &config->dbi_config,
&cmd, 1, data, len);
}
static inline size_t push_x_param(const struct device *dev,
@ -911,13 +856,7 @@ static int ssd16xx_controller_init(const struct device *dev)
data->blanking_on = false;
data->profile = SSD16XX_PROFILE_INVALID;
err = gpio_pin_set_dt(&config->reset_gpio, 1);
if (err < 0) {
return err;
}
k_msleep(SSD16XX_RESET_DELAY);
err = gpio_pin_set_dt(&config->reset_gpio, 0);
err = mipi_dbi_reset(config->mipi_dev, SSD16XX_RESET_DELAY);
if (err < 0) {
return err;
}
@ -970,35 +909,13 @@ static int ssd16xx_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;
}
data->read_supported =
(config->bus.config.operation & SPI_HALF_DUPLEX) != 0;
if (!gpio_is_ready_dt(&config->reset_gpio)) {
LOG_ERR("Reset GPIO device not ready");
return -ENODEV;
}
err = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE);
if (err < 0) {
LOG_ERR("Failed to configure reset GPIO");
return err;
}
if (!gpio_is_ready_dt(&config->dc_gpio)) {
LOG_ERR("DC GPIO device not ready");
return -ENODEV;
}
err = gpio_pin_configure_dt(&config->dc_gpio, GPIO_OUTPUT_INACTIVE);
if (err < 0) {
LOG_ERR("Failed to configure DC GPIO");
return err;
}
(config->dbi_config.config.operation & SPI_HALF_DUPLEX) != 0;
if (!gpio_is_ready_dt(&config->busy_gpio)) {
LOG_ERR("Busy GPIO device not ready");
@ -1134,12 +1051,13 @@ static struct ssd16xx_quirks quirks_solomon_ssd1681 = {
DT_FOREACH_CHILD(n, SSD16XX_PROFILE); \
\
static const struct ssd16xx_config ssd16xx_cfg_ ## n = { \
.bus = SPI_DT_SPEC_GET(n, \
.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_WORD_SET(8) | \
SPI_HOLD_ON_CS | SPI_LOCK_ON, \
0), \
.reset_gpio = GPIO_DT_SPEC_GET(n, reset_gpios), \
.dc_gpio = GPIO_DT_SPEC_GET(n, dc_gpios), \
SPI_HOLD_ON_CS | SPI_LOCK_ON, 0), \
}, \
.busy_gpio = GPIO_DT_SPEC_GET(n, busy_gpios), \
.quirks = quirks_ptr, \
.height = DT_PROP(n, height), \

View file

@ -3,31 +3,13 @@
description: SSD16XX EPD display controller
include: [spi-device.yaml, display-controller.yaml]
include: [mipi-dbi-spi-device.yaml, display-controller.yaml]
properties:
softstart:
type: uint8-array
description: Booster soft start values
reset-gpios:
type: phandle-array
required: true
description: RESET pin.
The RESET pin of SSD16XX 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 SSD16XX 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