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_buffer_field_indexes
61 enum rtc_registers_indexes
69 /* was it an alarm that triggered power on ? */
70 static bool alarm_start
= false;
72 static const unsigned char rtc_registers
[RTC_NUM_REGS
] =
74 [RTC_REG_TIME
] = MC13783_RTC_TIME
,
75 [RTC_REG_DAY
] = MC13783_RTC_DAY
,
76 [RTC_REG_TIME2
] = MC13783_RTC_TIME
,
79 static const unsigned char month_table
[2][12] =
81 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
82 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
85 static inline void to_bcd(unsigned char *bcd
, const unsigned char *buf
,
90 unsigned char d
= *buf
++;
91 *bcd
++ = ((d
/ 10) << 4) | (d
% 10);
95 static inline void from_bcd(unsigned char *buf
, const unsigned char *bcd
,
100 unsigned char d
= *bcd
++;
101 *buf
++ = ((d
>> 4) & 0x0f) * 10 + (d
& 0xf);
105 /* Get number of leaps since the reference date of 1601/01/01 */
106 static int get_leap_count(int d
)
108 int lm
= (d
+ 1) / 146097;
109 int lc
= (d
+ 1 - lm
) / 36524;
110 int ly
= (d
+ 1 - lm
+ lc
) / 1461;
114 static int is_leap_year(int y
)
116 return (y
% 4) == 0 && ((y
% 100) != 0 || (y
% 400) == 0) ? 1 : 0;
122 /* only needs to be polled on startup */
123 if (mc13783_read(MC13783_INTERRUPT_STATUS1
) & MC13783_TODAI
)
126 mc13783_write(MC13783_INTERRUPT_STATUS1
, MC13783_TODAI
);
130 int rtc_read_datetime(unsigned char* buf
)
132 uint32_t regs
[RTC_NUM_REGS
];
133 int year
, leap
, month
, day
;
135 /* Read time, day, time - 2nd read of time should be the same or
139 if (mc13783_read_regset(rtc_registers
, regs
,
140 RTC_NUM_REGS
) < RTC_NUM_REGS
)
142 /* Couldn't read registers */
146 /* If TOD counter turned over - reread */
147 while (regs
[RTC_REG_TIME2
] < regs
[RTC_REG_TIME
]);
149 /* TOD: = 0 to 86399 */
150 buf
[RTC_I_HOURS
] = regs
[RTC_REG_TIME
] / 3600;
151 regs
[RTC_REG_TIME
] -= buf
[RTC_I_HOURS
]*3600;
153 buf
[RTC_I_MINUTES
] = regs
[RTC_REG_TIME
] / 60;
154 regs
[RTC_REG_TIME
] -= buf
[RTC_I_MINUTES
]*60;
156 buf
[RTC_I_SECONDS
] = regs
[RTC_REG_TIME
];
158 /* DAY: 0 to 32767 */
159 day
= regs
[RTC_REG_DAY
] + RTC_BASE_DAY_COUNT
;
162 buf
[RTC_I_WEEKDAY
] = (day
+ 1) % 7; /* 1601/01/01 = Monday */
164 /* Get number of leaps for today */
165 leap
= get_leap_count(day
);
166 year
= (day
- leap
) / 365;
168 /* Get number of leaps for yesterday */
169 leap
= get_leap_count(day
- 1);
171 /* Get day number for year 0-364|365 */
172 day
= day
- leap
- year
* 365;
176 /* Get the current month */
177 leap
= is_leap_year(year
);
179 for (month
= 0; month
< 12; month
++)
181 int days
= month_table
[leap
][month
];
189 buf
[RTC_I_DAY
] = day
+ 1; /* 1 to 31 */
190 buf
[RTC_I_MONTH
] = month
+ 1; /* 1 to 12 */
191 buf
[RTC_I_YEAR
] = year
% 100;
193 to_bcd(buf
, buf
, RTC_NUM_FIELDS
);
198 int rtc_write_datetime(unsigned char* buf
)
201 unsigned char fld
[RTC_NUM_FIELDS
];
202 int year
, leap
, month
, day
, i
, base_yearday
;
204 from_bcd(fld
, buf
, RTC_NUM_FIELDS
);
206 regs
[RTC_REG_TIME
] = fld
[RTC_I_SECONDS
] +
207 fld
[RTC_I_MINUTES
]*60 +
208 fld
[RTC_I_HOURS
]*3600;
210 year
= fld
[RTC_I_YEAR
];
212 if (year
< RTC_BASE_YEAR
- 1900)
217 /* Get number of leaps for day before base */
218 leap
= get_leap_count(RTC_BASE_DAY_COUNT
- 1);
220 /* Get day number for base year 0-364|365 */
221 base_yearday
= RTC_BASE_DAY_COUNT
- leap
-
222 (RTC_BASE_YEAR
- 1601) * 365;
224 /* Get the number of days elapsed from reference */
225 for (i
= RTC_BASE_YEAR
, day
= 0; i
< year
; i
++)
227 day
+= is_leap_year(i
) ? 366 : 365;
230 /* Find the number of days passed this year up to the 1st of the
232 leap
= is_leap_year(year
);
233 month
= fld
[RTC_I_MONTH
] - 1;
235 for (i
= 0; i
< month
; i
++)
237 day
+= month_table
[leap
][i
];
240 regs
[RTC_REG_DAY
] = day
+ fld
[RTC_I_DAY
] - 1 - base_yearday
;
242 if (mc13783_write_regset(rtc_registers
, regs
, 2) == 2)
244 return RTC_NUM_FIELDS
;
250 bool rtc_check_alarm_flag(void)
252 /* We don't need to do anything special if it has already fired */
256 bool rtc_enable_alarm(bool enable
)
259 mc13783_clear(MC13783_INTERRUPT_MASK1
, MC13783_TODAM
);
261 mc13783_set(MC13783_INTERRUPT_MASK1
, MC13783_TODAM
);
266 bool rtc_check_alarm_started(bool release_alarm
)
268 bool rc
= alarm_start
;
276 void rtc_set_alarm(int h
, int m
)
278 int day
= mc13783_read(MC13783_RTC_DAY
);
279 int tod
= mc13783_read(MC13783_RTC_TIME
);
281 if (h
*3600 + m
*60 < tod
)
284 mc13783_write(MC13783_RTC_DAY_ALARM
, day
);
285 mc13783_write(MC13783_RTC_ALARM
, h
*3600 + m
*60);
288 void rtc_get_alarm(int *h
, int *m
)
290 int tod
= mc13783_read(MC13783_RTC_ALARM
);
292 *m
= tod
% 3600 / 60;