1 /*
2  * Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company) or
3  * an affiliate of Cypress Semiconductor Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @brief RTC driver for Infineon CAT1 MCU family.
10  */
11 
12 #include <zephyr/drivers/rtc.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/device.h>
15 #include <zephyr/logging/log.h>
16 #include <cy_pdl.h>
17 
18 LOG_MODULE_REGISTER(ifx_cat1_rtc, CONFIG_RTC_LOG_LEVEL);
19 
20 #define DT_DRV_COMPAT infineon_cat1_rtc
21 
22 #define _IFX_CAT1_RTC_STATE_UNINITIALIZED 0
23 #define _IFX_CAT1_RTC_STATE_ENABLED       1
24 #define _IFX_CAT1_RTC_STATE_TIME_SET      2
25 
26 #define _IFX_CAT1_RTC_INIT_CENTURY 2000
27 #define _IFX_CAT1_RTC_TM_YEAR_BASE 1900
28 
29 #if defined(CONFIG_SOC_FAMILY_INFINEON_CAT1B)
30 #if defined(SRSS_BACKUP_NUM_BREG3) && (SRSS_BACKUP_NUM_BREG3 > 0)
31 #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET3[SRSS_BACKUP_NUM_BREG3 - 1])
32 #elif defined(SRSS_BACKUP_NUM_BREG2) && (SRSS_BACKUP_NUM_BREG2 > 0)
33 #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET2[SRSS_BACKUP_NUM_BREG2 - 1])
34 #elif defined(SRSS_BACKUP_NUM_BREG1) && (SRSS_BACKUP_NUM_BREG1 > 0)
35 #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET1[SRSS_BACKUP_NUM_BREG1 - 1])
36 #elif defined(SRSS_BACKUP_NUM_BREG0) && (SRSS_BACKUP_NUM_BREG0 > 0)
37 #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET0[SRSS_BACKUP_NUM_BREG0 - 1])
38 #endif
39 #endif
40 
41 #define _IFX_CAT1_RTC_BREG_CENTURY_Pos 0UL
42 #define _IFX_CAT1_RTC_BREG_CENTURY_Msk 0x0000FFFFUL
43 #define _IFX_CAT1_RTC_BREG_STATE_Pos   16UL
44 #define _IFX_CAT1_RTC_BREG_STATE_Msk   0xFFFF0000UL
45 
46 static const uint32_t _IFX_CAT1_RTC_MAX_RETRY = 10;
47 static const uint32_t _IFX_CAT1_RTC_RETRY_DELAY_MS = 1;
48 
49 static cy_stc_rtc_dst_t *_ifx_cat1_rtc_dst;
50 
51 #ifdef CONFIG_PM
_ifx_cat1_rtc_syspm_callback(cy_stc_syspm_callback_params_t * params,cy_en_syspm_callback_mode_t mode)52 static cy_en_syspm_status_t _ifx_cat1_rtc_syspm_callback(cy_stc_syspm_callback_params_t *params,
53 							 cy_en_syspm_callback_mode_t mode)
54 {
55 	return Cy_RTC_DeepSleepCallback(params, mode);
56 }
57 
58 static cy_stc_syspm_callback_params_t _ifx_cat1_rtc_pm_cb_params = {NULL, NULL};
59 static cy_stc_syspm_callback_t _ifx_cat1_rtc_pm_cb = {
60 	.callback = &_ifx_cat1_rtc_syspm_callback,
61 	.type = CY_SYSPM_DEEPSLEEP,
62 	.callbackParams = &_ifx_cat1_rtc_pm_cb_params,
63 };
64 #endif /* CONFIG_PM */
65 
66 #define _IFX_CAT1_RTC_WAIT_ONE_MS() Cy_SysLib_Delay(_IFX_CAT1_RTC_RETRY_DELAY_MS);
67 
68 /* Internal macro to validate RTC year parameter falls within 21st century */
69 #define IFX_CAT1_RTC_VALID_CENTURY(year) ((year) >= _IFX_CAT1_RTC_INIT_CENTURY)
70 
71 #define MAX_IFX_CAT1_CAL (60)
72 
73 /* Convert parts per billion to groupings of 128 ticks added or removed from one hour of clock
74  * cycles at 32768 Hz.
75  *
76  * ROUND_DOWN(ppb * 32768Hz * 60min * 60sec / 1000000000, 128) / 128
77  * ROUND_DOWN(ppb * 117964800 / 1000000000, 128) / 128
78  * ROUND_DOWN(ppb * 9216 / 78125, 128) / 128
79  */
80 #define PPB_TO_WCO_PULSE_SETS(ppb) ((ROUND_DOWN((ppb * 9216 / 78125), 128)) / 128)
81 
82 /* Convert groupings of 128 ticks added or removed from one hour of clock cycles at
83  * 32768 Hz to parts per billion
84  *
85  * wps * 128 * 1000000000 / 32768Hz * 60min * 60sec
86  * wps * 128000000000 / 117964800
87  * wps * 78125 / 72
88  */
89 #define WCO_PULSE_SETS_TO_PPB(wps) (wps * 78125 / 72)
90 
91 struct ifx_cat1_rtc_data {
92 	struct k_spinlock lock;
93 };
94 
_ifx_cat1_rtc_get_state(void)95 static inline uint16_t _ifx_cat1_rtc_get_state(void)
96 {
97 	return _FLD2VAL(_IFX_CAT1_RTC_BREG_STATE, _IFX_CAT1_RTC_BREG);
98 }
99 
_ifx_cat1_rtc_set_state(uint16_t init)100 static inline void _ifx_cat1_rtc_set_state(uint16_t init)
101 {
102 	_IFX_CAT1_RTC_BREG &= _IFX_CAT1_RTC_BREG_CENTURY_Msk;
103 	_IFX_CAT1_RTC_BREG |= _VAL2FLD(_IFX_CAT1_RTC_BREG_STATE, init);
104 }
105 
_ifx_cat1_rtc_get_century(void)106 static inline uint16_t _ifx_cat1_rtc_get_century(void)
107 {
108 	return _FLD2VAL(_IFX_CAT1_RTC_BREG_CENTURY, _IFX_CAT1_RTC_BREG);
109 }
110 
_ifx_cat1_rtc_set_century(uint16_t century)111 static inline void _ifx_cat1_rtc_set_century(uint16_t century)
112 {
113 	_IFX_CAT1_RTC_BREG &= _IFX_CAT1_RTC_BREG_STATE_Msk;
114 	_IFX_CAT1_RTC_BREG |= _VAL2FLD(_IFX_CAT1_RTC_BREG_CENTURY, century);
115 }
116 
_ifx_cat1_rtc_from_pdl_time(cy_stc_rtc_config_t * pdlTime,const int year,struct rtc_time * z_time)117 static void _ifx_cat1_rtc_from_pdl_time(cy_stc_rtc_config_t *pdlTime, const int year,
118 					struct rtc_time *z_time)
119 {
120 	CY_ASSERT(pdlTime != NULL);
121 	CY_ASSERT(z_time != NULL);
122 
123 	z_time->tm_sec = (int)pdlTime->sec;
124 	z_time->tm_min = (int)pdlTime->min;
125 	z_time->tm_hour = (int)pdlTime->hour;
126 	z_time->tm_mday = (int)pdlTime->date;
127 	z_time->tm_year = (int)(year - _IFX_CAT1_RTC_TM_YEAR_BASE);
128 
129 	/* The subtraction of 1 here is to translate between internal ifx_cat1 code and the Zephyr
130 	 * driver.
131 	 */
132 	z_time->tm_mon = (int)(pdlTime->month - 1u);
133 	z_time->tm_wday = (int)(pdlTime->dayOfWeek - 1u);
134 
135 	/* year day not known in pdl RTC structure without conversion */
136 	z_time->tm_yday = -1;
137 
138 	/* daylight savings currently marked as unknown */
139 	z_time->tm_isdst = -1;
140 
141 	/* nanoseconds not tracked by ifx code. Set to value indicating unknown */
142 	z_time->tm_nsec = 0;
143 }
144 
_ifx_cat1_rtc_isr_handler(void)145 static void _ifx_cat1_rtc_isr_handler(void)
146 {
147 	Cy_RTC_Interrupt(_ifx_cat1_rtc_dst, NULL != _ifx_cat1_rtc_dst);
148 }
149 
_ifx_cat1_rtc_century_interrupt(void)150 void _ifx_cat1_rtc_century_interrupt(void)
151 {
152 	/* The century is stored in its own register so when a "century interrupt"
153 	 * occurs at a rollover. The current century is retrieved and 100 is added
154 	 * to it and the register is reset to reflect the new century.
155 	 * i.e. 1999->2000
156 	 */
157 	_ifx_cat1_rtc_set_century(_ifx_cat1_rtc_get_century() + 100);
158 }
159 
ifx_cat1_rtc_init(const struct device * dev)160 static int ifx_cat1_rtc_init(const struct device *dev)
161 {
162 	cy_rslt_t rslt = CY_RSLT_SUCCESS;
163 
164 	Cy_SysClk_ClkBakSetSource(CY_SYSCLK_BAK_IN_CLKLF);
165 
166 	if (_ifx_cat1_rtc_get_state() == _IFX_CAT1_RTC_STATE_UNINITIALIZED) {
167 		if (Cy_RTC_IsExternalResetOccurred()) {
168 			_ifx_cat1_rtc_set_century(_IFX_CAT1_RTC_INIT_CENTURY);
169 		}
170 
171 #ifdef CONFIG_PM
172 		rslt = Cy_SysPm_RegisterCallback(&_ifx_cat1_rtc_pm_cb)
173 #endif /* CONFIG_PM */
174 
175 		if (rslt == CY_RSLT_SUCCESS) {
176 			_ifx_cat1_rtc_set_state(_IFX_CAT1_RTC_STATE_ENABLED);
177 		} else {
178 			rslt = -EINVAL;
179 		}
180 
181 	} else if (_ifx_cat1_rtc_get_state() == _IFX_CAT1_RTC_STATE_ENABLED ||
182 		   _ifx_cat1_rtc_get_state() == _IFX_CAT1_RTC_STATE_TIME_SET) {
183 
184 		if (Cy_RTC_GetInterruptStatus() & CY_RTC_INTR_CENTURY) {
185 			_ifx_cat1_rtc_century_interrupt();
186 		}
187 	}
188 
189 	Cy_RTC_ClearInterrupt(CY_RTC_INTR_CENTURY);
190 	Cy_RTC_SetInterruptMask(CY_RTC_INTR_CENTURY);
191 
192 	_ifx_cat1_rtc_dst = NULL;
193 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), _ifx_cat1_rtc_isr_handler,
194 		    DEVICE_DT_INST_GET(0), 0);
195 	irq_enable(DT_INST_IRQN(0));
196 
197 	return rslt;
198 }
199 
ifx_cat1_rtc_set_time(const struct device * dev,const struct rtc_time * timeptr)200 static int ifx_cat1_rtc_set_time(const struct device *dev, const struct rtc_time *timeptr)
201 {
202 	struct ifx_cat1_rtc_data *data = dev->data;
203 
204 	uint32_t sec = timeptr->tm_sec;
205 	uint32_t min = timeptr->tm_min;
206 	uint32_t hour = timeptr->tm_hour;
207 	uint32_t day = timeptr->tm_mday;
208 	/* The addition of 1 here is to translate between internal ifx_cat1 code and the Zephyr
209 	 * driver.
210 	 */
211 	uint32_t mon = timeptr->tm_mon + 1;
212 	uint32_t year = timeptr->tm_year + _IFX_CAT1_RTC_TM_YEAR_BASE;
213 	uint32_t year2digit = year % 100;
214 
215 	cy_rslt_t rslt;
216 	uint32_t retry = 0;
217 
218 	if (!CY_RTC_IS_SEC_VALID(sec) || !CY_RTC_IS_MIN_VALID(min) || !CY_RTC_IS_HOUR_VALID(hour) ||
219 	    !CY_RTC_IS_MONTH_VALID(mon) || !CY_RTC_IS_YEAR_SHORT_VALID(year2digit) ||
220 	    !IFX_CAT1_RTC_VALID_CENTURY(year)) {
221 
222 		return -EINVAL;
223 	}
224 	do {
225 		if (retry != 0) {
226 			_IFX_CAT1_RTC_WAIT_ONE_MS();
227 		}
228 
229 		k_spinlock_key_t key = k_spin_lock(&data->lock);
230 
231 		rslt = Cy_RTC_SetDateAndTimeDirect(sec, min, hour, day, mon, year2digit);
232 		if (rslt == CY_RSLT_SUCCESS) {
233 			_ifx_cat1_rtc_set_century((uint16_t)(year) - (uint16_t)(year2digit));
234 		}
235 
236 		k_spin_unlock(&data->lock, key);
237 		++retry;
238 	} while (rslt == CY_RTC_INVALID_STATE && retry < _IFX_CAT1_RTC_MAX_RETRY);
239 
240 	retry = 0;
241 	while (CY_RTC_BUSY == Cy_RTC_GetSyncStatus() && retry < _IFX_CAT1_RTC_MAX_RETRY) {
242 		_IFX_CAT1_RTC_WAIT_ONE_MS();
243 		++retry;
244 	}
245 
246 	if (rslt == CY_RSLT_SUCCESS) {
247 		_ifx_cat1_rtc_set_state(_IFX_CAT1_RTC_STATE_TIME_SET);
248 		return 0;
249 	} else {
250 		return -EINVAL;
251 	}
252 }
253 
ifx_cat1_rtc_get_time(const struct device * dev,struct rtc_time * timeptr)254 static int ifx_cat1_rtc_get_time(const struct device *dev, struct rtc_time *timeptr)
255 {
256 	struct ifx_cat1_rtc_data *data = dev->data;
257 
258 	cy_stc_rtc_config_t dateTime = {.hrFormat = CY_RTC_24_HOURS};
259 
260 	if (_ifx_cat1_rtc_get_state() != _IFX_CAT1_RTC_STATE_TIME_SET) {
261 		LOG_ERR("Valid time has not been set with rtc_set_time yet");
262 		return -ENODATA;
263 	}
264 
265 	k_spinlock_key_t key = k_spin_lock(&data->lock);
266 
267 	Cy_RTC_GetDateAndTime(&dateTime);
268 	const int year = (int)(dateTime.year + _ifx_cat1_rtc_get_century());
269 
270 	k_spin_unlock(&data->lock, key);
271 
272 	_ifx_cat1_rtc_from_pdl_time(&dateTime, year, timeptr);
273 
274 	return CY_RSLT_SUCCESS;
275 }
276 
277 #ifdef CONFIG_RTC_CALIBRATION
ifx_cat1_set_calibration(const struct device * dev,int32_t calibration)278 static int ifx_cat1_set_calibration(const struct device *dev, int32_t calibration)
279 {
280 	cy_rslt_t rslt;
281 
282 	uint8_t uint_calibration;
283 	cy_en_rtc_calib_sign_t calibration_sign;
284 
285 	if (calibration >= 0) {
286 		calibration_sign = CY_RTC_CALIB_SIGN_POSITIVE;
287 	} else {
288 		calibration = abs(calibration);
289 		calibration_sign = CY_RTC_CALIB_SIGN_NEGATIVE;
290 	}
291 
292 	uint_calibration = PPB_TO_WCO_PULSE_SETS(calibration);
293 
294 	/* Maximum calibration value on cat1b of 60 128 tick groupings */
295 	if (MAX_IFX_CAT1_CAL < uint_calibration) {
296 		/* out of supported range */
297 		return -EINVAL;
298 	}
299 
300 	rslt = Cy_RTC_CalibrationControlEnable(uint_calibration, calibration_sign,
301 					       CY_RTC_CAL_SEL_CAL1);
302 	if (rslt != CY_RSLT_SUCCESS) {
303 		return -EINVAL;
304 	}
305 
306 	return 0;
307 }
308 
ifx_cat1_get_calibration(const struct device * dev,int32_t * calibration)309 static int ifx_cat1_get_calibration(const struct device *dev, int32_t *calibration)
310 {
311 	ARG_UNUSED(dev);
312 
313 	uint32_t hw_calibration = _FLD2VAL(BACKUP_CAL_CTL_CALIB_VAL, BACKUP_CAL_CTL);
314 	cy_en_rtc_calib_sign_t hw_sign =
315 		(cy_en_rtc_calib_sign_t)(_FLD2VAL(BACKUP_CAL_CTL_CALIB_SIGN, BACKUP_CAL_CTL));
316 
317 	if (CY_RTC_CALIB_SIGN_POSITIVE == hw_sign) {
318 		*calibration = WCO_PULSE_SETS_TO_PPB(hw_calibration);
319 	} else {
320 		*calibration = WCO_PULSE_SETS_TO_PPB(hw_calibration) * -1;
321 	}
322 
323 	return 0;
324 }
325 #endif /* CONFIG_RTC_CALIBRATION */
326 
327 static DEVICE_API(rtc, ifx_cat1_rtc_driver_api) = {
328 	.set_time = ifx_cat1_rtc_set_time,
329 	.get_time = ifx_cat1_rtc_get_time,
330 #ifdef CONFIG_RTC_CALIBRATION
331 	.set_calibration = ifx_cat1_set_calibration,
332 	.get_calibration = ifx_cat1_get_calibration,
333 #endif
334 };
335 
336 #define INFINEON_CAT1_RTC_INIT(n)                                                                  \
337 	static struct ifx_cat1_rtc_data ifx_cat1_rtc_data##n;                                      \
338                                                                                                    \
339 	DEVICE_DT_INST_DEFINE(n, ifx_cat1_rtc_init, NULL, &ifx_cat1_rtc_data##n,                   \
340 			      NULL, PRE_KERNEL_1, CONFIG_RTC_INIT_PRIORITY,        \
341 			      &ifx_cat1_rtc_driver_api);
342 
343 DT_INST_FOREACH_STATUS_OKAY(INFINEON_CAT1_RTC_INIT)
344