| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id: rtc_as3514.c 12131 2007-01-27 20:48:48Z dan_a $ |
| * |
| * Copyright (C) 2007 by Barry Wardell |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| #include <stdbool.h> |
| #include "rtc.h" |
| #include "i2c-pp.h" |
| #include "as3514.h" |
| |
| #define MINUTE_SECONDS 60 |
| #define HOUR_SECONDS 3600 |
| #define DAY_SECONDS 86400 |
| #define WEEK_SECONDS 604800 |
| #define YEAR_SECONDS 31536000 |
| #define LEAP_YEAR_SECONDS 31622400 |
| |
| #define BCD2DEC(X) (((((X)>>4) & 0x0f) * 10) + ((X) & 0xf)) |
| #define DEC2BCD(X) ((((X)/10)<<4) | ((X)%10)) |
| |
| /* Days in each month */ |
| static unsigned int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
| |
| static inline bool is_leapyear(int year) |
| { |
| if( ((year%4)==0) && (((year%100)!=0) || ((year%400)==0)) ) |
| return true; |
| else |
| return false; |
| } |
| |
| void rtc_init(void) |
| { |
| } |
| |
| int rtc_read_datetime(unsigned char* buf) |
| { |
| char tmp[4]; |
| int year; |
| int i; |
| unsigned int seconds; |
| |
| /* RTC_AS3514's slave address is 0x46*/ |
| for (i=0;i<4;i++){ |
| tmp[i] = i2c_readbyte(AS3514_I2C_ADDR, AS3514_RTC_0 + i); |
| } |
| seconds = tmp[0] + (tmp[1]<<8) + (tmp[2]<<16) + (tmp[3]<<24); |
| |
| /* Convert seconds since Jan-1-1980 to format compatible with |
| * get_time() from firmware/common/timefuncs.c */ |
| |
| /* weekday */ |
| buf[3] = ((seconds % WEEK_SECONDS) / DAY_SECONDS + 2) % 7; |
| |
| /* Year */ |
| year = 1980; |
| while(seconds>=LEAP_YEAR_SECONDS) |
| { |
| if(is_leapyear(year)){ |
| seconds -= LEAP_YEAR_SECONDS; |
| } else { |
| seconds -= YEAR_SECONDS; |
| } |
| |
| year++; |
| } |
| |
| if(is_leapyear(year)) { |
| days_in_month[1] = 29; |
| } else { |
| days_in_month[1] = 28; |
| if(seconds>YEAR_SECONDS){ |
| year++; |
| seconds -= YEAR_SECONDS; |
| } |
| } |
| buf[6] = year%100; |
| |
| /* Month */ |
| for(i=0; i<12; i++) |
| { |
| if(seconds < days_in_month[i]*DAY_SECONDS){ |
| buf[5] = i+1; |
| break; |
| } |
| |
| seconds -= days_in_month[i]*DAY_SECONDS; |
| } |
| |
| /* Month Day */ |
| buf[4] = seconds/DAY_SECONDS; |
| seconds -= buf[4]*DAY_SECONDS; |
| buf[4]++; /* 1 ... 31 */ |
| |
| /* Hour */ |
| buf[2] = seconds/HOUR_SECONDS; |
| seconds -= buf[2]*HOUR_SECONDS; |
| |
| /* Minute */ |
| buf[1] = seconds/MINUTE_SECONDS; |
| seconds -= buf[1]*MINUTE_SECONDS; |
| |
| /* Second */ |
| buf[0] = seconds; |
| |
| /* Convert to Binary Coded Decimal format */ |
| for(i=0; i<7; i++) |
| buf[i] = DEC2BCD(buf[i]); |
| |
| return 7; |
| } |
| |
| int rtc_write_datetime(unsigned char* buf) |
| { |
| int i, year; |
| unsigned int year_days = 0; |
| unsigned int month_days = 0; |
| unsigned int seconds = 0; |
| |
| /* Convert from Binary Coded Decimal format */ |
| for(i=0; i<7; i++) |
| buf[i] = BCD2DEC(buf[i]); |
| |
| year = 2000 + buf[6]; |
| |
| if(is_leapyear(year)) { |
| days_in_month[1] = 29; |
| } else { |
| days_in_month[1] = 28; |
| } |
| |
| /* Number of days in months gone by this year*/ |
| for(i=0; i<(buf[5]-1); i++){ |
| month_days += days_in_month[i]; |
| } |
| |
| /* Number of days in years gone by since 1-Jan-1980 */ |
| year_days = 365*(buf[6]+20) + (buf[6]-1)/4 + 6; |
| |
| /* Convert to seconds since 1-Jan-1980 */ |
| seconds = buf[0] |
| + buf[1]*MINUTE_SECONDS |
| + buf[2]*HOUR_SECONDS |
| + (buf[4]-1)*DAY_SECONDS |
| + month_days*DAY_SECONDS |
| + year_days*DAY_SECONDS; |
| |
| /* Send data to RTC */ |
| for (i=0;i<4;i++){ |
| pp_i2c_send(AS3514_I2C_ADDR, AS3514_RTC_0 + i, ((seconds >> (8 * i)) & 0xff)); |
| } |
| return 1; |
| } |
| |