diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Makefile | 72 | ||||
-rw-r--r-- | drivers/rtc/bf5xx_rtc.c | 143 | ||||
-rw-r--r-- | drivers/rtc/date.c | 156 | ||||
-rw-r--r-- | drivers/rtc/ds12887.c | 238 | ||||
-rw-r--r-- | drivers/rtc/ds1302.c | 327 | ||||
-rw-r--r-- | drivers/rtc/ds1306.c | 438 | ||||
-rw-r--r-- | drivers/rtc/ds1307.c | 204 | ||||
-rw-r--r-- | drivers/rtc/ds1337.c | 191 | ||||
-rw-r--r-- | drivers/rtc/ds1374.c | 253 | ||||
-rw-r--r-- | drivers/rtc/ds1556.c | 206 | ||||
-rw-r--r-- | drivers/rtc/ds164x.c | 200 | ||||
-rw-r--r-- | drivers/rtc/ds174x.c | 202 | ||||
-rw-r--r-- | drivers/rtc/ds3231.c | 193 | ||||
-rw-r--r-- | drivers/rtc/m41t11.c | 202 | ||||
-rw-r--r-- | drivers/rtc/m41t60.c | 261 | ||||
-rw-r--r-- | drivers/rtc/m48t35ax.c | 166 | ||||
-rw-r--r-- | drivers/rtc/max6900.c | 131 | ||||
-rw-r--r-- | drivers/rtc/mc146818.c | 178 | ||||
-rw-r--r-- | drivers/rtc/mcfrtc.c | 121 | ||||
-rw-r--r-- | drivers/rtc/mk48t59.c | 237 | ||||
-rw-r--r-- | drivers/rtc/mpc5xxx.c | 140 | ||||
-rw-r--r-- | drivers/rtc/mpc8xx.c | 73 | ||||
-rw-r--r-- | drivers/rtc/pcf8563.c | 144 | ||||
-rw-r--r-- | drivers/rtc/rs5c372.c | 302 | ||||
-rw-r--r-- | drivers/rtc/s3c24x0_rtc.c | 178 | ||||
-rw-r--r-- | drivers/rtc/x1205.c | 178 |
26 files changed, 5134 insertions, 0 deletions
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile new file mode 100644 index 0000000..e5ee611 --- /dev/null +++ b/drivers/rtc/Makefile @@ -0,0 +1,72 @@ +# +# (C) Copyright 2001-2006 +# 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 +# + +include $(TOPDIR)/config.mk + +#CFLAGS += -DDEBUG + +LIB = $(obj)librtc.a + +COBJS-y += date.o +COBJS-y += bf5xx_rtc.o +COBJS-y += ds12887.o +COBJS-y += ds1302.o +COBJS-y += ds1306.o +COBJS-y += ds1307.o +COBJS-y += ds1337.o +COBJS-y += ds1374.o +COBJS-y += ds1556.o +COBJS-y += ds164x.o +COBJS-y += ds174x.o +COBJS-y += ds3231.o +COBJS-y += m41t11.o +COBJS-y += m41t60.o +COBJS-y += max6900.o +COBJS-y += m48t35ax.o +COBJS-y += mc146818.o +COBJS-y += mk48t59.o +COBJS-y += mpc5xxx.o +COBJS-y += mpc8xx.o +COBJS-y += pcf8563.o +COBJS-y += s3c24x0_rtc.o +COBJS-y += rs5c372.o +COBJS-y += mcfrtc.o +COBJS-y += x1205.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/rtc/bf5xx_rtc.c b/drivers/rtc/bf5xx_rtc.c new file mode 100644 index 0000000..8856bb9 --- /dev/null +++ b/drivers/rtc/bf5xx_rtc.c @@ -0,0 +1,143 @@ +/* + * (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 + * Real Time Clock interface of ADI21535 (Blackfin) for uCLinux + * + * Copyright (C) 2003 Motorola Corporation. All rights reserved. + * Richard Xiao (A2590C@email.mot.com) + * + * Copyright (C) 1996 Paul Gortmaker + * + * + * Based on other minimal char device drivers, like Alan's + * watchdog, Ted's random, etc. etc. + * + * 1.07 Paul Gortmaker. + * 1.08 Miquel van Smoorenburg: disallow certain things on the + * DEC Alpha as the CMOS clock is also used for other things. + * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. + * 1.09a Pete Zaitcev: Sun SPARC + * 1.09b Jeff Garzik: Modularize, init cleanup + * 1.09c Jeff Garzik: SMP cleanup + * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10a Andrea Arcangeli: Alpha updates + * 1.10b Andrew Morton: SMP lock fix + * 1.10c Cesar Barros: SMP locking fixes and cleanup + * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit + * 1.10e LG Soft India: Register access is different in BF533. + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> + +#if defined(CONFIG_RTC_BFIN) && defined(CONFIG_CMD_DATE) + +#include <asm/blackfin.h> +#include <asm/arch/bf5xx_rtc.h> + +void rtc_reset(void) +{ + return; /* nothing to do */ +} + +/* Wait for pending writes to complete */ +void wait_for_complete(void) +{ + while (!(*(volatile unsigned short *)RTC_ISTAT & 0x8000)) { + printf(""); + } + *(volatile unsigned short *)RTC_ISTAT = 0x8000; +} + +/* Enable the RTC prescaler enable register */ +void rtc_init() +{ + *(volatile unsigned short *)RTC_PREN = 0x1; + wait_for_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. + */ +void rtc_set(struct rtc_time *tmp) +{ + unsigned long n_days_1970 = 0; + unsigned long n_secs_rem = 0; + unsigned long n_hrs = 0; + unsigned long n_mins = 0; + unsigned long n_secs = 0; + unsigned long time_in_secs; + + if (tmp == NULL) { + printf("Error setting the date/time \n"); + return; + } + + time_in_secs = + mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour, + tmp->tm_min, tmp->tm_sec); + + /* Compute no. of days since 1970 */ + n_days_1970 = (unsigned long)(time_in_secs / (NUM_SECS_IN_DAY)); + + /* From the remining secs, compute the hrs(0-23), mins(0-59) and secs(0-59) */ + n_secs_rem = (unsigned long)(time_in_secs % (NUM_SECS_IN_DAY)); + n_hrs = n_secs_rem / (NUM_SECS_IN_HOUR); + n_secs_rem = n_secs_rem % (NUM_SECS_IN_HOUR); + n_mins = n_secs_rem / (NUM_SECS_IN_MIN); + n_secs = n_secs_rem % (NUM_SECS_IN_MIN); + + /* Store the new time in the RTC_STAT register */ + *(volatile unsigned long *)RTC_STAT = + ((n_days_1970 << DAY_BITS_OFF) | (n_hrs << HOUR_BITS_OFF) | + (n_mins << MIN_BITS_OFF) | (n_secs << SEC_BITS_OFF)); + + wait_for_complete(); +} + +/* Read the time from the RTC_STAT. time_in_seconds is seconds since Jan 1970 */ +void rtc_get(struct rtc_time *tmp) +{ + unsigned long cur_rtc_stat = 0; + unsigned long time_in_sec; + unsigned long tm_sec = 0, tm_min = 0, tm_hour = 0, tm_day = 0; + + if (tmp == NULL) { + printf("Error getting the date/time \n"); + return; + } + + /* Read the RTC_STAT register */ + cur_rtc_stat = *(volatile unsigned long *)RTC_STAT; + + /* Get the secs (0-59), mins (0-59), hrs (0-23) and the days since Jan 1970 */ + tm_sec = (cur_rtc_stat >> SEC_BITS_OFF) & 0x3f; + tm_min = (cur_rtc_stat >> MIN_BITS_OFF) & 0x3f; + tm_hour = (cur_rtc_stat >> HOUR_BITS_OFF) & 0x1f; + tm_day = (cur_rtc_stat >> DAY_BITS_OFF) & 0x7fff; + + /* Calculate the total number of seconds since Jan 1970 */ + time_in_sec = (tm_sec) + + MIN_TO_SECS(tm_min) + HRS_TO_SECS(tm_hour) + DAYS_TO_SECS(tm_day); + to_tm(time_in_sec, tmp); +} +#endif diff --git a/drivers/rtc/date.c b/drivers/rtc/date.c new file mode 100644 index 0000000..a83a723 --- /dev/null +++ b/drivers/rtc/date.c @@ -0,0 +1,156 @@ +/* + * (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 Philips PCF8563 RTC + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> + +#if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP) + +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) +#define leapyear(year) ((year) % 4 == 0) +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +void GregorianDay(struct rtc_time * tm) +{ + int leapsToDate; + int lastYear; + int day; + int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 }; + + lastYear=tm->tm_year-1; + + /* + * Number of leap corrections to apply up to end of last year + */ + leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; + + /* + * This year is a leap year if it is divisible by 4 except when it is + * divisible by 100 unless it is divisible by 400 + * + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be + */ + if((tm->tm_year%4==0) && + ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && + (tm->tm_mon>2)) { + /* + * We are past Feb. 29 in a leap year + */ + day=1; + } else { + day=0; + } + + day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; + + tm->tm_wday=day%7; +} + +void to_tm(int tim, struct rtc_time * tm) +{ + register int i; + register long hms, day; + + day = tim / SECDAY; + hms = tim % SECDAY; + + /* Hours, minutes, seconds are easy */ + tm->tm_hour = hms / 3600; + tm->tm_min = (hms % 3600) / 60; + tm->tm_sec = (hms % 3600) % 60; + + /* Number of years in days */ + for (i = STARTOFTIME; day >= days_in_year(i); i++) { + day -= days_in_year(i); + } + tm->tm_year = i; + + /* Number of months in days left */ + if (leapyear(tm->tm_year)) { + days_in_month(FEBRUARY) = 29; + } + for (i = 1; day >= days_in_month(i); i++) { + day -= days_in_month(i); + } + days_in_month(FEBRUARY) = 28; + tm->tm_mon = i; + + /* Days are what is left over (+1) from all that. */ + tm->tm_mday = day + 1; + + /* + * Determine the day of week + */ + GregorianDay(tm); +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +unsigned long +mktime (unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + + return ((( + (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +#endif diff --git a/drivers/rtc/ds12887.c b/drivers/rtc/ds12887.c new file mode 100644 index 0000000..84fecf0 --- /dev/null +++ b/drivers/rtc/ds12887.c @@ -0,0 +1,238 @@ +/* + * (C) Copyright 2003 + * + * 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 the DS12887 RTC + */ + +#undef RTC_DEBUG + +#include <common.h> +#include <command.h> +#include <config.h> +#include <rtc.h> + +#if defined(CONFIG_RTC_DS12887) && defined(CONFIG_CMD_DATE) + +#define RTC_SECONDS 0x00 +#define RTC_SECONDS_ALARM 0x01 +#define RTC_MINUTES 0x02 +#define RTC_MINUTES_ALARM 0x03 +#define RTC_HOURS 0x04 +#define RTC_HOURS_ALARM 0x05 +#define RTC_DAY_OF_WEEK 0x06 +#define RTC_DATE_OF_MONTH 0x07 +#define RTC_MONTH 0x08 +#define RTC_YEAR 0x09 +#define RTC_CONTROL_A 0x0A +#define RTC_CONTROL_B 0x0B +#define RTC_CONTROL_C 0x0C +#define RTC_CONTROL_D 0x0D + +#define RTC_CA_UIP 0x80 +#define RTC_CB_DM 0x04 +#define RTC_CB_24_12 0x02 +#define RTC_CB_SET 0x80 + +#if defined(CONFIG_ATC) + +static uchar rtc_read (uchar reg) +{ + uchar val; + + *(volatile unsigned char*)(RTC_PORT_ADDR) = reg; + __asm__ __volatile__ ("sync"); + + val = *(volatile unsigned char*)(RTC_PORT_DATA); + return (val); +} + +static void rtc_write (uchar reg, uchar val) +{ + *(volatile unsigned char*)(RTC_PORT_ADDR) = reg; + __asm__ __volatile__ ("sync"); + + *(volatile unsigned char*)(RTC_PORT_DATA) = val; + __asm__ __volatile__ ("sync"); +} + +#else +# error Board specific rtc access functions should be supplied +#endif + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon, year; + + /* check if rtc is available for access */ + while( rtc_read(RTC_CONTROL_A) & RTC_CA_UIP) + ; + + sec = rtc_read(RTC_SECONDS); + min = rtc_read(RTC_MINUTES); + hour = rtc_read(RTC_HOURS); + mday = rtc_read(RTC_DATE_OF_MONTH); + wday = rtc_read(RTC_DAY_OF_WEEK); + mon = rtc_read(RTC_MONTH); + year = rtc_read(RTC_YEAR); + +#ifdef RTC_DEBUG + printf( "Get RTC year: %d; mon: %d; mday: %d; wday: %d; " + "hr: %d; min: %d; sec: %d\n", + year, mon, mday, wday, hour, min, sec ); + + printf ( "Alarms: hour: %02x min: %02x sec: %02x\n", + rtc_read (RTC_HOURS_ALARM), + rtc_read (RTC_MINUTES_ALARM), + rtc_read (RTC_SECONDS_ALARM) ); +#endif + + if( !(rtc_read(RTC_CONTROL_B) & RTC_CB_DM)) + { /* Information is in BCD format */ +printf(" Get: Convert BSD to BIN\n"); + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon & 0x1F); + tmp->tm_year = bcd2bin (year); + tmp->tm_wday = bcd2bin (wday & 0x07); + } +else + { + tmp->tm_sec = sec & 0x7F; + tmp->tm_min = min & 0x7F; + tmp->tm_hour = hour & 0x3F; + tmp->tm_mday = mday & 0x3F; + tmp->tm_mon = mon & 0x1F; + tmp->tm_year = year; + tmp->tm_wday = wday & 0x07; + } + + + if(tmp->tm_year<70) + tmp->tm_year+=2000; + else + tmp->tm_year+=1900; + + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf ( "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); +#endif +} + +void rtc_set (struct rtc_time *tmp) +{ + uchar save_ctrl_b; + uchar sec, min, hour, mday, wday, mon, year; + +#ifdef RTC_DEBUG + printf ( "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); +#endif + + if( !(rtc_read(RTC_CONTROL_B) & RTC_CB_DM)) + { /* Information is in BCD format */ + year = bin2bcd(tmp->tm_year % 100); + mon = bin2bcd(tmp->tm_mon); + wday = bin2bcd(tmp->tm_wday); + mday = bin2bcd(tmp->tm_mday); + hour = bin2bcd(tmp->tm_hour); + min = bin2bcd(tmp->tm_min); + sec = bin2bcd(tmp->tm_sec); + } + else + { + year = tmp->tm_year % 100; + mon = tmp->tm_mon; + wday = tmp->tm_wday; + mday = tmp->tm_mday; + hour = tmp->tm_hour; + min = tmp->tm_min; + sec = tmp->tm_sec; + } + + /* disables the RTC to update the regs */ + save_ctrl_b = rtc_read(RTC_CONTROL_B); + save_ctrl_b |= RTC_CB_SET; + rtc_write(RTC_CONTROL_B, save_ctrl_b); + + rtc_write (RTC_YEAR, year); + rtc_write (RTC_MONTH, mon); + rtc_write (RTC_DAY_OF_WEEK, wday); + rtc_write (RTC_DATE_OF_MONTH, mday); + rtc_write (RTC_HOURS, hour); + rtc_write (RTC_MINUTES, min); + rtc_write (RTC_SECONDS, sec); + + /* enables the RTC to update the regs */ + save_ctrl_b &= ~RTC_CB_SET; + rtc_write(RTC_CONTROL_B, save_ctrl_b); +} + +void rtc_reset (void) +{ + struct rtc_time tmp; + uchar ctrl_rg; + + ctrl_rg = RTC_CB_SET; + rtc_write(RTC_CONTROL_B,ctrl_rg); + + tmp.tm_year = 1970 % 100; + tmp.tm_mon = 1; + tmp.tm_mday= 1; + tmp.tm_hour = 0; + tmp.tm_min = 0; + tmp.tm_sec = 0; + +#ifdef RTC_DEBUG + printf ( "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); +#endif + + ctrl_rg = RTC_CB_SET | RTC_CB_24_12 | RTC_CB_DM; + rtc_write(RTC_CONTROL_B,ctrl_rg); + rtc_set(&tmp); + + rtc_write(RTC_HOURS_ALARM, 0), + rtc_write(RTC_MINUTES_ALARM, 0), + rtc_write(RTC_SECONDS_ALARM, 0); + + ctrl_rg = RTC_CB_24_12 | RTC_CB_DM; + rtc_write(RTC_CONTROL_B,ctrl_rg); +} + +#endif diff --git a/drivers/rtc/ds1302.c b/drivers/rtc/ds1302.c new file mode 100644 index 0000000..55af130 --- /dev/null +++ b/drivers/rtc/ds1302.c @@ -0,0 +1,327 @@ +/* + * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip + * + * Rex G. Feany <rfeany@zumanetworks.com> + * + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> + +#if defined(CONFIG_RTC_DS1302) && defined(CONFIG_CMD_DATE) + +/* GPP Pins */ +#define DATA 0x200 +#define SCLK 0x400 +#define RST 0x800 + +/* Happy Fun Defines(tm) */ +#define RESET rtc_go_low(RST), rtc_go_low(SCLK) +#define N_RESET rtc_go_high(RST), rtc_go_low(SCLK) + +#define CLOCK_HIGH rtc_go_high(SCLK) +#define CLOCK_LOW rtc_go_low(SCLK) + +#define DATA_HIGH rtc_go_high(DATA) +#define DATA_LOW rtc_go_low(DATA) +#define DATA_READ (GTREGREAD(GPP_VALUE) & DATA) + +#undef RTC_DEBUG + +#ifdef RTC_DEBUG +# define DPRINTF(x,args...) printf("ds1302: " x , ##args) +static inline void DUMP(const char *ptr, int num) +{ + while (num--) printf("%x ", *ptr++); + printf("]\n"); +} +#else +# define DPRINTF(x,args...) +# define DUMP(ptr, num) +#endif + +/* time data format for DS1302 */ +struct ds1302_st +{ + unsigned char CH:1; /* clock halt 1=stop 0=start */ + unsigned char sec10:3; + unsigned char sec:4; + + unsigned char zero0:1; + unsigned char min10:3; + unsigned char min:4; + + unsigned char fmt:1; /* 1=12 hour 0=24 hour */ + unsigned char zero1:1; + unsigned char hr10:2; /* 10 (0-2) or am/pm (am/pm, 0-1) */ + unsigned char hr:4; + + unsigned char zero2:2; + unsigned char date10:2; + unsigned char date:4; + + unsigned char zero3:3; + unsigned char month10:1; + unsigned char month:4; + + unsigned char zero4:5; + unsigned char day:3; /* day of week */ + + unsigned char year10:4; + unsigned char year:4; + + unsigned char WP:1; /* write protect 1=protect 0=unprot */ + unsigned char zero5:7; +}; + +static int ds1302_initted=0; + +/* Pin control */ +static inline void +rtc_go_high(unsigned int mask) +{ + unsigned int f = GTREGREAD(GPP_VALUE) | mask; + + GT_REG_WRITE(GPP_VALUE, f); +} + +static inline void +rtc_go_low(unsigned int mask) +{ + unsigned int f = GTREGREAD(GPP_VALUE) & ~mask; + + GT_REG_WRITE(GPP_VALUE, f); +} + +static inline void +rtc_go_input(unsigned int mask) +{ + unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask; + + GT_REG_WRITE(GPP_IO_CONTROL, f); +} + +static inline void +rtc_go_output(unsigned int mask) +{ + unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask; + + GT_REG_WRITE(GPP_IO_CONTROL, f); +} + +/* Access data in RTC */ + +static void +write_byte(unsigned char b) +{ + int i; + unsigned char mask=1; + + for(i=0;i<8;i++) { + CLOCK_LOW; /* Lower clock */ + (b&mask)?DATA_HIGH:DATA_LOW; /* set data */ + udelay(1); + CLOCK_HIGH; /* latch data with rising clock */ + udelay(1); + mask=mask<<1; + } +} + +static unsigned char +read_byte(void) +{ + int i; + unsigned char mask=1; + unsigned char b=0; + + for(i=0;i<8;i++) { + CLOCK_LOW; + udelay(1); + if (DATA_READ) b|=mask; /* if this bit is high, set in b */ + CLOCK_HIGH; /* clock out next bit */ + udelay(1); + mask=mask<<1; + } + return b; +} + +static void +read_ser_drv(unsigned char addr, unsigned char *buf, int count) +{ + int i; +#ifdef RTC_DEBUG + char *foo = buf; +#endif + + DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr); + + addr|=1; /* READ */ + N_RESET; + udelay(4); + write_byte(addr); + rtc_go_input(DATA); /* Put gpp pin into input mode */ + udelay(1); + for(i=0;i<count;i++) *(buf++)=read_byte(); + RESET; + rtc_go_output(DATA);/* Reset gpp for output */ + udelay(4); + + DUMP(foo, count); +} + +static void +write_ser_drv(unsigned char addr, unsigned char *buf, int count) +{ + int i; + + DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr); + DUMP(buf, count); + + addr&=~1; /* WRITE */ + N_RESET; + udelay(4); + write_byte(addr); + for(i=0;i<count;i++) write_byte(*(buf++)); + RESET; + udelay(4); + +} + +void +rtc_init(void) +{ + struct ds1302_st bbclk; + unsigned char b; + int mod; + + DPRINTF("init\n"); + + rtc_go_output(DATA|SCLK|RST); + + /* disable write protect */ + b = 0; + write_ser_drv(0x8e,&b,1); + + /* enable trickle */ + b = 0xa5; /* 1010.0101 */ + write_ser_drv(0x90,&b,1); + + /* read burst */ + read_ser_drv(0xbe, (unsigned char *)&bbclk, 8); + + /* Sanity checks */ + mod = 0; + if (bbclk.CH) { + printf("ds1302: Clock was halted, starting clock\n"); + bbclk.CH=0; + mod=1; + } + + if (bbclk.fmt) { + printf("ds1302: Clock was in 12 hour mode, fixing\n"); + bbclk.fmt=0; + mod=1; + } + + if (bbclk.year>9) { + printf("ds1302: Year was corrupted, fixing\n"); + bbclk.year10=100/10; /* 2000 - why not? ;) */ + bbclk.year=0; + mod=1; + } + + /* Write out the changes if needed */ + if (mod) { + /* enable write protect */ + bbclk.WP = 1; + write_ser_drv(0xbe,(unsigned char *)&bbclk,8); + } else { + /* Else just turn write protect on */ + b = 0x80; + write_ser_drv(0x8e,&b,1); + } + DPRINTF("init done\n"); + + ds1302_initted=1; +} + +void +rtc_reset(void) +{ + if(!ds1302_initted) rtc_init(); + /* TODO */ +} + +void +rtc_get(struct rtc_time *tmp) +{ + struct ds1302_st bbclk; + + if(!ds1302_initted) rtc_init(); + + read_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* read burst */ + + if (bbclk.CH) { + printf("ds1302: rtc_get: Clock was halted, clock probably " + "corrupt\n"); + } + + tmp->tm_sec=10*bbclk.sec10+bbclk.sec; + tmp->tm_min=10*bbclk.min10+bbclk.min; + tmp->tm_hour=10*bbclk.hr10+bbclk.hr; + tmp->tm_wday=bbclk.day; + tmp->tm_mday=10*bbclk.date10+bbclk.date; + tmp->tm_mon=10*bbclk.month10+bbclk.month; + tmp->tm_year=10*bbclk.year10+bbclk.year + 1900; + + tmp->tm_yday = 0; + tmp->tm_isdst= 0; + + DPRINTF("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 ); +} + +void +rtc_set(struct rtc_time *tmp) +{ + struct ds1302_st bbclk; + unsigned char b=0; + + if(!ds1302_initted) rtc_init(); + + DPRINTF("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); + + memset(&bbclk,0,sizeof(bbclk)); + bbclk.CH=0; /* dont halt */ + bbclk.WP=1; /* write protect when we're done */ + + bbclk.sec10=tmp->tm_sec/10; + bbclk.sec=tmp->tm_sec%10; + + bbclk.min10=tmp->tm_min/10; + bbclk.min=tmp->tm_min%10; + + bbclk.hr10=tmp->tm_hour/10; + bbclk.hr=tmp->tm_hour%10; + + bbclk.day=tmp->tm_wday; + + bbclk.date10=tmp->tm_mday/10; + bbclk.date=tmp->tm_mday%10; + + bbclk.month10=tmp->tm_mon/10; + bbclk.month=tmp->tm_mon%10; + + tmp->tm_year -= 1900; + bbclk.year10=tmp->tm_year/10; + bbclk.year=tmp->tm_year%10; + + write_ser_drv(0x8e,&b,1); /* disable write protect */ + write_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* write burst */ +} + +#endif diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c new file mode 100644 index 0000000..89e433d --- /dev/null +++ b/drivers/rtc/ds1306.c @@ -0,0 +1,438 @@ +/* + * (C) Copyright 2002 SIXNET, dge@sixnetio.com. + * + * (C) Copyright 2004, Li-Pro.Net <www.li-pro.net> + * Stephan Linz <linz@li-pro.net> + * + * 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 DS1306 RTC using SPI: + * + * - SXNI855T: it uses its own soft SPI here in this file + * - all other: use the external spi_xfer() function + * (see include/spi.h) + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <spi.h> + +#if defined(CONFIG_RTC_DS1306) && defined(CONFIG_CMD_DATE) + +#define RTC_SECONDS 0x00 +#define RTC_MINUTES 0x01 +#define RTC_HOURS 0x02 +#define RTC_DAY_OF_WEEK 0x03 +#define RTC_DATE_OF_MONTH 0x04 +#define RTC_MONTH 0x05 +#define RTC_YEAR 0x06 + +#define RTC_SECONDS_ALARM0 0x07 +#define RTC_MINUTES_ALARM0 0x08 +#define RTC_HOURS_ALARM0 0x09 +#define RTC_DAY_OF_WEEK_ALARM0 0x0a + +#define RTC_SECONDS_ALARM1 0x0b +#define RTC_MINUTES_ALARM1 0x0c +#define RTC_HOURS_ALARM1 0x0d +#define RTC_DAY_OF_WEEK_ALARM1 0x0e + +#define RTC_CONTROL 0x0f +#define RTC_STATUS 0x10 +#define RTC_TRICKLE_CHARGER 0x11 + +#define RTC_USER_RAM_BASE 0x20 + +/* + * External table of chip select functions (see the appropriate board + * support for the actual definition of the table). + */ +extern spi_chipsel_type spi_chipsel[]; +extern int spi_chipsel_cnt; + +static unsigned int bin2bcd (unsigned int n); +static unsigned char bcd2bin (unsigned char c); + +/* ************************************************************************* */ +#ifdef CONFIG_SXNI855T /* !!! SHOULD BE CHANGED TO NEW CODE !!! */ + +static void soft_spi_send (unsigned char n); +static unsigned char soft_spi_read (void); +static void init_spi (void); + +/*----------------------------------------------------------------------- + * Definitions + */ + +#define PB_SPISCK 0x00000002 /* PB 30 */ +#define PB_SPIMOSI 0x00000004 /* PB 29 */ +#define PB_SPIMISO 0x00000008 /* PB 28 */ +#define PB_SPI_CE 0x00010000 /* PB 15 */ + +/* ------------------------------------------------------------------------- */ + +/* read clock time from DS1306 and return it in *tmp */ +void rtc_get (struct rtc_time *tmp) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + unsigned char spi_byte; /* Data Byte */ + + init_spi (); /* set port B for software SPI */ + + /* Now we can enable the DS1306 RTC */ + immap->im_cpm.cp_pbdat |= PB_SPI_CE; + udelay (10); + + /* Shift out the address (0) of the time in the Clock Chip */ + soft_spi_send (0); + + /* Put the clock readings into the rtc_time structure */ + tmp->tm_sec = bcd2bin (soft_spi_read ()); /* Read seconds */ + tmp->tm_min = bcd2bin (soft_spi_read ()); /* Read minutes */ + + /* Hours are trickier */ + spi_byte = soft_spi_read (); /* Read Hours into temporary value */ + if (spi_byte & 0x40) { + /* 12 hour mode bit is set (time is in 1-12 format) */ + if (spi_byte & 0x20) { + /* since PM we add 11 to get 0-23 for hours */ + tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) + 11; + } else { + /* since AM we subtract 1 to get 0-23 for hours */ + tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) - 1; + } + } else { + /* Otherwise, 0-23 hour format */ + tmp->tm_hour = (bcd2bin (spi_byte & 0x3F)); + } + + soft_spi_read (); /* Read and discard Day of week */ + tmp->tm_mday = bcd2bin (soft_spi_read ()); /* Read Day of the Month */ + tmp->tm_mon = bcd2bin (soft_spi_read ()); /* Read Month */ + + /* Read Year and convert to this century */ + tmp->tm_year = bcd2bin (soft_spi_read ()) + 2000; + + /* Now we can disable the DS1306 RTC */ + immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */ + udelay (10); + + GregorianDay (tmp); /* Determine the day of week */ + + 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); +} + +/* ------------------------------------------------------------------------- */ + +/* set clock time in DS1306 RTC and in MPC8xx RTC */ +void rtc_set (struct rtc_time *tmp) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + + init_spi (); /* set port B for software SPI */ + + /* Now we can enable the DS1306 RTC */ + immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */ + udelay (10); + + /* First disable write protect in the clock chip control register */ + soft_spi_send (0x8F); /* send address of the control register */ + soft_spi_send (0x00); /* send control register contents */ + + /* Now disable the DS1306 to terminate the write */ + immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; + udelay (10); + + /* Now enable the DS1306 to initiate a new write */ + immap->im_cpm.cp_pbdat |= PB_SPI_CE; + udelay (10); + + /* Next, send the address of the clock time write registers */ + soft_spi_send (0x80); /* send address of the first time register */ + + /* Use Burst Mode to send all of the time data to the clock */ + bin2bcd (tmp->tm_sec); + soft_spi_send (bin2bcd (tmp->tm_sec)); /* Send Seconds */ + soft_spi_send (bin2bcd (tmp->tm_min)); /* Send Minutes */ + soft_spi_send (bin2bcd (tmp->tm_hour)); /* Send Hour */ + soft_spi_send (bin2bcd (tmp->tm_wday)); /* Send Day of the Week */ + soft_spi_send (bin2bcd (tmp->tm_mday)); /* Send Day of Month */ + soft_spi_send (bin2bcd (tmp->tm_mon)); /* Send Month */ + soft_spi_send (bin2bcd (tmp->tm_year - 2000)); /* Send Year */ + + /* Now we can disable the Clock chip to terminate the burst write */ + immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */ + udelay (10); + + /* Now we can enable the Clock chip to initiate a new write */ + immap->im_cpm.cp_pbdat |= PB_SPI_CE; /* Enable DS1306 Chip */ + udelay (10); + + /* First we Enable write protect in the clock chip control register */ + soft_spi_send (0x8F); /* send address of the control register */ + soft_spi_send (0x40); /* send out Control Register contents */ + + /* Now disable the DS1306 */ + immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */ + udelay (10); + + /* Set standard MPC8xx clock to the same time so Linux will + * see the time even if it doesn't have a DS1306 clock driver. + * This helps with experimenting with standard kernels. + */ + { + ulong tim; + + tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + immap->im_sitk.sitk_rtck = KAPWR_KEY; + immap->im_sit.sit_rtc = tim; + } + + 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); +} + +/* ------------------------------------------------------------------------- */ + +/* Initialize Port B for software SPI */ +static void init_spi (void) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + + /* Force output pins to begin at logic 0 */ + immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK); + + /* Set these 3 signals as outputs */ + immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK); + + immap->im_cpm.cp_pbdir &= ~PB_SPIMISO; /* Make MISO pin an input */ + udelay (10); +} + +/* ------------------------------------------------------------------------- */ + +/* NOTE: soft_spi_send() assumes that the I/O lines are configured already */ +static void soft_spi_send (unsigned char n) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + unsigned char bitpos; /* bit position to receive */ + unsigned char i; /* Loop Control */ + + /* bit position to send, start with most significant bit */ + bitpos = 0x80; + + /* Send 8 bits to software SPI */ + for (i = 0; i < 8; i++) { /* Loop for 8 bits */ + immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */ + + if (n & bitpos) + immap->im_cpm.cp_pbdat |= PB_SPIMOSI; /* Set MOSI to 1 */ + else + immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI; /* Set MOSI to 0 */ + udelay (10); + + immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */ + udelay (10); + + bitpos >>= 1; /* Shift for next bit position */ + } +} + +/* ------------------------------------------------------------------------- */ + +/* NOTE: soft_spi_read() assumes that the I/O lines are configured already */ +static unsigned char soft_spi_read (void) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + + unsigned char spi_byte = 0; /* Return value, assume success */ + unsigned char bitpos; /* bit position to receive */ + unsigned char i; /* Loop Control */ + + /* bit position to receive, start with most significant bit */ + bitpos = 0x80; + + /* Read 8 bits here */ + for (i = 0; i < 8; i++) { /* Do 8 bits in loop */ + immap->im_cpm.cp_pbdat |= PB_SPISCK; /* Raise SCK */ + udelay (10); + if (immap->im_cpm.cp_pbdat & PB_SPIMISO) /* Get a bit of data */ + spi_byte |= bitpos; /* Set data accordingly */ + immap->im_cpm.cp_pbdat &= ~PB_SPISCK; /* Lower SCK */ + udelay (10); + bitpos >>= 1; /* Shift for next bit position */ + } + + return spi_byte; /* Return the byte read */ +} + +/* ------------------------------------------------------------------------- */ + +void rtc_reset (void) +{ + return; /* nothing to do */ +} + +#else /* not CONFIG_SXNI855T */ +/* ************************************************************************* */ + +static unsigned char rtc_read (unsigned char reg); +static void rtc_write (unsigned char reg, unsigned char val); + +/* read clock time from DS1306 and return it in *tmp */ +void rtc_get (struct rtc_time *tmp) +{ + unsigned char sec, min, hour, mday, wday, mon, year; + + sec = rtc_read (RTC_SECONDS); + min = rtc_read (RTC_MINUTES); + hour = rtc_read (RTC_HOURS); + mday = rtc_read (RTC_DATE_OF_MONTH); + wday = rtc_read (RTC_DAY_OF_WEEK); + mon = rtc_read (RTC_MONTH); + year = rtc_read (RTC_YEAR); + + debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, hour, min, sec); + debug ("Alarms[0]: wday: %02x hour: %02x min: %02x sec: %02x\n", + rtc_read (RTC_DAY_OF_WEEK_ALARM0), + rtc_read (RTC_HOURS_ALARM0), + rtc_read (RTC_MINUTES_ALARM0), rtc_read (RTC_SECONDS_ALARM0)); + debug ("Alarms[1]: wday: %02x hour: %02x min: %02x sec: %02x\n", + rtc_read (RTC_DAY_OF_WEEK_ALARM1), + rtc_read (RTC_HOURS_ALARM1), + rtc_read (RTC_MINUTES_ALARM1), rtc_read (RTC_SECONDS_ALARM1)); + + tmp->tm_sec = bcd2bin (sec & 0x7F); /* convert Seconds */ + tmp->tm_min = bcd2bin (min & 0x7F); /* convert Minutes */ + + /* convert Hours */ + tmp->tm_hour = (hour & 0x40) + ? ((hour & 0x20) /* 12 hour mode */ + ? bcd2bin (hour & 0x1F) + 11 /* PM */ + : bcd2bin (hour & 0x1F) - 1 /* AM */ + ) + : bcd2bin (hour & 0x3F); /* 24 hour mode */ + + tmp->tm_mday = bcd2bin (mday & 0x3F); /* convert Day of the Month */ + tmp->tm_mon = bcd2bin (mon & 0x1F); /* convert Month */ + tmp->tm_year = bcd2bin (year) + 2000; /* convert Year */ + tmp->tm_wday = bcd2bin (wday & 0x07) - 1; /* convert Day of the Week */ + 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); +} + +/* ------------------------------------------------------------------------- */ + +/* set clock time from *tmp in DS1306 RTC */ +void rtc_set (struct rtc_time *tmp) +{ + 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); + + rtc_write (RTC_SECONDS, bin2bcd (tmp->tm_sec)); + rtc_write (RTC_MINUTES, bin2bcd (tmp->tm_min)); + rtc_write (RTC_HOURS, bin2bcd (tmp->tm_hour)); + rtc_write (RTC_DAY_OF_WEEK, bin2bcd (tmp->tm_wday + 1)); + rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday)); + rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon)); + rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000)); +} + +/* ------------------------------------------------------------------------- */ + +/* reset the DS1306 */ +void rtc_reset (void) +{ + /* clear the control register */ + rtc_write (RTC_CONTROL, 0x00); /* 1st step: reset WP */ + rtc_write (RTC_CONTROL, 0x00); /* 2nd step: reset 1Hz, AIE1, AIE0 */ + + /* reset all alarms */ + rtc_write (RTC_SECONDS_ALARM0, 0x00); + rtc_write (RTC_SECONDS_ALARM1, 0x00); + rtc_write (RTC_MINUTES_ALARM0, 0x00); + rtc_write (RTC_MINUTES_ALARM1, 0x00); + rtc_write (RTC_HOURS_ALARM0, 0x00); + rtc_write (RTC_HOURS_ALARM1, 0x00); + rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00); + rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00); +} + +/* ------------------------------------------------------------------------- */ + +static unsigned char rtc_read (unsigned char reg) +{ + unsigned char dout[2]; /* SPI Output Data Bytes */ + unsigned char din[2]; /* SPI Input Data Bytes */ + + dout[0] = reg; + + if (spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din) != 0) { + return 0; + } else { + return din[1]; + } +} + +/* ------------------------------------------------------------------------- */ + +static void rtc_write (unsigned char reg, unsigned char val) +{ + unsigned char dout[2]; /* SPI Output Data Bytes */ + unsigned char din[2]; /* SPI Input Data Bytes */ + + dout[0] = 0x80 | reg; + dout[1] = val; + + spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din); +} + +#endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */ + +/* ------------------------------------------------------------------------- */ + +static unsigned char bcd2bin (unsigned char n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +/* ------------------------------------------------------------------------- */ + +static unsigned int bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c new file mode 100644 index 0000000..c882d79 --- /dev/null +++ b/drivers/rtc/ds1307.c @@ -0,0 +1,204 @@ +/* + * (C) Copyright 2001, 2002, 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Keith Outwater, keith_outwater@mvis.com` + * Steven Scholz, steven.scholz@imc-berlin.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 (no alarms) for Dallas Semiconductor (now Maxim) + * DS1307 and DS1338 Real Time Clock (RTC). + * + * based on ds1337.c + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if (defined(CONFIG_RTC_DS1307) || defined(CONFIG_RTC_DS1338) ) && \ + defined(CONFIG_CMD_DATE) + +/*---------------------------------------------------------------------*/ +#undef DEBUG_RTC + +#ifdef DEBUG_RTC +#define DEBUGR(fmt,args...) printf(fmt ,##args) +#else +#define DEBUGR(fmt,args...) +#endif +/*---------------------------------------------------------------------*/ + +#ifndef CFG_I2C_RTC_ADDR +# define CFG_I2C_RTC_ADDR 0x68 +#endif + +#if defined(CONFIG_RTC_DS1307) && (CFG_I2C_SPEED > 100000) +# error The DS1307 is specified only up to 100kHz! +#endif + +/* + * RTC register addresses + */ +#define RTC_SEC_REG_ADDR 0x00 +#define RTC_MIN_REG_ADDR 0x01 +#define RTC_HR_REG_ADDR 0x02 +#define RTC_DAY_REG_ADDR 0x03 +#define RTC_DATE_REG_ADDR 0x04 +#define RTC_MON_REG_ADDR 0x05 +#define RTC_YR_REG_ADDR 0x06 +#define RTC_CTL_REG_ADDR 0x07 + +#define RTC_SEC_BIT_CH 0x80 /* Clock Halt (in Register 0) */ + +#define RTC_CTL_BIT_RS0 0x01 /* Rate select 0 */ +#define RTC_CTL_BIT_RS1 0x02 /* Rate select 1 */ +#define RTC_CTL_BIT_SQWE 0x10 /* Square Wave Enable */ +#define RTC_CTL_BIT_OUT 0x80 /* Output Control */ + +static uchar rtc_read (uchar reg); +static void rtc_write (uchar reg, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin (uchar c); + +/* + * Get the current time from the RTC + */ +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon, year; + + sec = rtc_read (RTC_SEC_REG_ADDR); + min = rtc_read (RTC_MIN_REG_ADDR); + hour = rtc_read (RTC_HR_REG_ADDR); + wday = rtc_read (RTC_DAY_REG_ADDR); + mday = rtc_read (RTC_DATE_REG_ADDR); + mon = rtc_read (RTC_MON_REG_ADDR); + year = rtc_read (RTC_YR_REG_ADDR); + + DEBUGR ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, hour, min, sec); + + if (sec & RTC_SEC_BIT_CH) { + printf ("### Warning: RTC oscillator has stopped\n"); + /* clear the CH flag */ + rtc_write (RTC_SEC_REG_ADDR, + rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH); + } + + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon & 0x1F); + tmp->tm_year = bcd2bin (year) + ( bcd2bin (year) >= 70 ? 1900 : 2000); + tmp->tm_wday = bcd2bin ((wday - 1) & 0x07); + tmp->tm_yday = 0; + tmp->tm_isdst= 0; + + DEBUGR ("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); +} + + +/* + * Set the RTC + */ +void rtc_set (struct rtc_time *tmp) +{ + DEBUGR ("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) + printf("WARNING: year should be between 1970 and 2069!\n"); + + rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100)); + rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon)); + rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1)); + rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday)); + rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour)); + rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min)); + rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec)); +} + + +/* + * Reset the RTC. We setting the date back to 1970-01-01. + * We also enable the oscillator output on the SQW/OUT pin and program + * it for 32,768 Hz output. Note that according to the datasheet, turning + * on the square wave output increases the current drain on the backup + * battery to something between 480nA and 800nA. + */ +void rtc_reset (void) +{ + struct rtc_time tmp; + + rtc_write (RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */ + rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS0); + + 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); + + printf ( "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; +} + + +/* + * Helper functions + */ + +static +uchar rtc_read (uchar reg) +{ + return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg)); +} + + +static void rtc_write (uchar reg, uchar val) +{ + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/ds1337.c b/drivers/rtc/ds1337.c new file mode 100644 index 0000000..c636ac5 --- /dev/null +++ b/drivers/rtc/ds1337.c @@ -0,0 +1,191 @@ +/* + * (C) Copyright 2001, 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Keith Outwater, keith_outwater@mvis.com` + * + * 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 (no alarms) for Dallas Semiconductor (now Maxim) + * DS1337 Real Time Clock (RTC). + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_RTC_DS1337) && defined(CONFIG_CMD_DATE) + +/*---------------------------------------------------------------------*/ +#undef DEBUG_RTC + +#ifdef DEBUG_RTC +#define DEBUGR(fmt,args...) printf(fmt ,##args) +#else +#define DEBUGR(fmt,args...) +#endif +/*---------------------------------------------------------------------*/ + +/* + * RTC register addresses + */ +#define RTC_SEC_REG_ADDR 0x0 +#define RTC_MIN_REG_ADDR 0x1 +#define RTC_HR_REG_ADDR 0x2 +#define RTC_DAY_REG_ADDR 0x3 +#define RTC_DATE_REG_ADDR 0x4 +#define RTC_MON_REG_ADDR 0x5 +#define RTC_YR_REG_ADDR 0x6 +#define RTC_CTL_REG_ADDR 0x0e +#define RTC_STAT_REG_ADDR 0x0f + +/* + * RTC control register bits + */ +#define RTC_CTL_BIT_A1IE 0x1 /* Alarm 1 interrupt enable */ +#define RTC_CTL_BIT_A2IE 0x2 /* Alarm 2 interrupt enable */ +#define RTC_CTL_BIT_INTCN 0x4 /* Interrupt control */ +#define RTC_CTL_BIT_RS1 0x8 /* Rate select 1 */ +#define RTC_CTL_BIT_RS2 0x10 /* Rate select 2 */ +#define RTC_CTL_BIT_DOSC 0x80 /* Disable Oscillator */ + +/* + * RTC status register bits + */ +#define RTC_STAT_BIT_A1F 0x1 /* Alarm 1 flag */ +#define RTC_STAT_BIT_A2F 0x2 /* Alarm 2 flag */ +#define RTC_STAT_BIT_OSF 0x80 /* Oscillator stop flag */ + + +static uchar rtc_read (uchar reg); +static void rtc_write (uchar reg, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin (uchar c); + + +/* + * Get the current time from the RTC + */ +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon_cent, year, control, status; + + control = rtc_read (RTC_CTL_REG_ADDR); + status = rtc_read (RTC_STAT_REG_ADDR); + sec = rtc_read (RTC_SEC_REG_ADDR); + min = rtc_read (RTC_MIN_REG_ADDR); + hour = rtc_read (RTC_HR_REG_ADDR); + wday = rtc_read (RTC_DAY_REG_ADDR); + mday = rtc_read (RTC_DATE_REG_ADDR); + mon_cent = rtc_read (RTC_MON_REG_ADDR); + year = rtc_read (RTC_YR_REG_ADDR); + + DEBUGR ("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x control: %02x status: %02x\n", + year, mon_cent, mday, wday, hour, min, sec, control, status); + + if (status & RTC_STAT_BIT_OSF) { + printf ("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + rtc_write (RTC_STAT_REG_ADDR, + rtc_read (RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF); + } + + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon_cent & 0x1F); + tmp->tm_year = bcd2bin (year) + ((mon_cent & 0x80) ? 2000 : 1900); + tmp->tm_wday = bcd2bin ((wday - 1) & 0x07); + tmp->tm_yday = 0; + tmp->tm_isdst= 0; + + DEBUGR ("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); +} + + +/* + * Set the RTC + */ +void rtc_set (struct rtc_time *tmp) +{ + uchar century; + + DEBUGR ("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); + + rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100)); + + century = (tmp->tm_year >= 2000) ? 0x80 : 0; + rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon) | century); + + rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1)); + rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday)); + rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour)); + rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min)); + rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec)); +} + + +/* + * Reset the RTC. We also enable the oscillator output on the + * SQW/INTB* pin and program it for 32,768 Hz output. Note that + * according to the datasheet, turning on the square wave output + * increases the current drain on the backup battery from about + * 600 nA to 2uA. + */ +void rtc_reset (void) +{ + rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2); +} + + +/* + * Helper functions + */ + +static +uchar rtc_read (uchar reg) +{ + return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg)); +} + + +static void rtc_write (uchar reg, uchar val) +{ + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/ds1374.c b/drivers/rtc/ds1374.c new file mode 100644 index 0000000..e773dd9 --- /dev/null +++ b/drivers/rtc/ds1374.c @@ -0,0 +1,253 @@ +/* + * (C) Copyright 2001, 2002, 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Keith Outwater, keith_outwater@mvis.com` + * Steven Scholz, steven.scholz@imc-berlin.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 (no alarms) for Dallas Semiconductor (now Maxim) + * DS1374 Real Time Clock (RTC). + * + * based on ds1337.c + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if (defined(CONFIG_RTC_DS1374)) && defined(CONFIG_CMD_DATE) + +/*---------------------------------------------------------------------*/ +#undef DEBUG_RTC +#define DEBUG_RTC + +#ifdef DEBUG_RTC +#define DEBUGR(fmt,args...) printf(fmt ,##args) +#else +#define DEBUGR(fmt,args...) +#endif +/*---------------------------------------------------------------------*/ + +#ifndef CFG_I2C_RTC_ADDR +# define CFG_I2C_RTC_ADDR 0x68 +#endif + +#if defined(CONFIG_RTC_DS1374) && (CFG_I2C_SPEED > 400000) +# error The DS1374 is specified up to 400kHz in fast mode! +#endif + +/* + * RTC register addresses + */ +#define RTC_TOD_CNT_BYTE0_ADDR 0x00 /* TimeOfDay */ +#define RTC_TOD_CNT_BYTE1_ADDR 0x01 +#define RTC_TOD_CNT_BYTE2_ADDR 0x02 +#define RTC_TOD_CNT_BYTE3_ADDR 0x03 + +#define RTC_WD_ALM_CNT_BYTE0_ADDR 0x04 +#define RTC_WD_ALM_CNT_BYTE1_ADDR 0x05 +#define RTC_WD_ALM_CNT_BYTE2_ADDR 0x06 + +#define RTC_CTL_ADDR 0x07 /* RTC-CoNTrol-register */ +#define RTC_SR_ADDR 0x08 /* RTC-StatusRegister */ +#define RTC_TCS_DS_ADDR 0x09 /* RTC-TrickleChargeSelect DiodeSelect-register */ + +#define RTC_CTL_BIT_AIE (1<<0) /* Bit 0 - Alarm Interrupt enable */ +#define RTC_CTL_BIT_RS1 (1<<1) /* Bit 1/2 - Rate Select square wave output */ +#define RTC_CTL_BIT_RS2 (1<<2) /* Bit 2/2 - Rate Select square wave output */ +#define RTC_CTL_BIT_WDSTR (1<<3) /* Bit 3 - Watchdog Reset Steering */ +#define RTC_CTL_BIT_BBSQW (1<<4) /* Bit 4 - Battery-Backed Square-Wave */ +#define RTC_CTL_BIT_WD_ALM (1<<5) /* Bit 5 - Watchdoc/Alarm Counter Select */ +#define RTC_CTL_BIT_WACE (1<<6) /* Bit 6 - Watchdog/Alarm Counter Enable WACE*/ +#define RTC_CTL_BIT_EN_OSC (1<<7) /* Bit 7 - Enable Oscilator */ + +#define RTC_SR_BIT_AF 0x01 /* Bit 0 = Alarm Flag */ +#define RTC_SR_BIT_OSF 0x80 /* Bit 7 - Osc Stop Flag */ + +typedef unsigned char boolean_t; + +#ifndef TRUE +#define TRUE ((boolean_t)(0==0)) +#endif +#ifndef FALSE +#define FALSE (!TRUE) +#endif + +const char RtcTodAddr[] = { + RTC_TOD_CNT_BYTE0_ADDR, + RTC_TOD_CNT_BYTE1_ADDR, + RTC_TOD_CNT_BYTE2_ADDR, + RTC_TOD_CNT_BYTE3_ADDR +}; + +static uchar rtc_read (uchar reg); +static void rtc_write (uchar reg, uchar val, boolean_t set); +static void rtc_write_raw (uchar reg, uchar val); + +/* + * Get the current time from the RTC + */ +void rtc_get (struct rtc_time *tm){ + + unsigned long time1, time2; + unsigned int limit; + unsigned char tmp; + unsigned int i; + + /* + * Since the reads are being performed one byte at a time, + * there is a chance that a carry will occur during the read. + * To detect this, 2 reads are performed and compared. + */ + limit = 10; + do { + i = 4; + time1 = 0; + while (i--) { + tmp = rtc_read(RtcTodAddr[i]); + time1 = (time1 << 8) | (tmp & 0xff); + } + + i = 4; + time2 = 0; + while (i--) { + tmp = rtc_read(RtcTodAddr[i]); + time2 = (time2 << 8) | (tmp & 0xff); + } + } while ((time1 != time2) && limit--); + + if (time1 != time2) { + printf("can't get consistent time from rtc chip\n"); + } + + DEBUGR ("Get RTC s since 1.1.1970: %d\n", time1); + + to_tm(time1, tm); /* To Gregorian Date */ + + if (rtc_read(RTC_SR_ADDR) & RTC_SR_BIT_OSF) + printf ("### Warning: RTC oscillator has stopped\n"); + + DEBUGR ("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); +} + +/* + * Set the RTC + */ +void rtc_set (struct rtc_time *tmp){ + + unsigned long time; + unsigned i; + + DEBUGR ("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) + printf("WARNING: year should be between 1970 and 2069!\n"); + + time = mktime(tmp->tm_year, tmp->tm_mon, + tmp->tm_mday, tmp->tm_hour, + tmp->tm_min, tmp->tm_sec); + + DEBUGR ("Set RTC s since 1.1.1970: %d (0x%02x)\n", time, time); + + /* write to RTC_TOD_CNT_BYTEn_ADDR */ + for (i = 0; i <= 3; i++) { + rtc_write_raw(RtcTodAddr[i], (unsigned char)(time & 0xff)); + time = time >> 8; + } + + /* Start clock */ + rtc_write(RTC_CTL_ADDR, RTC_CTL_BIT_EN_OSC, FALSE); +} + +/* + * Reset the RTC. We setting the date back to 1970-01-01. + * We also enable the oscillator output on the SQW/OUT pin and program + * it for 32,768 Hz output. Note that according to the datasheet, turning + * on the square wave output increases the current drain on the backup + * battery to something between 480nA and 800nA. + */ +void rtc_reset (void){ + + struct rtc_time tmp; + + /* clear status flags */ + rtc_write (RTC_SR_ADDR, (RTC_SR_BIT_AF|RTC_SR_BIT_OSF), FALSE); /* clearing OSF and AF */ + + /* Initialise DS1374 oriented to MPC8349E-ADS */ + rtc_write (RTC_CTL_ADDR, (RTC_CTL_BIT_EN_OSC + |RTC_CTL_BIT_WACE + |RTC_CTL_BIT_AIE), FALSE);/* start osc, disable WACE, clear AIE + - set to 0 */ + rtc_write (RTC_CTL_ADDR, (RTC_CTL_BIT_WD_ALM + |RTC_CTL_BIT_WDSTR + |RTC_CTL_BIT_RS1 + |RTC_CTL_BIT_RS2 + |RTC_CTL_BIT_BBSQW), TRUE);/* disable WD/ALM, WDSTR set to INT-pin, + set BBSQW and SQW to 32k + - set to 1 */ + 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); + + printf("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); + + rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR,0xAC, TRUE); + rtc_write(RTC_WD_ALM_CNT_BYTE1_ADDR,0xDE, TRUE); + rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR,0xAD, TRUE); +} + +/* + * Helper functions + */ +static uchar rtc_read (uchar reg) +{ + return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg)); +} + +static void rtc_write (uchar reg, uchar val, boolean_t set) +{ + if (set == TRUE) { + val |= i2c_reg_read (CFG_I2C_RTC_ADDR, reg); + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); + } else { + val = i2c_reg_read (CFG_I2C_RTC_ADDR, reg) & ~val; + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); + } +} + +static void rtc_write_raw (uchar reg, uchar val) +{ + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); +} +#endif diff --git a/drivers/rtc/ds1556.c b/drivers/rtc/ds1556.c new file mode 100644 index 0000000..4365cfb --- /dev/null +++ b/drivers/rtc/ds1556.c @@ -0,0 +1,206 @@ +/* + * (C) Copyright 2002 + * ARIO Data Networks, Inc. dchiu@ariodata.com + * + * modified for DS1556: + * Frank Panno <fpanno@delphintech.com>, Delphin Technology AG + * + * Based on MontaVista DS1743 code and U-Boot mc146818 code + * + * 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 the DS1556 RTC + */ + +/*#define RTC_DEBUG */ + +#include <common.h> +#include <command.h> +#include <rtc.h> + + +#if defined(CONFIG_RTC_DS1556) && defined(CONFIG_CMD_DATE) + +static uchar rtc_read( unsigned int addr ); +static void rtc_write( unsigned int addr, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin(uchar c); + +#define RTC_BASE ( CFG_NVRAM_SIZE + CFG_NVRAM_BASE_ADDR ) + +#define RTC_YEAR ( RTC_BASE + 0xf ) +#define RTC_MONTH ( RTC_BASE + 0xe ) +#define RTC_DAY_OF_MONTH ( RTC_BASE + 0xd ) +#define RTC_DAY_OF_WEEK ( RTC_BASE + 0xc ) +#define RTC_HOURS ( RTC_BASE + 0xb ) +#define RTC_MINUTES ( RTC_BASE + 0xa ) +#define RTC_SECONDS ( RTC_BASE + 0x9 ) +#define RTC_CENTURY ( RTC_BASE + 0x8 ) + +#define RTC_CONTROLA RTC_CENTURY +#define RTC_CONTROLB RTC_SECONDS +#define RTC_CONTROLC RTC_BASE + +#define RTC_CA_WRITE 0x80 +#define RTC_CA_READ 0x40 + +#define RTC_CB_OSC_DISABLE 0x80 + +#define RTC_CC_BATTERY_FLAG 0x10 +#define RTC_CC_FREQ_TEST 0x40 + +/* ------------------------------------------------------------------------- */ + +void rtc_get( struct rtc_time *tmp ) +{ + uchar sec, min, hour; + uchar mday, wday, mon, year; + + int century; + + uchar reg_a; + + reg_a = rtc_read( RTC_CONTROLA ); + /* lock clock registers for read */ + rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ )); + + sec = rtc_read( RTC_SECONDS ); + min = rtc_read( RTC_MINUTES ); + hour = rtc_read( RTC_HOURS ); + mday = rtc_read( RTC_DAY_OF_MONTH ); + wday = rtc_read( RTC_DAY_OF_WEEK ); + mon = rtc_read( RTC_MONTH ); + year = rtc_read( RTC_YEAR ); + century = rtc_read( RTC_CENTURY ); + + /* unlock clock registers after read */ + rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ )); + +#ifdef RTC_DEBUG + printf( "Get RTC year: %02x mon/cent: %02x mon: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, century, mon, mday, wday, + hour, min, sec ); +#endif + tmp->tm_sec = bcd2bin( sec & 0x7F ); + tmp->tm_min = bcd2bin( min & 0x7F ); + tmp->tm_hour = bcd2bin( hour & 0x3F ); + tmp->tm_mday = bcd2bin( mday & 0x3F ); + tmp->tm_mon = bcd2bin( mon & 0x1F ); + tmp->tm_wday = bcd2bin( wday & 0x07 ); + + /* glue year from century and year in century */ + tmp->tm_year = bcd2bin( year ) + + ( bcd2bin( century & 0x3F ) * 100 ); + + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf( "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 ); +#endif +} + +void rtc_set( struct rtc_time *tmp ) +{ + uchar reg_a; +#ifdef RTC_DEBUG + printf( "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); +#endif + /* lock clock registers for write */ + reg_a = rtc_read( RTC_CONTROLA ); + rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE )); + + rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon )); + + rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday )); + rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday )); + rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour )); + rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min )); + rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec )); + + /* break year up into century and year in century */ + rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 )); + rtc_write( RTC_CENTURY, bin2bcd( tmp->tm_year / 100 )); + + /* unlock clock registers after read */ + rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE )); +} + +void rtc_reset (void) +{ + uchar reg_a, reg_b, reg_c; + + reg_a = rtc_read( RTC_CONTROLA ); + reg_b = rtc_read( RTC_CONTROLB ); + + if ( reg_b & RTC_CB_OSC_DISABLE ) + { + printf( "real-time-clock was stopped. Now starting...\n" ); + reg_a |= RTC_CA_WRITE; + reg_b &= ~RTC_CB_OSC_DISABLE; + + rtc_write( RTC_CONTROLA, reg_a ); + rtc_write( RTC_CONTROLB, reg_b ); + } + + /* make sure read/write clock register bits are cleared */ + reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ ); + rtc_write( RTC_CONTROLA, reg_a ); + + reg_c = rtc_read( RTC_CONTROLC ); + if (( reg_c & RTC_CC_BATTERY_FLAG ) == 0 ) + printf( "RTC battery low. Clock setting may not be reliable.\n" ); +} + +/* ------------------------------------------------------------------------- */ + +static uchar rtc_read( unsigned int addr ) +{ + uchar val = *(volatile unsigned char*)(addr); +#ifdef RTC_DEBUG + printf( "rtc_read: %x:%x\n", addr, val ); +#endif + return( val ); +} + +static void rtc_write( unsigned int addr, uchar val ) +{ +#ifdef RTC_DEBUG + printf( "rtc_write: %x:%x\n", addr, val ); +#endif + *(volatile unsigned char*)(addr) = val; +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/ds164x.c b/drivers/rtc/ds164x.c new file mode 100644 index 0000000..bff22b9 --- /dev/null +++ b/drivers/rtc/ds164x.c @@ -0,0 +1,200 @@ +/* + * (C) Copyright 2002 + * ARIO Data Networks, Inc. dchiu@ariodata.com + * + * modified for DS164x: + * The LEOX team <team@leox.org>, http://www.leox.org + * + * Based on MontaVista DS1743 code and U-Boot mc146818 code + * + * 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 the DS164x RTC + */ + +/* #define RTC_DEBUG */ + +#include <common.h> +#include <command.h> +#include <rtc.h> + + +#if defined(CONFIG_RTC_DS164x) && defined(CONFIG_CMD_DATE) + +static uchar rtc_read(unsigned int addr ); +static void rtc_write(unsigned int addr, uchar val); +static uchar bin2bcd(unsigned int n); +static unsigned bcd2bin(uchar c); + +#define RTC_EPOCH 2000 /* century */ + +/* + * DS164x registers layout + */ +#define RTC_BASE ( CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE ) + +#define RTC_YEAR ( RTC_BASE + 0x07 ) +#define RTC_MONTH ( RTC_BASE + 0x06 ) +#define RTC_DAY_OF_MONTH ( RTC_BASE + 0x05 ) +#define RTC_DAY_OF_WEEK ( RTC_BASE + 0x04 ) +#define RTC_HOURS ( RTC_BASE + 0x03 ) +#define RTC_MINUTES ( RTC_BASE + 0x02 ) +#define RTC_SECONDS ( RTC_BASE + 0x01 ) +#define RTC_CONTROL ( RTC_BASE + 0x00 ) + +#define RTC_CONTROLA RTC_CONTROL /* W=bit6, R=bit5 */ +#define RTC_CA_WRITE 0x80 +#define RTC_CA_READ 0x40 +#define RTC_CONTROLB RTC_SECONDS /* OSC=bit7 */ +#define RTC_CB_OSC_DISABLE 0x80 +#define RTC_CONTROLC RTC_DAY_OF_WEEK /* FT=bit6 */ +#define RTC_CC_FREQ_TEST 0x40 + +/* ------------------------------------------------------------------------- */ + +void rtc_get( struct rtc_time *tmp ) +{ + uchar sec, min, hour; + uchar mday, wday, mon, year; + + uchar reg_a; + + reg_a = rtc_read( RTC_CONTROLA ); + /* lock clock registers for read */ + rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ )); + + sec = rtc_read( RTC_SECONDS ); + min = rtc_read( RTC_MINUTES ); + hour = rtc_read( RTC_HOURS ); + mday = rtc_read( RTC_DAY_OF_MONTH ); + wday = rtc_read( RTC_DAY_OF_WEEK ); + mon = rtc_read( RTC_MONTH ); + year = rtc_read( RTC_YEAR ); + + /* unlock clock registers after read */ + rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ )); + +#ifdef RTC_DEBUG + printf( "Get RTC year: %02x mon: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, + hour, min, sec ); +#endif + tmp->tm_sec = bcd2bin( sec & 0x7F ); + tmp->tm_min = bcd2bin( min & 0x7F ); + tmp->tm_hour = bcd2bin( hour & 0x3F ); + tmp->tm_mday = bcd2bin( mday & 0x3F ); + tmp->tm_mon = bcd2bin( mon & 0x1F ); + tmp->tm_wday = bcd2bin( wday & 0x07 ); + + /* glue year in century (2000) */ + tmp->tm_year = bcd2bin( year ) + RTC_EPOCH; + + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf( "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 ); +#endif +} + +void rtc_set( struct rtc_time *tmp ) +{ + uchar reg_a; + +#ifdef RTC_DEBUG + printf( "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); +#endif + /* lock clock registers for write */ + reg_a = rtc_read( RTC_CONTROLA ); + rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE )); + + rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon )); + + rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday )); + rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday )); + rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour )); + rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min )); + rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec )); + + /* break year in century */ + rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 )); + + /* unlock clock registers after read */ + rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE )); +} + +void rtc_reset (void) +{ + uchar reg_a, reg_b; + + reg_a = rtc_read( RTC_CONTROLA ); + reg_b = rtc_read( RTC_CONTROLB ); + + if ( reg_b & RTC_CB_OSC_DISABLE ) + { + printf( "real-time-clock was stopped. Now starting...\n" ); + reg_a |= RTC_CA_WRITE; + reg_b &= ~RTC_CB_OSC_DISABLE; + + rtc_write( RTC_CONTROLA, reg_a ); + rtc_write( RTC_CONTROLB, reg_b ); + } + + /* make sure read/write clock register bits are cleared */ + reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ ); + rtc_write( RTC_CONTROLA, reg_a ); +} + +/* ------------------------------------------------------------------------- */ + +static uchar rtc_read( unsigned int addr ) +{ + uchar val = *(volatile unsigned char*)(addr); + +#ifdef RTC_DEBUG + printf( "rtc_read: %x:%x\n", addr, val ); +#endif + return( val ); +} + +static void rtc_write( unsigned int addr, uchar val ) +{ +#ifdef RTC_DEBUG + printf( "rtc_write: %x:%x\n", addr, val ); +#endif + *(volatile unsigned char*)(addr) = val; +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/ds174x.c b/drivers/rtc/ds174x.c new file mode 100644 index 0000000..5f85a68 --- /dev/null +++ b/drivers/rtc/ds174x.c @@ -0,0 +1,202 @@ +/* + * (C) Copyright 2001 + * ARIO Data Networks, Inc. dchiu@ariodata.com + * + * Based on MontaVista DS1743 code and U-Boot mc146818 code + * + * 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 the DS174x RTC + */ + +/*#define DEBUG*/ + +#include <common.h> +#include <command.h> +#include <rtc.h> + +#if defined(CONFIG_RTC_DS174x) && defined(CONFIG_CMD_DATE) + +static uchar rtc_read( unsigned int addr ); +static void rtc_write( unsigned int addr, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin(uchar c); + +#define RTC_BASE ( CFG_NVRAM_SIZE + CFG_NVRAM_BASE_ADDR ) + +#define RTC_YEAR ( RTC_BASE + 7 ) +#define RTC_MONTH ( RTC_BASE + 6 ) +#define RTC_DAY_OF_MONTH ( RTC_BASE + 5 ) +#define RTC_DAY_OF_WEEK ( RTC_BASE + 4 ) +#define RTC_HOURS ( RTC_BASE + 3 ) +#define RTC_MINUTES ( RTC_BASE + 2 ) +#define RTC_SECONDS ( RTC_BASE + 1 ) +#define RTC_CENTURY ( RTC_BASE + 0 ) + +#define RTC_CONTROLA RTC_CENTURY +#define RTC_CONTROLB RTC_SECONDS +#define RTC_CONTROLC RTC_DAY_OF_WEEK + +#define RTC_CA_WRITE 0x80 +#define RTC_CA_READ 0x40 + +#define RTC_CB_OSC_DISABLE 0x80 + +#define RTC_CC_BATTERY_FLAG 0x80 +#define RTC_CC_FREQ_TEST 0x40 + +/* ------------------------------------------------------------------------- */ + +void rtc_get( struct rtc_time *tmp ) +{ + uchar sec, min, hour; + uchar mday, wday, mon, year; + + int century; + + uchar reg_a; + + reg_a = rtc_read( RTC_CONTROLA ); + /* lock clock registers for read */ + rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ )); + + sec = rtc_read( RTC_SECONDS ); + min = rtc_read( RTC_MINUTES ); + hour = rtc_read( RTC_HOURS ); + mday = rtc_read( RTC_DAY_OF_MONTH ); + wday = rtc_read( RTC_DAY_OF_WEEK ); + mon = rtc_read( RTC_MONTH ); + year = rtc_read( RTC_YEAR ); + century = rtc_read( RTC_CENTURY ); + + /* unlock clock registers after read */ + rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ )); + +#ifdef RTC_DEBUG + printf( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon_cent, mday, wday, + hour, min, sec ); +#endif + tmp->tm_sec = bcd2bin( sec & 0x7F ); + tmp->tm_min = bcd2bin( min & 0x7F ); + tmp->tm_hour = bcd2bin( hour & 0x3F ); + tmp->tm_mday = bcd2bin( mday & 0x3F ); + tmp->tm_mon = bcd2bin( mon & 0x1F ); + tmp->tm_wday = bcd2bin( wday & 0x07 ); + + /* glue year from century and year in century */ + tmp->tm_year = bcd2bin( year ) + + ( bcd2bin( century & 0x3F ) * 100 ); + + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf( "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 ); +#endif +} + +void rtc_set( struct rtc_time *tmp ) +{ + uchar reg_a; +#ifdef RTC_DEBUG + printf( "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); +#endif + /* lock clock registers for write */ + reg_a = rtc_read( RTC_CONTROLA ); + rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE )); + + rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon )); + + rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday )); + rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday )); + rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour )); + rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min )); + rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec )); + + /* break year up into century and year in century */ + rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 )); + rtc_write( RTC_CENTURY, bin2bcd( tmp->tm_year / 100 )); + + /* unlock clock registers after read */ + rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_WRITE )); +} + +void rtc_reset (void) +{ + uchar reg_a, reg_b, reg_c; + + reg_a = rtc_read( RTC_CONTROLA ); + reg_b = rtc_read( RTC_CONTROLB ); + + if ( reg_b & RTC_CB_OSC_DISABLE ) + { + printf( "real-time-clock was stopped. Now starting...\n" ); + reg_a |= RTC_CA_WRITE; + reg_b &= ~RTC_CB_OSC_DISABLE; + + rtc_write( RTC_CONTROLA, reg_a ); + rtc_write( RTC_CONTROLB, reg_b ); + } + + /* make sure read/write clock register bits are cleared */ + reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ ); + rtc_write( RTC_CONTROLA, reg_a ); + + reg_c = rtc_read( RTC_CONTROLC ); + if (( reg_c & RTC_CC_BATTERY_FLAG ) == 0 ) + printf( "RTC battery low. Clock setting may not be reliable.\n" ); +} + +/* ------------------------------------------------------------------------- */ + +static uchar rtc_read( unsigned int addr ) +{ + uchar val = in8( addr ); +#ifdef RTC_DEBUG + printf( "rtc_read: %x:%x\n", addr, val ); +#endif + return( val ); +} + +static void rtc_write( unsigned int addr, uchar val ) +{ +#ifdef RTC_DEBUG + printf( "rtc_write: %x:%x\n", addr, val ); +#endif + out8( addr, val ); +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/ds3231.c b/drivers/rtc/ds3231.c new file mode 100644 index 0000000..fe11b86 --- /dev/null +++ b/drivers/rtc/ds3231.c @@ -0,0 +1,193 @@ +/* + * (C) Copyright 2006 + * Markus Klotzbuecher, mk@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 (no alarms) for Dallas Semiconductor (now Maxim) + * Extremly Accurate DS3231 Real Time Clock (RTC). + * + * copied from ds1337.c + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_RTC_DS3231) && defined(CONFIG_CMD_DATE) + +/*---------------------------------------------------------------------*/ +#undef DEBUG_RTC + +#ifdef DEBUG_RTC +#define DEBUGR(fmt,args...) printf(fmt ,##args) +#else +#define DEBUGR(fmt,args...) +#endif +/*---------------------------------------------------------------------*/ + +/* + * RTC register addresses + */ +#define RTC_SEC_REG_ADDR 0x0 +#define RTC_MIN_REG_ADDR 0x1 +#define RTC_HR_REG_ADDR 0x2 +#define RTC_DAY_REG_ADDR 0x3 +#define RTC_DATE_REG_ADDR 0x4 +#define RTC_MON_REG_ADDR 0x5 +#define RTC_YR_REG_ADDR 0x6 +#define RTC_CTL_REG_ADDR 0x0e +#define RTC_STAT_REG_ADDR 0x0f + + +/* + * RTC control register bits + */ +#define RTC_CTL_BIT_A1IE 0x1 /* Alarm 1 interrupt enable */ +#define RTC_CTL_BIT_A2IE 0x2 /* Alarm 2 interrupt enable */ +#define RTC_CTL_BIT_INTCN 0x4 /* Interrupt control */ +#define RTC_CTL_BIT_RS1 0x8 /* Rate select 1 */ +#define RTC_CTL_BIT_RS2 0x10 /* Rate select 2 */ +#define RTC_CTL_BIT_DOSC 0x80 /* Disable Oscillator */ + +/* + * RTC status register bits + */ +#define RTC_STAT_BIT_A1F 0x1 /* Alarm 1 flag */ +#define RTC_STAT_BIT_A2F 0x2 /* Alarm 2 flag */ +#define RTC_STAT_BIT_OSF 0x80 /* Oscillator stop flag */ + + +static uchar rtc_read (uchar reg); +static void rtc_write (uchar reg, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin (uchar c); + + +/* + * Get the current time from the RTC + */ +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon_cent, year, control, status; + + control = rtc_read (RTC_CTL_REG_ADDR); + status = rtc_read (RTC_STAT_REG_ADDR); + sec = rtc_read (RTC_SEC_REG_ADDR); + min = rtc_read (RTC_MIN_REG_ADDR); + hour = rtc_read (RTC_HR_REG_ADDR); + wday = rtc_read (RTC_DAY_REG_ADDR); + mday = rtc_read (RTC_DATE_REG_ADDR); + mon_cent = rtc_read (RTC_MON_REG_ADDR); + year = rtc_read (RTC_YR_REG_ADDR); + + DEBUGR ("Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x control: %02x status: %02x\n", + year, mon_cent, mday, wday, hour, min, sec, control, status); + + if (status & RTC_STAT_BIT_OSF) { + printf ("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + rtc_write (RTC_STAT_REG_ADDR, + rtc_read (RTC_STAT_REG_ADDR) & ~RTC_STAT_BIT_OSF); + } + + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon_cent & 0x1F); + tmp->tm_year = bcd2bin (year) + ((mon_cent & 0x80) ? 2000 : 1900); + tmp->tm_wday = bcd2bin ((wday - 1) & 0x07); + tmp->tm_yday = 0; + tmp->tm_isdst= 0; + + DEBUGR ("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); +} + + +/* + * Set the RTC + */ +void rtc_set (struct rtc_time *tmp) +{ + uchar century; + + DEBUGR ("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); + + rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100)); + + century = (tmp->tm_year >= 2000) ? 0x80 : 0; + rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon) | century); + + rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1)); + rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday)); + rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour)); + rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min)); + rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec)); +} + + +/* + * Reset the RTC. We also enable the oscillator output on the + * SQW/INTB* pin and program it for 32,768 Hz output. Note that + * according to the datasheet, turning on the square wave output + * increases the current drain on the backup battery from about + * 600 nA to 2uA. + */ +void rtc_reset (void) +{ + rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS2); +} + + +/* + * Helper functions + */ + +static +uchar rtc_read (uchar reg) +{ + return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg)); +} + + +static void rtc_write (uchar reg, uchar val) +{ + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/m41t11.c b/drivers/rtc/m41t11.c new file mode 100644 index 0000000..81da33a --- /dev/null +++ b/drivers/rtc/m41t11.c @@ -0,0 +1,202 @@ +/* + * (C) Copyright 2002 + * Andrew May, Viasat Inc, amay@viasat.com + * + * 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 + */ + +/* + * M41T11 Serial Access Timekeeper(R) SRAM + * can you believe a trademark on that? + */ + +/* #define DEBUG 1 */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +/* + I Don't have an example config file but this + is what should be done. + +#define CONFIG_RTC_M41T11 1 +#define CFG_I2C_RTC_ADDR 0x68 +#if 0 +#define CFG_M41T11_EXT_CENTURY_DATA +#else +#define CFG_M41T11_BASE_YEAR 2000 +#endif +*/ + +#if defined(CONFIG_RTC_M41T11) && defined(CFG_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE) + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + + +/* ------------------------------------------------------------------------- */ +/* + these are simple defines for the chip local to here so they aren't too + verbose + DAY/DATE aren't nice but that is how they are on the data sheet +*/ +#define RTC_SEC_ADDR 0x0 +#define RTC_MIN_ADDR 0x1 +#define RTC_HOUR_ADDR 0x2 +#define RTC_DAY_ADDR 0x3 +#define RTC_DATE_ADDR 0x4 +#define RTC_MONTH_ADDR 0x5 +#define RTC_YEARS_ADDR 0x6 + +#define RTC_REG_CNT 7 + +#define RTC_CONTROL_ADDR 0x7 + + +#ifndef CFG_M41T11_EXT_CENTURY_DATA + +#define REG_CNT (RTC_REG_CNT+1) + +/* + you only get 00-99 for the year we will asume you + want from the year 2000 if you don't set the config +*/ +#ifndef CFG_M41T11_BASE_YEAR +#define CFG_M41T11_BASE_YEAR 2000 +#endif + +#else +/* we will store extra year info in byte 9*/ +#define M41T11_YEAR_DATA 0x8 +#define M41T11_YEAR_SIZE 1 +#define REG_CNT (RTC_REG_CNT+1+M41T11_YEAR_SIZE) +#endif + +#define M41T11_STORAGE_SZ (64-REG_CNT) + +void rtc_get (struct rtc_time *tmp) +{ + uchar data[RTC_REG_CNT]; + + i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT); + + if( data[RTC_SEC_ADDR] & 0x80 ){ + printf( "m41t11 RTC Clock stopped!!!\n" ); + } + tmp->tm_sec = bcd2bin (data[RTC_SEC_ADDR] & 0x7F); + tmp->tm_min = bcd2bin (data[RTC_MIN_ADDR] & 0x7F); + tmp->tm_hour = bcd2bin (data[RTC_HOUR_ADDR] & 0x3F); + tmp->tm_mday = bcd2bin (data[RTC_DATE_ADDR] & 0x3F); + tmp->tm_mon = bcd2bin (data[RTC_MONTH_ADDR]& 0x1F); +#ifndef CFG_M41T11_EXT_CENTURY_DATA + tmp->tm_year = CFG_M41T11_BASE_YEAR + + bcd2bin(data[RTC_YEARS_ADDR]) + + ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0); +#else + { + unsigned char cent; + i2c_read(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE); + if( !(data[RTC_HOUR_ADDR] & 0x80) ){ + printf( "m41t11 RTC: cann't keep track of years without CEB set\n" ); + } + if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){ + /*century flip store off new year*/ + cent += 1; + i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE); + } + tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]); + } +#endif + tmp->tm_wday = bcd2bin (data[RTC_DAY_ADDR] & 0x07); + 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); +} + +void rtc_set (struct rtc_time *tmp) +{ + uchar data[RTC_REG_CNT]; + + 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); + + data[RTC_SEC_ADDR] = bin2bcd(tmp->tm_sec) & 0x7F;/*just in case*/ + data[RTC_MIN_ADDR] = bin2bcd(tmp->tm_min); + data[RTC_HOUR_ADDR] = bin2bcd(tmp->tm_hour) & 0x3F;/*handle cent stuff later*/ + data[RTC_DATE_ADDR] = bin2bcd(tmp->tm_mday) & 0x3F; + data[RTC_MONTH_ADDR] = bin2bcd(tmp->tm_mon); + data[RTC_DAY_ADDR] = bin2bcd(tmp->tm_wday) & 0x07; + + data[RTC_HOUR_ADDR] |= 0x80;/*we will always use CEB*/ + + data[RTC_YEARS_ADDR] = bin2bcd(tmp->tm_year%100);/*same thing either way*/ +#ifndef CFG_M41T11_EXT_CENTURY_DATA + if( ((tmp->tm_year - CFG_M41T11_BASE_YEAR) > 200) || + (tmp->tm_year < CFG_M41T11_BASE_YEAR) ){ + printf( "m41t11 RTC setting year out of range!!need recompile\n" ); + } + data[RTC_HOUR_ADDR] |= (tmp->tm_year - CFG_M41T11_BASE_YEAR) > 100 ? 0x40 : 0; +#else + { + unsigned char cent; + cent = tmp->tm_year ? tmp->tm_year / 100 : 0; + data[RTC_HOUR_ADDR] |= (cent & 0x1) ? 0x40 : 0; + i2c_write(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE); + } +#endif + i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT); +} + +void rtc_reset (void) +{ + unsigned char val; + /* clear all control & status registers */ + i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1); + val = val & 0x7F;/*make sure we are running*/ + i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT); + + i2c_read(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1); + val = val & 0x3F;/*turn off freq test keep calibration*/ + i2c_write(CFG_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1); +} + +int rtc_store(int addr, unsigned char* data, int size) +{ + /*don't let things wrap onto the time on a write*/ + if( (addr+size) >= M41T11_STORAGE_SZ ) + return 1; + return i2c_write( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size ); +} + +int rtc_recall(int addr, unsigned char* data, int size) +{ + return i2c_read( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size ); +} + +#endif diff --git a/drivers/rtc/m41t60.c b/drivers/rtc/m41t60.c new file mode 100644 index 0000000..7c80143 --- /dev/null +++ b/drivers/rtc/m41t60.c @@ -0,0 +1,261 @@ +/* + * (C) Copyright 2007 + * Larry Johnson, lrj@acm.org + * + * based on rtc/m41t11.c which is ... + * + * (C) Copyright 2002 + * Andrew May, Viasat Inc, amay@viasat.com + * + * 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 + */ + +/* + * STMicroelectronics M41T60 serial access real-time clock + */ + +/* #define DEBUG 1 */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_RTC_M41T60) && defined(CFG_I2C_RTC_ADDR) && \ + defined(CONFIG_CMD_DATE) + +static unsigned bcd2bin(uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd(unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +/* + * Convert between century and "century bits" (CB1 and CB0). These routines + * assume years are in the range 1900 - 2299. + */ + +static unsigned char year2cb(unsigned const year) +{ + if (year < 1900 || year >= 2300) + printf("M41T60 RTC: year %d out of range\n", year); + + return (year / 100) & 0x3; +} + +static unsigned cb2year(unsigned const cb) +{ + return 1900 + 100 * ((cb + 1) & 0x3); +} + +/* + * These are simple defines for the chip local to here so they aren't too + * verbose. DAY/DATE aren't nice but that is how they are on the data sheet. + */ +#define RTC_SEC 0x0 +#define RTC_MIN 0x1 +#define RTC_HOUR 0x2 +#define RTC_DAY 0x3 +#define RTC_DATE 0x4 +#define RTC_MONTH 0x5 +#define RTC_YEAR 0x6 + +#define RTC_REG_CNT 7 + +#define RTC_CTRL 0x7 + +#if defined(DEBUG) +static void rtc_dump(char const *const label) +{ + uchar data[8]; + + if (i2c_read(CFG_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) { + printf("I2C read failed in rtc_dump()\n"); + return; + } + printf("RTC dump %s: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", + label, data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); +} +#else +#define rtc_dump(label) +#endif + +static uchar *rtc_validate(void) +{ + /* + * This routine uses the OUT bit and the validity of the time values to + * determine whether there has been an initial power-up since the last + * time the routine was run. It assumes that the OUT bit is not being + * used for any other purpose. + */ + static const uchar daysInMonth[0x13] = { + 0x00, 0x31, 0x29, 0x31, 0x30, 0x31, 0x30, 0x31, + 0x31, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x30, 0x31 + }; + static uchar data[8]; + uchar min, date, month, years; + + rtc_dump("begin validate"); + if (i2c_read(CFG_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) { + printf("I2C read failed in rtc_validate()\n"); + return 0; + } + /* + * If the OUT bit is "1", there has been a loss of power, so stop the + * oscillator so it can be "kick-started" as per data sheet. + */ + if (0x00 != (data[RTC_CTRL] & 0x80)) { + printf("M41T60 RTC clock lost power.\n"); + data[RTC_SEC] = 0x80; + if (i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC, 1, data, 1)) { + printf("I2C write failed in rtc_validate()\n"); + return 0; + } + } + /* + * If the oscillator is stopped or the date is invalid, then reset the + * OUT bit to "0", reset the date registers, and start the oscillator. + */ + min = data[RTC_MIN] & 0x7F; + date = data[RTC_DATE]; + month = data[RTC_MONTH] & 0x3F; + years = data[RTC_YEAR]; + if (0x59 < data[RTC_SEC] || 0x09 < (data[RTC_SEC] & 0x0F) || + 0x59 < min || 0x09 < (min & 0x0F) || + 0x23 < data[RTC_HOUR] || 0x09 < (data[RTC_HOUR] & 0x0F) || + 0x07 < data[RTC_DAY] || 0x00 == data[RTC_DAY] || + 0x12 < month || + 0x99 < years || 0x09 < (years & 0x0F) || + daysInMonth[month] < date || 0x09 < (date & 0x0F) || 0x00 == date || + (0x29 == date && 0x02 == month && + ((0x00 != (years & 0x03)) || + (0x00 == years && 0x00 != (data[RTC_MONTH] & 0xC0))))) { + printf("Resetting M41T60 RTC clock.\n"); + /* + * Set to 00:00:00 1900-01-01 (Monday) + */ + data[RTC_SEC] = 0x00; + data[RTC_MIN] &= 0x80; /* preserve OFIE bit */ + data[RTC_HOUR] = 0x00; + data[RTC_DAY] = 0x02; + data[RTC_DATE] = 0x01; + data[RTC_MONTH] = 0xC1; + data[RTC_YEAR] = 0x00; + data[RTC_CTRL] &= 0x7F; /* reset OUT bit */ + + if (i2c_write(CFG_I2C_RTC_ADDR, 0, 1, data, sizeof(data))) { + printf("I2C write failed in rtc_validate()\n"); + return 0; + } + } + return data; +} + +void rtc_get(struct rtc_time *tmp) +{ + uchar const *const data = rtc_validate(); + + if (!data) + return; + + tmp->tm_sec = bcd2bin(data[RTC_SEC] & 0x7F); + tmp->tm_min = bcd2bin(data[RTC_MIN] & 0x7F); + tmp->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3F); + tmp->tm_mday = bcd2bin(data[RTC_DATE] & 0x3F); + tmp->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1F); + tmp->tm_year = cb2year(data[RTC_MONTH] >> 6) + bcd2bin(data[RTC_YEAR]); + tmp->tm_wday = bcd2bin(data[RTC_DAY] & 0x07) - 1; + 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); +} + +void rtc_set(struct rtc_time *tmp) +{ + uchar *const data = rtc_validate(); + + if (!data) + return; + + 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); + + data[RTC_SEC] = (data[RTC_SEC] & 0x80) | (bin2bcd(tmp->tm_sec) & 0x7F); + data[RTC_MIN] = (data[RTC_MIN] & 0X80) | (bin2bcd(tmp->tm_min) & 0X7F); + data[RTC_HOUR] = bin2bcd(tmp->tm_hour) & 0x3F; + data[RTC_DATE] = bin2bcd(tmp->tm_mday) & 0x3F; + data[RTC_MONTH] = bin2bcd(tmp->tm_mon) & 0x1F; + data[RTC_YEAR] = bin2bcd(tmp->tm_year % 100); + data[RTC_MONTH] |= year2cb(tmp->tm_year) << 6; + data[RTC_DAY] = bin2bcd(tmp->tm_wday + 1) & 0x07; + if (i2c_write(CFG_I2C_RTC_ADDR, 0, 1, data, RTC_REG_CNT)) { + printf("I2C write failed in rtc_set()\n"); + return; + } +} + +void rtc_reset(void) +{ + uchar *const data = rtc_validate(); + char const *const s = getenv("rtccal"); + + if (!data) + return; + + rtc_dump("begin reset"); + /* + * If environmental variable "rtccal" is present, it must be a hex value + * between 0x00 and 0x3F, inclusive. The five least-significan bits + * represent the calibration magnitude, and the sixth bit the sign bit. + * If these do not match the contents of the hardware register, that + * register is updated. The value 0x00 imples no correction. Consult + * the M41T60 documentation for further details. + */ + if (s) { + unsigned long const l = simple_strtoul(s, 0, 16); + + if (l <= 0x3F) { + if ((data[RTC_CTRL] & 0x3F) != l) { + printf("Setting RTC calibration to 0x%02X\n", + l); + data[RTC_CTRL] &= 0xC0; + data[RTC_CTRL] |= (uchar) l; + } + } else + printf("environment parameter \"rtccal\" not valid: " + "ignoring\n"); + } + /* + * Turn off frequency test. + */ + data[RTC_CTRL] &= 0xBF; + if (i2c_write(CFG_I2C_RTC_ADDR, RTC_CTRL, 1, data + RTC_CTRL, 1)) { + printf("I2C write failed in rtc_reset()\n"); + return; + } + rtc_dump("end reset"); +} +#endif /* CONFIG_RTC_M41T60 && CFG_I2C_RTC_ADDR && CONFIG_CMD_DATE */ diff --git a/drivers/rtc/m48t35ax.c b/drivers/rtc/m48t35ax.c new file mode 100644 index 0000000..0a0ffa8 --- /dev/null +++ b/drivers/rtc/m48t35ax.c @@ -0,0 +1,166 @@ +/* + * (C) Copyright 2001 + * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com. + * + * 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 ST Electronics M48T35Ax RTC + */ + +/*#define DEBUG */ + + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <config.h> + +#if defined(CONFIG_RTC_M48T35A) && defined(CONFIG_CMD_DATE) + +static uchar rtc_read (uchar reg); +static void rtc_write (uchar reg, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin(uchar c); + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, cent_day, date, month, year; + uchar ccr; /* Clock control register */ + + /* Lock RTC for read using clock control register */ + ccr = rtc_read(0); + ccr = ccr | 0x40; + rtc_write(0, ccr); + + sec = rtc_read (0x1); + min = rtc_read (0x2); + hour = rtc_read (0x3); + cent_day= rtc_read (0x4); + date = rtc_read (0x5); + month = rtc_read (0x6); + year = rtc_read (0x7); + + /* UNLock RTC */ + ccr = rtc_read(0); + ccr = ccr & 0xBF; + rtc_write(0, ccr); + + debug ( "Get RTC year: %02x month: %02x date: %02x cent_day: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, month, date, cent_day, + hour, min, sec ); + + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (date & 0x3F); + tmp->tm_mon = bcd2bin (month & 0x1F); + tmp->tm_year = bcd2bin (year) + ((cent_day & 0x10) ? 2000 : 1900); + tmp->tm_wday = bcd2bin (cent_day & 0x07); + 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); +} + +void rtc_set (struct rtc_time *tmp) +{ + uchar ccr; /* Clock control register */ + uchar century; + + 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); + + /* Lock RTC for write using clock control register */ + ccr = rtc_read(0); + ccr = ccr | 0x80; + rtc_write(0, ccr); + + rtc_write (0x07, bin2bcd(tmp->tm_year % 100)); + rtc_write (0x06, bin2bcd(tmp->tm_mon)); + rtc_write (0x05, bin2bcd(tmp->tm_mday)); + + century = ((tmp->tm_year >= 2000) ? 0x10 : 0) | 0x20; + rtc_write (0x04, bin2bcd(tmp->tm_wday) | century); + + rtc_write (0x03, bin2bcd(tmp->tm_hour)); + rtc_write (0x02, bin2bcd(tmp->tm_min )); + rtc_write (0x01, bin2bcd(tmp->tm_sec )); + + /* UNLock RTC */ + ccr = rtc_read(0); + ccr = ccr & 0x7F; + rtc_write(0, ccr); +} + +void rtc_reset (void) +{ + uchar val; + + /* Clear all clock control registers */ + rtc_write (0x0, 0x80); /* No Read Lock or calibration */ + + /* Clear stop bit */ + val = rtc_read (0x1); + val &= 0x7f; + rtc_write(0x1, val); + + /* Enable century / disable frequency test */ + val = rtc_read (0x4); + val = (val & 0xBF) | 0x20; + rtc_write(0x4, val); + + /* Clear write lock */ + rtc_write(0x0, 0); +} + +/* ------------------------------------------------------------------------- */ + +static uchar rtc_read (uchar reg) +{ + uchar val; + val = *(unsigned char *) + ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg); + return val; +} + +static void rtc_write (uchar reg, uchar val) +{ + *(unsigned char *) + ((CFG_NVRAM_BASE_ADDR + CFG_NVRAM_SIZE - 8) + reg) = val; +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/max6900.c b/drivers/rtc/max6900.c new file mode 100644 index 0000000..c75a8e0 --- /dev/null +++ b/drivers/rtc/max6900.c @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2004 + * 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 MAXIM MAX6900 RTC + */ + +/* #define DEBUG */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_RTC_MAX6900) && defined(CONFIG_CMD_DATE) + +#ifndef CFG_I2C_RTC_ADDR +#define CFG_I2C_RTC_ADDR 0x50 +#endif + +/* ------------------------------------------------------------------------- */ + +static uchar rtc_read (uchar reg) +{ + return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg)); +} + +static void rtc_write (uchar reg, uchar val) +{ + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); + udelay(2500); +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon, cent, year; + int retry = 1; + + do { + sec = rtc_read (0x80); + min = rtc_read (0x82); + hour = rtc_read (0x84); + mday = rtc_read (0x86); + mon = rtc_read (0x88); + wday = rtc_read (0x8a); + year = rtc_read (0x8c); + cent = rtc_read (0x92); + /* + * Check for seconds rollover + */ + if ((sec != 59) || (rtc_read(0x80) == sec)){ + retry = 0; + } + } while (retry); + + debug ( "Get RTC year: %02x mon: %02x cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, cent, mday, wday, + hour, min, sec ); + + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon & 0x1F); + tmp->tm_year = bcd2bin (year) + bcd2bin(cent) * 100; + tmp->tm_wday = bcd2bin (wday & 0x07); + 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); +} + +void rtc_set (struct rtc_time *tmp) +{ + + 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); + + rtc_write (0x9E, 0x00); + rtc_write (0x80, 0); /* Clear seconds to ensure no rollover */ + rtc_write (0x92, bin2bcd(tmp->tm_year / 100)); + rtc_write (0x8c, bin2bcd(tmp->tm_year % 100)); + rtc_write (0x8a, bin2bcd(tmp->tm_wday)); + rtc_write (0x88, bin2bcd(tmp->tm_mon)); + rtc_write (0x86, bin2bcd(tmp->tm_mday)); + rtc_write (0x84, bin2bcd(tmp->tm_hour)); + rtc_write (0x82, bin2bcd(tmp->tm_min )); + rtc_write (0x80, bin2bcd(tmp->tm_sec )); +} + +void rtc_reset (void) +{ +} + +#endif diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c new file mode 100644 index 0000000..ab377ed --- /dev/null +++ b/drivers/rtc/mc146818.c @@ -0,0 +1,178 @@ +/* + * (C) Copyright 2001 + * Denis Peter MPL AG Switzerland. d.peter@mpl.ch + * + * 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 the MC146818 (PIXX4) RTC + */ + +/*#define DEBUG*/ + +#include <common.h> +#include <command.h> +#include <rtc.h> + +#if defined(CONFIG_RTC_MC146818) && defined(CONFIG_CMD_DATE) + +static uchar rtc_read (uchar reg); +static void rtc_write (uchar reg, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin(uchar c); + +#define RTC_PORT_MC146818 CFG_ISA_IO_BASE_ADDRESS + 0x70 +#define RTC_SECONDS 0x00 +#define RTC_SECONDS_ALARM 0x01 +#define RTC_MINUTES 0x02 +#define RTC_MINUTES_ALARM 0x03 +#define RTC_HOURS 0x04 +#define RTC_HOURS_ALARM 0x05 +#define RTC_DAY_OF_WEEK 0x06 +#define RTC_DATE_OF_MONTH 0x07 +#define RTC_MONTH 0x08 +#define RTC_YEAR 0x09 +#define RTC_CONFIG_A 0x0A +#define RTC_CONFIG_B 0x0B +#define RTC_CONFIG_C 0x0C +#define RTC_CONFIG_D 0x0D + + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon, year; + /* here check if rtc can be accessed */ + while((rtc_read(RTC_CONFIG_A)&0x80)==0x80); + sec = rtc_read (RTC_SECONDS); + min = rtc_read (RTC_MINUTES); + hour = rtc_read (RTC_HOURS); + mday = rtc_read (RTC_DATE_OF_MONTH); + wday = rtc_read (RTC_DAY_OF_WEEK); + mon = rtc_read (RTC_MONTH); + year = rtc_read (RTC_YEAR); +#ifdef CONFIG_AMIGAONEG3SE + wday -= 1; /* VIA 686 stores Sunday = 1, Monday = 2, ... */ +#endif +#ifdef RTC_DEBUG + printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, + hour, min, sec ); + printf ( "Alarms: month: %02x hour: %02x min: %02x sec: %02x\n", + rtc_read (RTC_CONFIG_D) & 0x3F, + rtc_read (RTC_HOURS_ALARM), + rtc_read (RTC_MINUTES_ALARM), + rtc_read (RTC_SECONDS_ALARM) ); +#endif + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon & 0x1F); + tmp->tm_year = bcd2bin (year); + tmp->tm_wday = bcd2bin (wday & 0x07); + if(tmp->tm_year<70) + tmp->tm_year+=2000; + else + tmp->tm_year+=1900; + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf ( "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); +#endif +} + +void rtc_set (struct rtc_time *tmp) +{ +#ifdef RTC_DEBUG + printf ( "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); +#endif + rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */ + + rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100)); + rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon)); +#ifdef CONFIG_AMIGAONEG3SE + rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday)+1); +#else + rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday)); +#endif + rtc_write (RTC_DATE_OF_MONTH, bin2bcd(tmp->tm_mday)); + rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour)); + rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min )); + rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec )); + rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */ + +} + +void rtc_reset (void) +{ + rtc_write(RTC_CONFIG_B,0x82); /* disables the RTC to update the regs */ + rtc_write(RTC_CONFIG_A,0x20); /* Normal OP */ + rtc_write(RTC_CONFIG_B,0x00); + rtc_write(RTC_CONFIG_B,0x00); + rtc_write(RTC_CONFIG_B,0x02); /* enables the RTC to update the regs */ +} + +/* ------------------------------------------------------------------------- */ + +#ifdef CFG_RTC_REG_BASE_ADDR +/* + * use direct memory access + */ +static uchar rtc_read (uchar reg) +{ + return(in8(CFG_RTC_REG_BASE_ADDR+reg)); +} + +static void rtc_write (uchar reg, uchar val) +{ + out8(CFG_RTC_REG_BASE_ADDR+reg, val); +} +#else +static uchar rtc_read (uchar reg) +{ + out8(RTC_PORT_MC146818,reg); + return(in8(RTC_PORT_MC146818+1)); +} + +static void rtc_write (uchar reg, uchar val) +{ + out8(RTC_PORT_MC146818,reg); + out8(RTC_PORT_MC146818+1,val); +} +#endif + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c new file mode 100644 index 0000000..27386e5 --- /dev/null +++ b/drivers/rtc/mcfrtc.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * 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 + */ + +#include <common.h> + +#if defined(CONFIG_MCFRTC) && defined(CONFIG_CMD_DATE) + +#include <command.h> +#include <rtc.h> +#include <asm/immap.h> +#include <asm/rtc.h> + +#undef RTC_DEBUG + +#ifndef CFG_MCFRTC_BASE +#error RTC_BASE is not defined! +#endif + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) +#define STARTOFTIME 1970 + +void rtc_get(struct rtc_time *tmp) +{ + volatile rtc_t *rtc = (rtc_t *) (CFG_MCFRTC_BASE); + + int rtc_days, rtc_hrs, rtc_mins; + int tim; + + rtc_days = rtc->days; + rtc_hrs = rtc->hourmin >> 8; + rtc_mins = RTC_HOURMIN_MINUTES(rtc->hourmin); + + tim = (rtc_days * 24) + rtc_hrs; + tim = (tim * 60) + rtc_mins; + tim = (tim * 60) + rtc->seconds; + + to_tm(tim, tmp); + + tmp->tm_yday = 0; + tmp->tm_isdst = 0; + +#ifdef RTC_DEBUG + printf("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); +#endif +} + +void rtc_set(struct rtc_time *tmp) +{ + volatile rtc_t *rtc = (rtc_t *) (CFG_MCFRTC_BASE); + + static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + int days, i, months; + + if (tmp->tm_year > 2037) { + printf("Unable to handle. Exceeding integer limitation!\n"); + tmp->tm_year = 2027; + } +#ifdef RTC_DEBUG + printf("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); +#endif + + /* calculate days by years */ + for (i = STARTOFTIME, days = 0; i < tmp->tm_year; i++) { + days += 365 + isleap(i); + } + + /* calculate days by months */ + months = tmp->tm_mon - 1; + for (i = 0; i < months; i++) { + days += month_days[i]; + + if (i == 1) + days += isleap(i); + } + + days += tmp->tm_mday - 1; + + rtc->days = days; + rtc->hourmin = (tmp->tm_hour << 8) | tmp->tm_min; + rtc->seconds = tmp->tm_sec; +} + +void rtc_reset(void) +{ + volatile rtc_t *rtc = (rtc_t *) (CFG_MCFRTC_BASE); + + if ((rtc->cr & RTC_CR_EN) == 0) { + printf("real-time-clock was stopped. Now starting...\n"); + rtc->cr |= RTC_CR_EN; + } + + rtc->cr |= RTC_CR_SWR; +} + +#endif /* CONFIG_MCFRTC && CONFIG_CMD_DATE */ diff --git a/drivers/rtc/mk48t59.c b/drivers/rtc/mk48t59.c new file mode 100644 index 0000000..bacdb5b --- /dev/null +++ b/drivers/rtc/mk48t59.c @@ -0,0 +1,237 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Andreas Heppel <aheppel@sysgo.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 the MK48T59 RTC + */ + +#undef RTC_DEBUG + +#include <common.h> +#include <command.h> +#include <config.h> +#include <rtc.h> +#include <mk48t59.h> + +#if defined(CONFIG_RTC_MK48T59) + +#if defined(CONFIG_BAB7xx) + +static uchar rtc_read (short reg) +{ + out8(RTC_PORT_ADDR0, reg & 0xFF); + out8(RTC_PORT_ADDR1, (reg>>8) & 0xFF); + return in8(RTC_PORT_DATA); +} + +static void rtc_write (short reg, uchar val) +{ + out8(RTC_PORT_ADDR0, reg & 0xFF); + out8(RTC_PORT_ADDR1, (reg>>8) & 0xFF); + out8(RTC_PORT_DATA, val); +} + +#elif defined(CONFIG_PCIPPC2) + +#include "../board/pcippc2/pcippc2.h" + +static uchar rtc_read (short reg) +{ + return in8(RTC(reg)); +} + +static void rtc_write (short reg, uchar val) +{ + out8(RTC(reg),val); +} + +#elif defined(CONFIG_AMIGAONEG3SE) + +#include "../board/MAI/AmigaOneG3SE/via686.h" +#include "../board/MAI/AmigaOneG3SE/memio.h" + + +static uchar rtc_read (short reg) +{ + out_byte(CMOS_ADDR, (uint8)reg); + return in_byte(CMOS_DATA); +} + +static void rtc_write (short reg, uchar val) +{ + out_byte(CMOS_ADDR, (uint8)reg); + out_byte(CMOS_DATA, (uint8)val); +} + +#elif defined(CONFIG_EVAL5200) + +static uchar rtc_read (short reg) +{ + return in8(RTC(reg)); +} + +static void rtc_write (short reg, uchar val) +{ + out8(RTC(reg),val); +} + +#else +# error Board specific rtc access functions should be supplied +#endif + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +/* ------------------------------------------------------------------------- */ + +void *nvram_read(void *dest, const short src, size_t count) +{ + uchar *d = (uchar *) dest; + short s = src; + + while (count--) + *d++ = rtc_read(s++); + + return dest; +} + +void nvram_write(short dest, const void *src, size_t count) +{ + short d = dest; + uchar *s = (uchar *) src; + + while (count--) + rtc_write(d++, *s++); +} + +#if defined(CONFIG_CMD_DATE) + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + uchar save_ctrl_a; + uchar sec, min, hour, mday, wday, mon, year; + + /* Simple: freeze the clock, read it and allow updates again */ + save_ctrl_a = rtc_read(RTC_CONTROLA); + + /* Set the register to read the value. */ + save_ctrl_a |= RTC_CA_READ; + rtc_write(RTC_CONTROLA, save_ctrl_a); + + sec = rtc_read (RTC_SECONDS); + min = rtc_read (RTC_MINUTES); + hour = rtc_read (RTC_HOURS); + mday = rtc_read (RTC_DAY_OF_MONTH); + wday = rtc_read (RTC_DAY_OF_WEEK); + mon = rtc_read (RTC_MONTH); + year = rtc_read (RTC_YEAR); + + /* re-enable update */ + save_ctrl_a &= ~RTC_CA_READ; + rtc_write(RTC_CONTROLA, save_ctrl_a); + +#ifdef RTC_DEBUG + printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, + hour, min, sec ); +#endif + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon & 0x1F); + tmp->tm_year = bcd2bin (year); + tmp->tm_wday = bcd2bin (wday & 0x07); + if(tmp->tm_year<70) + tmp->tm_year+=2000; + else + tmp->tm_year+=1900; + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf ( "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); +#endif +} + +void rtc_set (struct rtc_time *tmp) +{ + uchar save_ctrl_a; + +#ifdef RTC_DEBUG + printf ( "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); +#endif + save_ctrl_a = rtc_read(RTC_CONTROLA); + + save_ctrl_a |= RTC_CA_WRITE; + rtc_write(RTC_CONTROLA, save_ctrl_a); /* disables the RTC to update the regs */ + + rtc_write (RTC_YEAR, bin2bcd(tmp->tm_year % 100)); + rtc_write (RTC_MONTH, bin2bcd(tmp->tm_mon)); + + rtc_write (RTC_DAY_OF_WEEK, bin2bcd(tmp->tm_wday)); + rtc_write (RTC_DAY_OF_MONTH, bin2bcd(tmp->tm_mday)); + rtc_write (RTC_HOURS, bin2bcd(tmp->tm_hour)); + rtc_write (RTC_MINUTES, bin2bcd(tmp->tm_min )); + rtc_write (RTC_SECONDS, bin2bcd(tmp->tm_sec )); + + save_ctrl_a &= ~RTC_CA_WRITE; + rtc_write(RTC_CONTROLA, save_ctrl_a); /* enables the RTC to update the regs */ +} + +void rtc_reset (void) +{ + uchar control_b; + + /* + * Start oscillator here. + */ + control_b = rtc_read(RTC_CONTROLB); + + control_b &= ~RTC_CB_STOP; + rtc_write(RTC_CONTROLB, control_b); +} + +void rtc_set_watchdog(short multi, short res) +{ + uchar wd_value; + + wd_value = RTC_WDS | ((multi & 0x1F) << 2) | (res & 0x3); + rtc_write(RTC_WATCHDOG, wd_value); +} + +#endif +#endif /* CONFIG_RTC_MK48T59 */ diff --git a/drivers/rtc/mpc5xxx.c b/drivers/rtc/mpc5xxx.c new file mode 100644 index 0000000..216386a --- /dev/null +++ b/drivers/rtc/mpc5xxx.c @@ -0,0 +1,140 @@ +/* + * (C) Copyright 2004 + * Reinhard Meyer, EMK Elektronik GmbH + * r.meyer@emk-elektronik.de + * www.emk-elektronik.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 internal RTC of MPC52xx + *****************************************************************************/ +/*#define DEBUG*/ + +#include <common.h> +#include <command.h> +#include <rtc.h> + +#if defined(CONFIG_RTC_MPC5200) && defined(CONFIG_CMD_DATE) + +/***************************************************************************** + * this structure should be defined in mpc5200.h ... + *****************************************************************************/ +typedef struct rtc5200 { + volatile ulong tsr; /* MBAR+0x800: time set register */ + volatile ulong dsr; /* MBAR+0x804: data set register */ + volatile ulong nysr; /* MBAR+0x808: new year and stopwatch register */ + volatile ulong aier; /* MBAR+0x80C: alarm and interrupt enable register */ + volatile ulong ctr; /* MBAR+0x810: current time register */ + volatile ulong cdr; /* MBAR+0x814: current data register */ + volatile ulong asir; /* MBAR+0x818: alarm and stopwatch interupt register */ + volatile ulong piber; /* MBAR+0x81C: periodic interrupt and bus error register */ + volatile ulong trdr; /* MBAR+0x820: test register/divides register */ +} RTC5200; + +#define RTC_SET 0x02000000 +#define RTC_PAUSE 0x01000000 + +/***************************************************************************** + * get time + *****************************************************************************/ +void rtc_get (struct rtc_time *tmp) +{ + RTC5200 *rtc = (RTC5200 *) (CFG_MBAR+0x800); + ulong time, date, time2; + + /* read twice to avoid getting a funny time when the second is just changing */ + do { + time = rtc->ctr; + date = rtc->cdr; + time2 = rtc->ctr; + } while (time != time2); + + tmp->tm_year = date & 0xfff; + tmp->tm_mon = (date >> 24) & 0xf; + tmp->tm_mday = (date >> 16) & 0x1f; + tmp->tm_wday = (date >> 21) & 7; + /* sunday is 7 in 5200 but 0 in rtc_time */ + if (tmp->tm_wday == 7) + tmp->tm_wday = 0; + tmp->tm_hour = (time >> 16) & 0x1f; + tmp->tm_min = (time >> 8) & 0x3f; + tmp->tm_sec = time & 0x3f; + + 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); +} + +/***************************************************************************** + * set time + *****************************************************************************/ +void rtc_set (struct rtc_time *tmp) +{ + RTC5200 *rtc = (RTC5200 *) (CFG_MBAR+0x800); + ulong time, date, year; + + 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); + + time = (tmp->tm_hour << 16) | (tmp->tm_min << 8) | tmp->tm_sec; + date = (tmp->tm_mon << 16) | tmp->tm_mday; + if (tmp->tm_wday == 0) + date |= (7 << 8); + else + date |= (tmp->tm_wday << 8); + year = tmp->tm_year; + + /* mask unwanted bits that might show up when rtc_time is corrupt */ + time &= 0x001f3f3f; + date &= 0x001f071f; + year &= 0x00000fff; + + /* pause and set the RTC */ + rtc->nysr = year; + rtc->dsr = date | RTC_PAUSE; + udelay (1000); + rtc->dsr = date | RTC_PAUSE | RTC_SET; + udelay (1000); + rtc->dsr = date | RTC_PAUSE; + udelay (1000); + rtc->dsr = date; + udelay (1000); + + rtc->tsr = time | RTC_PAUSE; + udelay (1000); + rtc->tsr = time | RTC_PAUSE | RTC_SET; + udelay (1000); + rtc->tsr = time | RTC_PAUSE; + udelay (1000); + rtc->tsr = time; + udelay (1000); +} + +/***************************************************************************** + * reset rtc circuit + *****************************************************************************/ +void rtc_reset (void) +{ + return; /* nothing to do */ +} + +#endif diff --git a/drivers/rtc/mpc8xx.c b/drivers/rtc/mpc8xx.c new file mode 100644 index 0000000..8d10c0e --- /dev/null +++ b/drivers/rtc/mpc8xx.c @@ -0,0 +1,73 @@ +/* + * (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 internal RTC of MPC8xx + */ + +/*#define DEBUG*/ + +#include <common.h> +#include <command.h> +#include <rtc.h> + +#if defined(CONFIG_RTC_MPC8xx) && defined(CONFIG_CMD_DATE) + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + ulong tim; + + tim = immr->im_sit.sit_rtc; + + to_tm (tim, tmp); + + 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); +} + +void rtc_set (struct rtc_time *tmp) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + ulong tim; + + 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); + + tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + immr->im_sitk.sitk_rtck = KAPWR_KEY; + immr->im_sit.sit_rtc = tim; +} + +void rtc_reset (void) +{ + return; /* nothing to do */ +} + +#endif diff --git a/drivers/rtc/pcf8563.c b/drivers/rtc/pcf8563.c new file mode 100644 index 0000000..2d73d5d --- /dev/null +++ b/drivers/rtc/pcf8563.c @@ -0,0 +1,144 @@ +/* + * (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 Philips PCF8563 RTC + */ + +/* #define DEBUG */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_RTC_PCF8563) && defined(CONFIG_CMD_DATE) + +static uchar rtc_read (uchar reg); +static void rtc_write (uchar reg, uchar val); +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin(uchar c); + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + uchar sec, min, hour, mday, wday, mon_cent, year; + + sec = rtc_read (0x02); + min = rtc_read (0x03); + hour = rtc_read (0x04); + mday = rtc_read (0x05); + wday = rtc_read (0x06); + mon_cent= rtc_read (0x07); + year = rtc_read (0x08); + + debug ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon_cent, mday, wday, + hour, min, sec ); + debug ( "Alarms: wday: %02x day: %02x hour: %02x min: %02x\n", + rtc_read (0x0C), + rtc_read (0x0B), + rtc_read (0x0A), + rtc_read (0x09) ); + + if (sec & 0x80) { + puts ("### Warning: RTC Low Voltage - date/time not reliable\n"); + } + + tmp->tm_sec = bcd2bin (sec & 0x7F); + tmp->tm_min = bcd2bin (min & 0x7F); + tmp->tm_hour = bcd2bin (hour & 0x3F); + tmp->tm_mday = bcd2bin (mday & 0x3F); + tmp->tm_mon = bcd2bin (mon_cent & 0x1F); + tmp->tm_year = bcd2bin (year) + ((mon_cent & 0x80) ? 2000 : 1900); + tmp->tm_wday = bcd2bin (wday & 0x07); + 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); +} + +void rtc_set (struct rtc_time *tmp) +{ + uchar century; + + 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); + + rtc_write (0x08, bin2bcd(tmp->tm_year % 100)); + + century = (tmp->tm_year >= 2000) ? 0x80 : 0; + rtc_write (0x07, bin2bcd(tmp->tm_mon) | century); + + rtc_write (0x06, bin2bcd(tmp->tm_wday)); + rtc_write (0x05, bin2bcd(tmp->tm_mday)); + rtc_write (0x04, bin2bcd(tmp->tm_hour)); + rtc_write (0x03, bin2bcd(tmp->tm_min )); + rtc_write (0x02, bin2bcd(tmp->tm_sec )); +} + +void rtc_reset (void) +{ + /* clear all control & status registers */ + rtc_write (0x00, 0x00); + rtc_write (0x01, 0x00); + rtc_write (0x0D, 0x00); + + /* clear Voltage Low bit */ + rtc_write (0x02, rtc_read (0x02) & 0x7F); + + /* reset all alarms */ + rtc_write (0x09, 0x00); + rtc_write (0x0A, 0x00); + rtc_write (0x0B, 0x00); + rtc_write (0x0C, 0x00); +} + +/* ------------------------------------------------------------------------- */ + +static uchar rtc_read (uchar reg) +{ + return (i2c_reg_read (CFG_I2C_RTC_ADDR, reg)); +} + +static void rtc_write (uchar reg, uchar val) +{ + i2c_reg_write (CFG_I2C_RTC_ADDR, reg, val); +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +#endif diff --git a/drivers/rtc/rs5c372.c b/drivers/rtc/rs5c372.c new file mode 100644 index 0000000..3d1346e --- /dev/null +++ b/drivers/rtc/rs5c372.c @@ -0,0 +1,302 @@ +/* + * rs5c372.c + * + * Device driver for Ricoh's Real Time Controller RS5C372A. + * + * Copyright (C) 2004 Gary Jennejohn garyj@denx.de + * + * Based in part in ds1307.c - + * (C) Copyright 2001, 2002, 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Keith Outwater, keith_outwater@mvis.com` + * Steven Scholz, steven.scholz@imc-berlin.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 version 2 as + * published by the Free Software Foundation. + * + * 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 + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_RTC_RS5C372A) && defined(CONFIG_CMD_DATE) +/* + * Reads are always done starting with register 15, which requires some + * jumping-through-hoops to access the data correctly. + * + * Writes are always done starting with register 0. + */ + +#define DEBUG 0 + +#if DEBUG +static unsigned int rtc_debug = DEBUG; +#else +#define rtc_debug 0 /* gcc will remove all the debug code for us */ +#endif + +#ifndef CFG_I2C_RTC_ADDR +#define CFG_I2C_RTC_ADDR 0x32 +#endif + +#define RS5C372_RAM_SIZE 0x10 +#define RATE_32000HZ 0x80 /* Rate Select 32.000KHz */ +#define RATE_32768HZ 0x00 /* Rate Select 32.768KHz */ + +#define STATUS_XPT 0x10 /* data invalid because voltage was 0 */ + +#define USE_24HOUR_MODE 0x20 +#define TWELVE_HOUR_MODE(n) ((((n) >> 5) & 1) == 0) +#define HOURS_AP(n) (((n) >> 5) & 1) +#define HOURS_12(n) bcd2bin((n) & 0x1F) +#define HOURS_24(n) bcd2bin((n) & 0x3F) + + +static uchar bin2bcd (unsigned int n); +static unsigned bcd2bin (uchar c); + +static int setup_done = 0; + +static int +rs5c372_readram(unsigned char *buf, int len) +{ + int ret; + + ret = i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, len); + if (ret != 0) { + printf("%s: failed to read\n", __FUNCTION__); + return ret; + } + + if (buf[0] & STATUS_XPT) + printf("### Warning: RTC lost power\n"); + + return ret; +} + +static void +rs5c372_enable(void) +{ + unsigned char buf[RS5C372_RAM_SIZE + 1]; + int ret; + + /* note that this returns reg. 15 in buf[1] */ + ret = rs5c372_readram(&buf[1], RS5C372_RAM_SIZE); + if (ret != 0) { + printf("%s: failed\n", __FUNCTION__); + return; + } + + buf[0] = 0; + /* we want to start writing at register 0 so we have to copy the */ + /* register contents up one slot */ + for (ret = 2; ret < 9; ret++) + buf[ret - 1] = buf[ret]; + /* registers 0 to 6 (time values) are not touched */ + buf[8] = RATE_32768HZ; /* reg. 7 */ + buf[9] = 0; /* reg. 8 */ + buf[10] = 0; /* reg. 9 */ + buf[11] = 0; /* reg. 10 */ + buf[12] = 0; /* reg. 11 */ + buf[13] = 0; /* reg. 12 */ + buf[14] = 0; /* reg. 13 */ + buf[15] = 0; /* reg. 14 */ + buf[16] = USE_24HOUR_MODE; /* reg. 15 */ + ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1); + if (ret != 0) { + printf("%s: failed\n", __FUNCTION__); + return; + } + setup_done = 1; + + return; +} + +static void +rs5c372_convert_to_time(struct rtc_time *dt, unsigned char *buf) +{ + /* buf[0] is register 15 */ + dt->tm_sec = bcd2bin(buf[1]); + dt->tm_min = bcd2bin(buf[2]); + + if (TWELVE_HOUR_MODE(buf[0])) { + dt->tm_hour = HOURS_12(buf[3]); + if (HOURS_AP(buf[3])) /* PM */ + dt->tm_hour += 12; + } else /* 24-hour-mode */ + dt->tm_hour = HOURS_24(buf[3]); + + dt->tm_mday = bcd2bin(buf[5]); + dt->tm_mon = bcd2bin(buf[6]); + dt->tm_year = bcd2bin(buf[7]); + if (dt->tm_year >= 70) + dt->tm_year += 1900; + else + dt->tm_year += 2000; + /* 0 is Sunday */ + dt->tm_wday = bcd2bin(buf[4] & 0x07); + dt->tm_yday = 0; + dt->tm_isdst= 0; + + if(rtc_debug > 2) { + printf("rs5c372_convert_to_time: year = %d\n", dt->tm_year); + printf("rs5c372_convert_to_time: mon = %d\n", dt->tm_mon); + printf("rs5c372_convert_to_time: mday = %d\n", dt->tm_mday); + printf("rs5c372_convert_to_time: hour = %d\n", dt->tm_hour); + printf("rs5c372_convert_to_time: min = %d\n", dt->tm_min); + printf("rs5c372_convert_to_time: sec = %d\n", dt->tm_sec); + } +} + +/* + * Get the current time from the RTC + */ +void +rtc_get (struct rtc_time *tmp) +{ + unsigned char buf[RS5C372_RAM_SIZE]; + int ret; + + if (!setup_done) + rs5c372_enable(); + + if (!setup_done) + return; + + memset(buf, 0, sizeof(buf)); + + /* note that this returns reg. 15 in buf[0] */ + ret = rs5c372_readram(buf, RS5C372_RAM_SIZE); + if (ret != 0) { + printf("%s: failed\n", __FUNCTION__); + return; + } + + rs5c372_convert_to_time(tmp, buf); + + return; +} + +/* + * Set the RTC + */ +void +rtc_set (struct rtc_time *tmp) +{ + unsigned char buf[8], reg15; + int ret; + + if (!setup_done) + rs5c372_enable(); + + if (!setup_done) + return; + + if(rtc_debug > 2) { + printf("rtc_set: tm_year = %d\n", tmp->tm_year); + printf("rtc_set: tm_mon = %d\n", tmp->tm_mon); + printf("rtc_set: tm_mday = %d\n", tmp->tm_mday); + printf("rtc_set: tm_hour = %d\n", tmp->tm_hour); + printf("rtc_set: tm_min = %d\n", tmp->tm_min); + printf("rtc_set: tm_sec = %d\n", tmp->tm_sec); + } + + memset(buf, 0, sizeof(buf)); + + /* only read register 15 */ + ret = i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, 1); + + if (ret == 0) { + /* need to save register 15 */ + reg15 = buf[0]; + buf[0] = 0; /* register address on RS5C372 */ + buf[1] = bin2bcd(tmp->tm_sec); + buf[2] = bin2bcd(tmp->tm_min); + /* need to handle 12 hour mode */ + if (TWELVE_HOUR_MODE(reg15)) { + if (tmp->tm_hour >= 12) { /* PM */ + /* 12 PM is a special case */ + if (tmp->tm_hour == 12) + buf[3] = bin2bcd(tmp->tm_hour); + else + buf[3] = bin2bcd(tmp->tm_hour - 12); + buf[3] |= 0x20; + } + } else { + buf[3] = bin2bcd(tmp->tm_hour); + } + + buf[4] = bin2bcd(tmp->tm_wday); + buf[5] = bin2bcd(tmp->tm_mday); + buf[6] = bin2bcd(tmp->tm_mon); + if (tmp->tm_year < 1970 || tmp->tm_year > 2069) + printf("WARNING: year should be between 1970 and 2069!\n"); + buf[7] = bin2bcd(tmp->tm_year % 100); + + ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, 8); + if (ret != 0) + printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret); + } + + return; +} + +/* + * Reset the RTC. We set the date back to 1970-01-01. + */ +void +rtc_reset (void) +{ + struct rtc_time tmp; + + if (!setup_done) + rs5c372_enable(); + + if (!setup_done) + return; + + tmp.tm_year = 1970; + tmp.tm_mon = 1; + /* Jan. 1, 1970 was a Thursday */ + tmp.tm_wday= 4; + tmp.tm_mday= 1; + tmp.tm_hour = 0; + tmp.tm_min = 0; + tmp.tm_sec = 0; + + rtc_set(&tmp); + + printf ("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; +} + +static unsigned int +bcd2bin (unsigned char n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char +bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} +#endif diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c new file mode 100644 index 0000000..7f8b4fa --- /dev/null +++ b/drivers/rtc/s3c24x0_rtc.c @@ -0,0 +1,178 @@ +/* + * (C) Copyright 2003 + * David Müller ELSOFT AG Switzerland. d.mueller@elsoft.ch + * + * 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 the built-in Samsung S3C24X0 RTC + */ + +#include <common.h> +#include <command.h> + +#if defined(CONFIG_RTC_S3C24X0) && (defined(CONFIG_CMD_DATE)) + +#if defined(CONFIG_S3C2400) +#include <s3c2400.h> +#elif defined(CONFIG_S3C2410) +#include <s3c2410.h> +#endif + +#include <rtc.h> + +/*#define DEBUG*/ + +typedef enum { + RTC_ENABLE, + RTC_DISABLE +} RTC_ACCESS; + + +static inline void SetRTC_Access(RTC_ACCESS a) +{ + S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + switch (a) { + case RTC_ENABLE: + rtc->RTCCON |= 0x01; break; + + case RTC_DISABLE: + rtc->RTCCON &= ~0x01; break; + } +} + +static unsigned bcd2bin (uchar n) +{ + return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); +} + +static unsigned char bin2bcd (unsigned int n) +{ + return (((n / 10) << 4) | (n % 10)); +} + +/* ------------------------------------------------------------------------- */ + +void rtc_get (struct rtc_time *tmp) +{ + S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + uchar sec, min, hour, mday, wday, mon, year; + uchar a_sec,a_min, a_hour, a_date, a_mon, a_year, a_armed; + + /* enable access to RTC registers */ + SetRTC_Access(RTC_ENABLE); + + /* read RTC registers */ + do { + sec = rtc->BCDSEC; + min = rtc->BCDMIN; + hour = rtc->BCDHOUR; + mday = rtc->BCDDATE; + wday = rtc->BCDDAY; + mon = rtc->BCDMON; + year = rtc->BCDYEAR; + } while (sec != rtc->BCDSEC); + + /* read ALARM registers */ + a_sec = rtc->ALMSEC; + a_min = rtc->ALMMIN; + a_hour = rtc->ALMHOUR; + a_date = rtc->ALMDATE; + a_mon = rtc->ALMMON; + a_year = rtc->ALMYEAR; + a_armed = rtc->RTCALM; + + /* disable access to RTC registers */ + SetRTC_Access(RTC_DISABLE); + +#ifdef RTC_DEBUG + printf ( "Get RTC year: %02x mon/cent: %02x mday: %02x wday: %02x " + "hr: %02x min: %02x sec: %02x\n", + year, mon, mday, wday, + hour, min, sec); + printf ( "Alarms: %02x: year: %02x month: %02x date: %02x hour: %02x min: %02x sec: %02x\n", + a_armed, + a_year, a_mon, a_date, + a_hour, a_min, a_sec); +#endif + + tmp->tm_sec = bcd2bin(sec & 0x7F); + tmp->tm_min = bcd2bin(min & 0x7F); + tmp->tm_hour = bcd2bin(hour & 0x3F); + tmp->tm_mday = bcd2bin(mday & 0x3F); + tmp->tm_mon = bcd2bin(mon & 0x1F); + tmp->tm_year = bcd2bin(year); + tmp->tm_wday = bcd2bin(wday & 0x07); + if(tmp->tm_year<70) + tmp->tm_year+=2000; + else + tmp->tm_year+=1900; + tmp->tm_yday = 0; + tmp->tm_isdst= 0; +#ifdef RTC_DEBUG + printf ( "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); +#endif +} + +void rtc_set (struct rtc_time *tmp) +{ + S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + uchar sec, min, hour, mday, wday, mon, year; + +#ifdef RTC_DEBUG + printf ( "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); +#endif + year = bin2bcd(tmp->tm_year % 100); + mon = bin2bcd(tmp->tm_mon); + wday = bin2bcd(tmp->tm_wday); + mday = bin2bcd(tmp->tm_mday); + hour = bin2bcd(tmp->tm_hour); + min = bin2bcd(tmp->tm_min); + sec = bin2bcd(tmp->tm_sec); + + /* enable access to RTC registers */ + SetRTC_Access(RTC_ENABLE); + + /* write RTC registers */ + rtc->BCDSEC = sec; + rtc->BCDMIN = min; + rtc->BCDHOUR = hour; + rtc->BCDDATE = mday; + rtc->BCDDAY = wday; + rtc->BCDMON = mon; + rtc->BCDYEAR = year; + + /* disable access to RTC registers */ + SetRTC_Access(RTC_DISABLE); +} + +void rtc_reset (void) +{ + S3C24X0_RTC * const rtc = S3C24X0_GetBase_RTC(); + + rtc->RTCCON = (rtc->RTCCON & ~0x06) | 0x08; + rtc->RTCCON &= ~(0x08|0x01); +} + +#endif diff --git a/drivers/rtc/x1205.c b/drivers/rtc/x1205.c new file mode 100644 index 0000000..319f051 --- /dev/null +++ b/drivers/rtc/x1205.c @@ -0,0 +1,178 @@ +/* + * (C) Copyright 2007 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * based on a the Linux rtc-x1207.c driver which is: + * Copyright 2004 Karen Spearel + * Copyright 2005 Alessandro Zummo + * + * Information and datasheet: + * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html + * + * 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 Xicor/Intersil X1205 RTC + */ + +/* #define DEBUG */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> +#include <bcd.h> + +#if defined(CONFIG_RTC_X1205) && defined(CONFIG_CMD_DATE) + +#define CCR_SEC 0 +#define CCR_MIN 1 +#define CCR_HOUR 2 +#define CCR_MDAY 3 +#define CCR_MONTH 4 +#define CCR_YEAR 5 +#define CCR_WDAY 6 +#define CCR_Y2K 7 + +#define X1205_REG_SR 0x3F /* status register */ +#define X1205_REG_Y2K 0x37 +#define X1205_REG_DW 0x36 +#define X1205_REG_YR 0x35 +#define X1205_REG_MO 0x34 +#define X1205_REG_DT 0x33 +#define X1205_REG_HR 0x32 +#define X1205_REG_MN 0x31 +#define X1205_REG_SC 0x30 +#define X1205_REG_DTR 0x13 +#define X1205_REG_ATR 0x12 +#define X1205_REG_INT 0x11 +#define X1205_REG_0 0x10 +#define X1205_REG_Y2K1 0x0F +#define X1205_REG_DWA1 0x0E +#define X1205_REG_YRA1 0x0D +#define X1205_REG_MOA1 0x0C +#define X1205_REG_DTA1 0x0B +#define X1205_REG_HRA1 0x0A +#define X1205_REG_MNA1 0x09 +#define X1205_REG_SCA1 0x08 +#define X1205_REG_Y2K0 0x07 +#define X1205_REG_DWA0 0x06 +#define X1205_REG_YRA0 0x05 +#define X1205_REG_MOA0 0x04 +#define X1205_REG_DTA0 0x03 +#define X1205_REG_HRA0 0x02 +#define X1205_REG_MNA0 0x01 +#define X1205_REG_SCA0 0x00 + +#define X1205_CCR_BASE 0x30 /* Base address of CCR */ +#define X1205_ALM0_BASE 0x00 /* Base address of ALARM0 */ + +#define X1205_SR_RTCF 0x01 /* Clock failure */ +#define X1205_SR_WEL 0x02 /* Write Enable Latch */ +#define X1205_SR_RWEL 0x04 /* Register Write Enable */ + +#define X1205_DTR_DTR0 0x01 +#define X1205_DTR_DTR1 0x02 +#define X1205_DTR_DTR2 0x04 + +#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ + +static void rtc_write(int reg, u8 val) +{ + i2c_write(CFG_I2C_RTC_ADDR, reg, 2, &val, 1); +} + +/* + * In the routines that deal directly with the x1205 hardware, we use + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch + * Epoch is initialized as 2000. Time is set to UTC. + */ +void rtc_get(struct rtc_time *tm) +{ + u8 buf[8]; + + i2c_read(CFG_I2C_RTC_ADDR, X1205_CCR_BASE, 2, buf, 8); + + debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, " + "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", + __FUNCTION__, + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + tm->tm_sec = BCD2BIN(buf[CCR_SEC]); + tm->tm_min = BCD2BIN(buf[CCR_MIN]); + tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ + tm->tm_mday = BCD2BIN(buf[CCR_MDAY]); + tm->tm_mon = BCD2BIN(buf[CCR_MONTH]); /* mon is 0-11 */ + tm->tm_year = BCD2BIN(buf[CCR_YEAR]) + + (BCD2BIN(buf[CCR_Y2K]) * 100); + tm->tm_wday = buf[CCR_WDAY]; + + debug("%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); +} + +void rtc_set(struct rtc_time *tm) +{ + int i; + u8 buf[8]; + + 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); + + buf[CCR_SEC] = BIN2BCD(tm->tm_sec); + buf[CCR_MIN] = BIN2BCD(tm->tm_min); + + /* set hour and 24hr bit */ + buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL; + + buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); + + /* month, 1 - 12 */ + buf[CCR_MONTH] = BIN2BCD(tm->tm_mon); + + /* year, since the rtc epoch*/ + buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100); + buf[CCR_WDAY] = tm->tm_wday & 0x07; + buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100); + + /* this sequence is required to unlock the chip */ + rtc_write(X1205_REG_SR, X1205_SR_WEL); + rtc_write(X1205_REG_SR, X1205_SR_WEL | X1205_SR_RWEL); + + /* write register's data */ + for (i = 0; i < 8; i++) + rtc_write(X1205_CCR_BASE + i, buf[i]); + + rtc_write(X1205_REG_SR, 0); +} + +void rtc_reset(void) +{ + /* + * Nothing to do + */ +} + +#endif |