[PATCH 0/7] rtc: davinci: add driver model support

The series adds driver model support for omap RTC plus some fixes.
Dario Binacchi (7): rtc: davinci: enable compilation for omap architectures rtc: davinci: replace 32bit access with 8bit access rtc: davinci: check BUSY bit before set TC registers rtc: davinci: use unlock/lock mechanism arm: dts: sync rtc node of am335x boards with Linux 5.9-rc7 rtc: davinci: add driver model support rtc: davinci: fix date loaded on reset
arch/arm/dts/am335x-bone-common.dtsi | 5 + arch/arm/dts/am335x-evm.dts | 5 + arch/arm/dts/am335x-evmsk.dts | 5 + arch/arm/dts/am335x-osd335x-common.dtsi | 6 + drivers/rtc/Kconfig | 7 + drivers/rtc/davinci.c | 467 ++++++++++++++++++++++-- 6 files changed, 466 insertions(+), 29 deletions(-)

The Davinci's onchip RTC is also present on TI OMAP1, AM33XX, AM43XX and DRA7XX SOCs. So, let's enable compilation for these architectures too.
Signed-off-by: Dario Binacchi dariobin@libero.it ---
drivers/rtc/Kconfig | 7 +++++++ drivers/rtc/davinci.c | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c84a9d2b27..cbdfddb80f 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -188,4 +188,11 @@ config RTC_ABX80X families of ultra-low-power battery- and capacitor-backed real-time clock chips.
+config RTC_DAVINCI + bool "Enable TI OMAP RTC driver" + depends on ARCH_DAVINCI || ARCH_OMAP2PLUS + help + Say "yes" here to support the on chip real time clock + present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. + endmenu diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index c446e7a735..8f5f76c9d6 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -9,11 +9,16 @@ #include <rtc.h> #include <asm/io.h> #include <asm/davinci_rtc.h> +#include <asm/arch/hardware.h> #include <linux/delay.h>
+#if !defined(RTC_BASE) && defined(DAVINCI_RTC_BASE) +#define RTC_BASE DAVINCI_RTC_BASE +#endif + int rtc_get(struct rtc_time *tmp) { - struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE; + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; unsigned long sec, min, hour, mday, wday, mon_cent, year; unsigned long status;
@@ -57,7 +62,7 @@ int rtc_get(struct rtc_time *tmp)
int rtc_set(struct rtc_time *tmp) { - struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE; + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, @@ -75,7 +80,7 @@ int rtc_set(struct rtc_time *tmp)
void rtc_reset(void) { - struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE; + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
/* run RTC counter */ writel(0x01, &rtc->ctrl);

On Friday 07 May 2021 06:15:02 Dario Binacchi wrote:
The Davinci's onchip RTC is also present on TI OMAP1, AM33XX, AM43XX and DRA7XX SOCs. So, let's enable compilation for these architectures too.
Hello! If it is available on AM33XX, do you know if it is also on OMAP3?
Signed-off-by: Dario Binacchi dariobin@libero.it
drivers/rtc/Kconfig | 7 +++++++ drivers/rtc/davinci.c | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c84a9d2b27..cbdfddb80f 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -188,4 +188,11 @@ config RTC_ABX80X families of ultra-low-power battery- and capacitor-backed real-time clock chips.
+config RTC_DAVINCI
- bool "Enable TI OMAP RTC driver"
- depends on ARCH_DAVINCI || ARCH_OMAP2PLUS
- help
Say "yes" here to support the on chip real time clock
present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx.
endmenu diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index c446e7a735..8f5f76c9d6 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -9,11 +9,16 @@ #include <rtc.h> #include <asm/io.h> #include <asm/davinci_rtc.h> +#include <asm/arch/hardware.h> #include <linux/delay.h>
+#if !defined(RTC_BASE) && defined(DAVINCI_RTC_BASE) +#define RTC_BASE DAVINCI_RTC_BASE +#endif
int rtc_get(struct rtc_time *tmp) {
- struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
- struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; unsigned long sec, min, hour, mday, wday, mon_cent, year; unsigned long status;
@@ -57,7 +62,7 @@ int rtc_get(struct rtc_time *tmp)
int rtc_set(struct rtc_time *tmp) {
- struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -75,7 +80,7 @@ int rtc_set(struct rtc_time *tmp)
void rtc_reset(void) {
- struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
/* run RTC counter */ writel(0x01, &rtc->ctrl);
-- 2.17.1

Hi Pali,
Il 07/05/2021 09:56 Pali Rohár pali@kernel.org ha scritto:
On Friday 07 May 2021 06:15:02 Dario Binacchi wrote:
The Davinci's onchip RTC is also present on TI OMAP1, AM33XX, AM43XX and DRA7XX SOCs. So, let's enable compilation for these architectures too.
Hello! If it is available on AM33XX, do you know if it is also on OMAP3?
I do not think so. I think am335x is omap2 and not omap3. In https://www.ti.com/lit/ug/spruf98y/spruf98y.pdf I don't see any reference to the RTC.
Thanks and regards, Dario
Signed-off-by: Dario Binacchi dariobin@libero.it
drivers/rtc/Kconfig | 7 +++++++ drivers/rtc/davinci.c | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c84a9d2b27..cbdfddb80f 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -188,4 +188,11 @@ config RTC_ABX80X families of ultra-low-power battery- and capacitor-backed real-time clock chips.
+config RTC_DAVINCI
- bool "Enable TI OMAP RTC driver"
- depends on ARCH_DAVINCI || ARCH_OMAP2PLUS
- help
Say "yes" here to support the on chip real time clock
present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx.
endmenu diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index c446e7a735..8f5f76c9d6 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -9,11 +9,16 @@ #include <rtc.h> #include <asm/io.h> #include <asm/davinci_rtc.h> +#include <asm/arch/hardware.h> #include <linux/delay.h>
+#if !defined(RTC_BASE) && defined(DAVINCI_RTC_BASE) +#define RTC_BASE DAVINCI_RTC_BASE +#endif
int rtc_get(struct rtc_time *tmp) {
- struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
- struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; unsigned long sec, min, hour, mday, wday, mon_cent, year; unsigned long status;
@@ -57,7 +62,7 @@ int rtc_get(struct rtc_time *tmp)
int rtc_set(struct rtc_time *tmp) {
- struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -75,7 +80,7 @@ int rtc_set(struct rtc_time *tmp)
void rtc_reset(void) {
- struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE;
struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
/* run RTC counter */ writel(0x01, &rtc->ctrl);
-- 2.17.1

On 07/05/21 9:45 am, Dario Binacchi wrote:
The Davinci's onchip RTC is also present on TI OMAP1, AM33XX, AM43XX and DRA7XX SOCs. So, let's enable compilation for these architectures too.
Signed-off-by: Dario Binacchi dariobin@libero.it
drivers/rtc/Kconfig | 7 +++++++ drivers/rtc/davinci.c | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c84a9d2b27..cbdfddb80f 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -188,4 +188,11 @@ config RTC_ABX80X families of ultra-low-power battery- and capacitor-backed real-time clock chips.
+config RTC_DAVINCI
- bool "Enable TI OMAP RTC driver"
- depends on ARCH_DAVINCI || ARCH_OMAP2PLUS
I assume you are converting to a Kconfig symbol? Can you keep this as a separate patch and use tools/moveconfig.py?
Thanks and regards, Lokesh

Hi Lokesh,
Il 27/05/2021 11:59 Lokesh Vutla lokeshvutla@ti.com ha scritto:
On 07/05/21 9:45 am, Dario Binacchi wrote:
The Davinci's onchip RTC is also present on TI OMAP1, AM33XX, AM43XX and DRA7XX SOCs. So, let's enable compilation for these architectures too.
Signed-off-by: Dario Binacchi dariobin@libero.it
drivers/rtc/Kconfig | 7 +++++++ drivers/rtc/davinci.c | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c84a9d2b27..cbdfddb80f 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -188,4 +188,11 @@ config RTC_ABX80X families of ultra-low-power battery- and capacitor-backed real-time clock chips.
+config RTC_DAVINCI
- bool "Enable TI OMAP RTC driver"
- depends on ARCH_DAVINCI || ARCH_OMAP2PLUS
I assume you are converting to a Kconfig symbol? Can you keep this as a separate patch and use tools/moveconfig.py?
The CONFIG_RTC_DAVINCI symbol was only in the Makefile. I ran moveconfig.py and in fact it didn't find it in any configuration header. I'll add the Kconfig symbol in a separate patch.
Thanks and regards Dario Binacchi
Thanks and regards, Lokesh

Use 32-bit access only where it is needed. Most of the RTC registers contain useful information in the 8 least significant bits, the others are reserved.
Signed-off-by: Dario Binacchi dariobin@libero.it ---
drivers/rtc/davinci.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index 8f5f76c9d6..99ae31e2a5 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -22,7 +22,7 @@ int rtc_get(struct rtc_time *tmp) unsigned long sec, min, hour, mday, wday, mon_cent, year; unsigned long status;
- status = readl(&rtc->status); + status = readb(&rtc->status); if ((status & RTC_STATE_RUN) != RTC_STATE_RUN) { printf("RTC doesn't run\n"); return -1; @@ -30,13 +30,13 @@ int rtc_get(struct rtc_time *tmp) if ((status & RTC_STATE_BUSY) == RTC_STATE_BUSY) udelay(20);
- sec = readl(&rtc->second); - min = readl(&rtc->minutes); - hour = readl(&rtc->hours); - mday = readl(&rtc->day); - wday = readl(&rtc->dotw); - mon_cent = readl(&rtc->month); - year = readl(&rtc->year); + sec = readb(&rtc->second); + min = readb(&rtc->minutes); + hour = readb(&rtc->hours); + mday = readb(&rtc->day); + wday = readb(&rtc->dotw); + mon_cent = readb(&rtc->month); + year = readb(&rtc->year);
debug("Get RTC year: %02lx mon/cent: %02lx mday: %02lx wday: %02lx " "hr: %02lx min: %02lx sec: %02lx\n", @@ -67,14 +67,14 @@ int rtc_set(struct rtc_time *tmp) debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - writel(bin2bcd(tmp->tm_year % 100), &rtc->year); - writel(bin2bcd(tmp->tm_mon), &rtc->month); + writeb(bin2bcd(tmp->tm_year % 100), &rtc->year); + writeb(bin2bcd(tmp->tm_mon), &rtc->month);
- writel(bin2bcd(tmp->tm_wday), &rtc->dotw); - writel(bin2bcd(tmp->tm_mday), &rtc->day); - writel(bin2bcd(tmp->tm_hour), &rtc->hours); - writel(bin2bcd(tmp->tm_min), &rtc->minutes); - writel(bin2bcd(tmp->tm_sec), &rtc->second); + writeb(bin2bcd(tmp->tm_wday), &rtc->dotw); + writeb(bin2bcd(tmp->tm_mday), &rtc->day); + writeb(bin2bcd(tmp->tm_hour), &rtc->hours); + writeb(bin2bcd(tmp->tm_min), &rtc->minutes); + writeb(bin2bcd(tmp->tm_sec), &rtc->second); return 0; }
@@ -83,5 +83,5 @@ void rtc_reset(void) struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
/* run RTC counter */ - writel(0x01, &rtc->ctrl); + writeb(0x01, &rtc->ctrl); }

To write correct data to the TC registers, the STATUS register must be read until the BUSY bit is equal to zero. Once the BUSY flag is zero, there is a 15 μs access period in which the TC registers can be programmed. The rtc_wait_not_busy() has been inspired by the Kernel.
Signed-off-by: Dario Binacchi dariobin@libero.it ---
drivers/rtc/davinci.c | 45 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-)
diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index 99ae31e2a5..7b8c729f3b 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -16,19 +16,39 @@ #define RTC_BASE DAVINCI_RTC_BASE #endif
-int rtc_get(struct rtc_time *tmp) +static int davinci_rtc_wait_not_busy(struct davinci_rtc *rtc) { - struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; - unsigned long sec, min, hour, mday, wday, mon_cent, year; - unsigned long status; + int count; + u8 status;
status = readb(&rtc->status); if ((status & RTC_STATE_RUN) != RTC_STATE_RUN) { printf("RTC doesn't run\n"); return -1; } - if ((status & RTC_STATE_BUSY) == RTC_STATE_BUSY) - udelay(20); + + /* BUSY may stay active for 1/32768 second (~30 usec) */ + for (count = 0; count < 50; count++) { + if (!(status & RTC_STATE_BUSY)) + break; + + udelay(1); + status = readb(&rtc->status); + } + + /* now we have ~15 usec to read/write various registers */ + return 0; +} + +int rtc_get(struct rtc_time *tmp) +{ + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; + unsigned long sec, min, hour, mday, wday, mon_cent, year; + int ret; + + ret = davinci_rtc_wait_not_busy(rtc); + if (ret) + return ret;
sec = readb(&rtc->second); min = readb(&rtc->minutes); @@ -63,10 +83,12 @@ int rtc_get(struct rtc_time *tmp) int rtc_set(struct rtc_time *tmp) { struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; + int ret; + + ret = davinci_rtc_wait_not_busy(rtc); + if (ret) + return ret;
- debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); writeb(bin2bcd(tmp->tm_year % 100), &rtc->year); writeb(bin2bcd(tmp->tm_mon), &rtc->month);
@@ -75,6 +97,11 @@ int rtc_set(struct rtc_time *tmp) writeb(bin2bcd(tmp->tm_hour), &rtc->hours); writeb(bin2bcd(tmp->tm_min), &rtc->minutes); writeb(bin2bcd(tmp->tm_sec), &rtc->second); + + debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", + tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + return 0; }

The RTC module contains a kicker mechanism to prevent any spurious writes from changing the register values. To set the time, you must first unlock the TC registers, update them and then lock.
Signed-off-by: Dario Binacchi dariobin@libero.it ---
drivers/rtc/davinci.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index 7b8c729f3b..82e5eb3b43 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -16,6 +16,18 @@ #define RTC_BASE DAVINCI_RTC_BASE #endif
+static void davinci_rtc_lock(struct davinci_rtc *rtc) +{ + writel(0, &rtc->kick0r); + writel(0, &rtc->kick1r); +} + +static void davinci_rtc_unlock(struct davinci_rtc *rtc) +{ + writel(RTC_KICK0R_WE, &rtc->kick0r); + writel(RTC_KICK1R_WE, &rtc->kick1r); +} + static int davinci_rtc_wait_not_busy(struct davinci_rtc *rtc) { int count; @@ -89,6 +101,7 @@ int rtc_set(struct rtc_time *tmp) if (ret) return ret;
+ davinci_rtc_unlock(rtc); writeb(bin2bcd(tmp->tm_year % 100), &rtc->year); writeb(bin2bcd(tmp->tm_mon), &rtc->month);
@@ -97,6 +110,7 @@ int rtc_set(struct rtc_time *tmp) writeb(bin2bcd(tmp->tm_hour), &rtc->hours); writeb(bin2bcd(tmp->tm_min), &rtc->minutes); writeb(bin2bcd(tmp->tm_sec), &rtc->second); + davinci_rtc_lock(rtc);
debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,

There have been some changes to the am335x-<board> DTs related to the rtc node, so let's re-syncs them with Linux.
Signed-off-by: Dario Binacchi dariobin@libero.it ---
arch/arm/dts/am335x-bone-common.dtsi | 5 +++++ arch/arm/dts/am335x-evm.dts | 5 +++++ arch/arm/dts/am335x-evmsk.dts | 5 +++++ arch/arm/dts/am335x-osd335x-common.dtsi | 6 ++++++ 4 files changed, 21 insertions(+)
diff --git a/arch/arm/dts/am335x-bone-common.dtsi b/arch/arm/dts/am335x-bone-common.dtsi index 5b8230e281..8dcfac3a5b 100644 --- a/arch/arm/dts/am335x-bone-common.dtsi +++ b/arch/arm/dts/am335x-bone-common.dtsi @@ -398,3 +398,8 @@ &sham { status = "okay"; }; + +&rtc { + clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>; + clock-names = "ext-clk", "int-clk"; +}; diff --git a/arch/arm/dts/am335x-evm.dts b/arch/arm/dts/am335x-evm.dts index c4bd1855f2..136f685bc5 100644 --- a/arch/arm/dts/am335x-evm.dts +++ b/arch/arm/dts/am335x-evm.dts @@ -783,3 +783,8 @@ pinctrl-names = "default"; pinctrl-0 = <&dcan1_pins_default>; }; + +&rtc { + clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>; + clock-names = "ext-clk", "int-clk"; +}; diff --git a/arch/arm/dts/am335x-evmsk.dts b/arch/arm/dts/am335x-evmsk.dts index c94c33b595..b14bf2ff1b 100644 --- a/arch/arm/dts/am335x-evmsk.dts +++ b/arch/arm/dts/am335x-evmsk.dts @@ -724,3 +724,8 @@ &lcdc { status = "okay"; }; + +&rtc { + clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>; + clock-names = "ext-clk", "int-clk"; +}; diff --git a/arch/arm/dts/am335x-osd335x-common.dtsi b/arch/arm/dts/am335x-osd335x-common.dtsi index f8ff473f94..2b55b7d0f9 100644 --- a/arch/arm/dts/am335x-osd335x-common.dtsi +++ b/arch/arm/dts/am335x-osd335x-common.dtsi @@ -122,3 +122,9 @@ &sham { status = "okay"; }; + +&rtc { + clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>; + clock-names = "ext-clk", "int-clk"; + system-power-controller; +};

Update the driver to support the device tree and the driver model. The read / write helpers in rtc_ops allow access to scratch registers only. The offset parameter is added to the address of the scratch0 register.
Signed-off-by: Dario Binacchi dariobin@libero.it ---
drivers/rtc/davinci.c | 373 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 363 insertions(+), 10 deletions(-)
diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index 82e5eb3b43..b0a077cba7 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -2,20 +2,20 @@ /* * (C) Copyright 2011 DENX Software Engineering GmbH * Heiko Schocher hs@denx.de + * Copyright (C) 2021 Dario Binacchi dariobin@libero.it */ #include <common.h> #include <command.h> +#include <dm.h> +#include <clk.h> #include <log.h> #include <rtc.h> #include <asm/io.h> #include <asm/davinci_rtc.h> #include <asm/arch/hardware.h> +#include <dm/device_compat.h> #include <linux/delay.h>
-#if !defined(RTC_BASE) && defined(DAVINCI_RTC_BASE) -#define RTC_BASE DAVINCI_RTC_BASE -#endif - static void davinci_rtc_lock(struct davinci_rtc *rtc) { writel(0, &rtc->kick0r); @@ -52,9 +52,8 @@ static int davinci_rtc_wait_not_busy(struct davinci_rtc *rtc) return 0; }
-int rtc_get(struct rtc_time *tmp) +static int davinci_rtc_get(struct davinci_rtc *rtc, struct rtc_time *tmp) { - struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; unsigned long sec, min, hour, mday, wday, mon_cent, year; int ret;
@@ -92,9 +91,8 @@ int rtc_get(struct rtc_time *tmp) return 0; }
-int rtc_set(struct rtc_time *tmp) +static int davinci_rtc_set(struct davinci_rtc *rtc, const struct rtc_time *tmp) { - struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; int ret;
ret = davinci_rtc_wait_not_busy(rtc); @@ -119,10 +117,365 @@ int rtc_set(struct rtc_time *tmp) return 0; }
+static void davinci_rtc_reset(struct davinci_rtc *rtc) +{ + /* run RTC counter */ + writeb(0x01, &rtc->ctrl); +} + +#if !CONFIG_IS_ENABLED(DM_RTC) + +#if !defined(RTC_BASE) && defined(DAVINCI_RTC_BASE) +#define RTC_BASE DAVINCI_RTC_BASE +#endif + +int rtc_get(struct rtc_time *tmp) +{ + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; + + return davinci_rtc_get(rtc, tmp); +} + +int rtc_set(struct rtc_time *tmp) +{ + struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; + + return davinci_rtc_set(rtc, tmp); +} + void rtc_reset(void) { struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
- /* run RTC counter */ - writeb(0x01, &rtc->ctrl); + davinci_rtc_reset(rtc); +} + +#else /* CONFIG_DM_RTC */ + +#define OMAP_RTC_CTRL_REG 0x40 +#define OMAP_RTC_STATUS_REG 0x44 +#define OMAP_RTC_INTERRUPTS_REG 0x48 + +#define OMAP_RTC_OSC_REG 0x54 + +#define OMAP_RTC_SCRATCH0_REG 0x60 +#define OMAP_RTC_SCRATCH1_REG 0x64 +#define OMAP_RTC_SCRATCH2_REG 0x68 + +#define OMAP_RTC_KICK0_REG 0x6c +#define OMAP_RTC_KICK1_REG 0x70 + +#define OMAP_RTC_PMIC_REG 0x98 + +/* OMAP_RTC_CTRL_REG bit fields: */ +#define OMAP_RTC_CTRL_SPLIT BIT(7) +#define OMAP_RTC_CTRL_DISABLE BIT(6) +#define OMAP_RTC_CTRL_SET_32_COUNTER BIT(5) +#define OMAP_RTC_CTRL_TEST BIT(4) +#define OMAP_RTC_CTRL_MODE_12_24 BIT(3) +#define OMAP_RTC_CTRL_AUTO_COMP BIT(2) +#define OMAP_RTC_CTRL_ROUND_30S BIT(1) +#define OMAP_RTC_CTRL_STOP BIT(0) + +/* OMAP_RTC_STATUS_REG bit fields */ +#define OMAP_RTC_STATUS_POWER_UP BIT(7) +#define OMAP_RTC_STATUS_ALARM2 BIT(7) +#define OMAP_RTC_STATUS_ALARM BIT(6) +#define OMAP_RTC_STATUS_1D_EVENT BIT(5) +#define OMAP_RTC_STATUS_1H_EVENT BIT(4) +#define OMAP_RTC_STATUS_1M_EVENT BIT(3) +#define OMAP_RTC_STATUS_1S_EVENT BIT(2) +#define OMAP_RTC_STATUS_RUN BIT(1) +#define OMAP_RTC_STATUS_BUSY BIT(0) + +/* OMAP_RTC_OSC_REG bit fields */ +#define OMAP_RTC_OSC_32KCLK_EN BIT(6) +#define OMAP_RTC_OSC_SEL_32KCLK_SRC BIT(3) +#define OMAP_RTC_OSC_OSC32K_GZ_DISABLE BIT(4) + +struct omap_rtc_device_type { + bool has_32kclk_en; + bool has_irqwakeen; + bool has_pmic_mode; + bool has_power_up_reset; +}; + +struct omap_rtc_priv { + fdt_addr_t base; + u8 max_reg; + struct udevice *dev; + struct clk clk; + bool has_ext_clk; + const struct omap_rtc_device_type *type; +}; + +static inline u8 omap_rtc_readb(struct omap_rtc_priv *priv, unsigned int reg) +{ + return readb(priv->base + reg); +} + +static inline u32 omap_rtc_readl(struct omap_rtc_priv *priv, unsigned int reg) +{ + return readl(priv->base + reg); +} + +static inline void omap_rtc_writeb(struct omap_rtc_priv *priv, unsigned int reg, + u8 val) +{ + writeb(val, priv->base + reg); +} + +static inline void omap_rtc_writel(struct omap_rtc_priv *priv, unsigned int reg, + u32 val) +{ + writel(val, priv->base + reg); +} + +static inline void omap_rtc_unlock(struct omap_rtc_priv *priv) +{ + davinci_rtc_unlock((struct davinci_rtc *)priv->base); +} + +static inline void omap_rtc_lock(struct omap_rtc_priv *priv) +{ + davinci_rtc_lock((struct davinci_rtc *)priv->base); +} + +static int omap_rtc_reset(struct udevice *dev) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + + davinci_rtc_reset((struct davinci_rtc *)priv->base); + return 0; +} + +static int omap_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + + return davinci_rtc_set((struct davinci_rtc *)priv->base, tm); } + +static int omap_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + + return davinci_rtc_get((struct davinci_rtc *)priv->base, tm); +} + +static int omap_rtc_scratch_read(struct udevice *dev, uint offset, + u8 *buffer, uint len) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + u32 *val = (u32 *)buffer; + unsigned int reg; + int i; + + if (len & 3) + return -EFAULT; + + for (i = 0; i < len / 4; i++) { + reg = OMAP_RTC_SCRATCH0_REG + offset + (i * 4); + if (reg >= OMAP_RTC_KICK0_REG) + return -EFAULT; + + val[i] = omap_rtc_readl(priv, reg); + } + + return 0; +} + +static int omap_rtc_scratch_write(struct udevice *dev, uint offset, + const u8 *buffer, uint len) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + u32 *val = (u32 *)buffer; + unsigned int reg; + int i; + + if (len & 3) + return -EFAULT; + + omap_rtc_unlock(priv); + for (i = 0; i < len / 4; i++) { + reg = OMAP_RTC_SCRATCH0_REG + offset + (i * 4); + if (reg >= OMAP_RTC_KICK0_REG) + return -EFAULT; + + omap_rtc_writel(priv, reg, val[i]); + } + omap_rtc_lock(priv); + + return 0; +} + +static int omap_rtc_remove(struct udevice *dev) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + u8 reg; + + if (priv->clk.dev) + clk_disable(&priv->clk); + + omap_rtc_unlock(priv); + + /* leave rtc running, but disable irqs */ + omap_rtc_writeb(priv, OMAP_RTC_INTERRUPTS_REG, 0); + + if (priv->has_ext_clk) { + reg = omap_rtc_readb(priv, OMAP_RTC_OSC_REG); + reg &= ~OMAP_RTC_OSC_SEL_32KCLK_SRC; + omap_rtc_writeb(priv, OMAP_RTC_OSC_REG, reg); + } + + omap_rtc_lock(priv); + return 0; +} + +static int omap_rtc_probe(struct udevice *dev) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + u8 reg, mask, new_ctrl; + + priv->dev = dev; + priv->type = (struct omap_rtc_device_type *)dev_get_driver_data(dev); + priv->max_reg = OMAP_RTC_PMIC_REG; + + if (!clk_get_by_name(dev, "ext-clk", &priv->clk)) + priv->has_ext_clk = true; + else + clk_get_by_name(dev, "int-clk", &priv->clk); + + if (priv->clk.dev) + clk_enable(&priv->clk); + else + dev_warn(dev, "missing clock\n"); + + omap_rtc_unlock(priv); + + /* + * disable interrupts + * + * NOTE: ALARM2 is not cleared on AM3352 if rtc_write (writeb) is used + */ + omap_rtc_writel(priv, OMAP_RTC_INTERRUPTS_REG, 0); + + if (priv->type->has_32kclk_en) { + reg = omap_rtc_readb(priv, OMAP_RTC_OSC_REG); + omap_rtc_writeb(priv, OMAP_RTC_OSC_REG, + reg | OMAP_RTC_OSC_32KCLK_EN); + } + + /* clear old status */ + reg = omap_rtc_readb(priv, OMAP_RTC_STATUS_REG); + + mask = OMAP_RTC_STATUS_ALARM; + + if (priv->type->has_pmic_mode) + mask |= OMAP_RTC_STATUS_ALARM2; + + if (priv->type->has_power_up_reset) { + mask |= OMAP_RTC_STATUS_POWER_UP; + if (reg & OMAP_RTC_STATUS_POWER_UP) + dev_info(dev, "RTC power up reset detected\n"); + } + + if (reg & mask) + omap_rtc_writeb(priv, OMAP_RTC_STATUS_REG, reg & mask); + + /* On boards with split power, RTC_ON_NOFF won't reset the RTC */ + reg = omap_rtc_readb(priv, OMAP_RTC_CTRL_REG); + if (reg & OMAP_RTC_CTRL_STOP) + dev_info(dev, "already running\n"); + + /* force to 24 hour mode */ + new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT | OMAP_RTC_CTRL_AUTO_COMP); + new_ctrl |= OMAP_RTC_CTRL_STOP; + + /* + * BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE: + * + * - Device wake-up capability setting should come through chip + * init logic. OMAP1 boards should initialize the "wakeup capable" + * flag in the platform device if the board is wired right for + * being woken up by RTC alarm. For OMAP-L138, this capability + * is built into the SoC by the "Deep Sleep" capability. + * + * - Boards wired so RTC_ON_nOFF is used as the reset signal, + * rather than nPWRON_RESET, should forcibly enable split + * power mode. (Some chip errata report that RTC_CTRL_SPLIT + * is write-only, and always reads as zero...) + */ + + if (new_ctrl & OMAP_RTC_CTRL_SPLIT) + dev_info(dev, "split power mode\n"); + + if (reg != new_ctrl) + omap_rtc_writeb(priv, OMAP_RTC_CTRL_REG, new_ctrl); + + /* + * If we have the external clock then switch to it so we can keep + * ticking across suspend. + */ + if (priv->has_ext_clk) { + reg = omap_rtc_readb(priv, OMAP_RTC_OSC_REG); + reg &= ~OMAP_RTC_OSC_OSC32K_GZ_DISABLE; + reg |= OMAP_RTC_OSC_32KCLK_EN | OMAP_RTC_OSC_SEL_32KCLK_SRC; + omap_rtc_writeb(priv, OMAP_RTC_OSC_REG, reg); + } + + omap_rtc_lock(priv); + return 0; +} + +static int omap_rtc_of_to_plat(struct udevice *dev) +{ + struct omap_rtc_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) { + dev_err(dev, "invalid address\n"); + return -EINVAL; + } + + dev_dbg(dev, "base=%pa\n", &priv->base); + return 0; +} + +static const struct rtc_ops omap_rtc_ops = { + .get = omap_rtc_get, + .set = omap_rtc_set, + .reset = omap_rtc_reset, + .read = omap_rtc_scratch_read, + .write = omap_rtc_scratch_write, +}; + +static const struct omap_rtc_device_type omap_rtc_am3352_type = { + .has_32kclk_en = true, + .has_irqwakeen = true, + .has_pmic_mode = true, +}; + +static const struct omap_rtc_device_type omap_rtc_da830_type = { + .has_32kclk_en = false, + .has_irqwakeen = false, + .has_pmic_mode = false, +}; + +static const struct udevice_id omap_rtc_ids[] = { + {.compatible = "ti,am3352-rtc", .data = (ulong)&omap_rtc_am3352_type}, + {.compatible = "ti,da830-rtc", .data = (ulong)&omap_rtc_da830_type } +}; + +U_BOOT_DRIVER(omap_rtc) = { + .name = "omap_rtc", + .id = UCLASS_RTC, + .of_match = omap_rtc_ids, + .ops = &omap_rtc_ops, + .of_to_plat = omap_rtc_of_to_plat, + .probe = omap_rtc_probe, + .remove = omap_rtc_remove, + .priv_auto = sizeof(struct omap_rtc_priv), +}; + +#endif /* CONFIG_DM_RTC */

On 07/05/21 9:45 am, Dario Binacchi wrote:
Update the driver to support the device tree and the driver model. The read / write helpers in rtc_ops allow access to scratch registers only. The offset parameter is added to the address of the scratch0 register.
Signed-off-by: Dario Binacchi dariobin@libero.it
drivers/rtc/davinci.c | 373 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 363 insertions(+), 10 deletions(-)
diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index 82e5eb3b43..b0a077cba7 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -2,20 +2,20 @@ /*
- (C) Copyright 2011 DENX Software Engineering GmbH
- Heiko Schocher hs@denx.de
*/
- Copyright (C) 2021 Dario Binacchi dariobin@libero.it
#include <common.h> #include <command.h> +#include <dm.h> +#include <clk.h> #include <log.h> #include <rtc.h> #include <asm/io.h> #include <asm/davinci_rtc.h> #include <asm/arch/hardware.h> +#include <dm/device_compat.h> #include <linux/delay.h>
-#if !defined(RTC_BASE) && defined(DAVINCI_RTC_BASE) -#define RTC_BASE DAVINCI_RTC_BASE -#endif
static void davinci_rtc_lock(struct davinci_rtc *rtc) { writel(0, &rtc->kick0r); @@ -52,9 +52,8 @@ static int davinci_rtc_wait_not_busy(struct davinci_rtc *rtc) return 0; }
-int rtc_get(struct rtc_time *tmp) +static int davinci_rtc_get(struct davinci_rtc *rtc, struct rtc_time *tmp)
can we use use consistent naming? omap_rtc_<function>?
{
- struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; unsigned long sec, min, hour, mday, wday, mon_cent, year; int ret;
@@ -92,9 +91,8 @@ int rtc_get(struct rtc_time *tmp) return 0; }
-int rtc_set(struct rtc_time *tmp) +static int davinci_rtc_set(struct davinci_rtc *rtc, const struct rtc_time *tmp) {
struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE; int ret;
ret = davinci_rtc_wait_not_busy(rtc);
@@ -119,10 +117,365 @@ int rtc_set(struct rtc_time *tmp) return 0; }
+static void davinci_rtc_reset(struct davinci_rtc *rtc) +{
- /* run RTC counter */
- writeb(0x01, &rtc->ctrl);
+}
+#if !CONFIG_IS_ENABLED(DM_RTC)
Are there any users of non-DM? If not can we just drop the support for non-DM?
Thanks and regards, Lokesh

On reset, the RTC loads the 2000-01-01 date with a wrong day of the week (Sunday instead of Saturday).
Signed-off-by: Dario Binacchi dariobin@libero.it
---
drivers/rtc/davinci.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index b0a077cba7..88fd56b1ba 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -335,6 +335,7 @@ static int omap_rtc_remove(struct udevice *dev) static int omap_rtc_probe(struct udevice *dev) { struct omap_rtc_priv *priv = dev_get_priv(dev); + struct rtc_time tm; u8 reg, mask, new_ctrl;
priv->dev = dev; @@ -425,6 +426,15 @@ static int omap_rtc_probe(struct udevice *dev) }
omap_rtc_lock(priv); + + if (omap_rtc_get(dev, &tm)) { + dev_err(dev, "failed to get datetime\n"); + } else if (tm.tm_year == 2000 && tm.tm_mon == 1 && tm.tm_mday == 1 && + tm.tm_wday == 0) { + tm.tm_wday = 6; + omap_rtc_set(dev, &tm); + } + return 0; }
participants (3)
-
Dario Binacchi
-
Lokesh Vutla
-
Pali Rohár