1 /*
2  * Copyright (c) 2024 Analog Devices, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT adi_max32_rtc_counter
8 
9 #include <zephyr/drivers/counter.h>
10 #include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
11 #include <zephyr/drivers/pinctrl.h>
12 #include <zephyr/irq.h>
13 
14 #include <rtc.h>
15 #include <wrap_max32_lp.h>
16 
17 /* Resoultion is 1sec for time of day alarm*/
18 #define MAX32_RTC_COUNTER_FREQ 1
19 
20 /* 20bits used for time of day alarm */
21 #define MAX32_RTC_COUNTER_MAX_VALUE ((1 << 21) - 1)
22 
23 #define MAX32_RTC_COUNTER_INT_FL MXC_RTC_INT_FL_LONG
24 #define MAX32_RTC_COUNTER_INT_EN MXC_RTC_INT_EN_LONG
25 
26 struct max32_rtc_data {
27 	counter_alarm_callback_t alarm_callback;
28 	counter_top_callback_t top_callback;
29 	void *alarm_user_data;
30 	void *top_user_data;
31 };
32 
33 struct max32_rtc_config {
34 	struct counter_config_info info;
35 	mxc_rtc_regs_t *regs;
36 	void (*irq_func)(void);
37 };
38 
api_start(const struct device * dev)39 static int api_start(const struct device *dev)
40 {
41 	/* Ensure that both sec and subsec are reset to 0 */
42 	while (MXC_RTC_Init(0, 0) == E_BUSY) {
43 		;
44 	}
45 
46 	while (MXC_RTC_Start() == E_BUSY) {
47 		;
48 	}
49 
50 	while (MXC_RTC_EnableInt(MAX32_RTC_COUNTER_INT_EN) == E_BUSY) {
51 		;
52 	}
53 
54 	return 0;
55 }
56 
api_stop(const struct device * dev)57 static int api_stop(const struct device *dev)
58 {
59 	ARG_UNUSED(dev);
60 
61 	while (MXC_RTC_DisableInt(MAX32_RTC_COUNTER_INT_EN) == E_BUSY) {
62 		;
63 	}
64 	MXC_RTC_Stop();
65 
66 	return 0;
67 }
68 
api_get_value(const struct device * dev,uint32_t * ticks)69 static int api_get_value(const struct device *dev, uint32_t *ticks)
70 {
71 	const struct max32_rtc_config *cfg = dev->config;
72 	mxc_rtc_regs_t *regs = cfg->regs;
73 	uint32_t sec = 0, subsec = 0;
74 
75 	/* Read twice incase of glitch */
76 	sec = regs->sec;
77 	if (regs->sec != sec) {
78 		sec = regs->sec;
79 	}
80 
81 	/* Read twice incase of glitch */
82 	subsec = regs->ssec;
83 	if (regs->ssec != subsec) {
84 		subsec = regs->ssec;
85 	}
86 
87 	*ticks = sec;
88 	if (subsec >= (MXC_RTC_MAX_SSEC / 2)) {
89 		*ticks += 1;
90 	}
91 
92 	return 0;
93 }
94 
api_set_top_value(const struct device * dev,const struct counter_top_cfg * counter_cfg)95 static int api_set_top_value(const struct device *dev, const struct counter_top_cfg *counter_cfg)
96 {
97 	const struct max32_rtc_config *cfg = dev->config;
98 	struct max32_rtc_data *const data = dev->data;
99 
100 	if (counter_cfg->ticks == 0) {
101 		return -EINVAL;
102 	}
103 
104 	if (counter_cfg->ticks != cfg->info.max_top_value) {
105 		return -ENOTSUP;
106 	}
107 
108 	data->top_callback = counter_cfg->callback;
109 	data->top_user_data = counter_cfg->user_data;
110 
111 	return 0;
112 }
113 
api_get_pending_int(const struct device * dev)114 static uint32_t api_get_pending_int(const struct device *dev)
115 {
116 	ARG_UNUSED(dev);
117 	int flags = MXC_RTC_GetFlags();
118 
119 	if (flags & MAX32_RTC_COUNTER_INT_FL) {
120 		return 1;
121 	}
122 
123 	return 0;
124 }
125 
api_get_top_value(const struct device * dev)126 static uint32_t api_get_top_value(const struct device *dev)
127 {
128 	const struct max32_rtc_config *cfg = dev->config;
129 
130 	return cfg->info.max_top_value;
131 }
132 
api_set_alarm(const struct device * dev,uint8_t chan,const struct counter_alarm_cfg * alarm_cfg)133 static int api_set_alarm(const struct device *dev, uint8_t chan,
134 			 const struct counter_alarm_cfg *alarm_cfg)
135 {
136 	int ret;
137 	struct max32_rtc_data *data = dev->data;
138 	uint32_t ticks = alarm_cfg->ticks;
139 	uint32_t current;
140 
141 	/* Alarm frequenct is 1Hz so that it seems ticks becomes 0
142 	 * some times, in that case system being blocked.
143 	 * Set it to 1 if ticks is 0
144 	 */
145 	if (ticks == 0) {
146 		ticks = 1;
147 	}
148 
149 	if (alarm_cfg->ticks > api_get_top_value(dev)) {
150 		return -EINVAL;
151 	}
152 
153 	if (data->alarm_callback != NULL) {
154 		return -EBUSY;
155 	}
156 
157 	api_stop(dev);
158 
159 	api_get_value(dev, &current);
160 	if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) {
161 		ticks += current;
162 	}
163 
164 	ret = MXC_RTC_SetTimeofdayAlarm(ticks);
165 	if (ret == E_BUSY) {
166 		ret = -EBUSY;
167 	}
168 
169 	if (ret == 0) {
170 		data->alarm_callback = alarm_cfg->callback;
171 		data->alarm_user_data = alarm_cfg->user_data;
172 	}
173 
174 	api_start(dev);
175 
176 	return ret;
177 }
178 
api_cancel_alarm(const struct device * dev,uint8_t chan)179 static int api_cancel_alarm(const struct device *dev, uint8_t chan)
180 {
181 	struct max32_rtc_data *data = dev->data;
182 
183 	while (MXC_RTC_DisableInt(MAX32_RTC_COUNTER_INT_EN) == E_BUSY) {
184 		;
185 	}
186 	data->alarm_callback = NULL;
187 
188 	return 0;
189 }
190 
rtc_max32_isr(const struct device * dev)191 static void rtc_max32_isr(const struct device *dev)
192 {
193 	struct max32_rtc_data *const data = dev->data;
194 	int flags = MXC_RTC_GetFlags();
195 
196 	if (flags & MAX32_RTC_COUNTER_INT_FL) {
197 		if (data->alarm_callback) {
198 			counter_alarm_callback_t cb;
199 			uint32_t current;
200 
201 			api_get_value(dev, &current);
202 
203 			cb = data->alarm_callback;
204 			data->alarm_callback = NULL;
205 			cb(dev, 0, current, data->alarm_user_data);
206 		}
207 	}
208 
209 	/* Clear all flags */
210 	MXC_RTC_ClearFlags(flags);
211 }
212 
rtc_max32_init(const struct device * dev)213 static int rtc_max32_init(const struct device *dev)
214 {
215 	const struct max32_rtc_config *cfg = dev->config;
216 
217 	while (MXC_RTC_Init(0, 0) == E_BUSY) {
218 		;
219 	}
220 
221 	api_stop(dev);
222 
223 	cfg->irq_func();
224 
225 	return 0;
226 }
227 
228 static DEVICE_API(counter, counter_rtc_max32_driver_api) = {
229 	.start = api_start,
230 	.stop = api_stop,
231 	.get_value = api_get_value,
232 	.set_top_value = api_set_top_value,
233 	.get_pending_int = api_get_pending_int,
234 	.get_top_value = api_get_top_value,
235 	.set_alarm = api_set_alarm,
236 	.cancel_alarm = api_cancel_alarm,
237 };
238 
239 #define COUNTER_RTC_MAX32_INIT(_num)                                                               \
240 	static struct max32_rtc_data rtc_max32_data_##_num;                                        \
241 	static void max32_rtc_irq_init_##_num(void)                                                \
242 	{                                                                                          \
243 		IRQ_CONNECT(DT_INST_IRQN(_num), DT_INST_IRQ(_num, priority), rtc_max32_isr,        \
244 			    DEVICE_DT_INST_GET(_num), 0);                                          \
245 		irq_enable(DT_INST_IRQN(_num));                                                    \
246 		if (DT_INST_PROP(_num, wakeup_source)) {                                           \
247 			MXC_LP_EnableRTCAlarmWakeup();                                             \
248 		}                                                                                  \
249 	};                                                                                         \
250 	static const struct max32_rtc_config rtc_max32_config_##_num = {                           \
251 		.info =                                                                            \
252 			{                                                                          \
253 				.max_top_value = MAX32_RTC_COUNTER_MAX_VALUE,                      \
254 				.freq = MAX32_RTC_COUNTER_FREQ,                                    \
255 				.flags = COUNTER_CONFIG_INFO_COUNT_UP,                             \
256 				.channels = 1,                                                     \
257 			},                                                                         \
258 		.regs = (mxc_rtc_regs_t *)DT_INST_REG_ADDR(_num),                                  \
259 		.irq_func = max32_rtc_irq_init_##_num,                                             \
260 	};                                                                                         \
261                                                                                                    \
262 	DEVICE_DT_INST_DEFINE(_num, &rtc_max32_init, NULL, &rtc_max32_data_##_num,                 \
263 			      &rtc_max32_config_##_num, PRE_KERNEL_1,                              \
264 			      CONFIG_COUNTER_INIT_PRIORITY, &counter_rtc_max32_driver_api);
265 
266 DT_INST_FOREACH_STATUS_OKAY(COUNTER_RTC_MAX32_INIT)
267