summaryrefslogtreecommitdiff
path: root/src/drivers/i2c/rx6110sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/i2c/rx6110sa')
-rw-r--r--src/drivers/i2c/rx6110sa/Kconfig5
-rw-r--r--src/drivers/i2c/rx6110sa/Makefile.inc1
-rw-r--r--src/drivers/i2c/rx6110sa/chip.h26
-rw-r--r--src/drivers/i2c/rx6110sa/rx6110sa.c146
-rw-r--r--src/drivers/i2c/rx6110sa/rx6110sa.h59
5 files changed, 237 insertions, 0 deletions
diff --git a/src/drivers/i2c/rx6110sa/Kconfig b/src/drivers/i2c/rx6110sa/Kconfig
new file mode 100644
index 0000000000..a5608f82f7
--- /dev/null
+++ b/src/drivers/i2c/rx6110sa/Kconfig
@@ -0,0 +1,5 @@
+config DRIVERS_I2C_RX6110SA
+ bool
+ default n
+ help
+ Enable support for external RTC chip RX6110 SA.
diff --git a/src/drivers/i2c/rx6110sa/Makefile.inc b/src/drivers/i2c/rx6110sa/Makefile.inc
new file mode 100644
index 0000000000..44c76a3291
--- /dev/null
+++ b/src/drivers/i2c/rx6110sa/Makefile.inc
@@ -0,0 +1 @@
+ramstage-$(CONFIG_DRIVERS_I2C_RX6110SA) += rx6110sa.c
diff --git a/src/drivers/i2c/rx6110sa/chip.h b/src/drivers/i2c/rx6110sa/chip.h
new file mode 100644
index 0000000000..b90a52963b
--- /dev/null
+++ b/src/drivers/i2c/rx6110sa/chip.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2017 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "rx6110sa.h"
+
+struct drivers_i2c_rx6110sa_config {
+ /* The day (of the week) is indicated by 7 bits, bit 0 to bit 6. */
+ unsigned char user_weekday; /* User day of the week to set */
+ unsigned char user_day; /* User day to set */
+ unsigned char user_month; /* User month to set */
+ unsigned char user_year; /* User year to set */
+ unsigned char set_user_date; /* Use user date from device tree */
+ unsigned char cof_selection; /* Set up "clock out" frequency */
+};
diff --git a/src/drivers/i2c/rx6110sa/rx6110sa.c b/src/drivers/i2c/rx6110sa/rx6110sa.c
new file mode 100644
index 0000000000..743b708c19
--- /dev/null
+++ b/src/drivers/i2c/rx6110sa/rx6110sa.c
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2017 Siemens AG.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <device/i2c.h>
+#include <device/device.h>
+#include <version.h>
+#include <console/console.h>
+#include <bcd.h>
+#include "chip.h"
+#include "rx6110sa.h"
+
+#define I2C_BUS_NUM (dev->bus->secondary - 1)
+#define I2C_DEV_NUM (dev->path.i2c.device)
+
+/* Set RTC date from coreboot build date. */
+static void rx6110sa_set_build_date(struct device *dev)
+{
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, YEAR_REG,
+ coreboot_build_date.year);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, MONTH_REG,
+ coreboot_build_date.month);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, DAY_REG,
+ coreboot_build_date.day);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, WEEK_REG,
+ (1 << coreboot_build_date.weekday));
+}
+
+/* Set RTC date from user defined date (available in e.g. device tree). */
+static void rx6110sa_set_user_date(struct device *dev)
+{
+ struct drivers_i2c_rx6110sa_config *config = dev->chip_info;
+
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, YEAR_REG,
+ bin2bcd(config->user_year));
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, MONTH_REG,
+ bin2bcd(config->user_month));
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, DAY_REG,
+ bin2bcd(config->user_day));
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, WEEK_REG,
+ (1 << config->user_weekday));
+}
+
+static void rx6110sa_final(struct device *dev)
+{
+ uint8_t hour, minute, second, year, month, day;
+
+ /* Read back current RTC date and time and print it to the console. */
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, HOUR_REG, &hour);
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, MINUTE_REG, &minute);
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, SECOND_REG, &second);
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, YEAR_REG, &year);
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, MONTH_REG, &month);
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, DAY_REG, &day);
+
+ printk(BIOS_INFO, "%s: Current date %02d.%02d.%02d %02d:%02d:%02d\n",
+ dev->chip_ops->name, bcd2bin(month), bcd2bin(day),
+ bcd2bin(year), bcd2bin(hour), bcd2bin(minute), bcd2bin(second));
+}
+
+static void rx6110sa_init(struct device *dev)
+{
+ struct drivers_i2c_rx6110sa_config *config = dev->chip_info;
+ uint8_t reg;
+
+ /* Do a dummy read first. */
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, SECOND_REG, &reg);
+
+ /*
+ * Check VLF-bit which indicates the RTC data loss, such as due to a
+ * supply voltage drop.
+ */
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, FLAG_REGISTER, &reg);
+
+ 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.
+ */
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, BATTERY_BACKUP_REG, 0x00);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, RESERVED_BIT_REG, RTC_INIT_VALUE);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, DIGITAL_REG, 0x00);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, IRQ_CONTROL_REG, 0x00);
+
+ /* Clear timer enable bit and set frequency of clock output. */
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, EXTENSION_REG, &reg);
+ reg &= ~(FSEL_MASK | TE_BIT);
+ reg |= (config->cof_selection << 6);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, EXTENSION_REG, reg);
+
+ /* Clear voltage low detect bit. */
+ i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, FLAG_REGISTER, &reg);
+ reg &= ~VLF_BIT;
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, FLAG_REGISTER, reg);
+
+ /* Before setting the clock stop oscillator. */
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, CTRL_REG, STOP_BIT);
+ if (config->set_user_date) {
+ /* Set user date defined in device tree. */
+ printk(BIOS_DEBUG, "%s: Set to user date\n",
+ dev->chip_ops->name);
+ rx6110sa_set_user_date(dev);
+ } else {
+ /* Set date from coreboot build. */
+ printk(BIOS_DEBUG, "%s: Set to coreboot build date\n",
+ dev->chip_ops->name);
+ rx6110sa_set_build_date(dev);
+ }
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, HOUR_REG, 1);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, MINUTE_REG, 0);
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, SECOND_REG, 0);
+ /* Start oscillator again as the RTC is set up now. */
+ i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, CTRL_REG, 0x00);
+}
+
+static struct device_operations rx6110sa_ops = {
+ .read_resources = DEVICE_NOOP,
+ .set_resources = DEVICE_NOOP,
+ .enable_resources = DEVICE_NOOP,
+ .init = rx6110sa_init,
+ .final = rx6110sa_final
+};
+
+static void rx6110sa_enable(struct device *dev)
+{
+ dev->ops = &rx6110sa_ops;
+}
+
+struct chip_operations drivers_i2c_rx6110sa_ops = {
+ CHIP_NAME("RX6110 SA")
+ .enable_dev = rx6110sa_enable
+};
diff --git a/src/drivers/i2c/rx6110sa/rx6110sa.h b/src/drivers/i2c/rx6110sa/rx6110sa.h
new file mode 100644
index 0000000000..99527e0420
--- /dev/null
+++ b/src/drivers/i2c/rx6110sa/rx6110sa.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _I2C_RX6110SA_H_
+#define _I2C_RX6110SA_H_
+
+/* The address of this RTC is fixed. */
+#define RX6110SA_SLAVE_ADR 0x32
+#define RX6110SA_I2C_CONTROLLER 0
+
+/* Register layout */
+#define SECOND_REG 0x10
+#define MINUTE_REG 0x11
+#define HOUR_REG 0x12
+#define WEEK_REG 0x13
+#define DAY_REG 0x14
+#define MONTH_REG 0x15
+#define YEAR_REG 0x16
+#define RESERVED_BIT_REG 0x17
+#define RTC_INIT_VALUE 0x28
+#define ALARM_MINUTE_REG 0x18
+#define ALARM_HOUR_REG 0x19
+#define ALARM_WEEKDAY_REG 0x1A
+#define TMR_COUNTER_0_REG 0x1B
+#define TMR_COUNTER_1_REG 0x1C
+#define EXTENSION_REG 0x1D
+#define TE_BIT (1 << 4)
+#define FSEL_MASK 0xC0
+#define FLAG_REGISTER 0x1E
+#define VLF_BIT (1 << 1)
+#define CTRL_REG 0x1F
+#define AIE_BIT (1 << 3)
+#define TIE_BIT (1 << 4)
+#define UIE_BIT (1 << 5)
+#define STOP_BIT (1 << 6)
+#define TEST_BIT (1 << 7)
+#define DIGITAL_REG 0x30
+#define BATTERY_BACKUP_REG 0x31
+#define IRQ_CONTROL_REG 0x32
+
+/* Define CLKOUT frequency divider values valid for parameter cof_selection */
+#define COF_OFF 0x00
+#define COF_1_HZ 0x01
+#define COF_1024_HZ 0x02
+#define COF_32768_HZ 0x03
+
+#endif /* _I2C_RX6110SA_H_ */