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