summaryrefslogtreecommitdiff
path: root/src/drivers/i2c/rx6110sa/rx6110sa.c
diff options
context:
space:
mode:
authorWerner Zeh <werner.zeh@siemens.com>2017-06-29 08:37:14 +0200
committerWerner Zeh <werner.zeh@siemens.com>2017-06-30 16:57:12 +0000
commit6e6261e89344ff25dc3beb0b8abb753ff2347624 (patch)
treefba5870c3072fe2c42165d225e2e1912d7dbef1f /src/drivers/i2c/rx6110sa/rx6110sa.c
parent083504b66b5f3b281221f0a8f4fd62a4d9071287 (diff)
rx6110sa: Add a software reset sequence in case of power loss
According to the datasheet the RTC needs a power rising slope of no more than 100µs/V to ensure a correct power-on reset. If the mainboard that hosts the RTC cannot guarantee this, a software reset sequence is needed in the case where the battery was drained completely. As the rising slope of the power supply depends on so many parameters and is highly mainboard specific, refactor the initialization code to perform a software reset every time a power loss event is recognized by the RTC. Change-Id: If64d672e51667523058041bd00e1e50ac047143d Signed-off-by: Werner Zeh <werner.zeh@siemens.com> Reviewed-on: https://review.coreboot.org/20412 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/drivers/i2c/rx6110sa/rx6110sa.c')
-rw-r--r--src/drivers/i2c/rx6110sa/rx6110sa.c87
1 files changed, 55 insertions, 32 deletions
diff --git a/src/drivers/i2c/rx6110sa/rx6110sa.c b/src/drivers/i2c/rx6110sa/rx6110sa.c
index 06735a7868..761d83d810 100644
--- a/src/drivers/i2c/rx6110sa/rx6110sa.c
+++ b/src/drivers/i2c/rx6110sa/rx6110sa.c
@@ -19,6 +19,7 @@
#include <version.h>
#include <console/console.h>
#include <bcd.h>
+#include <timer.h>
#include "chip.h"
#include "rx6110sa.h"
@@ -86,62 +87,84 @@ static void rx6110sa_final(struct device *dev)
static void rx6110sa_init(struct device *dev)
{
struct drivers_i2c_rx6110sa_config *config = dev->chip_info;
- uint8_t reg;
+ uint8_t reg, flags;
+ struct stopwatch sw;
/* Do a dummy read first as requested in the datasheet. */
rx6110sa_read(dev, SECOND_REG);
+ /* Check power loss status by reading the VLF-bit. */
+ flags = rx6110sa_read(dev, FLAG_REGISTER);
+ if (flags & VLF_BIT) {
+ /*
+ * Voltage low detected, perform RX6110 SA reset sequence as
+ * requested in the datasheet. The meaning of the registers 0x60
+ * and above is not documented in the datasheet, they have to be
+ * used as requested according to Epson.
+ */
+ rx6110sa_write(dev, BATTERY_BACKUP_REG, 0x00);
+ rx6110sa_write(dev, CTRL_REG, 0x00);
+ rx6110sa_write(dev, CTRL_REG, TEST_BIT);
+ rx6110sa_write(dev, 0x60, 0xd3);
+ rx6110sa_write(dev, 0x66, 0x03);
+ rx6110sa_write(dev, 0x6b, 0x02);
+ rx6110sa_write(dev, 0x6b, 0x01);
+ /* According to the datasheet one have to wait for at least 2 ms
+ * before the VLF bit can be cleared in the flag register after
+ * this reset sequence. As the other registers are still
+ * accessible use the stopwatch to parallel the flow.
+ */
+ stopwatch_init_msecs_expire(&sw, AFTER_RESET_DELAY_MS);
+ }
/*
- * Set battery backup mode and power monitor sampling time even if there
- * was no power loss to make sure that the right mode is used as it
- * directly influences the backup current consumption and therefore the
- * backup time.
+ * Set up important registers even if there was no power loss to make
+ * sure that the right mode is used as it directly influences the
+ * backup current consumption and therefore the backup time. These
+ * settings do not change current date and time and the RTC will not
+ * be stopped while the registers are set up.
*/
reg = (config->pmon_sampling & PMON_SAMPL_MASK) |
(!!config->bks_off << 2) | (!!config->bks_on << 3) |
(!!config->iocut_en << 4);
rx6110sa_write(dev, BATTERY_BACKUP_REG, reg);
- /*
- * Check VLF-bit which indicates the RTC data loss, such as due to a
- * supply voltage drop.
- */
- reg = rx6110sa_read(dev, FLAG_REGISTER);
- if (!(reg & VLF_BIT))
- /* No voltage low detected, everything is well. */
- return;
- /*
- * Voltage low detected, initialize RX6110 SA again.
- * Set first some registers to known state.
- */
- rx6110sa_write(dev, RESERVED_BIT_REG, RTC_INIT_VALUE);
- rx6110sa_write(dev, DIGITAL_REG, 0x00);
- reg = (!!config->enable_1hz_out << 4) |
- (!!config->irq_output_pin << 2) |
- (config->fout_output_pin & FOUT_OUTPUT_PIN_MASK);
- rx6110sa_write(dev, IRQ_CONTROL_REG, reg);
/* Clear timer enable bit and set frequency of clock output. */
reg = rx6110sa_read(dev, EXTENSION_REG);
- reg &= ~(FSEL_MASK | TE_BIT);
- reg |= (config->cof_selection << 6);
+ reg &= ~(FSEL_MASK);
+ reg |= ((config->cof_selection << 6) & FSEL_MASK);
if (config->timer_preset) {
/* Timer needs to be in stop mode prior to programming it. */
- rx6110sa_write(dev, EXTENSION_REG, reg);
- reg &= ~TSEL_MASK;
+ if (reg & TE_BIT) {
+ reg &= ~TE_BIT;
+ rx6110sa_write(dev, EXTENSION_REG, reg);
+ }
/* Program the timer preset value. */
rx6110sa_write(dev, TMR_COUNTER_0_REG,
config->timer_preset & 0xff);
rx6110sa_write(dev, TMR_COUNTER_1_REG,
(config->timer_preset >> 8) & 0xff);
/* Set Timer Enable bit and the timer clock value. */
+ reg &= ~TSEL_MASK;
reg |= ((!!config->timer_en << 4) |
(config->timer_clk & TSEL_MASK));
}
rx6110sa_write(dev, EXTENSION_REG, reg);
-
- /* Clear voltage low detect bit. */
- reg = rx6110sa_read(dev, FLAG_REGISTER);
- reg &= ~VLF_BIT;
- rx6110sa_write(dev, FLAG_REGISTER, reg);
+ rx6110sa_write(dev, CTRL_REG, 0x00);
+ rx6110sa_write(dev, DIGITAL_REG, 0x00);
+ rx6110sa_write(dev, RESERVED_BIT_REG, RTC_INIT_VALUE);
+ reg = (!!config->enable_1hz_out << 4) |
+ (!!config->irq_output_pin << 2) |
+ (config->fout_output_pin & FOUT_OUTPUT_PIN_MASK);
+ rx6110sa_write(dev, IRQ_CONTROL_REG, reg);
+ /* If there was no power loss event no further steps are needed. */
+ if (!(flags & VLF_BIT))
+ return;
+ /* There was a power loss event, clear voltage low detect bit.
+ * Take the needed delay after a reset sequence into account before the
+ * VLF-bit can be cleared.
+ */
+ while (!stopwatch_expired(&sw))
+ flags &= ~VLF_BIT;
+ rx6110sa_write(dev, FLAG_REGISTER, flags);
/* Before setting the clock stop oscillator. */
rx6110sa_write(dev, CTRL_REG, STOP_BIT);