Skip to content

Commit f096bdb

Browse files
Wolfram Sangalexandrebelloni
authored andcommitted
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 <[email protected]> Reviewed-by: Geert Uytterhoeven <[email protected]> Reviewed-by: Miquel Raynal <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent a50f00c commit f096bdb

File tree

1 file changed

+46
-12
lines changed

1 file changed

+46
-12
lines changed

drivers/rtc/rtc-rzn1.c

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313

1414
#include <linux/bcd.h>
15+
#include <linux/clk.h>
1516
#include <linux/init.h>
1617
#include <linux/iopoll.h>
1718
#include <linux/module.h>
@@ -22,7 +23,6 @@
2223
#include <linux/spinlock.h>
2324

2425
#define RZN1_RTC_CTL0 0x00
25-
#define RZN1_RTC_CTL0_SLSB_SUBU 0
2626
#define RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
2727
#define RZN1_RTC_CTL0_AMPM BIT(5)
2828
#define RZN1_RTC_CTL0_CEST BIT(6)
@@ -50,6 +50,8 @@
5050
#define RZN1_RTC_SUBU_DEV BIT(7)
5151
#define RZN1_RTC_SUBU_DECR BIT(6)
5252

53+
#define RZN1_RTC_SCMP 0x3c
54+
5355
#define RZN1_RTC_ALM 0x40
5456
#define RZN1_RTC_ALH 0x44
5557
#define RZN1_RTC_ALW 0x48
@@ -357,7 +359,7 @@ static int rzn1_rtc_set_offset(struct device *dev, long offset)
357359
return 0;
358360
}
359361

360-
static const struct rtc_class_ops rzn1_rtc_ops = {
362+
static const struct rtc_class_ops rzn1_rtc_ops_subu = {
361363
.read_time = rzn1_rtc_read_time,
362364
.set_time = rzn1_rtc_set_time,
363365
.read_alarm = rzn1_rtc_read_alarm,
@@ -367,12 +369,21 @@ static const struct rtc_class_ops rzn1_rtc_ops = {
367369
.set_offset = rzn1_rtc_set_offset,
368370
};
369371

372+
static const struct rtc_class_ops rzn1_rtc_ops_scmp = {
373+
.read_time = rzn1_rtc_read_time,
374+
.set_time = rzn1_rtc_set_time,
375+
.read_alarm = rzn1_rtc_read_alarm,
376+
.set_alarm = rzn1_rtc_set_alarm,
377+
.alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
378+
};
379+
370380
static int rzn1_rtc_probe(struct platform_device *pdev)
371381
{
372382
struct rzn1_rtc *rtc;
373-
u32 val;
374-
int irq;
375-
int ret;
383+
u32 val, scmp_val = 0;
384+
struct clk *xtal;
385+
unsigned long rate;
386+
int irq, ret;
376387

377388
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
378389
if (!rtc)
@@ -395,7 +406,6 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
395406
rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
396407
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
397408
rtc->rtcdev->alarm_offset_max = 7 * 86400;
398-
rtc->rtcdev->ops = &rzn1_rtc_ops;
399409

400410
ret = devm_pm_runtime_enable(&pdev->dev);
401411
if (ret < 0)
@@ -404,10 +414,24 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
404414
if (ret < 0)
405415
return ret;
406416

407-
/*
408-
* Ensure the clock counter is enabled.
409-
* Set 24-hour mode and possible oscillator offset compensation in SUBU mode.
410-
*/
417+
/* Only switch to scmp if we have an xtal clock with a valid rate and != 32768 */
418+
xtal = devm_clk_get_optional(&pdev->dev, "xtal");
419+
if (IS_ERR(xtal)) {
420+
ret = PTR_ERR(xtal);
421+
goto dis_runtime_pm;
422+
} else if (xtal) {
423+
rate = clk_get_rate(xtal);
424+
425+
if (rate < 32000 || rate > BIT(22)) {
426+
ret = -EOPNOTSUPP;
427+
goto dis_runtime_pm;
428+
}
429+
430+
if (rate != 32768)
431+
scmp_val = RZN1_RTC_CTL0_SLSB_SCMP;
432+
}
433+
434+
/* Disable controller during SUBU/SCMP setup */
411435
val = readl(rtc->base + RZN1_RTC_CTL0) & ~RZN1_RTC_CTL0_CE;
412436
writel(val, rtc->base + RZN1_RTC_CTL0);
413437
/* Wait 2-4 32k clock cycles for the disabled controller */
@@ -416,8 +440,18 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
416440
if (ret)
417441
goto dis_runtime_pm;
418442

419-
writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU,
420-
rtc->base + RZN1_RTC_CTL0);
443+
/* Set desired modes leaving the controller disabled */
444+
writel(RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
445+
446+
if (scmp_val) {
447+
writel(rate - 1, rtc->base + RZN1_RTC_SCMP);
448+
rtc->rtcdev->ops = &rzn1_rtc_ops_scmp;
449+
} else {
450+
rtc->rtcdev->ops = &rzn1_rtc_ops_subu;
451+
}
452+
453+
/* Enable controller finally */
454+
writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
421455

422456
/* Disable all interrupts */
423457
writel(0, rtc->base + RZN1_RTC_CTL1);

0 commit comments

Comments
 (0)