From be23e70fffac332df2ad8bd9e458701ef86cf3f8 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 5 Jun 2024 10:34:30 -0500 Subject: [PATCH] drivers: display: gc9x01: convert to MIPI DBI API Convert galaxycore GC9X01 to MIPI DBI API. In tree boards and tests using this display have also had their devicetrees updated to use the new MIPI DBI SPI emulated device. Signed-off-by: Daniel DeGrasse --- .../seeed_xiao_round_display.overlay | 32 +++-- .../esp32s3_touch_lcd_1_28_esp32s3_procpu.dts | 35 +++-- drivers/display/Kconfig.gc9x01x | 2 +- drivers/display/display_gc9x01x.c | 129 +++++------------- dts/bindings/display/galaxycore,gc9x01x.yaml | 16 +-- tests/drivers/build_all/display/app.overlay | 29 ++-- 6 files changed, 96 insertions(+), 147 deletions(-) diff --git a/boards/shields/seeed_xiao_round_display/seeed_xiao_round_display.overlay b/boards/shields/seeed_xiao_round_display/seeed_xiao_round_display.overlay index dab060bb604..d4a3ad1329e 100644 --- a/boards/shields/seeed_xiao_round_display/seeed_xiao_round_display.overlay +++ b/boards/shields/seeed_xiao_round_display/seeed_xiao_round_display.overlay @@ -27,6 +27,26 @@ aliases { rtc = &pcf8563_xiao_round_display; }; + + xiao_round_display_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&xiao_spi>; + dc-gpios = <&xiao_d 3 GPIO_ACTIVE_HIGH>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + gc9a01_xiao_round_display: gc9a01@0 { + status = "okay"; + compatible = "galaxycore,gc9x01x"; + reg = <0>; + mipi-max-frequency = ; + pixel-format = ; + width = <240>; + height = <240>; + display-inversion; + }; + }; }; &xiao_adc { @@ -62,18 +82,6 @@ status = "okay"; cs-gpios = <&xiao_d 1 GPIO_ACTIVE_LOW>, <&xiao_d 2 GPIO_ACTIVE_LOW>; - gc9a01_xiao_round_display: gc9a01@0 { - status = "okay"; - compatible = "galaxycore,gc9x01x"; - reg = <0>; - spi-max-frequency = ; - cmd-data-gpios = <&xiao_d 3 GPIO_ACTIVE_HIGH>; - pixel-format = ; - width = <240>; - height = <240>; - display-inversion; - }; - sdhc_xiao_round_display: sdhc@1 { compatible = "zephyr,sdhc-spi-slot"; reg = <1>; diff --git a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.dts b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.dts index f6a62874fe5..cb4bd891f61 100644 --- a/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.dts +++ b/boards/waveshare/esp32s3_touch_lcd_1_28/esp32s3_touch_lcd_1_28_esp32s3_procpu.dts @@ -56,6 +56,28 @@ pwms = <&ledc0 0 PWM_HZ(250) PWM_POLARITY_NORMAL>; }; }; + + /* MIPI DBI */ + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&spi2>; + dc-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + gc9a01: gc9a01@0 { + status = "okay"; + compatible = "galaxycore,gc9x01x"; + reg = <0>; + mipi-max-frequency = <100000000>; + pixel-format = ; + display-inversion; + width = <240>; + height = <240>; + }; + }; }; &flash0 { @@ -146,19 +168,6 @@ pinctrl-0 = <&spim2_default>; pinctrl-names = "default"; cs-gpios = <&gpio0 9 GPIO_ACTIVE_LOW>; - - gc9a01: gc9a01@0 { - status = "okay"; - compatible = "galaxycore,gc9x01x"; - reg = <0>; - spi-max-frequency = <100000000>; - cmd-data-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; - pixel-format = ; - display-inversion; - width = <240>; - height = <240>; - }; }; &trng0 { diff --git a/drivers/display/Kconfig.gc9x01x b/drivers/display/Kconfig.gc9x01x index aba24c445f1..650b0de9191 100644 --- a/drivers/display/Kconfig.gc9x01x +++ b/drivers/display/Kconfig.gc9x01x @@ -5,6 +5,6 @@ config GC9X01X bool "GC9X01X display driver" default y depends on DT_HAS_GALAXYCORE_GC9X01X_ENABLED - select SPI + select MIPI_DBI help Enable driver for GC9X01X display driver. diff --git a/drivers/display/display_gc9x01x.c b/drivers/display/display_gc9x01x.c index 1d432d3f355..963e0dbe7a6 100644 --- a/drivers/display/display_gc9x01x.c +++ b/drivers/display/display_gc9x01x.c @@ -10,8 +10,7 @@ #include #include -#include -#include +#include #include #include #include @@ -19,12 +18,6 @@ #include LOG_MODULE_REGISTER(display_gc9x01x, CONFIG_DISPLAY_LOG_LEVEL); -/* Command/data GPIO level for commands. */ -#define GC9X01X_GPIO_LEVEL_CMD 0U - -/* Command/data GPIO level for data. */ -#define GC9X01X_GPIO_LEVEL_DATA 1U - /* Maximum number of default init registers */ #define GC9X01X_NUM_DEFAULT_INIT_REGS 12U @@ -37,9 +30,8 @@ struct gc9x01x_data { /* Configuration data struct.*/ struct gc9x01x_config { - struct spi_dt_spec spi; - struct gpio_dt_spec cmd_data; - struct gpio_dt_spec reset; + const struct device *mipi_dev; + struct mipi_dbi_config dbi_config; uint8_t pixel_format; uint16_t orientation; uint16_t x_resolution; @@ -229,35 +221,9 @@ static int gc9x01x_transmit(const struct device *dev, uint8_t cmd, const void *t size_t tx_len) { const struct gc9x01x_config *config = dev->config; - int ret; - struct spi_buf tx_buf = {.buf = &cmd, .len = 1U}; - struct spi_buf_set tx_bufs = {.buffers = &tx_buf, .count = 1U}; - - ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_CMD); - if (ret < 0) { - return ret; - } - ret = spi_write_dt(&config->spi, &tx_bufs); - if (ret < 0) { - return ret; - } - - /* send data (if any) */ - if (tx_data != NULL) { - tx_buf.buf = (void *)tx_data; - tx_buf.len = tx_len; - - ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_DATA); - if (ret < 0) { - return ret; - } - ret = spi_write_dt(&config->spi, &tx_bufs); - if (ret < 0) { - return ret; - } - } - return 0; + return mipi_dbi_command_write(config->mipi_dev, &config->dbi_config, + cmd, tx_data, tx_len); } static int gc9x01x_regs_init(const struct device *dev) @@ -266,6 +232,10 @@ static int gc9x01x_regs_init(const struct device *dev) const struct gc9x01x_regs *regs = config->regs; int ret; + if (!device_is_ready(config->mipi_dev)) { + return -ENODEV; + } + /* Enable inter-command mode */ ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN1, NULL, 0); if (ret < 0) { @@ -371,17 +341,15 @@ static int gc9x01x_enter_sleep(const struct device *dev) static int gc9x01x_hw_reset(const struct device *dev) { const struct gc9x01x_config *config = dev->config; + int ret; - if (config->reset.port == NULL) { - return -ENODEV; + ret = mipi_dbi_reset(config->mipi_dev, 100); + if (ret < 0) { + return ret; } - - gpio_pin_set_dt(&config->reset, 1U); - k_msleep(100); - gpio_pin_set_dt(&config->reset, 0U); k_msleep(10); - return 0; + return ret; } static int gc9x01x_display_blanking_off(const struct device *dev) @@ -492,38 +460,8 @@ static int gc9x01x_configure(const struct device *dev) static int gc9x01x_init(const struct device *dev) { - const struct gc9x01x_config *config = dev->config; int ret; - if (!spi_is_ready_dt(&config->spi)) { - LOG_ERR("SPI device is not ready"); - return -ENODEV; - } - - if (!gpio_is_ready_dt(&config->cmd_data)) { - LOG_ERR("Command/Data GPIO device not ready"); - return -ENODEV; - } - - ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); - if (ret < 0) { - LOG_ERR("Could not configure command/data GPIO (%d)", ret); - return ret; - } - - if (config->reset.port != NULL) { - if (!device_is_ready(config->reset.port)) { - LOG_ERR("Reset GPIO device not ready"); - return -ENODEV; - } - - ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); - if (ret < 0) { - LOG_ERR("Could not configure reset GPIO (%d)", ret); - return ret; - } - } - gc9x01x_hw_reset(dev); gc9x01x_display_blanking_on(dev); @@ -573,8 +511,7 @@ static int gc9x01x_write(const struct device *dev, const uint16_t x, const uint1 struct gc9x01x_data *data = dev->data; int ret; const uint8_t *write_data_start = (const uint8_t *)buf; - struct spi_buf tx_buf; - struct spi_buf_set tx_bufs; + struct display_buffer_descriptor mipi_desc; uint16_t write_cnt; uint16_t nbr_of_writes; uint16_t write_h; @@ -592,26 +529,30 @@ static int gc9x01x_write(const struct device *dev, const uint16_t x, const uint1 if (desc->pitch > desc->width) { write_h = 1U; nbr_of_writes = desc->height; + mipi_desc.height = 1; + mipi_desc.buf_size = desc->pitch * data->bytes_per_pixel; } else { write_h = desc->height; + mipi_desc.height = desc->height; + mipi_desc.buf_size = desc->width * data->bytes_per_pixel * write_h; nbr_of_writes = 1U; } - ret = gc9x01x_transmit(dev, GC9X01X_CMD_MEMWR, write_data_start, - desc->width * data->bytes_per_pixel * write_h); + mipi_desc.width = desc->width; + /* Per MIPI API, pitch must always match width */ + mipi_desc.pitch = desc->width; + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_MEMWR, NULL, 0); if (ret < 0) { return ret; } - tx_bufs.buffers = &tx_buf; - tx_bufs.count = 1U; - - write_data_start += desc->pitch * data->bytes_per_pixel; - for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) { - tx_buf.buf = (void *)write_data_start; - tx_buf.len = desc->width * data->bytes_per_pixel * write_h; - - ret = spi_write_dt(&config->spi, &tx_bufs); + for (write_cnt = 0U; write_cnt < nbr_of_writes; ++write_cnt) { + ret = mipi_dbi_write_display(config->mipi_dev, + &config->dbi_config, + write_data_start, + &mipi_desc, + data->pixel_format); if (ret < 0) { return ret; } @@ -679,9 +620,13 @@ static const struct display_driver_api gc9x01x_api = { #define GC9X01X_INIT(inst) \ GC9X01X_REGS_INIT(inst); \ static const struct gc9x01x_config gc9x01x_config_##inst = { \ - .spi = SPI_DT_SPEC_INST_GET(inst, SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0), \ - .cmd_data = GPIO_DT_SPEC_INST_GET(inst, cmd_data_gpios), \ - .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \ + .mipi_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .dbi_config = { \ + .mode = MIPI_DBI_MODE_SPI_4WIRE, \ + .config = MIPI_DBI_SPI_CONFIG_DT_INST(inst, \ + SPI_OP_MODE_MASTER | \ + SPI_WORD_SET(8), 0), \ + }, \ .pixel_format = DT_INST_PROP(inst, pixel_format), \ .orientation = DT_INST_ENUM_IDX(inst, orientation), \ .x_resolution = DT_INST_PROP(inst, width), \ diff --git a/dts/bindings/display/galaxycore,gc9x01x.yaml b/dts/bindings/display/galaxycore,gc9x01x.yaml index bc85c652b06..7867de55a0d 100644 --- a/dts/bindings/display/galaxycore,gc9x01x.yaml +++ b/dts/bindings/display/galaxycore,gc9x01x.yaml @@ -29,23 +29,9 @@ description: | compatible: "galaxycore,gc9x01x" -include: [spi-device.yaml, display-controller.yaml, lcd-controller.yaml] +include: [mipi-dbi-spi-device.yaml, display-controller.yaml, lcd-controller.yaml] properties: - reset-gpios: - type: phandle-array - description: | - RESET pin of the GC9X01X. - If connected directly the MCU pin should be configured - as active low. - - cmd-data-gpios: - type: phandle-array - required: true - description: | - Data/Command pin of the GC9X01X is to be configured - high(1) for data, low(0) for command. - orientation: type: string default: "normal" diff --git a/tests/drivers/build_all/display/app.overlay b/tests/drivers/build_all/display/app.overlay index a30348fcf0d..b17b02e8d7b 100644 --- a/tests/drivers/build_all/display/app.overlay +++ b/tests/drivers/build_all/display/app.overlay @@ -125,6 +125,16 @@ tcon = <0x22>; }; }; + + test_spi_gc9x01x: gc9x01x@6 { + compatible = "galaxycore,gc9x01x"; + reg = <6>; + mipi-max-frequency = <100000000>; + pixel-format = <16>; + + width = <240>; + height = <240>; + }; }; @@ -136,21 +146,12 @@ status = "okay"; clock-frequency = <2000000>; - /* one entry for every devices at spi.dtsi */ + /* one entry for every device. Note that this must + * include MIPI DBI devices as well. + */ cs-gpios = <&test_gpio 0 0 &test_gpio 0 1 &test_gpio 0 2 - &test_gpio 0 3 &test_gpio 0 4 &test_gpio 0 5>; - - test_spi_gc9x01x: gc9x01x@1 { - compatible = "galaxycore,gc9x01x"; - reg = <1>; - spi-max-frequency = <100000000>; - cmd-data-gpios = <&test_gpio 1 0>; - reset-gpios = <&test_gpio 2 0>; - pixel-format = <16>; - - width = <240>; - height = <240>; - }; + &test_gpio 0 3 &test_gpio 0 4 &test_gpio 0 5 + &test_gpio 0 6>; test_led_strip_0: lpd8806@2 { compatible = "greeled,lpd8806";