rtc: rv8803: re-initialize all Epson RX8803 registers on voltage loss
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 d3700b6b64
("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@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20220426071056.1187235-4-s.hauer@pengutronix.de
This commit is contained in:
parent
f8176e0bb8
commit
c27fee16fa
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue