1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2008 by Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
26 /* NOTE: Defined the base to be original firmware compatible if needed -
27 * ie. the day and year as it would interpret a DAY register value of zero. */
29 /* None of this code concerns itself with (year mod 100) = 0 leap year
30 * exceptions because all (year mod 4) = 0 years in the relevant range are
31 * leap years. A base year of 1901 to an end date of 28 Feb 2100 are ok. */
33 #ifdef TOSHIBA_GIGABEAT_S
34 /* Gigabeat S seems to be 1 day behind the ususual - this will
35 * make the RTC match file dates created by retailos. */
36 #define RTC_BASE_WDAY 1 /* Monday */
37 #define RTC_BASE_YDAY 364 /* 31 Dec */
38 #define RTC_BASE_YEAR 1979
40 #define RTC_BASE_WDAY 2 /* Tuesday */
41 #define RTC_BASE_YDAY 0 /* 01 Jan */
42 #define RTC_BASE_YEAR 1980
44 #define RTC_BASE_WDAY 4 /* Thursday */
45 #define RTC_BASE_YDAY 0 /* 01 Jan */
46 #define RTC_BASE_YEAR 1970
49 /* Reference year for leap calculation - year that is on or before the base
50 * year and immediately follows a leap year */
51 #define RTC_REF_YEAR_OFFS ((RTC_BASE_YEAR - 1) & 3)
52 #define RTC_REF_YEAR (RTC_BASE_YEAR - RTC_REF_YEAR_OFFS)
54 enum rtc_registers_indexes
63 static const unsigned char rtc_registers
[RTC_NUM_REGS_RD
] =
65 [RTC_REG_TIME
] = MC13783_RTC_TIME
,
66 [RTC_REG_DAY
] = MC13783_RTC_DAY
,
67 [RTC_REG_TIME2
] = MC13783_RTC_TIME
,
70 /* was it an alarm that triggered power on ? */
71 static bool alarm_start
= false;
73 static const unsigned short month_table
[13] =
75 /* Since 1 Jan, how many days have passed this year? (non-leap)
76 +31 28 31 30 31 30 31 31 30 31 30 31 */
77 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
80 static bool read_time_and_day(uint32_t regs
[RTC_NUM_REGS_RD
])
82 /* Read time, day, time - 2nd read of time should be the same or
86 if (mc13783_read_regs(rtc_registers
, regs
,
87 RTC_NUM_REGS_RD
) < RTC_NUM_REGS_RD
)
89 /* Couldn't read registers */
93 /* If TOD counter turned over - reread */
94 while (regs
[RTC_REG_TIME2
] < regs
[RTC_REG_TIME
]);
102 /* only needs to be polled on startup */
103 if (mc13783_read(MC13783_INTERRUPT_STATUS1
) & MC13783_TODAI
)
106 mc13783_write(MC13783_INTERRUPT_STATUS1
, MC13783_TODAI
);
110 int rtc_read_datetime(struct tm
*tm
)
112 uint32_t regs
[RTC_NUM_REGS_RD
];
113 int year
, month
, yday
, x
, n
;
115 if (!read_time_and_day(regs
))
118 /* TOD: 0 to 86399 */
119 x
= regs
[RTC_REG_TIME
];
134 /* DAY: 0 to 32767 */
135 x
= regs
[RTC_REG_DAY
];
138 tm
->tm_wday
= (x
+ RTC_BASE_WDAY
) % 7;
141 x
+= RTC_REF_YEAR_OFFS
*365 + RTC_BASE_YDAY
;
143 /* Lag year increment by subtracting leaps since the reference year
144 * on 31 Dec of each leap year, essentially removing them from the
147 year
= (x
- n
) / 365;
150 yday
= x
- n
- year
*365;
152 /* If (x + 1) mod 1461 == 0, then it is yday 365 of a leap year */
153 if (n
* 1461 - 1 == x
)
156 tm
->tm_yday
= x
= yday
;
158 if (((year
+ RTC_REF_YEAR
) & 3) == 0 && x
>= month_table
[2])
160 if (x
> month_table
[2])
161 yday
--; /* 1 Mar or after; lag date by one day */
163 x
--; /* 29 Feb or after, lag month by one day */
166 /* Get the current month */
167 month
= x
>> 5; /* yday / 32, close enough */
169 if (month_table
[month
+ 1] <= x
)
170 month
++; /* Round to next */
172 tm
->tm_mday
= yday
- month_table
[month
] + 1; /* 1 to 31 */
173 tm
->tm_mon
= month
; /* 0 to 11 */
175 /* {BY to (BY+89 or 90)} - 1900 */
176 tm
->tm_year
= year
+ RTC_REF_YEAR
- 1900;
181 int rtc_write_datetime(const struct tm
*tm
)
183 uint32_t regs
[RTC_NUM_REGS_WR
];
186 /* Convert time of day into seconds since midnight */
187 x
= tm
->tm_sec
+ tm
->tm_min
*60 + tm
->tm_hour
*3600;
189 /* Keep in range (it throws off the PMIC counters otherwise) */
190 regs
[RTC_REG_TIME
] = MAX(0, MIN(86399, x
));
192 year
= tm
->tm_year
+ 1900;
194 /* Get the number of days elapsed from 1 Jan of reference year to 1 Jan of
196 x
= year
- RTC_REF_YEAR
;
197 x
= x
*365 + (x
>> 2);
199 /* Add the number of days passed this year since 1 Jan and offset by the
200 * base yearday and the reference offset in days from the base */
202 x
+= month_table
[month
] + tm
->tm_mday
- RTC_REF_YEAR_OFFS
*365
205 if ((year
& 3) != 0 || month
< 2) {
206 /* Sub one day because tm_mday starts at 1, otherwise the offset is
207 * required because of 29 Feb */
212 regs
[RTC_REG_DAY
] = MAX(0, MIN(32767, x
));
214 if (mc13783_write_regs(rtc_registers
, regs
, RTC_NUM_REGS_WR
)
223 bool rtc_check_alarm_flag(void)
225 /* We don't need to do anything special if it has already fired */
229 void rtc_enable_alarm(bool enable
)
232 mc13783_clear(MC13783_INTERRUPT_MASK1
, MC13783_TODAM
);
234 mc13783_set(MC13783_INTERRUPT_MASK1
, MC13783_TODAM
);
237 bool rtc_check_alarm_started(bool release_alarm
)
239 bool rc
= alarm_start
;
247 void rtc_set_alarm(int h
, int m
)
249 uint32_t regs
[RTC_NUM_REGS_RD
];
252 if (!read_time_and_day(regs
))
257 if (tod
< regs
[RTC_REG_TIME
])
260 mc13783_write(MC13783_RTC_DAY_ALARM
, regs
[RTC_REG_DAY
]);
261 mc13783_write(MC13783_RTC_ALARM
, tod
);
264 void rtc_get_alarm(int *h
, int *m
)
266 uint32_t tod
= mc13783_read(MC13783_RTC_ALARM
);
268 *m
= tod
% 3600 / 60;