From 0c698dcaa70275eb8814f665b545547cee013892 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sat, 24 Nov 2007 20:59:50 +0100 Subject: drivers/rtc : move rtc drivers to drivers/rtc Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- drivers/rtc/Makefile | 70 ++++++++ drivers/rtc/bf5xx_rtc.c | 143 +++++++++++++++ drivers/rtc/date.c | 156 +++++++++++++++++ drivers/rtc/ds12887.c | 238 +++++++++++++++++++++++++ drivers/rtc/ds1302.c | 327 ++++++++++++++++++++++++++++++++++ drivers/rtc/ds1306.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/rtc/ds1307.c | 204 +++++++++++++++++++++ drivers/rtc/ds1337.c | 191 ++++++++++++++++++++ drivers/rtc/ds1374.c | 253 ++++++++++++++++++++++++++ drivers/rtc/ds1556.c | 206 ++++++++++++++++++++++ drivers/rtc/ds164x.c | 200 +++++++++++++++++++++ drivers/rtc/ds174x.c | 202 +++++++++++++++++++++ drivers/rtc/ds3231.c | 193 ++++++++++++++++++++ drivers/rtc/m41t11.c | 202 +++++++++++++++++++++ drivers/rtc/m48t35ax.c | 166 ++++++++++++++++++ drivers/rtc/max6900.c | 131 ++++++++++++++ drivers/rtc/mc146818.c | 178 +++++++++++++++++++ drivers/rtc/mcfrtc.c | 121 +++++++++++++ drivers/rtc/mk48t59.c | 237 +++++++++++++++++++++++++ drivers/rtc/mpc5xxx.c | 140 +++++++++++++++ drivers/rtc/mpc8xx.c | 73 ++++++++ drivers/rtc/pcf8563.c | 144 +++++++++++++++ drivers/rtc/rs5c372.c | 302 ++++++++++++++++++++++++++++++++ drivers/rtc/s3c24x0_rtc.c | 178 +++++++++++++++++++ 24 files changed, 4693 insertions(+) create mode 100644 drivers/rtc/Makefile create mode 100644 drivers/rtc/bf5xx_rtc.c create mode 100644 drivers/rtc/date.c create mode 100644 drivers/rtc/ds12887.c create mode 100644 drivers/rtc/ds1302.c create mode 100644 drivers/rtc/ds1306.c create mode 100644 drivers/rtc/ds1307.c create mode 100644 drivers/rtc/ds1337.c create mode 100644 drivers/rtc/ds1374.c create mode 100644 drivers/rtc/ds1556.c create mode 100644 drivers/rtc/ds164x.c create mode 100644 drivers/rtc/ds174x.c create mode 100644 drivers/rtc/ds3231.c create mode 100644 drivers/rtc/m41t11.c create mode 100644 drivers/rtc/m48t35ax.c create mode 100644 drivers/rtc/max6900.c create mode 100644 drivers/rtc/mc146818.c create mode 100644 drivers/rtc/mcfrtc.c create mode 100644 drivers/rtc/mk48t59.c create mode 100644 drivers/rtc/mpc5xxx.c create mode 100644 drivers/rtc/mpc8xx.c create mode 100644 drivers/rtc/pcf8563.c create mode 100644 drivers/rtc/rs5c372.c create mode 100644 drivers/rtc/s3c24x0_rtc.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile new file mode 100644 index 00000000000..4a22b0d94ff --- /dev/null +++ b/drivers/rtc/Makefile @@ -0,0 +1,70 @@ +# +# (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 += 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 := $(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 00000000000..8856bb9b5f8 --- /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 +#include +#include + +#if defined(CONFIG_RTC_BFIN) && defined(CONFIG_CMD_DATE) + +#include +#include + +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 00000000000..a83a7235ab6 --- /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 +#include +#include + +#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 00000000000..84fecf01940 --- /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 +#include +#include +#include + +#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 00000000000..55af1302d57 --- /dev/null +++ b/drivers/rtc/ds1302.c @@ -0,0 +1,327 @@ +/* + * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip + * + * Rex G. Feany + * + */ + +#include +#include +#include + +#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;i9) { + 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 00000000000..89e433dabd8 --- /dev/null +++ b/drivers/rtc/ds1306.c @@ -0,0 +1,438 @@ +/* + * (C) Copyright 2002 SIXNET, dge@sixnetio.com. + * + * (C) Copyright 2004, Li-Pro.Net + * Stephan Linz + * + * 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 +#include +#include +#include + +#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 00000000000..c882d7989a0 --- /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 +#include +#include +#include + +#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 00000000000..c636ac5948f --- /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 +#include +#include +#include + +#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 00000000000..e773dd92615 --- /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 +#include +#include +#include + +#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 00000000000..4365cfb9813 --- /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 , 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 +#include +#include + + +#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 00000000000..bff22b9a058 --- /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 , 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 +#include +#include + + +#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 00000000000..5f85a68170b --- /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 +#include +#include + +#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 00000000000..fe11b869f55 --- /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 +#include +#include +#include + +#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 00000000000..81da33a31e1 --- /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 +#include +#include +#include + +/* + 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/m48t35ax.c b/drivers/rtc/m48t35ax.c new file mode 100644 index 00000000000..0a0ffa8aac1 --- /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 +#include +#include +#include + +#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 00000000000..c75a8e04c24 --- /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 +#include +#include +#include + +#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 00000000000..ab377ed73e5 --- /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 +#include +#include + +#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 00000000000..27386e586a6 --- /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 + +#if defined(CONFIG_MCFRTC) && defined(CONFIG_CMD_DATE) + +#include +#include +#include +#include + +#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 00000000000..bacdb5b70ba --- /dev/null +++ b/drivers/rtc/mk48t59.c @@ -0,0 +1,237 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * 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 +#include +#include +#include +#include + +#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 00000000000..216386aba05 --- /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 +#include +#include + +#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 00000000000..8d10c0e465e --- /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 +#include +#include + +#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 00000000000..2d73d5d7ef9 --- /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 +#include +#include +#include + +#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 00000000000..3d1346eaa7a --- /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 +#include +#include +#include + +#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 00000000000..7f8b4fad0dd --- /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 +#include + +#if defined(CONFIG_RTC_S3C24X0) && (defined(CONFIG_CMD_DATE)) + +#if defined(CONFIG_S3C2400) +#include +#elif defined(CONFIG_S3C2410) +#include +#endif + +#include + +/*#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 -- cgit v1.2.3 From 8809a2713b1ceaf3da55d9d785470294f15de06a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 11 Dec 2007 11:46:01 +0100 Subject: rtc: Fix merging problem Signed-off-by: Stefan Roese --- drivers/rtc/x1205.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 drivers/rtc/x1205.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/x1205.c b/drivers/rtc/x1205.c new file mode 100644 index 00000000000..319f0512ca8 --- /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 +#include +#include +#include +#include + +#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 -- cgit v1.2.3 From 12618278688ea9b3d76536960a5ad2e3790fac40 Mon Sep 17 00:00:00 2001 From: Larry Johnson Date: Sat, 22 Dec 2007 15:14:00 -0500 Subject: Add driver for STMicroelectronics M41T60 RTC This driver is based on the driver for the M41T11. In the intended application, the RTC will be powered by a large capacitor, rather than a battery. The driver therefore checks to see whether the RTC has lost power. The chip's OUT bit is normally reset from its power-up state. If the OUT bit is read as set, or if the date and time are not valid, then the RTC is assumed to have lost power, and its date and time are reset to 1900-01-01 00:00:00. Support for adjusting the speed of the clock to improve accuracy is provided through an environment variable. Signed-off-by: Larry Johnson --- drivers/rtc/Makefile | 1 + drivers/rtc/m41t60.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 drivers/rtc/m41t60.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1d6016ef87f..e5ee6113506 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -40,6 +40,7 @@ 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 diff --git a/drivers/rtc/m41t60.c b/drivers/rtc/m41t60.c new file mode 100644 index 00000000000..7c80143e684 --- /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 +#include +#include +#include + +#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 */ -- cgit v1.2.3