1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "pico.h"
8 
9 #include "hardware/irq.h"
10 #include "hardware/rtc.h"
11 #include "hardware/resets.h"
12 #include "hardware/clocks.h"
13 
14 // Set this when setting an alarm
15 static rtc_callback_t _callback = NULL;
16 static bool _alarm_repeats = false;
17 
rtc_running(void)18 bool rtc_running(void) {
19     return (rtc_hw->ctrl & RTC_CTRL_RTC_ACTIVE_BITS);
20 }
21 
rtc_init(void)22 void rtc_init(void) {
23     // Get clk_rtc freq and make sure it is running
24     uint rtc_freq = clock_get_hz(clk_rtc);
25     assert(rtc_freq != 0);
26 
27     // Take rtc out of reset now that we know clk_rtc is running
28     reset_unreset_block_num_wait_blocking(RESET_RTC);
29 
30     // Set up the 1 second divider.
31     // If rtc_freq is 400 then clkdiv_m1 should be 399
32     rtc_freq -= 1;
33 
34     // Check the freq is not too big to divide
35     assert(rtc_freq <= RTC_CLKDIV_M1_BITS);
36 
37     // Write divide value
38     rtc_hw->clkdiv_m1 = rtc_freq;
39 }
40 
valid_datetime(const datetime_t * t)41 static bool valid_datetime(const datetime_t *t) {
42     // Valid ranges taken from RTC doc. Note when setting an RTC alarm
43     // these values are allowed to be -1 to say "don't match this value"
44     if (!(t->year >= 0 && t->year <= 4095)) return false;
45     if (!(t->month >= 1 && t->month <= 12)) return false;
46     if (!(t->day >= 1 && t->day <= 31)) return false;
47     if (!(t->dotw >= 0 && t->dotw <= 6)) return false;
48     if (!(t->hour >= 0 && t->hour <= 23)) return false;
49     if (!(t->min >= 0 && t->min <= 59)) return false;
50     if (!(t->sec >= 0 && t->sec <= 59)) return false;
51     return true;
52 }
53 
rtc_set_datetime(const datetime_t * t)54 bool rtc_set_datetime(const datetime_t *t) {
55     if (!valid_datetime(t)) {
56         return false;
57     }
58 
59     // Disable RTC
60     rtc_hw->ctrl = 0;
61     // Wait while it is still active
62     while (rtc_running()) {
63         tight_loop_contents();
64     }
65 
66     // Write to setup registers
67     rtc_hw->setup_0 = (((uint32_t)t->year)  << RTC_SETUP_0_YEAR_LSB ) |
68                       (((uint32_t)t->month) << RTC_SETUP_0_MONTH_LSB) |
69                       (((uint32_t)t->day)   << RTC_SETUP_0_DAY_LSB);
70     rtc_hw->setup_1 = (((uint32_t)t->dotw)  << RTC_SETUP_1_DOTW_LSB) |
71                       (((uint32_t)t->hour)  << RTC_SETUP_1_HOUR_LSB) |
72                       (((uint32_t)t->min)   << RTC_SETUP_1_MIN_LSB)  |
73                       (((uint32_t)t->sec)   << RTC_SETUP_1_SEC_LSB);
74 
75     // Load setup values into rtc clock domain
76     rtc_hw->ctrl = RTC_CTRL_LOAD_BITS;
77 
78     // Enable RTC and wait for it to be running
79     rtc_hw->ctrl = RTC_CTRL_RTC_ENABLE_BITS;
80     while (!rtc_running()) {
81         tight_loop_contents();
82     }
83 
84     return true;
85 }
86 
rtc_get_datetime(datetime_t * t)87 bool rtc_get_datetime(datetime_t *t) {
88     // Make sure RTC is running
89     if (!rtc_running()) {
90         return false;
91     }
92 
93     // Note: RTC_0 should be read before RTC_1
94     uint32_t rtc_0 = rtc_hw->rtc_0;
95     uint32_t rtc_1 = rtc_hw->rtc_1;
96 
97     t->dotw  = (int8_t) ((rtc_0 & RTC_RTC_0_DOTW_BITS ) >> RTC_RTC_0_DOTW_LSB);
98     t->hour  = (int8_t) ((rtc_0 & RTC_RTC_0_HOUR_BITS ) >> RTC_RTC_0_HOUR_LSB);
99     t->min   = (int8_t) ((rtc_0 & RTC_RTC_0_MIN_BITS  ) >> RTC_RTC_0_MIN_LSB);
100     t->sec   = (int8_t) ((rtc_0 & RTC_RTC_0_SEC_BITS  ) >> RTC_RTC_0_SEC_LSB);
101     t->year  = (int16_t) ((rtc_1 & RTC_RTC_1_YEAR_BITS ) >> RTC_RTC_1_YEAR_LSB);
102     t->month = (int8_t) ((rtc_1 & RTC_RTC_1_MONTH_BITS) >> RTC_RTC_1_MONTH_LSB);
103     t->day   = (int8_t) ((rtc_1 & RTC_RTC_1_DAY_BITS  ) >> RTC_RTC_1_DAY_LSB);
104 
105     return true;
106 }
107 
rtc_enable_alarm(void)108 void rtc_enable_alarm(void) {
109     // Set matching and wait for it to be enabled
110     hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MATCH_ENA_BITS);
111     while(!(rtc_hw->irq_setup_0 & RTC_IRQ_SETUP_0_MATCH_ACTIVE_BITS)) {
112         tight_loop_contents();
113     }
114 }
115 
rtc_irq_handler(void)116 static void rtc_irq_handler(void) {
117     // Always disable the alarm to clear the current IRQ.
118     // Even if it is a repeatable alarm, we don't want it to keep firing.
119     // If it matches on a second it can keep firing for that second.
120     rtc_disable_alarm();
121 
122     if (_alarm_repeats) {
123         // If it is a repeatable alarm, re enable the alarm.
124         rtc_enable_alarm();
125     }
126 
127     // Call user callback function
128     if (_callback) {
129         _callback();
130     }
131 }
132 
rtc_alarm_repeats(const datetime_t * t)133 static bool rtc_alarm_repeats(const datetime_t *t) {
134     // If any value is set to -1 then we don't match on that value
135     // hence the alarm will eventually repeat
136     if (t->year  < 0) return true;
137     if (t->month < 0) return true;
138     if (t->day   < 0) return true;
139     if (t->dotw  < 0) return true;
140     if (t->hour  < 0) return true;
141     if (t->min   < 0) return true;
142     if (t->sec   < 0) return true;
143     return false;
144 }
145 
rtc_set_alarm(const datetime_t * t,rtc_callback_t user_callback)146 void rtc_set_alarm(const datetime_t *t, rtc_callback_t user_callback) {
147     rtc_disable_alarm();
148 
149     // Only add to setup if it isn't -1
150     rtc_hw->irq_setup_0 = ((t->year  < 0) ? 0 : (((uint32_t)t->year)  << RTC_IRQ_SETUP_0_YEAR_LSB )) |
151                           ((t->month < 0) ? 0 : (((uint32_t)t->month) << RTC_IRQ_SETUP_0_MONTH_LSB)) |
152                           ((t->day   < 0) ? 0 : (((uint32_t)t->day)   << RTC_IRQ_SETUP_0_DAY_LSB  ));
153     rtc_hw->irq_setup_1 = ((t->dotw  < 0) ? 0 : (((uint32_t)t->dotw)  << RTC_IRQ_SETUP_1_DOTW_LSB)) |
154                           ((t->hour  < 0) ? 0 : (((uint32_t)t->hour)  << RTC_IRQ_SETUP_1_HOUR_LSB)) |
155                           ((t->min   < 0) ? 0 : (((uint32_t)t->min)   << RTC_IRQ_SETUP_1_MIN_LSB )) |
156                           ((t->sec   < 0) ? 0 : (((uint32_t)t->sec)   << RTC_IRQ_SETUP_1_SEC_LSB ));
157 
158     // Set the match enable bits for things we care about
159     if (t->year  >= 0) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_YEAR_ENA_BITS);
160     if (t->month >= 0) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MONTH_ENA_BITS);
161     if (t->day   >= 0) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_DAY_ENA_BITS);
162     if (t->dotw  >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_DOTW_ENA_BITS);
163     if (t->hour  >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_HOUR_ENA_BITS);
164     if (t->min   >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_MIN_ENA_BITS);
165     if (t->sec   >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_SEC_ENA_BITS);
166 
167     // Does it repeat? I.e. do we not match on any of the bits
168     _alarm_repeats = rtc_alarm_repeats(t);
169 
170     // Store function pointer we can call later
171     _callback = user_callback;
172 
173     irq_set_exclusive_handler(RTC_IRQ, rtc_irq_handler);
174 
175     // Enable the IRQ at the peri
176     rtc_hw->inte = RTC_INTE_RTC_BITS;
177 
178     // Enable the IRQ at the proc
179     irq_set_enabled(RTC_IRQ, true);
180 
181     rtc_enable_alarm();
182 }
183 
rtc_disable_alarm(void)184 void rtc_disable_alarm(void) {
185     // Disable matching and wait for it to stop being active
186     hw_clear_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MATCH_ENA_BITS);
187     while(rtc_hw->irq_setup_0 & RTC_IRQ_SETUP_0_MATCH_ACTIVE_BITS) {
188         tight_loop_contents();
189     }
190 }
191