summaryrefslogtreecommitdiff
path: root/firmware/drivers/rtc/rtc_pcf50606.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/rtc/rtc_pcf50606.c')
-rw-r--r--firmware/drivers/rtc/rtc_pcf50606.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/firmware/drivers/rtc/rtc_pcf50606.c b/firmware/drivers/rtc/rtc_pcf50606.c
index 2c751e5b01..540ebfff06 100644
--- a/firmware/drivers/rtc/rtc_pcf50606.c
+++ b/firmware/drivers/rtc/rtc_pcf50606.c
@@ -26,8 +26,14 @@
26#include "pcf50606.h" 26#include "pcf50606.h"
27#include "timefuncs.h" 27#include "timefuncs.h"
28 28
29/* Values which each disable one alarm time register */
30static const char alarm_disable[] = {
31 0x7f, 0x7f, 0x3f, 0x07, 0x3f, 0x1f, 0xff
32};
33
29void rtc_init(void) 34void rtc_init(void)
30{ 35{
36 rtc_check_alarm_started(false);
31} 37}
32 38
33int rtc_read_datetime(struct tm *tm) 39int rtc_read_datetime(struct tm *tm)
@@ -97,3 +103,104 @@ int rtc_write_datetime(const struct tm *tm)
97 return rc; 103 return rc;
98} 104}
99 105
106/**
107 * Checks the PCF interrupt 1 register bit 7 to see if an alarm interrupt has
108 * triggered since last we checked.
109 */
110bool rtc_check_alarm_flag(void)
111{
112 int oldlevel = disable_irq_save();
113 int rc = pcf50606_read(0x02) & 0x80;
114 restore_irq(oldlevel);
115 return rc;
116}
117
118/**
119 * Enables or disables the alarm.
120 * The Ipod bootloader clears all PCF interrupt registers and always enables
121 * the "wake on RTC" bit on OOCC1, so we have to rely on other means to find
122 * out if we just woke from an alarm.
123 * Return value is always false for us.
124 */
125void rtc_enable_alarm(bool enable)
126{
127 int oldlevel = disable_irq_save();
128 if (enable) {
129 /* Tell the PCF to ignore everything but second, minute and hour, so
130 * that an alarm will trigger the next time the alarm time occurs.
131 */
132 pcf50606_write_multiple(0x14, alarm_disable + 3, 4);
133 /* Unmask the alarm interrupt (might be unneeded) */
134 pcf50606_write(0x5, pcf50606_read(0x5) & ~0x80);
135 /* Make sure wake on RTC is set when shutting down */
136 pcf50606_write(0x8, pcf50606_read(0x8) | 0x10);
137 } else {
138 /* We use this year to indicate a disabled alarm. If you happen to live
139 * around this time and are annoyed by this, feel free to seek out my
140 * grave and do something nasty to it.
141 */
142 pcf50606_write(0x17, 0x99);
143 /* Make sure we don't wake on RTC after shutting down */
144 pcf50606_write(0x8, pcf50606_read(0x8) & ~0x10);
145 }
146 restore_irq(oldlevel);
147 return;
148}
149
150/**
151 * Check if alarm caused unit to start.
152 */
153bool rtc_check_alarm_started(bool release_alarm)
154{
155 static bool run_before = false, alarm_state;
156 bool rc;
157
158 if (run_before) {
159 rc = alarm_state;
160 alarm_state &= ~release_alarm;
161 } else {
162 char rt[3], at[3];
163 /* The Ipod bootloader seems to read (and thus clear) the PCF interrupt
164 * registers, so we need to find some other way to detect if an alarm
165 * just happened
166 */
167 int oldlevel = disable_irq_save();
168 pcf50606_read_multiple(0x0a, rt, 3);
169 pcf50606_read_multiple(0x11, at, 3);
170 restore_irq(oldlevel);
171
172 /* If alarm time and real time match within 10 seconds of each other, we
173 * assume an alarm just triggered
174 */
175 rc = alarm_state = rt[1] == at[1] && rt[2] == at[2]
176 && (rt[0] - at[0]) <= 10;
177 run_before = true;
178 }
179 return rc;
180}
181
182
183/* set alarm time registers to the given time (repeat once per day) */
184void rtc_set_alarm(int h, int m)
185{
186 int oldlevel = disable_irq_save();
187 /* Set us to wake at the first second of the specified time */
188 pcf50606_write(0x11, 0);
189 /* Convert to BCD */
190 pcf50606_write(0x12, ((m/10) << 4) | m%10);
191 pcf50606_write(0x13, ((h/10) << 4) | h%10);
192 restore_irq(oldlevel);
193}
194
195/* read out the current alarm time */
196void rtc_get_alarm(int *h, int *m)
197{
198 char buf[2];
199
200 int oldlevel = disable_irq_save();
201 pcf50606_read_multiple(0x12, buf, 2);
202 restore_irq(oldlevel);
203 /* Convert from BCD */
204 *m = ((buf[0] >> 4) & 0x7)*10 + (buf[0] & 0x0f);
205 *h = ((buf[1] >> 4) & 0x3)*10 + (buf[1] & 0x0f);
206}