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