From: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> The reference manuals of both the RX8803 and RV8803 dictate that "[On V2F/VLF = ] all registers must be initialized". The RV-8803 application manual (rev. 1.6) further specifies that crossing V_LOW2 threshold enables flag V2F and triggers a Power-On reset. According to table 3.11 in the document, all control registers are defined to sensible values. However, The Epson RX-8803 doesn't offer the same guarantees. It explicitly states: During the initial power-up, the TEST bit is reset to "0" and the VLF bit is set to "1". ∗ At this point, all other register values are _undefined_, so be sure to perform a reset before using the module. Commit d3700b6b6479 ("rtc: rv8803: Stop the clock while setting the time") also had this rationale: Indeed, all the registers must be initialized if the voltage has been lower than VLOW2 (triggering V2F), but not low enough to trigger a POR. We should follow the advice and initialize all applicable registers. We can group the registers into 3 groups: A) Already correctly handled registers: * 0B-0Ch | Timer Counter | unused and disabled by clearing TE in 0Dh * 0Dh | Extension Reg | already initialized in rv8803_regs_configure * 0Eh | Flag Reg | handled in IRQ handler, except for VLF, VDET * 0Eh | VLF, VDET | cleared in ->set_time * 10h | 100th Seconds | Already reset via RESET bit * 20-21h | Capture Buffer | holds timestamp unused by driver * 2Fh | Event Control | resets automatically B) Registers that are hardware initialized on POR, but not on VLF: * 0Fh | Control Reg * 2Ch | OSC Offset C) RAM that is undefined on voltage loss: * 00-06h | Date/Time * 07h | RAM * 08-0Ah | Alarm This means we should initialize after VLF the registers in group B (RV8803_CTRL and RV8803_OSC_OFFSET). Group C is all-zero after voltage loss on the RV-8803, but undefined on the RX-8803. This is ok for Date/Time because ->get_time returns an error code for as long as the voltage loss flag is active. It's cleared on ->set_time however. Zeroing both RAM and alarm ensures a fixed value is read afterwards. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- drivers/rtc/rtc-rv8803.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 21a6f1eddb092..fe1247e771b98 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -9,6 +9,7 @@ #include <linux/bcd.h> #include <linux/bitops.h> +#include <linux/bitfield.h> #include <linux/log2.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -33,6 +34,7 @@ #define RV8803_EXT 0x0D #define RV8803_FLAG 0x0E #define RV8803_CTRL 0x0F +#define RV8803_OSC_OFFSET 0x2C #define RV8803_EXT_WADA BIT(6) @@ -49,12 +51,15 @@ #define RV8803_CTRL_TIE BIT(4) #define RV8803_CTRL_UIE BIT(5) +#define RX8803_CTRL_CSEL GENMASK(7, 6) + #define RX8900_BACKUP_CTRL 0x18 #define RX8900_FLAG_SWOFF BIT(2) #define RX8900_FLAG_VDETOFF BIT(3) enum rv8803_type { rv_8803, + rx_8803, rx_8804, rx_8900 }; @@ -137,10 +142,41 @@ static int rv8803_write_regs(const struct i2c_client *client, return ret; } +static int rv8803_regs_init(struct rv8803_data *rv8803) +{ + int ret; + + ret = rv8803_write_reg(rv8803->client, RV8803_OSC_OFFSET, 0x00); + if (ret) + return ret; + + ret = rv8803_write_reg(rv8803->client, RV8803_CTRL, + FIELD_PREP(RX8803_CTRL_CSEL, 1)); /* 2s */ + if (ret) + return ret; + + ret = rv8803_write_regs(rv8803->client, RV8803_ALARM_MIN, 3, + (u8[]){ 0, 0, 0 }); + if (ret) + return ret; + + return rv8803_write_reg(rv8803->client, RV8803_RAM, 0x00); +} + static int rv8803_regs_configure(struct rv8803_data *rv8803); static int rv8803_regs_reset(struct rv8803_data *rv8803) { + /* + * The RV-8803 resets all registers to POR defaults after voltage-loss, + * the Epson RTCs don't, so we manually reset the remainder here. + */ + if (rv8803->type == rx_8803 || rv8803->type == rx_8900) { + int ret = rv8803_regs_init(rv8803); + if (ret) + return ret; + } + return rv8803_regs_configure(rv8803); } @@ -631,7 +667,7 @@ static int rv8803_probe(struct i2c_client *client, static const struct i2c_device_id rv8803_id[] = { { "rv8803", rv_8803 }, { "rv8804", rx_8804 }, - { "rx8803", rv_8803 }, + { "rx8803", rx_8803 }, { "rx8900", rx_8900 }, { } }; @@ -644,7 +680,7 @@ static const __maybe_unused struct of_device_id rv8803_of_match[] = { }, { .compatible = "epson,rx8803", - .data = (void *)rv_8803 + .data = (void *)rx_8803 }, { .compatible = "epson,rx8804", -- 2.30.2