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 <xiaoq@google.com>
This commit is contained in:
Xiao Qin 2023-09-14 14:32:17 -07:00 committed by Carles Cufí
parent 2b20c0e3e6
commit 7c46b0b898
4 changed files with 126 additions and 28 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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