[PATCH v2 4/4] rtc: stm32: add alarm A out feature
From: Valentin Caron <hidden>
Date: 2024-07-17 07:50:20
Also in:
linux-devicetree, linux-rtc, lkml
Subsystem:
real time clock (rtc) subsystem, the rest · Maintainers:
Alexandre Belloni, Linus Torvalds
STM32 RTC can pulse some SOC pins when an RTC alarm expires. This patch adds this functionality for alarm A. The pulse can out on three pins RTC_OUT1, RTC_OUT2, RTC_OUT2_RMP (PC13, PB2, PI8 on stm32mp15) (PC13, PB2, PI1 on stm32mp13) (PC13, PF4/PF6, PI8 on stm32mp25). This patch only adds the functionality for devices which are using st,stm32mp1-rtc and st,stm32mp25-rtc compatible. Add "alarm-a" in pinmux functions. Signed-off-by: Valentin Caron <redacted> --- drivers/rtc/rtc-stm32.c | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index 675860a13051..3e4f2ee22b0b 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c@@ -47,8 +47,10 @@ #define STM32_RTC_CR_ALRAE BIT(8) #define STM32_RTC_CR_ALRAIE BIT(12) #define STM32_RTC_CR_OSEL GENMASK(22, 21) +#define STM32_RTC_CR_OSEL_ALARM_A FIELD_PREP(STM32_RTC_CR_OSEL, 0x01) #define STM32_RTC_CR_COE BIT(23) #define STM32_RTC_CR_TAMPOE BIT(26) +#define STM32_RTC_CR_TAMPALRM_TYPE BIT(30) #define STM32_RTC_CR_OUT2EN BIT(31) /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
@@ -158,6 +160,7 @@ struct stm32_rtc_data { bool need_accuracy; bool rif_protected; bool has_lsco; + bool has_alarm_out; }; struct stm32_rtc {
@@ -245,6 +248,47 @@ struct stm32_rtc_pinmux_func { int (*action)(struct pinctrl_dev *pctl_dev, unsigned int pin); }; +static int stm32_rtc_pinmux_action_alarm(struct pinctrl_dev *pctldev, unsigned int pin) +{ + struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev); + struct stm32_rtc_registers regs = rtc->data->regs; + unsigned int cr = readl_relaxed(rtc->base + regs.cr); + unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr); + + if (!rtc->data->has_alarm_out) + return -EPERM; + + cr &= ~STM32_RTC_CR_OSEL; + cr |= STM32_RTC_CR_OSEL_ALARM_A; + cr &= ~STM32_RTC_CR_TAMPOE; + cr &= ~STM32_RTC_CR_COE; + cr &= ~STM32_RTC_CR_TAMPALRM_TYPE; + + switch (pin) { + case OUT1: + cr &= ~STM32_RTC_CR_OUT2EN; + cfgr &= ~STM32_RTC_CFGR_OUT2_RMP; + break; + case OUT2: + cr |= STM32_RTC_CR_OUT2EN; + cfgr &= ~STM32_RTC_CFGR_OUT2_RMP; + break; + case OUT2_RMP: + cr |= STM32_RTC_CR_OUT2EN; + cfgr |= STM32_RTC_CFGR_OUT2_RMP; + break; + default: + return -EINVAL; + } + + stm32_rtc_wpr_unlock(rtc); + writel_relaxed(cr, rtc->base + regs.cr); + writel_relaxed(cfgr, rtc->base + regs.cfgr); + stm32_rtc_wpr_lock(rtc); + + return 0; +} + static int stm32_rtc_pinmux_lsco_available(struct pinctrl_dev *pctldev, unsigned int pin) { struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
@@ -307,6 +351,7 @@ static int stm32_rtc_pinmux_action_lsco(struct pinctrl_dev *pctldev, unsigned in static const struct stm32_rtc_pinmux_func stm32_rtc_pinmux_functions[] = { STM32_RTC_PINMUX("lsco", &stm32_rtc_pinmux_action_lsco, "out1", "out2_rmp"), + STM32_RTC_PINMUX("alarm-a", &stm32_rtc_pinmux_action_alarm, "out1", "out2", "out2_rmp"), }; static int stm32_rtc_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
@@ -763,6 +808,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { .need_accuracy = false, .rif_protected = false, .has_lsco = false, + .has_alarm_out = false, .regs = { .tr = 0x00, .dr = 0x04,
@@ -788,6 +834,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { .need_accuracy = false, .rif_protected = false, .has_lsco = false, + .has_alarm_out = false, .regs = { .tr = 0x00, .dr = 0x04,
@@ -822,6 +869,7 @@ static const struct stm32_rtc_data stm32mp1_data = { .need_accuracy = true, .rif_protected = false, .has_lsco = true, + .has_alarm_out = true, .regs = { .tr = 0x00, .dr = 0x04,
@@ -847,6 +895,7 @@ static const struct stm32_rtc_data stm32mp25_data = { .need_accuracy = true, .rif_protected = true, .has_lsco = true, + .has_alarm_out = true, .regs = { .tr = 0x00, .dr = 0x04,
@@ -878,6 +927,17 @@ MODULE_DEVICE_TABLE(of, stm32_rtc_of_match); static void stm32_rtc_clean_outs(struct stm32_rtc *rtc) { struct stm32_rtc_registers regs = rtc->data->regs; + unsigned int cr = readl_relaxed(rtc->base + regs.cr); + + cr &= ~STM32_RTC_CR_OSEL; + cr &= ~STM32_RTC_CR_TAMPOE; + cr &= ~STM32_RTC_CR_COE; + cr &= ~STM32_RTC_CR_TAMPALRM_TYPE; + cr &= ~STM32_RTC_CR_OUT2EN; + + stm32_rtc_wpr_unlock(rtc); + writel_relaxed(cr, rtc->base + regs.cr); + stm32_rtc_wpr_lock(rtc); if (regs.cfgr != UNDEF_REG) { unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
--
2.25.1