summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlexander Feilke <[email protected]>2026-05-22 17:39:26 +0200
committerTom Rini <[email protected]>2026-06-05 10:14:24 -0600
commit2b6de25797b49a1b3eff6d24bfa0f7808028b962 (patch)
treeeadf1c6c0d00743a40ddf64c1e9905b8780f2019 /drivers
parent49754d293ea4a2df923cd70de8a69a4ba150477d (diff)
rtc: pcf85063: keep the divider chain in reset during set_time
Sync from upstream linux v6.19. Reviewed-by: Alexander Sverdlin <[email protected]> Signed-off-by: Alexander Feilke <[email protected]>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/pcf85063.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/drivers/rtc/pcf85063.c b/drivers/rtc/pcf85063.c
index 06c85d939e0..0b336b8c5ee 100644
--- a/drivers/rtc/pcf85063.c
+++ b/drivers/rtc/pcf85063.c
@@ -68,12 +68,25 @@ static int pcf85063_get_time(struct udevice *dev, struct rtc_time *tm)
static int pcf85063_set_time(struct udevice *dev, const struct rtc_time *tm)
{
u8 regs[7];
+ int rc;
if (tm->tm_year < 2000 || tm->tm_year > 2099) {
dev_err(dev, "Year must be between 2000 and 2099.\n");
return -EINVAL;
}
+ /*
+ * to accurately set the time, reset the divider chain and keep it in
+ * reset state until all time/date registers are written
+ */
+ rc = dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1,
+ PCF85063_REG_CTRL1_EXT_TEST |
+ PCF85063_REG_CTRL1_STOP,
+ PCF85063_REG_CTRL1_STOP);
+
+ if (rc)
+ return rc;
+
/* hours, minutes and seconds */
regs[0] = bin2bcd(tm->tm_sec) & (~PCF85063_REG_SC_OS);
@@ -91,7 +104,17 @@ static int pcf85063_set_time(struct udevice *dev, const struct rtc_time *tm)
/* adjust register to match rtc_time spec */
regs[6] = bin2bcd(tm->tm_year % 100);
- return dm_i2c_write(dev, PCF85063_REG_SC, regs, sizeof(regs));
+ rc = dm_i2c_write(dev, PCF85063_REG_SC, regs, sizeof(regs));
+ if (rc)
+ return rc;
+
+ /*
+ * Write the control register as a separate action since the size of
+ * the register space is different between the PCF85063TP and
+ * PCF85063A devices. The rollover point can not be used.
+ */
+ return dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1,
+ PCF85063_REG_CTRL1_STOP, 0);
}
static int pcf85063_reset(struct udevice *dev)