m41t11.c 5.9 KB
Newer Older
W
wdenk 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * (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?
 */

26 27
/* #define DEBUG 1 */

W
wdenk 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
#include <common.h>
#include <command.h>
#include <rtc.h>
#include <i2c.h>

/*
	I Don't have an example config file but this
	is what should be done.

#define CONFIG_RTC_M41T11 1
#define CFG_I2C_RTC_ADDR 0x68
#if 0
#define CFG_M41T11_EXT_CENTURY_DATA
#else
#define CFG_M41T11_BASE_YEAR 2000
#endif
*/

M
Michal Simek 已提交
46
#if defined(CFG_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE)
W
wdenk 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

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)

Y
Yuri Tikhonov 已提交
99
int rtc_get (struct rtc_time *tmp)
W
wdenk 已提交
100
{
Y
Yuri Tikhonov 已提交
101
	int rel = 0;
W
wdenk 已提交
102
	uchar data[RTC_REG_CNT];
W
wdenk 已提交
103

W
wdenk 已提交
104
	i2c_read(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
W
wdenk 已提交
105

W
wdenk 已提交
106 107
	if( data[RTC_SEC_ADDR] & 0x80 ){
		printf( "m41t11 RTC Clock stopped!!!\n" );
Y
Yuri Tikhonov 已提交
108
		rel = -1;
W
wdenk 已提交
109
	}
W
wdenk 已提交
110 111 112 113 114 115
	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
W
wdenk 已提交
116 117 118
	tmp->tm_year = CFG_M41T11_BASE_YEAR
		+ bcd2bin(data[RTC_YEARS_ADDR])
		+ ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0);
W
wdenk 已提交
119
#else
W
wdenk 已提交
120 121 122 123 124
	{
		unsigned char cent;
		i2c_read(CFG_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, &cent, M41T11_YEAR_SIZE);
		if( !(data[RTC_HOUR_ADDR] & 0x80) ){
			printf( "m41t11 RTC: cann't keep track of years without CEB set\n" );
Y
Yuri Tikhonov 已提交
125
			rel = -1;
W
wdenk 已提交
126 127 128 129 130 131 132 133
		}
		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, &cent, M41T11_YEAR_SIZE);
		}
		tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]);
	}
W
wdenk 已提交
134 135 136 137 138 139 140 141
#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);
Y
Yuri Tikhonov 已提交
142 143

	return rel;
W
wdenk 已提交
144 145
}

146
int rtc_set (struct rtc_time *tmp)
W
wdenk 已提交
147
{
W
wdenk 已提交
148
	uchar data[RTC_REG_CNT];
W
wdenk 已提交
149 150 151 152 153 154 155 156 157 158 159 160

	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;

W
wdenk 已提交
161
	data[RTC_HOUR_ADDR]   |= 0x80;/*we will always use CEB*/
W
wdenk 已提交
162

W
wdenk 已提交
163
	data[RTC_YEARS_ADDR]  = bin2bcd(tmp->tm_year%100);/*same thing either way*/
W
wdenk 已提交
164
#ifndef CFG_M41T11_EXT_CENTURY_DATA
W
wdenk 已提交
165 166 167 168 169
	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;
W
wdenk 已提交
170
#else
W
wdenk 已提交
171 172 173 174 175 176
	{
		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, &cent, M41T11_YEAR_SIZE);
	}
W
wdenk 已提交
177
#endif
W
wdenk 已提交
178
	i2c_write(CFG_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT);
179 180

	return 0;
W
wdenk 已提交
181 182 183 184
}

void rtc_reset (void)
{
W
wdenk 已提交
185
	unsigned char val;
W
wdenk 已提交
186
	/* clear all control & status registers */
W
wdenk 已提交
187 188 189
	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);
W
wdenk 已提交
190

W
wdenk 已提交
191 192 193
	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);
W
wdenk 已提交
194 195 196 197
}

int rtc_store(int addr, unsigned char* data, int size)
{
W
wdenk 已提交
198 199 200 201
	/*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 );
W
wdenk 已提交
202 203 204 205
}

int rtc_recall(int addr, unsigned char* data, int size)
{
W
wdenk 已提交
206
	return i2c_read( CFG_I2C_RTC_ADDR, REG_CNT+addr, 1, data, size );
W
wdenk 已提交
207 208
}

209
#endif