123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*
- * 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_CMD_DATE)
- /* GPP Pins */
- #define DATA 0x200
- #define SCLK 0x400
- #define RST 0x800
- /* Happy Fun Defines(tm) */
- #define RESET rtc_go_low(RST), rtc_go_low(SCLK)
- #define N_RESET rtc_go_high(RST), rtc_go_low(SCLK)
- #define CLOCK_HIGH rtc_go_high(SCLK)
- #define CLOCK_LOW rtc_go_low(SCLK)
- #define DATA_HIGH rtc_go_high(DATA)
- #define DATA_LOW rtc_go_low(DATA)
- #define DATA_READ (GTREGREAD(GPP_VALUE) & DATA)
- #undef RTC_DEBUG
- #ifdef RTC_DEBUG
- # define DPRINTF(x,args...) printf("ds1302: " x , ##args)
- static inline void DUMP(const char *ptr, int num)
- {
- while (num--) printf("%x ", *ptr++);
- printf("]\n");
- }
- #else
- # define DPRINTF(x,args...)
- # define DUMP(ptr, num)
- #endif
- /* time data format for DS1302 */
- struct ds1302_st
- {
- unsigned char CH:1; /* clock halt 1=stop 0=start */
- unsigned char sec10:3;
- unsigned char sec:4;
- unsigned char zero0:1;
- unsigned char min10:3;
- unsigned char min:4;
- unsigned char fmt:1; /* 1=12 hour 0=24 hour */
- unsigned char zero1:1;
- unsigned char hr10:2; /* 10 (0-2) or am/pm (am/pm, 0-1) */
- unsigned char hr:4;
- unsigned char zero2:2;
- unsigned char date10:2;
- unsigned char date:4;
- unsigned char zero3:3;
- unsigned char month10:1;
- unsigned char month:4;
- unsigned char zero4:5;
- unsigned char day:3; /* day of week */
- unsigned char year10:4;
- unsigned char year:4;
- unsigned char WP:1; /* write protect 1=protect 0=unprot */
- unsigned char zero5:7;
- };
- static int ds1302_initted=0;
- /* Pin control */
- static inline void
- rtc_go_high(unsigned int mask)
- {
- unsigned int f = GTREGREAD(GPP_VALUE) | mask;
- GT_REG_WRITE(GPP_VALUE, f);
- }
- static inline void
- rtc_go_low(unsigned int mask)
- {
- unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
- GT_REG_WRITE(GPP_VALUE, f);
- }
- static inline void
- rtc_go_input(unsigned int mask)
- {
- unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask;
- GT_REG_WRITE(GPP_IO_CONTROL, f);
- }
- static inline void
- rtc_go_output(unsigned int mask)
- {
- unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask;
- GT_REG_WRITE(GPP_IO_CONTROL, f);
- }
- /* Access data in RTC */
- static void
- write_byte(unsigned char b)
- {
- int i;
- unsigned char mask=1;
- for(i=0;i<8;i++) {
- CLOCK_LOW; /* Lower clock */
- (b&mask)?DATA_HIGH:DATA_LOW; /* set data */
- udelay(1);
- CLOCK_HIGH; /* latch data with rising clock */
- udelay(1);
- mask=mask<<1;
- }
- }
- static unsigned char
- read_byte(void)
- {
- int i;
- unsigned char mask=1;
- unsigned char b=0;
- for(i=0;i<8;i++) {
- CLOCK_LOW;
- udelay(1);
- if (DATA_READ) b|=mask; /* if this bit is high, set in b */
- CLOCK_HIGH; /* clock out next bit */
- udelay(1);
- mask=mask<<1;
- }
- return b;
- }
- static void
- read_ser_drv(unsigned char addr, unsigned char *buf, int count)
- {
- int i;
- #ifdef RTC_DEBUG
- char *foo = buf;
- #endif
- DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr);
- addr|=1; /* READ */
- N_RESET;
- udelay(4);
- write_byte(addr);
- rtc_go_input(DATA); /* Put gpp pin into input mode */
- udelay(1);
- for(i=0;i<count;i++) *(buf++)=read_byte();
- RESET;
- rtc_go_output(DATA);/* Reset gpp for output */
- udelay(4);
- DUMP(foo, count);
- }
- static void
- write_ser_drv(unsigned char addr, unsigned char *buf, int count)
- {
- int i;
- DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr);
- DUMP(buf, count);
- addr&=~1; /* WRITE */
- N_RESET;
- udelay(4);
- write_byte(addr);
- for(i=0;i<count;i++) write_byte(*(buf++));
- RESET;
- udelay(4);
- }
- void
- rtc_init(void)
- {
- struct ds1302_st bbclk;
- unsigned char b;
- int mod;
- DPRINTF("init\n");
- rtc_go_output(DATA|SCLK|RST);
- /* disable write protect */
- b = 0;
- write_ser_drv(0x8e,&b,1);
- /* enable trickle */
- b = 0xa5; /* 1010.0101 */
- write_ser_drv(0x90,&b,1);
- /* read burst */
- read_ser_drv(0xbe, (unsigned char *)&bbclk, 8);
- /* Sanity checks */
- mod = 0;
- if (bbclk.CH) {
- printf("ds1302: Clock was halted, starting clock\n");
- bbclk.CH=0;
- mod=1;
- }
- if (bbclk.fmt) {
- printf("ds1302: Clock was in 12 hour mode, fixing\n");
- bbclk.fmt=0;
- mod=1;
- }
- if (bbclk.year>9) {
- printf("ds1302: Year was corrupted, fixing\n");
- bbclk.year10=100/10; /* 2000 - why not? ;) */
- bbclk.year=0;
- mod=1;
- }
- /* Write out the changes if needed */
- if (mod) {
- /* enable write protect */
- bbclk.WP = 1;
- write_ser_drv(0xbe,(unsigned char *)&bbclk,8);
- } else {
- /* Else just turn write protect on */
- b = 0x80;
- write_ser_drv(0x8e,&b,1);
- }
- DPRINTF("init done\n");
- ds1302_initted=1;
- }
- void
- rtc_reset(void)
- {
- if(!ds1302_initted) rtc_init();
- /* TODO */
- }
- int
- rtc_get(struct rtc_time *tmp)
- {
- int rel = 0;
- 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");
- rel = -1;
- }
- 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 );
- return rel;
- }
- int 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 */
- return 0;
- }
- #endif
|