Skip to content

Commit

Permalink
drivers: display: uc81xx: add support for uc8175
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
xqinx committed Dec 8, 2023
1 parent 3c2a896 commit c8eab38
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 30 deletions.
2 changes: 1 addition & 1 deletion drivers/display/Kconfig.uc81xx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
122 changes: 98 additions & 24 deletions drivers/display/uc81xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -403,13 +401,7 @@ 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;
Expand All @@ -425,8 +417,7 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16
__ASSERT(!(desc->width % UC81XX_PIXELS_PER_BYTE),
"Buffer width not multiple of %d", UC81XX_PIXELS_PER_BYTE);

if ((y_end_idx > (config->height - 1)) ||
(x_end_idx > (config->width - 1))) {
if ((y_end_idx > (config->height - 1)) || (x_end_idx > (config->width - 1))) {
LOG_ERR("Position out of bounds");
return -EINVAL;
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -675,14 +727,31 @@ 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,

.auto_copy = false,

.set_cdi = uc8176_set_cdi,
.set_tres = uc81xx_set_tres_16,
.set_ptl = uc81xx_set_ptl_16,
};
#endif

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);

Expand Down
27 changes: 22 additions & 5 deletions drivers/display/uc81xx_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,43 @@
#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;
uint16_t vred;
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
Expand Down
8 changes: 8 additions & 0 deletions dts/bindings/display/ultrachip,uc8175.yaml
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit c8eab38

Please sign in to comment.