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