mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 10:08:59 +00:00
851e7f77e4
New stm32 target introduces support for stm32mp1 based devices. For now it includes an initial support of the STM32MP135F-DK device. The specifications bellow only list supported features. Specifications -------------- SOC: STM32MP135FAF7 RAM: 512 MiB Storage: SD Card Ethernet: 2x 100 Mbps Wireless: 2.4GHz Cypress CYW43455 (802.11b/g/n) LEDs: Heartbeat (Blue) Buttons: 1x Reset, 1x User (USER2) USB: 4x 2.0 Type-A Signed-off-by: Thomas Richard <thomas.richard@bootlin.com> Link: https://github.com/openwrt/openwrt/pull/16716 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
254 lines
7.3 KiB
Diff
254 lines
7.3 KiB
Diff
From 229476a4de2e237ebadddca8a82d20afa9298f71 Mon Sep 17 00:00:00 2001
|
|
From: Valentin Caron <valentin.caron@foss.st.com>
|
|
Date: Mon, 22 Jul 2024 18:00:21 +0200
|
|
Subject: [PATCH] rtc: stm32: add Low Speed Clock Output (LSCO) support
|
|
|
|
RTC is able to output on a pin the "LSE" internal clock.
|
|
|
|
STM32 RTC is now registered as a clock provider.
|
|
It provides rtc_lsco clock, that means RTC_LSCO is output on either
|
|
RTC_OUT1 or RTC_OUT2_RMP, depending on pinmux DT property.
|
|
The clock is marked as CLK_IGNORE_UNUSED and CLK_IS_CRITICAL because
|
|
RTC_LSCO can be early required by devices needed it to init.
|
|
|
|
Add LSCO in pinmux functions.
|
|
|
|
Add "stm32_rtc_clean_outs" to disable LSCO. As RTC is part of "backup"
|
|
power domain, it is not reset during shutdown or reboot. So force LSCO
|
|
disable at probe.
|
|
|
|
Co-developed-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
|
|
Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
|
|
Signed-off-by: Valentin Caron <valentin.caron@foss.st.com>
|
|
Link: https://lore.kernel.org/r/20240722160022.454226-4-valentin.caron@foss.st.com
|
|
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
|
|
---
|
|
drivers/rtc/Kconfig | 1 +
|
|
drivers/rtc/rtc-stm32.c | 99 +++++++++++++++++++++++++++++++++++++++++
|
|
2 files changed, 100 insertions(+)
|
|
|
|
--- a/drivers/rtc/Kconfig
|
|
+++ b/drivers/rtc/Kconfig
|
|
@@ -1892,6 +1892,7 @@ config RTC_DRV_STM32
|
|
select PINMUX
|
|
select PINCONF
|
|
select GENERIC_PINCONF
|
|
+ depends on COMMON_CLK
|
|
help
|
|
If you say yes here you get support for the STM32 On-Chip
|
|
Real Time Clock.
|
|
--- a/drivers/rtc/rtc-stm32.c
|
|
+++ b/drivers/rtc/rtc-stm32.c
|
|
@@ -6,6 +6,7 @@
|
|
|
|
#include <linux/bcd.h>
|
|
#include <linux/clk.h>
|
|
+#include <linux/clk-provider.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/ioport.h>
|
|
@@ -44,6 +45,10 @@
|
|
#define STM32_RTC_CR_FMT BIT(6)
|
|
#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_COE BIT(23)
|
|
+#define STM32_RTC_CR_TAMPOE BIT(26)
|
|
+#define STM32_RTC_CR_OUT2EN BIT(31)
|
|
|
|
/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
|
|
#define STM32_RTC_ISR_ALRAWF BIT(0)
|
|
@@ -80,6 +85,12 @@
|
|
/* STM32_RTC_SR/_SCR bit fields */
|
|
#define STM32_RTC_SR_ALRA BIT(0)
|
|
|
|
+/* STM32_RTC_CFGR bit fields */
|
|
+#define STM32_RTC_CFGR_OUT2_RMP BIT(0)
|
|
+#define STM32_RTC_CFGR_LSCOEN GENMASK(2, 1)
|
|
+#define STM32_RTC_CFGR_LSCOEN_OUT1 1
|
|
+#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2
|
|
+
|
|
/* STM32_RTC_VERR bit fields */
|
|
#define STM32_RTC_VERR_MINREV_SHIFT 0
|
|
#define STM32_RTC_VERR_MINREV GENMASK(3, 0)
|
|
@@ -117,6 +128,7 @@ struct stm32_rtc_registers {
|
|
u16 wpr;
|
|
u16 sr;
|
|
u16 scr;
|
|
+ u16 cfgr;
|
|
u16 verr;
|
|
};
|
|
|
|
@@ -131,6 +143,7 @@ struct stm32_rtc_data {
|
|
bool has_pclk;
|
|
bool need_dbp;
|
|
bool need_accuracy;
|
|
+ bool has_lsco;
|
|
};
|
|
|
|
struct stm32_rtc {
|
|
@@ -143,6 +156,7 @@ struct stm32_rtc {
|
|
struct clk *rtc_ck;
|
|
const struct stm32_rtc_data *data;
|
|
int irq_alarm;
|
|
+ struct clk *clk_lsco;
|
|
};
|
|
|
|
static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
|
|
@@ -209,7 +223,68 @@ struct stm32_rtc_pinmux_func {
|
|
int (*action)(struct pinctrl_dev *pctl_dev, unsigned int pin);
|
|
};
|
|
|
|
+static int stm32_rtc_pinmux_lsco_available(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);
|
|
+ unsigned int calib = STM32_RTC_CR_COE;
|
|
+ unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL;
|
|
+
|
|
+ switch (pin) {
|
|
+ case OUT1:
|
|
+ if ((!(cr & STM32_RTC_CR_OUT2EN) &&
|
|
+ ((cr & calib) || cr & tampalrm)) ||
|
|
+ ((cr & calib) && (cr & tampalrm)))
|
|
+ return -EBUSY;
|
|
+ break;
|
|
+ case OUT2_RMP:
|
|
+ if ((cr & STM32_RTC_CR_OUT2EN) &&
|
|
+ (cfgr & STM32_RTC_CFGR_OUT2_RMP) &&
|
|
+ ((cr & calib) || (cr & tampalrm)))
|
|
+ return -EBUSY;
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (clk_get_rate(rtc->rtc_ck) != 32768)
|
|
+ return -ERANGE;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_rtc_pinmux_action_lsco(struct pinctrl_dev *pctldev, unsigned int pin)
|
|
+{
|
|
+ struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
|
+ struct stm32_rtc_registers regs = rtc->data->regs;
|
|
+ struct device *dev = rtc->rtc_dev->dev.parent;
|
|
+ u8 lscoen;
|
|
+ int ret;
|
|
+
|
|
+ if (!rtc->data->has_lsco)
|
|
+ return -EPERM;
|
|
+
|
|
+ ret = stm32_rtc_pinmux_lsco_available(pctldev, pin);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ lscoen = (pin == OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : STM32_RTC_CFGR_LSCOEN_OUT2_RMP;
|
|
+
|
|
+ rtc->clk_lsco = clk_register_gate(dev, "rtc_lsco", __clk_get_name(rtc->rtc_ck),
|
|
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
|
|
+ rtc->base + regs.cfgr, lscoen, 0, NULL);
|
|
+ if (IS_ERR(rtc->clk_lsco))
|
|
+ return PTR_ERR(rtc->clk_lsco);
|
|
+
|
|
+ of_clk_add_provider(dev->of_node, of_clk_src_simple_get, rtc->clk_lsco);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct stm32_rtc_pinmux_func stm32_rtc_pinmux_functions[] = {
|
|
+ STM32_RTC_PINMUX("lsco", &stm32_rtc_pinmux_action_lsco, "out1", "out2_rmp"),
|
|
};
|
|
|
|
static int stm32_rtc_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
|
|
@@ -664,6 +739,7 @@ static const struct stm32_rtc_data stm32
|
|
.has_pclk = false,
|
|
.need_dbp = true,
|
|
.need_accuracy = false,
|
|
+ .has_lsco = false,
|
|
.regs = {
|
|
.tr = 0x00,
|
|
.dr = 0x04,
|
|
@@ -674,6 +750,7 @@ static const struct stm32_rtc_data stm32
|
|
.wpr = 0x24,
|
|
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
|
.scr = UNDEF_REG,
|
|
+ .cfgr = UNDEF_REG,
|
|
.verr = UNDEF_REG,
|
|
},
|
|
.events = {
|
|
@@ -686,6 +763,7 @@ static const struct stm32_rtc_data stm32
|
|
.has_pclk = true,
|
|
.need_dbp = true,
|
|
.need_accuracy = false,
|
|
+ .has_lsco = false,
|
|
.regs = {
|
|
.tr = 0x00,
|
|
.dr = 0x04,
|
|
@@ -696,6 +774,7 @@ static const struct stm32_rtc_data stm32
|
|
.wpr = 0x24,
|
|
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
|
.scr = UNDEF_REG,
|
|
+ .cfgr = UNDEF_REG,
|
|
.verr = UNDEF_REG,
|
|
},
|
|
.events = {
|
|
@@ -717,6 +796,7 @@ static const struct stm32_rtc_data stm32
|
|
.has_pclk = true,
|
|
.need_dbp = false,
|
|
.need_accuracy = true,
|
|
+ .has_lsco = true,
|
|
.regs = {
|
|
.tr = 0x00,
|
|
.dr = 0x04,
|
|
@@ -727,6 +807,7 @@ static const struct stm32_rtc_data stm32
|
|
.wpr = 0x24,
|
|
.sr = 0x50,
|
|
.scr = 0x5C,
|
|
+ .cfgr = 0x60,
|
|
.verr = 0x3F4,
|
|
},
|
|
.events = {
|
|
@@ -743,6 +824,19 @@ static const struct of_device_id stm32_r
|
|
};
|
|
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;
|
|
+
|
|
+ if (regs.cfgr != UNDEF_REG) {
|
|
+ unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
|
|
+
|
|
+ cfgr &= ~STM32_RTC_CFGR_LSCOEN;
|
|
+ cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
|
|
+ writel_relaxed(cfgr, rtc->base + regs.cfgr);
|
|
+ }
|
|
+}
|
|
+
|
|
static int stm32_rtc_init(struct platform_device *pdev,
|
|
struct stm32_rtc *rtc)
|
|
{
|
|
@@ -946,6 +1040,8 @@ static int stm32_rtc_probe(struct platfo
|
|
goto err;
|
|
}
|
|
|
|
+ stm32_rtc_clean_outs(rtc);
|
|
+
|
|
ret = devm_pinctrl_register_and_init(&pdev->dev, &stm32_rtc_pdesc, rtc, &pctl);
|
|
if (ret)
|
|
return dev_err_probe(&pdev->dev, ret, "pinctrl register failed");
|
|
@@ -992,6 +1088,9 @@ static void stm32_rtc_remove(struct plat
|
|
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
|
unsigned int cr;
|
|
|
|
+ if (!IS_ERR_OR_NULL(rtc->clk_lsco))
|
|
+ clk_unregister_gate(rtc->clk_lsco);
|
|
+
|
|
/* Disable interrupts */
|
|
stm32_rtc_wpr_unlock(rtc);
|
|
cr = readl_relaxed(rtc->base + regs->cr);
|