From 7fd20beaf81455cc29271283426e25e722b90fe1 Mon Sep 17 00:00:00 2001 From: Mario Scheithauer Date: Mon, 8 May 2017 16:09:26 +0200 Subject: drivers/i2c: Add new driver for RTC type RX6110 SA This driver enables the usage of the external RTC chip RX6110 SA (http://www5.epsondevice.com/en/products/i2c/rx6110sab.html) which is connected to the I2C bus. The I2C address of this device is fixed. One can change parameters in the device tree so that the used setup can be adapted to match the configuration of the device on the mainboard. Change-Id: I1290a10c2d5ad76a317c99c8b92a013309a605d6 Signed-off-by: Mario Scheithauer Reviewed-on: https://review.coreboot.org/19625 Tested-by: build bot (Jenkins) Reviewed-by: Werner Zeh --- src/drivers/i2c/rx6110sa/Kconfig | 5 ++ src/drivers/i2c/rx6110sa/Makefile.inc | 1 + src/drivers/i2c/rx6110sa/chip.h | 26 ++++++ src/drivers/i2c/rx6110sa/rx6110sa.c | 146 ++++++++++++++++++++++++++++++++++ src/drivers/i2c/rx6110sa/rx6110sa.h | 59 ++++++++++++++ 5 files changed, 237 insertions(+) create mode 100644 src/drivers/i2c/rx6110sa/Kconfig create mode 100644 src/drivers/i2c/rx6110sa/Makefile.inc create mode 100644 src/drivers/i2c/rx6110sa/chip.h create mode 100644 src/drivers/i2c/rx6110sa/rx6110sa.c create mode 100644 src/drivers/i2c/rx6110sa/rx6110sa.h (limited to 'src/drivers/i2c') 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 +#include +#include +#include +#include +#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, ®); + + /* + * 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, ®); + + 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 &= ~(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 &= ~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_ */ -- cgit v1.2.3