FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / firmware / drivers / rtc / rtc_mc13783.c
blob15ed5b148b90ba254c6149bf7f8fdff9bc4d6d02
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include "config.h"
22 #include "system.h"
23 #include "rtc.h"
24 #include "mc13783.h"
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
37 #elif 1
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
42 #else
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
47 #endif
49 enum rtc_buffer_field_indexes
51 RTC_I_SECONDS = 0,
52 RTC_I_MINUTES,
53 RTC_I_HOURS,
54 RTC_I_WEEKDAY,
55 RTC_I_DAY,
56 RTC_I_MONTH,
57 RTC_I_YEAR,
58 RTC_NUM_FIELDS,
61 enum rtc_registers_indexes
63 RTC_REG_TIME = 0,
64 RTC_REG_DAY,
65 RTC_REG_TIME2,
66 RTC_NUM_REGS,
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,
86 int len)
88 while (len-- > 0)
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,
96 int len)
98 while (len-- > 0)
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;
111 return ly - lc + lm;
114 static int is_leap_year(int y)
116 return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0) ? 1 : 0;
119 /** Public APIs **/
120 void rtc_init(void)
122 /* only needs to be polled on startup */
123 if (mc13783_read(MC13783_INTERRUPT_STATUS1) & MC13783_TODAI)
125 alarm_start = true;
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
136 * greater */
139 if (mc13783_read_regset(rtc_registers, regs,
140 RTC_NUM_REGS) < RTC_NUM_REGS)
142 /* Couldn't read registers */
143 return 0;
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;
161 /* Weekday */
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;
174 year += 1601;
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];
183 if (day < days)
184 break;
186 day -= days;
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);
195 return 7;
198 int rtc_write_datetime(unsigned char* buf)
200 uint32_t regs[2];
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)
213 year += 2000;
214 else
215 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
231 * month. */
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;
247 return 0;
250 bool rtc_check_alarm_flag(void)
252 /* We don't need to do anything special if it has already fired */
253 return false;
256 bool rtc_enable_alarm(bool enable)
258 if (enable)
259 mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_TODAM);
260 else
261 mc13783_set(MC13783_INTERRUPT_MASK1, MC13783_TODAM);
263 return false;
266 bool rtc_check_alarm_started(bool release_alarm)
268 bool rc = alarm_start;
270 if (release_alarm)
271 alarm_start = false;
273 return rc;
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)
282 day++;
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);
291 *h = tod / 3600;
292 *m = tod % 3600 / 60;