lkml.org 
[lkml]   [2022]   [May]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 4/6] rtc: stm32: add alarm A out feature
Date
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 <valentin.caron@foss.st.com>
---
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
\
 
 \ /
  Last update: 2022-05-04 15:08    [W:0.189 / U:1.332 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site