From 728600e5147be5363978fc40e2ef7d8d352d5263 Mon Sep 17 00:00:00 2001 From: mcuelenaere Date: Fri, 8 Jan 2010 14:52:15 +0000 Subject: [PATCH] Ingenic Jz4740: simplify RTC driver (you will need to re-set the clock) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24201 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/rtc/rtc_jz4740.c | 423 ++++++++++---------------------------- 1 file changed, 105 insertions(+), 318 deletions(-) rewrite firmware/drivers/rtc/rtc_jz4740.c (80%) diff --git a/firmware/drivers/rtc/rtc_jz4740.c b/firmware/drivers/rtc/rtc_jz4740.c dissimilarity index 80% index a73f300aa..b82978ed2 100644 --- a/firmware/drivers/rtc/rtc_jz4740.c +++ b/firmware/drivers/rtc/rtc_jz4740.c @@ -1,318 +1,105 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2008 by Maurus Cuelenaere - * - * 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. - * - ****************************************************************************/ - -/* - * Jz OnChip Real Time Clock interface for Linux - * - */ - -#include "config.h" -#include "jz4740.h" -#include "rtc.h" -#include "timefuncs.h" -#include "logf.h" - -static const unsigned int yearday[5] = {0, 366, 366+365, 366+365*2, 366+365*3}; -static const unsigned int sweekday = 6; -static const unsigned int sum_monthday[13] = { - 0, - 31, - 31+28, - 31+28+31, - 31+28+31+30, - 31+28+31+30+31, - 31+28+31+30+31+30, - 31+28+31+30+31+30+31, - 31+28+31+30+31+30+31+31, - 31+28+31+30+31+30+31+31+30, - 31+28+31+30+31+30+31+31+30+31, - 31+28+31+30+31+30+31+31+30+31+30, - 365 -}; - -static unsigned int jz_mktime(int year, int mon, int day, int hour, int min, - int sec) -{ - unsigned int seccounter; - - if (year < 2000) - year = 2000; - year -= 2000; - seccounter = (year/4)*(365*3+366); - seccounter += yearday[year%4]; - if (year%4) - seccounter += sum_monthday[mon-1]; - else - if (mon >= 3) - seccounter += sum_monthday[mon-1]+1; - else - seccounter += sum_monthday[mon-1]; - seccounter += day-1; - seccounter *= 24; - seccounter += hour; - seccounter *= 60; - seccounter += min; - seccounter *= 60; - seccounter += sec; - - return seccounter; -} - -static void jz_gettime(unsigned int rtc, int *year, int *mon, int *day, - int *hour, int *min, int *sec, int *weekday) -{ - unsigned int tday, tsec, i, tmp; - - tday = rtc/(24*3600); - *weekday = ((tday % 7) + sweekday) % 7; - *year = (tday/(366+365*3)) * 4; - tday = tday%(366+365*3); - for (i=0;i<5;i++) - { - if (tday=2)) - tmp += 1; - if (tday=2)) - tmp += 1; - *day = tday - tmp + 1; - break; - } - } - tsec = rtc % (24 * 3600); - *hour = tsec / 3600; - *min = (tsec / 60) % 60; - *sec = tsec - *hour*3600 - *min*60; - *year += 2000; -} - -int rtc_read_datetime(struct tm *tm) -{ - unsigned int sec,mon,mday,wday,year,hour,min; - - /* - * Only the values that we read from the RTC are set. We leave - * tm_wday, tm_yday and tm_isdst untouched. Even though the - * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated - * by the RTC when initially set to a non-zero value. - */ - jz_gettime(REG_RTC_RSR, &year, &mon, &mday, &hour, &min, &sec, &wday); - - year -= 2000; - - tm->tm_sec = sec; - tm->tm_min = min; - tm->tm_hour = hour; - tm->tm_mday = mday; - tm->tm_wday = wday; - /* Don't use centry, but start from year 1970 */ - tm->tm_mon = mon; - if (year <= 69) - year += 100; - tm->tm_year = year; - - return 1; -} - -int rtc_write_datetime(const struct tm *tm) -{ - unsigned int year, lval; - - year = tm->tm_year; - /* Don't use centry, but start from year 1970 */ - if (year > 69) - year -= 100; - year += 2000; - - lval = jz_mktime(year, tm->tm_mon, tm->tm_mday, tm->tm_hour, - tm->tm_min, tm->tm_sec); - - __cpm_start_rtc(); - udelay(100); - REG_RTC_RSR = lval; - __cpm_stop_rtc(); - - return 0; -} - -#if 0 -void get_rtc_alm_time(struct rtc_time *alm_tm) -{ - unsigned int sec,mon,mday,wday,year,hour,min; - unsigned int lval; - unsigned long flags; - /* - * Only the values that we read from the RTC are set. That - * means only tm_hour, tm_min, and tm_sec. - */ - lval = REG_RTC_RSAR; - jz_gettime(lval, &year, &mon, &mday, &hour, &min, &sec, &wday); - - alm_tm->tm_sec = sec; - alm_tm->tm_min = min; - alm_tm->tm_hour = hour; -} - - -int rtc_ioctl(unsigned int cmd,struct rtc_time *val,unsigned int epo) -{ - struct rtc_time wtime; - switch (cmd) { - case RTC_ALM_READ: /* Read the present alarm time */ - /* - * This returns a struct rtc_time. Reading >= 0xc0 - * means "don't care" or "match all". Only the tm_hour, - * tm_min, and tm_sec values are filled in. - */ - get_rtc_alm_time(val); - break; - case RTC_ALM_SET: /* Store a time into the alarm */ - { - unsigned char ahrs, amin, asec; - unsigned int sec,mon,mday,wday,year,hour,min; - unsigned int lval; - unsigned long flags; - struct rtc_time alm_tm; - - alm_tm = *val; - ahrs = alm_tm.tm_hour; - amin = alm_tm.tm_min; - asec = alm_tm.tm_sec; - - - - if (ahrs >= 24) - return -1; - - if (amin >= 60) - return -1; - - if (asec >= 60) - return -1; - - flags = spin_lock_irqsave(); - lval = REG_RTC_RSR; - jz_gettime(lval, &year, &mon, &mday, &hour, &min, &sec, &wday); - hour = ahrs; - min = amin; - sec = asec; - lval = jz_mktime(year, mon, mday, hour, min, sec); - REG_RTC_RSAR = lval; - spin_unlock_irqrestore(flags); - break; - } - case RTC_RD_TIME: /* Read the time/date from RTC */ - get_rtc_time(val); - break; - case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned int mon, day, hrs, min, sec, leap_yr, date; - unsigned int yrs; - unsigned int lval; - unsigned long flags; - - rtc_tm = *val; - yrs = rtc_tm.tm_year;// + 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_wday; - date = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - - if (yrs < 1970) - return -EINVAL; - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (date == 0)) - return -EINVAL; - - if (date > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ((yrs -= epoch) > 255) /* They are unsigned */ - return -EINVAL; - - flags = spin_lock_irqsave(); - /* These limits and adjustments are independant of - * whether the chip is in binary mode or not. - */ - - if (yrs > 169) { - spin_unlock_irqrestore(flags); - return -EINVAL; - } - - yrs += epoch; - lval = jz_mktime(yrs, mon, date, hrs, min, sec); - REG_RTC_RSR = lval; - /* FIXME: maybe we need to write alarm register here. */ - spin_unlock_irqrestore(flags); - - return 0; - } - break; - case RTC_EPOCH_READ: /* Read the epoch. */ - epo = epoch; - return 0; - case RTC_EPOCH_SET: /* Set the epoch. */ - /* - * There were no RTC clocks before 1900. - */ - if (epo < 1900) - return -EINVAL; - - epoch = epo; - return 0; - default: - return -EINVAL; - } - return -EINVAL; -} -#endif - -void rtc_init(void) -{ - __cpm_start_rtc(); - REG_RTC_RCR = RTC_RCR_RTCE; - udelay(70); - while( !(REG_RTC_RCR & RTC_RCR_WRDY) ); - REG_RTC_RGR = (0x7fff | RTC_RGR_LOCK); - udelay(70); - __cpm_stop_rtc(); -} +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * 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. + * + ****************************************************************************/ + +/* + * Jz OnChip Real Time Clock interface for Linux + * + */ + +#include "config.h" +#include "jz4740.h" +#include "rtc.h" +#include "timefuncs.h" +#include "logf.h" + +/* Stolen from dietlibc-0.29/libugly/gmtime_r.c (GPLv2) */ +#define SPD (24*60*60) +#define ISLEAP(year) (!(year%4) && ((year%100) || !(year%400))) +static void _localtime(const time_t t, struct tm *r) +{ + time_t i; + register time_t work = t % SPD; + static int m_to_d[12] = /* This could be shared with mktime() */ + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + r->tm_sec = work % 60; + work /= 60; + r->tm_min = work % 60; + r->tm_hour = work / 60; + work = t / SPD; + r->tm_wday = (4 + work) % 7; + + for (i=1970; ; ++i) + { + register time_t k = ISLEAP(i) ? 366 : 365; + + if (work >= k) + work -= k; + else + break; + } + + r->tm_year = i - 1900; + r->tm_yday = work; + + r->tm_mday = 1; + if (ISLEAP(i) && (work>58)) + { + if (work==59) + r->tm_mday=2; /* 29.2. */ + + work-=1; + } + + for (i=11; i && (m_to_d[i] > work); --i); + r->tm_mon = i; + r->tm_mday += work - m_to_d[i]; +} + +int rtc_read_datetime(struct tm *tm) +{ + _localtime(REG_RTC_RSR, tm); + + return 1; +} + +int rtc_write_datetime(const struct tm *tm) +{ + time_t val = mktime((struct tm*)tm); + + __cpm_start_rtc(); + udelay(100); + REG_RTC_RSR = val; + __cpm_stop_rtc(); + + return 0; +} + +void rtc_init(void) +{ + __cpm_start_rtc(); + REG_RTC_RCR = RTC_RCR_RTCE; + udelay(70); + while( !(REG_RTC_RCR & RTC_RCR_WRDY) ); + REG_RTC_RGR = (0x7fff | RTC_RGR_LOCK); + udelay(70); + __cpm_stop_rtc(); +} -- 2.11.4.GIT