mirror of https://github.com/torvalds/linux.git
rtc: rzn1: support input frequencies other than 32768Hz
When using the SCMP mode instead of SUBU, this RTC can also support other input frequencies than 32768Hz. Also, upcoming SoCs will only support SCMP. Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/r/20250526095801.35781-8-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
parent
a50f00cb87
commit
f096bdbf08
|
|
@ -12,6 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/bcd.h>
|
#include <linux/bcd.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
@ -22,7 +23,6 @@
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
#define RZN1_RTC_CTL0 0x00
|
#define RZN1_RTC_CTL0 0x00
|
||||||
#define RZN1_RTC_CTL0_SLSB_SUBU 0
|
|
||||||
#define RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
|
#define RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
|
||||||
#define RZN1_RTC_CTL0_AMPM BIT(5)
|
#define RZN1_RTC_CTL0_AMPM BIT(5)
|
||||||
#define RZN1_RTC_CTL0_CEST BIT(6)
|
#define RZN1_RTC_CTL0_CEST BIT(6)
|
||||||
|
|
@ -50,6 +50,8 @@
|
||||||
#define RZN1_RTC_SUBU_DEV BIT(7)
|
#define RZN1_RTC_SUBU_DEV BIT(7)
|
||||||
#define RZN1_RTC_SUBU_DECR BIT(6)
|
#define RZN1_RTC_SUBU_DECR BIT(6)
|
||||||
|
|
||||||
|
#define RZN1_RTC_SCMP 0x3c
|
||||||
|
|
||||||
#define RZN1_RTC_ALM 0x40
|
#define RZN1_RTC_ALM 0x40
|
||||||
#define RZN1_RTC_ALH 0x44
|
#define RZN1_RTC_ALH 0x44
|
||||||
#define RZN1_RTC_ALW 0x48
|
#define RZN1_RTC_ALW 0x48
|
||||||
|
|
@ -357,7 +359,7 @@ static int rzn1_rtc_set_offset(struct device *dev, long offset)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rtc_class_ops rzn1_rtc_ops = {
|
static const struct rtc_class_ops rzn1_rtc_ops_subu = {
|
||||||
.read_time = rzn1_rtc_read_time,
|
.read_time = rzn1_rtc_read_time,
|
||||||
.set_time = rzn1_rtc_set_time,
|
.set_time = rzn1_rtc_set_time,
|
||||||
.read_alarm = rzn1_rtc_read_alarm,
|
.read_alarm = rzn1_rtc_read_alarm,
|
||||||
|
|
@ -367,12 +369,21 @@ static const struct rtc_class_ops rzn1_rtc_ops = {
|
||||||
.set_offset = rzn1_rtc_set_offset,
|
.set_offset = rzn1_rtc_set_offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct rtc_class_ops rzn1_rtc_ops_scmp = {
|
||||||
|
.read_time = rzn1_rtc_read_time,
|
||||||
|
.set_time = rzn1_rtc_set_time,
|
||||||
|
.read_alarm = rzn1_rtc_read_alarm,
|
||||||
|
.set_alarm = rzn1_rtc_set_alarm,
|
||||||
|
.alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
|
||||||
|
};
|
||||||
|
|
||||||
static int rzn1_rtc_probe(struct platform_device *pdev)
|
static int rzn1_rtc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct rzn1_rtc *rtc;
|
struct rzn1_rtc *rtc;
|
||||||
u32 val;
|
u32 val, scmp_val = 0;
|
||||||
int irq;
|
struct clk *xtal;
|
||||||
int ret;
|
unsigned long rate;
|
||||||
|
int irq, ret;
|
||||||
|
|
||||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||||
if (!rtc)
|
if (!rtc)
|
||||||
|
|
@ -395,7 +406,6 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
|
||||||
rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||||
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
|
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
|
||||||
rtc->rtcdev->alarm_offset_max = 7 * 86400;
|
rtc->rtcdev->alarm_offset_max = 7 * 86400;
|
||||||
rtc->rtcdev->ops = &rzn1_rtc_ops;
|
|
||||||
|
|
||||||
ret = devm_pm_runtime_enable(&pdev->dev);
|
ret = devm_pm_runtime_enable(&pdev->dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
@ -404,10 +414,24 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/*
|
/* Only switch to scmp if we have an xtal clock with a valid rate and != 32768 */
|
||||||
* Ensure the clock counter is enabled.
|
xtal = devm_clk_get_optional(&pdev->dev, "xtal");
|
||||||
* Set 24-hour mode and possible oscillator offset compensation in SUBU mode.
|
if (IS_ERR(xtal)) {
|
||||||
*/
|
ret = PTR_ERR(xtal);
|
||||||
|
goto dis_runtime_pm;
|
||||||
|
} else if (xtal) {
|
||||||
|
rate = clk_get_rate(xtal);
|
||||||
|
|
||||||
|
if (rate < 32000 || rate > BIT(22)) {
|
||||||
|
ret = -EOPNOTSUPP;
|
||||||
|
goto dis_runtime_pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rate != 32768)
|
||||||
|
scmp_val = RZN1_RTC_CTL0_SLSB_SCMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable controller during SUBU/SCMP setup */
|
||||||
val = readl(rtc->base + RZN1_RTC_CTL0) & ~RZN1_RTC_CTL0_CE;
|
val = readl(rtc->base + RZN1_RTC_CTL0) & ~RZN1_RTC_CTL0_CE;
|
||||||
writel(val, rtc->base + RZN1_RTC_CTL0);
|
writel(val, rtc->base + RZN1_RTC_CTL0);
|
||||||
/* Wait 2-4 32k clock cycles for the disabled controller */
|
/* Wait 2-4 32k clock cycles for the disabled controller */
|
||||||
|
|
@ -416,8 +440,18 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto dis_runtime_pm;
|
goto dis_runtime_pm;
|
||||||
|
|
||||||
writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU,
|
/* Set desired modes leaving the controller disabled */
|
||||||
rtc->base + RZN1_RTC_CTL0);
|
writel(RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
|
||||||
|
|
||||||
|
if (scmp_val) {
|
||||||
|
writel(rate - 1, rtc->base + RZN1_RTC_SCMP);
|
||||||
|
rtc->rtcdev->ops = &rzn1_rtc_ops_scmp;
|
||||||
|
} else {
|
||||||
|
rtc->rtcdev->ops = &rzn1_rtc_ops_subu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable controller finally */
|
||||||
|
writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
|
||||||
|
|
||||||
/* Disable all interrupts */
|
/* Disable all interrupts */
|
||||||
writel(0, rtc->base + RZN1_RTC_CTL1);
|
writel(0, rtc->base + RZN1_RTC_CTL1);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue