diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/bfin_rtc.c | 121 | ||||
-rw-r--r-- | drivers/rtc/ds1307.c | 209 |
4 files changed, 196 insertions, 142 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cb79a016316..d06130c7a2e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -23,4 +23,11 @@ config RTC_PCF2127 has a selectable I2C-bus or SPI-bus, a backup battery switch-over circuit, a programmable watchdog function, a timestamp function, and many other features. +config RTC_DS1307 + bool "Enable DS1307 driver" + depends on DM_RTC + help + Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and + compatible Real Time Clock devices. + endmenu diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c9194270851..87c3d9cae20 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_DM_RTC) += rtc-uclass.o obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o -obj-$(CONFIG_RTC_BFIN) += bfin_rtc.o obj-y += date.o obj-$(CONFIG_RTC_DAVINCI) += davinci.o obj-$(CONFIG_RTC_DS1302) += ds1302.o diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c deleted file mode 100644 index a079a1d4723..00000000000 --- a/drivers/rtc/bfin_rtc.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2004-2008 Analog Devices Inc. - * - * (C) Copyright 2001 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * Licensed under the GPL-2 or later. - */ - -#include <common.h> -#include <command.h> -#include <rtc.h> - -#if defined(CONFIG_CMD_DATE) - -#include <asm/blackfin.h> -#include <asm/mach-common/bits/rtc.h> - -#define pr_stamp() debug("%s:%s:%i: here i am\n", __FILE__, __func__, __LINE__) - -#define MIN_TO_SECS(x) (60 * (x)) -#define HRS_TO_SECS(x) (60 * MIN_TO_SECS(x)) -#define DAYS_TO_SECS(x) (24 * HRS_TO_SECS(x)) - -#define NUM_SECS_IN_MIN MIN_TO_SECS(1) -#define NUM_SECS_IN_HR HRS_TO_SECS(1) -#define NUM_SECS_IN_DAY DAYS_TO_SECS(1) - -/* Enable the RTC prescaler enable register */ -void rtc_init(void) -{ - if (!(bfin_read_RTC_PREN() & 0x1)) - bfin_write_RTC_PREN(0x1); -} - -/* Our on-chip RTC has no notion of "reset" */ -void rtc_reset(void) -{ - rtc_init(); -} - -/* Wait for pending writes to complete */ -static void wait_for_complete(void) -{ - pr_stamp(); - while (!(bfin_read_RTC_ISTAT() & WRITE_COMPLETE)) - if (!(bfin_read_RTC_ISTAT() & WRITE_PENDING)) - break; - bfin_write_RTC_ISTAT(WRITE_COMPLETE); -} - -/* Set the time. Get the time_in_secs which is the number of seconds since Jan 1970 and set the RTC registers - * based on this value. - */ -int rtc_set(struct rtc_time *tmp) -{ - unsigned long remain, days, hrs, mins, secs; - - pr_stamp(); - - if (tmp == NULL) { - puts("Error setting the date/time\n"); - return -1; - } - - rtc_init(); - wait_for_complete(); - - /* Calculate number of seconds this incoming time represents */ - remain = rtc_mktime(tmp); - - /* Figure out how many days since epoch */ - days = remain / NUM_SECS_IN_DAY; - - /* From the remaining secs, compute the hrs(0-23), mins(0-59) and secs(0-59) */ - remain = remain % NUM_SECS_IN_DAY; - hrs = remain / NUM_SECS_IN_HR; - remain = remain % NUM_SECS_IN_HR; - mins = remain / NUM_SECS_IN_MIN; - secs = remain % NUM_SECS_IN_MIN; - - /* Encode these time values into our RTC_STAT register */ - bfin_write_RTC_STAT(SET_ALARM(days, hrs, mins, secs)); - - return 0; -} - -/* Read the time from the RTC_STAT. time_in_seconds is seconds since Jan 1970 */ -int rtc_get(struct rtc_time *tmp) -{ - uint32_t cur_rtc_stat; - int time_in_sec; - int tm_sec, tm_min, tm_hr, tm_day; - - pr_stamp(); - - if (tmp == NULL) { - puts("Error getting the date/time\n"); - return -1; - } - - rtc_init(); - wait_for_complete(); - - /* Read the RTC_STAT register */ - cur_rtc_stat = bfin_read_RTC_STAT(); - - /* Convert our encoded format into actual time values */ - tm_sec = (cur_rtc_stat & RTC_SEC) >> RTC_SEC_P; - tm_min = (cur_rtc_stat & RTC_MIN) >> RTC_MIN_P; - tm_hr = (cur_rtc_stat & RTC_HR ) >> RTC_HR_P; - tm_day = (cur_rtc_stat & RTC_DAY) >> RTC_DAY_P; - - /* Calculate the total number of seconds since epoch */ - time_in_sec = (tm_sec) + MIN_TO_SECS(tm_min) + HRS_TO_SECS(tm_hr) + DAYS_TO_SECS(tm_day); - rtc_to_tm(time_in_sec, tmp); - - return 0; -} - -#endif diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index 3be1da68731..5df15c7fd6c 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -16,28 +16,16 @@ #include <common.h> #include <command.h> +#include <dm.h> #include <rtc.h> #include <i2c.h> -#if defined(CONFIG_CMD_DATE) - -/*---------------------------------------------------------------------*/ -#undef DEBUG_RTC - -#ifdef DEBUG_RTC -#define DEBUGR(fmt,args...) printf(fmt ,##args) -#else -#define DEBUGR(fmt,args...) -#endif -/*---------------------------------------------------------------------*/ - -#ifndef CONFIG_SYS_I2C_RTC_ADDR -# define CONFIG_SYS_I2C_RTC_ADDR 0x68 -#endif - -#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000) -# error The DS1307 is specified only up to 100kHz! -#endif +enum ds_type { + ds_1307, + ds_1337, + ds_1340, + mcp794xx, +}; /* * RTC register addresses @@ -62,6 +50,28 @@ #define MCP7941X_BIT_ST 0x80 #define MCP7941X_BIT_VBATEN 0x08 +#ifndef CONFIG_DM_RTC + +#if defined(CONFIG_CMD_DATE) + +/*---------------------------------------------------------------------*/ +#undef DEBUG_RTC + +#ifdef DEBUG_RTC +#define DEBUGR(fmt, args...) printf(fmt, ##args) +#else +#define DEBUGR(fmt, args...) +#endif +/*---------------------------------------------------------------------*/ + +#ifndef CONFIG_SYS_I2C_RTC_ADDR +# define CONFIG_SYS_I2C_RTC_ADDR 0x68 +#endif + +#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000) +# error The DS1307 is specified only up to 100kHz! +#endif + static uchar rtc_read (uchar reg); static void rtc_write (uchar reg, uchar val); @@ -211,4 +221,163 @@ static void rtc_write (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } -#endif + +#endif /* CONFIG_CMD_DATE*/ + +#endif /* !CONFIG_DM_RTC */ + +#ifdef CONFIG_DM_RTC +static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + int ret; + uchar buf[7]; + enum ds_type type = dev_get_driver_data(dev); + + debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + if (tm->tm_year < 1970 || tm->tm_year > 2069) + printf("WARNING: year should be between 1970 and 2069!\n"); + + buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100); + buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon); + buf[RTC_DAY_REG_ADDR] = bin2bcd(tm->tm_wday + 1); + buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday); + buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour); + buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min); + buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec); + + if (type == mcp794xx) { + buf[RTC_DAY_REG_ADDR] |= MCP7941X_BIT_VBATEN; + buf[RTC_SEC_REG_ADDR] |= MCP7941X_BIT_ST; + } + + ret = dm_i2c_write(dev, 0, buf, sizeof(buf)); + if (ret < 0) + return ret; + + return 0; +} + +static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + int ret; + uchar buf[7]; + enum ds_type type = dev_get_driver_data(dev); + +read_rtc: + ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); + if (ret < 0) + return ret; + + if (type == ds_1307) { + if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the CH flag */ + buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; + dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, + buf[RTC_SEC_REG_ADDR]); + return -1; + } + } + + if (type == mcp794xx) { + /* make sure that the backup battery is enabled */ + if (!(buf[RTC_DAY_REG_ADDR] & MCP7941X_BIT_VBATEN)) { + dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR, + buf[RTC_DAY_REG_ADDR] | + MCP7941X_BIT_VBATEN); + } + + /* clock halted? turn it on, so clock can tick. */ + if (!(buf[RTC_SEC_REG_ADDR] & MCP7941X_BIT_ST)) { + dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, + MCP7941X_BIT_ST); + printf("Started RTC\n"); + goto read_rtc; + } + } + + tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F); + tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F); + tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F); + tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F); + tm->tm_mon = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F); + tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + + (bcd2bin(buf[RTC_YR_REG_ADDR]) >= 70 ? + 1900 : 2000); + tm->tm_wday = bcd2bin((buf[RTC_DAY_REG_ADDR] - 1) & 0x07); + tm->tm_yday = 0; + tm->tm_isdst = 0; + + debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int ds1307_rtc_reset(struct udevice *dev) +{ + int ret; + struct rtc_time tmp = { + .tm_year = 1970, + .tm_mon = 1, + .tm_mday = 1, + .tm_hour = 0, + .tm_min = 0, + .tm_sec = 0, + }; + + /* clear Clock Halt */ + ret = dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, 0x00); + if (ret < 0) + return ret; + ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, + RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | + RTC_CTL_BIT_RS0); + if (ret < 0) + return ret; + + ret = ds1307_rtc_set(dev, &tmp); + if (ret < 0) + return ret; + + debug("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n", + tmp.tm_year, tmp.tm_mon, tmp.tm_mday, + tmp.tm_hour, tmp.tm_min, tmp.tm_sec); + + return 0; +} + +static int ds1307_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + return 0; +} + +static const struct rtc_ops ds1307_rtc_ops = { + .get = ds1307_rtc_get, + .set = ds1307_rtc_set, + .reset = ds1307_rtc_reset, +}; + +static const struct udevice_id ds1307_rtc_ids[] = { + { .compatible = "dallas,ds1307", .data = ds_1307 }, + { .compatible = "dallas,ds1337", .data = ds_1337 }, + { .compatible = "dallas,ds1340", .data = ds_1340 }, + { .compatible = "microchip,mcp7941x", .data = mcp794xx }, + { } +}; + +U_BOOT_DRIVER(rtc_ds1307) = { + .name = "rtc-ds1307", + .id = UCLASS_RTC, + .probe = ds1307_probe, + .of_match = ds1307_rtc_ids, + .ops = &ds1307_rtc_ops, +}; +#endif /* CONFIG_DM_RTC */ |