diff options
| author | wdenk <wdenk> | 2004-10-10 18:03:33 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2004-10-10 18:03:33 +0000 | 
| commit | b65085130aed33584d95502c20317ad4379c1ca6 (patch) | |
| tree | eed2284bd6c1d9336df1ba926a1c6f2be8b876ff /rtc/rs5c372.c | |
| parent | 2cbe571a5676a41aa32ff98e9b1a2934e3922574 (diff) | |
| download | olio-uboot-2014.01-b65085130aed33584d95502c20317ad4379c1ca6.tar.xz olio-uboot-2014.01-b65085130aed33584d95502c20317ad4379c1ca6.zip | |
Code Cleanup
Patch by Gary Jennejohn, 04 Oct 2004:
- fix I2C on at91rm9200
- add support for Ricoh RS5C372A RTC
Diffstat (limited to 'rtc/rs5c372.c')
| -rw-r--r-- | rtc/rs5c372.c | 303 | 
1 files changed, 303 insertions, 0 deletions
| diff --git a/rtc/rs5c372.c b/rtc/rs5c372.c new file mode 100644 index 000000000..0f8ec6224 --- /dev/null +++ b/rtc/rs5c372.c @@ -0,0 +1,303 @@ +/* + * rs5c372.c + * + * Device driver for Ricoh's Real Time Controller RS5C372A. + * + * Copyright (C) 2004 Gary Jennejohn garyj@denx.de + * + * Based in part in ds1307.c - + * (C) Copyright 2001, 2002, 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Keith Outwater, keith_outwater@mvis.com` + * Steven Scholz, steven.scholz@imc-berlin.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <rtc.h> +#include <i2c.h> + +#if defined(CONFIG_RTC_RS5C372A) && (CONFIG_COMMANDS & CFG_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(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, 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 /* defined(CONFIG_RTC_RS5C372A) && (CONFIG_COMMANDS & CFG_CMD_DATE) */ |