Thread (13 messages) 13 messages, 3 authors, 2022-07-22
STALE1449d

[PATCH 4/6] rtc: stm32: add alarm A out feature

From: Valentin Caron <hidden>
Date: 2022-05-04 13:07:53
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).

This patch only adds the functionality for devices which are using
st,stm32mp1-rtc compatible.

Signed-off-by: Valentin Caron <redacted>
---
 drivers/rtc/rtc-stm32.c | 77 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index ace041eb44b8..f27927be20b2 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -5,6 +5,7 @@
  */
 
 #include <linux/bcd.h>
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/iopoll.h>
@@ -44,8 +45,10 @@
 #define STM32_RTC_CR_ALRAIE		BIT(12)
 #define STM32_RTC_CR_COSEL		BIT(19)
 #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 */
@@ -134,6 +137,7 @@ struct stm32_rtc_data {
 	bool need_dbp;
 	bool has_wakeirq;
 	bool has_lsco;
+	bool has_alarm_out;
 };
 
 struct stm32_rtc {
@@ -149,6 +153,7 @@ struct stm32_rtc {
 	int wakeirq_alarm;
 	int lsco;
 	struct clk *clk_lsco;
+	int out_alarm;
 };
 
 /*
@@ -253,6 +258,64 @@ static void stm32_rtc_clk_lsco_disable(struct platform_device *pdev)
 	writel_relaxed(cfgr &= ~STM32_RTC_CFGR_LSCOEN, rtc->base + regs.cfgr);
 }
 
+static int stm32_rtc_out_alarm_config(struct platform_device *pdev)
+{
+	struct stm32_rtc *rtc = platform_get_drvdata(pdev);
+	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);
+
+	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 (rtc->out_alarm) {
+	case RTC_OUT1:
+		cr &= ~STM32_RTC_CR_OUT2EN;
+		cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
+		break;
+	case RTC_OUT2:
+		cr |= STM32_RTC_CR_OUT2EN;
+		cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
+		break;
+	case RTC_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 void stm32_rtc_out_alarm_disable(struct platform_device *pdev)
+{
+	struct stm32_rtc *rtc = platform_get_drvdata(pdev);
+	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);
+
+	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;
+	cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
+
+	stm32_rtc_wpr_unlock(rtc);
+	writel_relaxed(cr, rtc->base + regs.cr);
+	writel_relaxed(cfgr, rtc->base + regs.cfgr);
+	stm32_rtc_wpr_lock(rtc);
+}
+
 static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
 {
 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
@@ -657,6 +720,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {
 	.need_dbp = true,
 	.has_wakeirq = false,
 	.has_lsco = false,
+	.has_alarm_out = false,
 	.regs = {
 		.tr = 0x00,
 		.dr = 0x04,
@@ -681,6 +745,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
 	.need_dbp = true,
 	.has_wakeirq = false,
 	.has_lsco = false,
+	.has_alarm_out = false,
 	.regs = {
 		.tr = 0x00,
 		.dr = 0x04,
@@ -714,6 +779,7 @@ static const struct stm32_rtc_data stm32mp1_data = {
 	.need_dbp = false,
 	.has_wakeirq = true,
 	.has_lsco = true,
+	.has_alarm_out = true,
 	.regs = {
 		.tr = 0x00,
 		.dr = 0x04,
@@ -928,6 +994,17 @@ static int stm32_rtc_probe(struct platform_device *pdev)
 		goto err;
 	}
 
+	if (rtc->data->has_alarm_out) {
+		ret = of_property_read_s32(pdev->dev.of_node, "st,alarm", &rtc->out_alarm);
+		if (!ret) {
+			ret = stm32_rtc_out_alarm_config(pdev);
+		} else {
+			stm32_rtc_out_alarm_disable(pdev);
+			rtc->out_alarm = ret;
+			dev_dbg(&pdev->dev, "No alarm out: %d\n", ret);
+		}
+	}
+
 	if (rtc->data->has_lsco) {
 		ret = of_property_read_s32(pdev->dev.of_node,
 					   "st,lsco", &rtc->lsco);
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help