]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
rtc: stm32: add alarm A out feature
authorValentin Caron <valentin.caron@foss.st.com>
Mon, 22 Jul 2024 16:00:22 +0000 (18:00 +0200)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Wed, 14 Aug 2024 09:37:07 +0000 (11:37 +0200)
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 <valentin.caron@foss.st.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20240722160022.454226-5-valentin.caron@foss.st.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/rtc/rtc-stm32.c

index 675860a130518c5fdbaf79f7e6ae69c4cd1a138b..3e4f2ee22b0bc81e24ba0029fafd8be5a0b2049b 100644 (file)
 #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);