uboot/drivers/rtc/ds1302.c
<<
>>
Prefs
   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_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)
  34static 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 */
  45struct 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
  78static int ds1302_initted=0;
  79
  80/* Pin control */
  81static inline void
  82rtc_go_high(unsigned int mask)
  83{
  84        unsigned int f = GTREGREAD(GPP_VALUE) | mask;
  85
  86        GT_REG_WRITE(GPP_VALUE, f);
  87}
  88
  89static inline void
  90rtc_go_low(unsigned int mask)
  91{
  92        unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
  93
  94        GT_REG_WRITE(GPP_VALUE, f);
  95}
  96
  97static inline void
  98rtc_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
 105static inline void
 106rtc_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
 115static void
 116write_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
 131static unsigned char
 132read_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
 149static void
 150read_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
 173static void
 174write_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
 191void
 192rtc_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
 249void
 250rtc_reset(void)
 251{
 252        if(!ds1302_initted) rtc_init();
 253        /* TODO */
 254}
 255
 256int
 257rtc_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
 290int rtc_set(struct rtc_time *tmp)
 291{
 292        struct ds1302_st bbclk;
 293        unsigned char b=0;
 294
 295        if(!ds1302_initted) rtc_init();
 296
 297        DPRINTF("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
 298                tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
 299                tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 300
 301        memset(&bbclk,0,sizeof(bbclk));
 302        bbclk.CH=0; /* dont halt */
 303        bbclk.WP=1; /* write protect when we're done */
 304
 305        bbclk.sec10=tmp->tm_sec/10;
 306        bbclk.sec=tmp->tm_sec%10;
 307
 308        bbclk.min10=tmp->tm_min/10;
 309        bbclk.min=tmp->tm_min%10;
 310
 311        bbclk.hr10=tmp->tm_hour/10;
 312        bbclk.hr=tmp->tm_hour%10;
 313
 314        bbclk.day=tmp->tm_wday;
 315
 316        bbclk.date10=tmp->tm_mday/10;
 317        bbclk.date=tmp->tm_mday%10;
 318
 319        bbclk.month10=tmp->tm_mon/10;
 320        bbclk.month=tmp->tm_mon%10;
 321
 322        tmp->tm_year -= 1900;
 323        bbclk.year10=tmp->tm_year/10;
 324        bbclk.year=tmp->tm_year%10;
 325
 326        write_ser_drv(0x8e,&b,1);           /* disable write protect */
 327        write_ser_drv(0xbe,(unsigned char *)&bbclk, 8);     /* write burst */
 328
 329        return 0;
 330}
 331
 332#endif
 333