summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-11-30 11:18:16 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2024-11-30 11:18:16 -0800
commit0e287d31b62bb53ad81d5e59778384a40f8b6f56 (patch)
tree4ffd2509808b16b6d276d5e1456b068dca1a0b0c
parent831c1926ee728c3e747255f7c0f434762e8e863d (diff)
parente0779a0dcf41a6452ac0a169cd96863feb5787c7 (diff)
Merge tag 'rtc-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni: "New drivers: - Amlogic A4 and A5 RTC - Marvell 88PM886 PMIC RTC - Renesas RTCA-3 for Renesas RZ/G3S Driver updates: - ab-eoz9: fix temperature and alarm support - cmos: improve locking behaviour - isl12022: add alarm support - m48t59: improve epoch handling - mt6359: add range - rzn1: fix BCD conversions and simplify driver" * tag 'rtc-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (38 commits) rtc: ab-eoz9: don't fail temperature reads on undervoltage notification rtc: rzn1: reduce register access rtc: rzn1: drop superfluous wday calculation m68k: mvme147, mvme16x: Adopt rtc-m48t59 platform driver rtc: brcmstb-waketimer: don't include 'pm_wakeup.h' directly rtc: m48t59: Use platform_data struct for year offset value rtc: ab-eoz9: fix abeoz9_rtc_read_alarm rtc: rv3028: fix RV3028_TS_COUNT type rtc: rzn1: update Michel's email rtc: rzn1: fix BCD to rtc_time conversion errors rtc: amlogic-a4: fix compile error rtc: amlogic-a4: drop error messages MAINTAINERS: Add an entry for Amlogic RTC driver rtc: support for the Amlogic on-chip RTC dt-bindings: rtc: Add Amlogic A4 and A5 RTC rtc: add driver for Marvell 88PM886 PMIC RTC rtc: check if __rtc_read_time was successful in rtc_timer_do_work() rtc: pcf8563: Switch to regmap rtc: pcf8563: Sort headers alphabetically rtc: abx80x: Fix WDT bit position of the status register ...
-rw-r--r--Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml4
-rw-r--r--Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml63
-rw-r--r--Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml (renamed from Documentation/devicetree/bindings/rtc/microchip,mfps-rtc.yaml)10
-rw-r--r--Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml84
-rw-r--r--MAINTAINERS17
-rw-r--r--arch/m68k/configs/multi_defconfig1
-rw-r--r--arch/m68k/configs/mvme147_defconfig1
-rw-r--r--arch/m68k/configs/mvme16x_defconfig1
-rw-r--r--arch/m68k/include/asm/mvme147hw.h19
-rw-r--r--arch/m68k/include/asm/mvme16xhw.h18
-rw-r--r--arch/m68k/mvme147/config.c55
-rw-r--r--arch/m68k/mvme16x/Makefile2
-rw-r--r--arch/m68k/mvme16x/config.c57
-rw-r--r--arch/m68k/mvme16x/rtc.c165
-rw-r--r--arch/sparc/kernel/time_32.c1
-rw-r--r--arch/sparc/kernel/time_64.c1
-rw-r--r--drivers/rtc/Kconfig33
-rw-r--r--drivers/rtc/Makefile5
-rw-r--r--drivers/rtc/interface.c7
-rw-r--r--drivers/rtc/rtc-88pm80x.c2
-rw-r--r--drivers/rtc/rtc-88pm860x.c2
-rw-r--r--drivers/rtc/rtc-88pm886.c97
-rw-r--r--drivers/rtc/rtc-ab-eoz9.c11
-rw-r--r--drivers/rtc/rtc-ab8500.c2
-rw-r--r--drivers/rtc/rtc-abx80x.c2
-rw-r--r--drivers/rtc/rtc-ac100.c2
-rw-r--r--drivers/rtc/rtc-amlogic-a4.c465
-rw-r--r--drivers/rtc/rtc-asm9260.c2
-rw-r--r--drivers/rtc/rtc-at91rm9200.c2
-rw-r--r--drivers/rtc/rtc-at91sam9.c2
-rw-r--r--drivers/rtc/rtc-brcmstb-waketimer.c3
-rw-r--r--drivers/rtc/rtc-cadence.c2
-rw-r--r--drivers/rtc/rtc-cmos.c33
-rw-r--r--drivers/rtc/rtc-cros-ec.c2
-rw-r--r--drivers/rtc/rtc-ds1685.c2
-rw-r--r--drivers/rtc/rtc-ftrtc010.c2
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c2
-rw-r--r--drivers/rtc/rtc-imxdi.c2
-rw-r--r--drivers/rtc/rtc-isl12022.c269
-rw-r--r--drivers/rtc/rtc-loongson.c2
-rw-r--r--drivers/rtc/rtc-lpc24xx.c2
-rw-r--r--drivers/rtc/rtc-m48t59.c26
-rw-r--r--drivers/rtc/rtc-max77686.c2
-rw-r--r--drivers/rtc/rtc-mc13xxx.c2
-rw-r--r--drivers/rtc/rtc-mc146818-lib.c6
-rw-r--r--drivers/rtc/rtc-mpc5121.c2
-rw-r--r--drivers/rtc/rtc-mpfs.c2
-rw-r--r--drivers/rtc/rtc-mt6397.c29
-rw-r--r--drivers/rtc/rtc-mt7622.c2
-rw-r--r--drivers/rtc/rtc-mv.c2
-rw-r--r--drivers/rtc/rtc-mxc_v2.c2
-rw-r--r--drivers/rtc/rtc-nxp-bbnsm.c20
-rw-r--r--drivers/rtc/rtc-omap.c2
-rw-r--r--drivers/rtc/rtc-palmas.c2
-rw-r--r--drivers/rtc/rtc-pcf50633.c2
-rw-r--r--drivers/rtc/rtc-pcf8563.c212
-rw-r--r--drivers/rtc/rtc-pic32.c2
-rw-r--r--drivers/rtc/rtc-pm8xxx.c2
-rw-r--r--drivers/rtc/rtc-pxa.c2
-rw-r--r--drivers/rtc/rtc-rc5t583.c2
-rw-r--r--drivers/rtc/rtc-renesas-rtca3.c900
-rw-r--r--drivers/rtc/rtc-rtd119x.c2
-rw-r--r--drivers/rtc/rtc-rv3028.c6
-rw-r--r--drivers/rtc/rtc-rzn1.c92
-rw-r--r--drivers/rtc/rtc-s3c.c2
-rw-r--r--drivers/rtc/rtc-sa1100.c2
-rw-r--r--drivers/rtc/rtc-sh.c2
-rw-r--r--drivers/rtc/rtc-spear.c2
-rw-r--r--drivers/rtc/rtc-st-lpc.c5
-rw-r--r--drivers/rtc/rtc-stm32.c2
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c2
-rw-r--r--drivers/rtc/rtc-sunplus.c2
-rw-r--r--drivers/rtc/rtc-tegra.c2
-rw-r--r--drivers/rtc/rtc-tps6586x.c2
-rw-r--r--drivers/rtc/rtc-twl.c2
-rw-r--r--drivers/rtc/rtc-vt8500.c2
-rw-r--r--drivers/rtc/rtc-wm8350.c2
-rw-r--r--drivers/rtc/rtc-xgene.c2
-rw-r--r--drivers/rtc/rtc-zynqmp.c2
-rw-r--r--include/linux/mfd/88pm886.h9
-rw-r--r--include/linux/rtc/m48t59.h3
81 files changed, 2221 insertions, 599 deletions
diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
index 4531eec568a6..9df5cdb6f63f 100644
--- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
@@ -30,7 +30,9 @@ properties:
- const: allwinner,sun50i-a64-rtc
- const: allwinner,sun8i-h3-rtc
- items:
- - const: allwinner,sun20i-d1-rtc
+ - enum:
+ - allwinner,sun20i-d1-rtc
+ - allwinner,sun55i-a523-rtc
- const: allwinner,sun50i-r329-rtc
reg:
diff --git a/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml b/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
new file mode 100644
index 000000000000..5d3ac737abcb
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/amlogic,a4-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic A4 and A5 RTC
+
+maintainers:
+ - Yiting Deng <yiting.deng@amlogic.com>
+ - Xianwei Zhao <xianwei.zhao@amlogic.com>
+
+allOf:
+ - $ref: rtc.yaml#
+
+properties:
+ compatible:
+ enum:
+ - amlogic,a4-rtc
+ - amlogic,a5-rtc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: RTC clock source, available 24M or 32K crystal
+ oscillator source. when using 24M, need to divide 24M into 32K.
+ - description: RTC module accesses the clock of the apb bus.
+
+ clock-names:
+ items:
+ - const: osc
+ - const: sys
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ apb {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ rtc@8e600 {
+ compatible = "amlogic,a4-rtc";
+ reg = <0x0 0x8e600 0x0 0x38>;
+ clocks = <&xtal_32k>, <&clkc_periphs 1>;
+ clock-names = "osc", "sys";
+ interrupts = <GIC_SPI 131 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/rtc/microchip,mfps-rtc.yaml b/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml
index 7742465b9383..a3e60d9f8399 100644
--- a/Documentation/devicetree/bindings/rtc/microchip,mfps-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: http://devicetree.org/schemas/rtc/microchip,mfps-rtc.yaml#
+$id: http://devicetree.org/schemas/rtc/microchip,mpfs-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
@@ -12,12 +12,14 @@ allOf:
maintainers:
- Daire McNamara <daire.mcnamara@microchip.com>
- - Lewis Hanly <lewis.hanly@microchip.com>
properties:
compatible:
- enum:
- - microchip,mpfs-rtc
+ oneOf:
+ - items:
+ - const: microchip,pic64gx-rtc
+ - const: microchip,mpfs-rtc
+ - const: microchip,mpfs-rtc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml b/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
new file mode 100644
index 000000000000..e70eeb66aa64
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/renesas,rz-rtca3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RTCA-3 Real Time Clock
+
+maintainers:
+ - Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+
+allOf:
+ - $ref: rtc.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - renesas,r9a08g045-rtca3 # RZ/G3S
+ - const: renesas,rz-rtca3
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ items:
+ - description: Alarm interrupt
+ - description: Periodic interrupt
+ - description: Carry interrupt
+
+ interrupt-names:
+ items:
+ - const: alarm
+ - const: period
+ - const: carry
+
+ clocks:
+ items:
+ - description: RTC bus clock
+ - description: RTC counter clock
+
+ clock-names:
+ items:
+ - const: bus
+ - const: counter
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ items:
+ - description: VBATTB module reset
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - clocks
+ - clock-names
+ - power-domains
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/r9a08g045-cpg.h>
+ #include <dt-bindings/clock/renesas,r9a08g045-vbattb.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ rtc@1004ec00 {
+ compatible = "renesas,r9a08g045-rtca3", "renesas,rz-rtca3";
+ reg = <0x1004ec00 0x400>;
+ interrupts = <GIC_SPI 315 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 316 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "alarm", "period", "carry";
+ clocks = <&cpg CPG_MOD R9A08G045_VBAT_BCLK>, <&vbattclk VBATTB_VBATTCLK>;
+ clock-names = "bus", "counter";
+ power-domains = <&cpg>;
+ resets = <&cpg R9A08G045_VBAT_BRESETN>;
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 9417ce74905e..3cf2858145bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1218,6 +1218,14 @@ F: Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml
F: drivers/perf/amlogic/
F: include/soc/amlogic/
+AMLOGIC RTC DRIVER
+M: Yiting Deng <yiting.deng@amlogic.com>
+M: Xianwei Zhao <xianwei.zhao@amlogic.com>
+L: linux-amlogic@lists.infradead.org
+S: Maintained
+F: Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
+F: drivers/rtc/rtc-amlogic-a4.c
+
AMPHENOL CHIPCAP 2 HUMIDITY-TEMPERATURE IIO DRIVER
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
L: linux-hwmon@vger.kernel.org
@@ -13794,6 +13802,7 @@ F: Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml
F: drivers/input/misc/88pm886-onkey.c
F: drivers/mfd/88pm886.c
F: drivers/regulator/88pm886-regulator.c
+F: drivers/rtc/rtc-88pm886.c
F: include/linux/mfd/88pm886.h
MARVELL ARMADA 3700 PHY DRIVERS
@@ -19915,6 +19924,14 @@ S: Supported
F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml
F: drivers/counter/rz-mtu3-cnt.c
+RENESAS RTCA-3 RTC DRIVER
+M: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+L: linux-rtc@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml
+F: drivers/rtc/rtc-renesas-rtca3.c
+
RENESAS RZ/N1 A5PSW SWITCH DRIVER
M: Clément Léger <clement.leger@bootlin.com>
L: linux-renesas-soc@vger.kernel.org
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index f8edc9082724..20d877cb4e30 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -503,6 +503,7 @@ CONFIG_UHID=m
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set
+CONFIG_RTC_DRV_M48T59=m
CONFIG_RTC_DRV_MSM6242=m
CONFIG_RTC_DRV_RP5C01=m
CONFIG_RTC_DRV_GENERIC=m
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index 71fc71bb660e..5e1c8d0d3da5 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -391,6 +391,7 @@ CONFIG_UHID=m
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set
+CONFIG_RTC_DRV_M48T59=y
CONFIG_RTC_DRV_GENERIC=m
# CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index 41072e68028e..5d1409e6a137 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -392,6 +392,7 @@ CONFIG_UHID=m
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
# CONFIG_RTC_NVMEM is not set
+CONFIG_RTC_DRV_M48T59=y
CONFIG_RTC_DRV_GENERIC=m
# CONFIG_VIRTIO_MENU is not set
# CONFIG_VHOST_MENU is not set
diff --git a/arch/m68k/include/asm/mvme147hw.h b/arch/m68k/include/asm/mvme147hw.h
index dbf88059e47a..6ad93bac06f9 100644
--- a/arch/m68k/include/asm/mvme147hw.h
+++ b/arch/m68k/include/asm/mvme147hw.h
@@ -4,24 +4,7 @@
#include <asm/irq.h>
-typedef struct {
- unsigned char
- ctrl,
- bcd_sec,
- bcd_min,
- bcd_hr,
- bcd_dow,
- bcd_dom,
- bcd_mth,
- bcd_year;
-} MK48T02;
-
-#define RTC_WRITE 0x80
-#define RTC_READ 0x40
-#define RTC_STOP 0x20
-
-#define m147_rtc ((MK48T02 * volatile)0xfffe07f8)
-
+#define MVME147_RTC_BASE 0xfffe0000
struct pcc_regs {
volatile u_long dma_tadr;
diff --git a/arch/m68k/include/asm/mvme16xhw.h b/arch/m68k/include/asm/mvme16xhw.h
index cc7f5ae1220f..ff1126a51fbe 100644
--- a/arch/m68k/include/asm/mvme16xhw.h
+++ b/arch/m68k/include/asm/mvme16xhw.h
@@ -24,23 +24,7 @@ typedef struct {
#define mvmelp ((*(volatile MVMElpPtr)(MVME_LPR_BASE)))
-typedef struct {
- unsigned char
- ctrl,
- bcd_sec,
- bcd_min,
- bcd_hr,
- bcd_dow,
- bcd_dom,
- bcd_mth,
- bcd_year;
-} MK48T08_t, *MK48T08ptr_t;
-
-#define RTC_WRITE 0x80
-#define RTC_READ 0x40
-#define RTC_STOP 0x20
-
-#define MVME_RTC_BASE 0xfffc1ff8
+#define MVME_RTC_BASE 0xfffc0000
#define MVME_I596_BASE 0xfff46000
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 824c42a302c6..3054d3857efa 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -19,8 +19,9 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/major.h>
-#include <linux/rtc.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/rtc/m48t59.h>
#include <asm/bootinfo.h>
#include <asm/bootinfo-vme.h>
@@ -36,13 +37,9 @@
static void mvme147_get_model(char *model);
static void __init mvme147_sched_init(void);
-extern int mvme147_hwclk (int, struct rtc_time *);
extern void mvme147_reset (void);
-static int bcd2int (unsigned char b);
-
-
int __init mvme147_parse_bootinfo(const struct bi_record *bi)
{
uint16_t tag = be16_to_cpu(bi->tag);
@@ -80,7 +77,6 @@ void __init config_mvme147(void)
{
mach_sched_init = mvme147_sched_init;
mach_init_IRQ = mvme147_init_IRQ;
- mach_hwclk = mvme147_hwclk;
mach_reset = mvme147_reset;
mach_get_model = mvme147_get_model;
@@ -89,6 +85,28 @@ void __init config_mvme147(void)
vme_brdtype = VME_TYPE_MVME147;
}
+static struct resource m48t59_rsrc[] = {
+ DEFINE_RES_MEM(MVME147_RTC_BASE, 0x800),
+};
+
+static struct m48t59_plat_data m48t59_data = {
+ .type = M48T59RTC_TYPE_M48T02,
+ .yy_offset = 70,
+};
+
+static int __init mvme147_platform_init(void)
+{
+ if (!MACH_IS_MVME147)
+ return 0;
+
+ platform_device_register_resndata(NULL, "rtc-m48t59", -1,
+ m48t59_rsrc, ARRAY_SIZE(m48t59_rsrc),
+ &m48t59_data, sizeof(m48t59_data));
+ return 0;
+}
+
+arch_initcall(mvme147_platform_init);
+
static u64 mvme147_read_clk(struct clocksource *cs);
static struct clocksource mvme147_clk = {
@@ -162,31 +180,6 @@ static u64 mvme147_read_clk(struct clocksource *cs)
return ticks;
}
-static int bcd2int (unsigned char b)
-{
- return ((b>>4)*10 + (b&15));
-}
-
-int mvme147_hwclk(int op, struct rtc_time *t)
-{
- if (!op) {
- m147_rtc->ctrl = RTC_READ;
- t->tm_year = bcd2int (m147_rtc->bcd_year);
- t->tm_mon = bcd2int(m147_rtc->bcd_mth) - 1;
- t->tm_mday = bcd2int (m147_rtc->bcd_dom);
- t->tm_hour = bcd2int (m147_rtc->bcd_hr);
- t->tm_min = bcd2int (m147_rtc->bcd_min);
- t->tm_sec = bcd2int (m147_rtc->bcd_sec);
- m147_rtc->ctrl = 0;
- if (t->tm_year < 70)
- t->tm_year += 100;
- } else {
- /* FIXME Setting the time is not yet supported */
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
static void scc_delay(void)
{
__asm__ __volatile__ ("nop; nop;");
diff --git a/arch/m68k/mvme16x/Makefile b/arch/m68k/mvme16x/Makefile
index a8a368c2cbea..02f9e4ad8209 100644
--- a/arch/m68k/mvme16x/Makefile
+++ b/arch/m68k/mvme16x/Makefile
@@ -3,4 +3,4 @@
# Makefile for Linux arch/m68k/mvme16x source directory
#
-obj-y := config.o rtc.o
+obj-y := config.o
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index d1fbd1704d65..99768fe8da73 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -21,9 +21,10 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/major.h>
-#include <linux/rtc.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc/m48t59.h>
#include <asm/bootinfo.h>
#include <asm/bootinfo-vme.h>
@@ -39,16 +40,10 @@
extern t_bdid mvme_bdid;
-static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
-
static void mvme16x_get_model(char *model);
extern void mvme16x_sched_init(void);
-extern int mvme16x_hwclk (int, struct rtc_time *);
extern void mvme16x_reset (void);
-int bcd2int (unsigned char b);
-
-
unsigned short mvme16x_config;
EXPORT_SYMBOL(mvme16x_config);
@@ -268,7 +263,6 @@ void __init config_mvme16x(void)
mach_sched_init = mvme16x_sched_init;
mach_init_IRQ = mvme16x_init_IRQ;
- mach_hwclk = mvme16x_hwclk;
mach_reset = mvme16x_reset;
mach_get_model = mvme16x_get_model;
mach_get_hardware_list = mvme16x_get_hardware_list;
@@ -312,6 +306,28 @@ void __init config_mvme16x(void)
}
}
+static struct resource m48t59_rsrc[] = {
+ DEFINE_RES_MEM(MVME_RTC_BASE, 0x2000),
+};
+
+static struct m48t59_plat_data m48t59_data = {
+ .type = M48T59RTC_TYPE_M48T08,
+ .yy_offset = 70,
+};
+
+static int __init mvme16x_platform_init(void)
+{
+ if (!MACH_IS_MVME16x)
+ return 0;
+
+ platform_device_register_resndata(NULL, "rtc-m48t59", -1,
+ m48t59_rsrc, ARRAY_SIZE(m48t59_rsrc),
+ &m48t59_data, sizeof(m48t59_data));
+ return 0;
+}
+
+arch_initcall(mvme16x_platform_init);
+
static irqreturn_t mvme16x_abort_int (int irq, void *dev_id)
{
unsigned long *new = (unsigned long *)vectors;
@@ -426,28 +442,3 @@ static u64 mvme16x_read_clk(struct clocksource *cs)
return ticks;
}
-
-int bcd2int (unsigned char b)
-{
- return ((b>>4)*10 + (b&15));
-}
-
-int mvme16x_hwclk(int op, struct rtc_time *t)
-{
- if (!op) {
- rtc->ctrl = RTC_READ;
- t->tm_year = bcd2int (rtc->bcd_year);
- t->tm_mon = bcd2int(rtc->bcd_mth) - 1;
- t->tm_mday = bcd2int (rtc->bcd_dom);
- t->tm_hour = bcd2int (rtc->bcd_hr);
- t->tm_min = bcd2int (rtc->bcd_min);
- t->tm_sec = bcd2int (rtc->bcd_sec);
- rtc->ctrl = 0;
- if (t->tm_year < 70)
- t->tm_year += 100;
- } else {
- /* FIXME Setting the time is not yet supported */
- return -EOPNOTSUPP;
- }
- return 0;
-}
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
deleted file mode 100644
index ccbaae1125e6..000000000000
--- a/arch/m68k/mvme16x/rtc.c
+++ /dev/null
@@ -1,165 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Real Time Clock interface for Linux on the MVME16x
- *
- * Based on the PC driver by Paul Gortmaker.
- */
-
-#define RTC_VERSION "1.00"
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/capability.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/rtc.h> /* For struct rtc_time and ioctls, etc */
-#include <linux/bcd.h>
-#include <asm/mvme16xhw.h>
-
-#include <asm/io.h>
-#include <linux/uaccess.h>
-#include <asm/setup.h>
-
-/*
- * We sponge a minor off of the misc major. No need slurping
- * up another valuable major dev number for this. If you add
- * an ioctl, make sure you don't conflict with SPARC's RTC
- * ioctls.
- */
-
-static const unsigned char days_in_mo[] =
-{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-static atomic_t rtc_ready = ATOMIC_INIT(1);
-
-static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- volatile MK48T08ptr_t rtc = (MK48T08ptr_t)MVME_RTC_BASE;
- unsigned long flags;
- struct rtc_time wtime;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case RTC_RD_TIME: /* Read the time/date from RTC */
- {
- local_irq_save(flags);
- /* Ensure clock and real-time-mode-register are accessible */
- rtc->ctrl = RTC_READ;
- memset(&wtime, 0, sizeof(struct rtc_time));
- wtime.tm_sec = bcd2bin(rtc->bcd_sec);
- wtime.tm_min = bcd2bin(rtc->bcd_min);
- wtime.tm_hour = bcd2bin(rtc->bcd_hr);
- wtime.tm_mday = bcd2bin(rtc->bcd_dom);
- wtime.tm_mon = bcd2bin(rtc->bcd_mth)-1;
- wtime.tm_year = bcd2bin(rtc->bcd_year);
- if (wtime.tm_year < 70)
- wtime.tm_year += 100;
- wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
- rtc->ctrl = 0;
- local_irq_restore(flags);
- return copy_to_user(argp, &wtime, sizeof wtime) ?
- -EFAULT : 0;
- }
- case RTC_SET_TIME: /* Set the RTC */
- {
- struct rtc_time rtc_tm;
- unsigned char mon, day, hrs, min, sec, leap_yr;
- unsigned int yrs;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time)))
- return -EFAULT;
-
- yrs = rtc_tm.tm_year;
- if (yrs < 1900)
- yrs += 1900;
- mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
- day = rtc_tm.tm_mday;
- hrs = rtc_tm.tm_hour;
- min = rtc_tm.tm_min;
- sec = rtc_tm.tm_sec;
-
- leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
-
- if ((mon > 12) || (day == 0))
- return -EINVAL;
-
- if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
- return -EINVAL;
-
- if ((hrs >= 24) || (min >= 60) || (sec >= 60))
- return -EINVAL;
-
- if (yrs >= 2070)
- return -EINVAL;
-
- local_irq_save(flags);
- rtc->ctrl = RTC_WRITE;
-
- rtc->bcd_sec = bin2bcd(sec);
- rtc->bcd_min = bin2bcd(min);
- rtc->bcd_hr = bin2bcd(hrs);
- rtc->bcd_dom = bin2bcd(day);
- rtc->bcd_mth = bin2bcd(mon);
- rtc->bcd_year = bin2bcd(yrs%100);
-
- rtc->ctrl = 0;
- local_irq_restore(flags);
- return 0;
- }
- default:
- return -EINVAL;
- }
-}
-
-/*
- * We enforce only one user at a time here with the open/close.
- */
-static int rtc_open(struct inode *inode, struct file *file)
-{
- if( !atomic_dec_and_test(&rtc_ready) )
- {
- atomic_inc( &rtc_ready );
- return -EBUSY;
- }
- return 0;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
- atomic_inc( &rtc_ready );
- return 0;
-}
-
-/*
- * The various file operations we support.
- */
-
-static const struct file_operations rtc_fops = {
- .unlocked_ioctl = rtc_ioctl,
- .open = rtc_open,
- .release = rtc_release,
- .llseek = noop_llseek,
-};
-
-static struct miscdevice rtc_dev=
-{
- .minor = RTC_MINOR,
- .name = "rtc",
- .fops = &rtc_fops
-};
-
-static int __init rtc_MK48T08_init(void)
-{
- if (!MACH_IS_MVME16x)
- return -ENODEV;
-
- pr_info("MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
- return misc_register(&rtc_dev);
-}
-device_initcall(rtc_MK48T08_init);
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index 08bbdc458596..578fd0d49f30 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -255,6 +255,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
static struct m48t59_plat_data m48t59_data = {
.read_byte = mostek_read_byte,
.write_byte = mostek_write_byte,
+ .yy_offset = 68,
};
/* resource is set at runtime */
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
index 60f1c8cc5363..b32f27f929d1 100644
--- a/arch/sparc/kernel/time_64.c
+++ b/arch/sparc/kernel/time_64.c
@@ -544,6 +544,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
static struct m48t59_plat_data m48t59_data = {
.read_byte = mostek_read_byte,
.write_byte = mostek_write_byte,
+ .yy_offset = 68,
};
static struct platform_device m48t59_rtc = {
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 66eb1122248b..a60bcc791a48 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -182,6 +182,16 @@ config RTC_DRV_88PM80X
This driver can also be built as a module. If so, the module
will be called rtc-88pm80x.
+config RTC_DRV_88PM886
+ tristate "Marvell 88PM886 RTC driver"
+ depends on MFD_88PM886_PMIC
+ help
+ If you say yes here you will get support for the RTC function in the
+ Marvell 88PM886 chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-88pm886.
+
config RTC_DRV_ABB5ZES3
select REGMAP_I2C
tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
@@ -496,6 +506,7 @@ config RTC_DRV_PCF85363
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
+ select REGMAP_I2C
help
If you say yes here you get support for the
Philips PCF8563 RTC chip. The Epson RTC8564
@@ -2005,6 +2016,16 @@ config RTC_DRV_MA35D1
This driver can also be built as a module, if so, the module
will be called "rtc-ma35d1".
+config RTC_DRV_RENESAS_RTCA3
+ tristate "Renesas RTCA-3 RTC"
+ depends on ARCH_RENESAS
+ help
+ If you say yes here you get support for the Renesas RTCA-3 RTC
+ available on the Renesas RZ/G3S SoC.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-rtca3".
+
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME
@@ -2070,4 +2091,16 @@ config RTC_DRV_SSD202D
This driver can also be built as a module, if so, the module
will be called "rtc-ssd20xd".
+config RTC_DRV_AMLOGIC_A4
+ tristate "Amlogic RTC"
+ depends on ARCH_MESON || COMPILE_TEST
+ select REGMAP_MMIO
+ default y
+ help
+ If you say yes here you get support for the RTC block on the
+ Amlogic A113L2(A4) and A113X2(A5) SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called "rtc-amlogic-a4".
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f62340ecc534..489b4ab07068 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -21,11 +21,13 @@ obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o
obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
+obj-$(CONFIG_RTC_DRV_88PM886) += rtc-88pm886.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABEOZ9) += rtc-ab-eoz9.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
+obj-$(CONFIG_RTC_DRV_AMLOGIC_A4) += rtc-amlogic-a4.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
@@ -158,13 +160,14 @@ obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8111) += rtc-rx8111.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o
+obj-$(CONFIG_RTC_DRV_RENESAS_RTCA3) += rtc-renesas-rtca3.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o
-obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
+obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index cca650b2e0b9..aaf76406cd7d 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -904,13 +904,18 @@ void rtc_timer_do_work(struct work_struct *work)
struct timerqueue_node *next;
ktime_t now;
struct rtc_time tm;
+ int err;
struct rtc_device *rtc =
container_of(work, struct rtc_device, irqwork);
mutex_lock(&rtc->ops_lock);
again:
- __rtc_read_time(rtc, &tm);
+ err = __rtc_read_time(rtc, &tm);
+ if (err) {
+ mutex_unlock(&rtc->ops_lock);
+ return;
+ }
now = rtc_tm_to_ktime(tm);
while ((next = timerqueue_getnext(&rtc->timerqueue))) {
if (next->expires > now)
diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c
index f40cc06b0979..5c39cf252392 100644
--- a/drivers/rtc/rtc-88pm80x.c
+++ b/drivers/rtc/rtc-88pm80x.c
@@ -329,7 +329,7 @@ static struct platform_driver pm80x_rtc_driver = {
.pm = &pm80x_rtc_pm_ops,
},
.probe = pm80x_rtc_probe,
- .remove_new = pm80x_rtc_remove,
+ .remove = pm80x_rtc_remove,
};
module_platform_driver(pm80x_rtc_driver);
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index 0f124ed5b3e5..814230d61842 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -371,7 +371,7 @@ static struct platform_driver pm860x_rtc_driver = {
.pm = &pm860x_rtc_pm_ops,
},
.probe = pm860x_rtc_probe,
- .remove_new = pm860x_rtc_remove,
+ .remove = pm860x_rtc_remove,
};
module_platform_driver(pm860x_rtc_driver);
diff --git a/drivers/rtc/rtc-88pm886.c b/drivers/rtc/rtc-88pm886.c
new file mode 100644
index 000000000000..57e9b0a66eed
--- /dev/null
+++ b/drivers/rtc/rtc-88pm886.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/limits.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <linux/mfd/88pm886.h>
+
+/*
+ * Time is calculated as the sum of a 32-bit read-only advancing counter and a
+ * writeable constant offset stored in the chip's spare registers.
+ */
+
+static int pm886_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u32 time;
+ u32 buf;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, PM886_REG_RTC_SPARE1, &buf, 4);
+ if (ret)
+ return ret;
+ time = buf;
+
+ ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4);
+ if (ret)
+ return ret;
+ time += buf;
+
+ rtc_time64_to_tm(time, tm);
+
+ return 0;
+}
+
+static int pm886_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u32 buf;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4);
+ if (ret)
+ return ret;
+
+ buf = rtc_tm_to_time64(tm) - buf;
+
+ return regmap_bulk_write(regmap, PM886_REG_RTC_SPARE1, &buf, 4);
+}
+
+static const struct rtc_class_ops pm886_rtc_ops = {
+ .read_time = pm886_rtc_read_time,
+ .set_time = pm886_rtc_set_time,
+};
+
+static int pm886_rtc_probe(struct platform_device *pdev)
+{
+ struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct rtc_device *rtc;
+ int ret;
+
+ platform_set_drvdata(pdev, chip->regmap);
+
+ rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc))
+ return dev_err_probe(dev, PTR_ERR(rtc),
+ "Failed to allocate RTC device\n");
+
+ rtc->ops = &pm886_rtc_ops;
+ rtc->range_max = U32_MAX;
+
+ ret = devm_rtc_register_device(rtc);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register RTC device\n");
+
+ return 0;
+}
+
+static const struct platform_device_id pm886_rtc_id_table[] = {
+ { "88pm886-rtc", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, pm886_rtc_id_table);
+
+static struct platform_driver pm886_rtc_driver = {
+ .driver = {
+ .name = "88pm886-rtc",
+ },
+ .probe = pm886_rtc_probe,
+ .id_table = pm886_rtc_id_table,
+};
+module_platform_driver(pm886_rtc_driver);
+
+MODULE_DESCRIPTION("Marvell 88PM886 RTC driver");
+MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c
index 02f7d0711287..d2b60487d462 100644
--- a/drivers/rtc/rtc-ab-eoz9.c
+++ b/drivers/rtc/rtc-ab-eoz9.c
@@ -64,7 +64,7 @@
#define ABEOZ9_BIT_ALARM_MIN GENMASK(6, 0)
#define ABEOZ9_REG_ALARM_HOURS 0x12
#define ABEOZ9_BIT_ALARM_HOURS_PM BIT(5)
-#define ABEOZ9_BIT_ALARM_HOURS GENMASK(4, 0)
+#define ABEOZ9_BIT_ALARM_HOURS GENMASK(5, 0)
#define ABEOZ9_REG_ALARM_DAYS 0x13
#define ABEOZ9_BIT_ALARM_DAYS GENMASK(5, 0)
#define ABEOZ9_REG_ALARM_WEEKDAYS 0x14
@@ -231,8 +231,6 @@ static int abeoz9_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
alarm->time.tm_sec = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_SEC, regs[0]));
alarm->time.tm_min = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_MIN, regs[1]));
alarm->time.tm_hour = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_HOURS, regs[2]));
- if (FIELD_GET(ABEOZ9_BIT_ALARM_HOURS_PM, regs[2]))
- alarm->time.tm_hour += 12;
alarm->time.tm_mday = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_DAYS, regs[3]));
@@ -396,13 +394,6 @@ static int abeoz9z3_temp_read(struct device *dev,
if (ret < 0)
return ret;
- if ((val & ABEOZ9_REG_CTRL_STATUS_V1F) ||
- (val & ABEOZ9_REG_CTRL_STATUS_V2F)) {
- dev_err(dev,
- "thermometer might be disabled due to low voltage\n");
- return -EINVAL;
- }
-
switch (attr) {
case hwmon_temp_input:
ret = regmap_read(regmap, ABEOZ9_REG_REG_TEMP, &val);
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index 75bb2ac9005c..2dcda96f4a8e 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -403,7 +403,7 @@ static struct platform_driver ab8500_rtc_driver = {
.name = "ab8500-rtc",
},
.probe = ab8500_rtc_probe,
- .remove_new = ab8500_rtc_remove,
+ .remove = ab8500_rtc_remove,
.id_table = ab85xx_rtc_ids,
};
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 1298962402ff..3fee27914ba8 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -39,7 +39,7 @@
#define ABX8XX_REG_STATUS 0x0f
#define ABX8XX_STATUS_AF BIT(2)
#define ABX8XX_STATUS_BLF BIT(4)
-#define ABX8XX_STATUS_WDT BIT(6)
+#define ABX8XX_STATUS_WDT BIT(5)
#define ABX8XX_REG_CTRL1 0x10
#define ABX8XX_CTRL_WRITE BIT(0)
diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c
index fa642bba3cee..33626311fa78 100644
--- a/drivers/rtc/rtc-ac100.c
+++ b/drivers/rtc/rtc-ac100.c
@@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, ac100_rtc_match);
static struct platform_driver ac100_rtc_driver = {
.probe = ac100_rtc_probe,
- .remove_new = ac100_rtc_remove,
+ .remove = ac100_rtc_remove,
.driver = {
.name = "ac100-rtc",
.of_match_table = of_match_ptr(ac100_rtc_match),
diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c
new file mode 100644
index 000000000000..2278b4c98a71
--- /dev/null
+++ b/drivers/rtc/rtc-amlogic-a4.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2024 Amlogic, Inc. All rights reserved
+ * Author: Yiting Deng <yiting.deng@amlogic.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/time64.h>
+
+/* rtc oscillator rate */
+#define OSC_32K 32768
+#define OSC_24M 24000000
+
+#define RTC_CTRL (0x0 << 2) /* Control RTC */
+#define RTC_ALRM0_EN BIT(0)
+#define RTC_OSC_SEL BIT(8)
+#define RTC_ENABLE BIT(12)
+
+#define RTC_COUNTER_REG (0x1 << 2) /* Program RTC counter initial value */
+
+#define RTC_ALARM0_REG (0x2 << 2) /* Program RTC alarm0 value */
+
+#define RTC_SEC_ADJUST_REG (0x6 << 2) /* Control second-based timing adjustment */
+#define RTC_MATCH_COUNTER GENMASK(18, 0)
+#define RTC_SEC_ADJUST_CTRL GENMASK(20, 19)
+#define RTC_ADJ_VALID BIT(23)
+
+#define RTC_INT_MASK (0x8 << 2) /* RTC interrupt mask */
+#define RTC_ALRM0_IRQ_MSK BIT(0)
+
+#define RTC_INT_CLR (0x9 << 2) /* Clear RTC interrupt */
+#define RTC_ALRM0_IRQ_CLR BIT(0)
+
+#define RTC_OSCIN_CTRL0 (0xa << 2) /* Control RTC clk from 24M */
+#define RTC_OSCIN_CTRL1 (0xb << 2) /* Control RTC clk from 24M */
+#define RTC_OSCIN_IN_EN BIT(31)
+#define RTC_OSCIN_OUT_CFG GENMASK(29, 28)
+#define RTC_OSCIN_OUT_N0M0 GENMASK(11, 0)
+#define RTC_OSCIN_OUT_N1M1 GENMASK(23, 12)
+
+#define RTC_INT_STATUS (0xc << 2) /* RTC interrupt status */
+#define RTC_ALRM0_IRQ_STATUS BIT(0)
+
+#define RTC_REAL_TIME (0xd << 2) /* RTC time value */
+
+#define RTC_OSCIN_OUT_32K_N0 0x2dc
+#define RTC_OSCIN_OUT_32K_N1 0x2db
+#define RTC_OSCIN_OUT_32K_M0 0x1
+#define RTC_OSCIN_OUT_32K_M1 0x2
+
+#define RTC_SWALLOW_SECOND 0x2
+#define RTC_INSERT_SECOND 0x3
+
+struct aml_rtc_config {
+ bool gray_stored;
+};
+
+struct aml_rtc_data {
+ struct regmap *map;
+ struct rtc_device *rtc_dev;
+ int irq;
+ struct clk *rtc_clk;
+ struct clk *sys_clk;
+ int rtc_enabled;
+ const struct aml_rtc_config *config;
+};
+
+static const struct regmap_config aml_rtc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = RTC_REAL_TIME,
+};
+
+static inline u32 gray_to_binary(u32 gray)
+{
+ u32 bcd = gray;
+ int size = sizeof(bcd) * 8;
+ int i;
+
+ for (i = 0; (1 << i) < size; i++)
+ bcd ^= bcd >> (1 << i);
+
+ return bcd;
+}
+
+static inline u32 binary_to_gray(u32 bcd)
+{
+ return bcd ^ (bcd >> 1);
+}
+
+static int aml_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 time_sec;
+
+ /* if RTC disabled, read time failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_read(rtc->map, RTC_REAL_TIME, &time_sec);
+ if (rtc->config->gray_stored)
+ time_sec = gray_to_binary(time_sec);
+ rtc_time64_to_tm(time_sec, tm);
+ dev_dbg(dev, "%s: read time = %us\n", __func__, time_sec);
+
+ return 0;
+}
+
+static int aml_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 time_sec;
+
+ /* if RTC disabled, first enable it */
+ if (!rtc->rtc_enabled) {
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_ENABLE, RTC_ENABLE);
+ usleep_range(100, 200);
+ rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE);
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+ }
+
+ time_sec = rtc_tm_to_time64(tm);
+ if (rtc->config->gray_stored)
+ time_sec = binary_to_gray(time_sec);
+ regmap_write(rtc->map, RTC_COUNTER_REG, time_sec);
+ dev_dbg(dev, "%s: set time = %us\n", __func__, time_sec);
+
+ return 0;
+}
+
+static int aml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ time64_t alarm_sec;
+
+ /* if RTC disabled, set alarm failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_update_bits(rtc->map, RTC_CTRL,
+ RTC_ALRM0_EN, RTC_ALRM0_EN);
+ regmap_update_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, 0);
+
+ alarm_sec = rtc_tm_to_time64(&alarm->time);
+ if (rtc->config->gray_stored)
+ alarm_sec = binary_to_gray(alarm_sec);
+ regmap_write(rtc->map, RTC_ALARM0_REG, alarm_sec);
+
+ dev_dbg(dev, "%s: alarm->enabled=%d alarm_set=%llds\n", __func__,
+ alarm->enabled, alarm_sec);
+
+ return 0;
+}
+
+static int aml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 alarm_sec;
+ int alarm_enable;
+ int alarm_mask;
+
+ /* if RTC disabled, read alarm failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_read(rtc->map, RTC_ALARM0_REG, &alarm_sec);
+ if (rtc->config->gray_stored)
+ alarm_sec = gray_to_binary(alarm_sec);
+ rtc_time64_to_tm(alarm_sec, &alarm->time);
+
+ alarm_enable = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN);
+ alarm_mask = regmap_test_bits(rtc->map, RTC_INT_MASK, RTC_ALRM0_IRQ_MSK);
+ alarm->enabled = (alarm_enable && !alarm_mask) ? 1 : 0;
+ dev_dbg(dev, "%s: alarm->enabled=%d alarm=%us\n", __func__,
+ alarm->enabled, alarm_sec);
+
+ return 0;
+}
+
+static int aml_rtc_read_offset(struct device *dev, long *offset)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 reg_val;
+ long val;
+ int sign, match_counter, enable;
+
+ /* if RTC disabled, read offset failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_read(rtc->map, RTC_SEC_ADJUST_REG, &reg_val);
+ enable = FIELD_GET(RTC_ADJ_VALID, reg_val);
+ if (!enable) {
+ val = 0;
+ } else {
+ sign = FIELD_GET(RTC_SEC_ADJUST_CTRL, reg_val);
+ match_counter = FIELD_GET(RTC_MATCH_COUNTER, reg_val);
+ val = 1000000000 / (match_counter + 1);
+ if (sign == RTC_SWALLOW_SECOND)
+ val = -val;
+ }
+ *offset = val;
+
+ return 0;
+}
+
+static int aml_rtc_set_offset(struct device *dev, long offset)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ int sign = 0;
+ int match_counter = 0;
+ int enable = 0;
+ u32 reg_val;
+
+ /* if RTC disabled, set offset failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ if (offset) {
+ enable = 1;
+ sign = offset < 0 ? RTC_SWALLOW_SECOND : RTC_INSERT_SECOND;
+ match_counter = 1000000000 / abs(offset) - 1;
+ if (match_counter < 0 || match_counter > RTC_MATCH_COUNTER)
+ return -EINVAL;
+ }
+
+ reg_val = FIELD_PREP(RTC_ADJ_VALID, enable) |
+ FIELD_PREP(RTC_SEC_ADJUST_CTRL, sign) |
+ FIELD_PREP(RTC_MATCH_COUNTER, match_counter);
+ regmap_write(rtc->map, RTC_SEC_ADJUST_REG, reg_val);
+
+ return 0;
+}
+
+static int aml_rtc_alarm_enable(struct device *dev, unsigned int enabled)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+
+ if (enabled) {
+ regmap_update_bits(rtc->map, RTC_CTRL,
+ RTC_ALRM0_EN, RTC_ALRM0_EN);
+ regmap_update_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, 0);
+ } else {
+ regmap_update_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK);
+ regmap_update_bits(rtc->map, RTC_CTRL,
+ RTC_ALRM0_EN, 0);
+ }
+
+ return 0;
+}
+
+static const struct rtc_class_ops aml_rtc_ops = {
+ .read_time = aml_rtc_read_time,
+ .set_time = aml_rtc_set_time,
+ .read_alarm = aml_rtc_read_alarm,
+ .set_alarm = aml_rtc_set_alarm,
+ .alarm_irq_enable = aml_rtc_alarm_enable,
+ .read_offset = aml_rtc_read_offset,
+ .set_offset = aml_rtc_set_offset,
+};
+
+static irqreturn_t aml_rtc_handler(int irq, void *data)
+{
+ struct aml_rtc_data *rtc = (struct aml_rtc_data *)data;
+
+ regmap_write(rtc->map, RTC_ALARM0_REG, 0);
+ regmap_write(rtc->map, RTC_INT_CLR, RTC_ALRM0_IRQ_STATUS);
+
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+
+ return IRQ_HANDLED;
+}
+
+static void aml_rtc_init(struct aml_rtc_data *rtc)
+{
+ u32 reg_val = 0;
+
+ rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE);
+ if (!rtc->rtc_enabled) {
+ if (clk_get_rate(rtc->rtc_clk) == OSC_24M) {
+ /* select 24M oscillator */
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, RTC_OSC_SEL);
+
+ /*
+ * Set RTC oscillator to freq_out to freq_in/((N0*M0+N1*M1)/(M0+M1))
+ * Enable clock_in gate of oscillator 24MHz
+ * Set N0 to 733, N1 to 732
+ */
+ reg_val = FIELD_PREP(RTC_OSCIN_IN_EN, 1)
+ | FIELD_PREP(RTC_OSCIN_OUT_CFG, 1)
+ | FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_N0)
+ | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_N1);
+ regmap_write_bits(rtc->map, RTC_OSCIN_CTRL0, RTC_OSCIN_IN_EN
+ | RTC_OSCIN_OUT_CFG | RTC_OSCIN_OUT_N0M0
+ | RTC_OSCIN_OUT_N1M1, reg_val);
+
+ /* Set M0 to 2, M1 to 3, so freq_out = 32768 Hz*/
+ reg_val = FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_M0)
+ | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_M1);
+ regmap_write_bits(rtc->map, RTC_OSCIN_CTRL1, RTC_OSCIN_OUT_N0M0
+ | RTC_OSCIN_OUT_N1M1, reg_val);
+ } else {
+ /* select 32K oscillator */
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, 0);
+ }
+ }
+ regmap_write_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK);
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN, 0);
+}
+
+static int aml_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct aml_rtc_data *rtc;
+ void __iomem *base;
+ int ret = 0;
+
+ rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->config = of_device_get_match_data(dev);
+ if (!rtc->config)
+ return -ENODEV;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base), "resource ioremap failed\n");
+
+ rtc->map = devm_regmap_init_mmio(dev, base, &aml_rtc_regmap_config);
+ if (IS_ERR(rtc->map))
+ return dev_err_probe(dev, PTR_ERR(rtc->map), "regmap init failed\n");
+
+ rtc->irq = platform_get_irq(pdev, 0);
+ if (rtc->irq < 0)
+ return rtc->irq;
+
+ rtc->rtc_clk = devm_clk_get(dev, "osc");
+ if (IS_ERR(rtc->rtc_clk))
+ return dev_err_probe(dev, PTR_ERR(rtc->rtc_clk),
+ "failed to find rtc clock\n");
+ if (clk_get_rate(rtc->rtc_clk) != OSC_32K && clk_get_rate(rtc->rtc_clk) != OSC_24M)
+ return dev_err_probe(dev, -EINVAL, "Invalid clock configuration\n");
+
+ rtc->sys_clk = devm_clk_get_enabled(dev, "sys");
+ if (IS_ERR(rtc->sys_clk))
+ return dev_err_probe(dev, PTR_ERR(rtc->sys_clk),
+ "failed to get_enable rtc sys clk\n");
+ aml_rtc_init(rtc);
+
+ device_init_wakeup(dev, 1);
+ platform_set_drvdata(pdev, rtc);
+
+ rtc->rtc_dev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc->rtc_dev)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err_clk;
+ }
+
+ ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler,
+ IRQF_ONESHOT, "aml-rtc alarm", rtc);
+ if (ret) {
+ dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n",
+ rtc->irq, ret);
+ goto err_clk;
+ }
+
+ rtc->rtc_dev->ops = &aml_rtc_ops;
+ rtc->rtc_dev->range_min = 0;
+ rtc->rtc_dev->range_max = U32_MAX;
+
+ ret = devm_rtc_register_device(rtc->rtc_dev);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret);
+ goto err_clk;
+ }
+
+ return 0;
+err_clk:
+ clk_disable_unprepare(rtc->sys_clk);
+ device_init_wakeup(dev, 0);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int aml_rtc_suspend(struct device *dev)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(rtc->irq);
+
+ return 0;
+}
+
+static int aml_rtc_resume(struct device *dev)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(rtc->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops,
+ aml_rtc_suspend, aml_rtc_resume);
+
+static void aml_rtc_remove(struct platform_device *pdev)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev);
+
+ clk_disable_unprepare(rtc->sys_clk);
+ device_init_wakeup(&pdev->dev, 0);
+}
+
+static const struct aml_rtc_config a5_rtc_config = {
+};
+
+static const struct aml_rtc_config a4_rtc_config = {
+ .gray_stored = true,
+};
+
+static const struct of_device_id aml_rtc_device_id[] = {
+ {
+ .compatible = "amlogic,a4-rtc",
+ .data = &a4_rtc_config,
+ },
+ {
+ .compatible = "amlogic,a5-rtc",
+ .data = &a5_rtc_config,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, aml_rtc_device_id);
+
+static struct platform_driver aml_rtc_driver = {
+ .probe = aml_rtc_probe,
+ .remove = aml_rtc_remove,
+ .driver = {
+ .name = "aml-rtc",
+ .pm = &aml_rtc_pm_ops,
+ .of_match_table = aml_rtc_device_id,
+ },
+};
+
+module_platform_driver(aml_rtc_driver);
+MODULE_DESCRIPTION("Amlogic RTC driver");
+MODULE_AUTHOR("Yiting Deng <yiting.deng@amlogic.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c
index a83b47e0d8f5..705470ae8428 100644
--- a/drivers/rtc/rtc-asm9260.c
+++ b/drivers/rtc/rtc-asm9260.c
@@ -325,7 +325,7 @@ MODULE_DEVICE_TABLE(of, asm9260_dt_ids);
static struct platform_driver asm9260_rtc_driver = {
.probe = asm9260_rtc_probe,
- .remove_new = asm9260_rtc_remove,
+ .remove = asm9260_rtc_remove,
.driver = {
.name = "asm9260-rtc",
.of_match_table = asm9260_dt_ids,
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index c16fe711a0d9..9b3898b8de7c 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -640,7 +640,7 @@ static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
* triggering a section mismatch warning.
*/
static struct platform_driver at91_rtc_driver __refdata = {
- .remove_new = __exit_p(at91_rtc_remove),
+ .remove = __exit_p(at91_rtc_remove),
.shutdown = at91_rtc_shutdown,
.driver = {
.name = "at91_rtc",
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 993c0878fb66..15b21da2788f 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -530,7 +530,7 @@ MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
static struct platform_driver at91_rtc_driver = {
.probe = at91_rtc_probe,
- .remove_new = at91_rtc_remove,
+ .remove = at91_rtc_remove,
.shutdown = at91_rtc_shutdown,
.driver = {
.name = "rtc-at91sam9",
diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c
index 1a65a4e0dc00..fb47c32ab5ff 100644
--- a/drivers/rtc/rtc-brcmstb-waketimer.c
+++ b/drivers/rtc/rtc-brcmstb-waketimer.c
@@ -17,7 +17,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
-#include <linux/pm_wakeup.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/stat.h>
@@ -417,7 +416,7 @@ static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = {
static struct platform_driver brcmstb_waketmr_driver = {
.probe = brcmstb_waketmr_probe,
- .remove_new = brcmstb_waketmr_remove,
+ .remove = brcmstb_waketmr_remove,
.driver = {
.name = "brcmstb-waketimer",
.pm = &brcmstb_waketmr_pm_ops,
diff --git a/drivers/rtc/rtc-cadence.c b/drivers/rtc/rtc-cadence.c
index 4ca60b519836..bf2a9a1fdea7 100644
--- a/drivers/rtc/rtc-cadence.c
+++ b/drivers/rtc/rtc-cadence.c
@@ -402,7 +402,7 @@ static struct platform_driver cdns_rtc_driver = {
.pm = &cdns_rtc_pm_ops,
},
.probe = cdns_rtc_probe,
- .remove_new = cdns_rtc_remove,
+ .remove = cdns_rtc_remove,
};
module_platform_driver(cdns_rtc_driver);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 35dca2accbb8..78f2ce12c75a 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -645,18 +645,17 @@ static int cmos_nvram_read(void *priv, unsigned int off, void *val,
unsigned char *buf = val;
off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
- for (; count; count--, off++) {
+ for (; count; count--, off++, buf++) {
+ guard(spinlock_irq)(&rtc_lock);
if (off < 128)
- *buf++ = CMOS_READ(off);
+ *buf = CMOS_READ(off);
else if (can_bank2)
- *buf++ = cmos_read_bank2(off);
+ *buf = cmos_read_bank2(off);
else
- break;
+ return -EIO;
}
- spin_unlock_irq(&rtc_lock);
- return count ? -EIO : 0;
+ return 0;
}
static int cmos_nvram_write(void *priv, unsigned int off, void *val,
@@ -671,23 +670,23 @@ static int cmos_nvram_write(void *priv, unsigned int off, void *val,
* NVRAM to update, updating checksums is also part of its job.
*/
off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
- for (; count; count--, off++) {
+ for (; count; count--, off++, buf++) {
/* don't trash RTC registers */
if (off == cmos->day_alrm
|| off == cmos->mon_alrm
|| off == cmos->century)
- buf++;
- else if (off < 128)
- CMOS_WRITE(*buf++, off);
+ continue;
+
+ guard(spinlock_irq)(&rtc_lock);
+ if (off < 128)
+ CMOS_WRITE(*buf, off);
else if (can_bank2)
- cmos_write_bank2(*buf++, off);
+ cmos_write_bank2(*buf, off);
else
- break;
+ return -EIO;
}
- spin_unlock_irq(&rtc_lock);
- return count ? -EIO : 0;
+ return 0;
}
/*----------------------------------------------------------------*/
@@ -1528,7 +1527,7 @@ static void cmos_platform_shutdown(struct platform_device *pdev)
MODULE_ALIAS("platform:rtc_cmos");
static struct platform_driver cmos_platform_driver = {
- .remove_new = cmos_platform_remove,
+ .remove = cmos_platform_remove,
.shutdown = cmos_platform_shutdown,
.driver = {
.name = driver_name,
diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c
index f57462c7b2c6..60a48c3ba3ca 100644
--- a/drivers/rtc/rtc-cros-ec.c
+++ b/drivers/rtc/rtc-cros-ec.c
@@ -401,7 +401,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_rtc_id);
static struct platform_driver cros_ec_rtc_driver = {
.probe = cros_ec_rtc_probe,
- .remove_new = cros_ec_rtc_remove,
+ .remove = cros_ec_rtc_remove,
.driver = {
.name = DRV_NAME,
.pm = &cros_ec_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 04dbf35cf3b7..38e25f63597a 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -1354,7 +1354,7 @@ static struct platform_driver ds1685_rtc_driver = {
.name = "rtc-ds1685",
},
.probe = ds1685_rtc_probe,
- .remove_new = ds1685_rtc_remove,
+ .remove = ds1685_rtc_remove,
};
module_platform_driver(ds1685_rtc_driver);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c
index 8bfe7378f653..cb4a5d101f53 100644
--- a/drivers/rtc/rtc-ftrtc010.c
+++ b/drivers/rtc/rtc-ftrtc010.c
@@ -214,7 +214,7 @@ static struct platform_driver ftrtc010_rtc_driver = {
.of_match_table = ftrtc010_rtc_dt_match,
},
.probe = ftrtc010_rtc_probe,
- .remove_new = ftrtc010_rtc_remove,
+ .remove = ftrtc010_rtc_remove,
};
module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);
diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c
index b81cea505ee9..e30f80dc9319 100644
--- a/drivers/rtc/rtc-hid-sensor-time.c
+++ b/drivers/rtc/rtc-hid-sensor-time.c
@@ -319,7 +319,7 @@ static struct platform_driver hid_time_platform_driver = {
.name = KBUILD_MODNAME,
},
.probe = hid_time_probe,
- .remove_new = hid_time_remove,
+ .remove = hid_time_remove,
};
module_platform_driver(hid_time_platform_driver);
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 284011c419db..ca4a0af95e8c 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -860,7 +860,7 @@ static struct platform_driver dryice_rtc_driver __refdata = {
.name = "imxdi_rtc",
.of_match_table = dryice_dt_ids,
},
- .remove_new = __exit_p(dryice_rtc_remove),
+ .remove = __exit_p(dryice_rtc_remove),
};
module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe);
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index 6fa9a68af9d9..9b44839a7402 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -21,7 +21,7 @@
#include <asm/byteorder.h>
-/* ISL register offsets */
+/* RTC - Real time clock registers */
#define ISL12022_REG_SC 0x00
#define ISL12022_REG_MN 0x01
#define ISL12022_REG_HR 0x02
@@ -30,21 +30,36 @@
#define ISL12022_REG_YR 0x05
#define ISL12022_REG_DW 0x06
+/* CSR - Control and status registers */
#define ISL12022_REG_SR 0x07
#define ISL12022_REG_INT 0x08
-
#define ISL12022_REG_PWR_VBAT 0x0a
-
#define ISL12022_REG_BETA 0x0d
+
+/* ALARM - Alarm registers */
+#define ISL12022_REG_SCA0 0x10
+#define ISL12022_REG_MNA0 0x11
+#define ISL12022_REG_HRA0 0x12
+#define ISL12022_REG_DTA0 0x13
+#define ISL12022_REG_MOA0 0x14
+#define ISL12022_REG_DWA0 0x15
+#define ISL12022_ALARM ISL12022_REG_SCA0
+#define ISL12022_ALARM_LEN (ISL12022_REG_DWA0 - ISL12022_REG_SCA0 + 1)
+
+/* TEMP - Temperature sensor registers */
#define ISL12022_REG_TEMP_L 0x28
/* ISL register bits */
#define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */
+#define ISL12022_SR_ALM (1 << 4)
#define ISL12022_SR_LBAT85 (1 << 2)
#define ISL12022_SR_LBAT75 (1 << 1)
+#define ISL12022_INT_ARST (1 << 7)
#define ISL12022_INT_WRTC (1 << 6)
+#define ISL12022_INT_IM (1 << 5)
+#define ISL12022_INT_FOBATB (1 << 4)
#define ISL12022_INT_FO_MASK GENMASK(3, 0)
#define ISL12022_INT_FO_OFF 0x0
#define ISL12022_INT_FO_32K 0x1
@@ -52,8 +67,19 @@
#define ISL12022_REG_VB85_MASK GENMASK(5, 3)
#define ISL12022_REG_VB75_MASK GENMASK(2, 0)
+#define ISL12022_ALARM_ENABLE (1 << 7) /* for all ALARM registers */
+
#define ISL12022_BETA_TSE (1 << 7)
+static struct i2c_driver isl12022_driver;
+
+struct isl12022 {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ int irq;
+ bool irq_enabled;
+};
+
static umode_t isl12022_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
@@ -116,7 +142,8 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = {
static void isl12022_hwmon_register(struct device *dev)
{
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
struct device *hwmon;
int ret;
@@ -143,8 +170,9 @@ static void isl12022_hwmon_register(struct device *dev)
*/
static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct regmap *regmap = dev_get_drvdata(dev);
- uint8_t buf[ISL12022_REG_INT + 1];
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ u8 buf[ISL12022_REG_INT + 1];
int ret;
ret = regmap_bulk_read(regmap, ISL12022_REG_SC, buf, sizeof(buf));
@@ -178,9 +206,10 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
int ret;
- uint8_t buf[ISL12022_REG_DW + 1];
+ u8 buf[ISL12022_REG_DW + 1];
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
@@ -208,9 +237,198 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf));
}
+static int isl12022_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *tm = &alarm->time;
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ u8 buf[ISL12022_ALARM_LEN];
+ unsigned int i, yr;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, ISL12022_ALARM, buf, sizeof(buf));
+ if (ret) {
+ dev_dbg(dev, "%s: reading ALARM registers failed\n",
+ __func__);
+ return ret;
+ }
+
+ /* The alarm doesn't store the year so get it from the rtc section */
+ ret = regmap_read(regmap, ISL12022_REG_YR, &yr);
+ if (ret) {
+ dev_dbg(dev, "%s: reading YR register failed\n", __func__);
+ return ret;
+ }
+
+ dev_dbg(dev,
+ "%s: sc=%02x, mn=%02x, hr=%02x, dt=%02x, mo=%02x, dw=%02x yr=%u\n",
+ __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], yr);
+
+ tm->tm_sec = bcd2bin(buf[ISL12022_REG_SCA0 - ISL12022_ALARM] & 0x7F);
+ tm->tm_min = bcd2bin(buf[ISL12022_REG_MNA0 - ISL12022_ALARM] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[ISL12022_REG_HRA0 - ISL12022_ALARM] & 0x3F);
+ tm->tm_mday = bcd2bin(buf[ISL12022_REG_DTA0 - ISL12022_ALARM] & 0x3F);
+ tm->tm_mon = bcd2bin(buf[ISL12022_REG_MOA0 - ISL12022_ALARM] & 0x1F) - 1;
+ tm->tm_wday = buf[ISL12022_REG_DWA0 - ISL12022_ALARM] & 0x07;
+ tm->tm_year = bcd2bin(yr) + 100;
+
+ for (i = 0; i < ISL12022_ALARM_LEN; i++) {
+ if (buf[i] & ISL12022_ALARM_ENABLE) {
+ alarm->enabled = 1;
+ break;
+ }
+ }
+
+ dev_dbg(dev, "%s: %ptR\n", __func__, tm);
+
+ return 0;
+}
+
+static int isl12022_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *alarm_tm = &alarm->time;
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ u8 regs[ISL12022_ALARM_LEN] = { 0, };
+ struct rtc_time rtc_tm;
+ int ret, enable, dw;
+
+ ret = isl12022_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ return ret;
+
+ /* If the alarm time is before the current time disable the alarm */
+ if (!alarm->enabled || rtc_tm_sub(alarm_tm, &rtc_tm) <= 0)
+ enable = 0;
+ else
+ enable = ISL12022_ALARM_ENABLE;
+
+ /*
+ * Set non-matching day of the week to safeguard against early false
+ * matching while setting all the alarm registers (this rtc lacks a
+ * general alarm/irq enable/disable bit).
+ */
+ ret = regmap_read(regmap, ISL12022_REG_DW, &dw);
+ if (ret) {
+ dev_dbg(dev, "%s: reading DW failed\n", __func__);
+ return ret;
+ }
+ /* ~4 days into the future should be enough to avoid match */
+ dw = ((dw + 4) % 7) | ISL12022_ALARM_ENABLE;
+ ret = regmap_write(regmap, ISL12022_REG_DWA0, dw);
+ if (ret) {
+ dev_dbg(dev, "%s: writing DWA0 failed\n", __func__);
+ return ret;
+ }
+
+ /* Program the alarm and enable it for each setting */
+ regs[ISL12022_REG_SCA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_sec) | enable;
+ regs[ISL12022_REG_MNA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_min) | enable;
+ regs[ISL12022_REG_HRA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_hour) | enable;
+ regs[ISL12022_REG_DTA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mday) | enable;
+ regs[ISL12022_REG_MOA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mon + 1) | enable;
+ regs[ISL12022_REG_DWA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_wday & 7) | enable;
+
+ /* write ALARM registers */
+ ret = regmap_bulk_write(regmap, ISL12022_ALARM, &regs, sizeof(regs));
+ if (ret) {
+ dev_dbg(dev, "%s: writing ALARM registers failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static irqreturn_t isl12022_rtc_interrupt(int irq, void *data)
+{
+ struct isl12022 *isl12022 = data;
+ struct rtc_device *rtc = isl12022->rtc;
+ struct device *dev = &rtc->dev;
+ struct regmap *regmap = isl12022->regmap;
+ u32 val = 0;
+ unsigned long events = 0;
+ int ret;
+
+ ret = regmap_read(regmap, ISL12022_REG_SR, &val);
+ if (ret) {
+ dev_dbg(dev, "%s: reading SR failed\n", __func__);
+ return IRQ_HANDLED;
+ }
+
+ if (val & ISL12022_SR_ALM)
+ events |= RTC_IRQF | RTC_AF;
+
+ if (events & RTC_AF)
+ dev_dbg(dev, "alarm!\n");
+
+ if (!events)
+ return IRQ_NONE;
+
+ rtc_update_irq(rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+static int isl12022_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+
+ /* Make sure enabled is 0 or 1 */
+ enabled = !!enabled;
+
+ if (isl12022->irq_enabled == enabled)
+ return 0;
+
+ if (enabled)
+ enable_irq(isl12022->irq);
+ else
+ disable_irq(isl12022->irq);
+
+ isl12022->irq_enabled = enabled;
+
+ return 0;
+}
+
+static int isl12022_setup_irq(struct device *dev, int irq)
+{
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ unsigned int reg_mask, reg_val;
+ u8 buf[ISL12022_ALARM_LEN] = { 0, };
+ int ret;
+
+ /* Clear and disable all alarm registers */
+ ret = regmap_bulk_write(regmap, ISL12022_ALARM, buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ /*
+ * Enable automatic reset of ALM bit and enable single event interrupt
+ * mode.
+ */
+ reg_mask = ISL12022_INT_ARST | ISL12022_INT_IM | ISL12022_INT_FO_MASK;
+ reg_val = ISL12022_INT_ARST | ISL12022_INT_FO_OFF;
+ ret = regmap_write_bits(regmap, ISL12022_REG_INT,
+ reg_mask, reg_val);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ isl12022_rtc_interrupt,
+ IRQF_SHARED | IRQF_ONESHOT,
+ isl12022_driver.driver.name,
+ isl12022);
+ if (ret)
+ return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
+
+ isl12022->irq = irq;
+ return 0;
+}
+
static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
u32 user, val;
int ret;
@@ -238,6 +456,9 @@ static const struct rtc_class_ops isl12022_rtc_ops = {
.ioctl = isl12022_rtc_ioctl,
.read_time = isl12022_rtc_read_time,
.set_time = isl12022_rtc_set_time,
+ .read_alarm = isl12022_rtc_read_alarm,
+ .set_alarm = isl12022_rtc_set_alarm,
+ .alarm_irq_enable = isl12022_rtc_alarm_irq_enable,
};
static const struct regmap_config regmap_config = {
@@ -248,7 +469,8 @@ static const struct regmap_config regmap_config = {
static int isl12022_register_clock(struct device *dev)
{
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
struct clk_hw *hw;
int ret;
@@ -288,7 +510,8 @@ static const u32 trip_levels[2][7] = {
static void isl12022_set_trip_levels(struct device *dev)
{
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
u32 levels[2] = {0, 0};
int ret, i, j, x[2];
u8 val, mask;
@@ -325,6 +548,7 @@ static void isl12022_set_trip_levels(struct device *dev)
static int isl12022_probe(struct i2c_client *client)
{
+ struct isl12022 *isl12022;
struct rtc_device *rtc;
struct regmap *regmap;
int ret;
@@ -332,13 +556,17 @@ static int isl12022_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
+ /* Allocate driver state */
+ isl12022 = devm_kzalloc(&client->dev, sizeof(*isl12022), GFP_KERNEL);
+ if (!isl12022)
+ return -ENOMEM;
+
regmap = devm_regmap_init_i2c(client, &regmap_config);
- if (IS_ERR(regmap)) {
- dev_err(&client->dev, "regmap allocation failed\n");
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap), "regmap allocation failed\n");
+ isl12022->regmap = regmap;
- dev_set_drvdata(&client->dev, regmap);
+ dev_set_drvdata(&client->dev, isl12022);
ret = isl12022_register_clock(&client->dev);
if (ret)
@@ -350,11 +578,20 @@ static int isl12022_probe(struct i2c_client *client)
rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
+ isl12022->rtc = rtc;
rtc->ops = &isl12022_rtc_ops;
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->range_max = RTC_TIMESTAMP_END_2099;
+ if (client->irq > 0) {
+ ret = isl12022_setup_irq(&client->dev, client->irq);
+ if (ret)
+ return ret;
+ } else {
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
+ }
+
return devm_rtc_register_device(rtc);
}
diff --git a/drivers/rtc/rtc-loongson.c b/drivers/rtc/rtc-loongson.c
index e8ffc1ab90b0..8d713e563d7c 100644
--- a/drivers/rtc/rtc-loongson.c
+++ b/drivers/rtc/rtc-loongson.c
@@ -381,7 +381,7 @@ MODULE_DEVICE_TABLE(acpi, loongson_rtc_acpi_match);
static struct platform_driver loongson_rtc_driver = {
.probe = loongson_rtc_probe,
- .remove_new = loongson_rtc_remove,
+ .remove = loongson_rtc_remove,
.driver = {
.name = "loongson-rtc",
.of_match_table = loongson_rtc_of_match,
diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c
index df17c48ff086..2dcdc77ff646 100644
--- a/drivers/rtc/rtc-lpc24xx.c
+++ b/drivers/rtc/rtc-lpc24xx.c
@@ -285,7 +285,7 @@ MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match);
static struct platform_driver lpc24xx_rtc_driver = {
.probe = lpc24xx_rtc_probe,
- .remove_new = lpc24xx_rtc_remove,
+ .remove = lpc24xx_rtc_remove,
.driver = {
.name = "lpc24xx-rtc",
.of_match_table = lpc24xx_rtc_match,
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 5d30ce8e13ca..4e608bc8bbd3 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -71,7 +71,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
- tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
+ tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset;
/* tm_mon is 0-11 */
tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY));
@@ -82,10 +82,6 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
dev_dbg(dev, "Century bit is enabled\n");
tm->tm_year += 100; /* one century */
}
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- tm->tm_year += 68;
-#endif
tm->tm_wday = bcd2bin(val & 0x07);
tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F);
@@ -106,12 +102,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
unsigned long flags;
u8 val = 0;
- int year = tm->tm_year;
-
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- year -= 68;
-#endif
+ int year = tm->tm_year - pdata->yy_offset;
dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n",
year + 1900, tm->tm_mon, tm->tm_mday,
@@ -162,11 +153,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
/* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
- tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- tm->tm_year += 68;
-#endif
+ tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset;
/* tm_mon is 0-11 */
tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
@@ -197,12 +184,7 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time;
u8 mday, hour, min, sec;
unsigned long flags;
- int year = tm->tm_year;
-
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- year -= 68;
-#endif
+ int year = tm->tm_year - pdata->yy_offset;
/* If no irq, we don't support ALARM */
if (m48t59->irq == NO_IRQ)
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index 35a6021d9ba4..a8f4b645c09d 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -875,7 +875,7 @@ static struct platform_driver max77686_rtc_driver = {
.pm = &max77686_rtc_pm_ops,
},
.probe = max77686_rtc_probe,
- .remove_new = max77686_rtc_remove,
+ .remove = max77686_rtc_remove,
.id_table = rtc_id,
};
diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c
index 763a42f422eb..e7b87130e624 100644
--- a/drivers/rtc/rtc-mc13xxx.c
+++ b/drivers/rtc/rtc-mc13xxx.c
@@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
static struct platform_driver mc13xxx_rtc_driver = {
.id_table = mc13xxx_rtc_idtable,
- .remove_new = mc13xxx_rtc_remove,
+ .remove = mc13xxx_rtc_remove,
.driver = {
.name = DRIVER_NAME,
},
diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c
index 651bf3c279c7..dbd2d5835f00 100644
--- a/drivers/rtc/rtc-mc146818-lib.c
+++ b/drivers/rtc/rtc-mc146818-lib.c
@@ -216,7 +216,7 @@ int mc146818_set_time(struct rtc_time *time)
unsigned char save_control, save_freq_select;
unsigned int yrs;
#ifdef CONFIG_MACH_DECSTATION
- unsigned int real_yrs, leap_yr;
+ unsigned int real_yrs;
#endif
unsigned char century = 0;
@@ -232,8 +232,6 @@ int mc146818_set_time(struct rtc_time *time)
#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
- leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
- !((yrs + 1900) % 400));
yrs = 72;
/*
@@ -241,7 +239,7 @@ int mc146818_set_time(struct rtc_time *time)
* for non-leap years, so that Feb, 29th is handled
* correctly.
*/
- if (!leap_yr && mon < 3) {
+ if (!is_leap_year(real_yrs + 1900) && mon < 3) {
real_yrs--;
yrs = 73;
}
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index 71eafe4fbc72..600328131603 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -398,7 +398,7 @@ static struct platform_driver mpc5121_rtc_driver = {
.of_match_table = of_match_ptr(mpc5121_rtc_match),
},
.probe = mpc5121_rtc_probe,
- .remove_new = mpc5121_rtc_remove,
+ .remove = mpc5121_rtc_remove,
};
module_platform_driver(mpc5121_rtc_driver);
diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
index 5b96a6d39210..3892b0f9917f 100644
--- a/drivers/rtc/rtc-mpfs.c
+++ b/drivers/rtc/rtc-mpfs.c
@@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, mpfs_rtc_of_match);
static struct platform_driver mpfs_rtc_driver = {
.probe = mpfs_rtc_probe,
- .remove_new = mpfs_rtc_remove,
+ .remove = mpfs_rtc_remove,
.driver = {
.name = "mpfs_rtc",
.of_match_table = mpfs_rtc_of_match,
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 1617063669cc..152699219a2b 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -75,6 +75,7 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
tm->tm_min = data[RTC_OFFSET_MIN];
tm->tm_hour = data[RTC_OFFSET_HOUR];
tm->tm_mday = data[RTC_OFFSET_DOM];
+ tm->tm_wday = data[RTC_OFFSET_DOW];
tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK;
tm->tm_year = data[RTC_OFFSET_YEAR];
@@ -86,9 +87,8 @@ exit:
static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- time64_t time;
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
- int days, sec, ret;
+ int sec, ret;
do {
ret = __mtk_rtc_read_time(rtc, tm, &sec);
@@ -96,21 +96,9 @@ static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
goto exit;
} while (sec < tm->tm_sec);
- /* HW register use 7 bits to store year data, minus
- * RTC_MIN_YEAR_OFFSET before write year data to register, and plus
- * RTC_MIN_YEAR_OFFSET back after read year from register
- */
- tm->tm_year += RTC_MIN_YEAR_OFFSET;
-
- /* HW register start mon from one, but tm_mon start from zero. */
+ /* HW register start mon/wday from one, but tm_mon/tm_wday start from zero. */
tm->tm_mon--;
- time = rtc_tm_to_time64(tm);
-
- /* rtc_tm_to_time64 covert Gregorian date to seconds since
- * 01-01-1970 00:00:00, and this date is Thursday.
- */
- days = div_s64(time, 86400);
- tm->tm_wday = (days + 4) % 7;
+ tm->tm_wday--;
exit:
return ret;
@@ -122,13 +110,14 @@ static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
int ret;
u16 data[RTC_OFFSET_COUNT];
- tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++;
+ tm->tm_wday++;
data[RTC_OFFSET_SEC] = tm->tm_sec;
data[RTC_OFFSET_MIN] = tm->tm_min;
data[RTC_OFFSET_HOUR] = tm->tm_hour;
data[RTC_OFFSET_DOM] = tm->tm_mday;
+ data[RTC_OFFSET_DOW] = tm->tm_wday;
data[RTC_OFFSET_MTH] = tm->tm_mon;
data[RTC_OFFSET_YEAR] = tm->tm_year;
@@ -178,7 +167,6 @@ static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK;
tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK;
- tm->tm_year += RTC_MIN_YEAR_OFFSET;
tm->tm_mon--;
return 0;
@@ -194,7 +182,6 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
int ret;
u16 data[RTC_OFFSET_COUNT];
- tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++;
mutex_lock(&rtc->lock);
@@ -302,6 +289,10 @@ static int mtk_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
rtc->rtc_dev->ops = &mtk_rtc_ops;
+ rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
+ rtc->rtc_dev->range_max = mktime64(2027, 12, 31, 23, 59, 59);
+ rtc->rtc_dev->start_secs = mktime64(1968, 1, 2, 0, 0, 0);
+ rtc->rtc_dev->set_start_time = true;
return devm_rtc_register_device(rtc->rtc_dev);
}
diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c
index 094c649fc137..4cf0cbb31a31 100644
--- a/drivers/rtc/rtc-mt7622.c
+++ b/drivers/rtc/rtc-mt7622.c
@@ -394,7 +394,7 @@ static SIMPLE_DEV_PM_OPS(mtk_rtc_pm_ops, mtk_rtc_suspend, mtk_rtc_resume);
static struct platform_driver mtk_rtc_driver = {
.probe = mtk_rtc_probe,
- .remove_new = mtk_rtc_remove,
+ .remove = mtk_rtc_remove,
.driver = {
.name = MTK_RTC_DEV,
.of_match_table = mtk_rtc_match,
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index db31da56bfa7..51029c536244 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -308,7 +308,7 @@ MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table);
* triggering a section mismatch warning.
*/
static struct platform_driver mv_rtc_driver __refdata = {
- .remove_new = __exit_p(mv_rtc_remove),
+ .remove = __exit_p(mv_rtc_remove),
.driver = {
.name = "rtc-mv",
.of_match_table = of_match_ptr(rtc_mv_of_match_table),
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
index 6934bce4b29f..13c041bb79f1 100644
--- a/drivers/rtc/rtc-mxc_v2.c
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -381,7 +381,7 @@ static struct platform_driver mxc_rtc_driver = {
.of_match_table = mxc_ids,
},
.probe = mxc_rtc_probe,
- .remove_new = mxc_rtc_remove,
+ .remove = mxc_rtc_remove,
};
module_platform_driver(mxc_rtc_driver);
diff --git a/drivers/rtc/rtc-nxp-bbnsm.c b/drivers/rtc/rtc-nxp-bbnsm.c
index acbfbeb8b070..fa3b0328c7a2 100644
--- a/drivers/rtc/rtc-nxp-bbnsm.c
+++ b/drivers/rtc/rtc-nxp-bbnsm.c
@@ -197,13 +197,28 @@ static int bbnsm_rtc_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to request irq %d: %d\n",
bbnsm->irq, ret);
- return ret;
+ goto err;
}
bbnsm->rtc->ops = &bbnsm_rtc_ops;
bbnsm->rtc->range_max = U32_MAX;
- return devm_rtc_register_device(bbnsm->rtc);
+ ret = devm_rtc_register_device(bbnsm->rtc);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
+ return ret;
+}
+
+static void bbnsm_rtc_remove(struct platform_device *pdev)
+{
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
}
static const struct of_device_id bbnsm_dt_ids[] = {
@@ -218,6 +233,7 @@ static struct platform_driver bbnsm_rtc_driver = {
.of_match_table = bbnsm_dt_ids,
},
.probe = bbnsm_rtc_probe,
+ .remove = bbnsm_rtc_remove,
};
module_platform_driver(bbnsm_rtc_driver);
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index e6b2a9c15b54..c123778e2d9b 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -1014,7 +1014,7 @@ static void omap_rtc_shutdown(struct platform_device *pdev)
static struct platform_driver omap_rtc_driver = {
.probe = omap_rtc_probe,
- .remove_new = omap_rtc_remove,
+ .remove = omap_rtc_remove,
.shutdown = omap_rtc_shutdown,
.driver = {
.name = "omap_rtc",
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
index 6971e47c6021..7256a88b490c 100644
--- a/drivers/rtc/rtc-palmas.c
+++ b/drivers/rtc/rtc-palmas.c
@@ -346,7 +346,7 @@ MODULE_DEVICE_TABLE(of, of_palmas_rtc_match);
static struct platform_driver palmas_rtc_driver = {
.probe = palmas_rtc_probe,
- .remove_new = palmas_rtc_remove,
+ .remove = palmas_rtc_remove,
.driver = {
.name = "palmas-rtc",
.pm = &palmas_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
index 23edd11aa40c..c019c4d91c7d 100644
--- a/drivers/rtc/rtc-pcf50633.c
+++ b/drivers/rtc/rtc-pcf50633.c
@@ -273,7 +273,7 @@ static struct platform_driver pcf50633_rtc_driver = {
.name = "pcf50633-rtc",
},
.probe = pcf50633_rtc_probe,
- .remove_new = pcf50633_rtc_remove,
+ .remove = pcf50633_rtc_remove,
};
module_platform_driver(pcf50633_rtc_driver);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 647d52f1f5c5..5a084d426e58 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -11,14 +11,15 @@
* https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf
*/
+#include <linux/bcd.h>
#include <linux/clk-provider.h>
+#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
#define PCF8563_REG_ST1 0x00 /* status */
#define PCF8563_REG_ST2 0x01
@@ -77,64 +78,18 @@ struct pcf8563 {
*/
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
- struct i2c_client *client;
+ struct regmap *regmap;
#ifdef CONFIG_COMMON_CLK
struct clk_hw clkout_hw;
#endif
};
-static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg,
- unsigned char length, unsigned char *buf)
-{
- struct i2c_msg msgs[] = {
- {/* setup read ptr */
- .addr = client->addr,
- .len = 1,
- .buf = &reg,
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = buf
- },
- };
-
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
- return -EIO;
- }
-
- return 0;
-}
-
-static int pcf8563_write_block_data(struct i2c_client *client,
- unsigned char reg, unsigned char length,
- unsigned char *buf)
-{
- int i, err;
-
- for (i = 0; i < length; i++) {
- unsigned char data[2] = { reg + i, buf[i] };
-
- err = i2c_master_send(client, data, sizeof(data));
- if (err != sizeof(data)) {
- dev_err(&client->dev,
- "%s: err=%d addr=%02x, data=%02x\n",
- __func__, err, data[0], data[1]);
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
+static int pcf8563_set_alarm_mode(struct pcf8563 *pcf8563, bool on)
{
- unsigned char buf;
+ u32 buf;
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
+ err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf);
if (err < 0)
return err;
@@ -145,23 +100,17 @@ static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N);
- err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
- if (err < 0) {
- dev_err(&client->dev, "%s: write error\n", __func__);
- return -EIO;
- }
-
- return 0;
+ return regmap_write(pcf8563->regmap, PCF8563_REG_ST2, buf);
}
-static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en,
+static int pcf8563_get_alarm_mode(struct pcf8563 *pcf8563, unsigned char *en,
unsigned char *pen)
{
- unsigned char buf;
+ u32 buf;
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
- if (err)
+ err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf);
+ if (err < 0)
return err;
if (en)
@@ -174,17 +123,17 @@ static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en,
static irqreturn_t pcf8563_irq(int irq, void *dev_id)
{
- struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id);
- int err;
+ struct pcf8563 *pcf8563 = dev_id;
char pending;
+ int err;
- err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending);
+ err = pcf8563_get_alarm_mode(pcf8563, NULL, &pending);
if (err)
return IRQ_NONE;
if (pending) {
rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF);
- pcf8563_set_alarm_mode(pcf8563->client, 1);
+ pcf8563_set_alarm_mode(pcf8563, 1);
return IRQ_HANDLED;
}
@@ -197,22 +146,22 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id)
*/
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[9];
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST1, 9, buf);
- if (err)
+ err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_ST1, buf,
+ sizeof(buf));
+ if (err < 0)
return err;
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
- dev_err(&client->dev,
+ dev_err(dev,
"low voltage detected, date/time is not reliable.\n");
return -EINVAL;
}
- dev_dbg(&client->dev,
+ dev_dbg(dev,
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
__func__,
@@ -220,7 +169,6 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
buf[4], buf[5], buf[6], buf[7],
buf[8]);
-
tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
@@ -232,7 +180,7 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
(tm->tm_year >= 100) : (tm->tm_year < 100);
- dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
@@ -243,11 +191,10 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[9];
- dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
@@ -270,22 +217,24 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
- return pcf8563_write_block_data(client, PCF8563_REG_SC,
- 9 - PCF8563_REG_SC, buf + PCF8563_REG_SC);
+ return regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC,
+ buf + PCF8563_REG_SC,
+ sizeof(buf) - PCF8563_REG_SC);
}
static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
int ret;
switch (cmd) {
case RTC_VL_READ:
- ret = i2c_smbus_read_byte_data(client, PCF8563_REG_SC);
+ ret = regmap_test_bits(pcf8563->regmap, PCF8563_REG_SC,
+ PCF8563_SC_LV);
if (ret < 0)
return ret;
- return put_user(ret & PCF8563_SC_LV ? RTC_VL_DATA_INVALID : 0,
+ return put_user(ret ? RTC_VL_DATA_INVALID : 0,
(unsigned int __user *)arg);
default:
return -ENOIOCTLCMD;
@@ -294,15 +243,16 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4];
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf);
- if (err)
+ err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_AMN, buf,
+ sizeof(buf));
+ if (err < 0)
return err;
- dev_dbg(&client->dev,
+ dev_dbg(dev,
"%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
__func__, buf[0], buf[1], buf[2], buf[3]);
@@ -312,11 +262,11 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
- err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending);
+ err = pcf8563_get_alarm_mode(pcf8563, &tm->enabled, &tm->pending);
if (err < 0)
return err;
- dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d,"
+ dev_dbg(dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d,"
" enabled=%d, pending=%d\n", __func__, tm->time.tm_min,
tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday,
tm->enabled, tm->pending);
@@ -326,7 +276,7 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4];
int err;
@@ -335,17 +285,20 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
buf[2] = bin2bcd(tm->time.tm_mday);
buf[3] = tm->time.tm_wday & 0x07;
- err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf);
+ err = regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC, buf,
+ sizeof(buf));
if (err)
return err;
- return pcf8563_set_alarm_mode(client, !!tm->enabled);
+ return pcf8563_set_alarm_mode(pcf8563, !!tm->enabled);
}
static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
{
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
+
dev_dbg(dev, "%s: en=%d\n", __func__, enabled);
- return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled);
+ return pcf8563_set_alarm_mode(pcf8563, !!enabled);
}
#ifdef CONFIG_COMMON_CLK
@@ -366,10 +319,10 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ u32 buf;
+ int ret;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return 0;
@@ -393,11 +346,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
- int i;
+ int i, ret;
+ u32 buf;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@@ -405,10 +357,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] == rate) {
buf &= ~PCF8563_REG_CLKO_F_MASK;
buf |= i;
- ret = pcf8563_write_block_data(client,
- PCF8563_REG_CLKO, 1,
- &buf);
- return ret;
+ return regmap_update_bits(pcf8563->regmap,
+ PCF8563_REG_CLKO,
+ PCF8563_REG_CLKO_F_MASK,
+ buf);
}
return -EINVAL;
@@ -417,10 +369,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ u32 buf;
+ int ret;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@@ -429,8 +381,8 @@ static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
else
buf &= ~PCF8563_REG_CLKO_FE;
- ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
- return ret;
+ return regmap_update_bits(pcf8563->regmap, PCF8563_REG_CLKO,
+ PCF8563_REG_CLKO_FE, buf);
}
static int pcf8563_clkout_prepare(struct clk_hw *hw)
@@ -446,10 +398,10 @@ static void pcf8563_clkout_unprepare(struct clk_hw *hw)
static int pcf8563_clkout_is_prepared(struct clk_hw *hw)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ u32 buf;
+ int ret;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@@ -467,16 +419,14 @@ static const struct clk_ops pcf8563_clkout_ops = {
static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
{
- struct i2c_client *client = pcf8563->client;
- struct device_node *node = client->dev.of_node;
- struct clk *clk;
+ struct device_node *node = pcf8563->rtc->dev.of_node;
struct clk_init_data init;
+ struct clk *clk;
int ret;
- unsigned char buf;
/* disable the clkout output */
- buf = 0;
- ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ ret = regmap_clear_bits(pcf8563->regmap, PCF8563_REG_CLKO,
+ PCF8563_REG_CLKO_FE);
if (ret < 0)
return ERR_PTR(ret);
@@ -491,7 +441,7 @@ static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
of_property_read_string(node, "clock-output-names", &init.name);
/* register the clock */
- clk = devm_clk_register(&client->dev, &pcf8563->clkout_hw);
+ clk = devm_clk_register(&pcf8563->rtc->dev, &pcf8563->clkout_hw);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
@@ -509,11 +459,16 @@ static const struct rtc_class_ops pcf8563_rtc_ops = {
.alarm_irq_enable = pcf8563_irq_enable,
};
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xF,
+};
+
static int pcf8563_probe(struct i2c_client *client)
{
struct pcf8563 *pcf8563;
int err;
- unsigned char buf;
dev_dbg(&client->dev, "%s\n", __func__);
@@ -525,20 +480,23 @@ static int pcf8563_probe(struct i2c_client *client)
if (!pcf8563)
return -ENOMEM;
+ pcf8563->regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(pcf8563->regmap))
+ return PTR_ERR(pcf8563->regmap);
+
i2c_set_clientdata(client, pcf8563);
- pcf8563->client = client;
+ device_set_wakeup_capable(&client->dev, 1);
/* Set timer to lowest frequency to save power (ref Haoyu datasheet) */
- buf = PCF8563_TMRC_1_60;
- err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf);
+ err = regmap_set_bits(pcf8563->regmap, PCF8563_REG_TMRC,
+ PCF8563_TMRC_1_60);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return err;
}
/* Clear flags and disable interrupts */
- buf = 0;
- err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
+ err = regmap_write(pcf8563->regmap, PCF8563_REG_ST2, 0);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return err;
diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c
index 4f85e0c3d757..bed3c27e665f 100644
--- a/drivers/rtc/rtc-pic32.c
+++ b/drivers/rtc/rtc-pic32.c
@@ -371,7 +371,7 @@ MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids);
static struct platform_driver pic32_rtc_driver = {
.probe = pic32_rtc_probe,
- .remove_new = pic32_rtc_remove,
+ .remove = pic32_rtc_remove,
.driver = {
.name = "pic32-rtc",
.of_match_table = of_match_ptr(pic32_rtc_dt_ids),
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index c32fba550c8e..2f32187ecc8d 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -537,7 +537,7 @@ static void pm8xxx_remove(struct platform_device *pdev)
static struct platform_driver pm8xxx_rtc_driver = {
.probe = pm8xxx_rtc_probe,
- .remove_new = pm8xxx_remove,
+ .remove = pm8xxx_remove,
.driver = {
.name = "rtc-pm8xxx",
.of_match_table = pm8xxx_id_table,
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index cdb39fc4cab5..34d8545c8e15 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -409,7 +409,7 @@ static SIMPLE_DEV_PM_OPS(pxa_rtc_pm_ops, pxa_rtc_suspend, pxa_rtc_resume);
* triggering a section mismatch warning.
*/
static struct platform_driver pxa_rtc_driver __refdata = {
- .remove_new = __exit_p(pxa_rtc_remove),
+ .remove = __exit_p(pxa_rtc_remove),
.driver = {
.name = "pxa-rtc",
.of_match_table = of_match_ptr(pxa_rtc_dt_ids),
diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c
index 115c46f862f9..eecb49bab56a 100644
--- a/drivers/rtc/rtc-rc5t583.c
+++ b/drivers/rtc/rtc-rc5t583.c
@@ -298,7 +298,7 @@ static SIMPLE_DEV_PM_OPS(rc5t583_rtc_pm_ops, rc5t583_rtc_suspend,
static struct platform_driver rc5t583_rtc_driver = {
.probe = rc5t583_rtc_probe,
- .remove_new = rc5t583_rtc_remove,
+ .remove = rc5t583_rtc_remove,
.driver = {
.name = "rtc-rc5t583",
.pm = &rc5t583_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
new file mode 100644
index 000000000000..d127933bfc8a
--- /dev/null
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -0,0 +1,900 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * On-Chip RTC Support available on RZ/G3S SoC
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+#include <linux/bcd.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/rtc.h>
+
+/* Counter registers. */
+#define RTCA3_RSECCNT 0x2
+#define RTCA3_RSECCNT_SEC GENMASK(6, 0)
+#define RTCA3_RMINCNT 0x4
+#define RTCA3_RMINCNT_MIN GENMASK(6, 0)
+#define RTCA3_RHRCNT 0x6
+#define RTCA3_RHRCNT_HR GENMASK(5, 0)
+#define RTCA3_RHRCNT_PM BIT(6)
+#define RTCA3_RWKCNT 0x8
+#define RTCA3_RWKCNT_WK GENMASK(2, 0)
+#define RTCA3_RDAYCNT 0xa
+#define RTCA3_RDAYCNT_DAY GENMASK(5, 0)
+#define RTCA3_RMONCNT 0xc
+#define RTCA3_RMONCNT_MONTH GENMASK(4, 0)
+#define RTCA3_RYRCNT 0xe
+#define RTCA3_RYRCNT_YEAR GENMASK(7, 0)
+
+/* Alarm registers. */
+#define RTCA3_RSECAR 0x10
+#define RTCA3_RSECAR_SEC GENMASK(6, 0)
+#define RTCA3_RMINAR 0x12
+#define RTCA3_RMINAR_MIN GENMASK(6, 0)
+#define RTCA3_RHRAR 0x14
+#define RTCA3_RHRAR_HR GENMASK(5, 0)
+#define RTCA3_RHRAR_PM BIT(6)
+#define RTCA3_RWKAR 0x16
+#define RTCA3_RWKAR_DAYW GENMASK(2, 0)
+#define RTCA3_RDAYAR 0x18
+#define RTCA3_RDAYAR_DATE GENMASK(5, 0)
+#define RTCA3_RMONAR 0x1a
+#define RTCA3_RMONAR_MON GENMASK(4, 0)
+#define RTCA3_RYRAR 0x1c
+#define RTCA3_RYRAR_YR GENMASK(7, 0)
+#define RTCA3_RYRAREN 0x1e
+
+/* Alarm enable bit (for all alarm registers). */
+#define RTCA3_AR_ENB BIT(7)
+
+/* Control registers. */
+#define RTCA3_RCR1 0x22
+#define RTCA3_RCR1_AIE BIT(0)
+#define RTCA3_RCR1_CIE BIT(1)
+#define RTCA3_RCR1_PIE BIT(2)
+#define RTCA3_RCR1_PES GENMASK(7, 4)
+#define RTCA3_RCR1_PES_1_64_SEC 0x8
+#define RTCA3_RCR2 0x24
+#define RTCA3_RCR2_START BIT(0)
+#define RTCA3_RCR2_RESET BIT(1)
+#define RTCA3_RCR2_AADJE BIT(4)
+#define RTCA3_RCR2_ADJP BIT(5)
+#define RTCA3_RCR2_HR24 BIT(6)
+#define RTCA3_RCR2_CNTMD BIT(7)
+#define RTCA3_RSR 0x20
+#define RTCA3_RSR_AF BIT(0)
+#define RTCA3_RSR_CF BIT(1)
+#define RTCA3_RSR_PF BIT(2)
+#define RTCA3_RADJ 0x2e
+#define RTCA3_RADJ_ADJ GENMASK(5, 0)
+#define RTCA3_RADJ_ADJ_MAX 0x3f
+#define RTCA3_RADJ_PMADJ GENMASK(7, 6)
+#define RTCA3_RADJ_PMADJ_NONE 0
+#define RTCA3_RADJ_PMADJ_ADD 1
+#define RTCA3_RADJ_PMADJ_SUB 2
+
+/* Polling operation timeouts. */
+#define RTCA3_DEFAULT_TIMEOUT_US 150
+#define RTCA3_IRQSET_TIMEOUT_US 5000
+#define RTCA3_START_TIMEOUT_US 150000
+#define RTCA3_RESET_TIMEOUT_US 200000
+
+/**
+ * enum rtca3_alrm_set_step - RTCA3 alarm set steps
+ * @RTCA3_ALRM_SSTEP_DONE: alarm setup done step
+ * @RTCA3_ALRM_SSTEP_IRQ: two 1/64 periodic IRQs were generated step
+ * @RTCA3_ALRM_SSTEP_INIT: alarm setup initialization step
+ */
+enum rtca3_alrm_set_step {
+ RTCA3_ALRM_SSTEP_DONE = 0,
+ RTCA3_ALRM_SSTEP_IRQ = 1,
+ RTCA3_ALRM_SSTEP_INIT = 3,
+};
+
+/**
+ * struct rtca3_ppb_per_cycle - PPB per cycle
+ * @ten_sec: PPB per cycle in 10 seconds adjutment mode
+ * @sixty_sec: PPB per cycle in 60 seconds adjustment mode
+ */
+struct rtca3_ppb_per_cycle {
+ int ten_sec;
+ int sixty_sec;
+};
+
+/**
+ * struct rtca3_priv - RTCA3 private data structure
+ * @base: base address
+ * @rtc_dev: RTC device
+ * @rstc: reset control
+ * @set_alarm_completion: alarm setup completion
+ * @alrm_sstep: alarm setup step (see enum rtca3_alrm_set_step)
+ * @lock: device lock
+ * @ppb: ppb per cycle for each the available adjustment modes
+ * @wakeup_irq: wakeup IRQ
+ */
+struct rtca3_priv {
+ void __iomem *base;
+ struct rtc_device *rtc_dev;
+ struct reset_control *rstc;
+ struct completion set_alarm_completion;
+ atomic_t alrm_sstep;
+ spinlock_t lock;
+ struct rtca3_ppb_per_cycle ppb;
+ int wakeup_irq;
+};
+
+static void rtca3_byte_update_bits(struct rtca3_priv *priv, u8 off, u8 mask, u8 val)
+{
+ u8 tmp;
+
+ tmp = readb(priv->base + off);
+ tmp &= ~mask;
+ tmp |= (val & mask);
+ writeb(tmp, priv->base + off);
+}
+
+static u8 rtca3_alarm_handler_helper(struct rtca3_priv *priv)
+{
+ u8 val, pending;
+
+ val = readb(priv->base + RTCA3_RSR);
+ pending = val & RTCA3_RSR_AF;
+ writeb(val & ~pending, priv->base + RTCA3_RSR);
+
+ if (pending)
+ rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);
+
+ return pending;
+}
+
+static irqreturn_t rtca3_alarm_handler(int irq, void *dev_id)
+{
+ struct rtca3_priv *priv = dev_id;
+ u8 pending;
+
+ guard(spinlock)(&priv->lock);
+
+ pending = rtca3_alarm_handler_helper(priv);
+
+ return IRQ_RETVAL(pending);
+}
+
+static irqreturn_t rtca3_periodic_handler(int irq, void *dev_id)
+{
+ struct rtca3_priv *priv = dev_id;
+ u8 val, pending;
+
+ guard(spinlock)(&priv->lock);
+
+ val = readb(priv->base + RTCA3_RSR);
+ pending = val & RTCA3_RSR_PF;
+
+ if (pending) {
+ writeb(val & ~pending, priv->base + RTCA3_RSR);
+
+ if (atomic_read(&priv->alrm_sstep) > RTCA3_ALRM_SSTEP_IRQ) {
+ /* Alarm setup in progress. */
+ atomic_dec(&priv->alrm_sstep);
+
+ if (atomic_read(&priv->alrm_sstep) == RTCA3_ALRM_SSTEP_IRQ) {
+ /*
+ * We got 2 * 1/64 periodic interrupts. Disable
+ * interrupt and let alarm setup continue.
+ */
+ rtca3_byte_update_bits(priv, RTCA3_RCR1,
+ RTCA3_RCR1_PIE, 0);
+ readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, val,
+ !(val & RTCA3_RCR1_PIE),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ complete(&priv->set_alarm_completion);
+ }
+ }
+ }
+
+ return IRQ_RETVAL(pending);
+}
+
+static void rtca3_prepare_cntalrm_regs_for_read(struct rtca3_priv *priv, bool cnt)
+{
+ /* Offset b/w time and alarm registers. */
+ u8 offset = cnt ? 0 : 0xe;
+
+ /*
+ * According to HW manual (section 22.6.4. Notes on writing to and
+ * reading from registers) after writing to count registers, alarm
+ * registers, year alarm enable register, bits RCR2.AADJE, AADJP,
+ * and HR24 register, we need to do 3 empty reads before being
+ * able to fetch the registers content.
+ */
+ for (u8 i = 0; i < 3; i++) {
+ readb(priv->base + RTCA3_RSECCNT + offset);
+ readb(priv->base + RTCA3_RMINCNT + offset);
+ readb(priv->base + RTCA3_RHRCNT + offset);
+ readb(priv->base + RTCA3_RWKCNT + offset);
+ readb(priv->base + RTCA3_RDAYCNT + offset);
+ readw(priv->base + RTCA3_RYRCNT + offset);
+ if (!cnt)
+ readb(priv->base + RTCA3_RYRAREN);
+ }
+}
+
+static int rtca3_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 sec, min, hour, wday, mday, month, tmp;
+ u8 trials = 0;
+ u32 year100;
+ u16 year;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ tmp = readb(priv->base + RTCA3_RCR2);
+ if (!(tmp & RTCA3_RCR2_START))
+ return -EINVAL;
+
+ do {
+ /* Clear carry interrupt. */
+ rtca3_byte_update_bits(priv, RTCA3_RSR, RTCA3_RSR_CF, 0);
+
+ /* Read counters. */
+ sec = readb(priv->base + RTCA3_RSECCNT);
+ min = readb(priv->base + RTCA3_RMINCNT);
+ hour = readb(priv->base + RTCA3_RHRCNT);
+ wday = readb(priv->base + RTCA3_RWKCNT);
+ mday = readb(priv->base + RTCA3_RDAYCNT);
+ month = readb(priv->base + RTCA3_RMONCNT);
+ year = readw(priv->base + RTCA3_RYRCNT);
+
+ tmp = readb(priv->base + RTCA3_RSR);
+
+ /*
+ * We cannot generate carries due to reading 64Hz counter as
+ * the driver doesn't implement carry, thus, carries will be
+ * generated once per seconds. Add a timeout of 5 trials here
+ * to avoid infinite loop, if any.
+ */
+ } while ((tmp & RTCA3_RSR_CF) && ++trials < 5);
+
+ if (trials >= 5)
+ return -ETIMEDOUT;
+
+ tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECCNT_SEC, sec));
+ tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINCNT_MIN, min));
+ tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRCNT_HR, hour));
+ tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKCNT_WK, wday));
+ tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYCNT_DAY, mday));
+ tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONCNT_MONTH, month)) - 1;
+ year = FIELD_GET(RTCA3_RYRCNT_YEAR, year);
+ year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
+ tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+
+ return 0;
+}
+
+static int rtca3_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 rcr2, tmp;
+ int ret;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ /* Stop the RTC. */
+ rcr2 = readb(priv->base + RTCA3_RCR2);
+ writeb(rcr2 & ~RTCA3_RCR2_START, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
+ !(tmp & RTCA3_RCR2_START),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Update time. */
+ writeb(bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECCNT);
+ writeb(bin2bcd(tm->tm_min), priv->base + RTCA3_RMINCNT);
+ writeb(bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRCNT);
+ writeb(bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKCNT);
+ writeb(bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYCNT);
+ writeb(bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONCNT);
+ writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRCNT);
+
+ /* Make sure we can read back the counters. */
+ rtca3_prepare_cntalrm_regs_for_read(priv, true);
+
+ /* Start RTC. */
+ writeb(rcr2 | RTCA3_RCR2_START, priv->base + RTCA3_RCR2);
+ return readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
+ (tmp & RTCA3_RCR2_START),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+}
+
+static int rtca3_alarm_irq_set_helper(struct rtca3_priv *priv,
+ u8 interrupts,
+ unsigned int enabled)
+{
+ u8 tmp, val;
+
+ if (enabled) {
+ /*
+ * AIE, CIE, PIE bit indexes in RSR corresponds with
+ * those on RCR1. Same interrupts mask can be used.
+ */
+ rtca3_byte_update_bits(priv, RTCA3_RSR, interrupts, 0);
+ val = interrupts;
+ } else {
+ val = 0;
+ }
+
+ rtca3_byte_update_bits(priv, RTCA3_RCR1, interrupts, val);
+ return readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
+ ((tmp & interrupts) == val),
+ 10, RTCA3_IRQSET_TIMEOUT_US);
+}
+
+static int rtca3_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ return rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, enabled);
+}
+
+static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 sec, min, hour, wday, mday, month;
+ struct rtc_time *tm = &wkalrm->time;
+ u32 year100;
+ u16 year;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ sec = readb(priv->base + RTCA3_RSECAR);
+ min = readb(priv->base + RTCA3_RMINAR);
+ hour = readb(priv->base + RTCA3_RHRAR);
+ wday = readb(priv->base + RTCA3_RWKAR);
+ mday = readb(priv->base + RTCA3_RDAYAR);
+ month = readb(priv->base + RTCA3_RMONAR);
+ year = readw(priv->base + RTCA3_RYRAR);
+
+ tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECAR_SEC, sec));
+ tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINAR_MIN, min));
+ tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRAR_HR, hour));
+ tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKAR_DAYW, wday));
+ tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYAR_DATE, mday));
+ tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONAR_MON, month)) - 1;
+ year = FIELD_GET(RTCA3_RYRAR_YR, year);
+ year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
+ tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+
+ wkalrm->enabled = !!(readb(priv->base + RTCA3_RCR1) & RTCA3_RCR1_AIE);
+
+ return 0;
+}
+
+static int rtca3_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ struct rtc_time *tm = &wkalrm->time;
+ u8 rcr1, tmp;
+ int ret;
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ tmp = readb(priv->base + RTCA3_RCR2);
+ if (!(tmp & RTCA3_RCR2_START))
+ return -EPERM;
+
+ /* Disable AIE to prevent false interrupts. */
+ rcr1 = readb(priv->base + RTCA3_RCR1);
+ rcr1 &= ~RTCA3_RCR1_AIE;
+ writeb(rcr1, priv->base + RTCA3_RCR1);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
+ !(tmp & RTCA3_RCR1_AIE),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Set the time and enable the alarm. */
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_min), priv->base + RTCA3_RMINAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONAR);
+
+ writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRAR);
+ writeb(RTCA3_AR_ENB, priv->base + RTCA3_RYRAREN);
+
+ /* Make sure we can read back the counters. */
+ rtca3_prepare_cntalrm_regs_for_read(priv, false);
+
+ /* Need to wait for 2 * 1/64 periodic interrupts to be generated. */
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_INIT);
+ reinit_completion(&priv->set_alarm_completion);
+
+ /* Enable periodic interrupt. */
+ rcr1 |= RTCA3_RCR1_PIE;
+ writeb(rcr1, priv->base + RTCA3_RCR1);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
+ (tmp & RTCA3_RCR1_PIE),
+ 10, RTCA3_IRQSET_TIMEOUT_US);
+ }
+
+ if (ret)
+ goto setup_failed;
+
+ /* Wait for the 2 * 1/64 periodic interrupts. */
+ ret = wait_for_completion_interruptible_timeout(&priv->set_alarm_completion,
+ msecs_to_jiffies(500));
+ if (ret <= 0) {
+ ret = -ETIMEDOUT;
+ goto setup_failed;
+ }
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ ret = rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, wkalrm->enabled);
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
+ }
+
+ return ret;
+
+setup_failed:
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ /*
+ * Disable PIE to avoid interrupt storm in case HW needed more than
+ * specified timeout for setup.
+ */
+ writeb(rcr1 & ~RTCA3_RCR1_PIE, priv->base + RTCA3_RCR1);
+ readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & ~RTCA3_RCR1_PIE),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
+ }
+
+ return ret;
+}
+
+static int rtca3_read_offset(struct device *dev, long *offset)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 val, radj, cycles;
+ u32 ppb_per_cycle;
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ radj = readb(priv->base + RTCA3_RADJ);
+ val = readb(priv->base + RTCA3_RCR2);
+ }
+
+ cycles = FIELD_GET(RTCA3_RADJ_ADJ, radj);
+
+ if (!cycles) {
+ *offset = 0;
+ return 0;
+ }
+
+ if (val & RTCA3_RCR2_ADJP)
+ ppb_per_cycle = priv->ppb.ten_sec;
+ else
+ ppb_per_cycle = priv->ppb.sixty_sec;
+
+ *offset = cycles * ppb_per_cycle;
+ val = FIELD_GET(RTCA3_RADJ_PMADJ, radj);
+ if (val == RTCA3_RADJ_PMADJ_SUB)
+ *offset = -(*offset);
+
+ return 0;
+}
+
+static int rtca3_set_offset(struct device *dev, long offset)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ int cycles, cycles10, cycles60;
+ u8 radj, adjp, tmp;
+ int ret;
+
+ /*
+ * Automatic time error adjustment could be set at intervals of 10
+ * or 60 seconds.
+ */
+ cycles10 = DIV_ROUND_CLOSEST(offset, priv->ppb.ten_sec);
+ cycles60 = DIV_ROUND_CLOSEST(offset, priv->ppb.sixty_sec);
+
+ /* We can set b/w 1 and 63 clock cycles. */
+ if (cycles60 >= -RTCA3_RADJ_ADJ_MAX &&
+ cycles60 <= RTCA3_RADJ_ADJ_MAX) {
+ cycles = cycles60;
+ adjp = 0;
+ } else if (cycles10 >= -RTCA3_RADJ_ADJ_MAX &&
+ cycles10 <= RTCA3_RADJ_ADJ_MAX) {
+ cycles = cycles10;
+ adjp = RTCA3_RCR2_ADJP;
+ } else {
+ return -ERANGE;
+ }
+
+ radj = FIELD_PREP(RTCA3_RADJ_ADJ, abs(cycles));
+ if (!cycles)
+ radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_NONE);
+ else if (cycles > 0)
+ radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_ADD);
+ else
+ radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_SUB);
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ tmp = readb(priv->base + RTCA3_RCR2);
+
+ if ((tmp & RTCA3_RCR2_ADJP) != adjp) {
+ /* RADJ.PMADJ need to be set to zero before setting RCR2.ADJP. */
+ writeb(0, priv->base + RTCA3_RADJ);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, !tmp,
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ rtca3_byte_update_bits(priv, RTCA3_RCR2, RTCA3_RCR2_ADJP, adjp);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
+ ((tmp & RTCA3_RCR2_ADJP) == adjp),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+ }
+
+ writeb(radj, priv->base + RTCA3_RADJ);
+ return readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, (tmp == radj),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+}
+
+static const struct rtc_class_ops rtca3_ops = {
+ .read_time = rtca3_read_time,
+ .set_time = rtca3_set_time,
+ .read_alarm = rtca3_read_alarm,
+ .set_alarm = rtca3_set_alarm,
+ .alarm_irq_enable = rtca3_alarm_irq_enable,
+ .set_offset = rtca3_set_offset,
+ .read_offset = rtca3_read_offset,
+};
+
+static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv)
+{
+ unsigned long osc32k_rate;
+ u8 val, tmp, mask;
+ u32 sleep_us;
+ int ret;
+
+ osc32k_rate = clk_get_rate(clk);
+ if (!osc32k_rate)
+ return -EINVAL;
+
+ sleep_us = DIV_ROUND_UP_ULL(1000000ULL, osc32k_rate) * 6;
+
+ priv->ppb.ten_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 10));
+ priv->ppb.sixty_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 60));
+
+ /*
+ * According to HW manual (section 22.4.2. Clock and count mode setting procedure)
+ * we need to wait at least 6 cycles of the 32KHz clock after clock was enabled.
+ */
+ usleep_range(sleep_us, sleep_us + 10);
+
+ /* Disable all interrupts. */
+ mask = RTCA3_RCR1_AIE | RTCA3_RCR1_CIE | RTCA3_RCR1_PIE;
+ ret = rtca3_alarm_irq_set_helper(priv, mask, 0);
+ if (ret)
+ return ret;
+
+ mask = RTCA3_RCR2_START | RTCA3_RCR2_HR24;
+ val = readb(priv->base + RTCA3_RCR2);
+ /* Nothing to do if already started in 24 hours and calendar count mode. */
+ if ((val & mask) == mask)
+ return 0;
+
+ /* Reconfigure the RTC in 24 hours and calendar count mode. */
+ mask = RTCA3_RCR2_START | RTCA3_RCR2_CNTMD;
+ writeb(0, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * Set 24 hours mode. According to HW manual (section 22.3.19. RTC Control
+ * Register 2) this needs to be done separate from stop operation.
+ */
+ mask = RTCA3_RCR2_HR24;
+ val = RTCA3_RCR2_HR24;
+ writeb(val, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, (tmp & mask),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Execute reset. */
+ mask = RTCA3_RCR2_RESET;
+ writeb(val | RTCA3_RCR2_RESET, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask),
+ 10, RTCA3_RESET_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * According to HW manual (section 22.6.3. Notes on writing to and reading
+ * from registers) after reset we need to wait 6 clock cycles before
+ * writing to RTC registers.
+ */
+ usleep_range(sleep_us, sleep_us + 10);
+
+ /* Set no adjustment. */
+ writeb(0, priv->base + RTCA3_RADJ);
+ ret = readb_poll_timeout(priv->base + RTCA3_RADJ, tmp, !tmp, 10,
+ RTCA3_DEFAULT_TIMEOUT_US);
+
+ /* Start the RTC and enable automatic time error adjustment. */
+ mask = RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
+ val |= RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
+ writeb(val, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, ((tmp & mask) == mask),
+ 10, RTCA3_START_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * According to HW manual (section 22.6.4. Notes on writing to and reading
+ * from registers) we need to wait 1/128 seconds while the clock is operating
+ * (RCR2.START bit = 1) to be able to read the counters after a return from
+ * reset.
+ */
+ usleep_range(8000, 9000);
+
+ /* Set period interrupt to 1/64 seconds. It is necessary for alarm setup. */
+ val = FIELD_PREP(RTCA3_RCR1_PES, RTCA3_RCR1_PES_1_64_SEC);
+ rtca3_byte_update_bits(priv, RTCA3_RCR1, RTCA3_RCR1_PES, val);
+ return readb_poll_timeout(priv->base + RTCA3_RCR1, tmp, ((tmp & RTCA3_RCR1_PES) == val),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+}
+
+static int rtca3_request_irqs(struct platform_device *pdev, struct rtca3_priv *priv)
+{
+ struct device *dev = &pdev->dev;
+ int ret, irq;
+
+ irq = platform_get_irq_byname(pdev, "alarm");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get alarm IRQ!\n");
+
+ ret = devm_request_irq(dev, irq, rtca3_alarm_handler, 0, "rtca3-alarm", priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request alarm IRQ!\n");
+ priv->wakeup_irq = irq;
+
+ irq = platform_get_irq_byname(pdev, "period");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get period IRQ!\n");
+
+ ret = devm_request_irq(dev, irq, rtca3_periodic_handler, 0, "rtca3-period", priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request period IRQ!\n");
+
+ /*
+ * Driver doesn't implement carry handler. Just get the IRQ here
+ * for backward compatibility, in case carry support will be added later.
+ */
+ irq = platform_get_irq_byname(pdev, "carry");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get carry IRQ!\n");
+
+ return 0;
+}
+
+static void rtca3_action(void *data)
+{
+ struct device *dev = data;
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_assert(priv->rstc);
+ if (ret)
+ dev_err(dev, "Failed to de-assert reset!");
+
+ ret = pm_runtime_put_sync(dev);
+ if (ret < 0)
+ dev_err(dev, "Failed to runtime suspend!");
+}
+
+static int rtca3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtca3_priv *priv;
+ struct clk *clk;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ priv->rstc = devm_reset_control_get_shared(dev, NULL);
+ if (IS_ERR(priv->rstc))
+ return PTR_ERR(priv->rstc);
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(priv->rstc);
+ if (ret) {
+ pm_runtime_put_sync(dev);
+ return ret;
+ }
+
+ dev_set_drvdata(dev, priv);
+ ret = devm_add_action_or_reset(dev, rtca3_action, dev);
+ if (ret)
+ return ret;
+
+ /*
+ * This must be an always-on clock to keep the RTC running even after
+ * driver is unbinded.
+ */
+ clk = devm_clk_get_enabled(dev, "counter");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ spin_lock_init(&priv->lock);
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
+ init_completion(&priv->set_alarm_completion);
+
+ ret = rtca3_initial_setup(clk, priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup the RTC!\n");
+
+ ret = rtca3_request_irqs(pdev, priv);
+ if (ret)
+ return ret;
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ priv->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(priv->rtc_dev))
+ return PTR_ERR(priv->rtc_dev);
+
+ priv->rtc_dev->ops = &rtca3_ops;
+ priv->rtc_dev->max_user_freq = 256;
+ priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
+
+ return devm_rtc_register_device(priv->rtc_dev);
+}
+
+static void rtca3_remove(struct platform_device *pdev)
+{
+ struct rtca3_priv *priv = platform_get_drvdata(pdev);
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ /*
+ * Disable alarm, periodic interrupts. The RTC device cannot
+ * power up the system.
+ */
+ rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE | RTCA3_RCR1_PIE, 0);
+}
+
+static int rtca3_suspend(struct device *dev)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+
+ if (!device_may_wakeup(dev))
+ return 0;
+
+ /* Alarm setup in progress. */
+ if (atomic_read(&priv->alrm_sstep) != RTCA3_ALRM_SSTEP_DONE)
+ return -EBUSY;
+
+ enable_irq_wake(priv->wakeup_irq);
+
+ return 0;
+}
+
+static int rtca3_clean_alarm(struct rtca3_priv *priv)
+{
+ struct rtc_device *rtc_dev = priv->rtc_dev;
+ time64_t alarm_time, now;
+ struct rtc_wkalrm alarm;
+ struct rtc_time tm;
+ u8 pending;
+ int ret;
+
+ ret = rtc_read_alarm(rtc_dev, &alarm);
+ if (ret)
+ return ret;
+
+ if (!alarm.enabled)
+ return 0;
+
+ ret = rtc_read_time(rtc_dev, &tm);
+ if (ret)
+ return ret;
+
+ alarm_time = rtc_tm_to_time64(&alarm.time);
+ now = rtc_tm_to_time64(&tm);
+ if (alarm_time >= now)
+ return 0;
+
+ /*
+ * Heuristically, it has been determined that when returning from deep
+ * sleep state the RTCA3_RSR.AF is zero even though the alarm expired.
+ * Call again the rtc_update_irq() if alarm helper detects this.
+ */
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ pending = rtca3_alarm_handler_helper(priv);
+ if (!pending)
+ rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);
+
+ return 0;
+}
+
+static int rtca3_resume(struct device *dev)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+
+ if (!device_may_wakeup(dev))
+ return 0;
+
+ disable_irq_wake(priv->wakeup_irq);
+
+ /*
+ * According to the HW manual (section 22.6.4 Notes on writing to
+ * and reading from registers) we need to wait 1/128 seconds while
+ * RCR2.START = 1 to be able to read the counters after a return from low
+ * power consumption state.
+ */
+ mdelay(8);
+
+ /*
+ * The alarm cannot wake the system from deep sleep states. In case
+ * we return from deep sleep states and the alarm expired we need
+ * to disable it to avoid failures when setting another alarm.
+ */
+ return rtca3_clean_alarm(priv);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rtca3_pm_ops, rtca3_suspend, rtca3_resume);
+
+static const struct of_device_id rtca3_of_match[] = {
+ { .compatible = "renesas,rz-rtca3", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rtca3_of_match);
+
+static struct platform_driver rtca3_platform_driver = {
+ .driver = {
+ .name = "rtc-rtca3",
+ .pm = pm_ptr(&rtca3_pm_ops),
+ .of_match_table = rtca3_of_match,
+ },
+ .probe = rtca3_probe,
+ .remove = rtca3_remove,
+};
+module_platform_driver(rtca3_platform_driver);
+
+MODULE_DESCRIPTION("Renesas RTCA-3 RTC driver");
+MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rtd119x.c b/drivers/rtc/rtc-rtd119x.c
index 29662dfd56fe..85a138db81d7 100644
--- a/drivers/rtc/rtc-rtd119x.c
+++ b/drivers/rtc/rtc-rtd119x.c
@@ -228,7 +228,7 @@ static void rtd119x_rtc_remove(struct platform_device *pdev)
static struct platform_driver rtd119x_rtc_driver = {
.probe = rtd119x_rtc_probe,
- .remove_new = rtd119x_rtc_remove,
+ .remove = rtd119x_rtc_remove,
.driver = {
.name = "rtd1295-rtc",
.of_match_table = rtd119x_rtc_dt_ids,
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index 2f001c59c61d..868d1b1eb0f4 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -120,8 +120,9 @@ static ssize_t timestamp0_show(struct device *dev,
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
struct rtc_time tm;
- int ret, count;
+ unsigned int count;
u8 date[6];
+ int ret;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret)
@@ -156,7 +157,8 @@ static ssize_t timestamp0_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
- int ret, count;
+ unsigned int count;
+ int ret;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret)
diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
index 56ebbd4d0481..cb220807d925 100644
--- a/drivers/rtc/rtc-rzn1.c
+++ b/drivers/rtc/rtc-rzn1.c
@@ -7,7 +7,7 @@
* - 2022 Schneider Electric
*
* Authors:
- * - Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
+ * - Michel Pollet <buserror@gmail.com>
* - Miquel Raynal <miquel.raynal@bootlin.com>
*/
@@ -35,13 +35,13 @@
#define RZN1_RTC_CTL2_WUST BIT(5)
#define RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST)
-#define RZN1_RTC_SEC 0x14
-#define RZN1_RTC_MIN 0x18
-#define RZN1_RTC_HOUR 0x1c
-#define RZN1_RTC_WEEK 0x20
-#define RZN1_RTC_DAY 0x24
-#define RZN1_RTC_MONTH 0x28
-#define RZN1_RTC_YEAR 0x2c
+#define RZN1_RTC_TIME 0x30
+#define RZN1_RTC_TIME_MIN_SHIFT 8
+#define RZN1_RTC_TIME_HOUR_SHIFT 16
+#define RZN1_RTC_CAL 0x34
+#define RZN1_RTC_CAL_DAY_SHIFT 8
+#define RZN1_RTC_CAL_MON_SHIFT 16
+#define RZN1_RTC_CAL_YEAR_SHIFT 24
#define RZN1_RTC_SUBU 0x38
#define RZN1_RTC_SUBU_DEV BIT(7)
@@ -52,12 +52,8 @@
#define RZN1_RTC_ALW 0x48
#define RZN1_RTC_SECC 0x4c
-#define RZN1_RTC_MINC 0x50
-#define RZN1_RTC_HOURC 0x54
-#define RZN1_RTC_WEEKC 0x58
-#define RZN1_RTC_DAYC 0x5c
-#define RZN1_RTC_MONTHC 0x60
-#define RZN1_RTC_YEARC 0x64
+#define RZN1_RTC_TIMEC 0x68
+#define RZN1_RTC_CALC 0x6c
struct rzn1_rtc {
struct rtc_device *rtcdev;
@@ -66,26 +62,18 @@ struct rzn1_rtc {
static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
{
- tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC);
- tm->tm_min = readl(rtc->base + RZN1_RTC_MINC);
- tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC);
- tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC);
- tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC);
- tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC);
- tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC);
-}
-
-static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm)
-{
- time64_t time;
- unsigned int days;
- u32 secs;
+ u32 val;
- time = rtc_tm_to_time64(tm);
- days = div_s64_rem(time, 86400, &secs);
+ val = readl(rtc->base + RZN1_RTC_TIMEC);
+ tm->tm_sec = bcd2bin(val);
+ tm->tm_min = bcd2bin(val >> RZN1_RTC_TIME_MIN_SHIFT);
+ tm->tm_hour = bcd2bin(val >> RZN1_RTC_TIME_HOUR_SHIFT);
- /* day of the week, 1970-01-01 was a Thursday */
- return (days + 4) % 7;
+ val = readl(rtc->base + RZN1_RTC_CALC);
+ tm->tm_wday = val & 0x0f;
+ tm->tm_mday = bcd2bin(val >> RZN1_RTC_CAL_DAY_SHIFT);
+ tm->tm_mon = bcd2bin(val >> RZN1_RTC_CAL_MON_SHIFT) - 1;
+ tm->tm_year = bcd2bin(val >> RZN1_RTC_CAL_YEAR_SHIFT) + 100;
}
static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -103,17 +91,9 @@ static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
rzn1_rtc_get_time_snapshot(rtc, tm);
secs = readl(rtc->base + RZN1_RTC_SECC);
- if (tm->tm_sec != secs)
+ if (tm->tm_sec != bcd2bin(secs))
rzn1_rtc_get_time_snapshot(rtc, tm);
- tm->tm_sec = bcd2bin(tm->tm_sec);
- tm->tm_min = bcd2bin(tm->tm_min);
- tm->tm_hour = bcd2bin(tm->tm_hour);
- tm->tm_wday = bcd2bin(tm->tm_wday);
- tm->tm_mday = bcd2bin(tm->tm_mday);
- tm->tm_mon = bcd2bin(tm->tm_mon);
- tm->tm_year = bcd2bin(tm->tm_year);
-
return 0;
}
@@ -123,14 +103,6 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
u32 val;
int ret;
- tm->tm_sec = bin2bcd(tm->tm_sec);
- tm->tm_min = bin2bcd(tm->tm_min);
- tm->tm_hour = bin2bcd(tm->tm_hour);
- tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm));
- tm->tm_mday = bin2bcd(tm->tm_mday);
- tm->tm_mon = bin2bcd(tm->tm_mon);
- tm->tm_year = bin2bcd(tm->tm_year);
-
val = readl(rtc->base + RZN1_RTC_CTL2);
if (!(val & RZN1_RTC_CTL2_STOPPED)) {
/* Hold the counter if it was counting up */
@@ -144,13 +116,17 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
return ret;
}
- writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC);
- writel(tm->tm_min, rtc->base + RZN1_RTC_MIN);
- writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR);
- writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK);
- writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY);
- writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH);
- writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR);
+ val = bin2bcd(tm->tm_sec);
+ val |= bin2bcd(tm->tm_min) << RZN1_RTC_TIME_MIN_SHIFT;
+ val |= bin2bcd(tm->tm_hour) << RZN1_RTC_TIME_HOUR_SHIFT;
+ writel(val, rtc->base + RZN1_RTC_TIME);
+
+ val = tm->tm_wday;
+ val |= bin2bcd(tm->tm_mday) << RZN1_RTC_CAL_DAY_SHIFT;
+ val |= bin2bcd(tm->tm_mon + 1) << RZN1_RTC_CAL_MON_SHIFT;
+ val |= bin2bcd(tm->tm_year - 100) << RZN1_RTC_CAL_YEAR_SHIFT;
+ writel(val, rtc->base + RZN1_RTC_CAL);
+
writel(0, rtc->base + RZN1_RTC_CTL2);
return 0;
@@ -405,7 +381,7 @@ MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match);
static struct platform_driver rzn1_rtc_driver = {
.probe = rzn1_rtc_probe,
- .remove_new = rzn1_rtc_remove,
+ .remove = rzn1_rtc_remove,
.driver = {
.name = "rzn1-rtc",
.of_match_table = rzn1_rtc_of_match,
@@ -413,7 +389,7 @@ static struct platform_driver rzn1_rtc_driver = {
};
module_platform_driver(rzn1_rtc_driver);
-MODULE_AUTHOR("Michel Pollet <Michel.Pollet@bp.renesas.com");
+MODULE_AUTHOR("Michel Pollet <buserror@gmail.com>");
MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
MODULE_DESCRIPTION("RZ/N1 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 282238818f63..c0ac3bdb2f42 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -597,7 +597,7 @@ MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
- .remove_new = s3c_rtc_remove,
+ .remove = s3c_rtc_remove,
.driver = {
.name = "s3c-rtc",
.pm = &s3c_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 0b2cfa8ca05b..13799b1abca1 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -341,7 +341,7 @@ MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
static struct platform_driver sa1100_rtc_driver = {
.probe = sa1100_rtc_probe,
- .remove_new = sa1100_rtc_remove,
+ .remove = sa1100_rtc_remove,
.driver = {
.name = "sa1100-rtc",
.pm = &sa1100_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 27a191fa3704..a5df521876ba 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -678,7 +678,7 @@ static struct platform_driver sh_rtc_platform_driver __refdata = {
.pm = &sh_rtc_pm_ops,
.of_match_table = sh_rtc_of_match,
},
- .remove_new = __exit_p(sh_rtc_remove),
+ .remove = __exit_p(sh_rtc_remove),
};
module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe);
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index 1df5c7e94198..26eed927f8b3 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -475,7 +475,7 @@ MODULE_DEVICE_TABLE(of, spear_rtc_id_table);
static struct platform_driver spear_rtc_driver = {
.probe = spear_rtc_probe,
- .remove_new = spear_rtc_remove,
+ .remove = spear_rtc_remove,
.shutdown = spear_rtc_shutdown,
.driver = {
.name = "rtc-spear",
diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c
index d492a2d26600..c6d4522411b3 100644
--- a/drivers/rtc/rtc-st-lpc.c
+++ b/drivers/rtc/rtc-st-lpc.c
@@ -218,15 +218,14 @@ static int st_rtc_probe(struct platform_device *pdev)
return -EINVAL;
}
- ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler, 0,
- pdev->name, rtc);
+ ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler,
+ IRQF_NO_AUTOEN, pdev->name, rtc);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq);
return ret;
}
enable_irq_wake(rtc->irq);
- disable_irq(rtc->irq);
rtc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(rtc->clk))
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index 3e4f2ee22b0b..9f1a019ec8af 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -1287,7 +1287,7 @@ static const struct dev_pm_ops stm32_rtc_pm_ops = {
static struct platform_driver stm32_rtc_driver = {
.probe = stm32_rtc_probe,
- .remove_new = stm32_rtc_remove,
+ .remove = stm32_rtc_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &stm32_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index 7566d0a44af8..7afcd14aeee5 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(of, rtc_dt_ids);
static struct platform_driver stmp3xxx_rtcdrv = {
.probe = stmp3xxx_rtc_probe,
- .remove_new = stmp3xxx_rtc_remove,
+ .remove = stmp3xxx_rtc_remove,
.driver = {
.name = "stmp3xxx-rtc",
.pm = &stmp3xxx_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c
index 20c7e97c2fc8..9b1ce0e8ba27 100644
--- a/drivers/rtc/rtc-sunplus.c
+++ b/drivers/rtc/rtc-sunplus.c
@@ -344,7 +344,7 @@ static SIMPLE_DEV_PM_OPS(sp_rtc_pm_ops, sp_rtc_suspend, sp_rtc_resume);
static struct platform_driver sp_rtc_driver = {
.probe = sp_rtc_probe,
- .remove_new = sp_rtc_remove,
+ .remove = sp_rtc_remove,
.driver = {
.name = "sp7021-rtc",
.of_match_table = sp_rtc_of_match,
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 441e0a66b215..79a3102c8354 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -399,7 +399,7 @@ static void tegra_rtc_shutdown(struct platform_device *pdev)
static struct platform_driver tegra_rtc_driver = {
.probe = tegra_rtc_probe,
- .remove_new = tegra_rtc_remove,
+ .remove = tegra_rtc_remove,
.shutdown = tegra_rtc_shutdown,
.driver = {
.name = "tegra_rtc",
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 20faf08c254c..e796729fc817 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -317,7 +317,7 @@ static struct platform_driver tps6586x_rtc_driver = {
.pm = &tps6586x_pm_ops,
},
.probe = tps6586x_rtc_probe,
- .remove_new = tps6586x_rtc_remove,
+ .remove = tps6586x_rtc_remove,
};
module_platform_driver(tps6586x_rtc_driver);
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 4e24c12004f1..794429182b34 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -673,7 +673,7 @@ MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
static struct platform_driver twl4030rtc_driver = {
.probe = twl_rtc_probe,
- .remove_new = twl_rtc_remove,
+ .remove = twl_rtc_remove,
.shutdown = twl_rtc_shutdown,
.driver = {
.name = "twl_rtc",
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
index ccfa76513a2c..c8b568498016 100644
--- a/drivers/rtc/rtc-vt8500.c
+++ b/drivers/rtc/rtc-vt8500.c
@@ -251,7 +251,7 @@ MODULE_DEVICE_TABLE(of, wmt_dt_ids);
static struct platform_driver vt8500_rtc_driver = {
.probe = vt8500_rtc_probe,
- .remove_new = vt8500_rtc_remove,
+ .remove = vt8500_rtc_remove,
.driver = {
.name = "vt8500-rtc",
.of_match_table = wmt_dt_ids,
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
index 3c773cff2b39..6797eb4d2e49 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -459,7 +459,7 @@ static SIMPLE_DEV_PM_OPS(wm8350_rtc_pm_ops, wm8350_rtc_suspend,
static struct platform_driver wm8350_rtc_driver = {
.probe = wm8350_rtc_probe,
- .remove_new = wm8350_rtc_remove,
+ .remove = wm8350_rtc_remove,
.driver = {
.name = "wm8350-rtc",
.pm = &wm8350_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c
index f78efc9760c0..0813ea1a03c2 100644
--- a/drivers/rtc/rtc-xgene.c
+++ b/drivers/rtc/rtc-xgene.c
@@ -263,7 +263,7 @@ MODULE_DEVICE_TABLE(of, xgene_rtc_of_match);
static struct platform_driver xgene_rtc_driver = {
.probe = xgene_rtc_probe,
- .remove_new = xgene_rtc_remove,
+ .remove = xgene_rtc_remove,
.driver = {
.name = "xgene-rtc",
.pm = &xgene_rtc_pm_ops,
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index 08ed171bdab4..af1abb69d1e3 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -382,7 +382,7 @@ MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match);
static struct platform_driver xlnx_rtc_driver = {
.probe = xlnx_rtc_probe,
- .remove_new = xlnx_rtc_remove,
+ .remove = xlnx_rtc_remove,
.driver = {
.name = KBUILD_MODNAME,
.pm = &xlnx_rtc_pm_ops,
diff --git a/include/linux/mfd/88pm886.h b/include/linux/mfd/88pm886.h
index 133aa302e492..85eca44f39ab 100644
--- a/include/linux/mfd/88pm886.h
+++ b/include/linux/mfd/88pm886.h
@@ -31,6 +31,15 @@
#define PM886_INT_WC BIT(1)
#define PM886_INT_MASK_MODE BIT(2)
+#define PM886_REG_RTC_CNT1 0xd1
+#define PM886_REG_RTC_CNT2 0xd2
+#define PM886_REG_RTC_CNT3 0xd3
+#define PM886_REG_RTC_CNT4 0xd4
+#define PM886_REG_RTC_SPARE1 0xea
+#define PM886_REG_RTC_SPARE2 0xeb
+#define PM886_REG_RTC_SPARE3 0xec
+#define PM886_REG_RTC_SPARE4 0xed
+#define PM886_REG_RTC_SPARE5 0xee
#define PM886_REG_RTC_SPARE6 0xef
#define PM886_REG_BUCK_EN 0x08
diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h
index 9465d5405fe2..373ba77071c6 100644
--- a/include/linux/rtc/m48t59.h
+++ b/include/linux/rtc/m48t59.h
@@ -56,6 +56,9 @@ struct m48t59_plat_data {
void __iomem *ioaddr;
/* offset to RTC registers, automatically set according to the type */
unsigned int offset;
+
+ /* YY digits (in RTC) are offset, i.e. year is 1900 + yy_offset + YY */
+ int yy_offset;
};
#endif /* _LINUX_RTC_M48T59_H_ */