diff options
| author | Michael Sevakis <jethead71@rockbox.org> | 2008-04-24 09:22:39 +0000 |
|---|---|---|
| committer | Michael Sevakis <jethead71@rockbox.org> | 2008-04-24 09:22:39 +0000 |
| commit | ac387d4d5cb7b71fc5d3b566988b55020b3d3c51 (patch) | |
| tree | 0864cd8d317898fc0d7339985119b93187dbf42c | |
| parent | 5f3356b942a23e8dd0907b416848439f1445cb17 (diff) | |
| download | rockbox-ac387d4d5cb7b71fc5d3b566988b55020b3d3c51.zip rockbox-ac387d4d5cb7b71fc5d3b566988b55020b3d3c51.tar.gz rockbox-ac387d4d5cb7b71fc5d3b566988b55020b3d3c51.tar.bz2 rockbox-ac387d4d5cb7b71fc5d3b566988b55020b3d3c51.tar.xz | |
Add a PMIC-based RTC driver for Gigabeat S.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17236 a1c6a512-1295-4272-9138-f99709370657
| -rw-r--r-- | firmware/SOURCES | 2 | ||||
| -rw-r--r-- | firmware/drivers/rtc/rtc_mc13783.c | 238 | ||||
| -rw-r--r-- | firmware/export/config-gigabeat-s.h | 2 | ||||
| -rw-r--r-- | firmware/export/config.h | 1 |
4 files changed, 242 insertions, 1 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index bf4fb86..0acfdd5 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -149,6 +149,8 @@ drivers/rtc/rtc_as3514.c drivers/rtc/rtc_rx5x348ab.c #elif (CONFIG_RTC == RTC_MR100) drivers/rtc/rtc_mr100.c +#elif (CONFIG_RTC == RTC_MC13783) +drivers/rtc/rtc_mc13783.c #endif /* (CONFIG_RTC == RTC_) */ #endif /* SIMULATOR */ diff --git a/firmware/drivers/rtc/rtc_mc13783.c b/firmware/drivers/rtc/rtc_mc13783.c new file mode 100644 index 0000000..2494e5e --- /dev/null +++ b/firmware/drivers/rtc/rtc_mc13783.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Michael Sevakis + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "rtc.h" +#include "mc13783.h" + +/* NOTE: Defined the base to be original firmware compatible if needed - + * ie. the day and year as it would interpret a DAY register value of zero. */ + +/* Days passed since midnight 01 Jan, 1601 to midnight on the base date. */ +#ifdef TOSHIBA_GIGABEAT_S + /* Gigabeat S seems to be 1 day behind the ususual - this will + * make the RTC match file dates created by retailos. */ + #define RTC_BASE_DAY_COUNT 138425 + #define RTC_BASE_MONTH 12 + #define RTC_BASE_DAY 31 + #define RTC_BASE_YEAR 1979 +#elif 1 + #define RTC_BASE_DAY_COUNT 138426 + #define RTC_BASE_MONTH 1 + #define RTC_BASE_DAY 1 + #define RTC_BASE_YEAR 1980 +#else + #define RTC_BASE_DAY_COUNT 134774 + #define RTC_BASE_MONTH 1 + #define RTC_BASE_DAY 1 + #define RTC_BASE_YEAR 1970 +#endif + +enum rtc_buffer_field_indexes +{ + RTC_I_SECONDS = 0, + RTC_I_MINUTES, + RTC_I_HOURS, + RTC_I_WEEKDAY, + RTC_I_DAY, + RTC_I_MONTH, + RTC_I_YEAR, + RTC_NUM_FIELDS, +}; + +enum rtc_registers_indexes +{ + RTC_REG_TIME = 0, + RTC_REG_DAY, + RTC_REG_TIME2, + RTC_NUM_REGS, +}; + +static const unsigned char rtc_registers[RTC_NUM_REGS] = +{ + [RTC_REG_TIME] = MC13783_RTC_TIME, + [RTC_REG_DAY] = MC13783_RTC_DAY, + [RTC_REG_TIME2] = MC13783_RTC_TIME, +}; + +static const unsigned char month_table[2][12] = +{ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, +}; + +static inline void to_bcd(unsigned char *bcd, const unsigned char *buf, + int len) +{ + while (len-- > 0) + { + unsigned char d = *buf++; + *bcd++ = ((d / 10) << 4) | (d % 10); + } +} + +static inline void from_bcd(unsigned char *buf, const unsigned char *bcd, + int len) +{ + while (len-- > 0) + { + unsigned char d = *bcd++; + *buf++ = ((d >> 4) & 0x0f) * 10 + (d & 0xf); + } +} + +/* Get number of leaps since the reference date of 1601/01/01 */ +static int get_leap_count(int d) +{ + int lm = (d + 1) / 146097; + int lc = (d + 1 - lm) / 36524; + int ly = (d + 1 - lm + lc) / 1461; + return ly - lc + lm; +} + +static int is_leap_year(int y) +{ + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0) ? 1 : 0; +} + +/** Public APIs **/ +void rtc_init(void) +{ + /* Nothing to do */ +} + +int rtc_read_datetime(unsigned char* buf) +{ + uint32_t regs[RTC_NUM_REGS]; + int year, leap, month, day; + + /* Read time, day, time - 2nd read of time should be the same or + * greater */ + do + { + if (mc13783_read_regset(rtc_registers, regs, + RTC_NUM_REGS) < RTC_NUM_REGS) + { + /* Couldn't read registers */ + return 0; + } + } + /* If TOD counter turned over - reread */ + while (regs[RTC_REG_TIME2] < regs[RTC_REG_TIME]); + + /* TOD: = 0 to 86399 */ + buf[RTC_I_HOURS] = regs[RTC_REG_TIME] / 3600; + regs[RTC_REG_TIME] -= buf[RTC_I_HOURS]*3600; + + buf[RTC_I_MINUTES] = regs[RTC_REG_TIME] / 60; + regs[RTC_REG_TIME] -= buf[RTC_I_MINUTES]*60; + + buf[RTC_I_SECONDS] = regs[RTC_REG_TIME]; + + /* DAY: 0 to 32767 */ + day = regs[RTC_REG_DAY] + RTC_BASE_DAY_COUNT; + + /* Weekday */ + buf[RTC_I_WEEKDAY] = (day + 1) % 7; /* 1601/01/01 = Monday */ + + /* Get number of leaps for today */ + leap = get_leap_count(day); + year = (day - leap) / 365; + + /* Get number of leaps for yesterday */ + leap = get_leap_count(day - 1); + + /* Get day number for year 0-364|365 */ + day = day - leap - year * 365; + + year += 1601; + + /* Get the current month */ + leap = is_leap_year(year); + + for (month = 0; month < 12; month++) + { + int days = month_table[leap][month]; + + if (day < days) + break; + + day -= days; + } + + buf[RTC_I_DAY] = day + 1; /* 1 to 31 */ + buf[RTC_I_MONTH] = month + 1; /* 1 to 12 */ + buf[RTC_I_YEAR] = year % 100; + + to_bcd(buf, buf, RTC_NUM_FIELDS); + + return 7; +} + +int rtc_write_datetime(unsigned char* buf) +{ + uint32_t regs[2]; + unsigned char fld[RTC_NUM_FIELDS]; + int year, leap, month, day, i, base_yearday; + + from_bcd(fld, buf, RTC_NUM_FIELDS); + + regs[RTC_REG_TIME] = fld[RTC_I_SECONDS] + + fld[RTC_I_MINUTES]*60 + + fld[RTC_I_HOURS]*3600; + + year = fld[RTC_I_YEAR]; + + if (year < RTC_BASE_YEAR - 1900) + year += 2000; + else + year += 1900; + + /* Get number of leaps for day before base */ + leap = get_leap_count(RTC_BASE_DAY_COUNT - 1); + + /* Get day number for base year 0-364|365 */ + base_yearday = RTC_BASE_DAY_COUNT - leap - + (RTC_BASE_YEAR - 1601) * 365; + + /* Get the number of days elapsed from reference */ + for (i = RTC_BASE_YEAR, day = 0; i < year; i++) + { + day += is_leap_year(i) ? 366 : 365; + } + + /* Find the number of days passed this year up to the 1st of the + * month. */ + leap = is_leap_year(year); + month = fld[RTC_I_MONTH] - 1; + + for (i = 0; i < month; i++) + { + day += month_table[leap][i]; + } + + regs[RTC_REG_DAY] = day + fld[RTC_I_DAY] - 1 - base_yearday; + + if (mc13783_write_regset(rtc_registers, regs, 2) == 2) + { + return RTC_NUM_FIELDS; + } + + return 0; +} diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h index bc70956..6eb57b2 100644 --- a/firmware/export/config-gigabeat-s.h +++ b/firmware/export/config-gigabeat-s.h @@ -43,7 +43,7 @@ #define CONFIG_CODEC SWCODEC /* define this if you have a real-time clock */ -//#define CONFIG_RTC RTC_IMX31L +#define CONFIG_RTC RTC_MC13783 /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT diff --git a/firmware/export/config.h b/firmware/export/config.h index c108171..e502043 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -165,6 +165,7 @@ #define RTC_TCC77X 10 #define RTC_TCC780X 11 #define RTC_MR100 12 +#define RTC_MC13783 13 /* Freescale MC13783 PMIC */ /* USB On-the-go */ #define USBOTG_ISP1362 1362 /* iriver H300 */ |