Skip to content

Commit 5b595e3

Browse files
mespunaiotcfriedt
authored andcommitted
drivers: display: uc8151d: Add UC8151D display controller support
Add support for the UltraChip UC8151D e-paper display (EPD) controller. The UC8151D is part of the UC81xx family of display controllers commonly used in e-ink displays. This implementation extends the existing UC81xx driver infrastructure by adding device tree bindings, Kconfig options, and the necessary driver code to support the UC8151D variant. Signed-off-by: Marc Espuña <[email protected]>
1 parent 5a70c3d commit 5b595e3

File tree

4 files changed

+155
-2
lines changed

4 files changed

+155
-2
lines changed

drivers/display/Kconfig.uc81xx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
config UC81XX
77
bool "UltraChip UC81xx compatible display controller driver"
88
default y
9-
depends on DT_HAS_ULTRACHIP_UC8175_ENABLED || DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED
9+
depends on DT_HAS_ULTRACHIP_UC8175_ENABLED || DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8151D_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED
1010
select MIPI_DBI
1111
help
1212
Enable driver for UC81xx compatible controller.

drivers/display/uc81xx.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
* Copyright (c) 2025 Cactus Engineering S.L
23
* Copyright (c) 2022 Andreas Sandberg
34
* Copyright (c) 2020 PHYTEC Messtechnik GmbH
45
* Copyright 2024 NXP
@@ -65,6 +66,7 @@ struct uc81xx_quirks {
6566
uint16_t max_height;
6667

6768
bool auto_copy;
69+
bool pon_after_softstart;
6870

6971
int (*set_cdi)(const struct device *dev, bool border);
7072
int (*set_tres)(const struct device *dev);
@@ -227,6 +229,22 @@ static int uc81xx_set_profile(const struct device *dev,
227229
return -EIO;
228230
}
229231

232+
if (config->quirks->pon_after_softstart) {
233+
/* UC8151D requires PON command after BTST for proper
234+
* power initialization
235+
*/
236+
LOG_DBG("Sending PON command after softstart");
237+
if (uc81xx_write_cmd(dev, UC81XX_CMD_PON, NULL, 0)) {
238+
return -EIO;
239+
}
240+
241+
/* Wait for power stabilization and BUSY_N = HIGH */
242+
k_sleep(K_MSEC(UC81XX_PON_DELAY));
243+
uc81xx_busy_wait(dev);
244+
245+
LOG_DBG("PON command completed");
246+
}
247+
230248
/*
231249
* Enable LUT overrides if a LUT has been provided by
232250
* the user.
@@ -660,6 +678,7 @@ static const struct uc81xx_quirks uc8175_quirks = {
660678
.max_height = 160,
661679

662680
.auto_copy = false,
681+
.pon_after_softstart = false,
663682

664683
.set_cdi = uc8176_set_cdi,
665684
.set_tres = uc81xx_set_tres_8,
@@ -673,13 +692,92 @@ static const struct uc81xx_quirks uc8176_quirks = {
673692
.max_height = 300,
674693

675694
.auto_copy = false,
695+
.pon_after_softstart = false,
676696

677697
.set_cdi = uc8176_set_cdi,
678698
.set_tres = uc81xx_set_tres_16,
679699
.set_ptl = uc81xx_set_ptl_16,
680700
};
681701
#endif
682702

703+
#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8151d)
704+
static int uc8151d_set_tres(const struct device *dev)
705+
{
706+
const struct uc81xx_config *config = dev->config;
707+
/* Pass pixel coordinates directly; hardware interprets as byte+bit encoding
708+
* See UC8151D datasheet page 22 (TRES command, R61h)
709+
*/
710+
const struct uc8151d_tres tres = {
711+
.hres = config->width,
712+
.vres = sys_cpu_to_be16(config->height),
713+
};
714+
715+
LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES");
716+
717+
return uc81xx_write_cmd(dev, UC81XX_CMD_TRES,
718+
(const void *)&tres, sizeof(tres));
719+
}
720+
721+
static int uc8151d_set_ptl(const struct device *dev, uint16_t x, uint16_t y,
722+
uint16_t x_end_idx, uint16_t y_end_idx,
723+
const struct display_buffer_descriptor *desc)
724+
{
725+
/* Pass pixel coordinates directly; hardware interprets as byte+bit encoding
726+
* See UC8151D datasheet page 26 (Partial Window command, R90h)
727+
*/
728+
const struct uc8151d_ptl ptl = {
729+
.hrst = x & BIT_MASK(8),
730+
.hred = x_end_idx & BIT_MASK(8),
731+
.vrst = sys_cpu_to_be16(y & BIT_MASK(9)),
732+
.vred = sys_cpu_to_be16(y_end_idx & BIT_MASK(9)),
733+
.pt_scan = UC81XX_PTL_FLAG_PT_SCAN,
734+
};
735+
736+
/* Setup Partial Window and enable Partial Mode */
737+
LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl");
738+
739+
return uc81xx_write_cmd(dev, UC81XX_CMD_PTL,
740+
(const void *)&ptl, sizeof(ptl));
741+
}
742+
743+
static int uc8151d_set_cdi(const struct device *dev, bool border)
744+
{
745+
const struct uc81xx_config *config = dev->config;
746+
const struct uc81xx_data *data = dev->data;
747+
const struct uc81xx_profile *p = config->profiles[data->profile];
748+
uint8_t cdi = UC8151D_CDI_DEFAULT; /* Start with 0xD7 */
749+
750+
if (!p || !p->override_cdi) {
751+
/* Use default CDI value if no profile override */
752+
cdi = UC8151D_CDI_DEFAULT;
753+
} else {
754+
/* Keep VBD and DDX bits from default, use profile CDI interval */
755+
cdi = (UC8151D_CDI_DEFAULT & (UC8151D_CDI_VBD_MASK | UC8151D_CDI_DDX_MASK)) |
756+
(p->cdi & UC8151D_CDI_MASK);
757+
}
758+
759+
if (!border) {
760+
/* Set VBD to floating for no border */
761+
cdi = (cdi & ~UC8151D_CDI_VBD_MASK) | UC8151D_CDI_VBD_FLOATING;
762+
}
763+
764+
LOG_DBG("CDI: %#hhx", cdi);
765+
return uc81xx_write_cmd_uint8(dev, UC81XX_CMD_CDI, cdi);
766+
}
767+
768+
static const struct uc81xx_quirks uc8151d_quirks = {
769+
.max_width = 160, /* Actual max from datasheet */
770+
.max_height = 296, /* Actual max from datasheet */
771+
772+
.auto_copy = false, /* Manual copy required */
773+
.pon_after_softstart = true,
774+
775+
.set_cdi = uc8151d_set_cdi,
776+
.set_tres = uc8151d_set_tres,
777+
.set_ptl = uc8151d_set_ptl,
778+
};
779+
#endif
780+
683781
#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8179)
684782
static int uc8179_set_cdi(const struct device *dev, bool border)
685783
{
@@ -706,6 +804,7 @@ static const struct uc81xx_quirks uc8179_quirks = {
706804
.max_height = 600,
707805

708806
.auto_copy = true,
807+
.pon_after_softstart = false,
709808

710809
.set_cdi = uc8179_set_cdi,
711810
.set_tres = uc81xx_set_tres_16,
@@ -813,5 +912,8 @@ DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8175, UC81XX_DEFINE,
813912
DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8176, UC81XX_DEFINE,
814913
&uc8176_quirks);
815914

915+
DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8151d, UC81XX_DEFINE,
916+
&uc8151d_quirks);
917+
816918
DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8179, UC81XX_DEFINE,
817919
&uc8179_quirks);

