Initial revision
diff --git a/rtc/ds1302.c b/rtc/ds1302.c
new file mode 100644
index 0000000..ec5616a
--- /dev/null
+++ b/rtc/ds1302.c
@@ -0,0 +1,327 @@
+/*
+ * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip
+ *
+ * Rex G. Feany <rfeany@zumanetworks.com>
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+#if defined(CONFIG_RTC_DS1302) && (CONFIG_COMMANDS & CFG_CMD_DATE)
+
+/* GPP Pins */
+#define DATA		0x200
+#define SCLK		0x400
+#define RST		0x800
+
+/* Happy Fun Defines(tm) */
+#define RESET		rtc_go_low(RST), rtc_go_low(SCLK)
+#define N_RESET		rtc_go_high(RST), rtc_go_low(SCLK)
+
+#define CLOCK_HIGH	rtc_go_high(SCLK)
+#define CLOCK_LOW	rtc_go_low(SCLK)
+
+#define DATA_HIGH	rtc_go_high(DATA)
+#define DATA_LOW	rtc_go_low(DATA)
+#define DATA_READ	(GTREGREAD(GPP_VALUE) & DATA)
+
+#undef RTC_DEBUG
+
+#ifdef RTC_DEBUG
+#  define DPRINTF(x,args...)	printf("ds1302: " x , ##args)
+static inline void DUMP(const char *ptr, int num)
+{
+	while (num--) printf("%x ", *ptr++);
+	printf("]\n");
+}
+#else
+#  define DPRINTF(x,args...)
+#  define DUMP(ptr, num)
+#endif
+
+/* time data format for DS1302 */
+struct ds1302_st
+{
+	unsigned char CH:1;		/* clock halt 1=stop 0=start */
+	unsigned char sec10:3;
+	unsigned char sec:4;
+
+	unsigned char zero0:1;
+	unsigned char min10:3;
+	unsigned char min:4;
+
+	unsigned char fmt:1;		/* 1=12 hour 0=24 hour */
+	unsigned char zero1:1;
+	unsigned char hr10:2;	/* 10 (0-2) or am/pm (am/pm, 0-1) */
+	unsigned char hr:4;
+
+	unsigned char zero2:2;
+	unsigned char date10:2;
+	unsigned char date:4;
+
+	unsigned char zero3:3;
+	unsigned char month10:1;
+	unsigned char month:4;
+
+	unsigned char zero4:5;
+	unsigned char day:3; 		/* day of week */
+
+	unsigned char year10:4;
+	unsigned char year:4;
+
+	unsigned char WP:1;		/* write protect 1=protect 0=unprot */
+	unsigned char zero5:7;
+};
+
+static int ds1302_initted=0;
+
+/* Pin control */
+static inline void
+rtc_go_high(unsigned int mask)
+{
+	unsigned int f = GTREGREAD(GPP_VALUE) | mask;
+
+	GT_REG_WRITE(GPP_VALUE, f);
+}
+
+static inline void
+rtc_go_low(unsigned int mask)
+{
+	unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
+
+	GT_REG_WRITE(GPP_VALUE, f);
+}
+
+static inline void
+rtc_go_input(unsigned int mask)
+{
+	unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask;
+
+	GT_REG_WRITE(GPP_IO_CONTROL, f);
+}
+
+static inline void
+rtc_go_output(unsigned int mask)
+{
+	unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask;
+
+	GT_REG_WRITE(GPP_IO_CONTROL, f);
+}
+
+/* Access data in RTC */
+
+static void
+write_byte(unsigned char b)
+{
+	int i;
+	unsigned char mask=1;
+
+	for(i=0;i<8;i++) {
+		CLOCK_LOW;			/* Lower clock */
+		(b&mask)?DATA_HIGH:DATA_LOW;	/* set data */
+		udelay(1);
+		CLOCK_HIGH;		/* latch data with rising clock */
+		udelay(1);
+		mask=mask<<1;
+	}
+}
+
+static unsigned char
+read_byte(void)
+{
+	int i;
+	unsigned char mask=1;
+	unsigned char b=0;
+
+	for(i=0;i<8;i++) {
+		CLOCK_LOW;
+		udelay(1);
+		if (DATA_READ) b|=mask;	/* if this bit is high, set in b */
+		CLOCK_HIGH;		/* clock out next bit */
+		udelay(1);
+		mask=mask<<1;
+	}
+	return b;
+}
+
+static void
+read_ser_drv(unsigned char addr, unsigned char *buf, int count)
+{
+	int i;
+#ifdef RTC_DEBUG
+	char *foo = buf;
+#endif
+
+	DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr);
+
+	addr|=1;	/* READ */
+	N_RESET;
+	udelay(4);
+	write_byte(addr);
+	rtc_go_input(DATA); /* Put gpp pin into input mode */
+	udelay(1);
+	for(i=0;i<count;i++) *(buf++)=read_byte();
+	RESET;
+	rtc_go_output(DATA);/* Reset gpp for output */
+	udelay(4);
+
+	DUMP(foo, count);
+}
+
+static void
+write_ser_drv(unsigned char addr, unsigned char *buf, int count)
+{
+	int i;
+
+	DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr);
+	DUMP(buf, count);
+
+	addr&=~1;	/* WRITE */
+	N_RESET;
+	udelay(4);
+	write_byte(addr);
+	for(i=0;i<count;i++) write_byte(*(buf++));
+	RESET;
+	udelay(4);
+
+}
+
+void
+rtc_init(void)
+{
+    	struct ds1302_st bbclk;
+	unsigned char b;
+	int mod;
+
+	DPRINTF("init\n");
+
+	rtc_go_output(DATA|SCLK|RST);
+
+	/* disable write protect */
+	b = 0;
+	write_ser_drv(0x8e,&b,1);
+
+	/* enable trickle */
+	b = 0xa5;	/* 1010.0101 */
+	write_ser_drv(0x90,&b,1);
+
+	/* read burst */
+	read_ser_drv(0xbe, (unsigned char *)&bbclk, 8);
+
+	/* Sanity checks */
+	mod = 0;
+	if (bbclk.CH) {
+		printf("ds1302: Clock was halted, starting clock\n");
+		bbclk.CH=0;
+		mod=1;
+	}
+
+	if (bbclk.fmt) {
+		printf("ds1302: Clock was in 12 hour mode, fixing\n");
+		bbclk.fmt=0;
+		mod=1;
+	}
+
+	if (bbclk.year>9) {
+		printf("ds1302: Year was corrupted, fixing\n");
+		bbclk.year10=100;	/* 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/rtc/pcf8563.c b/rtc/pcf8563.c
new file mode 100644
index 0000000..97b09b8
--- /dev/null
+++ b/rtc/pcf8563.c
@@ -0,0 +1,144 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Date & Time support for Philips PCF8563 RTC
+ */
+
+/* #define	DEBUG	*/
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+#if defined(CONFIG_RTC_PCF8563) && (CONFIG_COMMANDS & CFG_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) {
+		printf ("### 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	/* CONFIG_RTC_PCF8563 && CFG_CMD_DATE */