drivers: rtc: stm32: ensure thread safe operations

This adds mutex a lock in rtc_stm32_set_time and rtc_stm32_get_time to
ensure consistent data reading. Also performs register reading in a single
operation in rtc_stm32_get_calibration for the same reason.

Signed-off-by: Johan Lafon <johan.lafon@syslinbit.com>
This commit is contained in:
Johan Lafon 2023-09-11 18:50:45 +02:00 committed by Fabio Baltieri
commit a8b7076099

View file

@ -67,7 +67,7 @@ struct rtc_stm32_config {
};
struct rtc_stm32_data {
/* Currently empty */
struct k_mutex lock;
};
static int rtc_stm32_enter_initialization_mode(void)
@ -129,6 +129,7 @@ static int rtc_stm32_init(const struct device *dev)
{
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
const struct rtc_stm32_config *cfg = dev->config;
struct rtc_stm32_data *data = dev->data;
int err = 0;
@ -143,6 +144,8 @@ static int rtc_stm32_init(const struct device *dev)
return -EIO;
}
k_mutex_init(&data->lock);
/* Enable Backup access */
z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY);
#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP)
@ -181,6 +184,8 @@ static const struct rtc_stm32_config rtc_config = {
static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *timeptr)
{
struct rtc_stm32_data *data = dev->data;
uint32_t real_year = timeptr->tm_year + TM_YEAR_REF;
int err = 0;
@ -195,11 +200,17 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t
return -EINVAL;
}
err = k_mutex_lock(&data->lock, K_NO_WAIT);
if (err) {
return err;
}
LOG_INF("Setting clock");
LL_RTC_DisableWriteProtection(RTC);
err = rtc_stm32_enter_initialization_mode();
if (err) {
k_mutex_unlock(&data->lock);
return err;
}
@ -224,15 +235,24 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t
LL_RTC_EnableWriteProtection(RTC);
k_mutex_unlock(&data->lock);
return err;
}
static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr)
{
const struct rtc_stm32_config *cfg = dev->config;
struct rtc_stm32_data *data = dev->data;
uint32_t rtc_date, rtc_time, rtc_subsecond;
int err = k_mutex_lock(&data->lock, K_NO_WAIT);
if (err) {
return err;
}
do {
/* read date, time and subseconds and relaunch if a day increment occurred
* while doing so as it will result in an erroneous result otherwise
@ -247,6 +267,8 @@ static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr
} while (rtc_time != LL_RTC_TIME_Get(RTC));
} while (rtc_date != LL_RTC_DATE_Get(RTC));
k_mutex_unlock(&data->lock);
timeptr->tm_year = TM_TO_RTC_OFFSET + __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_YEAR(rtc_date));
/* tm_mon allowed values are 0-11 */
timeptr->tm_mon = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MONTH(rtc_date)) - 1;
@ -323,8 +345,10 @@ static int rtc_stm32_get_calibration(const struct device *dev, int32_t *calibrat
{
ARG_UNUSED(dev);
uint32_t calp_enabled = LL_RTC_CAL_IsPulseInserted(RTC);
uint32_t calm = LL_RTC_CAL_GetMinus(RTC);
uint32_t calr = sys_read32(&RTC->CALR);
bool calp_enabled = READ_BIT(calr, RTC_CALR_CALP);
uint32_t calm = READ_BIT(calr, RTC_CALR_CALM);
int32_t nb_pulses = -((int32_t) calm);