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 )
684782static 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,
813912DT_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+
816918DT_FOREACH_STATUS_OKAY_VARGS (ultrachip_uc8179 , UC81XX_DEFINE ,
817919 & uc8179_quirks );
0 commit comments