uboot/board/etin/debris/phantom.c
<<
>>
Prefs
   1/*
   2 * board/eva/phantom.c
   3 *
   4 * Phantom RTC device driver for EVA
   5 *
   6 * Author: Sangmoon Kim
   7 *         dogoil@etinsys.com
   8 *
   9 * Copyright 2002 Etinsys Inc.
  10 *
  11 * This program is free software; you can redistribute  it and/or modify it
  12 * under  the terms of  the GNU General  Public License as published by the
  13 * Free Software Foundation;  either version 2 of the  License, or (at your
  14 * option) any later version.
  15 */
  16
  17#include <common.h>
  18#include <command.h>
  19#include <rtc.h>
  20
  21#if defined(CONFIG_CMD_DATE)
  22
  23#define RTC_BASE (CONFIG_SYS_NVRAM_BASE_ADDR + 0x7fff8)
  24
  25#define RTC_YEAR                ( RTC_BASE + 7 )
  26#define RTC_MONTH               ( RTC_BASE + 6 )
  27#define RTC_DAY_OF_MONTH        ( RTC_BASE + 5 )
  28#define RTC_DAY_OF_WEEK         ( RTC_BASE + 4 )
  29#define RTC_HOURS               ( RTC_BASE + 3 )
  30#define RTC_MINUTES             ( RTC_BASE + 2 )
  31#define RTC_SECONDS             ( RTC_BASE + 1 )
  32#define RTC_CENTURY             ( RTC_BASE + 0 )
  33
  34#define RTC_CONTROLA            RTC_CENTURY
  35#define RTC_CONTROLB            RTC_SECONDS
  36#define RTC_CONTROLC            RTC_DAY_OF_WEEK
  37
  38#define RTC_CA_WRITE            0x80
  39#define RTC_CA_READ             0x40
  40
  41#define RTC_CB_OSC_DISABLE      0x80
  42
  43#define RTC_CC_BATTERY_FLAG     0x80
  44#define RTC_CC_FREQ_TEST        0x40
  45
  46
  47static int phantom_flag = -1;
  48static int century_flag = -1;
  49
  50static uchar rtc_read(unsigned int addr)
  51{
  52        return *(volatile unsigned char *)(addr);
  53}
  54
  55static void rtc_write(unsigned int addr, uchar val)
  56{
  57        *(volatile unsigned char *)(addr) = val;
  58}
  59
  60static unsigned char phantom_rtc_sequence[] = {
  61        0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
  62};
  63
  64static unsigned char* phantom_rtc_read(int addr, unsigned char rtc[8])
  65{
  66        int i, j;
  67        unsigned char v;
  68        unsigned char save = rtc_read(addr);
  69
  70        for (j = 0; j < 8; j++) {
  71                v = phantom_rtc_sequence[j];
  72                for (i = 0; i < 8; i++) {
  73                        rtc_write(addr, v & 1);
  74                        v >>= 1;
  75                }
  76        }
  77        for (j = 0; j < 8; j++) {
  78                v = 0;
  79                for (i = 0; i < 8; i++) {
  80                        if(rtc_read(addr) & 1)
  81                                v |= 1 << i;
  82                }
  83                rtc[j] = v;
  84        }
  85        rtc_write(addr, save);
  86        return rtc;
  87}
  88
  89static void phantom_rtc_write(int addr, unsigned char rtc[8])
  90{
  91        int i, j;
  92        unsigned char v;
  93        unsigned char save = rtc_read(addr);
  94        for (j = 0; j < 8; j++) {
  95                v = phantom_rtc_sequence[j];
  96                for (i = 0; i < 8; i++) {
  97                        rtc_write(addr, v & 1);
  98                        v >>= 1;
  99                }
 100        }
 101        for (j = 0; j < 8; j++) {
 102                v = rtc[j];
 103                for (i = 0; i < 8; i++) {
 104                        rtc_write(addr, v & 1);
 105                        v >>= 1;
 106                }
 107        }
 108        rtc_write(addr, save);
 109}
 110
 111static int get_phantom_flag(void)
 112{
 113        int i;
 114        unsigned char rtc[8];
 115
 116        phantom_rtc_read(RTC_BASE, rtc);
 117
 118        for(i = 1; i < 8; i++) {
 119                if (rtc[i] != rtc[0])
 120                        return 1;
 121        }
 122        return 0;
 123}
 124
 125void rtc_reset(void)
 126{
 127        if (phantom_flag < 0)
 128                phantom_flag = get_phantom_flag();
 129
 130        if (phantom_flag) {
 131                unsigned char rtc[8];
 132                phantom_rtc_read(RTC_BASE, rtc);
 133                if(rtc[4] & 0x30) {
 134                        printf( "real-time-clock was stopped. Now starting...\n" );
 135                        rtc[4] &= 0x07;
 136                        phantom_rtc_write(RTC_BASE, rtc);
 137                }
 138        } else {
 139                uchar reg_a, reg_b, reg_c;
 140                reg_a = rtc_read( RTC_CONTROLA );
 141                reg_b = rtc_read( RTC_CONTROLB );
 142
 143                if ( reg_b & RTC_CB_OSC_DISABLE )
 144                {
 145                        printf( "real-time-clock was stopped. Now starting...\n" );
 146                        reg_a |= RTC_CA_WRITE;
 147                        reg_b &= ~RTC_CB_OSC_DISABLE;
 148                        rtc_write( RTC_CONTROLA, reg_a );
 149                        rtc_write( RTC_CONTROLB, reg_b );
 150                }
 151
 152                /* make sure read/write clock register bits are cleared */
 153                reg_a &= ~( RTC_CA_WRITE | RTC_CA_READ );
 154                rtc_write( RTC_CONTROLA, reg_a );
 155
 156                reg_c = rtc_read( RTC_CONTROLC );
 157                if (( reg_c & RTC_CC_BATTERY_FLAG ) == 0 )
 158                        printf( "RTC battery low. Clock setting may not be reliable.\n");
 159        }
 160}
 161
 162static int get_century_flag(void)
 163{
 164        int flag = 0;
 165        int bcd, century;
 166        bcd = rtc_read( RTC_CENTURY );
 167        century = bcd2bin( bcd & 0x3F );
 168        rtc_write( RTC_CENTURY, bin2bcd(century+1));
 169        if (bcd == rtc_read( RTC_CENTURY ))
 170                flag = 1;
 171        rtc_write( RTC_CENTURY, bcd);
 172        return flag;
 173}
 174
 175int rtc_get( struct rtc_time *tmp)
 176{
 177        if (phantom_flag < 0)
 178                phantom_flag = get_phantom_flag();
 179
 180        if (phantom_flag)
 181        {
 182                unsigned char rtc[8];
 183
 184                phantom_rtc_read(RTC_BASE, rtc);
 185
 186                tmp->tm_sec     = bcd2bin(rtc[1] & 0x7f);
 187                tmp->tm_min     = bcd2bin(rtc[2] & 0x7f);
 188                tmp->tm_hour    = bcd2bin(rtc[3] & 0x1f);
 189                tmp->tm_wday    = bcd2bin(rtc[4] & 0x7);
 190                tmp->tm_mday    = bcd2bin(rtc[5] & 0x3f);
 191                tmp->tm_mon     = bcd2bin(rtc[6] & 0x1f);
 192                tmp->tm_year    = bcd2bin(rtc[7]) + 1900;
 193                tmp->tm_yday = 0;
 194                tmp->tm_isdst = 0;
 195
 196                if( (rtc[3] & 0x80)  && (rtc[3] & 0x40) ) tmp->tm_hour += 12;
 197                if (tmp->tm_year < 1970) tmp->tm_year += 100;
 198        } else {
 199                uchar sec, min, hour;
 200                uchar mday, wday, mon, year;
 201
 202                int century;
 203
 204                uchar reg_a;
 205
 206                if (century_flag < 0)
 207                        century_flag = get_century_flag();
 208
 209                reg_a = rtc_read( RTC_CONTROLA );
 210                /* lock clock registers for read */
 211                rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_READ ));
 212
 213                sec     = rtc_read( RTC_SECONDS );
 214                min     = rtc_read( RTC_MINUTES );
 215                hour    = rtc_read( RTC_HOURS );
 216                mday    = rtc_read( RTC_DAY_OF_MONTH );
 217                wday    = rtc_read( RTC_DAY_OF_WEEK );
 218                mon     = rtc_read( RTC_MONTH );
 219                year    = rtc_read( RTC_YEAR );
 220                century = rtc_read( RTC_CENTURY );
 221
 222                /* unlock clock registers after read */
 223                rtc_write( RTC_CONTROLA, ( reg_a & ~RTC_CA_READ ));
 224
 225                tmp->tm_sec  = bcd2bin( sec  & 0x7F );
 226                tmp->tm_min  = bcd2bin( min  & 0x7F );
 227                tmp->tm_hour = bcd2bin( hour & 0x3F );
 228                tmp->tm_mday = bcd2bin( mday & 0x3F );
 229                tmp->tm_mon  = bcd2bin( mon & 0x1F );
 230                tmp->tm_wday = bcd2bin( wday & 0x07 );
 231
 232                if (century_flag) {
 233                        tmp->tm_year = bcd2bin( year ) +
 234                                ( bcd2bin( century & 0x3F ) * 100 );
 235                } else {
 236                        tmp->tm_year = bcd2bin( year ) + 1900;
 237                        if (tmp->tm_year < 1970) tmp->tm_year += 100;
 238                }
 239
 240                tmp->tm_yday = 0;
 241                tmp->tm_isdst= 0;
 242        }
 243
 244        return 0;
 245}
 246
 247int rtc_set( struct rtc_time *tmp )
 248{
 249        if (phantom_flag < 0)
 250                phantom_flag = get_phantom_flag();
 251
 252        if (phantom_flag) {
 253                uint year;
 254                unsigned char rtc[8];
 255
 256                year = tmp->tm_year;
 257                year -= (year < 2000) ? 1900 : 2000;
 258
 259                rtc[0] = bin2bcd(0);
 260                rtc[1] = bin2bcd(tmp->tm_sec);
 261                rtc[2] = bin2bcd(tmp->tm_min);
 262                rtc[3] = bin2bcd(tmp->tm_hour);
 263                rtc[4] = bin2bcd(tmp->tm_wday);
 264                rtc[5] = bin2bcd(tmp->tm_mday);
 265                rtc[6] = bin2bcd(tmp->tm_mon);
 266                rtc[7] = bin2bcd(year);
 267
 268                phantom_rtc_write(RTC_BASE, rtc);
 269        } else {
 270                uchar reg_a;
 271                if (century_flag < 0)
 272                        century_flag = get_century_flag();
 273
 274                /* lock clock registers for write */
 275                reg_a = rtc_read( RTC_CONTROLA );
 276                rtc_write( RTC_CONTROLA, ( reg_a | RTC_CA_WRITE ));
 277
 278                rtc_write( RTC_MONTH, bin2bcd( tmp->tm_mon ));
 279
 280                rtc_write( RTC_DAY_OF_WEEK, bin2bcd( tmp->tm_wday ));
 281                rtc_write( RTC_DAY_OF_MONTH, bin2bcd( tmp->tm_mday ));
 282                rtc_write( RTC_HOURS, bin2bcd( tmp->tm_hour ));
 283                rtc_write( RTC_MINUTES, bin2bcd( tmp->tm_min ));
 284                rtc_write( RTC_SECONDS, bin2bcd( tmp->tm_sec ));
 285
 286                /* break year up into century and year in century */
 287                if (century_flag) {
 288                        rtc_write( RTC_YEAR, bin2bcd( tmp->tm_year % 100 ));
 289                        rtc_write( RTC_CENTURY, bin2bcd( tmp->tm_year / 100 ));
 290                        reg_a &= 0xc0;
 291                        reg_a |= bin2bcd( tmp->tm_year / 100 );
 292                } else {
 293                        rtc_write(RTC_YEAR, bin2bcd(tmp->tm_year -
 294                                ((tmp->tm_year < 2000) ? 1900 : 2000)));
 295                }
 296
 297                /* unlock clock registers after read */
 298                rtc_write( RTC_CONTROLA, ( reg_a  & ~RTC_CA_WRITE ));
 299        }
 300
 301        return 0;
 302}
 303
 304#endif
 305