summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-23 15:59:02 +0100
committerMark Brown <broonie@kernel.org>2026-10-23 15:59:02 +0100
commit894ce84eaff7fc5dc4e61eb7053398c849495535 (patch)
tree55cace2d63d78b309592f01296be68c7b25216c9
parent6f570494c89d1c963762d90a636c8f68af76fbc7 (diff)
parentc1c260266abf5d600bc7ce8efbd274ca86f9a4aa (diff)
downloadlinux-next-894ce84eaff7fc5dc4e61eb7053398c849495535.tar.gz
linux-next-894ce84eaff7fc5dc4e61eb7053398c849495535.zip
Merge branch 'rtc-next' of https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml6
-rw-r--r--Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml18
-rw-r--r--Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml3
-rw-r--r--Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml37
-rw-r--r--Documentation/devicetree/bindings/rtc/ricoh,r2223x.yaml58
-rw-r--r--Documentation/devicetree/bindings/rtc/rtc.yaml1
-rw-r--r--drivers/firmware/raspberrypi.c24
-rw-r--r--drivers/platform/x86/amd/pmc/pmc.c5
-rw-r--r--drivers/rtc/Kconfig58
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c8
-rw-r--r--drivers/rtc/rtc-abx80x.c643
-rw-r--r--drivers/rtc/rtc-ac100.c10
-rw-r--r--drivers/rtc/rtc-asm9260.c4
-rw-r--r--drivers/rtc/rtc-atcrtc100.c3
-rw-r--r--drivers/rtc/rtc-bd70528.c5
-rw-r--r--drivers/rtc/rtc-cmos.c32
-rw-r--r--drivers/rtc/rtc-ds1305.c4
-rw-r--r--drivers/rtc/rtc-ds1307.c14
-rw-r--r--drivers/rtc/rtc-ds1343.c6
-rw-r--r--drivers/rtc/rtc-ds1685.c3
-rw-r--r--drivers/rtc/rtc-ds3232.c50
-rw-r--r--drivers/rtc/rtc-ftrtc010.c73
-rw-r--r--drivers/rtc/rtc-hym8563.c6
-rw-r--r--drivers/rtc/rtc-m41t80.c12
-rw-r--r--drivers/rtc/rtc-mcp795.c3
-rw-r--r--drivers/rtc/rtc-mpfs.c4
-rw-r--r--drivers/rtc/rtc-mt6397.c91
-rw-r--r--drivers/rtc/rtc-nct3018y.c94
-rw-r--r--drivers/rtc/rtc-nct6694.c8
-rw-r--r--drivers/rtc/rtc-nvidia-vrs10.c5
-rw-r--r--drivers/rtc/rtc-omap.c5
-rw-r--r--drivers/rtc/rtc-pcf2123.c5
-rw-r--r--drivers/rtc/rtc-pcf8563.c5
-rw-r--r--drivers/rtc/rtc-raspberrypi.c278
-rw-r--r--drivers/rtc/rtc-rs5c372.c52
-rw-r--r--drivers/rtc/rtc-rv3029c2.c5
-rw-r--r--drivers/rtc/rtc-rx8010.c4
-rw-r--r--drivers/rtc/rtc-rx8025.c10
-rw-r--r--drivers/rtc/rtc-rzn1.c52
-rw-r--r--drivers/rtc/rtc-stm32.c4
-rw-r--r--drivers/rtc/rtc-sun6i.c23
-rw-r--r--drivers/soc/ti/pm33xx.c2
-rw-r--r--include/linux/mfd/mt6397/rtc.h7
-rw-r--r--include/linux/rtc.h5
-rw-r--r--include/linux/rtc/rtc-omap.h2
-rw-r--r--include/soc/bcm2835/raspberrypi-firmware.h2
-rw-r--r--tools/testing/selftests/rtc/rtctest.c60
48 files changed, 1326 insertions, 484 deletions
diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
index 983ea80eaec9..dc71fd57834e 100644
--- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
+++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml
@@ -133,6 +133,11 @@ properties:
required:
- compatible
+ trickle-voltage-millivolt:
+ $ref: /schemas/rtc/rtc.yaml#/properties/trickle-voltage-millivolt
+ minimum: 1300
+ maximum: 5000
+
required:
- compatible
- mboxes
@@ -144,6 +149,7 @@ examples:
firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
mboxes = <&mailbox>;
+ trickle-voltage-millivolt = <3300>;
firmware_clocks: clocks {
compatible = "raspberrypi,firmware-clocks";
diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml b/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml
index 355b0598411a..d105570bcd5a 100644
--- a/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml
+++ b/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/rtc/abracon,abx80x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Abracon ABX80X I2C ultra low power RTC/Alarm chip
+title: Abracon ABX80X (I2C) and ABX81X (SPI) ultra low power RTC/Alarm chips
maintainers:
- linux-rtc@vger.kernel.org
@@ -21,10 +21,12 @@ properties:
- abracon,ab0803
- abracon,ab0804
- abracon,ab0805
+ - abracon,ab0815
- abracon,ab1801
- abracon,ab1803
- abracon,ab1804
- abracon,ab1805
+ - abracon,ab1815
- microcrystal,rv1805
reg:
@@ -61,6 +63,7 @@ required:
- reg
allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
- $ref: rtc.yaml#
- if:
properties:
@@ -73,6 +76,8 @@ allOf:
- abracon,ab1804
- abracon,ab0805
- abracon,ab1805
+ - abracon,ab0815
+ - abracon,ab1815
then:
properties:
abracon,tc-diode: false
@@ -96,3 +101,14 @@ examples:
interrupts = <44 IRQ_TYPE_EDGE_FALLING>;
};
};
+
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@0 {
+ compatible = "abracon,ab1815";
+ reg = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
index f2b91186ed37..ebe35f893f8c 100644
--- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
@@ -19,6 +19,7 @@ properties:
- enum:
- allwinner,sun6i-a31-rtc
- allwinner,sun8i-a23-rtc
+ - allwinner,sun8i-b288-rtc
- allwinner,sun8i-h3-rtc
- allwinner,sun8i-r40-rtc
- allwinner,sun8i-v3-rtc
@@ -82,6 +83,7 @@ allOf:
contains:
enum:
- allwinner,sun8i-a23-rtc
+ - allwinner,sun8i-b288-rtc
- allwinner,sun8i-r40-rtc
- allwinner,sun8i-v3-rtc
@@ -162,6 +164,7 @@ allOf:
compatible:
contains:
enum:
+ - allwinner,sun8i-b288-rtc
- allwinner,sun8i-r40-rtc
- allwinner,sun50i-h616-rtc
- allwinner,sun50i-r329-rtc
diff --git a/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml b/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
index ea7b039a91e7..5a869e6c0ae7 100644
--- a/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml
@@ -14,14 +14,16 @@ properties:
oneOf:
- items:
- enum:
- - renesas,r9a06g032-rtc
- - const: renesas,rzn1-rtc
+ - renesas,r9a06g032-rtc # RZ/N1D
+ - const: renesas,rzn1-rtc # RZ/N1
- - const: renesas,r9a09g077-rtc
+ - const: renesas,r9a09g077-rtc # RZ/T2H
- items:
- - const: renesas,r9a09g087-rtc
- - const: renesas,r9a09g077-rtc
+ - const: renesas,r9a09g087-rtc # RZ/N2H
+ - const: renesas,r9a09g077-rtc # RZ/T2H
+
+ - const: renesas,r8a78000-rtc # R-Car X5H
reg:
maxItems: 1
@@ -49,11 +51,12 @@ properties:
power-domains:
maxItems: 1
+ resets:
+ maxItems: 1
+
required:
- compatible
- reg
- - interrupts
- - interrupt-names
- clocks
- clock-names
- power-domains
@@ -66,6 +69,7 @@ allOf:
compatible:
contains:
enum:
+ - renesas,r8a78000-rtc
- renesas,r9a09g077-rtc
- renesas,r9a09g087-rtc
then:
@@ -75,6 +79,24 @@ allOf:
clock-names:
minItems: 2
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r8a78000-rtc
+ then:
+ properties:
+ interrupts: false
+ interrupt-names: false
+ required:
+ - resets
+ else:
+ properties:
+ resets: false
+ required:
+ - interrupts
+ - interrupt-names
+
unevaluatedProperties: false
examples:
@@ -91,5 +113,4 @@ examples:
clocks = <&sysctrl R9A06G032_HCLK_RTC>;
clock-names = "hclk";
power-domains = <&sysctrl>;
- start-year = <2000>;
};
diff --git a/Documentation/devicetree/bindings/rtc/ricoh,r2223x.yaml b/Documentation/devicetree/bindings/rtc/ricoh,r2223x.yaml
new file mode 100644
index 000000000000..e64a1ee378e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/ricoh,r2223x.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/ricoh,r2223x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ricoh R2223x Real-Time Clock
+
+maintainers:
+ - Heiko Schocher <hs@nabladev.com>
+
+allOf:
+ - $ref: rtc.yaml#
+
+properties:
+ compatible:
+ const: ricoh,r2223x
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ "#clock-cells":
+ const: 0
+
+ ricoh,eco-mode:
+ type: boolean
+ description:
+ Put the RTC into eco mode, which lowers its current consumption while
+ running from the backup supply. Set this on boards where the RTC is
+ expected to keep time on a small backup cell.
+
+ start-year: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@32 {
+ compatible = "ricoh,r2223x";
+ reg = <0x32>;
+ interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+ #clock-cells = <0>;
+ ricoh,eco-mode;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/rtc/rtc.yaml b/Documentation/devicetree/bindings/rtc/rtc.yaml
index efb66df82782..e46d50b1063e 100644
--- a/Documentation/devicetree/bindings/rtc/rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/rtc.yaml
@@ -51,6 +51,7 @@ properties:
if trickle charger should be enabled.
trickle-voltage-millivolt:
+ $ref: /schemas/types.yaml#/definitions/uint32
description:
Selected voltage for trickle charger. Should be given
if trickle charger should be enabled and the trickle voltage is different
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index 0aa322e9a2e7..443459c8c90f 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -24,6 +24,7 @@
static struct platform_device *rpi_hwmon;
static struct platform_device *rpi_clk;
+static struct platform_device *rpi_rtc;
struct rpi_firmware {
struct mbox_client cl;
@@ -231,6 +232,26 @@ static void rpi_register_clk_driver(struct device *dev)
-1, NULL, 0);
}
+static void rpi_register_rtc_driver(struct device *dev)
+{
+ struct platform_device *pdev;
+
+ /*
+ * Check if our model of Raspberry Pi board is from the 5th gen
+ * as the RTC is only present on that model.
+ */
+ if (!of_machine_is_compatible("brcm,bcm2712"))
+ return;
+
+ pdev = platform_device_register_data(dev, "raspberrypi-rtc",
+ -1, NULL, 0);
+
+ if (IS_ERR(pdev))
+ return;
+
+ rpi_rtc = pdev;
+}
+
unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id)
{
struct rpi_firmware_clk_rate_request msg =
@@ -305,6 +326,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
rpi_firmware_print_firmware_revision(fw);
rpi_register_hwmon_driver(dev, fw);
rpi_register_clk_driver(dev);
+ rpi_register_rtc_driver(dev);
return 0;
}
@@ -327,6 +349,8 @@ static void rpi_firmware_remove(struct platform_device *pdev)
rpi_hwmon = NULL;
platform_device_unregister(rpi_clk);
rpi_clk = NULL;
+ platform_device_unregister(rpi_rtc);
+ rpi_rtc = NULL;
rpi_firmware_put(fw);
}
diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
index ef07b24bfeba..67731cd7c02b 100644
--- a/drivers/platform/x86/amd/pmc/pmc.c
+++ b/drivers/platform/x86/amd/pmc/pmc.c
@@ -14,6 +14,7 @@
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@@ -649,7 +650,6 @@ static int amd_pmc_wa_irq1(struct amd_pmc_dev *pdev)
static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
{
- struct rtc_device *rtc_device;
time64_t then, now, duration;
struct rtc_wkalrm alarm;
struct rtc_time tm;
@@ -665,7 +665,8 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
if (pdev->major < 64 || (pdev->major == 64 && pdev->minor < 53))
return 0;
- rtc_device = rtc_class_open("rtc0");
+ struct rtc_device *rtc_device __free(rtc_class_close) =
+ rtc_class_open("rtc0");
if (!rtc_device)
return 0;
rc = rtc_read_next_alarm(rtc_device, &alarm);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 05b9233b9418..1e863f1d36fd 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -30,6 +30,27 @@ config RTC_HCTOSYS
the value read from a specified RTC device. This is useful to avoid
unnecessary fsck runs at boot time, and to network better.
+config RTC_HCTOSYS_TIME32_LIMIT
+ bool "Reject RTC dates after the 2038 cutoff"
+ depends on RTC_HCTOSYS && COMPAT_32BIT_TIME && !64BIT
+ default y
+ help
+ Reject RTC dates after 03:14:07 UTC on 19 January 2038 when
+ initializing the system clock in order to work around broken
+ RTC implementations that produce nondeterministic timestamps
+ without a working backup battery.
+
+ A rejected date leaves system time unchanged, normally near
+ the Unix epoch, and the RTC's hctosys sysfs attribute reads
+ 0. Userspace must supply the time if no other source has
+ initialized it.
+
+ Say Y here if the kernel may have to run old time32 userspace on
+ hardware that can produce unpredictable RTC timestamps. If the
+ kernel is intended to only run time64 compatible userspace and
+ continue working past 2038, you must pick N here in order to
+ have a working RTC_HCTOSYS functionality.
+
config RTC_HCTOSYS_DEVICE
string "RTC used to set the system time"
depends on RTC_HCTOSYS
@@ -212,17 +233,6 @@ config RTC_DRV_ABEOZ9
This driver can also be built as a module. If so, the module
will be called rtc-ab-e0z9.
-config RTC_DRV_ABX80X
- tristate "Abracon ABx80x"
- select WATCHDOG_CORE if WATCHDOG
- help
- If you say yes here you get support for Abracon AB080X and AB180X
- families of ultra-low-power battery- and capacitor-backed real-time
- clock chips.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-abx80x.
-
config RTC_DRV_AC100
tristate "X-Powers AC100"
depends on MFD_AC100
@@ -954,6 +964,20 @@ config RTC_I2C_AND_SPI
comment "SPI and I2C RTC drivers"
+config RTC_DRV_ABX80X
+ tristate "Abracon ABx80x"
+ depends on RTC_I2C_AND_SPI
+ select WATCHDOG_CORE if WATCHDOG
+ select REGMAP_I2C if I2C
+ select REGMAP_SPI if SPI_MASTER
+ help
+ If you say yes here you get support for Abracon AB080X, AB180X,
+ AB081X and AB181X families of ultra-low-power battery- and
+ capacitor-backed real-time clock chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-abx80x.
+
config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232/DS3234"
depends on RTC_I2C_AND_SPI
@@ -1999,6 +2023,18 @@ config RTC_DRV_R7301
This driver can also be built as a module. If so, the module
will be called rtc-r7301.
+config RTC_DRV_RPI
+ tristate "Raspberry Pi RTC"
+ depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ default ARCH_BCM2835
+ help
+ If you say yes here you get support for the RTC found on
+ Raspberry Pi 5th gen devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-raspberrypi.
+
config RTC_DRV_STM32
tristate "STM32 RTC"
select REGMAP_MMIO
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0347645b021f..46f1a0fc2416 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
+obj-$(CONFIG_RTC_DRV_RPI) += rtc-raspberrypi.o
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 01ba04028f1f..18ea141ab8c2 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -72,12 +72,14 @@ static void rtc_hctosys(struct rtc_device *rtc)
tv64.tv_sec = rtc_tm_to_time64(&tm);
-#if BITS_PER_LONG == 32
- if (tv64.tv_sec > INT_MAX) {
+ if (IS_ENABLED(CONFIG_RTC_HCTOSYS_TIME32_LIMIT) &&
+ tv64.tv_sec > INT_MAX) {
+ dev_warn(rtc->dev.parent,
+ "hctosys: rejecting %ptR UTC due to CONFIG_RTC_HCTOSYS_TIME32_LIMIT=y\n",
+ &tm);
err = -ERANGE;
goto err_read;
}
-#endif
err = do_settimeofday64(&tv64);
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 5486d9d0b1e5..1c69d0e2f940 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * A driver for the I2C members of the Abracon AB x8xx RTC family,
- * and compatible: AB 1805 and AB 0805
+ * A driver for the I2C and SPI members of the Abracon AB x8xx RTC family,
+ * and compatible: AB 1805, AB 0805, AB 1815 and AB 0815
*
* Copyright 2014-2015 Macq S.A.
*
@@ -16,7 +16,9 @@
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/regmap.h>
#include <linux/rtc.h>
+#include <linux/spi/spi.h>
#include <linux/watchdog.h>
#define ABX8XX_REG_HTH 0x00
@@ -50,12 +52,18 @@
#define ABX8XX_CTRL2_RSVD BIT(5)
#define ABX8XX_REG_IRQ 0x12
+#define ABX8XX_IRQ_EX1E BIT(0)
+#define ABX8XX_IRQ_EX2E BIT(1)
#define ABX8XX_IRQ_AIE BIT(2)
+#define ABX8XX_IRQ_TIE BIT(3)
+#define ABX8XX_IRQ_BLIE BIT(4)
#define ABX8XX_IRQ_IM_1_4 (0x3 << 5)
#define ABX8XX_REG_CD_TIMER_CTL 0x18
#define ABX8XX_REG_OSC 0x1c
+#define ABX8XX_OSC_ACIE BIT(0)
+#define ABX8XX_OSC_OFIE BIT(1)
#define ABX8XX_OSC_FOS BIT(3)
#define ABX8XX_OSC_BOS BIT(4)
#define ABX8XX_OSC_ACAL_512 BIT(5)
@@ -101,8 +109,8 @@
static u8 trickle_resistors[] = {0, 3, 6, 11};
-enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
- AB1801, AB1803, AB1804, AB1805, RV1805, ABX80X};
+enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, AB0815,
+ AB1801, AB1803, AB1804, AB1805, AB1815, RV1805, ABX80X};
struct abx80x_cap {
u16 pn;
@@ -115,61 +123,66 @@ static struct abx80x_cap abx80x_caps[] = {
[AB0803] = {.pn = 0x0803},
[AB0804] = {.pn = 0x0804, .has_tc = true, .has_wdog = true},
[AB0805] = {.pn = 0x0805, .has_tc = true, .has_wdog = true},
+ [AB0815] = {.pn = 0x0815, .has_tc = true, .has_wdog = true},
[AB1801] = {.pn = 0x1801},
[AB1803] = {.pn = 0x1803},
[AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true},
[AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
+ [AB1815] = {.pn = 0x1815, .has_tc = true, .has_wdog = true},
[RV1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
[ABX80X] = {.pn = 0}
};
struct abx80x_priv {
struct rtc_device *rtc;
- struct i2c_client *client;
+ struct regmap *regmap;
struct watchdog_device wdog;
+ int irq;
};
-static int abx80x_write_config_key(struct i2c_client *client, u8 key)
+static int abx80x_write_config_key(struct device *dev, u8 key)
{
- if (i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY, key) < 0) {
- dev_err(&client->dev, "Unable to write configuration key\n");
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
+
+ if (regmap_write(priv->regmap, ABX8XX_REG_CFG_KEY, key) < 0) {
+ dev_err(dev, "Unable to write configuration key\n");
return -EIO;
}
return 0;
}
-static int abx80x_is_rc_mode(struct i2c_client *client)
+static int abx80x_is_rc_mode(struct device *dev)
{
- int flags = 0;
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
+ unsigned int flags = 0;
+ int err;
- flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
- if (flags < 0) {
- dev_err(&client->dev,
- "Failed to read autocalibration attribute\n");
- return flags;
+ err = regmap_read(priv->regmap, ABX8XX_REG_OSS, &flags);
+ if (err < 0) {
+ dev_err(dev, "Failed to read autocalibration attribute\n");
+ return err;
}
return (flags & ABX8XX_OSS_OMODE) ? 1 : 0;
}
-static int abx80x_enable_trickle_charger(struct i2c_client *client,
- u8 trickle_cfg)
+static int abx80x_enable_trickle_charger(struct device *dev, u8 trickle_cfg)
{
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
int err;
/*
* Write the configuration key register to enable access to the Trickle
* register
*/
- if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_MISC) < 0)
+ if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_MISC) < 0)
return -EIO;
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_TRICKLE,
- ABX8XX_TRICKLE_CHARGE_ENABLE |
- trickle_cfg);
+ err = regmap_write(priv->regmap, ABX8XX_REG_TRICKLE,
+ ABX8XX_TRICKLE_CHARGE_ENABLE | trickle_cfg);
if (err < 0) {
- dev_err(&client->dev, "Unable to write trickle register\n");
+ dev_err(dev, "Unable to write trickle register\n");
return -EIO;
}
@@ -178,19 +191,20 @@ static int abx80x_enable_trickle_charger(struct i2c_client *client,
static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
unsigned char buf[8];
- int err, flags, rc_mode = 0;
+ unsigned int flags;
+ int err, rc_mode = 0;
/* Read the Oscillator Failure only in XT mode */
- rc_mode = abx80x_is_rc_mode(client);
+ rc_mode = abx80x_is_rc_mode(dev);
if (rc_mode < 0)
return rc_mode;
if (!rc_mode) {
- flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
- if (flags < 0)
- return flags;
+ err = regmap_read(priv->regmap, ABX8XX_REG_OSS, &flags);
+ if (err < 0)
+ return err;
if (flags & ABX8XX_OSS_OF) {
dev_err(dev, "Oscillator failure, data is invalid.\n");
@@ -198,10 +212,9 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
}
}
- err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH,
- sizeof(buf), buf);
+ err = regmap_bulk_read(priv->regmap, ABX8XX_REG_HTH, buf, sizeof(buf));
if (err < 0) {
- dev_err(&client->dev, "Unable to read date\n");
+ dev_err(dev, "Unable to read date\n");
return -EIO;
}
@@ -218,9 +231,9 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
unsigned char buf[8];
- int err, flags;
+ int err;
if (tm->tm_year < 100)
return -EINVAL;
@@ -234,37 +247,33 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[ABX8XX_REG_YR] = bin2bcd(tm->tm_year - 100);
buf[ABX8XX_REG_WD] = tm->tm_wday;
- err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_HTH,
- sizeof(buf), buf);
+ err = regmap_bulk_write(priv->regmap, ABX8XX_REG_HTH, buf,
+ sizeof(buf));
if (err < 0) {
- dev_err(&client->dev, "Unable to write to date registers\n");
+ dev_err(dev, "Unable to write to date registers\n");
return -EIO;
}
/* Clear the OF bit of Oscillator Status Register */
- flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS);
- if (flags < 0)
- return flags;
+ err = regmap_update_bits(priv->regmap, ABX8XX_REG_OSS, ABX8XX_OSS_OF, 0);
+ if (err < 0)
+ dev_err(dev, "Unable to write oscillator status register\n");
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSS,
- flags & ~ABX8XX_OSS_OF);
- if (err < 0) {
- dev_err(&client->dev, "Unable to write oscillator status register\n");
- return err;
- }
-
- return 0;
+ return err;
}
static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
{
- struct i2c_client *client = dev_id;
- struct abx80x_priv *priv = i2c_get_clientdata(client);
+ struct device *dev = dev_id;
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
struct rtc_device *rtc = priv->rtc;
- int status;
+ unsigned int status, status_flags_clear;
+ int err;
- status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS);
- if (status < 0)
+ guard(rtc_ops)(rtc);
+
+ err = regmap_read(priv->regmap, ABX8XX_REG_STATUS, &status);
+ if (err < 0)
return IRQ_NONE;
if (status & ABX8XX_STATUS_AF)
@@ -275,31 +284,37 @@ static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
* reset kicks in.
*/
if (status & ABX8XX_STATUS_WDT)
- dev_alert(&client->dev, "watchdog timeout interrupt.\n");
+ dev_alert(dev, "watchdog timeout interrupt.\n");
+
+ status_flags_clear = status & (ABX8XX_STATUS_AF | ABX8XX_STATUS_WDT);
- i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0);
+ if (status_flags_clear) {
+ regmap_write(priv->regmap, ABX8XX_REG_STATUS,
+ status & ~status_flags_clear);
+ return IRQ_HANDLED;
+ }
- return IRQ_HANDLED;
+ return IRQ_NONE;
}
static int abx80x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
unsigned char buf[7];
- int irq_mask, err;
+ unsigned int irq_mask;
+ int err;
- if (client->irq <= 0)
+ if (priv->irq <= 0)
return -EINVAL;
- err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ASC,
- sizeof(buf), buf);
+ err = regmap_bulk_read(priv->regmap, ABX8XX_REG_ASC, buf, sizeof(buf));
if (err)
return err;
- irq_mask = i2c_smbus_read_byte_data(client, ABX8XX_REG_IRQ);
- if (irq_mask < 0)
- return irq_mask;
+ err = regmap_read(priv->regmap, ABX8XX_REG_IRQ, &irq_mask);
+ if (err < 0)
+ return err;
t->time.tm_sec = bcd2bin(buf[0] & 0x7F);
t->time.tm_min = bcd2bin(buf[1] & 0x7F);
@@ -311,16 +326,16 @@ static int abx80x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->enabled = !!(irq_mask & ABX8XX_IRQ_AIE);
t->pending = (buf[6] & ABX8XX_STATUS_AF) && t->enabled;
- return err;
+ return 0;
}
static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
u8 alarm[6];
int err;
- if (client->irq <= 0)
+ if (priv->irq <= 0)
return -EINVAL;
alarm[0] = 0x0;
@@ -330,17 +345,16 @@ static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
alarm[4] = bin2bcd(t->time.tm_mday);
alarm[5] = bin2bcd(t->time.tm_mon + 1);
- err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_AHTH,
- sizeof(alarm), alarm);
+ err = regmap_bulk_write(priv->regmap, ABX8XX_REG_AHTH,
+ alarm, sizeof(alarm));
if (err < 0) {
- dev_err(&client->dev, "Unable to write alarm registers\n");
+ dev_err(dev, "Unable to write alarm registers\n");
return -EIO;
}
if (t->enabled) {
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
- (ABX8XX_IRQ_IM_1_4 |
- ABX8XX_IRQ_AIE));
+ err = regmap_write(priv->regmap, ABX8XX_REG_IRQ,
+ ABX8XX_IRQ_IM_1_4 | ABX8XX_IRQ_AIE);
if (err)
return err;
}
@@ -351,8 +365,8 @@ static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
static int abx80x_rtc_set_autocalibration(struct device *dev,
int autocalibration)
{
- struct i2c_client *client = to_i2c_client(dev);
- int retval, flags = 0;
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
+ unsigned int flags = 0;
if ((autocalibration != 0) && (autocalibration != 1024) &&
(autocalibration != 512)) {
@@ -360,10 +374,6 @@ static int abx80x_rtc_set_autocalibration(struct device *dev,
return -EINVAL;
}
- flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
- if (flags < 0)
- return flags;
-
if (autocalibration == 0) {
flags &= ~(ABX8XX_OSC_ACAL_512 | ABX8XX_OSC_ACAL_1024);
} else if (autocalibration == 1024) {
@@ -375,23 +385,26 @@ static int abx80x_rtc_set_autocalibration(struct device *dev,
flags |= (ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512);
}
+ guard(rtc_ops)(priv->rtc);
+
/* Unlock write access to Oscillator Control Register */
- if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_OSC) < 0)
+ if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_OSC) < 0)
return -EIO;
- retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags);
-
- return retval;
+ return regmap_write_bits(priv->regmap, ABX8XX_REG_OSC,
+ ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512,
+ flags);
}
static int abx80x_rtc_get_autocalibration(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- int flags = 0, autocalibration;
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
+ unsigned int flags = 0;
+ int autocalibration, err;
- flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
- if (flags < 0)
- return flags;
+ err = regmap_read(priv->regmap, ABX8XX_REG_OSC, &flags);
+ if (err < 0)
+ return err;
if (flags & ABX8XX_OSC_ACAL_512)
autocalibration = 512;
@@ -442,8 +455,8 @@ static ssize_t oscillator_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev->parent);
- int retval, flags, rc_mode = 0;
+ struct abx80x_priv *priv = dev_get_drvdata(dev->parent);
+ int retval, rc_mode = 0;
if (strncmp(buf, "rc", 2) == 0) {
rc_mode = 1;
@@ -454,24 +467,16 @@ static ssize_t oscillator_store(struct device *dev,
return -EINVAL;
}
- flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC);
- if (flags < 0)
- return flags;
-
- if (rc_mode == 0)
- flags &= ~(ABX8XX_OSC_OSEL);
- else
- flags |= (ABX8XX_OSC_OSEL);
+ guard(rtc_ops)(priv->rtc);
/* Unlock write access on Oscillator Control register */
- if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_OSC) < 0)
+ if (abx80x_write_config_key(dev->parent, ABX8XX_CFG_KEY_OSC) < 0)
return -EIO;
- retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags);
- if (retval < 0) {
+ retval = regmap_write_bits(priv->regmap, ABX8XX_REG_OSC, ABX8XX_OSC_OSEL,
+ rc_mode == 0 ? 0 : (ABX8XX_OSC_OSEL));
+ if (retval < 0)
dev_err(dev, "Failed to write Oscillator Control register\n");
- return retval;
- }
return retval ? retval : count;
}
@@ -480,9 +485,8 @@ static ssize_t oscillator_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rc_mode = 0;
- struct i2c_client *client = to_i2c_client(dev->parent);
- rc_mode = abx80x_is_rc_mode(client);
+ rc_mode = abx80x_is_rc_mode(dev->parent);
if (rc_mode < 0) {
dev_err(dev, "Failed to read RTC oscillator selection\n");
@@ -510,47 +514,39 @@ static const struct attribute_group rtc_calib_attr_group = {
static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
int err;
if (enabled)
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
- (ABX8XX_IRQ_IM_1_4 |
- ABX8XX_IRQ_AIE));
+ err = regmap_write(priv->regmap, ABX8XX_REG_IRQ,
+ ABX8XX_IRQ_IM_1_4 | ABX8XX_IRQ_AIE);
else
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
- ABX8XX_IRQ_IM_1_4);
+ err = regmap_write(priv->regmap, ABX8XX_REG_IRQ,
+ ABX8XX_IRQ_IM_1_4);
return err;
}
static int abx80x_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
- struct i2c_client *client = to_i2c_client(dev);
- int status, tmp;
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
+ unsigned int status;
+ int err, tmp;
switch (cmd) {
case RTC_VL_READ:
- status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS);
- if (status < 0)
- return status;
+ err = regmap_read(priv->regmap, ABX8XX_REG_STATUS, &status);
+ if (err < 0)
+ return err;
tmp = status & ABX8XX_STATUS_BLF ? RTC_VL_BACKUP_LOW : 0;
return put_user(tmp, (unsigned int __user *)arg);
case RTC_VL_CLR:
- status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS);
- if (status < 0)
- return status;
+ err = regmap_update_bits(priv->regmap, ABX8XX_REG_STATUS,
+ ABX8XX_STATUS_BLF, 0);
- status &= ~ABX8XX_STATUS_BLF;
-
- tmp = i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS,
- status);
- if (tmp < 0)
- return tmp;
-
- return 0;
+ return err;
default:
return -ENOIOCTLCMD;
@@ -566,9 +562,9 @@ static const struct rtc_class_ops abx80x_rtc_ops = {
.ioctl = abx80x_ioctl,
};
-static int abx80x_dt_trickle_cfg(struct i2c_client *client)
+static int abx80x_dt_trickle_cfg(struct device *dev)
{
- struct device_node *np = client->dev.of_node;
+ struct device_node *np = dev->of_node;
const char *diode;
int trickle_cfg = 0;
int i, ret;
@@ -583,7 +579,7 @@ static int abx80x_dt_trickle_cfg(struct i2c_client *client)
} else if (!strcmp(diode, "schottky")) {
trickle_cfg |= ABX8XX_TRICKLE_SCHOTTKY_DIODE;
} else {
- dev_dbg(&client->dev, "Invalid tc-diode value: %s\n", diode);
+ dev_dbg(dev, "Invalid tc-diode value: %s\n", diode);
return -EINVAL;
}
@@ -596,7 +592,7 @@ static int abx80x_dt_trickle_cfg(struct i2c_client *client)
break;
if (i == sizeof(trickle_resistors)) {
- dev_dbg(&client->dev, "Invalid tc-resistor value: %u\n", tmp);
+ dev_dbg(dev, "Invalid tc-resistor value: %u\n", tmp);
return -EINVAL;
}
@@ -617,11 +613,13 @@ static int __abx80x_wdog_set_timeout(struct watchdog_device *wdog,
struct abx80x_priv *priv = watchdog_get_drvdata(wdog);
u8 val = ABX8XX_WDT_WDS | timeout_bits(timeout);
+ guard(rtc_ops)(priv->rtc);
+
/*
* Writing any timeout to the WDT register resets the watchdog timer.
* Writing 0 disables it.
*/
- return i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_WDT, val);
+ return regmap_write(priv->regmap, ABX8XX_REG_WDT, val);
}
static int abx80x_wdog_set_timeout(struct watchdog_device *wdog,
@@ -666,9 +664,11 @@ static const struct watchdog_ops abx80x_wdog_ops = {
.set_timeout = abx80x_wdog_set_timeout,
};
-static int abx80x_setup_watchdog(struct abx80x_priv *priv)
+static int abx80x_setup_watchdog(struct device *dev)
{
- priv->wdog.parent = &priv->client->dev;
+ struct abx80x_priv *priv = dev_get_drvdata(dev);
+
+ priv->wdog.parent = dev;
priv->wdog.ops = &abx80x_wdog_ops;
priv->wdog.info = &abx80x_wdog_info;
priv->wdog.min_timeout = 1;
@@ -677,10 +677,10 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv)
watchdog_set_drvdata(&priv->wdog, priv);
- return devm_watchdog_register_device(&priv->client->dev, &priv->wdog);
+ return devm_watchdog_register_device(dev, &priv->wdog);
}
#else
-static int abx80x_setup_watchdog(struct abx80x_priv *priv)
+static int abx80x_setup_watchdog(struct device *dev)
{
return 0;
}
@@ -692,31 +692,29 @@ static int abx80x_nvmem_xfer(struct abx80x_priv *priv, unsigned int offset,
int ret;
while (bytes) {
- u8 extram, reg, len, lower, upper;
+ u8 reg, len, lower, upper;
lower = FIELD_GET(NVMEM_ADDR_LOWER, offset);
upper = FIELD_GET(NVMEM_ADDR_UPPER, offset);
- extram = FIELD_PREP(ABX8XX_EXTRAM_XADS, upper);
reg = ABX8XX_SRAM_BASE + lower;
len = min(lower + bytes, (size_t)ABX8XX_SRAM_WIN_SIZE) - lower;
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
- ret = i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_EXTRAM,
- extram);
+ guard(rtc_ops)(priv->rtc);
+
+ ret = regmap_update_bits(priv->regmap, ABX8XX_REG_EXTRAM,
+ ABX8XX_EXTRAM_XADS, upper);
if (ret)
return ret;
if (write) {
- ret = i2c_smbus_write_i2c_block_data(priv->client, reg,
- len, val);
+ ret = regmap_bulk_write(priv->regmap, reg, val, len);
if (ret)
return ret;
} else {
- ret = i2c_smbus_read_i2c_block_data(priv->client, reg,
- len, val);
- if (ret <= 0)
- return ret ? ret : -EIO;
- len = ret;
+ ret = regmap_bulk_read(priv->regmap, reg, val, len);
+ if (ret)
+ return ret;
}
offset += len;
@@ -752,41 +750,58 @@ static int abx80x_setup_nvmem(struct abx80x_priv *priv)
return devm_rtc_nvmem_register(priv->rtc, &config);
}
-static const struct i2c_device_id abx80x_id[] = {
- { .name = "abx80x", .driver_data = ABX80X },
- { .name = "ab0801", .driver_data = AB0801 },
- { .name = "ab0803", .driver_data = AB0803 },
- { .name = "ab0804", .driver_data = AB0804 },
- { .name = "ab0805", .driver_data = AB0805 },
- { .name = "ab1801", .driver_data = AB1801 },
- { .name = "ab1803", .driver_data = AB1803 },
- { .name = "ab1804", .driver_data = AB1804 },
- { .name = "ab1805", .driver_data = AB1805 },
- { .name = "rv1805", .driver_data = RV1805 },
- { }
+static const struct regmap_range abx80x_no_read_ranges[] = {
+ regmap_reg_range(0x1e, 0x1e),
+ regmap_reg_range(0x22, 0x25),
+ regmap_reg_range(0x31, 0x3e),
};
-MODULE_DEVICE_TABLE(i2c, abx80x_id);
-static int abx80x_probe(struct i2c_client *client)
+static const struct regmap_range abx80x_no_write_ranges[] = {
+ regmap_reg_range(0x1e, 0x1e),
+ regmap_reg_range(0x22, 0x25),
+ regmap_reg_range(ABX8XX_REG_ID0, ABX8XX_REG_ID0 + 6),
+ regmap_reg_range(0x31, 0x3e),
+};
+
+static const struct regmap_access_table abx80x_read_table = {
+ .no_ranges = abx80x_no_read_ranges,
+ .n_no_ranges = ARRAY_SIZE(abx80x_no_read_ranges),
+};
+
+static const struct regmap_access_table abx80x_write_table = {
+ .no_ranges = abx80x_no_write_ranges,
+ .n_no_ranges = ARRAY_SIZE(abx80x_no_write_ranges),
+};
+
+static int abx80x_probe(struct device *dev, struct regmap *regmap, int irq,
+ struct device_node *np, unsigned int part)
{
- struct device_node *np = client->dev.of_node;
struct abx80x_priv *priv;
- int i, data, err, trickle_cfg = -EINVAL;
+ int i, err, trickle_cfg = -EINVAL;
char buf[7];
- unsigned int part = (uintptr_t)i2c_get_match_data(client);
unsigned int partnumber;
unsigned int majrev, minrev;
unsigned int lot;
unsigned int wafer;
unsigned int uid;
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- return -ENODEV;
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
- err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ID0,
- sizeof(buf), buf);
+ priv->rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(priv->rtc))
+ return PTR_ERR(priv->rtc);
+
+ priv->rtc->ops = &abx80x_rtc_ops;
+ priv->irq = irq;
+ priv->regmap = regmap;
+
+ dev_set_drvdata(dev, priv);
+
+ err = regmap_bulk_read(regmap, ABX8XX_REG_ID0, buf, sizeof(buf));
if (err < 0) {
- dev_err(&client->dev, "Unable to read partnumber\n");
+ dev_err(dev, "Unable to read partnumber\n");
return -EIO;
}
@@ -796,21 +811,14 @@ static int abx80x_probe(struct i2c_client *client)
lot = ((buf[4] & 0x80) << 2) | ((buf[6] & 0x80) << 1) | buf[3];
uid = ((buf[4] & 0x7f) << 8) | buf[5];
wafer = (buf[6] & 0x7c) >> 2;
- dev_info(&client->dev, "model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n",
+ dev_info(dev, "model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n",
partnumber, majrev, minrev, lot, wafer, uid);
- data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL1);
- if (data < 0) {
- dev_err(&client->dev, "Unable to read control register\n");
- return -EIO;
- }
-
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1,
- ((data & ~(ABX8XX_CTRL_12_24 |
- ABX8XX_CTRL_ARST)) |
- ABX8XX_CTRL_WRITE));
+ err = regmap_update_bits(regmap, ABX8XX_REG_CTRL1,
+ ABX8XX_CTRL_12_24 | ABX8XX_CTRL_ARST | ABX8XX_CTRL_WRITE,
+ ABX8XX_CTRL_WRITE);
if (err < 0) {
- dev_err(&client->dev, "Unable to write control register\n");
+ dev_err(dev, "Unable to write control register\n");
return -EIO;
}
@@ -822,30 +830,10 @@ static int abx80x_probe(struct i2c_client *client)
* register is set. RV-1805-C3 datasheet indicates that
* the bit should be cleared in section 11h - Control2.
*/
- data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL2);
- if (data < 0) {
- dev_err(&client->dev,
- "Unable to read control2 register\n");
- return -EIO;
- }
-
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL2,
- data & ~ABX8XX_CTRL2_RSVD);
+ err = regmap_update_bits(regmap, ABX8XX_REG_CTRL2,
+ ABX8XX_CTRL2_RSVD, 0);
if (err < 0) {
- dev_err(&client->dev,
- "Unable to write control2 register\n");
- return -EIO;
- }
-
- /*
- * Avoid extra power leakage. The RV1805 uses smaller
- * 10pin package and the EXTI input is not present.
- * Disable it to avoid leakage.
- */
- data = i2c_smbus_read_byte_data(client, ABX8XX_REG_OUT_CTRL);
- if (data < 0) {
- dev_err(&client->dev,
- "Unable to read output control register\n");
+ dev_err(dev, "Unable to write control2 register\n");
return -EIO;
}
@@ -853,13 +841,19 @@ static int abx80x_probe(struct i2c_client *client)
* Write the configuration key register to enable access to
* the config2 register
*/
- if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_MISC) < 0)
+ if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_MISC) < 0)
return -EIO;
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OUT_CTRL,
- data | ABX8XX_OUT_CTRL_EXDS);
+ /*
+ * Avoid extra power leakage. The RV1805 uses smaller
+ * 10pin package and the EXTI input is not present.
+ * Disable it to avoid leakage.
+ */
+ err = regmap_write_bits(regmap, ABX8XX_REG_OUT_CTRL,
+ ABX8XX_OUT_CTRL_EXDS,
+ ABX8XX_OUT_CTRL_EXDS);
if (err < 0) {
- dev_err(&client->dev,
+ dev_err(dev,
"Unable to write output control register\n");
return -EIO;
}
@@ -871,48 +865,52 @@ static int abx80x_probe(struct i2c_client *client)
if (partnumber == abx80x_caps[i].pn)
break;
if (abx80x_caps[i].pn == 0) {
- dev_err(&client->dev, "Unknown part: %04x\n",
- partnumber);
+ dev_err(dev, "Unknown part: %04x\n", partnumber);
return -EINVAL;
}
part = i;
}
if (partnumber != abx80x_caps[part].pn) {
- dev_err(&client->dev, "partnumber mismatch %04x != %04x\n",
+ dev_err(dev, "partnumber mismatch %04x != %04x\n",
partnumber, abx80x_caps[part].pn);
return -EINVAL;
}
if (np && abx80x_caps[part].has_tc)
- trickle_cfg = abx80x_dt_trickle_cfg(client);
+ trickle_cfg = abx80x_dt_trickle_cfg(dev);
if (trickle_cfg > 0) {
- dev_info(&client->dev, "Enabling trickle charger: %02x\n",
- trickle_cfg);
- abx80x_enable_trickle_charger(client, trickle_cfg);
+ dev_info(dev, "Enabling trickle charger: %02x\n", trickle_cfg);
+ abx80x_enable_trickle_charger(dev, trickle_cfg);
}
- err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CD_TIMER_CTL,
- BIT(2));
+ err = regmap_write(regmap, ABX8XX_REG_CD_TIMER_CTL, BIT(2));
if (err)
return err;
- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
- if (priv == NULL)
- return -ENOMEM;
-
- priv->rtc = devm_rtc_allocate_device(&client->dev);
- if (IS_ERR(priv->rtc))
- return PTR_ERR(priv->rtc);
+ /* Disable unused interrupts */
+ err = regmap_update_bits(regmap, ABX8XX_REG_IRQ,
+ ABX8XX_IRQ_EX1E | ABX8XX_IRQ_EX2E |
+ ABX8XX_IRQ_TIE | ABX8XX_IRQ_BLIE, 0);
+ if (err < 0) {
+ dev_err(dev, "Unable to update irq register\n");
+ return -EIO;
+ }
- priv->rtc->ops = &abx80x_rtc_ops;
- priv->client = client;
+ /* Unlock write access to Oscillator Control Register */
+ if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_OSC) < 0)
+ return -EIO;
- i2c_set_clientdata(client, priv);
+ err = regmap_write_bits(regmap, ABX8XX_REG_OSC,
+ ABX8XX_OSC_ACIE | ABX8XX_OSC_OFIE, 0);
+ if (err < 0) {
+ dev_err(dev, "Unable to update Oscillator Control register\n");
+ return -EIO;
+ }
if (abx80x_caps[part].has_wdog) {
- err = abx80x_setup_watchdog(priv);
+ err = abx80x_setup_watchdog(dev);
if (err)
return err;
}
@@ -921,31 +919,56 @@ static int abx80x_probe(struct i2c_client *client)
if (err)
return err;
- if (client->irq > 0) {
- dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
- err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ if (priv->irq > 0) {
+ dev_info(dev, "IRQ %d supplied\n", priv->irq);
+ err = devm_request_threaded_irq(dev, priv->irq, NULL,
abx80x_handle_irq,
IRQF_SHARED | IRQF_ONESHOT,
"abx8xx",
- client);
+ dev);
if (err) {
- dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
- client->irq = 0;
+ dev_err(dev, "unable to request IRQ, alarms disabled\n");
+ priv->irq = 0;
}
}
- if (client->irq <= 0)
+ if (priv->irq <= 0)
clear_bit(RTC_FEATURE_ALARM, priv->rtc->features);
err = rtc_add_group(priv->rtc, &rtc_calib_attr_group);
if (err) {
- dev_err(&client->dev, "Failed to create sysfs group: %d\n",
- err);
+ dev_err(dev, "Failed to create sysfs group: %d\n", err);
return err;
}
return devm_rtc_register_device(priv->rtc);
}
+#if IS_ENABLED(CONFIG_I2C)
+
+static const struct regmap_config abx80x_regmap_config_i2c = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ABX8XX_SRAM_BASE + ABX8XX_SRAM_WIN_SIZE - 1,
+
+ .rd_table = &abx80x_read_table,
+ .wr_table = &abx80x_write_table,
+};
+
+static const struct i2c_device_id abx80x_id[] = {
+ { .name = "abx80x", .driver_data = ABX80X },
+ { .name = "ab0801", .driver_data = AB0801 },
+ { .name = "ab0803", .driver_data = AB0803 },
+ { .name = "ab0804", .driver_data = AB0804 },
+ { .name = "ab0805", .driver_data = AB0805 },
+ { .name = "ab1801", .driver_data = AB1801 },
+ { .name = "ab1803", .driver_data = AB1803 },
+ { .name = "ab1804", .driver_data = AB1804 },
+ { .name = "ab1805", .driver_data = AB1805 },
+ { .name = "rv1805", .driver_data = RV1805 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, abx80x_id);
+
#ifdef CONFIG_OF
static const struct of_device_id abx80x_of_match[] = {
{
@@ -993,16 +1016,160 @@ static const struct of_device_id abx80x_of_match[] = {
MODULE_DEVICE_TABLE(of, abx80x_of_match);
#endif
+static int abx80x_i2c_probe(struct i2c_client *client)
+{
+ unsigned int part = (uintptr_t)i2c_get_match_data(client);
+ struct regmap *regmap;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ regmap = devm_regmap_init_i2c(client, &abx80x_regmap_config_i2c);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Unable to allocate regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return abx80x_probe(&client->dev, regmap, client->irq,
+ client->dev.of_node, part);
+}
+
static struct i2c_driver abx80x_driver = {
.driver = {
.name = "rtc-abx80x",
.of_match_table = of_match_ptr(abx80x_of_match),
},
- .probe = abx80x_probe,
+ .probe = abx80x_i2c_probe,
.id_table = abx80x_id,
};
-module_i2c_driver(abx80x_driver);
+static int abx80x_register_driver(void)
+{
+ return i2c_add_driver(&abx80x_driver);
+}
+
+static void abx80x_unregister_driver(void)
+{
+ i2c_del_driver(&abx80x_driver);
+}
+
+#else
+
+static int abx80x_register_driver(void)
+{
+ return 0;
+}
+
+static void abx80x_unregister_driver(void)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_I2C) */
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static const struct regmap_config abx80x_regmap_config_spi = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ABX8XX_SRAM_BASE + ABX8XX_SRAM_WIN_SIZE - 1,
+
+ .rd_table = &abx80x_read_table,
+ .wr_table = &abx80x_write_table,
+
+ .write_flag_mask = BIT(7),
+};
+
+static const struct spi_device_id abx81x_id[] = {
+ { "ab0815", AB0815 },
+ { "ab1815", AB1815 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, abx81x_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id abx81x_of_match[] = {
+ {
+ .compatible = "abracon,ab0815",
+ .data = (void *)AB0815
+ },
+ {
+ .compatible = "abracon,ab1815",
+ .data = (void *)AB1815
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, abx81x_of_match);
+#endif
+
+static int abx81x_spi_probe(struct spi_device *spi)
+{
+ unsigned int part = (uintptr_t)spi_get_device_match_data(spi);
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &abx80x_regmap_config_spi);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Unable to allocate regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return abx80x_probe(&spi->dev, regmap, spi->irq,
+ spi->dev.of_node, part);
+}
+
+static struct spi_driver abx81x_driver = {
+ .driver = {
+ .name = "rtc-abx81x",
+ .of_match_table = of_match_ptr(abx81x_of_match),
+ },
+ .probe = abx81x_spi_probe,
+ .id_table = abx81x_id,
+};
+
+static int abx81x_register_driver(void)
+{
+ return spi_register_driver(&abx81x_driver);
+}
+
+static void abx81x_unregister_driver(void)
+{
+ spi_unregister_driver(&abx81x_driver);
+}
+
+#else
+
+static int abx81x_register_driver(void)
+{
+ return 0;
+}
+
+static void abx81x_unregister_driver(void)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_SPI_MASTER) */
+
+static int __init abx80x_init(void)
+{
+ int ret;
+
+ ret = abx80x_register_driver();
+ if (ret)
+ return ret;
+
+ ret = abx81x_register_driver();
+ if (ret)
+ abx80x_unregister_driver();
+
+ return ret;
+}
+module_init(abx80x_init);
+
+static void __exit abx80x_exit(void)
+{
+ abx81x_unregister_driver();
+ abx80x_unregister_driver();
+}
+module_exit(abx80x_exit);
MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c
index c579c4bf5578..c6fca15af241 100644
--- a/drivers/rtc/rtc-ac100.c
+++ b/drivers/rtc/rtc-ac100.c
@@ -516,12 +516,12 @@ static irqreturn_t ac100_rtc_irq(int irq, void *data)
unsigned int val = 0;
int ret;
- rtc_lock(chip->rtc);
+ guard(rtc_ops)(chip->rtc);
/* read status */
ret = regmap_read(regmap, AC100_ALM_INT_STA, &val);
if (ret)
- goto out;
+ return IRQ_HANDLED;
if (val & AC100_ALM_INT_ENABLE) {
/* signal rtc framework */
@@ -530,16 +530,14 @@ static irqreturn_t ac100_rtc_irq(int irq, void *data)
/* clear status */
ret = regmap_write(regmap, AC100_ALM_INT_STA, val);
if (ret)
- goto out;
+ return IRQ_HANDLED;
/* disable interrupt */
ret = ac100_rtc_alarm_irq_enable(chip->dev, 0);
if (ret)
- goto out;
+ return IRQ_HANDLED;
}
-out:
- rtc_unlock(chip->rtc);
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c
index 705470ae8428..422c2e5d83aa 100644
--- a/drivers/rtc/rtc-asm9260.c
+++ b/drivers/rtc/rtc-asm9260.c
@@ -116,15 +116,13 @@ static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id)
u32 isr;
unsigned long events = 0;
- rtc_lock(priv->rtc);
+ guard(rtc_ops)(priv->rtc);
isr = ioread32(priv->iobase + HW_CIIR);
if (!isr) {
- rtc_unlock(priv->rtc);
return IRQ_NONE;
}
iowrite32(0, priv->iobase + HW_CIIR);
- rtc_unlock(priv->rtc);
events |= RTC_AF | RTC_IRQF;
diff --git a/drivers/rtc/rtc-atcrtc100.c b/drivers/rtc/rtc-atcrtc100.c
index 9808fc2c5a49..2433df386c40 100644
--- a/drivers/rtc/rtc-atcrtc100.c
+++ b/drivers/rtc/rtc-atcrtc100.c
@@ -147,7 +147,7 @@ static void atcrtc_alarm_clear(struct work_struct *work)
container_of(work, struct atcrtc_dev, rtc_work);
int ret;
- rtc_lock(rtc->rtc_dev);
+ guard(rtc_ops)(rtc->rtc_dev);
if (!rtc->alarm_en) {
ret = atcrtc_check_write_done(rtc);
@@ -159,7 +159,6 @@ static void atcrtc_alarm_clear(struct work_struct *work)
regmap_update_bits(rtc->regmap, RTC_CR,
ALARM_WAKEUP | ALARM_INT, 0);
}
- rtc_unlock(rtc->rtc_dev);
}
static int atcrtc_read_time(struct device *dev, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index fd415e327ea6..dd5569d17567 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
@@ -328,6 +329,10 @@ static int bd70528_probe(struct platform_device *pdev)
device_set_wakeup_capable(&pdev->dev, true);
device_wakeup_enable(&pdev->dev);
+ ret = devm_pm_set_wake_irq(&pdev->dev, irq);
+ if (ret)
+ return ret;
+
rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc)) {
dev_err(&pdev->dev, "RTC device creation failed\n");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index fa04ece151b8..209aa4ec732c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -57,7 +57,28 @@
*/
static bool use_acpi_alarm;
-module_param(use_acpi_alarm, bool, 0444);
+static bool use_acpi_alarm_explicit;
+
+static int set_use_acpi_alarm(const char *val, const struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_bool(val, kp);
+ if (!ret)
+ use_acpi_alarm_explicit = true;
+
+ return ret;
+}
+
+static const struct kernel_param_ops use_acpi_alarm_ops = {
+ .flags = KERNEL_PARAM_OPS_FL_NOARG,
+ .set = set_use_acpi_alarm,
+ .get = param_get_bool,
+};
+
+param_check_bool(use_acpi_alarm, &use_acpi_alarm);
+module_param_cb(use_acpi_alarm, &use_acpi_alarm_ops, &use_acpi_alarm, 0444);
+__MODULE_PARM_TYPE(use_acpi_alarm, "bool");
static inline int cmos_use_acpi_alarm(void)
{
@@ -758,7 +779,9 @@ static u32 rtc_handler(void *context)
unsigned char rtc_intr;
unsigned long flags;
-
+ /* Quiesce this event before rtc->irqwork can arm the next one. */
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
/*
* Always update rtc irq when ACPI is used as RTC Alarm.
* Or else, ACPI SCI is enabled during suspend/resume only,
@@ -781,8 +804,6 @@ static u32 rtc_handler(void *context)
}
pm_wakeup_hard_event(dev);
- acpi_clear_event(ACPI_EVENT_RTC);
- acpi_disable_event(ACPI_EVENT_RTC, 0);
return ACPI_INTERRUPT_HANDLED;
}
@@ -822,6 +843,9 @@ static void rtc_wake_off(struct device *dev)
#ifdef CONFIG_X86
static void use_acpi_alarm_quirks(void)
{
+ if (use_acpi_alarm_explicit)
+ return;
+
if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC)
return;
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index d4de401548b4..19a32d3476b5 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -440,7 +440,7 @@ static void ds1305_work(struct work_struct *work)
int status;
/* lock to protect ds1305->ctrl */
- rtc_lock(ds1305->rtc);
+ guard(rtc_ops)(ds1305->rtc);
/* Disable the IRQ, and clear its status ... for now, we "know"
* that if more than one alarm is active, they're in sync.
@@ -458,8 +458,6 @@ static void ds1305_work(struct work_struct *work)
if (status < 0)
dev_dbg(&spi->dev, "clear irq --> %d\n", status);
- rtc_unlock(ds1305->rtc);
-
if (!test_bit(FLAG_EXITING, &ds1305->flags))
enable_irq(spi->irq);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 522f7eef3b4a..8627f84232ce 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -579,28 +579,27 @@ static irqreturn_t rx8130_irq(int irq, void *dev_id)
u8 ctl[3];
int ret;
- rtc_lock(ds1307->rtc);
+ guard(rtc_ops)(ds1307->rtc);
/* Read control registers. */
ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl,
sizeof(ctl));
if (ret < 0)
- goto out;
+ return IRQ_HANDLED;
+
if (!(ctl[1] & RX8130_REG_FLAG_AF))
- goto out;
+ return IRQ_HANDLED;
+
ctl[1] &= ~RX8130_REG_FLAG_AF;
ctl[2] &= ~RX8130_REG_CONTROL0_AIE;
ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl,
sizeof(ctl));
if (ret < 0)
- goto out;
+ return IRQ_HANDLED;
rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
-out:
- rtc_unlock(ds1307->rtc);
-
return IRQ_HANDLED;
}
@@ -1891,7 +1890,6 @@ static int ds1307_probe(struct i2c_client *client)
if (!ds1307)
return -ENOMEM;
- dev_set_drvdata(&client->dev, ds1307);
ds1307->dev = &client->dev;
ds1307->name = client->name;
diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c
index 54f6af7886a8..22abec4ba656 100644
--- a/drivers/rtc/rtc-ds1343.c
+++ b/drivers/rtc/rtc-ds1343.c
@@ -312,11 +312,11 @@ static irqreturn_t ds1343_thread(int irq, void *dev_id)
unsigned int stat;
int res = 0;
- rtc_lock(priv->rtc);
+ guard(rtc_ops)(priv->rtc);
res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
if (res)
- goto out;
+ return IRQ_HANDLED;
if (stat & DS1343_IRQF0) {
stat &= ~DS1343_IRQF0;
@@ -328,8 +328,6 @@ static irqreturn_t ds1343_thread(int irq, void *dev_id)
DS1343_A0IE, 0);
}
-out:
- rtc_unlock(priv->rtc);
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 5fc8e36b1abf..284815e5f478 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -666,7 +666,7 @@ ds1685_rtc_irq_handler(int irq, void *dev_id)
if (unlikely(!rtc))
return IRQ_HANDLED;
- rtc_lock(rtc->dev);
+ guard(rtc_ops)(rtc->dev);
/* Ctrlb holds the interrupt-enable bits and ctrlc the flag bits. */
ctrlb = rtc->read(rtc, RTC_CTRL_B);
@@ -711,7 +711,6 @@ ds1685_rtc_irq_handler(int irq, void *dev_id)
}
}
rtc_update_irq(rtc->dev, num_irqs, events);
- rtc_unlock(rtc->dev);
return events ? IRQ_HANDLED : IRQ_NONE;
}
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index d1ef9e0dad34..f6407c631d6d 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -389,45 +389,39 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
int ret;
int stat, control;
- rtc_lock(ds3232->rtc);
+ guard(rtc_ops)(ds3232->rtc);
ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret)
- goto unlock;
+ return IRQ_HANDLED;
if (stat & DS3232_REG_SR_A1F) {
ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret) {
dev_warn(ds3232->dev,
"Read Control Register error %d\n", ret);
- } else {
- /* disable alarm1 interrupt */
- control &= ~(DS3232_REG_CR_A1IE);
- ret = regmap_write(ds3232->regmap, DS3232_REG_CR,
- control);
- if (ret) {
- dev_warn(ds3232->dev,
- "Write Control Register error %d\n",
- ret);
- goto unlock;
- }
-
- /* clear the alarm pend flag */
- stat &= ~DS3232_REG_SR_A1F;
- ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
- if (ret) {
- dev_warn(ds3232->dev,
- "Write Status Register error %d\n",
- ret);
- goto unlock;
- }
-
- rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+ return IRQ_HANDLED;
+ }
+ /* disable alarm1 interrupt */
+ control &= ~(DS3232_REG_CR_A1IE);
+ ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
+ if (ret) {
+ dev_warn(ds3232->dev,
+ "Write Control Register error %d\n", ret);
+ return IRQ_HANDLED;
+ }
+
+ /* clear the alarm pend flag */
+ stat &= ~DS3232_REG_SR_A1F;
+ ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
+ if (ret) {
+ dev_warn(ds3232->dev,
+ "Write Status Register error %d\n", ret);
+ return IRQ_HANDLED;
}
- }
-unlock:
- rtc_unlock(ds3232->rtc);
+ rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+ }
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c
index 98fa0f518303..c66d4a85f23c 100644
--- a/drivers/rtc/rtc-ftrtc010.c
+++ b/drivers/rtc/rtc-ftrtc010.c
@@ -72,7 +72,7 @@ static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD);
- time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
+ time = offset + (timeu64_t)days * 86400 + hour * 3600 + min * 60 + sec;
rtc_time64_to_tm(time, tm);
@@ -92,7 +92,7 @@ static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
- offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);
+ offset = time - ((timeu64_t)day * 86400 + hour * 3600 + min * 60 + sec);
writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD);
writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR);
@@ -119,51 +119,33 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
- rtc->pclk = devm_clk_get(dev, "PCLK");
- if (IS_ERR(rtc->pclk)) {
+ rtc->pclk = devm_clk_get_enabled(dev, "PCLK");
+ if (IS_ERR_OR_NULL(rtc->pclk)) {
dev_err(dev, "could not get PCLK\n");
- } else {
- ret = clk_prepare_enable(rtc->pclk);
- if (ret) {
- dev_err(dev, "failed to enable PCLK\n");
- return ret;
- }
+ return PTR_ERR_OR_ZERO(rtc->pclk);
}
- rtc->extclk = devm_clk_get(dev, "EXTCLK");
- if (IS_ERR(rtc->extclk)) {
+ rtc->extclk = devm_clk_get_enabled(dev, "EXTCLK");
+ if (IS_ERR_OR_NULL(rtc->extclk)) {
dev_err(dev, "could not get EXTCLK\n");
- } else {
- ret = clk_prepare_enable(rtc->extclk);
- if (ret) {
- dev_err(dev, "failed to enable EXTCLK\n");
- goto err_disable_pclk;
- }
+ return PTR_ERR_OR_ZERO(rtc->extclk);
}
rtc->rtc_irq = platform_get_irq(pdev, 0);
- if (rtc->rtc_irq < 0) {
- ret = rtc->rtc_irq;
- goto err_disable_extclk;
- }
+ if (rtc->rtc_irq < 0)
+ return rtc->rtc_irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENODEV;
- goto err_disable_extclk;
- }
+ if (!res)
+ return -ENODEV;
rtc->rtc_base = devm_ioremap(dev, res->start,
resource_size(res));
- if (!rtc->rtc_base) {
- ret = -ENOMEM;
- goto err_disable_extclk;
- }
+ if (!rtc->rtc_base)
+ return -ENOMEM;
rtc_dev = devm_rtc_allocate_device(dev);
- if (IS_ERR(rtc_dev)) {
- ret = PTR_ERR(rtc_dev);
- goto err_disable_extclk;
- }
+ if (IS_ERR(rtc_dev))
+ return PTR_ERR(rtc_dev);
rtc_dev->ops = &ftrtc010_rtc_ops;
@@ -178,25 +160,13 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
IRQF_SHARED, pdev->name, dev);
if (unlikely(ret))
- goto err_disable_extclk;
+ return ret;
- return devm_rtc_register_device(rtc_dev);
+ ret = devm_rtc_register_device(rtc_dev);
+ if (ret)
+ return ret;
-err_disable_extclk:
- clk_disable_unprepare(rtc->extclk);
-err_disable_pclk:
- clk_disable_unprepare(rtc->pclk);
- return ret;
-}
-
-static void ftrtc010_rtc_remove(struct platform_device *pdev)
-{
- struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev);
-
- if (!IS_ERR(rtc->extclk))
- clk_disable_unprepare(rtc->extclk);
- if (!IS_ERR(rtc->pclk))
- clk_disable_unprepare(rtc->pclk);
+ return 0;
}
static const struct of_device_id ftrtc010_rtc_dt_match[] = {
@@ -212,7 +182,6 @@ static struct platform_driver ftrtc010_rtc_driver = {
.of_match_table = ftrtc010_rtc_dt_match,
},
.probe = ftrtc010_rtc_probe,
- .remove = ftrtc010_rtc_remove,
};
module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);
diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c
index 1d52cc3def02..e3d7ca477e75 100644
--- a/drivers/rtc/rtc-hym8563.c
+++ b/drivers/rtc/rtc-hym8563.c
@@ -417,7 +417,7 @@ static irqreturn_t hym8563_irq(int irq, void *dev_id)
struct i2c_client *client = hym8563->client;
int data, ret;
- rtc_lock(hym8563->rtc);
+ guard(rtc_ops)(hym8563->rtc);
/* Clear the alarm flag */
@@ -425,7 +425,7 @@ static irqreturn_t hym8563_irq(int irq, void *dev_id)
if (data < 0) {
dev_err(&client->dev, "%s: error reading i2c data %d\n",
__func__, data);
- goto out;
+ return IRQ_HANDLED;
}
data &= ~HYM8563_CTL2_AF;
@@ -436,8 +436,6 @@ static irqreturn_t hym8563_irq(int irq, void *dev_id)
__func__, ret);
}
-out:
- rtc_unlock(hym8563->rtc);
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index ec86ca3f2c4c..1385cb43864b 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -162,19 +162,15 @@ static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
unsigned long events = 0;
int flags, flags_afe;
- rtc_lock(m41t80->rtc);
+ guard(rtc_ops)(m41t80->rtc);
flags_afe = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
- if (flags_afe < 0) {
- rtc_unlock(m41t80->rtc);
+ if (flags_afe < 0)
return IRQ_NONE;
- }
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
- if (flags <= 0) {
- rtc_unlock(m41t80->rtc);
+ if (flags <= 0)
return IRQ_NONE;
- }
if (flags & M41T80_FLAGS_AF) {
flags &= ~M41T80_FLAGS_AF;
@@ -189,8 +185,6 @@ static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
flags_afe);
}
- rtc_unlock(m41t80->rtc);
-
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c
index e12f0f806ec4..9b5b36b88122 100644
--- a/drivers/rtc/rtc-mcp795.c
+++ b/drivers/rtc/rtc-mcp795.c
@@ -352,7 +352,7 @@ static irqreturn_t mcp795_irq(int irq, void *data)
struct rtc_device *rtc = spi_get_drvdata(spi);
int ret;
- rtc_lock(rtc);
+ guard(rtc_ops)(rtc);
/* Disable alarm.
* There is no need to clear ALM0IF (Alarm 0 Interrupt Flag) bit,
@@ -364,7 +364,6 @@ static irqreturn_t mcp795_irq(int irq, void *data)
"Failed to disable alarm in IRQ (ret=%d)\n", ret);
rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
- rtc_unlock(rtc);
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
index 60596b0ea9d8..6616ca1f02c7 100644
--- a/drivers/rtc/rtc-mpfs.c
+++ b/drivers/rtc/rtc-mpfs.c
@@ -131,8 +131,8 @@ static int mpfs_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->enabled = mode & MODE_WAKE_EN;
- time = (u64)readl(rtcdev->base + ALARM_LOWER_REG) << 32;
- time |= (readl(rtcdev->base + ALARM_UPPER_REG) & ALARM_UPPER_MASK);
+ time = readl(rtcdev->base + ALARM_LOWER_REG);
+ time |= ((u64)readl(rtcdev->base + ALARM_UPPER_REG) & ALARM_UPPER_MASK) << 32;
rtc_time64_to_tm(time, &alrm->time);
return 0;
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 3d857681f760..d6e156516aa6 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -4,6 +4,8 @@
* Author: Tianping.Fang <tianping.fang@mediatek.com>
*/
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/mfd/mt6397/core.h>
@@ -243,10 +245,91 @@ static const struct rtc_class_ops mtk_rtc_ops = {
.set_alarm = mtk_rtc_set_alarm,
};
+/*
+ * The spare byte of each of these registers, in the order a board addresses
+ * them as RTC_NEW_SPARE0 to RTC_NEW_SPARE3.
+ */
+static const u32 mtk_rtc_spare_reg[] = {
+ RTC_AL_HOU, RTC_AL_DOM, RTC_AL_DOW, RTC_AL_MTH,
+};
+
+static int mtk_rtc_nvram_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct mt6397_rtc *rtc = priv;
+ u8 *buf = val;
+ u32 data;
+ int ret = 0;
+
+ if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) ||
+ bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset)
+ return -EINVAL;
+
+ mutex_lock(&rtc->lock);
+
+ while (bytes--) {
+ ret = regmap_read(rtc->regmap,
+ rtc->addr_base + mtk_rtc_spare_reg[offset++],
+ &data);
+ if (ret)
+ break;
+
+ *buf++ = FIELD_GET(RTC_SPARE_MASK, data);
+ }
+
+ mutex_unlock(&rtc->lock);
+
+ return ret;
+}
+
+static int mtk_rtc_nvram_write(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct mt6397_rtc *rtc = priv;
+ u8 *buf = val;
+ int ret = 0;
+
+ if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) ||
+ bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset)
+ return -EINVAL;
+
+ mutex_lock(&rtc->lock);
+
+ while (bytes--) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->addr_base + mtk_rtc_spare_reg[offset++],
+ RTC_SPARE_MASK,
+ FIELD_PREP(RTC_SPARE_MASK, *buf++));
+ if (ret)
+ goto out;
+ }
+
+ /*
+ * None of it reaches the always-on domain until the write trigger,
+ * which commits every pending alarm register at once -- so this runs
+ * under the same lock the alarm paths take, rather than landing in
+ * the middle of one of them.
+ */
+ ret = mtk_rtc_write_trigger(rtc);
+out:
+ mutex_unlock(&rtc->lock);
+
+ return ret;
+}
+
static int mtk_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
+ struct nvmem_config nvmem_cfg = {
+ .name = "mt6397_rtc_spare",
+ .word_size = 1,
+ .stride = 1,
+ .size = ARRAY_SIZE(mtk_rtc_spare_reg),
+ .type = NVMEM_TYPE_BATTERY_BACKED,
+ .reg_read = mtk_rtc_nvram_read,
+ .reg_write = mtk_rtc_nvram_write,
+ };
struct mt6397_rtc *rtc;
int ret;
@@ -293,7 +376,13 @@ static int mtk_rtc_probe(struct platform_device *pdev)
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);
+ ret = devm_rtc_register_device(rtc->rtc_dev);
+ if (ret)
+ return ret;
+
+ nvmem_cfg.priv = rtc;
+
+ return devm_rtc_nvmem_register(rtc->rtc_dev, &nvmem_cfg);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c
index 2f7ad57057a4..194ba077363a 100644
--- a/drivers/rtc/rtc-nct3018y.c
+++ b/drivers/rtc/rtc-nct3018y.c
@@ -4,6 +4,7 @@
#include <linux/bcd.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -23,6 +24,7 @@
#define NCT3018Y_REG_CTRL 0x0A /* timer control */
#define NCT3018Y_REG_ST 0x0B /* status */
#define NCT3018Y_REG_CLKO 0x0C /* clock out */
+#define NCT3018Y_REG_INTR_CTRL 0x12 /* intrusion control */
#define NCT3018Y_REG_PART 0x21 /* part info */
#define NCT3018Y_BIT_AF BIT(7)
@@ -34,6 +36,7 @@
#define NCT3018Y_BIT_OFIE BIT(2)
#define NCT3018Y_BIT_CIE BIT(1)
#define NCT3018Y_BIT_TWO BIT(0)
+#define NCT3018Y_BIT_INTRUSION BIT(1) /* in NCT3018Y_REG_INTR_CTRL */
#define NCT3018Y_REG_BAT_MASK 0x07
#define NCT3018Y_REG_CLKO_F_MASK 0x03 /* frequenc mask */
@@ -491,6 +494,95 @@ static const struct rtc_class_ops nct3018y_rtc_ops = {
.ioctl = nct3018y_ioctl,
};
+#if IS_REACHABLE(CONFIG_HWMON)
+
+static umode_t nct3018y_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ if (type == hwmon_intrusion && attr == hwmon_intrusion_alarm)
+ return 0644;
+
+ return 0;
+}
+
+static int nct3018y_hwmon_read(struct device *dev,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ struct nct3018y *nct3018y = dev_get_drvdata(dev);
+ int flags;
+
+ flags = i2c_smbus_read_byte_data(nct3018y->client,
+ NCT3018Y_REG_INTR_CTRL);
+ if (flags < 0)
+ return flags;
+
+ *val = !!(flags & NCT3018Y_BIT_INTRUSION);
+
+ return 0;
+}
+
+static int nct3018y_hwmon_write(struct device *dev,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel, long val)
+{
+ struct nct3018y *nct3018y = dev_get_drvdata(dev);
+ int flags;
+
+ /* The alarm latches until it is cleared, and only clearing is a
+ * meaningful thing to ask for.
+ */
+ if (val)
+ return -EINVAL;
+
+ flags = i2c_smbus_read_byte_data(nct3018y->client,
+ NCT3018Y_REG_INTR_CTRL);
+ if (flags < 0)
+ return flags;
+
+ return i2c_smbus_write_byte_data(nct3018y->client,
+ NCT3018Y_REG_INTR_CTRL,
+ flags & ~NCT3018Y_BIT_INTRUSION);
+}
+
+static const struct hwmon_channel_info * const nct3018y_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(intrusion, HWMON_INTRUSION_ALARM),
+ NULL
+};
+
+static const struct hwmon_ops nct3018y_hwmon_ops = {
+ .is_visible = nct3018y_hwmon_is_visible,
+ .read = nct3018y_hwmon_read,
+ .write = nct3018y_hwmon_write,
+};
+
+static const struct hwmon_chip_info nct3018y_hwmon_chip_info = {
+ .ops = &nct3018y_hwmon_ops,
+ .info = nct3018y_hwmon_info,
+};
+
+static void nct3018y_hwmon_register(struct nct3018y *nct3018y)
+{
+ struct device *dev;
+
+ dev = devm_hwmon_device_register_with_info(&nct3018y->client->dev,
+ "nct3018y", nct3018y,
+ &nct3018y_hwmon_chip_info,
+ NULL);
+ if (IS_ERR(dev))
+ dev_warn(&nct3018y->client->dev,
+ "unable to register hwmon device %ld\n", PTR_ERR(dev));
+}
+
+#else
+
+static void nct3018y_hwmon_register(struct nct3018y *nct3018y)
+{
+}
+
+#endif /* IS_REACHABLE(CONFIG_HWMON) */
+
static int nct3018y_probe(struct i2c_client *client)
{
struct nct3018y *nct3018y;
@@ -568,6 +660,8 @@ static int nct3018y_probe(struct i2c_client *client)
nct3018y_clkout_register_clk(nct3018y);
#endif
+ nct3018y_hwmon_register(nct3018y);
+
return devm_rtc_register_device(nct3018y->rtc);
}
diff --git a/drivers/rtc/rtc-nct6694.c b/drivers/rtc/rtc-nct6694.c
index 35401a0d9cf5..1cf9b672256a 100644
--- a/drivers/rtc/rtc-nct6694.c
+++ b/drivers/rtc/rtc-nct6694.c
@@ -210,20 +210,16 @@ static irqreturn_t nct6694_irq(int irq, void *dev_id)
};
int ret;
- rtc_lock(data->rtc);
+ guard(rtc_ops)(data->rtc);
sts->irq_en = NCT6694_RTC_IRQ_EN;
sts->irq_pend = NCT6694_RTC_IRQ_STS;
ret = nct6694_write_msg(data->nct6694, &cmd_hd, sts);
- if (ret) {
- rtc_unlock(data->rtc);
+ if (ret)
return IRQ_NONE;
- }
rtc_update_irq(data->rtc, 1, RTC_IRQF | RTC_AF);
- rtc_unlock(data->rtc);
-
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-nvidia-vrs10.c b/drivers/rtc/rtc-nvidia-vrs10.c
index b15796698558..caac63f4e0fc 100644
--- a/drivers/rtc/rtc-nvidia-vrs10.c
+++ b/drivers/rtc/rtc-nvidia-vrs10.c
@@ -358,11 +358,8 @@ static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data)
if (ret < 0)
return IRQ_NONE;
- if (ret & NVVRS_INT_SRC1_RTC_MASK) {
- rtc_lock(info->rtc);
+ if (ret & NVVRS_INT_SRC1_RTC_MASK)
rtc_update_irq(info->rtc, 1, RTC_IRQF | RTC_AF);
- rtc_unlock(info->rtc);
- }
/* Clear all interrupts */
if (nvvrs_pseq_irq_clear(info) < 0)
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 0f90065e352c..18492165a19f 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -408,7 +408,7 @@ static struct omap_rtc *omap_rtc_power_off_rtc;
* generates pmic_pwr_enable control, which can be used to control an external
* PMIC.
*/
-int omap_rtc_power_off_program(struct device *dev)
+int omap_rtc_power_off_program(void)
{
struct omap_rtc *rtc = omap_rtc_power_off_rtc;
struct rtc_time tm;
@@ -481,10 +481,9 @@ EXPORT_SYMBOL(omap_rtc_power_off_program);
*/
static void omap_rtc_power_off(void)
{
- struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc;
u32 val;
- omap_rtc_power_off_program(rtc->dev.parent);
+ omap_rtc_power_off_program();
/* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */
omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc);
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index e714661e61a9..22c626d57090 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -310,7 +310,8 @@ static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
unsigned int val = 0;
int ret = IRQ_NONE;
- rtc_lock(pcf2123->rtc);
+ guard(rtc_ops)(pcf2123->rtc);
+
regmap_read(pcf2123->map, PCF2123_REG_CTRL2, &val);
/* Alarm? */
@@ -323,8 +324,6 @@ static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
rtc_update_irq(pcf2123->rtc, 1, RTC_IRQF | RTC_AF);
}
- rtc_unlock(pcf2123->rtc);
-
return ret;
}
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 7eebdb058067..3801acc9ac8d 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -479,7 +479,8 @@ static int pcf8563_probe(struct i2c_client *client)
dev_dbg(&client->dev, "%s\n", __func__);
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
+ !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -ENODEV;
pcf8563 = devm_kzalloc(&client->dev, sizeof(struct pcf8563),
@@ -531,7 +532,7 @@ static int pcf8563_probe(struct i2c_client *client)
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8563_irq,
IRQF_SHARED | IRQF_ONESHOT | irqflags,
- pcf8563_driver.driver.name, client);
+ pcf8563_driver.driver.name, pcf8563);
if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n",
client->irq);
diff --git a/drivers/rtc/rtc-raspberrypi.c b/drivers/rtc/rtc-raspberrypi.c
new file mode 100644
index 000000000000..0547a96c62ac
--- /dev/null
+++ b/drivers/rtc/rtc-raspberrypi.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/**
+ * rtc-raspberrypi.c
+ *
+ * RTC driver using firmware mailbox
+ * Supports battery backed RTC and wake alarms
+ *
+ * Based on rtc-meson-vrtc by Neil Armstrong
+ *
+ * Copyright (c) 2023, Raspberry Pi Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/of.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RTC_TIME 0
+#define RTC_ALARM 1
+#define RTC_ALARM_PENDING 2
+#define RTC_ALARM_ENABLE 3
+#define RTC_BBAT_CHG_VOLTS 4
+#define RTC_BBAT_CHG_VOLTS_MIN 5
+#define RTC_BBAT_CHG_VOLTS_MAX 6
+#define RTC_BBAT_VOLTS 7
+
+struct rpi_rtc_data {
+ struct rtc_device *rtc;
+ struct rpi_firmware *fw;
+ u32 bbat_vchg_millivolts;
+ u32 bbat_vchg_min_millivolts;
+ u32 bbat_vchg_max_millivolts;
+};
+
+struct rpi_rtc_reg {
+ __le32 reg;
+ __le32 val;
+} __packed;
+
+static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_TIME)
+ };
+ int err;
+
+ err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ rtc_time64_to_tm(le32_to_cpu(data.val), tm);
+ return err;
+}
+
+static int rpi_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_TIME),
+ .val = cpu_to_le32(rtc_tm_to_time64(tm))
+ };
+
+ return rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+}
+
+static int rpi_rtc_alarm_irq_is_enabled(struct device *dev, unsigned char *enabled)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM_ENABLE)
+ };
+ int err;
+
+ err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ *enabled = le32_to_cpu(data.val) & 0x1;
+ return err;
+}
+
+static int rpi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM_ENABLE),
+ .val = cpu_to_le32(enabled)
+ };
+
+ return rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+}
+
+static int rpi_rtc_alarm_clear_pending(struct device *dev)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM_PENDING),
+ .val = cpu_to_le32(1)
+ };
+
+ return rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+}
+
+static int rpi_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM)
+ };
+ int err;
+
+ err = rpi_rtc_alarm_irq_is_enabled(dev, &alarm->enabled);
+ if (!err)
+ err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ rtc_time64_to_tm(le32_to_cpu(data.val), &alarm->time);
+
+ return err;
+}
+
+static int rpi_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_ALARM),
+ .val = cpu_to_le32(rtc_tm_to_time64(&alarm->time))
+ };
+ int err;
+
+ err = rpi_rtc_alarm_clear_pending(dev);
+
+ if (!err)
+ err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+
+ if (!err)
+ err = rpi_rtc_alarm_irq_enable(dev, alarm->enabled);
+
+ return err;
+}
+
+static const struct rtc_class_ops rpi_rtc_ops = {
+ .read_time = rpi_rtc_read_time,
+ .set_time = rpi_rtc_set_time,
+ .read_alarm = rpi_rtc_read_alarm,
+ .set_alarm = rpi_rtc_set_alarm,
+ .alarm_irq_enable = rpi_rtc_alarm_irq_enable,
+};
+
+static void rpi_rtc_set_limits(struct device *dev)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS_MIN)
+ };
+
+ int err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ if (!err)
+ rtc->bbat_vchg_min_millivolts = le32_to_cpu(data.val) / 1000U;
+ else
+ dev_warn(dev, "failed to get minimum trickle charge voltage\n");
+
+ data.reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS_MAX);
+ data.val = cpu_to_le32(0);
+ err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
+ &data, sizeof(data));
+ if (!err)
+ rtc->bbat_vchg_max_millivolts = le32_to_cpu(data.val) / 1000U;
+ else
+ dev_warn(dev, "failed to get maximum trickle charge voltage\n");
+}
+
+static void rpi_rtc_set_charge_voltage(struct device *dev)
+{
+ struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
+ struct rpi_rtc_reg data = {
+ .reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS),
+ .val = cpu_to_le32(rtc->bbat_vchg_millivolts * 1000U)
+ };
+ int err;
+
+ if (rtc->bbat_vchg_millivolts != 0 &&
+ (rtc->bbat_vchg_millivolts < rtc->bbat_vchg_min_millivolts ||
+ rtc->bbat_vchg_millivolts > rtc->bbat_vchg_max_millivolts)) {
+ dev_warn(dev, "trickle charge voltage %umV is outside of the supported range (%umV - %umV)\n",
+ rtc->bbat_vchg_millivolts,
+ rtc->bbat_vchg_min_millivolts,
+ rtc->bbat_vchg_max_millivolts);
+ return;
+ }
+
+ err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
+ &data, sizeof(data));
+
+ if (err)
+ dev_err(dev, "failed to set trickle charge voltage to %umV: %d\n",
+ rtc->bbat_vchg_millivolts, err);
+ else if (rtc->bbat_vchg_millivolts)
+ dev_info(dev, "trickle charging enabled at %umV\n",
+ rtc->bbat_vchg_millivolts);
+}
+
+static int rpi_rtc_probe(struct platform_device *pdev)
+{
+ struct rpi_rtc_data *rtc;
+ struct device *dev = &pdev->dev;
+ struct rpi_firmware *firmware;
+ int ret;
+
+ // Get the firmware device from the parent device
+ firmware = devm_rpi_firmware_get(dev, dev->parent->of_node);
+
+ if (!firmware)
+ return -EPROBE_DEFER;
+
+ rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->fw = firmware;
+
+ ret = devm_device_init_wakeup(dev);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, rtc);
+
+ rtc->rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc->rtc))
+ return PTR_ERR(rtc->rtc);
+
+ rtc->rtc->range_max = U32_MAX; /* 2106-02-07 */
+
+ set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->rtc->features);
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc->features);
+
+ rtc->rtc->ops = &rpi_rtc_ops;
+
+ rpi_rtc_alarm_clear_pending(dev);
+
+ /*
+ * The trickle-voltage property lives on the parent firmware node
+ * because we deliberately do not create a DT child node just to
+ * instantiate this driver (see DT maintainer guidance).
+ * The firmware driver registers us as a platform device at runtime.
+ */
+ rtc->bbat_vchg_millivolts = 0;
+ of_property_read_u32(dev->parent->of_node, "trickle-voltage-millivolt",
+ &rtc->bbat_vchg_millivolts);
+
+ rpi_rtc_set_limits(dev);
+ rpi_rtc_set_charge_voltage(dev);
+
+ return devm_rtc_register_device(rtc->rtc);
+}
+
+static const struct platform_device_id raspberrypi_rtc_id[] = {
+ { "raspberrypi-rtc" },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, raspberrypi_rtc_id);
+
+static struct platform_driver rpi_rtc_driver = {
+ .driver = {
+ .name = "raspberrypi-rtc",
+ },
+ .id_table = raspberrypi_rtc_id,
+ .probe = rpi_rtc_probe
+};
+
+module_platform_driver(rpi_rtc_driver);
+
+MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.com>");
+MODULE_AUTHOR("Sander Speetjens <sander.speetjens@gmail.com>");
+MODULE_DESCRIPTION("Raspberry Pi RTC driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 24bd795d9d95..9ab6f2c28f7b 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -52,6 +52,7 @@
#define RS5C_REG_CTRL2 15
# define RS5C372_CTRL2_24 (1 << 5)
# define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2x2x */
+# define R2223x_CTRL2_ECO (1 << 7) /* only if R2223x */
# define R2x2x_CTRL2_VDET (1 << 6) /* only if R2x2x */
# define R2x2x_CTRL2_XSTP (1 << 5) /* only if R2x2x */
# define R2x2x_CTRL2_PON (1 << 4) /* only if R2x2x */
@@ -68,6 +69,7 @@ enum rtc_type {
rtc_undef = 0,
rtc_r2025sd,
rtc_r2221tl,
+ rtc_r2223x,
rtc_rs5c372a,
rtc_rs5c372b,
rtc_rv5c386,
@@ -77,6 +79,7 @@ enum rtc_type {
static const struct i2c_device_id rs5c372_id[] = {
{ .name = "r2025sd", .driver_data = rtc_r2025sd },
{ .name = "r2221tl", .driver_data = rtc_r2221tl },
+ { .name = "r2223x", .driver_data = rtc_r2223x },
{ .name = "rs5c372a", .driver_data = rtc_rs5c372a },
{ .name = "rs5c372b", .driver_data = rtc_rs5c372b },
{ .name = "rv5c386", .driver_data = rtc_rv5c386 },
@@ -95,6 +98,10 @@ static const __maybe_unused struct of_device_id rs5c372_of_match[] = {
.data = (void *)rtc_r2221tl
},
{
+ .compatible = "ricoh,r2223x",
+ .data = (void *)rtc_r2223x
+ },
+ {
.compatible = "ricoh,rs5c372a",
.data = (void *)rtc_rs5c372a
},
@@ -221,8 +228,10 @@ static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
+ case rtc_r2223x:
if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
- (rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) {
+ ((rs5c->type == rtc_r2221tl || rs5c->type == rtc_r2223x) &&
+ (ctrl2 & R2x2x_CTRL2_XSTP))) {
dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
return -EINVAL;
}
@@ -292,6 +301,7 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
+ case rtc_r2223x:
ctrl2 &= ~(R2x2x_CTRL2_VDET | R2x2x_CTRL2_PON);
if (rs5c->type == rtc_r2025sd)
ctrl2 |= R2x2x_CTRL2_XSTP;
@@ -511,8 +521,10 @@ static int rs5c372_ioctl(struct device *dev, unsigned int cmd, unsigned long arg
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
+ case rtc_r2223x:
if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
- (rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) {
+ ((rs5c->type == rtc_r2221tl || rs5c->type == rtc_r2223x) &&
+ (ctrl2 & R2x2x_CTRL2_XSTP))) {
flags |= RTC_VL_DATA_INVALID;
}
if (ctrl2 & R2x2x_CTRL2_VDET)
@@ -527,7 +539,8 @@ static int rs5c372_ioctl(struct device *dev, unsigned int cmd, unsigned long arg
return put_user(flags, (unsigned int __user *)arg);
case RTC_VL_CLR:
/* clear VDET bit */
- if (rs5c->type == rtc_r2025sd || rs5c->type == rtc_r2221tl) {
+ if (rs5c->type == rtc_r2025sd || rs5c->type == rtc_r2221tl ||
+ rs5c->type == rtc_r2223x) {
ctrl2 &= ~R2x2x_CTRL2_VDET;
if (i2c_smbus_write_byte_data(rs5c->client, addr, ctrl2) < 0) {
dev_dbg(&rs5c->client->dev, "%s: write error in line %i\n",
@@ -554,6 +567,7 @@ static int rs5c372_read_offset(struct device *dev, long *offset)
switch (rs5c->type) {
case rtc_r2221tl:
+ case rtc_r2223x:
ppb_per_step = val & R2221TL_TRIM_DEV ? 1017 : 3051;
break;
case rtc_rs5c372a:
@@ -600,6 +614,7 @@ static int rs5c372_set_offset(struct device *dev, long offset)
}
break;
case rtc_r2221tl:
+ case rtc_r2223x:
/*
* Check if it is possible to use high resolution mode (DEV=1).
* In this mode, the minimum resolution is 2 / (32768 * 20 * 3),
@@ -750,6 +765,7 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
return ret;
break;
case rtc_r2221tl:
+ case rtc_r2223x:
if (!(buf[1] & R2x2x_CTRL2_XSTP))
return ret;
break;
@@ -768,6 +784,7 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
break;
case rtc_r2025sd:
case rtc_r2221tl:
+ case rtc_r2223x:
case rtc_rv5c386:
case rtc_rv5c387a:
buf[0] |= RV5C387_CTRL1_24;
@@ -791,6 +808,24 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
return 0;
}
+static int rs5c372_set_eco_mode(struct rs5c372 *rs5c372, bool eco)
+{
+ struct i2c_client *client = rs5c372->client;
+ int ctrl2;
+
+ ctrl2 = i2c_smbus_read_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2));
+ if (ctrl2 < 0)
+ return ctrl2;
+
+ if (eco)
+ ctrl2 |= R2223x_CTRL2_ECO;
+ else
+ ctrl2 &= ~R2223x_CTRL2_ECO;
+
+ return i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2),
+ ctrl2);
+}
+
static int rs5c372_probe(struct i2c_client *client)
{
int err = 0;
@@ -847,6 +882,7 @@ static int rs5c372_probe(struct i2c_client *client)
break;
case rtc_r2025sd:
case rtc_r2221tl:
+ case rtc_r2223x:
case rtc_rv5c386:
case rtc_rv5c387a:
if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
@@ -876,6 +912,7 @@ static int rs5c372_probe(struct i2c_client *client)
({ char *s; switch (rs5c372->type) {
case rtc_r2025sd: s = "r2025sd"; break;
case rtc_r2221tl: s = "r2221tl"; break;
+ case rtc_r2223x: s = "r2223x"; break;
case rtc_rs5c372a: s = "rs5c372a"; break;
case rtc_rs5c372b: s = "rs5c372b"; break;
case rtc_rv5c386: s = "rv5c386"; break;
@@ -885,6 +922,15 @@ static int rs5c372_probe(struct i2c_client *client)
rs5c372->time24 ? "24hr" : "am/pm"
);
+ if (rs5c372->type == rtc_r2223x) {
+ bool eco = device_property_read_bool(&client->dev,
+ "ricoh,eco-mode");
+
+ err = rs5c372_set_eco_mode(rs5c372, eco);
+ if (err < 0)
+ goto exit;
+ }
+
/* REVISIT use client->irq to register alarm irq ... */
rs5c372->rtc = devm_rtc_device_register(&client->dev,
rs5c372_driver.driver.name,
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index 98953af2a24a..c348b31928e9 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -270,19 +270,17 @@ static irqreturn_t rv3029_handle_irq(int irq, void *dev_id)
unsigned long events = 0;
int ret;
- rtc_lock(rv3029->rtc);
+ guard(rtc_ops)(rv3029->rtc);
ret = regmap_read(rv3029->regmap, RV3029_IRQ_CTRL, &controls);
if (ret) {
dev_warn(dev, "Read IRQ Control Register error %d\n", ret);
- rtc_unlock(rv3029->rtc);
return IRQ_NONE;
}
ret = regmap_read(rv3029->regmap, RV3029_IRQ_FLAGS, &flags);
if (ret) {
dev_warn(dev, "Read IRQ Flags Register error %d\n", ret);
- rtc_unlock(rv3029->rtc);
return IRQ_NONE;
}
@@ -297,7 +295,6 @@ static irqreturn_t rv3029_handle_irq(int irq, void *dev_id)
regmap_write(rv3029->regmap, RV3029_IRQ_FLAGS, flags);
regmap_write(rv3029->regmap, RV3029_IRQ_CTRL, controls);
}
- rtc_unlock(rv3029->rtc);
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
index ce3954132336..0a9be6ea62d0 100644
--- a/drivers/rtc/rtc-rx8010.c
+++ b/drivers/rtc/rtc-rx8010.c
@@ -73,11 +73,10 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
struct rx8010_data *rx8010 = i2c_get_clientdata(client);
int flagreg, err;
- rtc_lock(rx8010->rtc);
+ guard(rtc_ops)(rx8010->rtc);
err = regmap_read(rx8010->regs, RX8010_FLAG, &flagreg);
if (err) {
- rtc_unlock(rx8010->rtc);
return IRQ_NONE;
}
@@ -100,7 +99,6 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
}
err = regmap_write(rx8010->regs, RX8010_FLAG, flagreg);
- rtc_unlock(rx8010->rtc);
return err ? IRQ_NONE : IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index 5eeaa929f3ef..2f2deb59cbee 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -180,10 +180,11 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
struct rx8025_data *rx8025 = i2c_get_clientdata(client);
int status, xstp;
- rtc_lock(rx8025->rtc);
+ guard(rtc_ops)(rx8025->rtc);
+
status = rx8025_read_reg(client, RX8025_REG_CTRL2);
if (status < 0)
- goto out;
+ return IRQ_HANDLED;
xstp = rx8025_is_osc_stopped(rx8025->model, status);
if (xstp)
@@ -201,13 +202,10 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
status &= RX8025_BIT_CTRL2_DAFG;
if (rx8025_write_reg(client, RX8025_REG_CTRL1,
rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE))
- goto out;
+ return IRQ_HANDLED;
rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF);
}
-out:
- rtc_unlock(rx8025->rtc);
-
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
index b9d69ebdd224..1db518ab3a3a 100644
--- a/drivers/rtc/rtc-rzn1.c
+++ b/drivers/rtc/rtc-rzn1.c
@@ -68,6 +68,7 @@
struct rzn1_rtc_data {
bool has_subu;
+ bool broken_irqs;
};
struct rzn1_rtc {
@@ -396,6 +397,11 @@ static const struct rtc_class_ops rzn1_rtc_ops_scmp = {
.alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
};
+static const struct rtc_class_ops rzn1_rtc_ops_scmp_no_alarm = {
+ .read_time = rzn1_rtc_read_time,
+ .set_time = rzn1_rtc_set_time,
+};
+
static void rzn1_rtc_disable_hardware(void *data)
{
struct device *dev = data;
@@ -431,10 +437,6 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
if (IS_ERR(rtc->base))
return dev_err_probe(dev, PTR_ERR(rtc->base), "Missing reg\n");
- irq = platform_get_irq_byname(pdev, "alarm");
- if (irq < 0)
- return irq;
-
rtc->rtcdev = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc->rtcdev))
return PTR_ERR(rtc->rtcdev);
@@ -503,25 +505,40 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
spin_lock_init(&rtc->ctl1_access_lock);
- ret = devm_request_irq(dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc);
- if (ret)
- return dev_err_probe(dev, ret, "RTC alarm interrupt not available\n");
-
- irq = platform_get_irq_byname_optional(pdev, "pps");
- if (irq == -EPROBE_DEFER)
- return irq;
- if (irq >= 0)
- ret = devm_request_irq(dev, irq, rzn1_rtc_1s_irq, 0, "RZN1 RTC 1s", rtc);
-
- if (irq < 0 || ret) {
- set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
+ if (data->broken_irqs) {
+ /* All known broken irqs are on SCMP only variants */
+ rtc->rtcdev->ops = &rzn1_rtc_ops_scmp_no_alarm;
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
- dev_warn(dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n");
+ } else {
+ irq = platform_get_irq_byname(pdev, "alarm");
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc);
+ if (ret)
+ return dev_err_probe(dev, ret, "RTC alarm interrupt not available\n");
+
+ irq = platform_get_irq_byname_optional(pdev, "pps");
+ if (irq == -EPROBE_DEFER)
+ return irq;
+ if (irq >= 0)
+ ret = devm_request_irq(dev, irq, rzn1_rtc_1s_irq, 0, "RZN1 RTC 1s", rtc);
+
+ if (irq < 0 || ret) {
+ set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
+ dev_warn(dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n");
+ }
}
return devm_rtc_register_device(rtc->rtcdev);
}
+static const struct rzn1_rtc_data rzn1_rtc_r8a78000_data = {
+ .has_subu = false,
+ .broken_irqs = true,
+};
+
static const struct rzn1_rtc_data rzn1_rtc_rzt2h_data = {
.has_subu = false,
};
@@ -531,6 +548,7 @@ static const struct rzn1_rtc_data rzn1_rtc_rzn1_data = {
};
static const struct of_device_id rzn1_rtc_of_match[] = {
+ { .compatible = "renesas,r8a78000-rtc", .data = &rzn1_rtc_r8a78000_data },
{ .compatible = "renesas,r9a09g077-rtc", .data = &rzn1_rtc_rzt2h_data },
{ .compatible = "renesas,rzn1-rtc", .data = &rzn1_rtc_rzn1_data },
{ /* sentinel */ }
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index d4ebf3eb54aa..1c4e4bd7afe4 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -465,7 +465,7 @@ static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
const struct stm32_rtc_events *evts = &rtc->data->events;
unsigned int status, cr;
- rtc_lock(rtc->rtc_dev);
+ guard(rtc_ops)(rtc->rtc_dev);
status = readl_relaxed(rtc->base + regs->sr);
cr = readl_relaxed(rtc->base + regs->cr);
@@ -482,8 +482,6 @@ static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
stm32_rtc_clear_event_flags(rtc, evts->alra);
}
- rtc_unlock(rtc->rtc_dev);
-
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index 7fc60880e409..c6916edbf400 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -231,6 +231,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
const char *iosc_name = "rtc-int-osc";
const char *clkout_name = "osc32k-out";
const char *parents[2];
+ struct resource res;
u32 reg;
rtc = kzalloc_obj(*rtc);
@@ -267,9 +268,6 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
}
writel(reg, rtc->base + SUN6I_LOSC_CTRL);
- /* Yes, I know, this is ugly. */
- sun6i_rtc = rtc;
-
of_property_read_string_index(node, "clock-output-names", 2,
&iosc_name);
@@ -280,7 +278,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
300000000);
if (IS_ERR(rtc->int_osc)) {
pr_crit("Couldn't register the internal oscillator\n");
- goto err;
+ goto err_unmap;
}
parents[0] = clk_hw_get_name(rtc->int_osc);
@@ -309,7 +307,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
&rtc->lock);
if (IS_ERR(rtc->ext_losc)) {
pr_crit("Couldn't register the LOSC external gate\n");
- goto err_register;
+ goto err_losc;
}
clk_data->num = 3;
@@ -317,12 +315,22 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
clk_data->hws[2] = rtc->int_osc;
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+
+ /* Yes, I know, this is ugly. */
+ sun6i_rtc = rtc;
return;
+err_losc:
+ clk_unregister(rtc->losc);
err_register:
clk_hw_unregister_fixed_rate(rtc->int_osc);
+err_unmap:
+ iounmap(rtc->base);
+ of_address_to_resource(node, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
err:
kfree(clk_data);
+ kfree(rtc);
}
static const struct sun6i_rtc_clk_data sun6i_a31_rtc_data = {
@@ -350,6 +358,10 @@ static void __init sun8i_a23_rtc_clk_init(struct device_node *node)
CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc",
sun8i_a23_rtc_clk_init);
+/* The B288 RTC clocks are the same as the A23's */
+CLK_OF_DECLARE_DRIVER(sun8i_b288_rtc_clk, "allwinner,sun8i-b288-rtc",
+ sun8i_a23_rtc_clk_init);
+
static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = {
.rc_osc_rate = 16000000,
.fixed_prescaler = 32,
@@ -859,6 +871,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
static const struct of_device_id sun6i_rtc_dt_ids[] = {
{ .compatible = "allwinner,sun6i-a31-rtc" },
{ .compatible = "allwinner,sun8i-a23-rtc" },
+ { .compatible = "allwinner,sun8i-b288-rtc" },
{ .compatible = "allwinner,sun8i-h3-rtc" },
{ .compatible = "allwinner,sun8i-r40-rtc" },
{ .compatible = "allwinner,sun8i-v3-rtc" },
diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c
index dc52a2197d24..82979122417d 100644
--- a/drivers/soc/ti/pm33xx.c
+++ b/drivers/soc/ti/pm33xx.c
@@ -174,7 +174,7 @@ static struct wkup_m3_wakeup_src rtc_wake_src(void)
static int am33xx_rtc_only_idle(unsigned long wfi_flags)
{
- omap_rtc_power_off_program(&omap_rtc->dev);
+ omap_rtc_power_off_program();
am33xx_do_wfi_sram(wfi_flags);
return 0;
}
diff --git a/include/linux/mfd/mt6397/rtc.h b/include/linux/mfd/mt6397/rtc.h
index 27883af44f87..f4da579ec638 100644
--- a/include/linux/mfd/mt6397/rtc.h
+++ b/include/linux/mfd/mt6397/rtc.h
@@ -49,6 +49,13 @@
#define RTC_AL_SEC 0x0018
+/* The high byte of four of the alarms is spare, always-on storage */
+#define RTC_AL_HOU 0x001c
+#define RTC_AL_DOM 0x001e
+#define RTC_AL_DOW 0x0020
+#define RTC_AL_MTH 0x0022
+#define RTC_SPARE_MASK GENMASK(15, 8)
+
#define RTC_AL_SEC_MASK 0x003f
#define RTC_AL_MIN_MASK 0x003f
#define RTC_AL_HOU_MASK 0x001f
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index c09fc22819d0..169d93520dbd 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -13,6 +13,7 @@
#define _LINUX_RTC_H_
+#include <linux/cleanup.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/nvmem-provider.h>
@@ -167,6 +168,9 @@ struct rtc_device {
#define rtc_lock(d) mutex_lock(&d->ops_lock)
#define rtc_unlock(d) mutex_unlock(&d->ops_lock)
+DEFINE_GUARD(rtc_ops, struct rtc_device *, mutex_lock(&_T->ops_lock),
+ mutex_unlock(&_T->ops_lock))
+
/* useful timestamps */
#define RTC_TIMESTAMP_BEGIN_0000 -62167219200ULL /* 0000-01-01 00:00:00 */
#define RTC_TIMESTAMP_BEGIN_1900 -2208988800LL /* 1900-01-01 00:00:00 */
@@ -201,6 +205,7 @@ extern void rtc_update_irq(struct rtc_device *rtc,
extern struct rtc_device *rtc_class_open(const char *name);
extern void rtc_class_close(struct rtc_device *rtc);
+DEFINE_FREE(rtc_class_close, struct rtc_device *, if (_T) rtc_class_close(_T));
extern int rtc_irq_set_state(struct rtc_device *rtc, int enabled);
extern int rtc_irq_set_freq(struct rtc_device *rtc, int freq);
diff --git a/include/linux/rtc/rtc-omap.h b/include/linux/rtc/rtc-omap.h
index 9f03a329e63f..d6ec7c4daea6 100644
--- a/include/linux/rtc/rtc-omap.h
+++ b/include/linux/rtc/rtc-omap.h
@@ -3,5 +3,5 @@
#ifndef _LINUX_RTCOMAP_H_
#define _LINUX_RTCOMAP_H_
-int omap_rtc_power_off_program(struct device *dev);
+int omap_rtc_power_off_program(void);
#endif /* _LINUX_RTCOMAP_H_ */
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
index 975bef529854..8c3d43977a03 100644
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -75,6 +75,7 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
+ RPI_FIRMWARE_GET_RTC_REG = 0x00030087,
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
@@ -92,6 +93,7 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066,
+ RPI_FIRMWARE_SET_RTC_REG = 0x00038087,
/* Dispmanx TAGS */
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
diff --git a/tools/testing/selftests/rtc/rtctest.c b/tools/testing/selftests/rtc/rtctest.c
index 8047d9879039..552191fe1ca0 100644
--- a/tools/testing/selftests/rtc/rtctest.c
+++ b/tools/testing/selftests/rtc/rtctest.c
@@ -49,7 +49,7 @@ TEST_F(rtc, date_read) {
struct rtc_time rtc_tm;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
/* Read the RTC time/date */
@@ -116,9 +116,10 @@ TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
long iter_count = 0;
struct rtc_time rtc_tm;
time_t start_rtc_read, prev_rtc_read;
+ struct timespec prev_mono, cur_mono;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
@@ -126,25 +127,31 @@ TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
ASSERT_NE(-1, rc);
+ clock_gettime(CLOCK_MONOTONIC, &prev_mono);
start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
prev_rtc_read = start_rtc_read;
do {
time_t rtc_read;
+ time_t delta_s = 0;
rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
ASSERT_NE(-1, rc);
+ clock_gettime(CLOCK_MONOTONIC, &cur_mono);
rtc_read = rtc_time_to_timestamp(&rtc_tm);
+ delta_s = cur_mono.tv_sec - prev_mono.tv_sec;
+
/* Time should not go backwards */
ASSERT_LE(prev_rtc_read, rtc_read);
- /* Time should not increase more then 1s at a time */
- ASSERT_GE(prev_rtc_read + 1, rtc_read);
+ /* Time should not increase more then elapsed time + 1s */
+ ASSERT_GE(prev_rtc_read + delta_s + 1, rtc_read);
/* Sleep 11ms to avoid killing / overheating the RTC */
nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
prev_rtc_read = rtc_read;
+ prev_mono = cur_mono;
iter_count++;
} while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
@@ -156,15 +163,14 @@ TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
unsigned long data;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
/* Turn on update interrupts */
rc = ioctl(self->fd, RTC_UIE_ON, 0);
if (rc == -1) {
ASSERT_EQ(EINVAL, errno);
- TH_LOG("skip update IRQs not supported.");
- return;
+ SKIP(return, "update IRQs are not supported.");
}
for (i = 0; i < NUM_UIE; i++) {
@@ -185,15 +191,14 @@ TEST_F(rtc, uie_select) {
unsigned long data;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
/* Turn on update interrupts */
rc = ioctl(self->fd, RTC_UIE_ON, 0);
if (rc == -1) {
ASSERT_EQ(EINVAL, errno);
- TH_LOG("skip update IRQs not supported.");
- return;
+ SKIP(return, "update IRQs are not supported.");
}
for (i = 0; i < NUM_UIE; i++) {
@@ -229,14 +234,14 @@ TEST_F(rtc, alarm_alm_set) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 1);
if (alarm_state == RTC_ALARM_DISABLED)
- SKIP(return, "Skipping test since alarms are not supported.");
+ SKIP(return, "alarms are not supported.");
if (alarm_state == RTC_ALARM_RES_MINUTE)
- SKIP(return, "Skipping test since alarms has only minute granularity.");
+ SKIP(return, "alarms has only minute granularity.");
rc = ioctl(self->fd, RTC_RD_TIME, &tm);
ASSERT_NE(-1, rc);
@@ -252,8 +257,7 @@ TEST_F(rtc, alarm_alm_set) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
- TH_LOG("skip alarms are not supported.");
- return;
+ SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_ALM_READ, &tm);
@@ -299,14 +303,14 @@ TEST_F(rtc, alarm_wkalm_set) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 1);
if (alarm_state == RTC_ALARM_DISABLED)
- SKIP(return, "Skipping test since alarms are not supported.");
+ SKIP(return, "alarms are not supported.");
if (alarm_state == RTC_ALARM_RES_MINUTE)
- SKIP(return, "Skipping test since alarms has only minute granularity.");
+ SKIP(return, "alarms has only minute granularity.");
rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
ASSERT_NE(-1, rc);
@@ -324,8 +328,7 @@ TEST_F(rtc, alarm_wkalm_set) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
- TH_LOG("skip alarms are not supported.");
- return;
+ SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
@@ -363,12 +366,12 @@ TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 0);
if (alarm_state == RTC_ALARM_DISABLED)
- SKIP(return, "Skipping test since alarms are not supported.");
+ SKIP(return, "alarms are not supported.");
rc = ioctl(self->fd, RTC_RD_TIME, &tm);
ASSERT_NE(-1, rc);
@@ -384,8 +387,7 @@ TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
- TH_LOG("skip alarms are not supported.");
- return;
+ SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_ALM_READ, &tm);
@@ -431,12 +433,12 @@ TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
- SKIP(return, "Skipping test since %s does not exist", rtc_file);
+ SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 0);
if (alarm_state == RTC_ALARM_DISABLED)
- SKIP(return, "Skipping test since alarms are not supported.");
+ SKIP(return, "alarms are not supported.");
rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
ASSERT_NE(-1, rc);
@@ -454,8 +456,7 @@ TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
- TH_LOG("skip alarms are not supported.");
- return;
+ SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
@@ -502,8 +503,7 @@ int main(int argc, char **argv)
if (access(rtc_file, R_OK) == 0)
ret = test_harness_run(argc, argv);
else
- ksft_exit_skip("[SKIP]: Cannot access rtc file %s - Exiting\n",
- rtc_file);
+ ksft_exit_skip("Cannot access rtc file %s - Exiting\n", rtc_file);
return ret;
}