i.MX31/Gigabeat S: Actually enable DPTC which can set optimal voltage for 528MHz...
[kugel-rb.git] / firmware / drivers / rtc / rtc_mc13783.c
blob9cef3e904c998b3678abd1c0f89781b4f65fcacf
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_registers_indexes
51 RTC_REG_TIME = 0,
52 RTC_REG_DAY,
53 RTC_REG_TIME2,
54 RTC_NUM_REGS,
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;
79 return ly - lc + lm;
82 static int is_leap_year(int y)
84 return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0) ? 1 : 0;
87 /** Public APIs **/
88 void rtc_init(void)
90 /* only needs to be polled on startup */
91 if (mc13783_read(MC13783_INTERRUPT_STATUS1) & MC13783_TODAI)
93 alarm_start = true;
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
104 * greater */
107 if (mc13783_read_regs(rtc_registers, regs,
108 RTC_NUM_REGS) < RTC_NUM_REGS)
110 /* Couldn't read registers */
111 return 0;
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;
120 tm->tm_hour = hour;
122 min = regs[RTC_REG_TIME] / 60;
123 regs[RTC_REG_TIME] -= min*60;
124 tm->tm_min = min;
126 tm->tm_sec = regs[RTC_REG_TIME];
128 /* DAY: 0 to 32767 */
129 day = regs[RTC_REG_DAY] + RTC_BASE_DAY_COUNT;
131 /* Weekday */
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;
144 year += 1601;
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];
153 if (day < days)
154 break;
156 day -= days;
159 tm->tm_mday = day + 1; /* 1 to 31 */
160 tm->tm_mon = month; /* 0 to 11 */
161 tm->tm_year = year % 100 + 100;
163 return 7;
166 int rtc_write_datetime(const struct tm *tm)
168 uint32_t regs[2];
169 int year, leap, month, day, i, base_yearday;
171 regs[RTC_REG_TIME] = tm->tm_sec +
172 tm->tm_min*60 +
173 tm->tm_hour*3600;
175 year = tm->tm_year - 100;
177 if (year < RTC_BASE_YEAR - 1900)
178 year += 2000;
179 else
180 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
196 * month. */
197 leap = is_leap_year(year);
198 month = tm->tm_mon;
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)
209 return 7;
212 return 0;
215 bool rtc_check_alarm_flag(void)
217 /* We don't need to do anything special if it has already fired */
218 return false;
221 bool rtc_enable_alarm(bool enable)
223 if (enable)
224 mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_TODAM);
225 else
226 mc13783_set(MC13783_INTERRUPT_MASK1, MC13783_TODAM);
228 return false;
231 bool rtc_check_alarm_started(bool release_alarm)
233 bool rc = alarm_start;
235 if (release_alarm)
236 alarm_start = false;
238 return rc;
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)
247 day++;
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);
256 *h = tod / 3600;
257 *m = tod % 3600 / 60;