From 7c46b0b8984e1d3dacace7f10acb2c9ac3b29382 Mon Sep 17 00:00:00 2001 From: Xiao Qin Date: Thu, 14 Sep 2023 14:32:17 -0700 Subject: [PATCH] drivers: display: uc81xx: add support for uc8175 Add support for uc8175 display driver. uc8175 has a slightly different command/data length requirements for certain registers, namely TRES and PTL, compared to uc8176/uc8179 This commit refactors the driver code and such that setting TRES and PTL registers are now done by function pointers provided by config->quirks, by the same token as how it is done for setting CDI register Signed-off-by: Xiao Qin --- drivers/display/Kconfig.uc81xx | 2 +- drivers/display/uc81xx.c | 118 +++++++++++++++++---- drivers/display/uc81xx_regs.h | 26 ++++- dts/bindings/display/ultrachip,uc8175.yaml | 8 ++ 4 files changed, 126 insertions(+), 28 deletions(-) create mode 100644 dts/bindings/display/ultrachip,uc8175.yaml diff --git a/drivers/display/Kconfig.uc81xx b/drivers/display/Kconfig.uc81xx index 31951bd8180..75678d2f663 100644 --- a/drivers/display/Kconfig.uc81xx +++ b/drivers/display/Kconfig.uc81xx @@ -6,7 +6,7 @@ config UC81XX bool "UltraChip UC81xx compatible display controller driver" default y - depends on 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 help Enable driver for UC81xx compatible controller. diff --git a/drivers/display/uc81xx.c b/drivers/display/uc81xx.c index 88df6be0289..38a68cdfaf0 100644 --- a/drivers/display/uc81xx.c +++ b/drivers/display/uc81xx.c @@ -66,6 +66,10 @@ struct uc81xx_quirks { bool auto_copy; int (*set_cdi)(const struct device *dev, bool border); + int (*set_tres)(const struct device *dev); + int (*set_ptl)(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc); }; struct uc81xx_config { @@ -224,10 +228,6 @@ static int uc81xx_set_profile(const struct device *dev, UC81XX_PSR_SHL | UC81XX_PSR_SHD | UC81XX_PSR_RST; - const struct uc81xx_tres tres = { - .hres = sys_cpu_to_be16(config->width), - .vres = sys_cpu_to_be16(config->height), - }; if (type >= UC81XX_NUM_PROFILES) { return -EINVAL; @@ -272,9 +272,7 @@ static int uc81xx_set_profile(const struct device *dev, } /* Set panel resolution */ - LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); - if (uc81xx_write_cmd(dev, UC81XX_CMD_TRES, - (const void *)&tres, sizeof(tres))) { + if (config->quirks->set_tres(dev)) { return -EIO; } @@ -403,13 +401,6 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 uint16_t x_end_idx = x + desc->width - 1; uint16_t y_end_idx = y + desc->height - 1; - const struct uc81xx_ptl ptl = { - .hrst = sys_cpu_to_be16(x), - .hred = sys_cpu_to_be16(x_end_idx), - .vrst = sys_cpu_to_be16(y), - .vred = sys_cpu_to_be16(y_end_idx), - .flags = UC81XX_PTL_FLAG_PT_SCAN, - }; size_t buf_len; const uint8_t back_buffer = data->blanking_on ? UC81XX_CMD_DTM1 : UC81XX_CMD_DTM2; @@ -448,15 +439,11 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 } } - /* Setup Partial Window and enable Partial Mode */ - LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTIN, NULL, 0)) { return -EIO; } - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTL, - (const void *)&ptl, sizeof(ptl))) { + if (config->quirks->set_ptl(dev, x, y, x_end_idx, y_end_idx, desc)) { return -EIO; } @@ -487,8 +474,7 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 * needed. */ - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTL, - (const void *)&ptl, sizeof(ptl))) { + if (config->quirks->set_ptl(dev, x, y, x_end_idx, y_end_idx, desc)) { return -EIO; } @@ -654,7 +640,73 @@ static int uc81xx_init(const struct device *dev) return uc81xx_controller_init(dev); } -#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) +static int uc81xx_set_tres_8(const struct device *dev) +{ + const struct uc81xx_config *config = dev->config; + const struct uc81xx_tres8 tres = { + .hres = config->width, + .vres = config->height, + }; + + LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_TRES, (const void *)&tres, sizeof(tres)); +} + +static inline int uc81xx_set_ptl_8(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc) +{ + const struct uc81xx_ptl8 ptl = { + .hrst = x, + .hred = x_end_idx, + .vrst = y, + .vred = y_end_idx, + .flags = UC81XX_PTL_FLAG_PT_SCAN, + }; + + /* Setup Partial Window and enable Partial Mode */ + LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_PTL, (const void *)&ptl, sizeof(ptl)); +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) || DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8179) +static int uc81xx_set_tres_16(const struct device *dev) +{ + const struct uc81xx_config *config = dev->config; + const struct uc81xx_tres8 tres = { + .hres = sys_cpu_to_be16(config->width), + .vres = sys_cpu_to_be16(config->height), + }; + + LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_TRES, (const void *)&tres, sizeof(tres)); +} + +static inline int uc81xx_set_ptl_16(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc) +{ + const struct uc81xx_ptl16 ptl = { + .hrst = sys_cpu_to_be16(x), + .hred = sys_cpu_to_be16(x_end_idx), + .vrst = sys_cpu_to_be16(y), + .vred = sys_cpu_to_be16(y_end_idx), + .flags = UC81XX_PTL_FLAG_PT_SCAN, + }; + + /* Setup Partial Window and enable Partial Mode */ + LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_PTL, (const void *)&ptl, sizeof(ptl)); +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) || DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) static int uc8176_set_cdi(const struct device *dev, bool border) { const struct uc81xx_config *config = dev->config; @@ -675,7 +727,22 @@ static int uc8176_set_cdi(const struct device *dev, bool border) LOG_DBG("CDI: %#hhx", cdi); return uc81xx_write_cmd_uint8(dev, UC81XX_CMD_CDI, cdi); } +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) +static const struct uc81xx_quirks uc8175_quirks = { + .max_width = 80, + .max_height = 160, + + .auto_copy = false, + + .set_cdi = uc8176_set_cdi, + .set_tres = uc81xx_set_tres_8, + .set_ptl = uc81xx_set_ptl_8, +}; +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) static const struct uc81xx_quirks uc8176_quirks = { .max_width = 400, .max_height = 300, @@ -683,6 +750,8 @@ static const struct uc81xx_quirks uc8176_quirks = { .auto_copy = false, .set_cdi = uc8176_set_cdi, + .set_tres = uc81xx_set_tres_16, + .set_ptl = uc81xx_set_ptl_16, }; #endif @@ -714,6 +783,8 @@ static const struct uc81xx_quirks uc8179_quirks = { .auto_copy = true, .set_cdi = uc8179_set_cdi, + .set_tres = uc81xx_set_tres_16, + .set_ptl = uc81xx_set_ptl_16, }; #endif @@ -814,6 +885,9 @@ static struct display_driver_api uc81xx_driver_api = { CONFIG_DISPLAY_INIT_PRIORITY, \ &uc81xx_driver_api); +DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8175, UC81XX_DEFINE, + &uc8175_quirks); + DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8176, UC81XX_DEFINE, &uc8176_quirks); diff --git a/drivers/display/uc81xx_regs.h b/drivers/display/uc81xx_regs.h index 322423324ad..aba38ac3e7f 100644 --- a/drivers/display/uc81xx_regs.h +++ b/drivers/display/uc81xx_regs.h @@ -106,14 +106,31 @@ #define UC8179_CDI_DDX1 BIT(1) #define UC8179_CDI_DDX0 BIT(0) -struct uc81xx_tres { +struct uc81xx_tres8 { + uint8_t hres; + uint8_t vres; +} __packed; + +BUILD_ASSERT(sizeof(struct uc81xx_tres8) == 2); + +struct uc81xx_ptl8 { + uint8_t hrst; + uint8_t hred; + uint8_t vrst; + uint8_t vred; + uint8_t flags; +} __packed; + +BUILD_ASSERT(sizeof(struct uc81xx_ptl8) == 5); + +struct uc81xx_tres16 { uint16_t hres; uint16_t vres; } __packed; -BUILD_ASSERT(sizeof(struct uc81xx_tres) == 4); +BUILD_ASSERT(sizeof(struct uc81xx_tres16) == 4); -struct uc81xx_ptl { +struct uc81xx_ptl16 { uint16_t hrst; uint16_t hred; uint16_t vrst; @@ -121,11 +138,10 @@ struct uc81xx_ptl { uint8_t flags; } __packed; -BUILD_ASSERT(sizeof(struct uc81xx_ptl) == 9); +BUILD_ASSERT(sizeof(struct uc81xx_ptl16) == 9); #define UC81XX_PTL_FLAG_PT_SCAN BIT(0) - /* Time constants in ms */ #define UC81XX_RESET_DELAY 10U #define UC81XX_PON_DELAY 100U diff --git a/dts/bindings/display/ultrachip,uc8175.yaml b/dts/bindings/display/ultrachip,uc8175.yaml new file mode 100644 index 00000000000..8c89c86aded --- /dev/null +++ b/dts/bindings/display/ultrachip,uc8175.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Andreas Sandberg +# SPDX-License-Identifier: Apache-2.0 + +description: UltraChip UC8175 EPD controller + +compatible: "ultrachip,uc8175" + +include: ultrachip,uc81xx-common.yaml