1 /* 2 * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip 3 * 4 * Rex G. Feany <rfeany@zumanetworks.com> 5 * 6 */ 7 8 #include <common.h> 9 #include <command.h> 10 #include <rtc.h> 11 12 /* GPP Pins */ 13 #define DATA 0x200 14 #define SCLK 0x400 15 #define RST 0x800 16 17 /* Happy Fun Defines(tm) */ 18 #define RESET rtc_go_low(RST), rtc_go_low(SCLK) 19 #define N_RESET rtc_go_high(RST), rtc_go_low(SCLK) 20 21 #define CLOCK_HIGH rtc_go_high(SCLK) 22 #define CLOCK_LOW rtc_go_low(SCLK) 23 24 #define DATA_HIGH rtc_go_high(DATA) 25 #define DATA_LOW rtc_go_low(DATA) 26 #define DATA_READ (GTREGREAD(GPP_VALUE) & DATA) 27 28 #undef RTC_DEBUG 29 30 #ifdef RTC_DEBUG 31 # define DPRINTF(x,args...) printf("ds1302: " x , ##args) 32 static inline void DUMP(const char *ptr, int num) 33 { 34 while (num--) printf("%x ", *ptr++); 35 printf("]\n"); 36 } 37 #else 38 # define DPRINTF(x,args...) 39 # define DUMP(ptr, num) 40 #endif 41 42 /* time data format for DS1302 */ 43 struct ds1302_st 44 { 45 unsigned char CH:1; /* clock halt 1=stop 0=start */ 46 unsigned char sec10:3; 47 unsigned char sec:4; 48 49 unsigned char zero0:1; 50 unsigned char min10:3; 51 unsigned char min:4; 52 53 unsigned char fmt:1; /* 1=12 hour 0=24 hour */ 54 unsigned char zero1:1; 55 unsigned char hr10:2; /* 10 (0-2) or am/pm (am/pm, 0-1) */ 56 unsigned char hr:4; 57 58 unsigned char zero2:2; 59 unsigned char date10:2; 60 unsigned char date:4; 61 62 unsigned char zero3:3; 63 unsigned char month10:1; 64 unsigned char month:4; 65 66 unsigned char zero4:5; 67 unsigned char day:3; /* day of week */ 68 69 unsigned char year10:4; 70 unsigned char year:4; 71 72 unsigned char WP:1; /* write protect 1=protect 0=unprot */ 73 unsigned char zero5:7; 74 }; 75 76 static int ds1302_initted=0; 77 78 /* Pin control */ 79 static inline void 80 rtc_go_high(unsigned int mask) 81 { 82 unsigned int f = GTREGREAD(GPP_VALUE) | mask; 83 84 GT_REG_WRITE(GPP_VALUE, f); 85 } 86 87 static inline void 88 rtc_go_low(unsigned int mask) 89 { 90 unsigned int f = GTREGREAD(GPP_VALUE) & ~mask; 91 92 GT_REG_WRITE(GPP_VALUE, f); 93 } 94 95 static inline void 96 rtc_go_input(unsigned int mask) 97 { 98 unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask; 99 100 GT_REG_WRITE(GPP_IO_CONTROL, f); 101 } 102 103 static inline void 104 rtc_go_output(unsigned int mask) 105 { 106 unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask; 107 108 GT_REG_WRITE(GPP_IO_CONTROL, f); 109 } 110 111 /* Access data in RTC */ 112 113 static void 114 write_byte(unsigned char b) 115 { 116 int i; 117 unsigned char mask=1; 118 119 for(i=0;i<8;i++) { 120 CLOCK_LOW; /* Lower clock */ 121 (b&mask)?DATA_HIGH:DATA_LOW; /* set data */ 122 udelay(1); 123 CLOCK_HIGH; /* latch data with rising clock */ 124 udelay(1); 125 mask=mask<<1; 126 } 127 } 128 129 static unsigned char 130 read_byte(void) 131 { 132 int i; 133 unsigned char mask=1; 134 unsigned char b=0; 135 136 for(i=0;i<8;i++) { 137 CLOCK_LOW; 138 udelay(1); 139 if (DATA_READ) b|=mask; /* if this bit is high, set in b */ 140 CLOCK_HIGH; /* clock out next bit */ 141 udelay(1); 142 mask=mask<<1; 143 } 144 return b; 145 } 146 147 static void 148 read_ser_drv(unsigned char addr, unsigned char *buf, int count) 149 { 150 int i; 151 #ifdef RTC_DEBUG 152 char *foo = buf; 153 #endif 154 155 DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr); 156 157 addr|=1; /* READ */ 158 N_RESET; 159 udelay(4); 160 write_byte(addr); 161 rtc_go_input(DATA); /* Put gpp pin into input mode */ 162 udelay(1); 163 for(i=0;i<count;i++) *(buf++)=read_byte(); 164 RESET; 165 rtc_go_output(DATA);/* Reset gpp for output */ 166 udelay(4); 167 168 DUMP(foo, count); 169 } 170 171 static void 172 write_ser_drv(unsigned char addr, unsigned char *buf, int count) 173 { 174 int i; 175 176 DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr); 177 DUMP(buf, count); 178 179 addr&=~1; /* WRITE */ 180 N_RESET; 181 udelay(4); 182 write_byte(addr); 183 for(i=0;i<count;i++) write_byte(*(buf++)); 184 RESET; 185 udelay(4); 186 187 } 188 189 void 190 rtc_init(void) 191 { 192 struct ds1302_st bbclk; 193 unsigned char b; 194 int mod; 195 196 DPRINTF("init\n"); 197 198 rtc_go_output(DATA|SCLK|RST); 199 200 /* disable write protect */ 201 b = 0; 202 write_ser_drv(0x8e,&b,1); 203 204 /* enable trickle */ 205 b = 0xa5; /* 1010.0101 */ 206 write_ser_drv(0x90,&b,1); 207 208 /* read burst */ 209 read_ser_drv(0xbe, (unsigned char *)&bbclk, 8); 210 211 /* Sanity checks */ 212 mod = 0; 213 if (bbclk.CH) { 214 printf("ds1302: Clock was halted, starting clock\n"); 215 bbclk.CH=0; 216 mod=1; 217 } 218 219 if (bbclk.fmt) { 220 printf("ds1302: Clock was in 12 hour mode, fixing\n"); 221 bbclk.fmt=0; 222 mod=1; 223 } 224 225 if (bbclk.year>9) { 226 printf("ds1302: Year was corrupted, fixing\n"); 227 bbclk.year10=100/10; /* 2000 - why not? ;) */ 228 bbclk.year=0; 229 mod=1; 230 } 231 232 /* Write out the changes if needed */ 233 if (mod) { 234 /* enable write protect */ 235 bbclk.WP = 1; 236 write_ser_drv(0xbe,(unsigned char *)&bbclk,8); 237 } else { 238 /* Else just turn write protect on */ 239 b = 0x80; 240 write_ser_drv(0x8e,&b,1); 241 } 242 DPRINTF("init done\n"); 243 244 ds1302_initted=1; 245 } 246 247 void 248 rtc_reset(void) 249 { 250 if(!ds1302_initted) rtc_init(); 251 /* TODO */ 252 } 253 254 int 255 rtc_get(struct rtc_time *tmp) 256 { 257 int rel = 0; 258 struct ds1302_st bbclk; 259 260 if(!ds1302_initted) rtc_init(); 261 262 read_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* read burst */ 263 264 if (bbclk.CH) { 265 printf("ds1302: rtc_get: Clock was halted, clock probably " 266 "corrupt\n"); 267 rel = -1; 268 } 269 270 tmp->tm_sec=10*bbclk.sec10+bbclk.sec; 271 tmp->tm_min=10*bbclk.min10+bbclk.min; 272 tmp->tm_hour=10*bbclk.hr10+bbclk.hr; 273 tmp->tm_wday=bbclk.day; 274 tmp->tm_mday=10*bbclk.date10+bbclk.date; 275 tmp->tm_mon=10*bbclk.month10+bbclk.month; 276 tmp->tm_year=10*bbclk.year10+bbclk.year + 1900; 277 278 tmp->tm_yday = 0; 279 tmp->tm_isdst= 0; 280 281 DPRINTF("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 282 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 283 tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); 284 285 return rel; 286 } 287 288 int rtc_set(struct rtc_time *tmp) 289 { 290 struct ds1302_st bbclk; 291 unsigned char b=0; 292 293 if(!ds1302_initted) rtc_init(); 294 295 DPRINTF("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 296 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 297 tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 298 299 memset(&bbclk,0,sizeof(bbclk)); 300 bbclk.CH=0; /* dont halt */ 301 bbclk.WP=1; /* write protect when we're done */ 302 303 bbclk.sec10=tmp->tm_sec/10; 304 bbclk.sec=tmp->tm_sec%10; 305 306 bbclk.min10=tmp->tm_min/10; 307 bbclk.min=tmp->tm_min%10; 308 309 bbclk.hr10=tmp->tm_hour/10; 310 bbclk.hr=tmp->tm_hour%10; 311 312 bbclk.day=tmp->tm_wday; 313 314 bbclk.date10=tmp->tm_mday/10; 315 bbclk.date=tmp->tm_mday%10; 316 317 bbclk.month10=tmp->tm_mon/10; 318 bbclk.month=tmp->tm_mon%10; 319 320 tmp->tm_year -= 1900; 321 bbclk.year10=tmp->tm_year/10; 322 bbclk.year=tmp->tm_year%10; 323 324 write_ser_drv(0x8e,&b,1); /* disable write protect */ 325 write_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* write burst */ 326 327 return 0; 328 } 329