drivers/display/uc81xx_regs.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,48 @@ struct uc81xx_ptl16 {
140140

141141
BUILD_ASSERT(sizeof(struct uc81xx_ptl16) == 9);
142142

143-
#define UC81XX_PTL_FLAG_PT_SCAN BIT(0)
143+
/* UC8151D-specific structures */
144+
#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8151d)
145+
struct uc8151d_tres {
146+
/* Horizontal resolution in pixels.
147+
* Hardware interprets as bank[7:3] | column[2:0]
148+
*/
149+
uint8_t hres;
150+
uint16_t vres; /* Vertical resolution (big-endian) */
151+
} __packed;
152+
153+
BUILD_ASSERT(sizeof(struct uc8151d_tres) == 3);
154+
155+
struct uc8151d_ptl {
156+
uint8_t hrst; /* Horizontal start (byte-packed) */
157+
uint8_t hred; /* Horizontal end (byte-packed) */
158+
uint16_t vrst; /* Vertical start (big-endian, 9-bit) */
159+
uint16_t vred; /* Vertical end (big-endian, 9-bit) */
160+
uint8_t pt_scan; /* PT_SCAN - Scan mode */
161+
} __packed;
162+
163+
BUILD_ASSERT(sizeof(struct uc8151d_ptl) == 7);
164+
165+
/* UC8151D CDI register bit fields */
166+
#define UC8151D_CDI_VBD_MASK GENMASK(7, 6)
167+
#define UC8151D_CDI_DDX_MASK GENMASK(5, 4)
168+
#define UC8151D_CDI_MASK GENMASK(3, 0)
169+
#define UC8151D_CDI_DEFAULT 0xD7 /* Default value */
170+
171+
/* UC8151D CDI VBD values for border control */
172+
#define UC8151D_CDI_VBD_FLOATING 0x00 /* Floating border */
173+
#define UC8151D_CDI_VBD_LUT1 0x40 /* LUT1 border */
174+
#define UC8151D_CDI_VBD_LUT2 0x80 /* LUT2 border */
175+
#define UC8151D_CDI_VBD_LUT3 0xC0 /* LUT3 border */
176+
177+
/* UC8151D CDI DDX values for data polarity */
178+
#define UC8151D_CDI_DDX_DEFAULT 0x10 /* Default DDX setting */
179+
180+
/* UC8151D CDI interval values */
181+
#define UC8151D_CDI_10_HSYNC 0x07 /* 10 hsync (default) */
182+
#endif
183+
184+
#define UC81XX_PTL_FLAG_PT_SCAN BIT(0)
144185

145186
/* Time constants in ms */
146187
#define UC81XX_RESET_DELAY 10U
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 Cactus Engineering S.L
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
UltraChip UC8151D EPD controller with native 160x296 monochrome (1bpp)
6+
display support.
7+
8+
compatible: "ultrachip,uc8151d"
9+
10+
include: ultrachip,uc81xx-common.yaml

0 commit comments

Comments
 (0)