Commit 6b8548b0 authored by Albin Tonnerre's avatar Albin Tonnerre Committed by Wolfgang Denk

Add driver for the ST M41T94 SPI RTC

This RTC is used in some Calao boards. The driver code is taken from
the linux rtc-m41t94 driver
Signed-off-by: 's avatarAlbin Tonnerre <albin.tonnerre@free-electrons.com>
parent 885fc78c
......@@ -44,6 +44,7 @@ COBJS-$(CONFIG_RTC_ISL1208) += isl1208.o
COBJS-$(CONFIG_RTC_M41T11) += m41t11.o
COBJS-$(CONFIG_RTC_M41T60) += m41t60.o
COBJS-$(CONFIG_RTC_M41T62) += m41t62.o
COBJS-$(CONFIG_RTC_M41T94) += m41t94.o
COBJS-$(CONFIG_RTC_M48T35A) += m48t35ax.o
COBJS-$(CONFIG_RTC_MAX6900) += max6900.o
COBJS-$(CONFIG_RTC_MC13783) += mc13783-rtc.o
......
/*
* Driver for ST M41T94 SPI RTC
*
* Taken from the Linux kernel drivier:
* Copyright (C) 2008 Kim B. Heino
*
* Adaptation for U-Boot:
* Copyright (C) 2009
* Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <common.h>
#include <rtc.h>
#include <spi.h>
static struct spi_slave *slave;
#define M41T94_REG_SECONDS 0x01
#define M41T94_REG_MINUTES 0x02
#define M41T94_REG_HOURS 0x03
#define M41T94_REG_WDAY 0x04
#define M41T94_REG_DAY 0x05
#define M41T94_REG_MONTH 0x06
#define M41T94_REG_YEAR 0x07
#define M41T94_REG_HT 0x0c
#define M41T94_BIT_HALT 0x40
#define M41T94_BIT_STOP 0x80
#define M41T94_BIT_CB 0x40
#define M41T94_BIT_CEB 0x80
int rtc_set(struct rtc_time *tm)
{
u8 buf[8]; /* write cmd + 7 registers */
int ret;
if (!slave) {
slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS,
CONFIG_M41T94_SPI_CS, 1000000,
SPI_MODE_3);
if (!slave)
return -1;
}
spi_claim_bus(slave);
buf[0] = 0x80 | M41T94_REG_SECONDS; /* write time + date */
buf[M41T94_REG_SECONDS] = bin2bcd(tm->tm_sec);
buf[M41T94_REG_MINUTES] = bin2bcd(tm->tm_min);
buf[M41T94_REG_HOURS] = bin2bcd(tm->tm_hour);
buf[M41T94_REG_WDAY] = bin2bcd(tm->tm_wday + 1);
buf[M41T94_REG_DAY] = bin2bcd(tm->tm_mday);
buf[M41T94_REG_MONTH] = bin2bcd(tm->tm_mon + 1);
buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB;
if (tm->tm_year >= 100)
buf[M41T94_REG_HOURS] |= M41T94_BIT_CB;
buf[M41T94_REG_YEAR] = bin2bcd(tm->tm_year % 100);
ret = spi_xfer(slave, 64, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
spi_release_bus(slave);
return ret;
}
int rtc_get(struct rtc_time *tm)
{
u8 buf[2];
int ret, hour;
if (!slave) {
slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS,
CONFIG_M41T94_SPI_CS, 1000000,
SPI_MODE_3);
if (!slave)
return -1;
}
spi_claim_bus(slave);
/* clear halt update bit */
ret = spi_w8r8(slave, M41T94_REG_HT);
if (ret < 0)
return ret;
if (ret & M41T94_BIT_HALT) {
buf[0] = 0x80 | M41T94_REG_HT;
buf[1] = ret & ~M41T94_BIT_HALT;
spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
}
/* clear stop bit */
ret = spi_w8r8(slave, M41T94_REG_SECONDS);
if (ret < 0)
return ret;
if (ret & M41T94_BIT_STOP) {
buf[0] = 0x80 | M41T94_REG_SECONDS;
buf[1] = ret & ~M41T94_BIT_STOP;
spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
}
tm->tm_sec = bcd2bin(spi_w8r8(slave, M41T94_REG_SECONDS));
tm->tm_min = bcd2bin(spi_w8r8(slave, M41T94_REG_MINUTES));
hour = spi_w8r8(slave, M41T94_REG_HOURS);
tm->tm_hour = bcd2bin(hour & 0x3f);
tm->tm_wday = bcd2bin(spi_w8r8(slave, M41T94_REG_WDAY)) - 1;
tm->tm_mday = bcd2bin(spi_w8r8(slave, M41T94_REG_DAY));
tm->tm_mon = bcd2bin(spi_w8r8(slave, M41T94_REG_MONTH)) - 1;
tm->tm_year = bcd2bin(spi_w8r8(slave, M41T94_REG_YEAR));
if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB))
tm->tm_year += 100;
spi_release_bus(slave);
return 0;
}
void rtc_reset(void)
{
/*
* Could not be tested as the reset pin is not wired on
* the sbc35-ag20 board
*/
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment