-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Drivers: RTC: Initial implementation of RTC for IFX cyw920829m2evk_02 platform #79343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
aescolar
merged 2 commits into
zephyrproject-rtos:main
from
mcatee-infineon:ifx-cat1-rtc-driver
Oct 9, 2024
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,5 +20,6 @@ supported: | |
| - watchdog | ||
| - spi | ||
| - i2c | ||
| - rtc | ||
|
|
||
| vendor: infineon | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| # Infineon CAT1 RTC configuration options | ||
|
|
||
| # Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company) or | ||
| # an affiliate of Cypress Semiconductor Corporation | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| config RTC_INFINEON_CAT1 | ||
| bool "Infineon CAT1 RTC driver" | ||
| default y | ||
| depends on DT_HAS_INFINEON_CAT1_RTC_ENABLED | ||
| select USE_INFINEON_RTC | ||
| help | ||
| This option enables the RTC driver for Infineon CAT1 family. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,343 @@ | ||
| /* | ||
| * Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company) or | ||
| * an affiliate of Cypress Semiconductor Corporation | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| /** | ||
| * @brief RTC driver for Infineon CAT1 MCU family. | ||
| */ | ||
|
|
||
| #include <zephyr/drivers/rtc.h> | ||
| #include <zephyr/sys/util.h> | ||
| #include <zephyr/device.h> | ||
| #include <zephyr/logging/log.h> | ||
| #include <cy_pdl.h> | ||
|
|
||
| LOG_MODULE_REGISTER(ifx_cat1_rtc, CONFIG_RTC_LOG_LEVEL); | ||
|
|
||
| #define DT_DRV_COMPAT infineon_cat1_rtc | ||
|
|
||
| #define _IFX_CAT1_RTC_STATE_UNINITIALIZED 0 | ||
| #define _IFX_CAT1_RTC_STATE_ENABLED 1 | ||
| #define _IFX_CAT1_RTC_STATE_TIME_SET 2 | ||
|
|
||
| #define _IFX_CAT1_RTC_INIT_CENTURY 2000 | ||
| #define _IFX_CAT1_RTC_TM_YEAR_BASE 1900 | ||
|
|
||
| #if defined(CONFIG_SOC_FAMILY_INFINEON_CAT1B) | ||
| #if defined(SRSS_BACKUP_NUM_BREG3) && (SRSS_BACKUP_NUM_BREG3 > 0) | ||
| #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET3[SRSS_BACKUP_NUM_BREG3 - 1]) | ||
| #elif defined(SRSS_BACKUP_NUM_BREG2) && (SRSS_BACKUP_NUM_BREG2 > 0) | ||
| #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET2[SRSS_BACKUP_NUM_BREG2 - 1]) | ||
| #elif defined(SRSS_BACKUP_NUM_BREG1) && (SRSS_BACKUP_NUM_BREG1 > 0) | ||
| #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET1[SRSS_BACKUP_NUM_BREG1 - 1]) | ||
| #elif defined(SRSS_BACKUP_NUM_BREG0) && (SRSS_BACKUP_NUM_BREG0 > 0) | ||
| #define _IFX_CAT1_RTC_BREG (BACKUP->BREG_SET0[SRSS_BACKUP_NUM_BREG0 - 1]) | ||
| #endif | ||
| #endif | ||
|
|
||
| #define _IFX_CAT1_RTC_BREG_CENTURY_Pos 0UL | ||
| #define _IFX_CAT1_RTC_BREG_CENTURY_Msk 0x0000FFFFUL | ||
| #define _IFX_CAT1_RTC_BREG_STATE_Pos 16UL | ||
| #define _IFX_CAT1_RTC_BREG_STATE_Msk 0xFFFF0000UL | ||
|
|
||
| static const uint32_t _IFX_CAT1_RTC_MAX_RETRY = 10; | ||
| static const uint32_t _IFX_CAT1_RTC_RETRY_DELAY_MS = 1; | ||
|
|
||
| static cy_stc_rtc_dst_t *_ifx_cat1_rtc_dst; | ||
|
|
||
| #ifdef CONFIG_PM | ||
| static cy_en_syspm_status_t _ifx_cat1_rtc_syspm_callback(cy_stc_syspm_callback_params_t *params, | ||
npal-cy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| cy_en_syspm_callback_mode_t mode) | ||
| { | ||
| return Cy_RTC_DeepSleepCallback(params, mode); | ||
| } | ||
|
|
||
| static cy_stc_syspm_callback_params_t _ifx_cat1_rtc_pm_cb_params = {NULL, NULL}; | ||
| static cy_stc_syspm_callback_t _ifx_cat1_rtc_pm_cb = { | ||
| .callback = &_ifx_cat1_rtc_syspm_callback, | ||
| .type = CY_SYSPM_DEEPSLEEP, | ||
| .callbackParams = &_ifx_cat1_rtc_pm_cb_params, | ||
| }; | ||
| #endif /* CONFIG_PM */ | ||
|
|
||
| #define _IFX_CAT1_RTC_WAIT_ONE_MS() Cy_SysLib_Delay(_IFX_CAT1_RTC_RETRY_DELAY_MS); | ||
|
|
||
| /* Internal macro to validate RTC year parameter falls within 21st century */ | ||
| #define IFX_CAT1_RTC_VALID_CENTURY(year) ((year) >= _IFX_CAT1_RTC_INIT_CENTURY) | ||
|
|
||
| #define MAX_IFX_CAT1_CAL (60) | ||
|
|
||
| /* Convert parts per billion to groupings of 128 ticks added or removed from one hour of clock | ||
| * cycles at 32768 Hz. | ||
| * | ||
| * ROUND_DOWN(ppb * 32768Hz * 60min * 60sec / 1000000000, 128) / 128 | ||
| * ROUND_DOWN(ppb * 117964800 / 1000000000, 128) / 128 | ||
| * ROUND_DOWN(ppb * 9216 / 78125, 128) / 128 | ||
| */ | ||
| #define PPB_TO_WCO_PULSE_SETS(ppb) ((ROUND_DOWN((ppb * 9216 / 78125), 128)) / 128) | ||
|
|
||
| /* Convert groupings of 128 ticks added or removed from one hour of clock cycles at | ||
| * 32768 Hz to parts per billion | ||
| * | ||
| * wps * 128 * 1000000000 / 32768Hz * 60min * 60sec | ||
| * wps * 128000000000 / 117964800 | ||
| * wps * 78125 / 72 | ||
| */ | ||
| #define WCO_PULSE_SETS_TO_PPB(wps) (wps * 78125 / 72) | ||
|
|
||
| struct ifx_cat1_rtc_data { | ||
| struct k_spinlock lock; | ||
| }; | ||
|
|
||
| static inline uint16_t _ifx_cat1_rtc_get_state(void) | ||
| { | ||
| return _FLD2VAL(_IFX_CAT1_RTC_BREG_STATE, _IFX_CAT1_RTC_BREG); | ||
| } | ||
|
|
||
| static inline void _ifx_cat1_rtc_set_state(uint16_t init) | ||
| { | ||
| _IFX_CAT1_RTC_BREG &= _IFX_CAT1_RTC_BREG_CENTURY_Msk; | ||
| _IFX_CAT1_RTC_BREG |= _VAL2FLD(_IFX_CAT1_RTC_BREG_STATE, init); | ||
| } | ||
|
|
||
| static inline uint16_t _ifx_cat1_rtc_get_century(void) | ||
| { | ||
| return _FLD2VAL(_IFX_CAT1_RTC_BREG_CENTURY, _IFX_CAT1_RTC_BREG); | ||
| } | ||
|
|
||
| static inline void _ifx_cat1_rtc_set_century(uint16_t century) | ||
| { | ||
| _IFX_CAT1_RTC_BREG &= _IFX_CAT1_RTC_BREG_STATE_Msk; | ||
| _IFX_CAT1_RTC_BREG |= _VAL2FLD(_IFX_CAT1_RTC_BREG_CENTURY, century); | ||
| } | ||
|
|
||
| static void _ifx_cat1_rtc_from_pdl_time(cy_stc_rtc_config_t *pdlTime, const int year, | ||
| struct rtc_time *z_time) | ||
| { | ||
| CY_ASSERT(pdlTime != NULL); | ||
| CY_ASSERT(z_time != NULL); | ||
|
|
||
| z_time->tm_sec = (int)pdlTime->sec; | ||
| z_time->tm_min = (int)pdlTime->min; | ||
| z_time->tm_hour = (int)pdlTime->hour; | ||
| z_time->tm_mday = (int)pdlTime->date; | ||
| z_time->tm_year = (int)(year - _IFX_CAT1_RTC_TM_YEAR_BASE); | ||
|
|
||
| /* The subtraction of 1 here is to translate between internal ifx_cat1 code and the Zephyr | ||
| * driver. | ||
| */ | ||
| z_time->tm_mon = (int)(pdlTime->month - 1u); | ||
| z_time->tm_wday = (int)(pdlTime->dayOfWeek - 1u); | ||
|
|
||
| /* year day not known in pdl RTC structure without conversion */ | ||
| z_time->tm_yday = -1; | ||
|
|
||
| /* daylight savings currently marked as unknown */ | ||
| z_time->tm_isdst = -1; | ||
|
|
||
| /* nanoseconds not tracked by ifx code. Set to value indicating unknown */ | ||
| z_time->tm_nsec = 0; | ||
| } | ||
|
|
||
| static void _ifx_cat1_rtc_isr_handler(void) | ||
| { | ||
| Cy_RTC_Interrupt(_ifx_cat1_rtc_dst, NULL != _ifx_cat1_rtc_dst); | ||
| } | ||
|
|
||
| void _ifx_cat1_rtc_century_interrupt(void) | ||
| { | ||
| /* The century is stored in its own register so when a "century interrupt" | ||
| * occurs at a rollover. The current century is retrieved and 100 is added | ||
| * to it and the register is reset to reflect the new century. | ||
| * i.e. 1999->2000 | ||
| */ | ||
| _ifx_cat1_rtc_set_century(_ifx_cat1_rtc_get_century() + 100); | ||
ifyall marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| static int ifx_cat1_rtc_init(const struct device *dev) | ||
| { | ||
| cy_rslt_t rslt = CY_RSLT_SUCCESS; | ||
|
|
||
| Cy_SysClk_ClkBakSetSource(CY_SYSCLK_BAK_IN_CLKLF); | ||
|
|
||
| if (_ifx_cat1_rtc_get_state() == _IFX_CAT1_RTC_STATE_UNINITIALIZED) { | ||
| if (Cy_RTC_IsExternalResetOccurred()) { | ||
| _ifx_cat1_rtc_set_century(_IFX_CAT1_RTC_INIT_CENTURY); | ||
| } | ||
|
|
||
| #ifdef CONFIG_PM | ||
| rslt = Cy_SysPm_RegisterCallback(&_ifx_cat1_rtc_pm_cb) | ||
| #endif /* CONFIG_PM */ | ||
|
|
||
| if (rslt == CY_RSLT_SUCCESS) { | ||
| _ifx_cat1_rtc_set_state(_IFX_CAT1_RTC_STATE_ENABLED); | ||
| } else { | ||
| rslt = -EINVAL; | ||
|
Check notice on line 178 in drivers/rtc/rtc_ifx_cat1.c
|
||
| } | ||
|
|
||
| } else if (_ifx_cat1_rtc_get_state() == _IFX_CAT1_RTC_STATE_ENABLED || | ||
| _ifx_cat1_rtc_get_state() == _IFX_CAT1_RTC_STATE_TIME_SET) { | ||
|
|
||
| if (Cy_RTC_GetInterruptStatus() & CY_RTC_INTR_CENTURY) { | ||
| _ifx_cat1_rtc_century_interrupt(); | ||
| } | ||
| } | ||
|
|
||
| Cy_RTC_ClearInterrupt(CY_RTC_INTR_CENTURY); | ||
| Cy_RTC_SetInterruptMask(CY_RTC_INTR_CENTURY); | ||
|
|
||
| _ifx_cat1_rtc_dst = NULL; | ||
| IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), _ifx_cat1_rtc_isr_handler, | ||
| DEVICE_DT_INST_GET(0), 0); | ||
| irq_enable(DT_INST_IRQN(0)); | ||
|
|
||
| return rslt; | ||
| } | ||
|
|
||
| static int ifx_cat1_rtc_set_time(const struct device *dev, const struct rtc_time *timeptr) | ||
| { | ||
| struct ifx_cat1_rtc_data *data = dev->data; | ||
|
|
||
| uint32_t sec = timeptr->tm_sec; | ||
| uint32_t min = timeptr->tm_min; | ||
| uint32_t hour = timeptr->tm_hour; | ||
| uint32_t day = timeptr->tm_mday; | ||
| /* The addition of 1 here is to translate between internal ifx_cat1 code and the Zephyr | ||
| * driver. | ||
| */ | ||
| uint32_t mon = timeptr->tm_mon + 1; | ||
ifyall marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| uint32_t year = timeptr->tm_year + _IFX_CAT1_RTC_TM_YEAR_BASE; | ||
| uint32_t year2digit = year % 100; | ||
|
|
||
| cy_rslt_t rslt; | ||
| uint32_t retry = 0; | ||
|
|
||
| if (!CY_RTC_IS_SEC_VALID(sec) || !CY_RTC_IS_MIN_VALID(min) || !CY_RTC_IS_HOUR_VALID(hour) || | ||
| !CY_RTC_IS_MONTH_VALID(mon) || !CY_RTC_IS_YEAR_SHORT_VALID(year2digit) || | ||
| !IFX_CAT1_RTC_VALID_CENTURY(year)) { | ||
|
|
||
| return -EINVAL; | ||
| } | ||
| do { | ||
| if (retry != 0) { | ||
| _IFX_CAT1_RTC_WAIT_ONE_MS(); | ||
| } | ||
|
|
||
| k_spinlock_key_t key = k_spin_lock(&data->lock); | ||
|
|
||
| rslt = Cy_RTC_SetDateAndTimeDirect(sec, min, hour, day, mon, year2digit); | ||
| if (rslt == CY_RSLT_SUCCESS) { | ||
| _ifx_cat1_rtc_set_century((uint16_t)(year) - (uint16_t)(year2digit)); | ||
| } | ||
|
|
||
| k_spin_unlock(&data->lock, key); | ||
| ++retry; | ||
| } while (rslt == CY_RTC_INVALID_STATE && retry < _IFX_CAT1_RTC_MAX_RETRY); | ||
|
|
||
| retry = 0; | ||
| while (CY_RTC_BUSY == Cy_RTC_GetSyncStatus() && retry < _IFX_CAT1_RTC_MAX_RETRY) { | ||
| _IFX_CAT1_RTC_WAIT_ONE_MS(); | ||
| ++retry; | ||
| } | ||
|
|
||
| if (rslt == CY_RSLT_SUCCESS) { | ||
| _ifx_cat1_rtc_set_state(_IFX_CAT1_RTC_STATE_TIME_SET); | ||
| return 0; | ||
| } else { | ||
| return -EINVAL; | ||
| } | ||
| } | ||
|
|
||
| static int ifx_cat1_rtc_get_time(const struct device *dev, struct rtc_time *timeptr) | ||
| { | ||
| struct ifx_cat1_rtc_data *data = dev->data; | ||
|
|
||
| cy_stc_rtc_config_t dateTime = {.hrFormat = CY_RTC_24_HOURS}; | ||
|
|
||
| if (_ifx_cat1_rtc_get_state() != _IFX_CAT1_RTC_STATE_TIME_SET) { | ||
| LOG_ERR("Valid time has not been set with rtc_set_time yet"); | ||
| return -ENODATA; | ||
| } | ||
|
|
||
| k_spinlock_key_t key = k_spin_lock(&data->lock); | ||
|
|
||
| Cy_RTC_GetDateAndTime(&dateTime); | ||
| const int year = (int)(dateTime.year + _ifx_cat1_rtc_get_century()); | ||
bjarki-andreasen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| k_spin_unlock(&data->lock, key); | ||
|
|
||
| _ifx_cat1_rtc_from_pdl_time(&dateTime, year, timeptr); | ||
|
|
||
| return CY_RSLT_SUCCESS; | ||
| } | ||
|
|
||
| #ifdef CONFIG_RTC_CALIBRATION | ||
| static int ifx_cat1_set_calibration(const struct device *dev, int32_t calibration) | ||
| { | ||
| cy_rslt_t rslt; | ||
|
|
||
| uint8_t uint_calibration; | ||
| cy_en_rtc_calib_sign_t calibration_sign; | ||
|
|
||
| if (calibration >= 0) { | ||
| calibration_sign = CY_RTC_CALIB_SIGN_POSITIVE; | ||
| } else { | ||
| calibration = abs(calibration); | ||
| calibration_sign = CY_RTC_CALIB_SIGN_NEGATIVE; | ||
| } | ||
|
|
||
| uint_calibration = PPB_TO_WCO_PULSE_SETS(calibration); | ||
|
|
||
| /* Maximum calibration value on cat1b of 60 128 tick groupings */ | ||
| if (MAX_IFX_CAT1_CAL < uint_calibration) { | ||
| /* out of supported range */ | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| rslt = Cy_RTC_CalibrationControlEnable(uint_calibration, calibration_sign, | ||
| CY_RTC_CAL_SEL_CAL1); | ||
| if (rslt != CY_RSLT_SUCCESS) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static int ifx_cat1_get_calibration(const struct device *dev, int32_t *calibration) | ||
| { | ||
| ARG_UNUSED(dev); | ||
|
|
||
| uint32_t hw_calibration = _FLD2VAL(BACKUP_CAL_CTL_CALIB_VAL, BACKUP_CAL_CTL); | ||
| cy_en_rtc_calib_sign_t hw_sign = | ||
| (cy_en_rtc_calib_sign_t)(_FLD2VAL(BACKUP_CAL_CTL_CALIB_SIGN, BACKUP_CAL_CTL)); | ||
|
|
||
| if (CY_RTC_CALIB_SIGN_POSITIVE == hw_sign) { | ||
| *calibration = WCO_PULSE_SETS_TO_PPB(hw_calibration); | ||
| } else { | ||
| *calibration = WCO_PULSE_SETS_TO_PPB(hw_calibration) * -1; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
| #endif /* CONFIG_RTC_CALIBRATION */ | ||
|
|
||
| static const struct rtc_driver_api ifx_cat1_rtc_driver_api = { | ||
| .set_time = ifx_cat1_rtc_set_time, | ||
| .get_time = ifx_cat1_rtc_get_time, | ||
| #ifdef CONFIG_RTC_CALIBRATION | ||
| .set_calibration = ifx_cat1_set_calibration, | ||
| .get_calibration = ifx_cat1_get_calibration, | ||
| #endif | ||
| }; | ||
|
|
||
| #define INFINEON_CAT1_RTC_INIT(n) \ | ||
| static struct ifx_cat1_rtc_data ifx_cat1_rtc_data##n; \ | ||
| \ | ||
| DEVICE_DT_INST_DEFINE(n, ifx_cat1_rtc_init, NULL, &ifx_cat1_rtc_data##n, \ | ||
| NULL, PRE_KERNEL_1, CONFIG_RTC_INIT_PRIORITY, \ | ||
| &ifx_cat1_rtc_driver_api); | ||
|
|
||
|
Check notice on line 342 in drivers/rtc/rtc_ifx_cat1.c
|
||
| DT_INST_FOREACH_STATUS_OKAY(INFINEON_CAT1_RTC_INIT) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.