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
  22#include <common.h>
  23#include <command.h>
  24#include <rtc.h>
  25#include <i2c.h>
  26
  27/*
  28 * Reads are always done starting with register 15, which requires some
  29 * jumping-through-hoops to access the data correctly.
  30 *
  31 * Writes are always done starting with register 0.
  32 */
  33
  34#define DEBUG 0
  35
  36#if DEBUG
  37static unsigned int rtc_debug = DEBUG;
  38#else
  39#define rtc_debug 0     /* gcc will remove all the debug code for us */
  40#endif
  41
  42#ifndef CONFIG_SYS_I2C_RTC_ADDR
  43#define CONFIG_SYS_I2C_RTC_ADDR 0x32
  44#endif
  45
  46#define RS5C372_RAM_SIZE 0x10
  47#define RATE_32000HZ    0x80    /* Rate Select 32.000KHz */
  48#define RATE_32768HZ    0x00    /* Rate Select 32.768KHz */
  49
  50#define STATUS_XPT  0x10    /* data invalid because voltage was 0 */
  51
  52#define USE_24HOUR_MODE 0x20
  53#define TWELVE_HOUR_MODE(n) ((((n) >> 5) & 1) == 0)
  54#define HOURS_AP(n)     (((n) >> 5) & 1)
  55#define HOURS_12(n)     bcd2bin((n) & 0x1F)
  56#define HOURS_24(n)     bcd2bin((n) & 0x3F)
  57
  58
  59static int setup_done = 0;
  60
  61static int
  62rs5c372_readram(unsigned char *buf, int len)
  63{
  64        int ret;
  65
  66        ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, len);
  67        if (ret != 0) {
  68                printf("%s: failed to read\n", __FUNCTION__);
  69                return ret;
  70        }
  71
  72        if (buf[0] & STATUS_XPT)
  73                printf("### Warning: RTC lost power\n");
  74
  75        return ret;
  76}
  77
  78static void
  79rs5c372_enable(void)
  80{
  81        unsigned char buf[RS5C372_RAM_SIZE + 1];
  82        int ret;
  83
  84        /* note that this returns reg. 15 in buf[1] */
  85        ret = rs5c372_readram(&buf[1], RS5C372_RAM_SIZE);
  86        if (ret != 0) {
  87                printf("%s: failed\n", __FUNCTION__);
  88                return;
  89        }
  90
  91        buf[0] = 0;
  92        /* we want to start writing at register 0 so we have to copy the */
  93        /* register contents up one slot */
  94        for (ret = 2; ret < 9; ret++)
  95                buf[ret - 1] = buf[ret];
  96        /* registers 0 to 6 (time values) are not touched */
  97        buf[8] = RATE_32768HZ; /* reg. 7 */
  98        buf[9] = 0; /* reg. 8 */
  99        buf[10] = 0; /* reg. 9 */
 100        buf[11] = 0; /* reg. 10 */
 101        buf[12] = 0; /* reg. 11 */
 102        buf[13] = 0; /* reg. 12 */
 103        buf[14] = 0; /* reg. 13 */
 104        buf[15] = 0; /* reg. 14 */
 105        buf[16] = USE_24HOUR_MODE; /* reg. 15 */
 106        ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1);
 107        if (ret != 0) {
 108                printf("%s: failed\n", __FUNCTION__);
 109                return;
 110        }
 111        setup_done = 1;
 112
 113        return;
 114}
 115
 116static void
 117rs5c372_convert_to_time(struct rtc_time *dt, unsigned char *buf)
 118{
 119        /* buf[0] is register 15 */
 120        dt->tm_sec = bcd2bin(buf[1]);
 121        dt->tm_min = bcd2bin(buf[2]);
 122
 123        if (TWELVE_HOUR_MODE(buf[0])) {
 124                dt->tm_hour = HOURS_12(buf[3]);
 125                if (HOURS_AP(buf[3])) /* PM */
 126                        dt->tm_hour += 12;
 127        } else /* 24-hour-mode */
 128                dt->tm_hour = HOURS_24(buf[3]);
 129
 130        dt->tm_mday = bcd2bin(buf[5]);
 131        dt->tm_mon = bcd2bin(buf[6]);
 132        dt->tm_year = bcd2bin(buf[7]);
 133        if (dt->tm_year >= 70)
 134                dt->tm_year += 1900;
 135        else
 136                dt->tm_year += 2000;
 137        /* 0 is Sunday */
 138        dt->tm_wday = bcd2bin(buf[4] & 0x07);
 139        dt->tm_yday = 0;
 140        dt->tm_isdst= 0;
 141
 142        if(rtc_debug > 2) {
 143                printf("rs5c372_convert_to_time: year = %d\n", dt->tm_year);
 144                printf("rs5c372_convert_to_time: mon  = %d\n", dt->tm_mon);
 145                printf("rs5c372_convert_to_time: mday = %d\n", dt->tm_mday);
 146                printf("rs5c372_convert_to_time: hour = %d\n", dt->tm_hour);
 147                printf("rs5c372_convert_to_time: min  = %d\n", dt->tm_min);
 148                printf("rs5c372_convert_to_time: sec  = %d\n", dt->tm_sec);
 149        }
 150}
 151
 152/*
 153 * Get the current time from the RTC
 154 */
 155int
 156rtc_get (struct rtc_time *tmp)
 157{
 158        unsigned char buf[RS5C372_RAM_SIZE];
 159        int ret;
 160
 161        if (!setup_done)
 162                rs5c372_enable();
 163
 164        if (!setup_done)
 165                return -1;
 166
 167        memset(buf, 0, sizeof(buf));
 168
 169        /* note that this returns reg. 15 in buf[0] */
 170        ret = rs5c372_readram(buf, RS5C372_RAM_SIZE);
 171        if (ret != 0) {
 172                printf("%s: failed\n", __FUNCTION__);
 173                return -1;
 174        }
 175
 176        rs5c372_convert_to_time(tmp, buf);
 177
 178        return 0;
 179}
 180
 181/*
 182 * Set the RTC
 183 */
 184int rtc_set (struct rtc_time *tmp)
 185{
 186        unsigned char buf[8], reg15;
 187        int ret;
 188
 189        if (!setup_done)
 190                rs5c372_enable();
 191
 192        if (!setup_done)
 193                return -1;
 194
 195        if(rtc_debug > 2) {
 196                printf("rtc_set: tm_year = %d\n", tmp->tm_year);
 197                printf("rtc_set: tm_mon  = %d\n", tmp->tm_mon);
 198                printf("rtc_set: tm_mday = %d\n", tmp->tm_mday);
 199                printf("rtc_set: tm_hour = %d\n", tmp->tm_hour);
 200                printf("rtc_set: tm_min  = %d\n", tmp->tm_min);
 201                printf("rtc_set: tm_sec  = %d\n", tmp->tm_sec);
 202        }
 203
 204        memset(buf, 0, sizeof(buf));
 205
 206        /* only read register 15 */
 207        ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 1);
 208
 209        if (ret == 0) {
 210                /* need to save register 15 */
 211                reg15 = buf[0];
 212                buf[0] = 0;     /* register address on RS5C372 */
 213                buf[1] = bin2bcd(tmp->tm_sec);
 214                buf[2] = bin2bcd(tmp->tm_min);
 215                /* need to handle 12 hour mode */
 216                if (TWELVE_HOUR_MODE(reg15)) {
 217                        if (tmp->tm_hour >= 12) { /* PM */
 218                                /* 12 PM is a special case */
 219                                if (tmp->tm_hour == 12)
 220                                        buf[3] = bin2bcd(tmp->tm_hour);
 221                                else
 222                                        buf[3] = bin2bcd(tmp->tm_hour - 12);
 223                                buf[3] |= 0x20;
 224                        }
 225                } else {
 226                        buf[3] = bin2bcd(tmp->tm_hour);
 227                }
 228
 229                buf[4] = bin2bcd(tmp->tm_wday);
 230                buf[5] = bin2bcd(tmp->tm_mday);
 231                buf[6] = bin2bcd(tmp->tm_mon);
 232                if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
 233                        printf("WARNING: year should be between 1970 and 2069!\n");
 234                buf[7] = bin2bcd(tmp->tm_year % 100);
 235
 236                ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 8);
 237                if (ret != 0) {
 238                        printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret);
 239                        return -1;
 240                }
 241        } else {
 242                return -1;
 243        }
 244
 245        return 0;
 246}
 247
 248/*
 249 * Reset the RTC.
 250 */
 251void
 252rtc_reset (void)
 253{
 254        if (!setup_done)
 255                rs5c372_enable();
 256}
 257