1*5c4fa2eeSHeiko Schocher /* 2*5c4fa2eeSHeiko Schocher * (C) Copyright 2010 3*5c4fa2eeSHeiko Schocher * Heiko Schocher, DENX Software Engineering, hs@denx.de 4*5c4fa2eeSHeiko Schocher * 5*5c4fa2eeSHeiko Schocher * See file CREDITS for list of people who contributed to this 6*5c4fa2eeSHeiko Schocher * project. 7*5c4fa2eeSHeiko Schocher * 8*5c4fa2eeSHeiko Schocher * This program is free software; you can redistribute it and/or 9*5c4fa2eeSHeiko Schocher * modify it under the terms of the GNU General Public License as 10*5c4fa2eeSHeiko Schocher * published by the Free Software Foundation; either version 2 of 11*5c4fa2eeSHeiko Schocher * the License, or (at your option) any later version. 12*5c4fa2eeSHeiko Schocher * 13*5c4fa2eeSHeiko Schocher * This program is distributed in the hope that it will be useful, 14*5c4fa2eeSHeiko Schocher * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*5c4fa2eeSHeiko Schocher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*5c4fa2eeSHeiko Schocher * GNU General Public License for more details. 17*5c4fa2eeSHeiko Schocher * 18*5c4fa2eeSHeiko Schocher * You should have received a copy of the GNU General Public License 19*5c4fa2eeSHeiko Schocher * along with this program; if not, write to the Free Software 20*5c4fa2eeSHeiko Schocher * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21*5c4fa2eeSHeiko Schocher * MA 02111-1307 USA 22*5c4fa2eeSHeiko Schocher */ 23*5c4fa2eeSHeiko Schocher #include <common.h> 24*5c4fa2eeSHeiko Schocher #include <command.h> 25*5c4fa2eeSHeiko Schocher #include <i2c.h> 26*5c4fa2eeSHeiko Schocher #include <rtc.h> 27*5c4fa2eeSHeiko Schocher 28*5c4fa2eeSHeiko Schocher #define RTC_RV3029_CTRL_RESET 0x04 29*5c4fa2eeSHeiko Schocher #define RTC_RV3029_CTRL_SYS_R (1 << 4) 30*5c4fa2eeSHeiko Schocher 31*5c4fa2eeSHeiko Schocher #define RTC_RV3029_CLOCK_PAGE 0x08 32*5c4fa2eeSHeiko Schocher #define RTC_RV3029_PAGE_LEN 7 33*5c4fa2eeSHeiko Schocher 34*5c4fa2eeSHeiko Schocher #define RV3029C2_W_SECONDS 0x00 35*5c4fa2eeSHeiko Schocher #define RV3029C2_W_MINUTES 0x01 36*5c4fa2eeSHeiko Schocher #define RV3029C2_W_HOURS 0x02 37*5c4fa2eeSHeiko Schocher #define RV3029C2_W_DATE 0x03 38*5c4fa2eeSHeiko Schocher #define RV3029C2_W_DAYS 0x04 39*5c4fa2eeSHeiko Schocher #define RV3029C2_W_MONTHS 0x05 40*5c4fa2eeSHeiko Schocher #define RV3029C2_W_YEARS 0x06 41*5c4fa2eeSHeiko Schocher 42*5c4fa2eeSHeiko Schocher #define RV3029C2_REG_HR_12_24 (1 << 6) /* 24h/12h mode */ 43*5c4fa2eeSHeiko Schocher #define RV3029C2_REG_HR_PM (1 << 5) /* PM/AM bit in 12h mode */ 44*5c4fa2eeSHeiko Schocher 45*5c4fa2eeSHeiko Schocher int rtc_get( struct rtc_time *tmp ) 46*5c4fa2eeSHeiko Schocher { 47*5c4fa2eeSHeiko Schocher int ret; 48*5c4fa2eeSHeiko Schocher unsigned char buf[RTC_RV3029_PAGE_LEN]; 49*5c4fa2eeSHeiko Schocher 50*5c4fa2eeSHeiko Schocher ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CLOCK_PAGE, 1, buf, \ 51*5c4fa2eeSHeiko Schocher RTC_RV3029_PAGE_LEN); 52*5c4fa2eeSHeiko Schocher if (ret) { 53*5c4fa2eeSHeiko Schocher printf("%s: error reading RTC: %x\n", __func__, ret); 54*5c4fa2eeSHeiko Schocher return -1; 55*5c4fa2eeSHeiko Schocher } 56*5c4fa2eeSHeiko Schocher tmp->tm_sec = bcd2bin( buf[RV3029C2_W_SECONDS] & 0x7f); 57*5c4fa2eeSHeiko Schocher tmp->tm_min = bcd2bin( buf[RV3029C2_W_MINUTES] & 0x7f); 58*5c4fa2eeSHeiko Schocher if (buf[RV3029C2_W_HOURS] & RV3029C2_REG_HR_12_24) { 59*5c4fa2eeSHeiko Schocher /* 12h format */ 60*5c4fa2eeSHeiko Schocher tmp->tm_hour = bcd2bin(buf[RV3029C2_W_HOURS] & 0x1f); 61*5c4fa2eeSHeiko Schocher if (buf[RV3029C2_W_HOURS] & RV3029C2_REG_HR_PM) 62*5c4fa2eeSHeiko Schocher /* PM flag set */ 63*5c4fa2eeSHeiko Schocher tmp->tm_hour += 12; 64*5c4fa2eeSHeiko Schocher } else 65*5c4fa2eeSHeiko Schocher tmp->tm_hour = bcd2bin(buf[RV3029C2_W_HOURS] & 0x3f); 66*5c4fa2eeSHeiko Schocher 67*5c4fa2eeSHeiko Schocher tmp->tm_mday = bcd2bin( buf[RV3029C2_W_DATE] & 0x3F ); 68*5c4fa2eeSHeiko Schocher tmp->tm_mon = bcd2bin( buf[RV3029C2_W_MONTHS] & 0x1F ); 69*5c4fa2eeSHeiko Schocher tmp->tm_wday = bcd2bin( buf[RV3029C2_W_DAYS] & 0x07 ); 70*5c4fa2eeSHeiko Schocher /* RTC supports only years > 1999 */ 71*5c4fa2eeSHeiko Schocher tmp->tm_year = bcd2bin( buf[RV3029C2_W_YEARS]) + 2000; 72*5c4fa2eeSHeiko Schocher tmp->tm_yday = 0; 73*5c4fa2eeSHeiko Schocher tmp->tm_isdst = 0; 74*5c4fa2eeSHeiko Schocher 75*5c4fa2eeSHeiko Schocher #ifdef RTC_DEBUG 76*5c4fa2eeSHeiko Schocher printf( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 77*5c4fa2eeSHeiko Schocher tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 78*5c4fa2eeSHeiko Schocher tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); 79*5c4fa2eeSHeiko Schocher 80*5c4fa2eeSHeiko Schocher #endif 81*5c4fa2eeSHeiko Schocher return 0; 82*5c4fa2eeSHeiko Schocher } 83*5c4fa2eeSHeiko Schocher 84*5c4fa2eeSHeiko Schocher int rtc_set( struct rtc_time *tmp ) 85*5c4fa2eeSHeiko Schocher { 86*5c4fa2eeSHeiko Schocher int ret; 87*5c4fa2eeSHeiko Schocher unsigned char buf[RTC_RV3029_PAGE_LEN]; 88*5c4fa2eeSHeiko Schocher #ifdef RTC_DEBUG 89*5c4fa2eeSHeiko Schocher printf( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 90*5c4fa2eeSHeiko Schocher tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 91*5c4fa2eeSHeiko Schocher tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 92*5c4fa2eeSHeiko Schocher #endif 93*5c4fa2eeSHeiko Schocher 94*5c4fa2eeSHeiko Schocher if (tmp->tm_year < 2000) { 95*5c4fa2eeSHeiko Schocher printf("RTC: year %d < 2000 not possible\n", tmp->tm_year); 96*5c4fa2eeSHeiko Schocher return -1; 97*5c4fa2eeSHeiko Schocher } 98*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_SECONDS] = bin2bcd(tmp->tm_sec); 99*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_MINUTES] = bin2bcd(tmp->tm_min); 100*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_HOURS] = bin2bcd(tmp->tm_hour); 101*5c4fa2eeSHeiko Schocher /* set 24h format */ 102*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_HOURS] &= ~RV3029C2_REG_HR_12_24; 103*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_DATE] = bin2bcd(tmp->tm_mday); 104*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_DAYS] = bin2bcd(tmp->tm_wday); 105*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_MONTHS] = bin2bcd(tmp->tm_mon); 106*5c4fa2eeSHeiko Schocher tmp->tm_year -= 2000; 107*5c4fa2eeSHeiko Schocher buf[RV3029C2_W_YEARS] = bin2bcd(tmp->tm_year); 108*5c4fa2eeSHeiko Schocher ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CLOCK_PAGE, 1, 109*5c4fa2eeSHeiko Schocher buf, RTC_RV3029_PAGE_LEN); 110*5c4fa2eeSHeiko Schocher 111*5c4fa2eeSHeiko Schocher /* give the RTC some time to update */ 112*5c4fa2eeSHeiko Schocher udelay(1000); 113*5c4fa2eeSHeiko Schocher return 0; 114*5c4fa2eeSHeiko Schocher } 115*5c4fa2eeSHeiko Schocher 116*5c4fa2eeSHeiko Schocher void rtc_reset (void) 117*5c4fa2eeSHeiko Schocher { 118*5c4fa2eeSHeiko Schocher int ret; 119*5c4fa2eeSHeiko Schocher unsigned char buf[RTC_RV3029_PAGE_LEN]; 120*5c4fa2eeSHeiko Schocher 121*5c4fa2eeSHeiko Schocher buf[0] = RTC_RV3029_CTRL_SYS_R; 122*5c4fa2eeSHeiko Schocher ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL_RESET, 1, 123*5c4fa2eeSHeiko Schocher buf, 1); 124*5c4fa2eeSHeiko Schocher } 125