1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  *
4  * Copyright (c) 2024 Andriy Gelman
5  * Author: Andriy Gelman  <andriy.gelman@gmail.com>
6  */
7 
8 #include <zephyr/drivers/rtc.h>
9 #include <zephyr/logging/log.h>
10 #include <zephyr/sys/util.h>
11 #include <zephyr/kernel.h>
12 
13 #include <soc.h>
14 #include <xmc_rtc.h>
15 #include <xmc_scu.h>
16 
17 #define DT_DRV_COMPAT infineon_xmc4xxx_rtc
18 
19 #define RTC_XMC4XXX_DEFAULT_PRESCALER 0x7fff
20 
21 #define RTC_XMC4XXX_SUPPORTED_ALARM_MASK                                                           \
22 	(RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR |      \
23 	 RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_YEAR)
24 
25 struct rtc_xmc4xxx_data {
26 #if defined(CONFIG_RTC_ALARM)
27 	rtc_alarm_callback alarm_callback;
28 	void *alarm_user_data;
29 #endif
30 #if defined(CONFIG_RTC_UPDATE)
31 	rtc_update_callback update_callback;
32 	void *update_user_data;
33 #endif
34 };
35 
rtc_xmc4xxx_set_time(const struct device * dev,const struct rtc_time * timeptr)36 static int rtc_xmc4xxx_set_time(const struct device *dev, const struct rtc_time *timeptr)
37 {
38 	const struct tm *stdtime;
39 
40 	if (timeptr == NULL) {
41 		return -EINVAL;
42 	}
43 
44 	XMC_RTC_Stop();
45 
46 	stdtime = rtc_time_to_tm((struct rtc_time *)timeptr);
47 	XMC_RTC_SetTimeStdFormat(stdtime);
48 
49 	XMC_RTC_Start();
50 
51 	return 0;
52 }
53 
rtc_xmc4xxx_get_time(const struct device * dev,struct rtc_time * timeptr)54 static int rtc_xmc4xxx_get_time(const struct device *dev, struct rtc_time *timeptr)
55 {
56 	struct tm *stdtime = rtc_time_to_tm(timeptr);
57 
58 	if (!XMC_RTC_IsRunning()) {
59 		return -ENODATA;
60 	}
61 
62 	if (stdtime == NULL) {
63 		return -EINVAL;
64 	}
65 
66 	XMC_RTC_GetTimeStdFormat(stdtime);
67 	timeptr->tm_nsec = 0;
68 
69 	return 0;
70 }
71 
72 #if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE)
rtc_xmc4xxx_isr(const struct device * dev)73 static void rtc_xmc4xxx_isr(const struct device *dev)
74 {
75 	struct rtc_xmc4xxx_data *dev_data = dev->data;
76 
77 	uint32_t event = SCU_INTERRUPT->SRRAW;
78 
79 #if defined(CONFIG_RTC_ALARM)
80 	if ((event & XMC_SCU_INTERRUPT_EVENT_RTC_ALARM) != 0) {
81 		if (dev_data->alarm_callback != NULL) {
82 			dev_data->alarm_callback(dev, 0, dev_data->alarm_user_data);
83 		}
84 		XMC_SCU_INTERRUPT_ClearEventStatus(XMC_SCU_INTERRUPT_EVENT_RTC_ALARM);
85 	}
86 #endif
87 
88 #if defined(CONFIG_RTC_UPDATE)
89 	if ((event & XMC_SCU_INTERRUPT_EVENT_RTC_PERIODIC) != 0) {
90 		if (dev_data->update_callback != NULL) {
91 			dev_data->update_callback(dev, dev_data->update_user_data);
92 		}
93 		XMC_SCU_INTERRUPT_ClearEventStatus(XMC_SCU_INTERRUPT_EVENT_RTC_PERIODIC);
94 	}
95 #endif
96 }
97 #endif
98 
99 #ifdef CONFIG_RTC_ALARM
rtc_xmc4xxx_alarm_get_supported_fields(const struct device * dev,uint16_t id,uint16_t * mask)100 static int rtc_xmc4xxx_alarm_get_supported_fields(const struct device *dev, uint16_t id,
101 						  uint16_t *mask)
102 {
103 	ARG_UNUSED(dev);
104 	ARG_UNUSED(id);
105 
106 	*mask = RTC_XMC4XXX_SUPPORTED_ALARM_MASK;
107 	return 0;
108 }
109 
rtc_xmc4xxx_alarm_set_time(const struct device * dev,uint16_t id,uint16_t mask,const struct rtc_time * timeptr)110 static int rtc_xmc4xxx_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask,
111 				      const struct rtc_time *timeptr)
112 {
113 	const struct tm *stdtime = rtc_time_to_tm((struct rtc_time *)timeptr);
114 
115 	if (id != 0 || (mask > 0 && timeptr == NULL)) {
116 		return -EINVAL;
117 	}
118 
119 	if (mask == 0) {
120 		XMC_RTC_DisableEvent(XMC_RTC_EVENT_ALARM);
121 		XMC_SCU_INTERRUPT_ClearEventStatus(XMC_SCU_INTERRUPT_EVENT_RTC_ALARM);
122 		return 0;
123 	}
124 
125 	if (mask != RTC_XMC4XXX_SUPPORTED_ALARM_MASK) {
126 		return -EINVAL;
127 	}
128 
129 	XMC_RTC_SetAlarmStdFormat(stdtime);
130 	XMC_RTC_EnableEvent(XMC_RTC_EVENT_ALARM);
131 
132 	return 0;
133 }
134 
rtc_xmc4xxx_alarm_get_time(const struct device * dev,uint16_t id,uint16_t * mask,struct rtc_time * timeptr)135 static int rtc_xmc4xxx_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
136 				      struct rtc_time *timeptr)
137 {
138 	ARG_UNUSED(dev);
139 	struct tm *stdtime = rtc_time_to_tm(timeptr);
140 
141 	if (id != 0 || mask == NULL || timeptr == NULL) {
142 		return -EINVAL;
143 	}
144 
145 	*mask = RTC_XMC4XXX_SUPPORTED_ALARM_MASK;
146 
147 	XMC_RTC_GetAlarmStdFormat(stdtime);
148 
149 	return 0;
150 }
151 
rtc_xmc4xxx_alarm_is_pending(const struct device * dev,uint16_t id)152 static int rtc_xmc4xxx_alarm_is_pending(const struct device *dev, uint16_t id)
153 {
154 	ARG_UNUSED(dev);
155 	unsigned int key;
156 	int alarm = 0;
157 	uint32_t event;
158 
159 	if (id != 0) {
160 		return -EINVAL;
161 	}
162 
163 	key = irq_lock();
164 	event = SCU_INTERRUPT->SRRAW;
165 
166 	if ((event & XMC_SCU_INTERRUPT_EVENT_RTC_ALARM) != 0) {
167 		alarm = 1;
168 		XMC_SCU_INTERRUPT_ClearEventStatus(XMC_SCU_INTERRUPT_EVENT_RTC_ALARM);
169 	}
170 	irq_unlock(key);
171 
172 	return alarm;
173 }
174 
rtc_xmc4xxx_alarm_set_callback(const struct device * dev,uint16_t id,rtc_alarm_callback callback,void * user_data)175 static int rtc_xmc4xxx_alarm_set_callback(const struct device *dev, uint16_t id,
176 					  rtc_alarm_callback callback, void *user_data)
177 {
178 	struct rtc_xmc4xxx_data *dev_data = dev->data;
179 	unsigned int key;
180 
181 	if (id != 0) {
182 		return -EINVAL;
183 	}
184 
185 	key = irq_lock();
186 	dev_data->alarm_callback = callback;
187 	dev_data->alarm_user_data = user_data;
188 	irq_unlock(key);
189 
190 	if (dev_data->alarm_callback) {
191 		XMC_SCU_INTERRUPT_EnableEvent(XMC_SCU_INTERRUPT_EVENT_RTC_ALARM);
192 	} else {
193 		XMC_SCU_INTERRUPT_DisableEvent(XMC_SCU_INTERRUPT_EVENT_RTC_ALARM);
194 	}
195 
196 	return 0;
197 }
198 #endif /* CONFIG_RTC_ALARM */
199 
200 #ifdef CONFIG_RTC_UPDATE
rtc_xmc4xxx_update_set_callback(const struct device * dev,rtc_update_callback callback,void * user_data)201 static int rtc_xmc4xxx_update_set_callback(const struct device *dev, rtc_update_callback callback,
202 					   void *user_data)
203 {
204 	struct rtc_xmc4xxx_data *dev_data = dev->data;
205 	unsigned int key;
206 
207 	key = irq_lock();
208 	dev_data->update_callback = callback;
209 	dev_data->update_user_data = user_data;
210 	irq_unlock(key);
211 
212 	if (dev_data->update_callback) {
213 		XMC_RTC_EnableEvent(XMC_RTC_EVENT_PERIODIC_SECONDS);
214 		XMC_SCU_INTERRUPT_EnableEvent(XMC_SCU_INTERRUPT_EVENT_RTC_PERIODIC);
215 	} else {
216 		XMC_SCU_INTERRUPT_DisableEvent(XMC_SCU_INTERRUPT_EVENT_RTC_PERIODIC);
217 		XMC_RTC_DisableEvent(XMC_RTC_EVENT_PERIODIC_SECONDS);
218 	}
219 
220 	return 0;
221 }
222 #endif /* CONFIG_RTC_UPDATE */
223 
224 static DEVICE_API(rtc, rtc_xmc4xxx_driver_api) = {
225 	.set_time = rtc_xmc4xxx_set_time,
226 	.get_time = rtc_xmc4xxx_get_time,
227 #ifdef CONFIG_RTC_ALARM
228 	.alarm_get_supported_fields = rtc_xmc4xxx_alarm_get_supported_fields,
229 	.alarm_set_time = rtc_xmc4xxx_alarm_set_time,
230 	.alarm_get_time = rtc_xmc4xxx_alarm_get_time,
231 	.alarm_is_pending = rtc_xmc4xxx_alarm_is_pending,
232 	.alarm_set_callback = rtc_xmc4xxx_alarm_set_callback,
233 #endif
234 #ifdef CONFIG_RTC_UPDATE
235 	.update_set_callback = rtc_xmc4xxx_update_set_callback,
236 #endif
237 };
238 
239 #if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE)
rtc_xmc4xxx_irq_config(void)240 static void rtc_xmc4xxx_irq_config(void)
241 {
242 	/* RTC and watchdog share the same interrupt. Shared interrupts must */
243 	/* be enabled if WDT is enabled and RTC is using alarm or update feature */
244 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), rtc_xmc4xxx_isr,
245 		    DEVICE_DT_INST_GET(0), 0);
246 	irq_enable(DT_INST_IRQN(0));
247 }
248 #endif
249 
rtc_xmc4xxx_init(const struct device * dev)250 static int rtc_xmc4xxx_init(const struct device *dev)
251 {
252 	if (!XMC_RTC_IsRunning()) {
253 		if (!XMC_SCU_HIB_IsHibernateDomainEnabled()) {
254 			XMC_SCU_HIB_EnableHibernateDomain();
255 		}
256 		XMC_RTC_SetPrescaler(RTC_XMC4XXX_DEFAULT_PRESCALER);
257 	}
258 
259 #if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE)
260 	rtc_xmc4xxx_irq_config();
261 #endif
262 
263 	return 0;
264 }
265 
266 
267 static struct rtc_xmc4xxx_data rtc_xmc4xxx_data_0;
268 
269 DEVICE_DT_INST_DEFINE(0, rtc_xmc4xxx_init, NULL, &rtc_xmc4xxx_data_0, NULL,
270 		      POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, &rtc_xmc4xxx_driver_api);
271