uboot/drivers/rtc/rs5c372.c
<<
>>
Prefs
   1/*
   2 * rs5c372.c
   3 *
   4 * Device driver for Ricoh's Real Time Controller RS5C372A.
   5 *
   6 * Copyright (C) 2004 Gary Jennejohn garyj@denx.de
   7 *
   8 * Based in part in ds1307.c -
   9 * (C) Copyright 2001, 2002, 2003
  10 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  11 * Keith Outwater, keith_outwater@mvis.com`
  12 * Steven Scholz, steven.scholz@imc-berlin.de
  13 *
  14 * See file CREDITS for list of people who contributed to this
  15 * project.
  16 *
  17 * This program is free software; you can redistribute it and/or modify
  18 * it under the terms of the GNU General Public License version 2 as
  19 * published by the Free Software Foundation.
  20 *
  21 * This program is distributed in the hope that it will be useful,
  22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24 * GNU General Public License for more details.
  25 *
  26 * You should have received a copy of the GNU General Public License
  27 * along with this program; if not, write to the Free Software
  28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  29 * MA 02111-1307 USA
  30 */
  31
  32#include <common.h>
  33#include <command.h>
  34#include <rtc.h>
  35#include <i2c.h>
  36
  37#if defined(CONFIG_CMD_DATE)
  38/*
  39 * Reads are always done starting with register 15, which requires some
  40 * jumping-through-hoops to access the data correctly.
  41 *
  42 * Writes are always done starting with register 0.
  43 */
  44
  45#define DEBUG 0
  46
  47#if DEBUG
  48static unsigned int rtc_debug = DEBUG;
  49#else
  50#define rtc_debug 0     /* gcc will remove all the debug code for us */
  51#endif
  52
  53#ifndef CONFIG_SYS_I2C_RTC_ADDR
  54#define CONFIG_SYS_I2C_RTC_ADDR 0x32
  55#endif
  56
  57#define RS5C372_RAM_SIZE 0x10
  58#define RATE_32000HZ    0x80    /* Rate Select 32.000KHz */
  59#define RATE_32768HZ    0x00    /* Rate Select 32.768KHz */
  60
  61#define STATUS_XPT  0x10    /* data invalid because voltage was 0 */
  62
  63#define USE_24HOUR_MODE 0x20
  64#define TWELVE_HOUR_MODE(n) ((((n) >> 5) & 1) == 0)
  65#define HOURS_AP(n)     (((n) >> 5) & 1)
  66#define HOURS_12(n)     bcd2bin((n) & 0x1F)
  67#define HOURS_24(n)     bcd2bin((n) & 0x3F)
  68
  69
  70static int setup_done = 0;
  71
  72static int
  73rs5c372_readram(unsigned char *buf, int len)
  74{
  75        int ret;
  76
  77        ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, len);
  78        if (ret != 0) {
  79                printf("%s: failed to read\n", __FUNCTION__);
  80                return ret;
  81        }
  82
  83        if (buf[0] & STATUS_XPT)
  84                printf("### Warning: RTC lost power\n");
  85
  86        return ret;
  87}
  88
  89static void
  90rs5c372_enable(void)
  91{
  92        unsigned char buf[RS5C372_RAM_SIZE + 1];
  93        int ret;
  94
  95        /* note that this returns reg. 15 in buf[1] */
  96        ret = rs5c372_readram(&buf[1], RS5C372_RAM_SIZE);
  97        if (ret != 0) {
  98                printf("%s: failed\n", __FUNCTION__);
  99                return;
 100        }
 101
 102        buf[0] = 0;
 103        /* we want to start writing at register 0 so we have to copy the */
 104        /* register contents up one slot */
 105        for (ret = 2; ret < 9; ret++)
 106                buf[ret - 1] = buf[ret];
 107        /* registers 0 to 6 (time values) are not touched */
 108        buf[8] = RATE_32768HZ; /* reg. 7 */
 109        buf[9] = 0; /* reg. 8 */
 110        buf[10] = 0; /* reg. 9 */
 111        buf[11] = 0; /* reg. 10 */
 112        buf[12] = 0; /* reg. 11 */
 113        buf[13] = 0; /* reg. 12 */
 114        buf[14] = 0; /* reg. 13 */
 115        buf[15] = 0; /* reg. 14 */
 116        buf[16] = USE_24HOUR_MODE; /* reg. 15 */
 117        ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1);
 118        if (ret != 0) {
 119                printf("%s: failed\n", __FUNCTION__);
 120                return;
 121        }
 122        setup_done = 1;
 123
 124        return;
 125}
 126
 127static void
 128rs5c372_convert_to_time(struct rtc_time *dt, unsigned char *buf)
 129{
 130        /* buf[0] is register 15 */
 131        dt->tm_sec = bcd2bin(buf[1]);
 132        dt->tm_min = bcd2bin(buf[2]);
 133
 134        if (TWELVE_HOUR_MODE(buf[0])) {
 135                dt->tm_hour = HOURS_12(buf[3]);
 136                if (HOURS_AP(buf[3])) /* PM */
 137                        dt->tm_hour += 12;
 138        } else /* 24-hour-mode */
 139                dt->tm_hour = HOURS_24(buf[3]);
 140
 141        dt->tm_mday = bcd2bin(buf[5]);
 142        dt->tm_mon = bcd2bin(buf[6]);
 143        dt->tm_year = bcd2bin(buf[7]);
 144        if (dt->tm_year >= 70)
 145                dt->tm_year += 1900;
 146        else
 147                dt->tm_year += 2000;
 148        /* 0 is Sunday */
 149        dt->tm_wday = bcd2bin(buf[4] & 0x07);
 150        dt->tm_yday = 0;
 151        dt->tm_isdst= 0;
 152
 153        if(rtc_debug > 2) {
 154                printf("rs5c372_convert_to_time: year = %d\n", dt->tm_year);
 155                printf("rs5c372_convert_to_time: mon  = %d\n", dt->tm_mon);
 156                printf("rs5c372_convert_to_time: mday = %d\n", dt->tm_mday);
 157                printf("rs5c372_convert_to_time: hour = %d\n", dt->tm_hour);
 158                printf("rs5c372_convert_to_time: min  = %d\n", dt->tm_min);
 159                printf("rs5c372_convert_to_time: sec  = %d\n", dt->tm_sec);
 160        }
 161}
 162
 163/*
 164 * Get the current time from the RTC
 165 */
 166int
 167rtc_get (struct rtc_time *tmp)
 168{
 169        unsigned char buf[RS5C372_RAM_SIZE];
 170        int ret;
 171
 172        if (!setup_done)
 173                rs5c372_enable();
 174
 175        if (!setup_done)
 176                return -1;
 177
 178        memset(buf, 0, sizeof(buf));
 179
 180        /* note that this returns reg. 15 in buf[0] */
 181        ret = rs5c372_readram(buf, RS5C372_RAM_SIZE);
 182        if (ret != 0) {
 183                printf("%s: failed\n", __FUNCTION__);
 184                return -1;
 185        }
 186
 187        rs5c372_convert_to_time(tmp, buf);
 188
 189        return 0;
 190}
 191
 192/*
 193 * Set the RTC
 194 */
 195int rtc_set (struct rtc_time *tmp)
 196{
 197        unsigned char buf[8], reg15;
 198        int ret;
 199
 200        if (!setup_done)
 201                rs5c372_enable();
 202
 203        if (!setup_done)
 204                return -1;
 205
 206        if(rtc_debug > 2) {
 207                printf("rtc_set: tm_year = %d\n", tmp->tm_year);
 208                printf("rtc_set: tm_mon  = %d\n", tmp->tm_mon);
 209                printf("rtc_set: tm_mday = %d\n", tmp->tm_mday);
 210                printf("rtc_set: tm_hour = %d\n", tmp->tm_hour);
 211                printf("rtc_set: tm_min  = %d\n", tmp->tm_min);
 212                printf("rtc_set: tm_sec  = %d\n", tmp->tm_sec);
 213        }
 214
 215        memset(buf, 0, sizeof(buf));
 216
 217        /* only read register 15 */
 218        ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 1);
 219
 220        if (ret == 0) {
 221                /* need to save register 15 */
 222                reg15 = buf[0];
 223                buf[0] = 0;     /* register address on RS5C372 */
 224                buf[1] = bin2bcd(tmp->tm_sec);
 225                buf[2] = bin2bcd(tmp->tm_min);
 226                /* need to handle 12 hour mode */
 227                if (TWELVE_HOUR_MODE(reg15)) {
 228                        if (tmp->tm_hour >= 12) { /* PM */
 229                                /* 12 PM is a special case */
 230                                if (tmp->tm_hour == 12)
 231                                        buf[3] = bin2bcd(tmp->tm_hour);
 232                                else
 233                                        buf[3] = bin2bcd(tmp->tm_hour - 12);
 234                                buf[3] |= 0x20;
 235                        }
 236                } else {
 237                        buf[3] = bin2bcd(tmp->tm_hour);
 238                }
 239
 240                buf[4] = bin2bcd(tmp->tm_wday);
 241                buf[5] = bin2bcd(tmp->tm_mday);
 242                buf[6] = bin2bcd(tmp->tm_mon);
 243                if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
 244                        printf("WARNING: year should be between 1970 and 2069!\n");
 245                buf[7] = bin2bcd(tmp->tm_year % 100);
 246
 247                ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 8);
 248                if (ret != 0) {
 249                        printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret);
 250                        return -1;
 251                }
 252        } else {
 253                return -1;
 254        }
 255
 256        return 0;
 257}
 258
 259/*
 260 * Reset the RTC. We set the date back to 1970-01-01.
 261 */
 262void
 263rtc_reset (void)
 264{
 265        struct rtc_time tmp;
 266
 267        if (!setup_done)
 268                rs5c372_enable();
 269
 270        if (!setup_done)
 271                return;
 272
 273        tmp.tm_year = 1970;
 274        tmp.tm_mon = 1;
 275        /* Jan. 1, 1970 was a Thursday */
 276        tmp.tm_wday= 4;
 277        tmp.tm_mday= 1;
 278        tmp.tm_hour = 0;
 279        tmp.tm_min = 0;
 280        tmp.tm_sec = 0;
 281
 282        rtc_set(&tmp);
 283
 284        printf ("RTC:   %4d-%02d-%02d %2d:%02d:%02d UTC\n",
 285                tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
 286                tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
 287
 288        return;
 289}
 290
 291#endif
 292