1 /*
2 * Copyright (c) 2024 Andrew Featherstone
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/clock_control.h>
8 #include <zephyr/drivers/rtc.h>
9 #include <zephyr/irq.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/spinlock.h>
13
14 #include <hardware/irq.h>
15 #include <hardware/rtc.h>
16 #include <hardware/regs/rtc.h>
17
18 #include "rtc_utils.h"
19
20 #define DT_DRV_COMPAT raspberrypi_pico_rtc
21
22 #define CLK_DRV DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0))
23 #define CLK_ID (clock_control_subsys_t) DT_INST_PHA_BY_IDX(0, clocks, 0, clk_id)
24
25 /* struct tm start time: 1st, Jan, 1900 */
26 #define TM_YEAR_REF 1900
27 /* See section 4.8.1 of the RP2040 datasheet. */
28 #define RP2040_RTC_YEAR_MAX 4095
29 #ifdef CONFIG_RTC_ALARM
30 static int rtc_rpi_pico_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
31 struct rtc_time *timeptr);
32 #endif
33 struct rtc_rpi_pico_data {
34 struct k_spinlock lock;
35
36 #ifdef CONFIG_RTC_ALARM
37 struct rtc_time alarm_time;
38 uint16_t alarm_mask;
39 rtc_alarm_callback alarm_callback;
40 void *alarm_user_data;
41 bool alarm_pending;
42 #endif /* CONFIG_RTC_ALARM */
43 };
44
45 static struct rtc_rpi_pico_data rtc_data;
46
47 LOG_MODULE_REGISTER(rtc_rpi, CONFIG_RTC_LOG_LEVEL);
48
49 #ifdef CONFIG_RTC_ALARM
rtc_rpi_isr(const struct device * dev)50 static void rtc_rpi_isr(const struct device *dev)
51 {
52 struct rtc_rpi_pico_data *data = dev->data;
53
54 rtc_alarm_callback callback;
55 void *user_data;
56
57 rtc_disable_alarm();
58
59 K_SPINLOCK(&data->lock) {
60 callback = data->alarm_callback;
61 user_data = data->alarm_user_data;
62 }
63
64 if (callback != NULL) {
65 callback(dev, 0, user_data);
66 } else {
67 data->alarm_pending = true;
68 }
69 /* re-enable the alarm. */
70 rtc_enable_alarm();
71 }
72 #endif
73
rtc_rpi_pico_init(const struct device * dev)74 static int rtc_rpi_pico_init(const struct device *dev)
75 {
76 int ret;
77 #ifdef CONFIG_RTC_ALARM
78 struct rtc_rpi_pico_data *data = dev->data;
79 #endif
80
81 ret = clock_control_on(CLK_DRV, CLK_ID);
82 if (ret < 0) {
83 return ret;
84 }
85
86 #ifdef CONFIG_RTC_ALARM
87 data->alarm_mask = 0;
88 data->alarm_callback = NULL;
89 data->alarm_pending = false;
90
91 IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), rtc_rpi_isr, DEVICE_DT_INST_GET(0),
92 0);
93 irq_enable(DT_INST_IRQN(0));
94 #endif
95 rtc_init();
96 return 0;
97 }
98
rtc_rpi_pico_set_time(const struct device * dev,const struct rtc_time * timeptr)99 static int rtc_rpi_pico_set_time(const struct device *dev, const struct rtc_time *timeptr)
100 {
101 struct rtc_rpi_pico_data *data = dev->data;
102 int err = 0;
103
104 if (timeptr->tm_year + TM_YEAR_REF > RP2040_RTC_YEAR_MAX) {
105 return -EINVAL;
106 }
107
108 if (timeptr->tm_wday == -1) {
109 /* day of the week is expected */
110 return -EINVAL;
111 }
112
113 k_spinlock_key_t key = k_spin_lock(&data->lock);
114 datetime_t dt = {
115 .year = timeptr->tm_year + TM_YEAR_REF,
116 .month = timeptr->tm_mon + 1,
117 .day = timeptr->tm_mday,
118 .dotw = timeptr->tm_wday,
119 .hour = timeptr->tm_hour,
120 .min = timeptr->tm_min,
121 .sec = timeptr->tm_sec,
122 };
123 /* Use the validation in the Pico SDK. */
124 if (!rtc_set_datetime(&dt)) {
125 err = -EINVAL;
126 }
127 k_spin_unlock(&data->lock, key);
128
129 return err;
130 }
131
rtc_rpi_pico_get_time(const struct device * dev,struct rtc_time * timeptr)132 static int rtc_rpi_pico_get_time(const struct device *dev, struct rtc_time *timeptr)
133 {
134 struct rtc_rpi_pico_data *data = dev->data;
135 datetime_t dt;
136 int err = 0;
137 k_spinlock_key_t key = k_spin_lock(&data->lock);
138
139 if (!rtc_get_datetime(&dt)) {
140 err = -ENODATA;
141 }
142
143 timeptr->tm_sec = dt.sec;
144 timeptr->tm_min = dt.min;
145 timeptr->tm_hour = dt.hour;
146 timeptr->tm_mday = dt.day;
147 timeptr->tm_mon = dt.month - 1;
148 timeptr->tm_year = dt.year - TM_YEAR_REF;
149 timeptr->tm_wday = dt.dotw;
150 /* unknown values */
151 timeptr->tm_yday = -1;
152 timeptr->tm_isdst = -1;
153 timeptr->tm_nsec = 0;
154 k_spin_unlock(&data->lock, key);
155
156 return err;
157 }
158
159 #if defined(CONFIG_RTC_ALARM)
rtc_rpi_pico_alarm_get_supported_fields(const struct device * dev,uint16_t id,uint16_t * supported_fields)160 static int rtc_rpi_pico_alarm_get_supported_fields(const struct device *dev, uint16_t id,
161 uint16_t *supported_fields)
162 {
163 ARG_UNUSED(dev);
164
165 if (id != 0) {
166 return -EINVAL;
167 }
168 *supported_fields = RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE |
169 RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_WEEKDAY |
170 RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_MONTH |
171 RTC_ALARM_TIME_MASK_YEAR;
172
173 return 0;
174 }
175
rtc_rpi_pico_alarm_set_time(const struct device * dev,uint16_t id,uint16_t mask,const struct rtc_time * alarm)176 static int rtc_rpi_pico_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask,
177 const struct rtc_time *alarm)
178 {
179 struct rtc_rpi_pico_data *data = dev->data;
180 int err = 0;
181 uint16_t mask_available;
182
183 (void)rtc_rpi_pico_alarm_get_supported_fields(NULL, 0, &mask_available);
184
185 if (mask & ~mask_available) {
186 return -EINVAL;
187 }
188
189 if (!rtc_utils_validate_rtc_time(alarm, mask)) {
190 return -EINVAL;
191 }
192
193 LOG_INF("Setting alarm");
194
195 rtc_disable_alarm();
196 if (mask == 0) {
197 /* Disable the alarm */
198 data->alarm_mask = 0;
199 }
200 k_spinlock_key_t key = k_spin_lock(&data->lock);
201
202 /* Clear before updating. */
203 rtc_hw->irq_setup_0 = 0;
204 rtc_hw->irq_setup_1 = 0;
205
206 /* Set the match enable bits for things we care about */
207 if (mask & RTC_ALARM_TIME_MASK_YEAR) {
208 hw_set_bits(&rtc_hw->irq_setup_0,
209 RTC_IRQ_SETUP_0_YEAR_ENA_BITS |
210 ((alarm->tm_year + TM_YEAR_REF) << RTC_IRQ_SETUP_0_YEAR_LSB));
211 }
212 if (mask & RTC_ALARM_TIME_MASK_MONTH) {
213 hw_set_bits(&rtc_hw->irq_setup_0,
214 RTC_IRQ_SETUP_0_MONTH_ENA_BITS |
215 (alarm->tm_mon << RTC_IRQ_SETUP_0_MONTH_LSB));
216 }
217 if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) {
218 hw_set_bits(&rtc_hw->irq_setup_0,
219 RTC_IRQ_SETUP_0_DAY_ENA_BITS |
220 ((alarm->tm_mday + 1) << RTC_IRQ_SETUP_0_DAY_LSB));
221 }
222 if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) {
223 hw_set_bits(&rtc_hw->irq_setup_1,
224 RTC_IRQ_SETUP_1_DOTW_ENA_BITS |
225 (alarm->tm_wday << RTC_IRQ_SETUP_1_DOTW_LSB));
226 }
227 if (mask & RTC_ALARM_TIME_MASK_HOUR) {
228 hw_set_bits(&rtc_hw->irq_setup_1,
229 RTC_IRQ_SETUP_1_HOUR_ENA_BITS |
230 (alarm->tm_hour << RTC_IRQ_SETUP_1_HOUR_LSB));
231 }
232 if (mask & RTC_ALARM_TIME_MASK_MINUTE) {
233 hw_set_bits(&rtc_hw->irq_setup_1,
234 RTC_IRQ_SETUP_1_MIN_ENA_BITS |
235 (alarm->tm_min << RTC_IRQ_SETUP_1_MIN_LSB));
236 }
237 if (mask & RTC_ALARM_TIME_MASK_SECOND) {
238 hw_set_bits(&rtc_hw->irq_setup_1,
239 RTC_IRQ_SETUP_1_SEC_ENA_BITS |
240 (alarm->tm_sec << RTC_IRQ_SETUP_1_SEC_LSB));
241 }
242 data->alarm_time = *alarm;
243 data->alarm_mask = mask;
244 k_spin_unlock(&data->lock, key);
245
246 /* Enable the IRQ at the peri */
247 rtc_hw->inte = RTC_INTE_RTC_BITS;
248
249 rtc_enable_alarm();
250
251 return err;
252 }
253
rtc_rpi_pico_alarm_get_time(const struct device * dev,uint16_t id,uint16_t * mask,struct rtc_time * timeptr)254 static int rtc_rpi_pico_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
255 struct rtc_time *timeptr)
256 {
257 struct rtc_rpi_pico_data *data = dev->data;
258
259 if (id != 0) {
260 return -EINVAL;
261 }
262
263 K_SPINLOCK(&data->lock) {
264 *timeptr = data->alarm_time;
265 *mask = data->alarm_mask;
266 }
267
268 return 0;
269 }
270
rtc_rpi_pico_alarm_is_pending(const struct device * dev,uint16_t id)271 static int rtc_rpi_pico_alarm_is_pending(const struct device *dev, uint16_t id)
272 {
273 struct rtc_rpi_pico_data *data = dev->data;
274 int ret = 0;
275
276 if (id != 0) {
277 return -EINVAL;
278 }
279
280 K_SPINLOCK(&data->lock) {
281 ret = data->alarm_pending ? 1 : 0;
282 data->alarm_pending = false;
283 }
284
285 return ret;
286 }
287
rtc_rpi_pico_alarm_set_callback(const struct device * dev,uint16_t id,rtc_alarm_callback callback,void * user_data)288 static int rtc_rpi_pico_alarm_set_callback(const struct device *dev, uint16_t id,
289 rtc_alarm_callback callback, void *user_data)
290 {
291 struct rtc_rpi_pico_data *data = dev->data;
292
293 if (id != 0) {
294 return -EINVAL;
295 }
296
297 K_SPINLOCK(&data->lock) {
298 data->alarm_callback = callback;
299 data->alarm_user_data = user_data;
300 if ((callback == NULL) && (user_data == NULL)) {
301 rtc_disable_alarm();
302 }
303 }
304
305 return 0;
306 }
307
308 #endif /* CONFIG_RTC_ALARM */
309
310 static DEVICE_API(rtc, rtc_rpi_pico_driver_api) = {
311 .set_time = rtc_rpi_pico_set_time,
312 .get_time = rtc_rpi_pico_get_time,
313 #if defined(CONFIG_RTC_ALARM)
314 .alarm_get_supported_fields = rtc_rpi_pico_alarm_get_supported_fields,
315 .alarm_set_time = rtc_rpi_pico_alarm_set_time,
316 .alarm_get_time = rtc_rpi_pico_alarm_get_time,
317 .alarm_is_pending = rtc_rpi_pico_alarm_is_pending,
318 .alarm_set_callback = rtc_rpi_pico_alarm_set_callback,
319 #endif /* CONFIG_RTC_ALARM */
320 };
321
322 DEVICE_DT_INST_DEFINE(0, &rtc_rpi_pico_init, NULL, &rtc_data, NULL, POST_KERNEL,
323 CONFIG_RTC_INIT_PRIORITY, &rtc_rpi_pico_driver_api);
324