
Signed-off-by: Johannes Thumshirn johannes.thumshirn@men.de --- drivers/rtc/Makefile | 1 + drivers/rtc/rx8581.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 drivers/rtc/rx8581.c
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d5a2725..1502166 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -48,5 +48,6 @@ obj-$(CONFIG_RTC_RS5C372A) += rs5c372.o obj-$(CONFIG_RTC_RTC4543) += rtc4543.o obj-$(CONFIG_RTC_RV3029) += rv3029.o obj-$(CONFIG_RTC_RX8025) += rx8025.o +obj-$(CONFIG_RTC_RX8581) += rx8581.o obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o obj-$(CONFIG_RTC_X1205) += x1205.o diff --git a/drivers/rtc/rx8581.c b/drivers/rtc/rx8581.c new file mode 100644 index 0000000..71466d6 --- /dev/null +++ b/drivers/rtc/rx8581.c @@ -0,0 +1,180 @@ + /* + * (C) Copyright 2011 + * Ralf Truebenbach ralf.truebenbach@men.de, MEN Mikro Elektronik GmbH + * + * Based on: pcf8563.c + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Date & Time support for Epson RX8581 RTC + */ + +/* #define DEBUG */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_CMD_DATE) + +static uchar rtc_read(uchar reg); +static void rtc_write(uchar reg, uchar val); + +/* registers */ +#define RX8581_SEC 0x00 +#define RX8581_MIN 0x01 +#define RX8581_HOUR 0x02 +#define RX8581_WEEK 0x03 +#define RX8581_DAY 0x04 +#define RX8581_MONTH 0x05 +#define RX8581_YEAR 0x06 +#define RX8581_FLAG 0x0E +#define RX8581_CONTROL 0x0F + +/* masks */ +#define RX8581_SEC_MSK 0x7f +#define RX8581_MIN_MSK 0x7f +#define RX8581_HOUR_MSK 0x3f +#define RX8581_WEEK_MSK 0x7f +#define RX8581_DAY_MSK 0x3f +#define RX8581_MONTH_MSK 0x1f + +/* bits */ +#define RX8581_FLAG_VLF 0x02 + +#define RX8581_CONTROL_STOP 0x02 +#define RX8581_CONTROL_RESET 0x01 + +/* ------------------------------------------------------------------------- */ + +int rtc_get(struct rtc_time *tmp) +{ + int rel = 0; + uchar sec, min, hour, day, week, month, year, flag; + + sec = rtc_read(RX8581_SEC); + min = rtc_read(RX8581_MIN); + hour = rtc_read(RX8581_HOUR); + week = rtc_read(RX8581_WEEK); + day = rtc_read(RX8581_DAY); + month = rtc_read(RX8581_MONTH); + year = rtc_read(RX8581_YEAR); + flag = rtc_read(RX8581_FLAG); + + debug("Get RTC YEAR: 0x%02x MONTH: 0x%02x DAY: 0x%02x WEEK: 0x%02x ", + year, month, day, week); + debug("HOUR: 0x%02x MIN: 0x%02x SEC: 0x%02x Flag: 0x%02x\n", + hour, min, sec, flag); + debug("Alarms: MIN: 0x%02x HOUR: 0x%02x WEEK/DAY: 0x%02x\n", + rtc_read(0x08), rtc_read(0x09), rtc_read(0x0A)); + + if (flag & RX8581_FLAG_VLF) { + puts("## Warning: RTC Low Voltage - date/time not reliable\n"); + rel = -1; + } + + tmp->tm_sec = bcd2bin(sec & RX8581_SEC_MSK); + tmp->tm_min = bcd2bin(min & RX8581_MIN_MSK); + tmp->tm_hour = bcd2bin(hour & RX8581_HOUR_MSK); + tmp->tm_mday = bcd2bin(day & RX8581_DAY_MSK); + tmp->tm_mon = bcd2bin(month & RX8581_MONTH_MSK); + tmp->tm_year = bcd2bin(year) + (bcd2bin(year) >= 70 ? 1900 : 2000); + tmp->tm_wday = __ilog2(week & RX8581_WEEK_MSK); + tmp->tm_yday = 0; + tmp->tm_isdst = 0; + + debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + return rel; +} + +int rtc_set(struct rtc_time *tmp) +{ + uchar reg; + + debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + if (tmp->tm_year < 1970 || tmp->tm_year > 2069) + puts("## Warning: year should be between 1970 and 2069!\n"); + + /* stop */ + reg = rtc_read(RX8581_CONTROL); + rtc_write(RX8581_CONTROL, reg | RX8581_CONTROL_STOP); + + /* write data */ + rtc_write(RX8581_SEC, bin2bcd(tmp->tm_sec)); + rtc_write(RX8581_MIN, bin2bcd(tmp->tm_min)); + rtc_write(RX8581_HOUR, bin2bcd(tmp->tm_hour)); + rtc_write(RX8581_WEEK, bin2bcd(0x1 << tmp->tm_wday)); + rtc_write(RX8581_DAY, bin2bcd(tmp->tm_mday)); + rtc_write(RX8581_MONTH, bin2bcd(tmp->tm_mon)); + rtc_write(RX8581_YEAR, bin2bcd(tmp->tm_year % 100)); + + /* clear VLF */ + reg = rtc_read(RX8581_FLAG); + rtc_write(RX8581_FLAG, reg & ~RX8581_FLAG_VLF); + + /* restart */ + reg = rtc_read(RX8581_CONTROL); + rtc_write(RX8581_CONTROL, reg & ~RX8581_CONTROL_STOP); + + return 0; +} + +void rtc_reset(void) +{ + struct rtc_time tmp; + + /* reset device */ + rtc_write(0x0F, 0x03); + rtc_write(0x0F, 0x00); + + /* reset time */ + tmp.tm_year = 1970; + tmp.tm_mon = 1; + tmp.tm_mday = 1; + tmp.tm_hour = 0; + tmp.tm_min = 0; + tmp.tm_sec = 0; + + rtc_set(&tmp); +} + +/* ------------------------------------------------------------------------- */ + +static uchar rtc_read(uchar reg) +{ + return i2c_reg_read(CONFIG_SYS_I2C_RTC_ADDR, reg); +} + +static void rtc_write(uchar reg, uchar val) +{ + i2c_reg_write(CONFIG_SYS_I2C_RTC_ADDR, reg, val); +} + +#endif