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