uboot/drivers/rtc/m41t94.c
<<
>>
Prefs
   1/*
   2 * Driver for ST M41T94 SPI RTC
   3 *
   4 * Taken from the Linux kernel drivier:
   5 * Copyright (C) 2008 Kim B. Heino
   6 *
   7 * Adaptation for U-Boot:
   8 * Copyright (C) 2009
   9 * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com>
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 */
  15
  16#include <common.h>
  17#include <rtc.h>
  18#include <spi.h>
  19
  20static struct spi_slave *slave;
  21
  22#define M41T94_REG_SECONDS      0x01
  23#define M41T94_REG_MINUTES      0x02
  24#define M41T94_REG_HOURS        0x03
  25#define M41T94_REG_WDAY         0x04
  26#define M41T94_REG_DAY          0x05
  27#define M41T94_REG_MONTH        0x06
  28#define M41T94_REG_YEAR         0x07
  29#define M41T94_REG_HT           0x0c
  30
  31#define M41T94_BIT_HALT         0x40
  32#define M41T94_BIT_STOP         0x80
  33#define M41T94_BIT_CB           0x40
  34#define M41T94_BIT_CEB          0x80
  35
  36int rtc_set(struct rtc_time *tm)
  37{
  38        u8 buf[8]; /* write cmd + 7 registers */
  39        int ret;
  40
  41        if (!slave) {
  42                slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS,
  43                                        CONFIG_M41T94_SPI_CS, 1000000,
  44                                        SPI_MODE_3);
  45                if (!slave)
  46                        return -1;
  47        }
  48        spi_claim_bus(slave);
  49
  50        buf[0] = 0x80 | M41T94_REG_SECONDS; /* write time + date */
  51        buf[M41T94_REG_SECONDS] = bin2bcd(tm->tm_sec);
  52        buf[M41T94_REG_MINUTES] = bin2bcd(tm->tm_min);
  53        buf[M41T94_REG_HOURS]   = bin2bcd(tm->tm_hour);
  54        buf[M41T94_REG_WDAY]    = bin2bcd(tm->tm_wday + 1);
  55        buf[M41T94_REG_DAY]     = bin2bcd(tm->tm_mday);
  56        buf[M41T94_REG_MONTH]   = bin2bcd(tm->tm_mon + 1);
  57
  58        buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB;
  59        if (tm->tm_year >= 100)
  60                buf[M41T94_REG_HOURS] |= M41T94_BIT_CB;
  61        buf[M41T94_REG_YEAR] = bin2bcd(tm->tm_year % 100);
  62
  63        ret = spi_xfer(slave, 64, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
  64        spi_release_bus(slave);
  65        return ret;
  66}
  67
  68int rtc_get(struct rtc_time *tm)
  69{
  70        u8 buf[2];
  71        int ret, hour;
  72
  73        if (!slave) {
  74                slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS,
  75                                        CONFIG_M41T94_SPI_CS, 1000000,
  76                                        SPI_MODE_3);
  77                if (!slave)
  78                        return -1;
  79        }
  80        spi_claim_bus(slave);
  81
  82        /* clear halt update bit */
  83        ret = spi_w8r8(slave, M41T94_REG_HT);
  84        if (ret < 0)
  85                return ret;
  86        if (ret & M41T94_BIT_HALT) {
  87                buf[0] = 0x80 | M41T94_REG_HT;
  88                buf[1] = ret & ~M41T94_BIT_HALT;
  89                spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
  90        }
  91
  92        /* clear stop bit */
  93        ret = spi_w8r8(slave, M41T94_REG_SECONDS);
  94        if (ret < 0)
  95                return ret;
  96        if (ret & M41T94_BIT_STOP) {
  97                buf[0] = 0x80 | M41T94_REG_SECONDS;
  98                buf[1] = ret & ~M41T94_BIT_STOP;
  99                spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
 100        }
 101
 102        tm->tm_sec  = bcd2bin(spi_w8r8(slave, M41T94_REG_SECONDS));
 103        tm->tm_min  = bcd2bin(spi_w8r8(slave, M41T94_REG_MINUTES));
 104        hour = spi_w8r8(slave, M41T94_REG_HOURS);
 105        tm->tm_hour = bcd2bin(hour & 0x3f);
 106        tm->tm_wday = bcd2bin(spi_w8r8(slave, M41T94_REG_WDAY)) - 1;
 107        tm->tm_mday = bcd2bin(spi_w8r8(slave, M41T94_REG_DAY));
 108        tm->tm_mon  = bcd2bin(spi_w8r8(slave, M41T94_REG_MONTH)) - 1;
 109        tm->tm_year = bcd2bin(spi_w8r8(slave, M41T94_REG_YEAR));
 110        if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB))
 111                tm->tm_year += 100;
 112
 113        spi_release_bus(slave);
 114        return 0;
 115}
 116
 117void rtc_reset(void)
 118{
 119        /*
 120         * Could not be tested as the reset pin is not wired on
 121         * the sbc35-ag20 board
 122         */
 123}
 124