summaryrefslogtreecommitdiff
path: root/src/drivers/i2c
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
parent083504b66b5f3b281221f0a8f4fd62a4d9071287 (diff)
downloadcoreboot-6e6261e89344ff25dc3beb0b8abb753ff2347624.tar.xz
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')
-rw-r--r--src/drivers/i2c/rx6110sa/rx6110sa.c87
-rw-r--r--src/drivers/i2c/rx6110sa/rx6110sa.h10
2 files changed, 61 insertions, 36 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);
diff --git a/src/drivers/i2c/rx6110sa/rx6110sa.h b/src/drivers/i2c/rx6110sa/rx6110sa.h
index ebd75ead60..7e71f24ec3 100644
--- a/src/drivers/i2c/rx6110sa/rx6110sa.h
+++ b/src/drivers/i2c/rx6110sa/rx6110sa.h
@@ -29,7 +29,7 @@
#define MONTH_REG 0x15
#define YEAR_REG 0x16
#define RESERVED_BIT_REG 0x17
-#define RTC_INIT_VALUE 0x28
+#define RTC_INIT_VALUE 0xA8
#define ALARM_MINUTE_REG 0x18
#define ALARM_HOUR_REG 0x19
#define ALARM_WEEKDAY_REG 0x1A
@@ -81,8 +81,10 @@
#define PMON_SAMPL_256_MS 0x03
/* Define on which pin of the RTC the generated square wave will be driven. */
-#define FOUT_IRQ2 0x00 /* IRQ2 pin used for Fout */
-#define FOUT_IRQ1 0x01 /* IRQ1 pin used for Fout */
-#define FOUT_DO_FOUT 0x02 /* DO/FOUT pin used for Fout */
+#define FOUT_IRQ2 0x00 /* IRQ2 pin used for Fout */
+#define FOUT_IRQ1 0x01 /* IRQ1 pin used for Fout */
+#define FOUT_DO_FOUT 0x02 /* DO/FOUT pin used for Fout */
+
+#define AFTER_RESET_DELAY_MS 2 /* Delay after reset sequence */
#endif /* _I2C_RX6110SA_H_ */