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 /* Days passed since midnight 01 Jan, 1601 to midnight on the base date. */
30 #ifdef TOSHIBA_GIGABEAT_S
31 /* Gigabeat S seems to be 1 day behind the ususual - this will
32 * make the RTC match file dates created by retailos. */
33 #define RTC_BASE_DAY_COUNT 138425
34 #define RTC_BASE_MONTH 12
35 #define RTC_BASE_DAY 31
36 #define RTC_BASE_YEAR 1979
38 #define RTC_BASE_DAY_COUNT 138426
39 #define RTC_BASE_MONTH 1
40 #define RTC_BASE_DAY 1
41 #define RTC_BASE_YEAR 1980
43 #define RTC_BASE_DAY_COUNT 134774
44 #define RTC_BASE_MONTH 1
45 #define RTC_BASE_DAY 1
46 #define RTC_BASE_YEAR 1970
49 enum rtc_registers_indexes
57 /* was it an alarm that triggered power on ? */
58 static bool alarm_start
= false;
60 static const unsigned char rtc_registers
[RTC_NUM_REGS
] =
62 [RTC_REG_TIME
] = MC13783_RTC_TIME
,
63 [RTC_REG_DAY
] = MC13783_RTC_DAY
,
64 [RTC_REG_TIME2
] = MC13783_RTC_TIME
,
67 static const unsigned char month_table
[2][12] =
69 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
70 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
73 /* Get number of leaps since the reference date of 1601/01/01 */
74 static int get_leap_count(int d
)
76 int lm
= (d
+ 1) / 146097;
77 int lc
= (d
+ 1 - lm
) / 36524;
78 int ly
= (d
+ 1 - lm
+ lc
) / 1461;
82 static int is_leap_year(int y
)
84 return (y
% 4) == 0 && ((y
% 100) != 0 || (y
% 400) == 0) ? 1 : 0;
90 /* only needs to be polled on startup */
91 if (mc13783_read(MC13783_INTERRUPT_STATUS1
) & MC13783_TODAI
)
94 mc13783_write(MC13783_INTERRUPT_STATUS1
, MC13783_TODAI
);
98 int rtc_read_datetime(struct tm
*tm
)
100 uint32_t regs
[RTC_NUM_REGS
];
101 int year
, leap
, month
, day
, hour
, min
;
103 /* Read time, day, time - 2nd read of time should be the same or
107 if (mc13783_read_regs(rtc_registers
, regs
,
108 RTC_NUM_REGS
) < RTC_NUM_REGS
)
110 /* Couldn't read registers */
114 /* If TOD counter turned over - reread */
115 while (regs
[RTC_REG_TIME2
] < regs
[RTC_REG_TIME
]);
117 /* TOD: = 0 to 86399 */
118 hour
= regs
[RTC_REG_TIME
] / 3600;
119 regs
[RTC_REG_TIME
] -= hour
*3600;
122 min
= regs
[RTC_REG_TIME
] / 60;
123 regs
[RTC_REG_TIME
] -= min
*60;
126 tm
->tm_sec
= regs
[RTC_REG_TIME
];
128 /* DAY: 0 to 32767 */
129 day
= regs
[RTC_REG_DAY
] + RTC_BASE_DAY_COUNT
;
132 tm
->tm_wday
= (day
+ 1) % 7; /* 1601/01/01 = Monday */
134 /* Get number of leaps for today */
135 leap
= get_leap_count(day
);
136 year
= (day
- leap
) / 365;
138 /* Get number of leaps for yesterday */
139 leap
= get_leap_count(day
- 1);
141 /* Get day number for year 0-364|365 */
142 day
= day
- leap
- year
* 365;
146 /* Get the current month */
147 leap
= is_leap_year(year
);
149 for (month
= 0; month
< 12; month
++)
151 int days
= month_table
[leap
][month
];
159 tm
->tm_mday
= day
+ 1; /* 1 to 31 */
160 tm
->tm_mon
= month
; /* 0 to 11 */
161 tm
->tm_year
= year
% 100 + 100;
166 int rtc_write_datetime(const struct tm
*tm
)
169 int year
, leap
, month
, day
, i
, base_yearday
;
171 regs
[RTC_REG_TIME
] = tm
->tm_sec
+
175 year
= tm
->tm_year
- 100;
177 if (year
< RTC_BASE_YEAR
- 1900)
182 /* Get number of leaps for day before base */
183 leap
= get_leap_count(RTC_BASE_DAY_COUNT
- 1);
185 /* Get day number for base year 0-364|365 */
186 base_yearday
= RTC_BASE_DAY_COUNT
- leap
-
187 (RTC_BASE_YEAR
- 1601) * 365;
189 /* Get the number of days elapsed from reference */
190 for (i
= RTC_BASE_YEAR
, day
= 0; i
< year
; i
++)
192 day
+= is_leap_year(i
) ? 366 : 365;
195 /* Find the number of days passed this year up to the 1st of the
197 leap
= is_leap_year(year
);
200 for (i
= 0; i
< month
; i
++)
202 day
+= month_table
[leap
][i
];
205 regs
[RTC_REG_DAY
] = day
+ tm
->tm_mday
- 1 - base_yearday
;
207 if (mc13783_write_regs(rtc_registers
, regs
, 2) == 2)
215 bool rtc_check_alarm_flag(void)
217 /* We don't need to do anything special if it has already fired */
221 bool rtc_enable_alarm(bool enable
)
224 mc13783_clear(MC13783_INTERRUPT_MASK1
, MC13783_TODAM
);
226 mc13783_set(MC13783_INTERRUPT_MASK1
, MC13783_TODAM
);
231 bool rtc_check_alarm_started(bool release_alarm
)
233 bool rc
= alarm_start
;
241 void rtc_set_alarm(int h
, int m
)
243 int day
= mc13783_read(MC13783_RTC_DAY
);
244 int tod
= mc13783_read(MC13783_RTC_TIME
);
246 if (h
*3600 + m
*60 < tod
)
249 mc13783_write(MC13783_RTC_DAY_ALARM
, day
);
250 mc13783_write(MC13783_RTC_ALARM
, h
*3600 + m
*60);
253 void rtc_get_alarm(int *h
, int *m
)
255 int tod
= mc13783_read(MC13783_RTC_ALARM
);
257 *m
= tod
% 3600 / 60;