summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig283
-rw-r--r--drivers/rtc/Makefile23
-rw-r--r--drivers/rtc/class.c28
-rw-r--r--drivers/rtc/dev.c5
-rw-r--r--drivers/rtc/interface.c51
-rw-r--r--drivers/rtc/lib.c36
-rw-r--r--drivers/rtc/lib_test.c81
-rw-r--r--drivers/rtc/nvmem.c1
-rw-r--r--drivers/rtc/rtc-88pm80x.c5
-rw-r--r--drivers/rtc/rtc-88pm860x.c6
-rw-r--r--drivers/rtc/rtc-88pm886.c97
-rw-r--r--drivers/rtc/rtc-ab-b5ze-s3.c4
-rw-r--r--drivers/rtc/rtc-ab-eoz9.c48
-rw-r--r--drivers/rtc/rtc-ab8500.c13
-rw-r--r--drivers/rtc/rtc-abx80x.c87
-rw-r--r--drivers/rtc/rtc-ac100.c8
-rw-r--r--drivers/rtc/rtc-amlogic-a4.c465
-rw-r--r--drivers/rtc/rtc-armada38x.c14
-rw-r--r--drivers/rtc/rtc-as3722.c2
-rw-r--r--drivers/rtc/rtc-asm9260.c3
-rw-r--r--drivers/rtc/rtc-aspeed.c18
-rw-r--r--drivers/rtc/rtc-at91rm9200.c18
-rw-r--r--drivers/rtc/rtc-at91sam9.c9
-rw-r--r--drivers/rtc/rtc-bd70528.c5
-rw-r--r--drivers/rtc/rtc-bq32k.c4
-rw-r--r--drivers/rtc/rtc-brcmstb-waketimer.c200
-rw-r--r--drivers/rtc/rtc-cadence.c6
-rw-r--r--drivers/rtc/rtc-cmos.c92
-rw-r--r--drivers/rtc/rtc-cpcap.c3
-rw-r--r--drivers/rtc/rtc-cros-ec.c83
-rw-r--r--drivers/rtc/rtc-cv1800.c218
-rw-r--r--drivers/rtc/rtc-da9055.c2
-rw-r--r--drivers/rtc/rtc-da9063.c114
-rw-r--r--drivers/rtc/rtc-ds1305.c5
-rw-r--r--drivers/rtc/rtc-ds1307.c47
-rw-r--r--drivers/rtc/rtc-ds1343.c8
-rw-r--r--drivers/rtc/rtc-ds1374.c4
-rw-r--r--drivers/rtc/rtc-ds1390.c2
-rw-r--r--drivers/rtc/rtc-ds1511.c340
-rw-r--r--drivers/rtc/rtc-ds1672.c4
-rw-r--r--drivers/rtc/rtc-ds1685.c10
-rw-r--r--drivers/rtc/rtc-ds1742.c1
-rw-r--r--drivers/rtc/rtc-ds2404.c181
-rw-r--r--drivers/rtc/rtc-ds3232.c36
-rw-r--r--drivers/rtc/rtc-efi.c74
-rw-r--r--drivers/rtc/rtc-em3027.c4
-rw-r--r--drivers/rtc/rtc-ep93xx.c24
-rw-r--r--drivers/rtc/rtc-fm3130.c4
-rw-r--r--drivers/rtc/rtc-fsl-ftm-alarm.c7
-rw-r--r--drivers/rtc/rtc-ftrtc010.c21
-rw-r--r--drivers/rtc/rtc-goldfish.c1
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c6
-rw-r--r--drivers/rtc/rtc-hym8563.c28
-rw-r--r--drivers/rtc/rtc-imx-sm-bbm.c162
-rw-r--r--drivers/rtc/rtc-imxdi.c12
-rw-r--r--drivers/rtc/rtc-isl12022.c443
-rw-r--r--drivers/rtc/rtc-isl12026.c5
-rw-r--r--drivers/rtc/rtc-isl1208.c179
-rw-r--r--drivers/rtc/rtc-jz4740.c102
-rw-r--r--drivers/rtc/rtc-loongson.c408
-rw-r--r--drivers/rtc/rtc-lp8788.c2
-rw-r--r--drivers/rtc/rtc-lpc24xx.c9
-rw-r--r--drivers/rtc/rtc-lpc32xx.c2
-rw-r--r--drivers/rtc/rtc-ls1x.c192
-rw-r--r--drivers/rtc/rtc-m41t80.c120
-rw-r--r--drivers/rtc/rtc-m48t59.c30
-rw-r--r--drivers/rtc/rtc-m48t86.c22
-rw-r--r--drivers/rtc/rtc-ma35d1.c304
-rw-r--r--drivers/rtc/rtc-max31335.c778
-rw-r--r--drivers/rtc/rtc-max6900.c4
-rw-r--r--drivers/rtc/rtc-max77686.c43
-rw-r--r--drivers/rtc/rtc-max8907.c1
-rw-r--r--drivers/rtc/rtc-max8925.c2
-rw-r--r--drivers/rtc/rtc-max8997.c2
-rw-r--r--drivers/rtc/rtc-mc13xxx.c17
-rw-r--r--drivers/rtc/rtc-mc146818-lib.c45
-rw-r--r--drivers/rtc/rtc-mcp795.c1
-rw-r--r--drivers/rtc/rtc-meson-vrtc.c18
-rw-r--r--drivers/rtc/rtc-meson.c17
-rw-r--r--drivers/rtc/rtc-moxart.c89
-rw-r--r--drivers/rtc/rtc-mpc5121.c11
-rw-r--r--drivers/rtc/rtc-mpfs.c12
-rw-r--r--drivers/rtc/rtc-mt6397.c34
-rw-r--r--drivers/rtc/rtc-mt7622.c10
-rw-r--r--drivers/rtc/rtc-mv.c16
-rw-r--r--drivers/rtc/rtc-mxc.c3
-rw-r--r--drivers/rtc/rtc-mxc_v2.c5
-rw-r--r--drivers/rtc/rtc-nct3018y.c82
-rw-r--r--drivers/rtc/rtc-nct6694.c297
-rw-r--r--drivers/rtc/rtc-nxp-bbnsm.c231
-rw-r--r--drivers/rtc/rtc-omap.c24
-rw-r--r--drivers/rtc/rtc-optee.c465
-rw-r--r--drivers/rtc/rtc-palmas.c5
-rw-r--r--drivers/rtc/rtc-pcap.c6
-rw-r--r--drivers/rtc/rtc-pcf2123.c7
-rw-r--r--drivers/rtc/rtc-pcf2127.c980
-rw-r--r--drivers/rtc/rtc-pcf50633.c286
-rw-r--r--drivers/rtc/rtc-pcf85063.c337
-rw-r--r--drivers/rtc/rtc-pcf8523.c53
-rw-r--r--drivers/rtc/rtc-pcf85363.c73
-rw-r--r--drivers/rtc/rtc-pcf8563.c249
-rw-r--r--drivers/rtc/rtc-pcf8583.c4
-rw-r--r--drivers/rtc/rtc-pic32.c6
-rw-r--r--drivers/rtc/rtc-pl030.c16
-rw-r--r--drivers/rtc/rtc-pl031.c8
-rw-r--r--drivers/rtc/rtc-pm8xxx.c706
-rw-r--r--drivers/rtc/rtc-pxa.c14
-rw-r--r--drivers/rtc/rtc-r7301.c35
-rw-r--r--drivers/rtc/rtc-rc5t583.c6
-rw-r--r--drivers/rtc/rtc-rc5t619.c15
-rw-r--r--drivers/rtc/rtc-renesas-rtca3.c897
-rw-r--r--drivers/rtc/rtc-rk808.c2
-rw-r--r--drivers/rtc/rtc-rs5c372.c7
-rw-r--r--drivers/rtc/rtc-rtd119x.c4
-rw-r--r--drivers/rtc/rtc-rv3028.c119
-rw-r--r--drivers/rtc/rtc-rv3029c2.c13
-rw-r--r--drivers/rtc/rtc-rv3032.c49
-rw-r--r--drivers/rtc/rtc-rv8803.c95
-rw-r--r--drivers/rtc/rtc-rx6110.c10
-rw-r--r--drivers/rtc/rtc-rx8010.c12
-rw-r--r--drivers/rtc/rtc-rx8025.c4
-rw-r--r--drivers/rtc/rtc-rx8111.c368
-rw-r--r--drivers/rtc/rtc-rx8581.c90
-rw-r--r--drivers/rtc/rtc-rzn1.c276
-rw-r--r--drivers/rtc/rtc-s32g.c385
-rw-r--r--drivers/rtc/rtc-s35390a.c27
-rw-r--r--drivers/rtc/rtc-s3c.c59
-rw-r--r--drivers/rtc/rtc-s3c.h19
-rw-r--r--drivers/rtc/rtc-s5m.c309
-rw-r--r--drivers/rtc/rtc-sa1100.c6
-rw-r--r--drivers/rtc/rtc-sc27xx.c4
-rw-r--r--drivers/rtc/rtc-sd2405al.c229
-rw-r--r--drivers/rtc/rtc-sd3078.c75
-rw-r--r--drivers/rtc/rtc-sh.c307
-rw-r--r--drivers/rtc/rtc-spacemit-p1.c167
-rw-r--r--drivers/rtc/rtc-spear.c8
-rw-r--r--drivers/rtc/rtc-ssd202d.c249
-rw-r--r--drivers/rtc/rtc-st-lpc.c21
-rw-r--r--drivers/rtc/rtc-stm32.c565
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c7
-rw-r--r--drivers/rtc/rtc-sun6i.c25
-rw-r--r--drivers/rtc/rtc-sunplus.c19
-rw-r--r--drivers/rtc/rtc-sunxi.c2
-rw-r--r--drivers/rtc/rtc-tegra.c6
-rw-r--r--drivers/rtc/rtc-test.c8
-rw-r--r--drivers/rtc/rtc-ti-k3.c5
-rw-r--r--drivers/rtc/rtc-tps6586x.c8
-rw-r--r--drivers/rtc/rtc-tps65910.c10
-rw-r--r--drivers/rtc/rtc-tps6594.c505
-rw-r--r--drivers/rtc/rtc-twl.c50
-rw-r--r--drivers/rtc/rtc-v3020.c369
-rw-r--r--drivers/rtc/rtc-vt8500.c4
-rw-r--r--drivers/rtc/rtc-wm831x.c2
-rw-r--r--drivers/rtc/rtc-wm8350.c15
-rw-r--r--drivers/rtc/rtc-x1205.c6
-rw-r--r--drivers/rtc/rtc-xgene.c7
-rw-r--r--drivers/rtc/rtc-zynqmp.c31
-rw-r--r--drivers/rtc/sysfs.c64
-rw-r--r--drivers/rtc/test_rtc_lib.c106
159 files changed, 11326 insertions, 4143 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 677d2601d305..2933c41c77c8 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -182,6 +182,16 @@ config RTC_DRV_88PM80X
This driver can also be built as a module. If so, the module
will be called rtc-88pm80x.
+config RTC_DRV_88PM886
+ tristate "Marvell 88PM886 RTC driver"
+ depends on MFD_88PM886_PMIC
+ help
+ If you say yes here you will get support for the RTC function in the
+ Marvell 88PM886 chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-88pm886.
+
config RTC_DRV_ABB5ZES3
select REGMAP_I2C
tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
@@ -373,6 +383,19 @@ config RTC_DRV_MAX8997
This driver can also be built as a module. If so, the module
will be called rtc-max8997.
+config RTC_DRV_MAX31335
+ tristate "Analog Devices MAX31335"
+ depends on I2C
+ depends on COMMON_CLK
+ depends on HWMON || HWMON=n
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the Analog Devices
+ MAX31335.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max31335.
+
config RTC_DRV_MAX77686
tristate "Maxim MAX77686"
depends on MFD_MAX77686 || MFD_MAX77620 || MFD_MAX77714 || COMPILE_TEST
@@ -383,6 +406,16 @@ config RTC_DRV_MAX77686
This driver can also be built as a module. If so, the module
will be called rtc-max77686.
+config RTC_DRV_SPACEMIT_P1
+ tristate "SpacemiT P1 RTC"
+ depends on ARCH_SPACEMIT || COMPILE_TEST
+ select MFD_SPACEMIT_P1
+ default ARCH_SPACEMIT
+ help
+ Enable support for the RTC function in the SpacemiT P1 PMIC.
+ This driver can also be built as a module, which will be called
+ "spacemit-p1-rtc".
+
config RTC_DRV_NCT3018Y
tristate "Nuvoton NCT3018Y"
depends on OF
@@ -393,9 +426,19 @@ config RTC_DRV_NCT3018Y
This driver can also be built as a module, if so, the module will be
called "rtc-nct3018y".
+config RTC_DRV_NCT6694
+ tristate "Nuvoton NCT6694 RTC support"
+ depends on MFD_NCT6694
+ help
+ If you say yes to this option, support will be included for Nuvoton
+ NCT6694, a USB device to RTC.
+
+ This driver can also be built as a module. If so, the module will
+ be called rtc-nct6694.
+
config RTC_DRV_RK808
tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC"
- depends on MFD_RK808
+ depends on MFD_RK8XX
help
If you say yes here you will get support for the
RTC of RK805, RK809 and RK817, RK808 and RK818 PMIC.
@@ -460,15 +503,6 @@ config RTC_DRV_PCF8523
This driver can also be built as a module. If so, the module
will be called rtc-pcf8523.
-config RTC_DRV_PCF85063
- tristate "NXP PCF85063"
- select REGMAP_I2C
- help
- If you say yes here you get support for the PCF85063 RTC chip
-
- This driver can also be built as a module. If so, the module
- will be called rtc-pcf85063.
-
config RTC_DRV_PCF85363
tristate "NXP PCF85363"
select REGMAP_I2C
@@ -483,6 +517,7 @@ config RTC_DRV_PCF85363
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
+ select REGMAP_I2C
help
If you say yes here you get support for the
Philips PCF8563 RTC chip. The Epson RTC8564
@@ -578,6 +613,18 @@ config RTC_DRV_TPS6586X
along with alarm. This driver supports the RTC driver for
the TPS6586X RTC module.
+config RTC_DRV_TPS6594
+ tristate "TI TPS6594 RTC driver"
+ depends on MFD_TPS6594
+ default MFD_TPS6594
+ help
+ TI Power Management IC TPS6594 supports RTC functionality
+ along with alarm. This driver supports the RTC driver for
+ the TPS6594 RTC module.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-tps6594.
+
config RTC_DRV_TPS65910
tristate "TI TPS65910 RTC driver"
depends on MFD_TPS65910
@@ -639,6 +686,16 @@ config RTC_DRV_RX8010
This driver can also be built as a module. If so, the module
will be called rtc-rx8010.
+config RTC_DRV_RX8111
+ tristate "Epson RX8111"
+ select REGMAP_I2C
+ depends on I2C
+ help
+ If you say yes here you will get support for the Epson RX8111 RTC.
+
+ This driver can also be built as a module. If so, the module will be
+ called rtc-rx8111.
+
config RTC_DRV_RX8581
tristate "Epson RX-8571/RX-8581"
select REGMAP_I2C
@@ -708,6 +765,16 @@ config RTC_DRV_S5M
This driver can also be built as a module. If so, the module
will be called rtc-s5m.
+config RTC_DRV_SD2405AL
+ tristate "DFRobot SD2405AL"
+ select REGMAP_I2C
+ help
+ If you say yes here you will get support for the
+ DFRobot SD2405AL I2C RTC Module.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-sd2405al.
+
config RTC_DRV_SD3078
tristate "ZXW Shenzhen whwave SD3078"
select REGMAP_I2C
@@ -904,9 +971,9 @@ config RTC_DRV_PCF2127
select REGMAP_SPI if SPI_MASTER
select WATCHDOG_CORE if WATCHDOG
help
- If you say yes here you get support for the NXP PCF2127/29 RTC
+ If you say yes here you get support for the NXP PCF2127/29/31 RTC
chips with integrated quartz crystal for industrial applications.
- Both chips also have watchdog timer and tamper switch detection
+ These chips also have watchdog timer and tamper switch detection
features.
PCF2127 has an additional feature of 512 bytes battery backed
@@ -915,6 +982,18 @@ config RTC_DRV_PCF2127
This driver can also be built as a module. If so, the module
will be called rtc-pcf2127.
+config RTC_DRV_PCF85063
+ tristate "NXP PCF85063"
+ depends on RTC_I2C_AND_SPI
+ select REGMAP_I2C if I2C
+ select REGMAP_SPI if SPI_MASTER
+ help
+ If you say yes here you get support for the PCF85063 and RV8063
+ RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf85063.
+
config RTC_DRV_RV3029C2
tristate "Micro Crystal RV3029/3049"
depends on RTC_I2C_AND_SPI
@@ -956,6 +1035,7 @@ comment "Platform RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on X86 || ARM || PPC || MIPS || SPARC64
+ depends on HAS_IOPORT || MACH_DECSTATION
default y if X86
select RTC_MC146818_LIB
help
@@ -976,6 +1056,7 @@ config RTC_DRV_CMOS
config RTC_DRV_ALPHA
bool "Alpha PC-style CMOS"
depends on ALPHA
+ depends on HAS_IOPORT
select RTC_MC146818_LIB
default y
help
@@ -1193,7 +1274,8 @@ config RTC_DRV_MSM6242
config RTC_DRV_BQ4802
tristate "TI BQ4802"
- depends on HAS_IOMEM
+ depends on HAS_IOMEM && HAS_IOPORT
+ depends on SPARC || COMPILE_TEST
help
If you say Y here you will get support for the TI
BQ4802 RTC chip.
@@ -1212,15 +1294,6 @@ config RTC_DRV_RP5C01
This driver can also be built as a module. If so, the module
will be called rtc-rp5c01.
-config RTC_DRV_V3020
- tristate "EM Microelectronic V3020"
- help
- If you say yes here you will get support for the
- EM Microelectronic v3020 RTC chip.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-v3020.
-
config RTC_DRV_GAMECUBE
tristate "Nintendo GameCube, Wii and Wii U RTC"
depends on GAMECUBE || WII || COMPILE_TEST
@@ -1266,18 +1339,11 @@ config RTC_DRV_SC27XX
config RTC_DRV_SPEAR
tristate "SPEAR ST RTC"
depends on PLAT_SPEAR || COMPILE_TEST
- default y
+ default PLAT_SPEAR
help
If you say Y here you will get support for the RTC found on
spear
-config RTC_DRV_PCF50633
- depends on MFD_PCF50633
- tristate "NXP PCF50633 RTC"
- help
- If you say yes here you get support for the RTC subsystem of the
- NXP PCF50633 used in embedded systems.
-
config RTC_DRV_AB8500
tristate "ST-Ericsson AB8500 RTC"
depends on AB8500_CORE
@@ -1345,6 +1411,18 @@ config RTC_DRV_ASM9260
This driver can also be built as a module. If so, the module
will be called rtc-asm9260.
+config RTC_DRV_CV1800
+ tristate "Sophgo CV1800 RTC"
+ depends on SOPHGO_CV1800_RTCSYS || COMPILE_TEST
+ select MFD_SYSCON
+ select REGMAP
+ help
+ If you say yes here you get support the RTC driver for Sophgo CV1800
+ series SoC.
+
+ This driver can also be built as a module. If so, the module will be
+ called rtc-cv1800.
+
config RTC_DRV_DIGICOLOR
tristate "Conexant Digicolor RTC"
depends on ARCH_DIGICOLOR || COMPILE_TEST
@@ -1357,7 +1435,7 @@ config RTC_DRV_DIGICOLOR
config RTC_DRV_IMXDI
tristate "Freescale IMX DryIce Real Time Clock"
- depends on ARCH_MXC
+ depends on ARCH_MXC || COMPILE_TEST
depends on OF
help
Support for Freescale IMX DryIce RTC
@@ -1415,18 +1493,14 @@ config RTC_DRV_OMAP
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
- depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S3C24XX || ARCH_S5PV210 || \
+ depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S5PV210 || \
COMPILE_TEST
help
RTC (Realtime Clock) driver for the clock inbuilt into the
- Samsung S3C24XX series of SoCs. This can provide periodic
+ Samsung S3C64XX series of SoCs. This can provide periodic
interrupt rates from 1Hz to 64Hz for user programs, and
wakeup from Alarm.
- The driver currently supports the common features on all the
- S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440
- and S3C2442.
-
This driver can also be build as a module. If so, the module
will be called rtc-s3c.
@@ -1690,7 +1764,7 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
depends on MIPS || COMPILE_TEST
- depends on OF
+ depends on OF && COMMON_CLK
help
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
controllers.
@@ -1698,10 +1772,24 @@ config RTC_DRV_JZ4740
This driver can also be built as a module. If so, the module
will be called rtc-jz4740.
+config RTC_DRV_LOONGSON
+ tristate "Loongson On-chip RTC"
+ depends on MACH_LOONGSON32 || MACH_LOONGSON64 || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This is a driver for the Loongson on-chip Counter0 (Time-Of-Year
+ counter) to be used as a RTC.
+ It can be found on Loongson-1 series cpu, Loongson-2K series cpu
+ and Loongson LS7A bridge chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-loongson.
+
config RTC_DRV_LPC24XX
tristate "NXP RTC for LPC178x/18xx/408x/43xx"
depends on ARCH_LPC18XX || COMPILE_TEST
depends on OF && HAS_IOMEM
+ depends on COMMON_CLK
help
This enables support for the NXP RTC found which can be found on
NXP LPC178x/18xx/408x/43xx devices.
@@ -1739,16 +1827,6 @@ config RTC_DRV_TEGRA
This drive can also be built as a module. If so, the module
will be called rtc-tegra.
-config RTC_DRV_LOONGSON1
- tristate "loongson1 RTC support"
- depends on MACH_LOONGSON32
- help
- This is a driver for the loongson1 on-chip Counter0 (Time-Of-Year
- counter) to be used as a RTC.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-ls1x.
-
config RTC_DRV_MXC
tristate "Freescale MXC Real Time Clock"
depends on ARCH_MXC || COMPILE_TEST
@@ -1786,6 +1864,29 @@ config RTC_DRV_SNVS
This driver can also be built as a module, if so, the module
will be called "rtc-snvs".
+config RTC_DRV_BBNSM
+ tristate "NXP BBNSM RTC support"
+ select REGMAP_MMIO
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on HAS_IOMEM
+ depends on OF
+ help
+ If you say yes here you get support for the NXP BBNSM RTC module.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-bbnsm".
+
+config RTC_DRV_IMX_BBM_SCMI
+ depends on IMX_SCMI_BBM_EXT || COMPILE_TEST
+ default y if ARCH_MXC
+ tristate "NXP i.MX BBM SCMI RTC support"
+ help
+ If you say yes here you get support for the NXP i.MX BBSM SCMI
+ RTC module.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-imx-sm-bbm.
+
config RTC_DRV_IMX_SC
depends on IMX_SCU
depends on HAVE_ARM_SMCCC
@@ -1827,7 +1928,8 @@ config RTC_DRV_MT2712
config RTC_DRV_MT6397
tristate "MediaTek PMIC based RTC"
- depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
+ depends on MFD_MT6397 || COMPILE_TEST
+ select IRQ_DOMAIN
help
This selects the MediaTek(R) RTC driver. RTC is part of MediaTek
MT6397 PMIC. You should enable MT6397 PMIC MFD before select
@@ -1881,6 +1983,12 @@ config RTC_DRV_STM32
tristate "STM32 RTC"
select REGMAP_MMIO
depends on ARCH_STM32 || COMPILE_TEST
+ depends on OF
+ depends on PINCTRL
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ depends on COMMON_CLK
help
If you say yes here you get support for the STM32 On-Chip
Real Time Clock.
@@ -1925,19 +2033,26 @@ config RTC_DRV_TI_K3
This driver can also be built as a module, if so, the module
will be called "rtc-ti-k3".
-comment "HID Sensor RTC drivers"
+config RTC_DRV_MA35D1
+ tristate "Nuvoton MA35D1 RTC"
+ depends on ARCH_MA35 || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ If you say yes here you get support for the Nuvoton MA35D1
+ On-Chip Real Time Clock.
-config RTC_DRV_HID_SENSOR_TIME
- tristate "HID Sensor Time"
- depends on USB_HID
- depends on HID_SENSOR_HUB && IIO
- select HID_SENSOR_IIO_COMMON
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-ma35d1".
+
+config RTC_DRV_RENESAS_RTCA3
+ tristate "Renesas RTCA-3 RTC"
+ depends on ARCH_RENESAS
help
- Say yes here to build support for the HID Sensors of type Time.
- This drivers makes such sensors available as RTCs.
+ If you say yes here you get support for the Renesas RTCA-3 RTC
+ available on the Renesas RZ/G3S SoC.
- If this driver is compiled as a module, it will be named
- rtc-hid-sensor-time.
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-rtca3".
config RTC_DRV_GOLDFISH
tristate "Goldfish Real Time Clock"
@@ -1971,7 +2086,7 @@ config RTC_DRV_MSC313
config RTC_DRV_POLARFIRE_SOC
tristate "Microchip PolarFire SoC built-in RTC"
- depends on SOC_MICROCHIP_POLARFIRE
+ depends on ARCH_MICROCHIP_POLARFIRE
help
If you say yes here you will get support for the
built-in RTC on Polarfire SoC.
@@ -1979,4 +2094,52 @@ config RTC_DRV_POLARFIRE_SOC
This driver can also be built as a module, if so, the module
will be called "rtc-mpfs".
+config RTC_DRV_SSD202D
+ tristate "SigmaStar SSD202D RTC"
+ depends on ARCH_MSTARV7 || COMPILE_TEST
+ default ARCH_MSTARV7
+ help
+ If you say yes here you get support for the SigmaStar SSD202D On-Chip
+ Real Time Clock.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-ssd20xd".
+
+config RTC_DRV_AMLOGIC_A4
+ tristate "Amlogic RTC"
+ depends on ARCH_MESON || COMPILE_TEST
+ select REGMAP_MMIO
+ default ARCH_MESON
+ help
+ If you say yes here you get support for the RTC block on the
+ Amlogic A113L2(A4) and A113X2(A5) SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called "rtc-amlogic-a4".
+
+config RTC_DRV_S32G
+ tristate "RTC driver for S32G2/S32G3 SoCs"
+ depends on ARCH_S32 || COMPILE_TEST
+ depends on COMMON_CLK
+ help
+ Say yes to enable RTC driver for platforms based on the
+ S32G2/S32G3 SoC family.
+
+ This RTC module can be used as a wakeup source.
+ Please note that it is not battery-powered.
+
+comment "HID Sensor RTC drivers"
+
+config RTC_DRV_HID_SENSOR_TIME
+ tristate "HID Sensor Time"
+ depends on USB_HID
+ depends on HID_SENSOR_HUB && IIO
+ select HID_SENSOR_IIO_COMMON
+ help
+ Say yes here to build support for the HID Sensors of type Time.
+ This drivers makes such sensors available as RTCs.
+
+ If this driver is compiled as a module, it will be named
+ rtc-hid-sensor-time.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index d3c042dcbc73..8221bda6e6dc 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -15,17 +15,19 @@ rtc-core-$(CONFIG_RTC_INTF_DEV) += dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += sysfs.o
-obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o
+obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += test_rtc_lib.o
# Keep the list ordered.
obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
+obj-$(CONFIG_RTC_DRV_88PM886) += rtc-88pm886.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABEOZ9) += rtc-ab-eoz9.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
+obj-$(CONFIG_RTC_DRV_AMLOGIC_A4) += rtc-amlogic-a4.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
@@ -33,6 +35,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
+obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o
obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
@@ -41,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_CADENCE) += rtc-cadence.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o
obj-$(CONFIG_RTC_DRV_CROS_EC) += rtc-cros-ec.o
+obj-$(CONFIG_RTC_DRV_CV1800) += rtc-cv1800.o
obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
@@ -73,11 +77,12 @@ obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
obj-$(CONFIG_RTC_DRV_IMX_SC) += rtc-imx-sc.o
+obj-$(CONFIG_RTC_DRV_IMX_BBM_SCMI) += rtc-imx-sm-bbm.o
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
-obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
+obj-$(CONFIG_RTC_DRV_LOONGSON) += rtc-loongson.o
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
obj-$(CONFIG_RTC_DRV_LPC24XX) += rtc-lpc24xx.o
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
@@ -87,6 +92,8 @@ obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_MA35D1) += rtc-ma35d1.o
+obj-$(CONFIG_RTC_DRV_MAX31335) += rtc-max31335.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MAX6916) += rtc-max6916.o
@@ -102,6 +109,7 @@ obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MSC313) += rtc-msc313.o
+obj-$(CONFIG_RTC_DRV_SSD202D) += rtc-ssd202d.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MT2712) += rtc-mt2712.o
obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
@@ -111,6 +119,7 @@ obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o
obj-$(CONFIG_RTC_DRV_GAMECUBE) += rtc-gamecube.o
obj-$(CONFIG_RTC_DRV_NCT3018Y) += rtc-nct3018y.o
+obj-$(CONFIG_RTC_DRV_NCT6694) += rtc-nct6694.o
obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
@@ -119,7 +128,6 @@ obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
-obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
@@ -150,16 +158,21 @@ obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o
obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
+obj-$(CONFIG_RTC_DRV_RX8111) += rtc-rx8111.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o
+obj-$(CONFIG_RTC_DRV_RENESAS_RTCA3) += rtc-renesas-rtca3.o
+obj-$(CONFIG_RTC_DRV_S32G) += rtc-s32g.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
-obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
+obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o
+obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
+obj-$(CONFIG_RTC_DRV_SPACEMIT_P1) += rtc-spacemit-p1.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
@@ -174,9 +187,9 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o
obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
+obj-$(CONFIG_RTC_DRV_TPS6594) += rtc-tps6594.o
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
-obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o
obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index e5b7b48cffac..b1a2be1f9e3b 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -21,7 +21,6 @@
#include "rtc-core.h"
static DEFINE_IDA(rtc_ida);
-struct class *rtc_class;
static void rtc_device_release(struct device *dev)
{
@@ -199,6 +198,11 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
#define RTC_CLASS_DEV_PM_OPS NULL
#endif
+const struct class rtc_class = {
+ .name = "rtc",
+ .pm = RTC_CLASS_DEV_PM_OPS,
+};
+
/* Ensure the caller will set the id before releasing the device */
static struct rtc_device *rtc_allocate_device(void)
{
@@ -220,7 +224,7 @@ static struct rtc_device *rtc_allocate_device(void)
rtc->irq_freq = 1;
rtc->max_user_freq = 64;
- rtc->dev.class = rtc_class;
+ rtc->dev.class = &rtc_class;
rtc->dev.groups = rtc_get_dev_attribute_groups();
rtc->dev.release = rtc_device_release;
@@ -236,8 +240,7 @@ static struct rtc_device *rtc_allocate_device(void)
/* Init uie timer */
rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, rtc);
/* Init pie timer */
- hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- rtc->pie_timer.function = rtc_pie_update_irq;
+ hrtimer_setup(&rtc->pie_timer, rtc_pie_update_irq, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
rtc->pie_enabled = 0;
set_bit(RTC_FEATURE_ALARM, rtc->features);
@@ -256,7 +259,7 @@ static int rtc_device_get_id(struct device *dev)
of_id = of_alias_get_id(dev->parent->of_node, "rtc");
if (of_id >= 0) {
- id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL);
+ id = ida_alloc_range(&rtc_ida, of_id, of_id, GFP_KERNEL);
if (id < 0)
dev_warn(dev, "/aliases ID %d not available\n", of_id);
}
@@ -323,7 +326,7 @@ static void rtc_device_get_offset(struct rtc_device *rtc)
*
* Otherwise the offset seconds should be 0.
*/
- if (rtc->start_secs > rtc->range_max ||
+ if ((rtc->start_secs >= 0 && rtc->start_secs > rtc->range_max) ||
rtc->start_secs + range_secs - 1 < rtc->range_min)
rtc->offset_secs = rtc->start_secs - rtc->range_min;
else if (rtc->start_secs > rtc->range_min)
@@ -475,13 +478,14 @@ EXPORT_SYMBOL_GPL(devm_rtc_device_register);
static int __init rtc_init(void)
{
- rtc_class = class_create(THIS_MODULE, "rtc");
- if (IS_ERR(rtc_class)) {
- pr_err("couldn't create class\n");
- return PTR_ERR(rtc_class);
- }
- rtc_class->pm = RTC_CLASS_DEV_PM_OPS;
+ int err;
+
+ err = class_register(&rtc_class);
+ if (err)
+ return err;
+
rtc_dev_init();
+
return 0;
}
subsys_initcall(rtc_init);
diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c
index 4aad9bb99868..baf1a8ca8b2b 100644
--- a/drivers/rtc/dev.c
+++ b/drivers/rtc/dev.c
@@ -72,7 +72,7 @@ static void rtc_uie_task(struct work_struct *work)
static void rtc_uie_timer(struct timer_list *t)
{
- struct rtc_device *rtc = from_timer(rtc, t, uie_timer);
+ struct rtc_device *rtc = timer_container_of(rtc, t, uie_timer);
unsigned long flags;
spin_lock_irqsave(&rtc->irq_lock, flags);
@@ -90,7 +90,7 @@ static int clear_uie(struct rtc_device *rtc)
rtc->stop_uie_polling = 1;
if (rtc->uie_timer_active) {
spin_unlock_irq(&rtc->irq_lock);
- del_timer_sync(&rtc->uie_timer);
+ timer_delete_sync(&rtc->uie_timer);
spin_lock_irq(&rtc->irq_lock);
rtc->uie_timer_active = 0;
}
@@ -523,7 +523,6 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
- .llseek = no_llseek,
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.unlocked_ioctl = rtc_dev_ioctl,
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 7c30cb3c764d..b8b298efd9a9 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -205,7 +205,7 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc,
mutex_unlock(&rtc->ops_lock);
- trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
+ trace_rtc_read_alarm(err?0:rtc_tm_to_time64(&alarm->time), err);
return err;
}
@@ -274,10 +274,9 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
return err;
/* full-function RTCs won't have such missing fields */
- if (rtc_valid_tm(&alarm->time) == 0) {
- rtc_add_offset(rtc, &alarm->time);
- return 0;
- }
+ err = rtc_valid_tm(&alarm->time);
+ if (!err)
+ goto done;
/* get the "after" timestamp, to detect wrapped fields */
err = rtc_read_time(rtc, &now);
@@ -376,9 +375,11 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
err = rtc_valid_tm(&alarm->time);
done:
- if (err)
+ if (err && alarm->enabled)
dev_warn(&rtc->dev, "invalid alarm value: %ptR\n",
&alarm->time);
+ else
+ rtc_add_offset(rtc, &alarm->time);
return err;
}
@@ -392,7 +393,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
return err;
if (!rtc->ops) {
err = -ENODEV;
- } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) {
+ } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) {
err = -EINVAL;
} else {
memset(alarm, 0, sizeof(struct rtc_wkalrm));
@@ -442,6 +443,29 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
else
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
+ /*
+ * Check for potential race described above. If the waiting for next
+ * second, and the second just ticked since the check above, either
+ *
+ * 1) It ticked after the alarm was set, and an alarm irq should be
+ * generated.
+ *
+ * 2) It ticked before the alarm was set, and alarm irq most likely will
+ * not be generated.
+ *
+ * While we cannot easily check for which of these two scenarios we
+ * are in, we can return -ETIME to signal that the timer has already
+ * expired, which is true in both cases.
+ */
+ if ((scheduled - now) <= 1) {
+ err = __rtc_read_time(rtc, &tm);
+ if (err)
+ return err;
+ now = rtc_tm_to_time64(&tm);
+ if (scheduled <= now)
+ return -ETIME;
+ }
+
trace_rtc_set_alarm(rtc_tm_to_time64(&alarm->time), err);
return err;
}
@@ -593,6 +617,10 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
rtc->uie_rtctimer.period = ktime_set(1, 0);
err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
+ if (!err && rtc->ops && rtc->ops->alarm_irq_enable)
+ err = rtc->ops->alarm_irq_enable(rtc->dev.parent, 1);
+ if (err)
+ goto out;
} else {
rtc_timer_remove(rtc, &rtc->uie_rtctimer);
}
@@ -696,7 +724,7 @@ struct rtc_device *rtc_class_open(const char *name)
struct device *dev;
struct rtc_device *rtc = NULL;
- dev = class_find_device_by_name(rtc_class, name);
+ dev = class_find_device_by_name(&rtc_class, name);
if (dev)
rtc = to_rtc_device(dev);
@@ -903,13 +931,18 @@ void rtc_timer_do_work(struct work_struct *work)
struct timerqueue_node *next;
ktime_t now;
struct rtc_time tm;
+ int err;
struct rtc_device *rtc =
container_of(work, struct rtc_device, irqwork);
mutex_lock(&rtc->ops_lock);
again:
- __rtc_read_time(rtc, &tm);
+ err = __rtc_read_time(rtc, &tm);
+ if (err) {
+ mutex_unlock(&rtc->ops_lock);
+ return;
+ }
now = rtc_tm_to_ktime(tm);
while ((next = timerqueue_getnext(&rtc->timerqueue))) {
if (next->expires > now)
diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c
index fe361652727a..f7051592a6e3 100644
--- a/drivers/rtc/lib.c
+++ b/drivers/rtc/lib.c
@@ -46,27 +46,39 @@ EXPORT_SYMBOL(rtc_year_days);
* rtc_time64_to_tm - converts time64_t to rtc_time.
*
* @time: The number of seconds since 01-01-1970 00:00:00.
- * (Must be positive.)
+ * Works for values since at least 1900
* @tm: Pointer to the struct rtc_time.
*/
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
{
- unsigned int secs;
- int days;
+ int secs;
u64 u64tmp;
u32 u32tmp, udays, century, day_of_century, year_of_century, year,
day_of_year, month, day;
bool is_Jan_or_Feb, is_leap_year;
- /* time must be positive */
- days = div_s64_rem(time, 86400, &secs);
+ /*
+ * The time represented by `time` is given in seconds since 1970-01-01
+ * (UTC). As the division done below might misbehave for negative
+ * values, we convert it to seconds since 0000-03-01 and then assume it
+ * will be non-negative.
+ * Below we do 4 * udays + 3 which should fit into a 32 bit unsigned
+ * variable. So the latest date this algorithm works for is 1073741823
+ * days after 0000-03-01 which is in the year 2939805.
+ */
+ time += (u64)719468 * 86400;
+
+ udays = div_s64_rem(time, 86400, &secs);
- /* day of the week, 1970-01-01 was a Thursday */
- tm->tm_wday = (days + 4) % 7;
+ /*
+ * day of the week, 0000-03-01 was a Wednesday (in the proleptic
+ * Gregorian calendar)
+ */
+ tm->tm_wday = (udays + 3) % 7;
/*
- * The following algorithm is, basically, Proposition 6.3 of Neri
+ * The following algorithm is, basically, Figure 12 of Neri
* and Schneider [1]. In a few words: it works on the computational
* (fictitious) calendar where the year starts in March, month = 2
* (*), and finishes in February, month = 13. This calendar is
@@ -86,15 +98,15 @@ void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
* (using just arithmetics) it's easy to convert it to the
* corresponding date in the Gregorian calendar.
*
- * [1] "Euclidean Affine Functions and Applications to Calendar
- * Algorithms". https://arxiv.org/abs/2102.06959
+ * [1] Neri C, Schneider L. Euclidean affine functions and their
+ * application to calendar algorithms. Softw Pract Exper.
+ * 2023;53(4):937-970. doi: 10.1002/spe.3172
+ * https://doi.org/10.1002/spe.3172
*
* (*) The numbering of months follows rtc_time more closely and
* thus, is slightly different from [1].
*/
- udays = ((u32) days) + 719468;
-
u32tmp = 4 * udays + 3;
century = u32tmp / 146097;
day_of_century = u32tmp % 146097 / 4;
diff --git a/drivers/rtc/lib_test.c b/drivers/rtc/lib_test.c
deleted file mode 100644
index d5caf36c56cd..000000000000
--- a/drivers/rtc/lib_test.c
+++ /dev/null
@@ -1,81 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1+
-
-#include <kunit/test.h>
-#include <linux/rtc.h>
-
-/*
- * Advance a date by one day.
- */
-static void advance_date(int *year, int *month, int *mday, int *yday)
-{
- if (*mday != rtc_month_days(*month - 1, *year)) {
- ++*mday;
- ++*yday;
- return;
- }
-
- *mday = 1;
- if (*month != 12) {
- ++*month;
- ++*yday;
- return;
- }
-
- *month = 1;
- *yday = 1;
- ++*year;
-}
-
-/*
- * Checks every day in a 160000 years interval starting on 1970-01-01
- * against the expected result.
- */
-static void rtc_time64_to_tm_test_date_range(struct kunit *test)
-{
- /*
- * 160000 years = (160000 / 400) * 400 years
- * = (160000 / 400) * 146097 days
- * = (160000 / 400) * 146097 * 86400 seconds
- */
- time64_t total_secs = ((time64_t) 160000) / 400 * 146097 * 86400;
-
- int year = 1970;
- int month = 1;
- int mday = 1;
- int yday = 1;
-
- struct rtc_time result;
- time64_t secs;
- s64 days;
-
- for (secs = 0; secs <= total_secs; secs += 86400) {
-
- rtc_time64_to_tm(secs, &result);
-
- days = div_s64(secs, 86400);
-
- #define FAIL_MSG "%d/%02d/%02d (%2d) : %ld", \
- year, month, mday, yday, days
-
- KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG);
- KUNIT_ASSERT_EQ_MSG(test, month - 1, result.tm_mon, FAIL_MSG);
- KUNIT_ASSERT_EQ_MSG(test, mday, result.tm_mday, FAIL_MSG);
- KUNIT_ASSERT_EQ_MSG(test, yday, result.tm_yday, FAIL_MSG);
-
- advance_date(&year, &month, &mday, &yday);
- }
-}
-
-static struct kunit_case rtc_lib_test_cases[] = {
- KUNIT_CASE(rtc_time64_to_tm_test_date_range),
- {}
-};
-
-static struct kunit_suite rtc_lib_test_suite = {
- .name = "rtc_lib_test_cases",
- .test_cases = rtc_lib_test_cases,
-};
-
-kunit_test_suite(rtc_lib_test_suite);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c
index 07ede21cee34..37df7e80525b 100644
--- a/drivers/rtc/nvmem.c
+++ b/drivers/rtc/nvmem.c
@@ -21,6 +21,7 @@ int devm_rtc_nvmem_register(struct rtc_device *rtc,
nvmem_config->dev = dev;
nvmem_config->owner = rtc->owner;
+ nvmem_config->add_legacy_fixed_of_cells = true;
nvmem = devm_nvmem_register(dev, nvmem_config);
if (IS_ERR(nvmem))
dev_err(dev, "failed to register nvmem device for RTC\n");
diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c
index 6a3f44cf6ebe..a3e52a5a708f 100644
--- a/drivers/rtc/rtc-88pm80x.c
+++ b/drivers/rtc/rtc-88pm80x.c
@@ -308,7 +308,7 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
/* remember whether this power up is caused by PMIC RTC or not */
info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup;
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
return 0;
out_rtc:
@@ -317,11 +317,10 @@ out:
return ret;
}
-static int pm80x_rtc_remove(struct platform_device *pdev)
+static void pm80x_rtc_remove(struct platform_device *pdev)
{
struct pm80x_rtc_info *info = platform_get_drvdata(pdev);
pm80x_free_irq(info->chip, info->irq, info);
- return 0;
}
static struct platform_driver pm80x_rtc_driver = {
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index 2c809a1a445e..964cd048fcdb 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -326,12 +326,12 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
#endif /* VRTC_CALIBRATION */
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
return 0;
}
-static int pm860x_rtc_remove(struct platform_device *pdev)
+static void pm860x_rtc_remove(struct platform_device *pdev)
{
struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
@@ -340,8 +340,6 @@ static int pm860x_rtc_remove(struct platform_device *pdev)
/* disable measurement */
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
#endif /* VRTC_CALIBRATION */
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-88pm886.c b/drivers/rtc/rtc-88pm886.c
new file mode 100644
index 000000000000..57e9b0a66eed
--- /dev/null
+++ b/drivers/rtc/rtc-88pm886.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/limits.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <linux/mfd/88pm886.h>
+
+/*
+ * Time is calculated as the sum of a 32-bit read-only advancing counter and a
+ * writeable constant offset stored in the chip's spare registers.
+ */
+
+static int pm886_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u32 time;
+ u32 buf;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, PM886_REG_RTC_SPARE1, &buf, 4);
+ if (ret)
+ return ret;
+ time = buf;
+
+ ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4);
+ if (ret)
+ return ret;
+ time += buf;
+
+ rtc_time64_to_tm(time, tm);
+
+ return 0;
+}
+
+static int pm886_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ u32 buf;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4);
+ if (ret)
+ return ret;
+
+ buf = rtc_tm_to_time64(tm) - buf;
+
+ return regmap_bulk_write(regmap, PM886_REG_RTC_SPARE1, &buf, 4);
+}
+
+static const struct rtc_class_ops pm886_rtc_ops = {
+ .read_time = pm886_rtc_read_time,
+ .set_time = pm886_rtc_set_time,
+};
+
+static int pm886_rtc_probe(struct platform_device *pdev)
+{
+ struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct rtc_device *rtc;
+ int ret;
+
+ platform_set_drvdata(pdev, chip->regmap);
+
+ rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc))
+ return dev_err_probe(dev, PTR_ERR(rtc),
+ "Failed to allocate RTC device\n");
+
+ rtc->ops = &pm886_rtc_ops;
+ rtc->range_max = U32_MAX;
+
+ ret = devm_rtc_register_device(rtc);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register RTC device\n");
+
+ return 0;
+}
+
+static const struct platform_device_id pm886_rtc_id_table[] = {
+ { "88pm886-rtc", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, pm886_rtc_id_table);
+
+static struct platform_driver pm886_rtc_driver = {
+ .driver = {
+ .name = "88pm886-rtc",
+ },
+ .probe = pm886_rtc_probe,
+ .id_table = pm886_rtc_id_table,
+};
+module_platform_driver(pm886_rtc_driver);
+
+MODULE_DESCRIPTION("Marvell 88PM886 RTC driver");
+MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c
index f2b0971d2c65..684f9898d768 100644
--- a/drivers/rtc/rtc-ab-b5ze-s3.c
+++ b/drivers/rtc/rtc-ab-b5ze-s3.c
@@ -933,7 +933,7 @@ MODULE_DEVICE_TABLE(of, abb5zes3_dt_match);
#endif
static const struct i2c_device_id abb5zes3_id[] = {
- { "abb5zes3", 0 },
+ { "abb5zes3" },
{ }
};
MODULE_DEVICE_TABLE(i2c, abb5zes3_id);
@@ -944,7 +944,7 @@ static struct i2c_driver abb5zes3_driver = {
.pm = &abb5zes3_rtc_pm_ops,
.of_match_table = of_match_ptr(abb5zes3_dt_match),
},
- .probe_new = abb5zes3_probe,
+ .probe = abb5zes3_probe,
.id_table = abb5zes3_id,
};
module_i2c_driver(abb5zes3_driver);
diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c
index 2f8deb8c4cd3..de002f7a39bf 100644
--- a/drivers/rtc/rtc-ab-eoz9.c
+++ b/drivers/rtc/rtc-ab-eoz9.c
@@ -64,7 +64,7 @@
#define ABEOZ9_BIT_ALARM_MIN GENMASK(6, 0)
#define ABEOZ9_REG_ALARM_HOURS 0x12
#define ABEOZ9_BIT_ALARM_HOURS_PM BIT(5)
-#define ABEOZ9_BIT_ALARM_HOURS GENMASK(4, 0)
+#define ABEOZ9_BIT_ALARM_HOURS GENMASK(5, 0)
#define ABEOZ9_REG_ALARM_DAYS 0x13
#define ABEOZ9_BIT_ALARM_DAYS GENMASK(5, 0)
#define ABEOZ9_REG_ALARM_WEEKDAYS 0x14
@@ -231,8 +231,6 @@ static int abeoz9_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
alarm->time.tm_sec = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_SEC, regs[0]));
alarm->time.tm_min = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_MIN, regs[1]));
alarm->time.tm_hour = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_HOURS, regs[2]));
- if (FIELD_GET(ABEOZ9_BIT_ALARM_HOURS_PM, regs[2]))
- alarm->time.tm_hour += 12;
alarm->time.tm_mday = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_DAYS, regs[3]));
@@ -396,13 +394,6 @@ static int abeoz9z3_temp_read(struct device *dev,
if (ret < 0)
return ret;
- if ((val & ABEOZ9_REG_CTRL_STATUS_V1F) ||
- (val & ABEOZ9_REG_CTRL_STATUS_V2F)) {
- dev_err(dev,
- "thermometer might be disabled due to low voltage\n");
- return -EINVAL;
- }
-
switch (attr) {
case hwmon_temp_input:
ret = regmap_read(regmap, ABEOZ9_REG_REG_TEMP, &val);
@@ -435,29 +426,9 @@ static umode_t abeoz9_is_visible(const void *data,
}
}
-static const u32 abeoz9_chip_config[] = {
- HWMON_C_REGISTER_TZ,
- 0
-};
-
-static const struct hwmon_channel_info abeoz9_chip = {
- .type = hwmon_chip,
- .config = abeoz9_chip_config,
-};
-
-static const u32 abeoz9_temp_config[] = {
- HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN,
- 0
-};
-
-static const struct hwmon_channel_info abeoz9_temp = {
- .type = hwmon_temp,
- .config = abeoz9_temp_config,
-};
-
-static const struct hwmon_channel_info *abeoz9_info[] = {
- &abeoz9_chip,
- &abeoz9_temp,
+static const struct hwmon_channel_info * const abeoz9_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN),
NULL
};
@@ -536,9 +507,14 @@ static int abeoz9_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, data->rtc->features);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(dev, client->irq, NULL,
abeoz9_rtc_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
dev_name(dev), dev);
if (ret) {
dev_err(dev, "failed to request alarm irq\n");
@@ -570,7 +546,7 @@ MODULE_DEVICE_TABLE(of, abeoz9_dt_match);
#endif
static const struct i2c_device_id abeoz9_id[] = {
- { "abeoz9", 0 },
+ { "abeoz9" },
{ }
};
@@ -579,7 +555,7 @@ static struct i2c_driver abeoz9_driver = {
.name = "rtc-ab-eoz9",
.of_match_table = of_match_ptr(abeoz9_dt_match),
},
- .probe_new = abeoz9_probe,
+ .probe = abeoz9_probe,
.id_table = abeoz9_id,
};
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index ea33e149d545..ed2b6b8bb3bf 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -361,7 +361,7 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
return -ENODEV;
}
- device_init_wakeup(&pdev->dev, true);
+ devm_device_init_wakeup(&pdev->dev);
rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc))
@@ -375,7 +375,7 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
if (err < 0)
return err;
- dev_pm_set_wake_irq(&pdev->dev, irq);
+ devm_pm_set_wake_irq(&pdev->dev, irq);
platform_set_drvdata(pdev, rtc);
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features);
@@ -392,20 +392,11 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
return devm_rtc_register_device(rtc);
}
-static int ab8500_rtc_remove(struct platform_device *pdev)
-{
- dev_pm_clear_wake_irq(&pdev->dev);
- device_init_wakeup(&pdev->dev, false);
-
- return 0;
-}
-
static struct platform_driver ab8500_rtc_driver = {
.driver = {
.name = "ab8500-rtc",
},
.probe = ab8500_rtc_probe,
- .remove = ab8500_rtc_remove,
.id_table = ab85xx_rtc_ids,
};
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 2e0e6432901b..3fee27914ba8 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -11,10 +11,11 @@
*/
#include <linux/bcd.h>
+#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/rtc.h>
#include <linux/watchdog.h>
@@ -38,7 +39,7 @@
#define ABX8XX_REG_STATUS 0x0f
#define ABX8XX_STATUS_AF BIT(2)
#define ABX8XX_STATUS_BLF BIT(4)
-#define ABX8XX_STATUS_WDT BIT(6)
+#define ABX8XX_STATUS_WDT BIT(5)
#define ABX8XX_REG_CTRL1 0x10
#define ABX8XX_CTRL_WRITE BIT(0)
@@ -88,6 +89,16 @@
#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
#define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4
+#define ABX8XX_REG_EXTRAM 0x3f
+#define ABX8XX_EXTRAM_XADS GENMASK(1, 0)
+
+#define ABX8XX_SRAM_BASE 0x40
+#define ABX8XX_SRAM_WIN_SIZE 0x40
+#define ABX8XX_RAM_SIZE 256
+
+#define NVMEM_ADDR_LOWER GENMASK(5, 0)
+#define NVMEM_ADDR_UPPER GENMASK(7, 6)
+
static u8 trickle_resistors[] = {0, 3, 6, 11};
enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
@@ -674,6 +685,72 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv)
}
#endif
+static int abx80x_nvmem_xfer(struct abx80x_priv *priv, unsigned int offset,
+ void *val, size_t bytes, bool write)
+{
+ int ret;
+
+ while (bytes) {
+ u8 extram, 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);
+ if (ret)
+ return ret;
+
+ if (write) {
+ ret = i2c_smbus_write_i2c_block_data(priv->client, reg,
+ len, val);
+ 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;
+ }
+
+ offset += len;
+ val += len;
+ bytes -= len;
+ }
+
+ return 0;
+}
+
+static int abx80x_nvmem_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ return abx80x_nvmem_xfer(priv, offset, val, bytes, false);
+}
+
+static int abx80x_nvmem_write(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ return abx80x_nvmem_xfer(priv, offset, val, bytes, true);
+}
+
+static int abx80x_setup_nvmem(struct abx80x_priv *priv)
+{
+ struct nvmem_config config = {
+ .type = NVMEM_TYPE_BATTERY_BACKED,
+ .reg_read = abx80x_nvmem_read,
+ .reg_write = abx80x_nvmem_write,
+ .size = ABX8XX_RAM_SIZE,
+ .priv = priv,
+ };
+
+ return devm_rtc_nvmem_register(priv->rtc, &config);
+}
+
static const struct i2c_device_id abx80x_id[] = {
{ "abx80x", ABX80X },
{ "ab0801", AB0801 },
@@ -840,6 +917,10 @@ static int abx80x_probe(struct i2c_client *client)
return err;
}
+ err = abx80x_setup_nvmem(priv);
+ 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,
@@ -915,7 +996,7 @@ static struct i2c_driver abx80x_driver = {
.name = "rtc-abx80x",
.of_match_table = of_match_ptr(abx80x_of_match),
},
- .probe_new = abx80x_probe,
+ .probe = abx80x_probe,
.id_table = abx80x_id,
};
diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c
index 66783cb5e711..33626311fa78 100644
--- a/drivers/rtc/rtc-ac100.c
+++ b/drivers/rtc/rtc-ac100.c
@@ -99,7 +99,7 @@ struct ac100_rtc_dev {
struct clk_hw_onecell_data *clk_data;
};
-/**
+/*
* Clock controls for 3 clock output pins
*/
@@ -378,7 +378,7 @@ static void ac100_rtc_unregister_clks(struct ac100_rtc_dev *chip)
clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
}
-/**
+/*
* RTC related bits
*/
static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
@@ -613,13 +613,11 @@ static int ac100_rtc_probe(struct platform_device *pdev)
return devm_rtc_register_device(chip->rtc);
}
-static int ac100_rtc_remove(struct platform_device *pdev)
+static void ac100_rtc_remove(struct platform_device *pdev)
{
struct ac100_rtc_dev *chip = platform_get_drvdata(pdev);
ac100_rtc_unregister_clks(chip);
-
- return 0;
}
static const struct of_device_id ac100_rtc_match[] = {
diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c
new file mode 100644
index 000000000000..1928b29c1045
--- /dev/null
+++ b/drivers/rtc/rtc-amlogic-a4.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2024 Amlogic, Inc. All rights reserved
+ * Author: Yiting Deng <yiting.deng@amlogic.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/time64.h>
+
+/* rtc oscillator rate */
+#define OSC_32K 32768
+#define OSC_24M 24000000
+
+#define RTC_CTRL (0x0 << 2) /* Control RTC */
+#define RTC_ALRM0_EN BIT(0)
+#define RTC_OSC_SEL BIT(8)
+#define RTC_ENABLE BIT(12)
+
+#define RTC_COUNTER_REG (0x1 << 2) /* Program RTC counter initial value */
+
+#define RTC_ALARM0_REG (0x2 << 2) /* Program RTC alarm0 value */
+
+#define RTC_SEC_ADJUST_REG (0x6 << 2) /* Control second-based timing adjustment */
+#define RTC_MATCH_COUNTER GENMASK(18, 0)
+#define RTC_SEC_ADJUST_CTRL GENMASK(20, 19)
+#define RTC_ADJ_VALID BIT(23)
+
+#define RTC_INT_MASK (0x8 << 2) /* RTC interrupt mask */
+#define RTC_ALRM0_IRQ_MSK BIT(0)
+
+#define RTC_INT_CLR (0x9 << 2) /* Clear RTC interrupt */
+#define RTC_ALRM0_IRQ_CLR BIT(0)
+
+#define RTC_OSCIN_CTRL0 (0xa << 2) /* Control RTC clk from 24M */
+#define RTC_OSCIN_CTRL1 (0xb << 2) /* Control RTC clk from 24M */
+#define RTC_OSCIN_IN_EN BIT(31)
+#define RTC_OSCIN_OUT_CFG GENMASK(29, 28)
+#define RTC_OSCIN_OUT_N0M0 GENMASK(11, 0)
+#define RTC_OSCIN_OUT_N1M1 GENMASK(23, 12)
+
+#define RTC_INT_STATUS (0xc << 2) /* RTC interrupt status */
+#define RTC_ALRM0_IRQ_STATUS BIT(0)
+
+#define RTC_REAL_TIME (0xd << 2) /* RTC time value */
+
+#define RTC_OSCIN_OUT_32K_N0 0x2dc
+#define RTC_OSCIN_OUT_32K_N1 0x2db
+#define RTC_OSCIN_OUT_32K_M0 0x1
+#define RTC_OSCIN_OUT_32K_M1 0x2
+
+#define RTC_SWALLOW_SECOND 0x2
+#define RTC_INSERT_SECOND 0x3
+
+struct aml_rtc_config {
+ bool gray_stored;
+};
+
+struct aml_rtc_data {
+ struct regmap *map;
+ struct rtc_device *rtc_dev;
+ int irq;
+ struct clk *rtc_clk;
+ struct clk *sys_clk;
+ int rtc_enabled;
+ const struct aml_rtc_config *config;
+};
+
+static inline u32 gray_to_binary(u32 gray)
+{
+ u32 bcd = gray;
+ int size = sizeof(bcd) * 8;
+ int i;
+
+ for (i = 0; (1 << i) < size; i++)
+ bcd ^= bcd >> (1 << i);
+
+ return bcd;
+}
+
+static inline u32 binary_to_gray(u32 bcd)
+{
+ return bcd ^ (bcd >> 1);
+}
+
+static int aml_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 time_sec;
+
+ /* if RTC disabled, read time failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_read(rtc->map, RTC_REAL_TIME, &time_sec);
+ if (rtc->config->gray_stored)
+ time_sec = gray_to_binary(time_sec);
+ rtc_time64_to_tm(time_sec, tm);
+ dev_dbg(dev, "%s: read time = %us\n", __func__, time_sec);
+
+ return 0;
+}
+
+static int aml_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 time_sec;
+
+ /* if RTC disabled, first enable it */
+ if (!rtc->rtc_enabled) {
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_ENABLE, RTC_ENABLE);
+ usleep_range(100, 200);
+ rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE);
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+ }
+
+ time_sec = rtc_tm_to_time64(tm);
+ if (rtc->config->gray_stored)
+ time_sec = binary_to_gray(time_sec);
+ regmap_write(rtc->map, RTC_COUNTER_REG, time_sec);
+ dev_dbg(dev, "%s: set time = %us\n", __func__, time_sec);
+
+ return 0;
+}
+
+static int aml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ time64_t alarm_sec;
+
+ /* if RTC disabled, set alarm failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_update_bits(rtc->map, RTC_CTRL,
+ RTC_ALRM0_EN, RTC_ALRM0_EN);
+ regmap_update_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, 0);
+
+ alarm_sec = rtc_tm_to_time64(&alarm->time);
+ if (rtc->config->gray_stored)
+ alarm_sec = binary_to_gray(alarm_sec);
+ regmap_write(rtc->map, RTC_ALARM0_REG, alarm_sec);
+
+ dev_dbg(dev, "%s: alarm->enabled=%d alarm_set=%llds\n", __func__,
+ alarm->enabled, alarm_sec);
+
+ return 0;
+}
+
+static int aml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 alarm_sec;
+ int alarm_enable;
+ int alarm_mask;
+
+ /* if RTC disabled, read alarm failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_read(rtc->map, RTC_ALARM0_REG, &alarm_sec);
+ if (rtc->config->gray_stored)
+ alarm_sec = gray_to_binary(alarm_sec);
+ rtc_time64_to_tm(alarm_sec, &alarm->time);
+
+ alarm_enable = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN);
+ alarm_mask = regmap_test_bits(rtc->map, RTC_INT_MASK, RTC_ALRM0_IRQ_MSK);
+ alarm->enabled = (alarm_enable && !alarm_mask) ? 1 : 0;
+ dev_dbg(dev, "%s: alarm->enabled=%d alarm=%us\n", __func__,
+ alarm->enabled, alarm_sec);
+
+ return 0;
+}
+
+static int aml_rtc_read_offset(struct device *dev, long *offset)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ u32 reg_val;
+ long val;
+ int sign, match_counter, enable;
+
+ /* if RTC disabled, read offset failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ regmap_read(rtc->map, RTC_SEC_ADJUST_REG, &reg_val);
+ enable = FIELD_GET(RTC_ADJ_VALID, reg_val);
+ if (!enable) {
+ val = 0;
+ } else {
+ sign = FIELD_GET(RTC_SEC_ADJUST_CTRL, reg_val);
+ match_counter = FIELD_GET(RTC_MATCH_COUNTER, reg_val);
+ val = 1000000000 / (match_counter + 1);
+ if (sign == RTC_SWALLOW_SECOND)
+ val = -val;
+ }
+ *offset = val;
+
+ return 0;
+}
+
+static int aml_rtc_set_offset(struct device *dev, long offset)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+ int sign = 0;
+ int match_counter = 0;
+ int enable = 0;
+ u32 reg_val;
+
+ /* if RTC disabled, set offset failed */
+ if (!rtc->rtc_enabled)
+ return -EINVAL;
+
+ if (offset) {
+ enable = 1;
+ sign = offset < 0 ? RTC_SWALLOW_SECOND : RTC_INSERT_SECOND;
+ match_counter = 1000000000 / abs(offset) - 1;
+ if (match_counter < 0 || match_counter > RTC_MATCH_COUNTER)
+ return -EINVAL;
+ }
+
+ reg_val = FIELD_PREP(RTC_ADJ_VALID, enable) |
+ FIELD_PREP(RTC_SEC_ADJUST_CTRL, sign) |
+ FIELD_PREP(RTC_MATCH_COUNTER, match_counter);
+ regmap_write(rtc->map, RTC_SEC_ADJUST_REG, reg_val);
+
+ return 0;
+}
+
+static int aml_rtc_alarm_enable(struct device *dev, unsigned int enabled)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+
+ if (enabled) {
+ regmap_update_bits(rtc->map, RTC_CTRL,
+ RTC_ALRM0_EN, RTC_ALRM0_EN);
+ regmap_update_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, 0);
+ } else {
+ regmap_update_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK);
+ regmap_update_bits(rtc->map, RTC_CTRL,
+ RTC_ALRM0_EN, 0);
+ }
+
+ return 0;
+}
+
+static const struct rtc_class_ops aml_rtc_ops = {
+ .read_time = aml_rtc_read_time,
+ .set_time = aml_rtc_set_time,
+ .read_alarm = aml_rtc_read_alarm,
+ .set_alarm = aml_rtc_set_alarm,
+ .alarm_irq_enable = aml_rtc_alarm_enable,
+ .read_offset = aml_rtc_read_offset,
+ .set_offset = aml_rtc_set_offset,
+};
+
+static irqreturn_t aml_rtc_handler(int irq, void *data)
+{
+ struct aml_rtc_data *rtc = (struct aml_rtc_data *)data;
+
+ regmap_write(rtc->map, RTC_ALARM0_REG, 0);
+ regmap_write(rtc->map, RTC_INT_CLR, RTC_ALRM0_IRQ_STATUS);
+
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+
+ return IRQ_HANDLED;
+}
+
+static void aml_rtc_init(struct aml_rtc_data *rtc)
+{
+ u32 reg_val = 0;
+
+ rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE);
+ if (!rtc->rtc_enabled) {
+ if (clk_get_rate(rtc->rtc_clk) == OSC_24M) {
+ /* select 24M oscillator */
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, RTC_OSC_SEL);
+
+ /*
+ * Set RTC oscillator to freq_out to freq_in/((N0*M0+N1*M1)/(M0+M1))
+ * Enable clock_in gate of oscillator 24MHz
+ * Set N0 to 733, N1 to 732
+ */
+ reg_val = FIELD_PREP(RTC_OSCIN_IN_EN, 1)
+ | FIELD_PREP(RTC_OSCIN_OUT_CFG, 1)
+ | FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_N0)
+ | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_N1);
+ regmap_write_bits(rtc->map, RTC_OSCIN_CTRL0, RTC_OSCIN_IN_EN
+ | RTC_OSCIN_OUT_CFG | RTC_OSCIN_OUT_N0M0
+ | RTC_OSCIN_OUT_N1M1, reg_val);
+
+ /* Set M0 to 2, M1 to 3, so freq_out = 32768 Hz*/
+ reg_val = FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_M0)
+ | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_M1);
+ regmap_write_bits(rtc->map, RTC_OSCIN_CTRL1, RTC_OSCIN_OUT_N0M0
+ | RTC_OSCIN_OUT_N1M1, reg_val);
+ } else {
+ /* select 32K oscillator */
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, 0);
+ }
+ }
+ regmap_write_bits(rtc->map, RTC_INT_MASK,
+ RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK);
+ regmap_write_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN, 0);
+}
+
+static int aml_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct aml_rtc_data *rtc;
+ void __iomem *base;
+ int ret = 0;
+
+ const struct regmap_config aml_rtc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = RTC_REAL_TIME,
+ };
+
+ rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->config = of_device_get_match_data(dev);
+ if (!rtc->config)
+ return -ENODEV;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base), "resource ioremap failed\n");
+
+ rtc->map = devm_regmap_init_mmio(dev, base, &aml_rtc_regmap_config);
+ if (IS_ERR(rtc->map))
+ return dev_err_probe(dev, PTR_ERR(rtc->map), "regmap init failed\n");
+
+ rtc->irq = platform_get_irq(pdev, 0);
+ if (rtc->irq < 0)
+ return rtc->irq;
+
+ rtc->rtc_clk = devm_clk_get(dev, "osc");
+ if (IS_ERR(rtc->rtc_clk))
+ return dev_err_probe(dev, PTR_ERR(rtc->rtc_clk),
+ "failed to find rtc clock\n");
+ if (clk_get_rate(rtc->rtc_clk) != OSC_32K && clk_get_rate(rtc->rtc_clk) != OSC_24M)
+ return dev_err_probe(dev, -EINVAL, "Invalid clock configuration\n");
+
+ rtc->sys_clk = devm_clk_get_enabled(dev, "sys");
+ if (IS_ERR(rtc->sys_clk))
+ return dev_err_probe(dev, PTR_ERR(rtc->sys_clk),
+ "failed to get_enable rtc sys clk\n");
+ aml_rtc_init(rtc);
+
+ device_init_wakeup(dev, true);
+ platform_set_drvdata(pdev, rtc);
+
+ rtc->rtc_dev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc->rtc_dev)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err_clk;
+ }
+
+ ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler,
+ IRQF_ONESHOT, "aml-rtc alarm", rtc);
+ if (ret) {
+ dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n",
+ rtc->irq, ret);
+ goto err_clk;
+ }
+
+ rtc->rtc_dev->ops = &aml_rtc_ops;
+ rtc->rtc_dev->range_min = 0;
+ rtc->rtc_dev->range_max = U32_MAX;
+
+ ret = devm_rtc_register_device(rtc->rtc_dev);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret);
+ goto err_clk;
+ }
+
+ return 0;
+err_clk:
+ clk_disable_unprepare(rtc->sys_clk);
+ device_init_wakeup(dev, false);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int aml_rtc_suspend(struct device *dev)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(rtc->irq);
+
+ return 0;
+}
+
+static int aml_rtc_resume(struct device *dev)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(rtc->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops,
+ aml_rtc_suspend, aml_rtc_resume);
+
+static void aml_rtc_remove(struct platform_device *pdev)
+{
+ struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev);
+
+ clk_disable_unprepare(rtc->sys_clk);
+ device_init_wakeup(&pdev->dev, false);
+}
+
+static const struct aml_rtc_config a5_rtc_config = {
+};
+
+static const struct aml_rtc_config a4_rtc_config = {
+ .gray_stored = true,
+};
+
+static const struct of_device_id aml_rtc_device_id[] = {
+ {
+ .compatible = "amlogic,a4-rtc",
+ .data = &a4_rtc_config,
+ },
+ {
+ .compatible = "amlogic,a5-rtc",
+ .data = &a5_rtc_config,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, aml_rtc_device_id);
+
+static struct platform_driver aml_rtc_driver = {
+ .probe = aml_rtc_probe,
+ .remove = aml_rtc_remove,
+ .driver = {
+ .name = "aml-rtc",
+ .pm = &aml_rtc_pm_ops,
+ .of_match_table = aml_rtc_device_id,
+ },
+};
+
+module_platform_driver(aml_rtc_driver);
+MODULE_DESCRIPTION("Amlogic RTC driver");
+MODULE_AUTHOR("Yiting Deng <yiting.deng@amlogic.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
index cc542e6b1d5b..713fa0d077cd 100644
--- a/drivers/rtc/rtc-armada38x.c
+++ b/drivers/rtc/rtc-armada38x.c
@@ -11,7 +11,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
@@ -474,7 +473,6 @@ static const struct armada38x_rtc_data armada8k_data = {
.alarm = ALARM2,
};
-#ifdef CONFIG_OF
static const struct of_device_id armada38x_rtc_of_match_table[] = {
{
.compatible = "marvell,armada-380-rtc",
@@ -487,11 +485,9 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = {
{}
};
MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
-#endif
static __init int armada38x_rtc_probe(struct platform_device *pdev)
{
- struct resource *res;
struct armada38x_rtc *rtc;
rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
@@ -508,12 +504,10 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
spin_lock_init(&rtc->lock);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
- rtc->regs = devm_ioremap_resource(&pdev->dev, res);
+ rtc->regs = devm_platform_ioremap_resource_byname(pdev, "rtc");
if (IS_ERR(rtc->regs))
return PTR_ERR(rtc->regs);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc");
- rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res);
+ rtc->regs_soc = devm_platform_ioremap_resource_byname(pdev, "rtc-soc");
if (IS_ERR(rtc->regs_soc))
return PTR_ERR(rtc->regs_soc);
@@ -533,7 +527,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
if (rtc->irq != -1)
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
else
clear_bit(RTC_FEATURE_ALARM, rtc->rtc_dev->features);
@@ -580,7 +574,7 @@ static struct platform_driver armada38x_rtc_driver = {
.driver = {
.name = "armada38x-rtc",
.pm = &armada38x_rtc_pm_ops,
- .of_match_table = of_match_ptr(armada38x_rtc_of_match_table),
+ .of_match_table = armada38x_rtc_of_match_table,
},
};
diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c
index 0f21af27f4cf..9682d6457b7f 100644
--- a/drivers/rtc/rtc-as3722.c
+++ b/drivers/rtc/rtc-as3722.c
@@ -187,7 +187,7 @@ static int as3722_rtc_probe(struct platform_device *pdev)
return ret;
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
as3722_rtc->rtc = devm_rtc_device_register(&pdev->dev, "as3722-rtc",
&as3722_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c
index de795e489f71..705470ae8428 100644
--- a/drivers/rtc/rtc-asm9260.c
+++ b/drivers/rtc/rtc-asm9260.c
@@ -308,14 +308,13 @@ err_return:
return ret;
}
-static int asm9260_rtc_remove(struct platform_device *pdev)
+static void asm9260_rtc_remove(struct platform_device *pdev)
{
struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev);
/* Disable alarm matching */
iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR);
clk_disable_unprepare(priv->clk);
- return 0;
}
static const struct of_device_id asm9260_dt_ids[] = {
diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c
index a93352ed3aec..0d0053b52f9b 100644
--- a/drivers/rtc/rtc-aspeed.c
+++ b/drivers/rtc/rtc-aspeed.c
@@ -8,7 +8,6 @@
#include <linux/io.h>
struct aspeed_rtc {
- struct rtc_device *rtc_dev;
void __iomem *base;
};
@@ -85,6 +84,7 @@ static const struct rtc_class_ops aspeed_rtc_ops = {
static int aspeed_rtc_probe(struct platform_device *pdev)
{
struct aspeed_rtc *rtc;
+ struct rtc_device *rtc_dev;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
@@ -94,17 +94,17 @@ static int aspeed_rtc_probe(struct platform_device *pdev)
if (IS_ERR(rtc->base))
return PTR_ERR(rtc->base);
- rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(rtc->rtc_dev))
- return PTR_ERR(rtc->rtc_dev);
+ rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc_dev))
+ return PTR_ERR(rtc_dev);
platform_set_drvdata(pdev, rtc);
- rtc->rtc_dev->ops = &aspeed_rtc_ops;
- rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
- rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */
+ rtc_dev->ops = &aspeed_rtc_ops;
+ rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
+ rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */
- return devm_rtc_register_device(rtc->rtc_dev);
+ return devm_rtc_register_device(rtc_dev);
}
static const struct of_device_id aspeed_rtc_match[] = {
@@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(of, aspeed_rtc_match);
static struct platform_driver aspeed_rtc_driver = {
.driver = {
.name = "aspeed-rtc",
- .of_match_table = of_match_ptr(aspeed_rtc_match),
+ .of_match_table = aspeed_rtc_match,
},
};
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index e9d17232d0a8..643734dbae33 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -22,7 +22,6 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
@@ -529,7 +528,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
* being wake-capable; if it didn't, do that here.
*/
if (!device_can_wakeup(&pdev->dev))
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
if (at91_rtc_config->has_correction)
rtc->ops = &sama5d4_rtc_ops;
@@ -559,7 +558,7 @@ err_clk:
/*
* Disable and remove the RTC driver
*/
-static int __exit at91_rtc_remove(struct platform_device *pdev)
+static void __exit at91_rtc_remove(struct platform_device *pdev)
{
/* Disable all interrupts */
at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM |
@@ -567,8 +566,6 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
AT91_RTC_CALEV);
clk_disable_unprepare(sclk);
-
- return 0;
}
static void at91_rtc_shutdown(struct platform_device *pdev)
@@ -636,13 +633,19 @@ static int at91_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
-static struct platform_driver at91_rtc_driver = {
+/*
+ * at91_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver at91_rtc_driver __refdata = {
.remove = __exit_p(at91_rtc_remove),
.shutdown = at91_rtc_shutdown,
.driver = {
.name = "at91_rtc",
.pm = &at91_rtc_pm_ops,
- .of_match_table = of_match_ptr(at91_rtc_dt_ids),
+ .of_match_table = at91_rtc_dt_ids,
},
};
@@ -651,4 +654,3 @@ module_platform_driver_probe(at91_rtc_driver, at91_rtc_probe);
MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:at91_rtc");
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index b7b5ea1a4e67..38991cca5930 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -353,7 +353,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
/* platform setup code should have handled this; sigh */
if (!device_can_wakeup(&pdev->dev))
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
platform_set_drvdata(pdev, rtc);
@@ -368,6 +368,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
return ret;
rtc->gpbr = syscon_node_to_regmap(args.np);
+ of_node_put(args.np);
rtc->gpbr_offset = args.args[0];
if (IS_ERR(rtc->gpbr)) {
dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
@@ -442,7 +443,7 @@ err_clk:
/*
* Disable and remove the RTC driver
*/
-static int at91_rtc_remove(struct platform_device *pdev)
+static void at91_rtc_remove(struct platform_device *pdev)
{
struct sam9_rtc *rtc = platform_get_drvdata(pdev);
u32 mr = rtt_readl(rtc, MR);
@@ -451,8 +452,6 @@ static int at91_rtc_remove(struct platform_device *pdev)
rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
clk_disable_unprepare(rtc->sclk);
-
- return 0;
}
static void at91_rtc_shutdown(struct platform_device *pdev)
@@ -536,7 +535,7 @@ static struct platform_driver at91_rtc_driver = {
.driver = {
.name = "rtc-at91sam9",
.pm = &at91_rtc_pm_ops,
- .of_match_table = of_match_ptr(at91_rtc_dt_ids),
+ .of_match_table = at91_rtc_dt_ids,
},
};
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index 59b627fc1ecf..954ac4ef53e8 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -236,7 +236,6 @@ static int bd70528_probe(struct platform_device *pdev)
{
struct bd70528_rtc *bd_rtc;
const struct rtc_class_ops *rtc_ops;
- const char *irq_name;
int ret;
struct rtc_device *rtc;
int irq;
@@ -259,7 +258,6 @@ static int bd70528_probe(struct platform_device *pdev)
switch (chip) {
case ROHM_CHIP_TYPE_BD71815:
- irq_name = "bd71815-rtc-alm-0";
bd_rtc->reg_time_start = BD71815_REG_RTC_START;
/*
@@ -276,7 +274,6 @@ static int bd70528_probe(struct platform_device *pdev)
hour_reg = BD71815_REG_HOUR;
break;
case ROHM_CHIP_TYPE_BD71828:
- irq_name = "bd71828-rtc-alm-0";
bd_rtc->reg_time_start = BD71828_REG_RTC_START;
bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
hour_reg = BD71828_REG_RTC_HOUR;
@@ -286,7 +283,7 @@ static int bd70528_probe(struct platform_device *pdev)
return -ENOENT;
}
- irq = platform_get_irq_byname(pdev, irq_name);
+ irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm-0");
if (irq < 0)
return irq;
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c
index 967ddc6bf76d..7ad34539be4d 100644
--- a/drivers/rtc/rtc-bq32k.c
+++ b/drivers/rtc/rtc-bq32k.c
@@ -304,7 +304,7 @@ static void bq32k_remove(struct i2c_client *client)
}
static const struct i2c_device_id bq32k_id[] = {
- { "bq32000", 0 },
+ { "bq32000" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bq32k_id);
@@ -320,7 +320,7 @@ static struct i2c_driver bq32k_driver = {
.name = "bq32k",
.of_match_table = of_match_ptr(bq32k_of_match),
},
- .probe_new = bq32k_probe,
+ .probe = bq32k_probe,
.remove = bq32k_remove,
.id_table = bq32k_id,
};
diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c
index c74130e8f496..fb47c32ab5ff 100644
--- a/drivers/rtc/rtc-brcmstb-waketimer.c
+++ b/drivers/rtc/rtc-brcmstb-waketimer.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright © 2014-2017 Broadcom
+ * Copyright © 2014-2023 Broadcom
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -17,7 +17,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
-#include <linux/pm_wakeup.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/stat.h>
@@ -27,13 +26,18 @@ struct brcmstb_waketmr {
struct rtc_device *rtc;
struct device *dev;
void __iomem *base;
- int irq;
+ unsigned int wake_irq;
+ unsigned int alarm_irq;
struct notifier_block reboot_notifier;
struct clk *clk;
u32 rate;
+ unsigned long rtc_alarm;
+ bool alarm_en;
+ bool alarm_expired;
};
#define BRCMSTB_WKTMR_EVENT 0x00
+#define WKTMR_ALARM_EVENT BIT(0)
#define BRCMSTB_WKTMR_COUNTER 0x04
#define BRCMSTB_WKTMR_ALARM 0x08
#define BRCMSTB_WKTMR_PRESCALER 0x0C
@@ -41,28 +45,83 @@ struct brcmstb_waketmr {
#define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000
+static inline bool brcmstb_waketmr_is_pending(struct brcmstb_waketmr *timer)
+{
+ u32 reg;
+
+ reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+ return !!(reg & WKTMR_ALARM_EVENT);
+}
+
static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
{
- writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT);
+ u32 reg;
+
+ if (timer->alarm_en && timer->alarm_irq)
+ disable_irq(timer->alarm_irq);
+ timer->alarm_en = false;
+ reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+ writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM);
+ writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT);
(void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+ if (timer->alarm_expired) {
+ timer->alarm_expired = false;
+ /* maintain call balance */
+ enable_irq(timer->alarm_irq);
+ }
}
static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
unsigned int secs)
{
+ unsigned int now;
+
brcmstb_waketmr_clear_alarm(timer);
/* Make sure we are actually counting in seconds */
writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER);
- writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM);
+ writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM);
+ now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+
+ while ((int)(secs - now) <= 0 &&
+ !brcmstb_waketmr_is_pending(timer)) {
+ secs = now + 1;
+ writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM);
+ now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+ }
}
static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
{
struct brcmstb_waketmr *timer = data;
- pm_wakeup_event(timer->dev, 0);
+ if (!timer->alarm_irq)
+ pm_wakeup_event(timer->dev, 0);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t brcmstb_alarm_irq(int irq, void *data)
+{
+ struct brcmstb_waketmr *timer = data;
+
+ /* Ignore spurious interrupts */
+ if (!brcmstb_waketmr_is_pending(timer))
+ return IRQ_HANDLED;
+
+ if (timer->alarm_en) {
+ if (device_may_wakeup(timer->dev)) {
+ disable_irq_nosync(irq);
+ timer->alarm_expired = true;
+ } else {
+ writel_relaxed(WKTMR_ALARM_EVENT,
+ timer->base + BRCMSTB_WKTMR_EVENT);
+ }
+ rtc_update_irq(timer->rtc, 1, RTC_IRQF | RTC_AF);
+ } else {
+ writel_relaxed(WKTMR_ALARM_EVENT,
+ timer->base + BRCMSTB_WKTMR_EVENT);
+ }
return IRQ_HANDLED;
}
@@ -88,17 +147,25 @@ static void wktmr_read(struct brcmstb_waketmr *timer,
static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
{
struct device *dev = timer->dev;
- int ret = 0;
+ int ret;
if (device_may_wakeup(dev)) {
- ret = enable_irq_wake(timer->irq);
+ ret = enable_irq_wake(timer->wake_irq);
if (ret) {
dev_err(dev, "failed to enable wake-up interrupt\n");
return ret;
}
+ if (timer->alarm_en && timer->alarm_irq) {
+ ret = enable_irq_wake(timer->alarm_irq);
+ if (ret) {
+ dev_err(dev, "failed to enable rtc interrupt\n");
+ disable_irq_wake(timer->wake_irq);
+ return ret;
+ }
+ }
}
- return ret;
+ return 0;
}
/* If enabled as a wakeup-source, arm the timer when powering off */
@@ -146,46 +213,53 @@ static int brcmstb_waketmr_getalarm(struct device *dev,
struct rtc_wkalrm *alarm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
- time64_t sec;
- u32 reg;
- sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
- if (sec != 0) {
- /* Alarm is enabled */
- alarm->enabled = 1;
- rtc_time64_to_tm(sec, &alarm->time);
- }
+ alarm->enabled = timer->alarm_en;
+ rtc_time64_to_tm(timer->rtc_alarm, &alarm->time);
- reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
- alarm->pending = !!(reg & 1);
+ alarm->pending = brcmstb_waketmr_is_pending(timer);
return 0;
}
-static int brcmstb_waketmr_setalarm(struct device *dev,
- struct rtc_wkalrm *alarm)
+static int brcmstb_waketmr_alarm_enable(struct device *dev,
+ unsigned int enabled)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
- time64_t sec;
- if (alarm->enabled)
- sec = rtc_tm_to_time64(&alarm->time);
- else
- sec = 0;
-
- brcmstb_waketmr_set_alarm(timer, sec);
+ if (enabled && !timer->alarm_en) {
+ if ((int)(readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER) -
+ readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM)) >= 0 &&
+ !brcmstb_waketmr_is_pending(timer))
+ return -EINVAL;
+ timer->alarm_en = true;
+ if (timer->alarm_irq) {
+ if (timer->alarm_expired) {
+ timer->alarm_expired = false;
+ /* maintain call balance */
+ enable_irq(timer->alarm_irq);
+ }
+ enable_irq(timer->alarm_irq);
+ }
+ } else if (!enabled && timer->alarm_en) {
+ if (timer->alarm_irq)
+ disable_irq(timer->alarm_irq);
+ timer->alarm_en = false;
+ }
return 0;
}
-/*
- * Does not do much but keep the RTC class happy. We always support
- * alarms.
- */
-static int brcmstb_waketmr_alarm_enable(struct device *dev,
- unsigned int enabled)
+static int brcmstb_waketmr_setalarm(struct device *dev,
+ struct rtc_wkalrm *alarm)
{
- return 0;
+ struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+
+ timer->rtc_alarm = rtc_tm_to_time64(&alarm->time);
+
+ brcmstb_waketmr_set_alarm(timer, timer->rtc_alarm);
+
+ return brcmstb_waketmr_alarm_enable(dev, alarm->enabled);
}
static const struct rtc_class_ops brcmstb_waketmr_ops = {
@@ -221,12 +295,12 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
* Set wakeup capability before requesting wakeup interrupt, so we can
* process boot-time "wakeups" (e.g., from S5 soft-off)
*/
- device_set_wakeup_capable(dev, true);
- device_wakeup_enable(dev);
+ device_init_wakeup(dev, true);
- timer->irq = platform_get_irq(pdev, 0);
- if (timer->irq < 0)
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
return -ENODEV;
+ timer->wake_irq = (unsigned int)ret;
timer->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(timer->clk)) {
@@ -241,11 +315,24 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
timer->clk = NULL;
}
- ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0,
+ ret = devm_request_irq(dev, timer->wake_irq, brcmstb_waketmr_irq, 0,
"brcmstb-waketimer", timer);
if (ret < 0)
goto err_clk;
+ brcmstb_waketmr_clear_alarm(timer);
+
+ /* Attempt to initialize non-wake irq */
+ ret = platform_get_irq(pdev, 1);
+ if (ret > 0) {
+ timer->alarm_irq = (unsigned int)ret;
+ ret = devm_request_irq(dev, timer->alarm_irq, brcmstb_alarm_irq,
+ IRQF_NO_AUTOEN, "brcmstb-waketimer-rtc",
+ timer);
+ if (ret < 0)
+ timer->alarm_irq = 0;
+ }
+
timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
register_reboot_notifier(&timer->reboot_notifier);
@@ -256,8 +343,6 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
if (ret)
goto err_notifier;
- dev_info(dev, "registered, with irq %d\n", timer->irq);
-
return 0;
err_notifier:
@@ -269,14 +354,12 @@ err_clk:
return ret;
}
-static int brcmstb_waketmr_remove(struct platform_device *pdev)
+static void brcmstb_waketmr_remove(struct platform_device *pdev)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
unregister_reboot_notifier(&timer->reboot_notifier);
clk_disable_unprepare(timer->clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -287,6 +370,17 @@ static int brcmstb_waketmr_suspend(struct device *dev)
return brcmstb_waketmr_prepare_suspend(timer);
}
+static int brcmstb_waketmr_suspend_noirq(struct device *dev)
+{
+ struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+
+ /* Catch any alarms occurring prior to noirq */
+ if (timer->alarm_expired && device_may_wakeup(dev))
+ return -EBUSY;
+
+ return 0;
+}
+
static int brcmstb_waketmr_resume(struct device *dev)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
@@ -295,16 +389,25 @@ static int brcmstb_waketmr_resume(struct device *dev)
if (!device_may_wakeup(dev))
return 0;
- ret = disable_irq_wake(timer->irq);
+ ret = disable_irq_wake(timer->wake_irq);
+ if (timer->alarm_en && timer->alarm_irq)
+ disable_irq_wake(timer->alarm_irq);
brcmstb_waketmr_clear_alarm(timer);
return ret;
}
+#else
+#define brcmstb_waketmr_suspend NULL
+#define brcmstb_waketmr_suspend_noirq NULL
+#define brcmstb_waketmr_resume NULL
#endif /* CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops,
- brcmstb_waketmr_suspend, brcmstb_waketmr_resume);
+static const struct dev_pm_ops brcmstb_waketmr_pm_ops = {
+ .suspend = brcmstb_waketmr_suspend,
+ .suspend_noirq = brcmstb_waketmr_suspend_noirq,
+ .resume = brcmstb_waketmr_resume,
+};
static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = {
{ .compatible = "brcm,brcmstb-waketimer" },
@@ -325,4 +428,5 @@ module_platform_driver(brcmstb_waketmr_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris");
MODULE_AUTHOR("Markus Mayer");
+MODULE_AUTHOR("Doug Berger");
MODULE_DESCRIPTION("Wake-up timer driver for STB chips");
diff --git a/drivers/rtc/rtc-cadence.c b/drivers/rtc/rtc-cadence.c
index 1edf7f16d73a..8634eea799ab 100644
--- a/drivers/rtc/rtc-cadence.c
+++ b/drivers/rtc/rtc-cadence.c
@@ -354,17 +354,15 @@ err_disable_pclk:
return ret;
}
-static int cdns_rtc_remove(struct platform_device *pdev)
+static void cdns_rtc_remove(struct platform_device *pdev)
{
struct cdns_rtc *crtc = platform_get_drvdata(pdev);
cdns_rtc_alarm_irq_enable(&pdev->dev, 0);
- device_init_wakeup(&pdev->dev, 0);
+ device_init_wakeup(&pdev->dev, false);
clk_disable_unprepare(crtc->pclk);
clk_disable_unprepare(crtc->ref_clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 00e2ca7374ec..0743c6acd6e2 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -151,11 +151,6 @@ static inline int hpet_set_periodic_freq(unsigned long freq)
return 0;
}
-static inline int hpet_rtc_dropped_irq(void)
-{
- return 0;
-}
-
static inline int hpet_rtc_timer_init(void)
{
return 0;
@@ -231,7 +226,7 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t)
if (!pm_trace_rtc_valid())
return -EIO;
- ret = mc146818_get_time(t);
+ ret = mc146818_get_time(t, 1000);
if (ret < 0) {
dev_err_ratelimited(dev, "unable to read current time\n");
return ret;
@@ -292,7 +287,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
/* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq))
- return -EIO;
+ return -ETIMEDOUT;
/* Basic alarms only support hour, minute, and seconds fields.
* Some also support day and month, for alarms up to a year in
@@ -307,7 +302,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
*
* Use the mc146818_avoid_UIP() function to avoid this.
*/
- if (!mc146818_avoid_UIP(cmos_read_alarm_callback, &p))
+ if (!mc146818_avoid_UIP(cmos_read_alarm_callback, 10, &p))
return -EIO;
if (!(p.rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@@ -556,8 +551,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
*
* Use mc146818_avoid_UIP() to avoid this.
*/
- if (!mc146818_avoid_UIP(cmos_set_alarm_callback, &p))
- return -EIO;
+ if (!mc146818_avoid_UIP(cmos_set_alarm_callback, 10, &p))
+ return -ETIMEDOUT;
cmos->alarm_expires = rtc_tm_to_time64(&t->time);
@@ -643,21 +638,19 @@ static int cmos_nvram_read(void *priv, unsigned int off, void *val,
size_t count)
{
unsigned char *buf = val;
- int retval;
off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
- for (retval = 0; count; count--, off++, retval++) {
+ for (; count; count--, off++, buf++) {
+ guard(spinlock_irq)(&rtc_lock);
if (off < 128)
- *buf++ = CMOS_READ(off);
+ *buf = CMOS_READ(off);
else if (can_bank2)
- *buf++ = cmos_read_bank2(off);
+ *buf = cmos_read_bank2(off);
else
- break;
+ return -EIO;
}
- spin_unlock_irq(&rtc_lock);
- return retval;
+ return 0;
}
static int cmos_nvram_write(void *priv, unsigned int off, void *val,
@@ -665,7 +658,6 @@ static int cmos_nvram_write(void *priv, unsigned int off, void *val,
{
struct cmos_rtc *cmos = priv;
unsigned char *buf = val;
- int retval;
/* NOTE: on at least PCs and Ataris, the boot firmware uses a
* checksum on part of the NVRAM data. That's currently ignored
@@ -673,23 +665,23 @@ static int cmos_nvram_write(void *priv, unsigned int off, void *val,
* NVRAM to update, updating checksums is also part of its job.
*/
off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
- for (retval = 0; count; count--, off++, retval++) {
+ for (; count; count--, off++, buf++) {
/* don't trash RTC registers */
if (off == cmos->day_alrm
|| off == cmos->mon_alrm
|| off == cmos->century)
- buf++;
- else if (off < 128)
- CMOS_WRITE(*buf++, off);
+ continue;
+
+ guard(spinlock_irq)(&rtc_lock);
+ if (off < 128)
+ CMOS_WRITE(*buf, off);
else if (can_bank2)
- cmos_write_bank2(*buf++, off);
+ cmos_write_bank2(*buf, off);
else
- break;
+ return -EIO;
}
- spin_unlock_irq(&rtc_lock);
- return retval;
+ return 0;
}
/*----------------------------------------------------------------*/
@@ -700,8 +692,12 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
{
u8 irqstat;
u8 rtc_control;
+ unsigned long flags;
- spin_lock(&rtc_lock);
+ /* We cannot use spin_lock() here, as cmos_interrupt() is also called
+ * in a non-irq context.
+ */
+ spin_lock_irqsave(&rtc_lock, flags);
/* When the HPET interrupt handler calls us, the interrupt
* status is passed as arg1 instead of the irq number. But
@@ -735,7 +731,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
hpet_mask_rtc_irq_bit(RTC_AIE);
CMOS_READ(RTC_INTR_FLAGS);
}
- spin_unlock(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (is_intr(irqstat)) {
rtc_update_irq(p, 1, irqstat);
@@ -818,18 +814,24 @@ static void rtc_wake_off(struct device *dev)
}
#ifdef CONFIG_X86
-/* Enable use_acpi_alarm mode for Intel platforms no earlier than 2015 */
static void use_acpi_alarm_quirks(void)
{
- if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_INTEL:
+ if (dmi_get_bios_year() < 2015)
+ return;
+ break;
+ case X86_VENDOR_AMD:
+ case X86_VENDOR_HYGON:
+ if (dmi_get_bios_year() < 2021)
+ return;
+ break;
+ default:
return;
-
+ }
if (!is_hpet_enabled())
return;
- if (dmi_get_bios_year() < 2015)
- return;
-
use_acpi_alarm = true;
}
#else
@@ -861,7 +863,7 @@ static void acpi_cmos_wake_setup(struct device *dev)
dev_info(dev, "RTC can wake from S4\n");
/* RTC always wakes from S1/S2/S3, and often S4/STD */
- device_init_wakeup(dev, 1);
+ device_init_wakeup(dev, true);
}
static void cmos_check_acpi_rtc_status(struct device *dev,
@@ -913,6 +915,10 @@ static inline void cmos_check_acpi_rtc_status(struct device *dev,
#define INITSECTION __init
#endif
+#define SECS_PER_DAY (24 * 60 * 60)
+#define SECS_PER_MONTH (28 * SECS_PER_DAY)
+#define SECS_PER_YEAR (365 * SECS_PER_DAY)
+
static int INITSECTION
cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
{
@@ -1019,6 +1025,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup0;
}
+ if (cmos_rtc.mon_alrm)
+ cmos_rtc.rtc->alarm_offset_max = SECS_PER_YEAR - 1;
+ else if (cmos_rtc.day_alrm)
+ cmos_rtc.rtc->alarm_offset_max = SECS_PER_MONTH - 1;
+ else
+ cmos_rtc.rtc->alarm_offset_max = SECS_PER_DAY - 1;
+
rename_region(ports, dev_name(&cmos_rtc.rtc->dev));
if (!mc146818_does_rtc_work()) {
@@ -1286,9 +1299,7 @@ static void cmos_check_wkalrm(struct device *dev)
* ACK the rtc irq here
*/
if (t_now >= cmos->alarm_expires && cmos_use_acpi_alarm()) {
- local_irq_disable();
cmos_interrupt(0, (void *)cmos->rtc);
- local_irq_enable();
return;
}
@@ -1489,10 +1500,9 @@ static int __init cmos_platform_probe(struct platform_device *pdev)
return cmos_do_probe(&pdev->dev, resource, irq);
}
-static int cmos_platform_remove(struct platform_device *pdev)
+static void cmos_platform_remove(struct platform_device *pdev)
{
cmos_do_remove(&pdev->dev);
- return 0;
}
static void cmos_platform_shutdown(struct platform_device *pdev)
diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c
index afc8fcba8f88..c170345ac076 100644
--- a/drivers/rtc/rtc-cpcap.c
+++ b/drivers/rtc/rtc-cpcap.c
@@ -295,7 +295,7 @@ static int cpcap_rtc_probe(struct platform_device *pdev)
}
disable_irq(rtc->update_irq);
- err = device_init_wakeup(dev, 1);
+ err = device_init_wakeup(dev, true);
if (err) {
dev_err(dev, "wakeup initialization failed (%d)\n", err);
/* ignore error and continue without wakeup support */
@@ -320,7 +320,6 @@ static struct platform_driver cpcap_rtc_driver = {
module_platform_driver(cpcap_rtc_driver);
-MODULE_ALIAS("platform:cpcap-rtc");
MODULE_DESCRIPTION("CPCAP RTC driver");
MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c
index a3ec066d8066..e956505a06fb 100644
--- a/drivers/rtc/rtc-cros-ec.c
+++ b/drivers/rtc/rtc-cros-ec.c
@@ -5,6 +5,7 @@
// Author: Stephen Barber <smbarber@chromium.org>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
@@ -34,21 +35,18 @@ struct cros_ec_rtc {
static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command,
u32 *response)
{
+ DEFINE_RAW_FLEX(struct cros_ec_command, msg, data,
+ sizeof(struct ec_response_rtc));
int ret;
- struct {
- struct cros_ec_command msg;
- struct ec_response_rtc data;
- } __packed msg;
- memset(&msg, 0, sizeof(msg));
- msg.msg.command = command;
- msg.msg.insize = sizeof(msg.data);
+ msg->command = command;
+ msg->insize = sizeof(struct ec_response_rtc);
- ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
+ ret = cros_ec_cmd_xfer_status(cros_ec, msg);
if (ret < 0)
return ret;
- *response = msg.data.time;
+ *response = ((struct ec_response_rtc *)msg->data)->time;
return 0;
}
@@ -56,18 +54,15 @@ static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command,
static int cros_ec_rtc_set(struct cros_ec_device *cros_ec, u32 command,
u32 param)
{
+ DEFINE_RAW_FLEX(struct cros_ec_command, msg, data,
+ sizeof(struct ec_response_rtc));
int ret;
- struct {
- struct cros_ec_command msg;
- struct ec_response_rtc data;
- } __packed msg;
- memset(&msg, 0, sizeof(msg));
- msg.msg.command = command;
- msg.msg.outsize = sizeof(msg.data);
- msg.data.time = param;
+ msg->command = command;
+ msg->outsize = sizeof(struct ec_response_rtc);
+ ((struct ec_response_rtc *)msg->data)->time = param;
- ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
+ ret = cros_ec_cmd_xfer_status(cros_ec, msg);
if (ret < 0)
return ret;
return 0;
@@ -182,21 +177,15 @@ static int cros_ec_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset);
if (ret < 0) {
- if (ret == -EINVAL && alarm_offset >= SECS_PER_DAY) {
- /*
- * RTC chips on some older Chromebooks can only handle
- * alarms up to 24h in the future. Try to set an alarm
- * below that limit to avoid suspend failures.
- */
- ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM,
- SECS_PER_DAY - 1);
- }
-
- if (ret < 0) {
- dev_err(dev, "error setting alarm in %u seconds: %d\n",
- alarm_offset, ret);
- return ret;
- }
+ dev_err(dev, "error setting alarm in %u seconds: %d\n",
+ alarm_offset, ret);
+ /*
+ * The EC code returns -EINVAL if the alarm time is too
+ * far in the future. Convert it to the expected error code.
+ */
+ if (ret == -EINVAL)
+ ret = -ERANGE;
+ return ret;
}
return 0;
@@ -342,7 +331,7 @@ static int cros_ec_rtc_probe(struct platform_device *pdev)
return ret;
}
- ret = device_init_wakeup(&pdev->dev, 1);
+ ret = device_init_wakeup(&pdev->dev, true);
if (ret) {
dev_err(&pdev->dev, "failed to initialize wakeup\n");
return ret;
@@ -355,6 +344,20 @@ static int cros_ec_rtc_probe(struct platform_device *pdev)
cros_ec_rtc->rtc->ops = &cros_ec_rtc_ops;
cros_ec_rtc->rtc->range_max = U32_MAX;
+ /*
+ * The RTC on some older Chromebooks can only handle alarms less than
+ * 24 hours in the future. The only way to find out is to try to set an
+ * alarm further in the future. If that fails, assume that the RTC
+ * connected to the EC can only handle less than 24 hours of alarm
+ * window.
+ */
+ ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, SECS_PER_DAY * 2);
+ if (ret == -EINVAL)
+ cros_ec_rtc->rtc->alarm_offset_max = SECS_PER_DAY - 1;
+
+ (void)cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM,
+ EC_RTC_ALARM_CLEAR);
+
ret = devm_rtc_register_device(cros_ec_rtc->rtc);
if (ret)
return ret;
@@ -371,7 +374,7 @@ static int cros_ec_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int cros_ec_rtc_remove(struct platform_device *pdev)
+static void cros_ec_rtc_remove(struct platform_device *pdev)
{
struct cros_ec_rtc *cros_ec_rtc = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -382,10 +385,14 @@ static int cros_ec_rtc_remove(struct platform_device *pdev)
&cros_ec_rtc->notifier);
if (ret)
dev_err(dev, "failed to unregister notifier\n");
-
- return 0;
}
+static const struct platform_device_id cros_ec_rtc_id[] = {
+ { DRV_NAME, 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cros_ec_rtc_id);
+
static struct platform_driver cros_ec_rtc_driver = {
.probe = cros_ec_rtc_probe,
.remove = cros_ec_rtc_remove,
@@ -393,6 +400,7 @@ static struct platform_driver cros_ec_rtc_driver = {
.name = DRV_NAME,
.pm = &cros_ec_rtc_pm_ops,
},
+ .id_table = cros_ec_rtc_id,
};
module_platform_driver(cros_ec_rtc_driver);
@@ -400,4 +408,3 @@ module_platform_driver(cros_ec_rtc_driver);
MODULE_DESCRIPTION("RTC driver for Chrome OS ECs");
MODULE_AUTHOR("Stephen Barber <smbarber@chromium.org>");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/rtc/rtc-cv1800.c b/drivers/rtc/rtc-cv1800.c
new file mode 100644
index 000000000000..678c2c10bf58
--- /dev/null
+++ b/drivers/rtc/rtc-cv1800.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * rtc-cv1800.c: RTC driver for Sophgo cv1800 RTC
+ *
+ * Author: Jingbao Qiu <qiujingbao.dlmu@gmail.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define SEC_PULSE_GEN 0x1004
+#define ALARM_TIME 0x1008
+#define ALARM_ENABLE 0x100C
+#define SET_SEC_CNTR_VAL 0x1010
+#define SET_SEC_CNTR_TRIG 0x1014
+#define SEC_CNTR_VAL 0x1018
+
+/*
+ * When in VDDBKUP domain, this MACRO register
+ * does not power down
+ */
+#define MACRO_RO_T 0x14A8
+#define MACRO_RG_SET_T 0x1498
+
+#define ALARM_ENABLE_MASK BIT(0)
+#define SEL_SEC_PULSE BIT(31)
+
+struct cv1800_rtc_priv {
+ struct rtc_device *rtc_dev;
+ struct regmap *rtc_map;
+ struct clk *clk;
+ int irq;
+};
+
+static bool cv1800_rtc_enabled(struct device *dev)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ u32 reg;
+
+ regmap_read(info->rtc_map, SEC_PULSE_GEN, &reg);
+
+ return (reg & SEL_SEC_PULSE) == 0;
+}
+
+static void cv1800_rtc_enable(struct device *dev)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+
+ /* Sec pulse generated internally */
+ regmap_update_bits(info->rtc_map, SEC_PULSE_GEN, SEL_SEC_PULSE, 0);
+}
+
+static int cv1800_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+
+ regmap_write(info->rtc_map, ALARM_ENABLE, enabled);
+
+ return 0;
+}
+
+static int cv1800_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ unsigned long alarm_time;
+
+ alarm_time = rtc_tm_to_time64(&alrm->time);
+
+ cv1800_rtc_alarm_irq_enable(dev, 0);
+
+ regmap_write(info->rtc_map, ALARM_TIME, alarm_time);
+
+ cv1800_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+ return 0;
+}
+
+static int cv1800_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ u32 enabled;
+ u32 time;
+
+ if (!cv1800_rtc_enabled(dev)) {
+ alarm->enabled = 0;
+ return 0;
+ }
+
+ regmap_read(info->rtc_map, ALARM_ENABLE, &enabled);
+
+ alarm->enabled = enabled & ALARM_ENABLE_MASK;
+
+ regmap_read(info->rtc_map, ALARM_TIME, &time);
+
+ rtc_time64_to_tm(time, &alarm->time);
+
+ return 0;
+}
+
+static int cv1800_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ u32 sec;
+
+ if (!cv1800_rtc_enabled(dev))
+ return -EINVAL;
+
+ regmap_read(info->rtc_map, SEC_CNTR_VAL, &sec);
+
+ rtc_time64_to_tm(sec, tm);
+
+ return 0;
+}
+
+static int cv1800_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ unsigned long sec;
+
+ sec = rtc_tm_to_time64(tm);
+
+ regmap_write(info->rtc_map, SET_SEC_CNTR_VAL, sec);
+ regmap_write(info->rtc_map, SET_SEC_CNTR_TRIG, 1);
+
+ regmap_write(info->rtc_map, MACRO_RG_SET_T, sec);
+
+ cv1800_rtc_enable(dev);
+
+ return 0;
+}
+
+static irqreturn_t cv1800_rtc_irq_handler(int irq, void *dev_id)
+{
+ struct cv1800_rtc_priv *info = dev_id;
+
+ rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+ regmap_write(info->rtc_map, ALARM_ENABLE, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops cv1800_rtc_ops = {
+ .read_time = cv1800_rtc_read_time,
+ .set_time = cv1800_rtc_set_time,
+ .read_alarm = cv1800_rtc_read_alarm,
+ .set_alarm = cv1800_rtc_set_alarm,
+ .alarm_irq_enable = cv1800_rtc_alarm_irq_enable,
+};
+
+static int cv1800_rtc_probe(struct platform_device *pdev)
+{
+ struct cv1800_rtc_priv *rtc;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->rtc_map = device_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(rtc->rtc_map))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_map),
+ "cannot get parent regmap\n");
+
+ rtc->irq = platform_get_irq(pdev, 0);
+ if (rtc->irq < 0)
+ return rtc->irq;
+
+ rtc->clk = devm_clk_get_enabled(pdev->dev.parent, "rtc");
+ if (IS_ERR(rtc->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->clk),
+ "rtc clk not found\n");
+
+ platform_set_drvdata(pdev, rtc);
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
+ rtc->rtc_dev->ops = &cv1800_rtc_ops;
+ rtc->rtc_dev->range_max = U32_MAX;
+
+ ret = devm_request_irq(&pdev->dev, rtc->irq, cv1800_rtc_irq_handler,
+ IRQF_TRIGGER_HIGH, "rtc alarm", rtc);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "cannot register interrupt handler\n");
+
+ return devm_rtc_register_device(rtc->rtc_dev);
+}
+
+static const struct platform_device_id cv1800_rtc_id[] = {
+ { .name = "cv1800b-rtc" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, cv1800_rtc_id);
+
+static struct platform_driver cv1800_rtc_driver = {
+ .driver = {
+ .name = "sophgo-cv1800-rtc",
+ },
+ .probe = cv1800_rtc_probe,
+ .id_table = cv1800_rtc_id,
+};
+
+module_platform_driver(cv1800_rtc_driver);
+MODULE_AUTHOR("Jingbao Qiu");
+MODULE_DESCRIPTION("Sophgo cv1800 RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c
index 844168fcae1e..05adec6b77bf 100644
--- a/drivers/rtc/rtc-da9055.c
+++ b/drivers/rtc/rtc-da9055.c
@@ -288,7 +288,7 @@ static int da9055_rtc_probe(struct platform_device *pdev)
if (ret & DA9055_RTC_ALM_EN)
rtc->alarm_enable = 1;
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&da9055_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
index ee2efb496174..557c9b29dcc1 100644
--- a/drivers/rtc/rtc-da9063.c
+++ b/drivers/rtc/rtc-da9063.c
@@ -11,6 +11,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>
#include <linux/slab.h>
@@ -193,26 +194,17 @@ static void da9063_tm_to_data(struct rtc_time *tm, u8 *data,
config->rtc_count_year_mask;
}
-static int da9063_rtc_stop_alarm(struct device *dev)
-{
- struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
- const struct da9063_compatible_rtc_regmap *config = rtc->config;
-
- return regmap_update_bits(rtc->regmap,
- config->rtc_alarm_year_reg,
- config->rtc_alarm_on_mask,
- 0);
-}
-
-static int da9063_rtc_start_alarm(struct device *dev)
+static int da9063_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
{
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
const struct da9063_compatible_rtc_regmap *config = rtc->config;
+ u8 set_bit = enabled ? config->rtc_alarm_on_mask : 0;
return regmap_update_bits(rtc->regmap,
config->rtc_alarm_year_reg,
config->rtc_alarm_on_mask,
- config->rtc_alarm_on_mask);
+ set_bit);
}
static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -311,7 +303,7 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
da9063_tm_to_data(&alrm->time, data, rtc);
- ret = da9063_rtc_stop_alarm(dev);
+ ret = da9063_rtc_alarm_irq_enable(dev, 0);
if (ret < 0) {
dev_err(dev, "Failed to stop alarm: %d\n", ret);
return ret;
@@ -329,7 +321,7 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
da9063_data_to_tm(data, &rtc->alarm_time, rtc);
if (alrm->enabled) {
- ret = da9063_rtc_start_alarm(dev);
+ ret = da9063_rtc_alarm_irq_enable(dev, 1);
if (ret < 0) {
dev_err(dev, "Failed to start alarm: %d\n", ret);
return ret;
@@ -339,15 +331,6 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return ret;
}
-static int da9063_rtc_alarm_irq_enable(struct device *dev,
- unsigned int enabled)
-{
- if (enabled)
- return da9063_rtc_start_alarm(dev);
- else
- return da9063_rtc_stop_alarm(dev);
-}
-
static irqreturn_t da9063_alarm_event(int irq, void *data)
{
struct da9063_compatible_rtc *rtc = data;
@@ -376,7 +359,6 @@ static int da9063_rtc_probe(struct platform_device *pdev)
{
struct da9063_compatible_rtc *rtc;
const struct da9063_compatible_rtc_regmap *config;
- const struct of_device_id *match;
int irq_alarm;
u8 data[RTC_DATA_LEN];
int ret;
@@ -384,14 +366,11 @@ static int da9063_rtc_probe(struct platform_device *pdev)
if (!pdev->dev.of_node)
return -ENXIO;
- match = of_match_node(da9063_compatible_reg_id_table,
- pdev->dev.of_node);
-
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
- rtc->config = match->data;
+ rtc->config = device_get_match_data(&pdev->dev);
if (of_device_is_compatible(pdev->dev.of_node, "dlg,da9063-rtc")) {
struct da9063 *chip = dev_get_drvdata(pdev->dev.parent);
@@ -410,57 +389,49 @@ static int da9063_rtc_probe(struct platform_device *pdev)
config->rtc_enable_reg,
config->rtc_enable_mask,
config->rtc_enable_mask);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to enable RTC\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "Failed to enable RTC\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_enable_32k_crystal_reg,
config->rtc_crystal_mask,
config->rtc_crystal_mask);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to run 32kHz oscillator\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_alarm_secs_reg,
config->rtc_alarm_status_mask,
0);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to access RTC alarm register\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_alarm_secs_reg,
DA9063_ALARM_STATUS_ALARM,
DA9063_ALARM_STATUS_ALARM);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to access RTC alarm register\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_alarm_year_reg,
config->rtc_tick_on_mask,
0);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to disable TICKs\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to disable TICKs\n");
data[RTC_SEC] = 0;
ret = regmap_bulk_read(rtc->regmap,
config->rtc_alarm_secs_reg,
&data[config->rtc_data_start],
config->rtc_alarm_len);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n",
- ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to read initial alarm data\n");
platform_set_drvdata(pdev, rtc);
@@ -484,19 +455,29 @@ static int da9063_rtc_probe(struct platform_device *pdev)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc_dev->features);
}
- irq_alarm = platform_get_irq_byname(pdev, "ALARM");
- if (irq_alarm < 0)
+ irq_alarm = platform_get_irq_byname_optional(pdev, "ALARM");
+ if (irq_alarm >= 0) {
+ ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
+ da9063_alarm_event,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "ALARM", rtc);
+ if (ret)
+ dev_err(&pdev->dev,
+ "Failed to request ALARM IRQ %d: %d\n",
+ irq_alarm, ret);
+
+ ret = dev_pm_set_wake_irq(&pdev->dev, irq_alarm);
+ if (ret)
+ dev_warn(&pdev->dev,
+ "Failed to set IRQ %d as a wake IRQ: %d\n",
+ irq_alarm, ret);
+
+ device_init_wakeup(&pdev->dev, true);
+ } else if (irq_alarm != -ENXIO) {
return irq_alarm;
-
- ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
- da9063_alarm_event,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "ALARM", rtc);
- if (ret)
- dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
- irq_alarm, ret);
-
- device_init_wakeup(&pdev->dev, true);
+ } else {
+ clear_bit(RTC_FEATURE_ALARM, rtc->rtc_dev->features);
+ }
return devm_rtc_register_device(rtc->rtc_dev);
}
@@ -514,4 +495,3 @@ module_platform_driver(da9063_rtc_driver);
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC);
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index ed9360486953..d4de401548b4 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -336,8 +336,8 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
/* make sure alarm fires within the next 24 hours */
if (later <= now)
return -EINVAL;
- if ((later - now) > 24 * 60 * 60)
- return -EDOM;
+ if ((later - now) > ds1305->rtc->alarm_offset_max)
+ return -ERANGE;
/* disable alarm if needed */
if (ds1305->ctrl[0] & DS1305_AEI0) {
@@ -691,6 +691,7 @@ static int ds1305_probe(struct spi_device *spi)
ds1305->rtc->ops = &ds1305_ops;
ds1305->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
ds1305->rtc->range_max = RTC_TIMESTAMP_END_2099;
+ ds1305->rtc->alarm_offset_max = 24 * 60 * 60;
ds1305_nvmem_cfg.priv = ds1305;
status = devm_rtc_register_device(ds1305->rtc);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index def9b7f9d957..7205c59ff729 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -65,6 +65,7 @@ enum ds_type {
# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
#define DS1307_REG_WDAY 0x03 /* 01-07 */
+# define MCP794XX_BIT_OSCRUN BIT(5)
# define MCP794XX_BIT_VBATEN 0x08
#define DS1307_REG_MDAY 0x04 /* 01-31 */
#define DS1307_REG_MONTH 0x05 /* 01-12 */
@@ -242,6 +243,10 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
regs[DS1307_REG_MIN] & M41T0_BIT_OF) {
dev_warn_once(dev, "oscillator failed, set time!\n");
return -EINVAL;
+ } else if (ds1307->type == mcp794xx &&
+ !(regs[DS1307_REG_WDAY] & MCP794XX_BIT_OSCRUN)) {
+ dev_warn_once(dev, "oscillator failed, set time!\n");
+ return -EINVAL;
}
tmp = regs[DS1307_REG_SECS];
@@ -274,6 +279,13 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
if (tmp & DS1340_BIT_OSF)
return -EINVAL;
break;
+ case ds_1341:
+ ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &tmp);
+ if (ret)
+ return ret;
+ if (tmp & DS1337_BIT_OSF)
+ return -EINVAL;
+ break;
case ds_1388:
ret = regmap_read(ds1307->regmap, DS1388_REG_FLAG, &tmp);
if (ret)
@@ -354,7 +366,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
regs[DS1307_REG_MONTH] = bin2bcd(t->tm_mon + 1);
/* assume 20YY not 19YY */
- tmp = t->tm_year - 100;
+ tmp = t->tm_year % 100;
regs[DS1307_REG_YEAR] = bin2bcd(tmp);
if (chip->century_enable_bit)
@@ -372,6 +384,10 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG,
DS1340_BIT_OSF, 0);
break;
+ case ds_1341:
+ regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS,
+ DS1337_BIT_OSF, 0);
+ break;
case ds_1388:
regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG,
DS1388_BIT_OSF, 0);
@@ -1451,16 +1467,21 @@ static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw,
return ds3231_clk_sqw_rates[rate_sel];
}
-static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int ds3231_clk_sqw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) {
- if (ds3231_clk_sqw_rates[i] <= rate)
- return ds3231_clk_sqw_rates[i];
+ if (ds3231_clk_sqw_rates[i] <= req->rate) {
+ req->rate = ds3231_clk_sqw_rates[i];
+
+ return 0;
+ }
}
+ req->rate = ds3231_clk_sqw_rates[ARRAY_SIZE(ds3231_clk_sqw_rates) - 1];
+
return 0;
}
@@ -1520,7 +1541,7 @@ static const struct clk_ops ds3231_clk_sqw_ops = {
.unprepare = ds3231_clk_sqw_unprepare,
.is_prepared = ds3231_clk_sqw_is_prepared,
.recalc_rate = ds3231_clk_sqw_recalc_rate,
- .round_rate = ds3231_clk_sqw_round_rate,
+ .determine_rate = ds3231_clk_sqw_determine_rate,
.set_rate = ds3231_clk_sqw_set_rate,
};
@@ -1712,9 +1733,9 @@ static const struct regmap_config regmap_config = {
.val_bits = 8,
};
-static int ds1307_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ds1307_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ds1307 *ds1307;
const void *match;
int err = -ENODEV;
@@ -1744,7 +1765,7 @@ static int ds1307_probe(struct i2c_client *client,
match = device_get_match_data(&client->dev);
if (match) {
- ds1307->type = (enum ds_type)match;
+ ds1307->type = (uintptr_t)match;
chip = &chips[ds1307->type];
} else if (id) {
chip = &chips[id->driver_data];
@@ -1802,18 +1823,14 @@ static int ds1307_probe(struct i2c_client *client,
* For some variants, be sure alarms can trigger when we're
* running on Vbackup (BBSQI/BBSQW)
*/
- if (want_irq || ds1307_can_wakeup_device) {
+ if (want_irq || ds1307_can_wakeup_device)
regs[0] |= DS1337_BIT_INTCN | chip->bbsqi_bit;
- regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
- }
regmap_write(ds1307->regmap, DS1337_REG_CONTROL,
regs[0]);
- /* oscillator fault? clear flag, and warn */
+ /* oscillator fault? warn */
if (regs[1] & DS1337_BIT_OSF) {
- regmap_write(ds1307->regmap, DS1337_REG_STATUS,
- regs[1] & ~DS1337_BIT_OSF);
dev_warn(ds1307->dev, "SET TIME!\n");
}
break;
diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c
index ed5a6ba89a3e..aa9500791b7e 100644
--- a/drivers/rtc/rtc-ds1343.c
+++ b/drivers/rtc/rtc-ds1343.c
@@ -427,18 +427,13 @@ static int ds1343_probe(struct spi_device *spi)
"unable to request irq for rtc ds1343\n");
} else {
device_init_wakeup(&spi->dev, true);
- dev_pm_set_wake_irq(&spi->dev, spi->irq);
+ devm_pm_set_wake_irq(&spi->dev, spi->irq);
}
}
return 0;
}
-static void ds1343_remove(struct spi_device *spi)
-{
- dev_pm_clear_wake_irq(&spi->dev);
-}
-
#ifdef CONFIG_PM_SLEEP
static int ds1343_suspend(struct device *dev)
@@ -471,7 +466,6 @@ static struct spi_driver ds1343_driver = {
.pm = &ds1343_pm,
},
.probe = ds1343_probe,
- .remove = ds1343_remove,
.id_table = ds1343_id,
};
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 7f089f066163..c2359eb86bc9 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -52,7 +52,7 @@
#define DS1374_REG_TCR 0x09 /* Trickle Charge */
static const struct i2c_device_id ds1374_id[] = {
- { "ds1374", 0 },
+ { "ds1374" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1374_id);
@@ -572,7 +572,7 @@ static struct i2c_driver ds1374_driver = {
.of_match_table = of_match_ptr(ds1374_of_match),
.pm = &ds1374_pm,
},
- .probe_new = ds1374_probe,
+ .probe = ds1374_probe,
.remove = ds1374_remove,
.id_table = ds1374_id,
};
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
index 93ce72b9ae59..f46428ca77cc 100644
--- a/drivers/rtc/rtc-ds1390.c
+++ b/drivers/rtc/rtc-ds1390.c
@@ -213,7 +213,7 @@ static int ds1390_probe(struct spi_device *spi)
return res;
}
-static const struct of_device_id ds1390_of_match[] = {
+static const struct of_device_id ds1390_of_match[] __maybe_unused = {
{ .compatible = "dallas,ds1390" },
{}
};
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 1109cad83838..8b087d9556be 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -22,26 +22,24 @@
#include <linux/io.h>
#include <linux/module.h>
-enum ds1511reg {
- DS1511_SEC = 0x0,
- DS1511_MIN = 0x1,
- DS1511_HOUR = 0x2,
- DS1511_DOW = 0x3,
- DS1511_DOM = 0x4,
- DS1511_MONTH = 0x5,
- DS1511_YEAR = 0x6,
- DS1511_CENTURY = 0x7,
- DS1511_AM1_SEC = 0x8,
- DS1511_AM2_MIN = 0x9,
- DS1511_AM3_HOUR = 0xa,
- DS1511_AM4_DATE = 0xb,
- DS1511_WD_MSEC = 0xc,
- DS1511_WD_SEC = 0xd,
- DS1511_CONTROL_A = 0xe,
- DS1511_CONTROL_B = 0xf,
- DS1511_RAMADDR_LSB = 0x10,
- DS1511_RAMDATA = 0x13
-};
+#define DS1511_SEC 0x0
+#define DS1511_MIN 0x1
+#define DS1511_HOUR 0x2
+#define DS1511_DOW 0x3
+#define DS1511_DOM 0x4
+#define DS1511_MONTH 0x5
+#define DS1511_YEAR 0x6
+#define DS1511_CENTURY 0x7
+#define DS1511_AM1_SEC 0x8
+#define DS1511_AM2_MIN 0x9
+#define DS1511_AM3_HOUR 0xa
+#define DS1511_AM4_DATE 0xb
+#define DS1511_WD_MSEC 0xc
+#define DS1511_WD_SEC 0xd
+#define DS1511_CONTROL_A 0xe
+#define DS1511_CONTROL_B 0xf
+#define DS1511_RAMADDR_LSB 0x10
+#define DS1511_RAMDATA 0x13
#define DS1511_BLF1 0x80
#define DS1511_BLF2 0x40
@@ -61,35 +59,10 @@ enum ds1511reg {
#define DS1511_WDS 0x01
#define DS1511_RAM_MAX 0x100
-#define RTC_CMD DS1511_CONTROL_B
-#define RTC_CMD1 DS1511_CONTROL_A
-
-#define RTC_ALARM_SEC DS1511_AM1_SEC
-#define RTC_ALARM_MIN DS1511_AM2_MIN
-#define RTC_ALARM_HOUR DS1511_AM3_HOUR
-#define RTC_ALARM_DATE DS1511_AM4_DATE
-
-#define RTC_SEC DS1511_SEC
-#define RTC_MIN DS1511_MIN
-#define RTC_HOUR DS1511_HOUR
-#define RTC_DOW DS1511_DOW
-#define RTC_DOM DS1511_DOM
-#define RTC_MON DS1511_MONTH
-#define RTC_YEAR DS1511_YEAR
-#define RTC_CENTURY DS1511_CENTURY
-
-#define RTC_TIE DS1511_TIE
-#define RTC_TE DS1511_TE
-
-struct rtc_plat_data {
+struct ds1511_data {
struct rtc_device *rtc;
void __iomem *ioaddr; /* virtual base address */
int irq;
- unsigned int irqen;
- int alrm_sec;
- int alrm_min;
- int alrm_hour;
- int alrm_mday;
spinlock_t lock;
};
@@ -98,95 +71,33 @@ static DEFINE_SPINLOCK(ds1511_lock);
static __iomem char *ds1511_base;
static u32 reg_spacing = 1;
-static noinline void
-rtc_write(uint8_t val, uint32_t reg)
+static void rtc_write(uint8_t val, uint32_t reg)
{
writeb(val, ds1511_base + (reg * reg_spacing));
}
-static noinline uint8_t
-rtc_read(enum ds1511reg reg)
+static uint8_t rtc_read(uint32_t reg)
{
return readb(ds1511_base + (reg * reg_spacing));
}
-static inline void
-rtc_disable_update(void)
+static void rtc_disable_update(void)
{
- rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
+ rtc_write((rtc_read(DS1511_CONTROL_B) & ~DS1511_TE), DS1511_CONTROL_B);
}
-static void
-rtc_enable_update(void)
+static void rtc_enable_update(void)
{
- rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
-}
-
-/*
- * #define DS1511_WDOG_RESET_SUPPORT
- *
- * Uncomment this if you want to use these routines in
- * some platform code.
- */
-#ifdef DS1511_WDOG_RESET_SUPPORT
-/*
- * just enough code to set the watchdog timer so that it
- * will reboot the system
- */
-void
-ds1511_wdog_set(unsigned long deciseconds)
-{
- /*
- * the wdog timer can take 99.99 seconds
- */
- deciseconds %= 10000;
- /*
- * set the wdog values in the wdog registers
- */
- rtc_write(bin2bcd(deciseconds % 100), DS1511_WD_MSEC);
- rtc_write(bin2bcd(deciseconds / 100), DS1511_WD_SEC);
- /*
- * set wdog enable and wdog 'steering' bit to issue a reset
- */
- rtc_write(rtc_read(RTC_CMD) | DS1511_WDE | DS1511_WDS, RTC_CMD);
-}
-
-void
-ds1511_wdog_disable(void)
-{
- /*
- * clear wdog enable and wdog 'steering' bits
- */
- rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
- /*
- * clear the wdog counter
- */
- rtc_write(0, DS1511_WD_MSEC);
- rtc_write(0, DS1511_WD_SEC);
+ rtc_write((rtc_read(DS1511_CONTROL_B) | DS1511_TE), DS1511_CONTROL_B);
}
-#endif
-/*
- * set the rtc chip's idea of the time.
- * stupidly, some callers call with year unmolested;
- * and some call with year = year - 1900. thanks.
- */
static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
{
u8 mon, day, dow, hrs, min, sec, yrs, cen;
unsigned long flags;
- /*
- * won't have to change this for a while
- */
- if (rtc_tm->tm_year < 1900)
- rtc_tm->tm_year += 1900;
-
- if (rtc_tm->tm_year < 1970)
- return -EINVAL;
-
yrs = rtc_tm->tm_year % 100;
- cen = rtc_tm->tm_year / 100;
+ cen = 19 + rtc_tm->tm_year / 100;
mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */
day = rtc_tm->tm_mday;
dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */
@@ -194,15 +105,6 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
min = rtc_tm->tm_min;
sec = rtc_tm->tm_sec;
- if ((mon > 12) || (day == 0))
- return -EINVAL;
-
- if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year))
- return -EINVAL;
-
- if ((hrs >= 24) || (min >= 60) || (sec >= 60))
- return -EINVAL;
-
/*
* each register is a different number of valid bits
*/
@@ -216,14 +118,14 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
spin_lock_irqsave(&ds1511_lock, flags);
rtc_disable_update();
- rtc_write(cen, RTC_CENTURY);
- rtc_write(yrs, RTC_YEAR);
- rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON);
- rtc_write(day, RTC_DOM);
- rtc_write(hrs, RTC_HOUR);
- rtc_write(min, RTC_MIN);
- rtc_write(sec, RTC_SEC);
- rtc_write(dow, RTC_DOW);
+ rtc_write(cen, DS1511_CENTURY);
+ rtc_write(yrs, DS1511_YEAR);
+ rtc_write((rtc_read(DS1511_MONTH) & 0xe0) | mon, DS1511_MONTH);
+ rtc_write(day, DS1511_DOM);
+ rtc_write(hrs, DS1511_HOUR);
+ rtc_write(min, DS1511_MIN);
+ rtc_write(sec, DS1511_SEC);
+ rtc_write(dow, DS1511_DOW);
rtc_enable_update();
spin_unlock_irqrestore(&ds1511_lock, flags);
@@ -238,14 +140,14 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
spin_lock_irqsave(&ds1511_lock, flags);
rtc_disable_update();
- rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
- rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
- rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
- rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
- rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
- rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
- rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
- century = rtc_read(RTC_CENTURY);
+ rtc_tm->tm_sec = rtc_read(DS1511_SEC) & 0x7f;
+ rtc_tm->tm_min = rtc_read(DS1511_MIN) & 0x7f;
+ rtc_tm->tm_hour = rtc_read(DS1511_HOUR) & 0x3f;
+ rtc_tm->tm_mday = rtc_read(DS1511_DOM) & 0x3f;
+ rtc_tm->tm_wday = rtc_read(DS1511_DOW) & 0x7;
+ rtc_tm->tm_mon = rtc_read(DS1511_MONTH) & 0x1f;
+ rtc_tm->tm_year = rtc_read(DS1511_YEAR) & 0x7f;
+ century = rtc_read(DS1511_CENTURY);
rtc_enable_update();
spin_unlock_irqrestore(&ds1511_lock, flags);
@@ -271,106 +173,67 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
return 0;
}
-/*
- * write the alarm register settings
- *
- * we only have the use to interrupt every second, otherwise
- * known as the update interrupt, or the interrupt if the whole
- * date/hours/mins/secs matches. the ds1511 has many more
- * permutations, but the kernel doesn't.
- */
-static void
-ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
+static void ds1511_rtc_alarm_enable(unsigned int enabled)
{
- unsigned long flags;
-
- spin_lock_irqsave(&pdata->lock, flags);
- rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f,
- RTC_ALARM_DATE);
- rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : bin2bcd(pdata->alrm_hour) & 0x3f,
- RTC_ALARM_HOUR);
- rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : bin2bcd(pdata->alrm_min) & 0x7f,
- RTC_ALARM_MIN);
- rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
- 0x80 : bin2bcd(pdata->alrm_sec) & 0x7f,
- RTC_ALARM_SEC);
- rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
- rtc_read(RTC_CMD1); /* clear interrupts */
- spin_unlock_irqrestore(&pdata->lock, flags);
+ rtc_write(rtc_read(DS1511_CONTROL_B) | (enabled ? DS1511_TIE : 0), DS1511_CONTROL_B);
}
-static int
-ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+static int ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
- struct rtc_plat_data *pdata = dev_get_drvdata(dev);
+ struct ds1511_data *ds1511 = dev_get_drvdata(dev);
+ unsigned long flags;
- if (pdata->irq <= 0)
- return -EINVAL;
+ spin_lock_irqsave(&ds1511->lock, flags);
+ rtc_write(bin2bcd(alrm->time.tm_mday) & 0x3f, DS1511_AM4_DATE);
+ rtc_write(bin2bcd(alrm->time.tm_hour) & 0x3f, DS1511_AM3_HOUR);
+ rtc_write(bin2bcd(alrm->time.tm_min) & 0x7f, DS1511_AM2_MIN);
+ rtc_write(bin2bcd(alrm->time.tm_sec) & 0x7f, DS1511_AM1_SEC);
+ ds1511_rtc_alarm_enable(alrm->enabled);
- pdata->alrm_mday = alrm->time.tm_mday;
- pdata->alrm_hour = alrm->time.tm_hour;
- pdata->alrm_min = alrm->time.tm_min;
- pdata->alrm_sec = alrm->time.tm_sec;
- if (alrm->enabled)
- pdata->irqen |= RTC_AF;
+ rtc_read(DS1511_CONTROL_A); /* clear interrupts */
+ spin_unlock_irqrestore(&ds1511->lock, flags);
- ds1511_rtc_update_alarm(pdata);
return 0;
}
-static int
-ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+static int ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
- struct rtc_plat_data *pdata = dev_get_drvdata(dev);
-
- if (pdata->irq <= 0)
- return -EINVAL;
+ alrm->time.tm_mday = bcd2bin(rtc_read(DS1511_AM4_DATE) & 0x3f);
+ alrm->time.tm_hour = bcd2bin(rtc_read(DS1511_AM3_HOUR) & 0x3f);
+ alrm->time.tm_min = bcd2bin(rtc_read(DS1511_AM2_MIN) & 0x7f);
+ alrm->time.tm_sec = bcd2bin(rtc_read(DS1511_AM1_SEC) & 0x7f);
+ alrm->enabled = !!(rtc_read(DS1511_CONTROL_B) & DS1511_TIE);
- alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
- alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
- alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
- alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
- alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
return 0;
}
-static irqreturn_t
-ds1511_interrupt(int irq, void *dev_id)
+static irqreturn_t ds1511_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
- struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ struct ds1511_data *ds1511 = platform_get_drvdata(pdev);
unsigned long events = 0;
- spin_lock(&pdata->lock);
+ spin_lock(&ds1511->lock);
/*
* read and clear interrupt
*/
- if (rtc_read(RTC_CMD1) & DS1511_IRQF) {
- events = RTC_IRQF;
- if (rtc_read(RTC_ALARM_SEC) & 0x80)
- events |= RTC_UF;
- else
- events |= RTC_AF;
- rtc_update_irq(pdata->rtc, 1, events);
+ if (rtc_read(DS1511_CONTROL_A) & DS1511_IRQF) {
+ events = RTC_IRQF | RTC_AF;
+ rtc_update_irq(ds1511->rtc, 1, events);
}
- spin_unlock(&pdata->lock);
+ spin_unlock(&ds1511->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
}
static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
- struct rtc_plat_data *pdata = dev_get_drvdata(dev);
-
- if (pdata->irq <= 0)
- return -EINVAL;
- if (enabled)
- pdata->irqen |= RTC_AF;
- else
- pdata->irqen &= ~RTC_AF;
- ds1511_rtc_update_alarm(pdata);
+ struct ds1511_data *ds1511 = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ds1511->lock, flags);
+ ds1511_rtc_alarm_enable(enabled);
+ spin_unlock_irqrestore(&ds1511->lock, flags);
+
return 0;
}
@@ -408,7 +271,7 @@ static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf,
static int ds1511_rtc_probe(struct platform_device *pdev)
{
- struct rtc_plat_data *pdata;
+ struct ds1511_data *ds1511;
int ret = 0;
struct nvmem_config ds1511_nvmem_cfg = {
.name = "ds1511_nvram",
@@ -420,21 +283,21 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
.priv = &pdev->dev,
};
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
+ ds1511 = devm_kzalloc(&pdev->dev, sizeof(*ds1511), GFP_KERNEL);
+ if (!ds1511)
return -ENOMEM;
ds1511_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ds1511_base))
return PTR_ERR(ds1511_base);
- pdata->ioaddr = ds1511_base;
- pdata->irq = platform_get_irq(pdev, 0);
+ ds1511->ioaddr = ds1511_base;
+ ds1511->irq = platform_get_irq(pdev, 0);
/*
* turn on the clock and the crystal, etc.
*/
- rtc_write(DS1511_BME, RTC_CMD);
- rtc_write(0, RTC_CMD1);
+ rtc_write(DS1511_BME, DS1511_CONTROL_B);
+ rtc_write(0, DS1511_CONTROL_A);
/*
* clear the wdog counter
*/
@@ -448,38 +311,43 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
/*
* check for a dying bat-tree
*/
- if (rtc_read(RTC_CMD1) & DS1511_BLF1)
+ if (rtc_read(DS1511_CONTROL_A) & DS1511_BLF1)
dev_warn(&pdev->dev, "voltage-low detected.\n");
- spin_lock_init(&pdata->lock);
- platform_set_drvdata(pdev, pdata);
-
- pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(pdata->rtc))
- return PTR_ERR(pdata->rtc);
-
- pdata->rtc->ops = &ds1511_rtc_ops;
+ spin_lock_init(&ds1511->lock);
+ platform_set_drvdata(pdev, ds1511);
- ret = devm_rtc_register_device(pdata->rtc);
- if (ret)
- return ret;
+ ds1511->rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(ds1511->rtc))
+ return PTR_ERR(ds1511->rtc);
- devm_rtc_nvmem_register(pdata->rtc, &ds1511_nvmem_cfg);
+ ds1511->rtc->ops = &ds1511_rtc_ops;
+ ds1511->rtc->range_max = RTC_TIMESTAMP_END_2099;
+ ds1511->rtc->alarm_offset_max = 28 * 24 * 60 * 60 - 1;
/*
* if the platform has an interrupt in mind for this device,
* then by all means, set it
*/
- if (pdata->irq > 0) {
- rtc_read(RTC_CMD1);
- if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
+ if (ds1511->irq > 0) {
+ rtc_read(DS1511_CONTROL_A);
+ if (devm_request_irq(&pdev->dev, ds1511->irq, ds1511_interrupt,
IRQF_SHARED, pdev->name, pdev) < 0) {
dev_warn(&pdev->dev, "interrupt not available.\n");
- pdata->irq = 0;
+ ds1511->irq = 0;
}
}
+ if (ds1511->irq == 0)
+ clear_bit(RTC_FEATURE_ALARM, ds1511->rtc->features);
+
+ ret = devm_rtc_register_device(ds1511->rtc);
+ if (ret)
+ return ret;
+
+ devm_rtc_nvmem_register(ds1511->rtc, &ds1511_nvmem_cfg);
+
return 0;
}
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index a3bb2cd9c881..6e5314215d00 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -133,7 +133,7 @@ static int ds1672_probe(struct i2c_client *client)
}
static const struct i2c_device_id ds1672_id[] = {
- { "ds1672", 0 },
+ { "ds1672" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1672_id);
@@ -149,7 +149,7 @@ static struct i2c_driver ds1672_driver = {
.name = "rtc-ds1672",
.of_match_table = of_match_ptr(ds1672_of_match),
},
- .probe_new = ds1672_probe,
+ .probe = ds1672_probe,
.id_table = ds1672_id,
};
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 5db9c737c022..97423f1d0361 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -3,7 +3,7 @@
* An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time
* chips.
*
- * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>.
+ * Copyright (C) 2011-2014 Joshua Kinard <linux@kumba.dev>.
* Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>.
*
* References:
@@ -1322,7 +1322,7 @@ ds1685_rtc_probe(struct platform_device *pdev)
* ds1685_rtc_remove - removes rtc driver.
* @pdev: pointer to platform_device structure.
*/
-static int
+static void
ds1685_rtc_remove(struct platform_device *pdev)
{
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
@@ -1344,8 +1344,6 @@ ds1685_rtc_remove(struct platform_device *pdev)
rtc->write(rtc, RTC_EXT_CTRL_4A,
(rtc->read(rtc, RTC_EXT_CTRL_4A) &
~(RTC_CTRL_4A_RWK_MASK)));
-
- return 0;
}
/*
@@ -1434,11 +1432,11 @@ ds1685_rtc_poweroff(struct platform_device *pdev)
unreachable();
}
}
-EXPORT_SYMBOL(ds1685_rtc_poweroff);
+EXPORT_SYMBOL_GPL(ds1685_rtc_poweroff);
/* ----------------------------------------------------------------------- */
-MODULE_AUTHOR("Joshua Kinard <kumba@gentoo.org>");
+MODULE_AUTHOR("Joshua Kinard <linux@kumba.dev>");
MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd-electronics.com>");
MODULE_DESCRIPTION("Dallas/Maxim DS1685/DS1687-series RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index a5026b0514e7..6ae8b9a294fe 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -16,7 +16,6 @@
#include <linux/jiffies.h>
#include <linux/rtc.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/module.h>
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
index 0480f592307e..217694eca36c 100644
--- a/drivers/rtc/rtc-ds2404.c
+++ b/drivers/rtc/rtc-ds2404.c
@@ -7,9 +7,8 @@
#include <linux/rtc.h>
#include <linux/types.h>
#include <linux/bcd.h>
-#include <linux/platform_data/rtc-ds2404.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/io.h>
@@ -27,164 +26,139 @@
#define DS2404_CLK 1
#define DS2404_DQ 2
-struct ds2404_gpio {
- const char *name;
- unsigned int gpio;
-};
-
struct ds2404 {
- struct ds2404_gpio *gpio;
- struct rtc_device *rtc;
-};
-
-static struct ds2404_gpio ds2404_gpio[] = {
- { "RTC RST", 0 },
- { "RTC CLK", 0 },
- { "RTC DQ", 0 },
+ struct device *dev;
+ struct gpio_desc *rst_gpiod;
+ struct gpio_desc *clk_gpiod;
+ struct gpio_desc *dq_gpiod;
};
-static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
- struct ds2404_platform_data *pdata)
+static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev)
{
- int i, err;
-
- ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst;
- ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk;
- ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq;
-
- for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
- err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
- if (err) {
- dev_err(&pdev->dev, "error mapping gpio %s: %d\n",
- ds2404_gpio[i].name, err);
- goto err_request;
- }
- if (i != DS2404_DQ)
- gpio_direction_output(ds2404_gpio[i].gpio, 1);
- }
+ struct device *dev = &pdev->dev;
- chip->gpio = ds2404_gpio;
- return 0;
+ /* This will de-assert RESET, declare this GPIO as GPIOD_ACTIVE_LOW */
+ chip->rst_gpiod = devm_gpiod_get(dev, "rst", GPIOD_OUT_LOW);
+ if (IS_ERR(chip->rst_gpiod))
+ return PTR_ERR(chip->rst_gpiod);
-err_request:
- while (--i >= 0)
- gpio_free(ds2404_gpio[i].gpio);
- return err;
-}
+ chip->clk_gpiod = devm_gpiod_get(dev, "clk", GPIOD_OUT_HIGH);
+ if (IS_ERR(chip->clk_gpiod))
+ return PTR_ERR(chip->clk_gpiod);
-static void ds2404_gpio_unmap(void *data)
-{
- int i;
+ chip->dq_gpiod = devm_gpiod_get(dev, "dq", GPIOD_ASIS);
+ if (IS_ERR(chip->dq_gpiod))
+ return PTR_ERR(chip->dq_gpiod);
- for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++)
- gpio_free(ds2404_gpio[i].gpio);
+ return 0;
}
-static void ds2404_reset(struct device *dev)
+static void ds2404_reset(struct ds2404 *chip)
{
- gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0);
+ gpiod_set_value(chip->rst_gpiod, 1);
udelay(1000);
- gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1);
- gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
- gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0);
+ gpiod_set_value(chip->rst_gpiod, 0);
+ gpiod_set_value(chip->clk_gpiod, 0);
+ gpiod_direction_output(chip->dq_gpiod, 0);
udelay(10);
}
-static void ds2404_write_byte(struct device *dev, u8 byte)
+static void ds2404_write_byte(struct ds2404 *chip, u8 byte)
{
int i;
- gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1);
+ gpiod_direction_output(chip->dq_gpiod, 1);
for (i = 0; i < 8; i++) {
- gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i));
+ gpiod_set_value(chip->dq_gpiod, byte & (1 << i));
udelay(10);
- gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
+ gpiod_set_value(chip->clk_gpiod, 1);
udelay(10);
- gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
+ gpiod_set_value(chip->clk_gpiod, 0);
udelay(10);
}
}
-static u8 ds2404_read_byte(struct device *dev)
+static u8 ds2404_read_byte(struct ds2404 *chip)
{
int i;
u8 ret = 0;
- gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
+ gpiod_direction_input(chip->dq_gpiod);
for (i = 0; i < 8; i++) {
- gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
+ gpiod_set_value(chip->clk_gpiod, 0);
udelay(10);
- if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
+ if (gpiod_get_value(chip->dq_gpiod))
ret |= 1 << i;
- gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
+ gpiod_set_value(chip->clk_gpiod, 1);
udelay(10);
}
return ret;
}
-static void ds2404_read_memory(struct device *dev, u16 offset,
+static void ds2404_read_memory(struct ds2404 *chip, u16 offset,
int length, u8 *out)
{
- ds2404_reset(dev);
- ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD);
- ds2404_write_byte(dev, offset & 0xff);
- ds2404_write_byte(dev, (offset >> 8) & 0xff);
+ ds2404_reset(chip);
+ ds2404_write_byte(chip, DS2404_READ_MEMORY_CMD);
+ ds2404_write_byte(chip, offset & 0xff);
+ ds2404_write_byte(chip, (offset >> 8) & 0xff);
while (length--)
- *out++ = ds2404_read_byte(dev);
+ *out++ = ds2404_read_byte(chip);
}
-static void ds2404_write_memory(struct device *dev, u16 offset,
+static void ds2404_write_memory(struct ds2404 *chip, u16 offset,
int length, u8 *out)
{
int i;
u8 ta01, ta02, es;
- ds2404_reset(dev);
- ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD);
- ds2404_write_byte(dev, offset & 0xff);
- ds2404_write_byte(dev, (offset >> 8) & 0xff);
+ ds2404_reset(chip);
+ ds2404_write_byte(chip, DS2404_WRITE_SCRATCHPAD_CMD);
+ ds2404_write_byte(chip, offset & 0xff);
+ ds2404_write_byte(chip, (offset >> 8) & 0xff);
for (i = 0; i < length; i++)
- ds2404_write_byte(dev, out[i]);
+ ds2404_write_byte(chip, out[i]);
- ds2404_reset(dev);
- ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD);
+ ds2404_reset(chip);
+ ds2404_write_byte(chip, DS2404_READ_SCRATCHPAD_CMD);
- ta01 = ds2404_read_byte(dev);
- ta02 = ds2404_read_byte(dev);
- es = ds2404_read_byte(dev);
+ ta01 = ds2404_read_byte(chip);
+ ta02 = ds2404_read_byte(chip);
+ es = ds2404_read_byte(chip);
for (i = 0; i < length; i++) {
- if (out[i] != ds2404_read_byte(dev)) {
- dev_err(dev, "read invalid data\n");
+ if (out[i] != ds2404_read_byte(chip)) {
+ dev_err(chip->dev, "read invalid data\n");
return;
}
}
- ds2404_reset(dev);
- ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD);
- ds2404_write_byte(dev, ta01);
- ds2404_write_byte(dev, ta02);
- ds2404_write_byte(dev, es);
+ ds2404_reset(chip);
+ ds2404_write_byte(chip, DS2404_COPY_SCRATCHPAD_CMD);
+ ds2404_write_byte(chip, ta01);
+ ds2404_write_byte(chip, ta02);
+ ds2404_write_byte(chip, es);
- gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
- while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
+ while (gpiod_get_value(chip->dq_gpiod))
;
}
-static void ds2404_enable_osc(struct device *dev)
+static void ds2404_enable_osc(struct ds2404 *chip)
{
u8 in[1] = { 0x10 }; /* enable oscillator */
- ds2404_write_memory(dev, 0x201, 1, in);
+
+ ds2404_write_memory(chip, 0x201, 1, in);
}
static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
{
+ struct ds2404 *chip = dev_get_drvdata(dev);
unsigned long time = 0;
__le32 hw_time = 0;
- ds2404_read_memory(dev, 0x203, 4, (u8 *)&hw_time);
+ ds2404_read_memory(chip, 0x203, 4, (u8 *)&hw_time);
time = le32_to_cpu(hw_time);
rtc_time64_to_tm(time, dt);
@@ -193,8 +167,9 @@ static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
static int ds2404_set_time(struct device *dev, struct rtc_time *dt)
{
+ struct ds2404 *chip = dev_get_drvdata(dev);
u32 time = cpu_to_le32(rtc_tm_to_time64(dt));
- ds2404_write_memory(dev, 0x203, 4, (u8 *)&time);
+ ds2404_write_memory(chip, 0x203, 4, (u8 *)&time);
return 0;
}
@@ -205,40 +180,34 @@ static const struct rtc_class_ops ds2404_rtc_ops = {
static int rtc_probe(struct platform_device *pdev)
{
- struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct ds2404 *chip;
+ struct rtc_device *rtc;
int retval = -EBUSY;
chip = devm_kzalloc(&pdev->dev, sizeof(struct ds2404), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- chip->rtc = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(chip->rtc))
- return PTR_ERR(chip->rtc);
+ chip->dev = &pdev->dev;
- retval = ds2404_gpio_map(chip, pdev, pdata);
- if (retval)
- return retval;
+ rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- retval = devm_add_action_or_reset(&pdev->dev, ds2404_gpio_unmap, chip);
+ retval = ds2404_gpio_map(chip, pdev);
if (retval)
return retval;
- dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n",
- chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio,
- chip->gpio[DS2404_DQ].gpio);
-
platform_set_drvdata(pdev, chip);
- chip->rtc->ops = &ds2404_rtc_ops;
- chip->rtc->range_max = U32_MAX;
+ rtc->ops = &ds2404_rtc_ops;
+ rtc->range_max = U32_MAX;
- retval = devm_rtc_register_device(chip->rtc);
+ retval = devm_rtc_register_device(rtc);
if (retval)
return retval;
- ds2404_enable_osc(&pdev->dev);
+ ds2404_enable_osc(chip);
return 0;
}
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index dd31a60c1fc6..18f35823b4b5 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -339,29 +339,9 @@ static int ds3232_hwmon_read(struct device *dev,
return err;
}
-static u32 ds3232_hwmon_chip_config[] = {
- HWMON_C_REGISTER_TZ,
- 0
-};
-
-static const struct hwmon_channel_info ds3232_hwmon_chip = {
- .type = hwmon_chip,
- .config = ds3232_hwmon_chip_config,
-};
-
-static u32 ds3232_hwmon_temp_config[] = {
- HWMON_T_INPUT,
- 0
-};
-
-static const struct hwmon_channel_info ds3232_hwmon_temp = {
- .type = hwmon_temp,
- .config = ds3232_hwmon_temp_config,
-};
-
-static const struct hwmon_channel_info *ds3232_hwmon_info[] = {
- &ds3232_hwmon_chip,
- &ds3232_hwmon_temp,
+static const struct hwmon_channel_info * const ds3232_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
NULL
};
@@ -508,7 +488,7 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
return ret;
if (ds3232->irq > 0)
- device_init_wakeup(dev, 1);
+ device_init_wakeup(dev, true);
ds3232_hwmon_register(dev, name);
@@ -536,6 +516,8 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
return 0;
}
+#if IS_ENABLED(CONFIG_I2C)
+
#ifdef CONFIG_PM_SLEEP
static int ds3232_suspend(struct device *dev)
{
@@ -564,8 +546,6 @@ static const struct dev_pm_ops ds3232_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
};
-#if IS_ENABLED(CONFIG_I2C)
-
static int ds3232_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
@@ -586,7 +566,7 @@ static int ds3232_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ds3232_id[] = {
- { "ds3232", 0 },
+ { "ds3232" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds3232_id);
@@ -603,7 +583,7 @@ static struct i2c_driver ds3232_driver = {
.of_match_table = of_match_ptr(ds3232_of_match),
.pm = &ds3232_pm_ops,
},
- .probe_new = ds3232_i2c_probe,
+ .probe = ds3232_i2c_probe,
.id_table = ds3232_id,
};
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index e991cccdb6e9..b4f44999ef0f 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -112,48 +112,6 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
return true;
}
-static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
-{
- efi_time_t eft;
- efi_status_t status;
-
- /*
- * As of EFI v1.10, this call always returns an unsupported status
- */
- status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled,
- (efi_bool_t *)&wkalrm->pending, &eft);
-
- if (status != EFI_SUCCESS)
- return -EINVAL;
-
- if (!convert_from_efi_time(&eft, &wkalrm->time))
- return -EIO;
-
- return rtc_valid_tm(&wkalrm->time);
-}
-
-static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
-{
- efi_time_t eft;
- efi_status_t status;
-
- convert_to_efi_time(&wkalrm->time, &eft);
-
- /*
- * XXX Fixme:
- * As of EFI 0.92 with the firmware I have on my
- * machine this call does not seem to work quite
- * right
- *
- * As of v1.10, this call always returns an unsupported status
- */
- status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
-
- dev_warn(dev, "write status is %d\n", (int)status);
-
- return status == EFI_SUCCESS ? 0 : -EINVAL;
-}
-
static int efi_read_time(struct device *dev, struct rtc_time *tm)
{
efi_status_t status;
@@ -164,7 +122,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
if (status != EFI_SUCCESS) {
/* should never happen */
- dev_err(dev, "can't read time\n");
+ dev_err_once(dev, "can't read time\n");
return -EINVAL;
}
@@ -188,16 +146,13 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm)
static int efi_procfs(struct device *dev, struct seq_file *seq)
{
- efi_time_t eft, alm;
- efi_time_cap_t cap;
- efi_bool_t enabled, pending;
+ efi_time_t eft;
+ efi_time_cap_t cap;
memset(&eft, 0, sizeof(eft));
- memset(&alm, 0, sizeof(alm));
memset(&cap, 0, sizeof(cap));
efi.get_time(&eft, &cap);
- efi.get_wakeup_time(&enabled, &pending, &alm);
seq_printf(seq,
"Time\t\t: %u:%u:%u.%09u\n"
@@ -213,24 +168,6 @@ static int efi_procfs(struct device *dev, struct seq_file *seq)
/* XXX fixme: convert to string? */
seq_printf(seq, "Timezone\t: %u\n", eft.timezone);
- seq_printf(seq,
- "Alarm Time\t: %u:%u:%u.%09u\n"
- "Alarm Date\t: %u-%u-%u\n"
- "Alarm Daylight\t: %u\n"
- "Enabled\t\t: %s\n"
- "Pending\t\t: %s\n",
- alm.hour, alm.minute, alm.second, alm.nanosecond,
- alm.year, alm.month, alm.day,
- alm.daylight,
- enabled == 1 ? "yes" : "no",
- pending == 1 ? "yes" : "no");
-
- if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
- seq_puts(seq, "Timezone\t: unspecified\n");
- else
- /* XXX fixme: convert to string? */
- seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
-
/*
* now prints the capabilities
*/
@@ -246,8 +183,6 @@ static int efi_procfs(struct device *dev, struct seq_file *seq)
static const struct rtc_class_ops efi_rtc_ops = {
.read_time = efi_read_time,
.set_time = efi_set_time,
- .read_alarm = efi_read_alarm,
- .set_alarm = efi_set_alarm,
.proc = efi_procfs,
};
@@ -268,8 +203,7 @@ static int __init efi_rtc_probe(struct platform_device *dev)
platform_set_drvdata(dev, rtc);
rtc->ops = &efi_rtc_ops;
- clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
- set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features);
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
device_init_wakeup(&dev->dev, true);
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
index 53f9f9391a5f..dc1ccbc65dcb 100644
--- a/drivers/rtc/rtc-em3027.c
+++ b/drivers/rtc/rtc-em3027.c
@@ -129,7 +129,7 @@ static int em3027_probe(struct i2c_client *client)
}
static const struct i2c_device_id em3027_id[] = {
- { "em3027", 0 },
+ { "em3027" },
{ }
};
MODULE_DEVICE_TABLE(i2c, em3027_id);
@@ -147,7 +147,7 @@ static struct i2c_driver em3027_driver = {
.name = "rtc-em3027",
.of_match_table = of_match_ptr(em3027_of_match),
},
- .probe_new = em3027_probe,
+ .probe = em3027_probe,
.id_table = em3027_id,
};
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index acae7f16808f..dcdcdd06f30d 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -7,6 +7,7 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -27,7 +28,6 @@
struct ep93xx_rtc {
void __iomem *mmio_base;
- struct rtc_device *rtc;
};
static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
@@ -122,6 +122,7 @@ static const struct attribute_group ep93xx_rtc_sysfs_files = {
static int ep93xx_rtc_probe(struct platform_device *pdev)
{
struct ep93xx_rtc *ep93xx_rtc;
+ struct rtc_device *rtc;
int err;
ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
@@ -134,23 +135,30 @@ static int ep93xx_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ep93xx_rtc);
- ep93xx_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(ep93xx_rtc->rtc))
- return PTR_ERR(ep93xx_rtc->rtc);
+ rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- ep93xx_rtc->rtc->ops = &ep93xx_rtc_ops;
- ep93xx_rtc->rtc->range_max = U32_MAX;
+ rtc->ops = &ep93xx_rtc_ops;
+ rtc->range_max = U32_MAX;
- err = rtc_add_group(ep93xx_rtc->rtc, &ep93xx_rtc_sysfs_files);
+ err = rtc_add_group(rtc, &ep93xx_rtc_sysfs_files);
if (err)
return err;
- return devm_rtc_register_device(ep93xx_rtc->rtc);
+ return devm_rtc_register_device(rtc);
}
+static const struct of_device_id ep93xx_rtc_of_ids[] = {
+ { .compatible = "cirrus,ep9301-rtc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ep93xx_rtc_of_ids);
+
static struct platform_driver ep93xx_rtc_driver = {
.driver = {
.name = "ep93xx-rtc",
+ .of_match_table = ep93xx_rtc_of_ids,
},
.probe = ep93xx_rtc_probe,
};
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index f59bb81f23c0..f82728ebac0c 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -53,7 +53,7 @@ struct fm3130 {
int data_valid;
};
static const struct i2c_device_id fm3130_id[] = {
- { "fm3130", 0 },
+ { "fm3130" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fm3130_id);
@@ -517,7 +517,7 @@ static struct i2c_driver fm3130_driver = {
.driver = {
.name = "rtc-fm3130",
},
- .probe_new = fm3130_probe,
+ .probe = fm3130_probe,
.id_table = fm3130_id,
};
diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c
index 3d7c4077fe1c..c8015f04c71f 100644
--- a/drivers/rtc/rtc-fsl-ftm-alarm.c
+++ b/drivers/rtc/rtc-fsl-ftm-alarm.c
@@ -11,11 +11,8 @@
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/fsl/ftm.h>
#include <linux/rtc.h>
@@ -312,7 +309,7 @@ static const struct of_device_id ftm_rtc_match[] = {
};
MODULE_DEVICE_TABLE(of, ftm_rtc_match);
-static const struct acpi_device_id ftm_imx_acpi_ids[] = {
+static const struct acpi_device_id ftm_imx_acpi_ids[] __maybe_unused = {
{"NXP0014",},
{ }
};
diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c
index 25c6e7d9570f..02608d378495 100644
--- a/drivers/rtc/rtc-ftrtc010.c
+++ b/drivers/rtc/rtc-ftrtc010.c
@@ -28,7 +28,6 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);
struct ftrtc010_rtc {
- struct rtc_device *rtc_dev;
void __iomem *rtc_base;
int rtc_irq;
struct clk *pclk;
@@ -113,6 +112,7 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
struct ftrtc010_rtc *rtc;
struct device *dev = &pdev->dev;
struct resource *res;
+ struct rtc_device *rtc_dev;
int ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
@@ -160,29 +160,28 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
goto err_disable_extclk;
}
- rtc->rtc_dev = devm_rtc_allocate_device(dev);
- if (IS_ERR(rtc->rtc_dev)) {
- ret = PTR_ERR(rtc->rtc_dev);
+ rtc_dev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc_dev)) {
+ ret = PTR_ERR(rtc_dev);
goto err_disable_extclk;
}
- rtc->rtc_dev->ops = &ftrtc010_rtc_ops;
+ rtc_dev->ops = &ftrtc010_rtc_ops;
sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
- rtc->rtc_dev->range_min = (u64)days * 86400 + hour * 3600 +
- min * 60 + sec;
- rtc->rtc_dev->range_max = U32_MAX + rtc->rtc_dev->range_min;
+ rtc_dev->range_min = (u64)days * 86400 + hour * 3600 + min * 60 + sec;
+ rtc_dev->range_max = U32_MAX + rtc_dev->range_min;
ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
IRQF_SHARED, pdev->name, dev);
if (unlikely(ret))
goto err_disable_extclk;
- return devm_rtc_register_device(rtc->rtc_dev);
+ return devm_rtc_register_device(rtc_dev);
err_disable_extclk:
clk_disable_unprepare(rtc->extclk);
@@ -191,7 +190,7 @@ err_disable_pclk:
return ret;
}
-static int ftrtc010_rtc_remove(struct platform_device *pdev)
+static void ftrtc010_rtc_remove(struct platform_device *pdev)
{
struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev);
@@ -199,8 +198,6 @@ static int ftrtc010_rtc_remove(struct platform_device *pdev)
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[] = {
diff --git a/drivers/rtc/rtc-goldfish.c b/drivers/rtc/rtc-goldfish.c
index 59c0f38cc08d..53ec7173c28e 100644
--- a/drivers/rtc/rtc-goldfish.c
+++ b/drivers/rtc/rtc-goldfish.c
@@ -203,4 +203,5 @@ static struct platform_driver goldfish_rtc = {
module_platform_driver(goldfish_rtc);
+MODULE_DESCRIPTION("Android Goldfish Real Time Clock driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c
index 16fdefafec5d..6228d0b2486e 100644
--- a/drivers/rtc/rtc-hid-sensor-time.c
+++ b/drivers/rtc/rtc-hid-sensor-time.c
@@ -296,14 +296,12 @@ err_open:
return ret;
}
-static int hid_time_remove(struct platform_device *pdev)
+static void hid_time_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
sensor_hub_device_close(hsdev);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME);
-
- return 0;
}
static const struct platform_device_id hid_time_ids[] = {
@@ -328,4 +326,4 @@ module_platform_driver(hid_time_platform_driver);
MODULE_DESCRIPTION("HID Sensor Time");
MODULE_AUTHOR("Alexander Holler <holler@ahsoftware.de>");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(IIO_HID);
+MODULE_IMPORT_NS("IIO_HID");
diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c
index cc710d682121..7a170c0f9710 100644
--- a/drivers/rtc/rtc-hym8563.c
+++ b/drivers/rtc/rtc-hym8563.c
@@ -285,14 +285,19 @@ static unsigned long hym8563_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[ret];
}
-static long hym8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int hym8563_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -363,7 +368,7 @@ static const struct clk_ops hym8563_clkout_ops = {
.unprepare = hym8563_clkout_unprepare,
.is_prepared = hym8563_clkout_is_prepared,
.recalc_rate = hym8563_clkout_recalc_rate,
- .round_rate = hym8563_clkout_round_rate,
+ .determine_rate = hym8563_clkout_determine_rate,
.set_rate = hym8563_clkout_set_rate,
};
@@ -518,9 +523,14 @@ static int hym8563_probe(struct i2c_client *client)
}
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, hym8563_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
client->name, hym8563);
if (ret < 0) {
dev_err(&client->dev, "irq %d request failed, %d\n",
@@ -554,8 +564,8 @@ static int hym8563_probe(struct i2c_client *client)
}
static const struct i2c_device_id hym8563_id[] = {
- { "hym8563", 0 },
- {},
+ { "hym8563" },
+ {}
};
MODULE_DEVICE_TABLE(i2c, hym8563_id);
@@ -571,7 +581,7 @@ static struct i2c_driver hym8563_driver = {
.pm = &hym8563_pm_ops,
.of_match_table = hym8563_dt_idtable,
},
- .probe_new = hym8563_probe,
+ .probe = hym8563_probe,
.id_table = hym8563_id,
};
diff --git a/drivers/rtc/rtc-imx-sm-bbm.c b/drivers/rtc/rtc-imx-sm-bbm.c
new file mode 100644
index 000000000000..daa472be7c80
--- /dev/null
+++ b/drivers/rtc/rtc-imx-sm-bbm.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 NXP.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/scmi_protocol.h>
+#include <linux/scmi_imx_protocol.h>
+
+struct scmi_imx_bbm {
+ const struct scmi_imx_bbm_proto_ops *ops;
+ struct rtc_device *rtc_dev;
+ struct scmi_protocol_handle *ph;
+ struct notifier_block nb;
+};
+
+static int scmi_imx_bbm_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
+ struct scmi_protocol_handle *ph = bbnsm->ph;
+ u64 val;
+ int ret;
+
+ ret = bbnsm->ops->rtc_time_get(ph, 0, &val);
+ if (ret)
+ return ret;
+
+ rtc_time64_to_tm(val, tm);
+
+ return 0;
+}
+
+static int scmi_imx_bbm_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
+ struct scmi_protocol_handle *ph = bbnsm->ph;
+ u64 val;
+
+ val = rtc_tm_to_time64(tm);
+
+ return bbnsm->ops->rtc_time_set(ph, 0, val);
+}
+
+static int scmi_imx_bbm_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
+ struct scmi_protocol_handle *ph = bbnsm->ph;
+
+ /* scmi_imx_bbm_set_alarm enables the irq, just handle disable here */
+ if (!enable)
+ return bbnsm->ops->rtc_alarm_set(ph, 0, false, 0);
+
+ return 0;
+}
+
+static int scmi_imx_bbm_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
+ struct scmi_protocol_handle *ph = bbnsm->ph;
+ struct rtc_time *alrm_tm = &alrm->time;
+ u64 val;
+
+ val = rtc_tm_to_time64(alrm_tm);
+
+ return bbnsm->ops->rtc_alarm_set(ph, 0, true, val);
+}
+
+static const struct rtc_class_ops smci_imx_bbm_rtc_ops = {
+ .read_time = scmi_imx_bbm_read_time,
+ .set_time = scmi_imx_bbm_set_time,
+ .set_alarm = scmi_imx_bbm_set_alarm,
+ .alarm_irq_enable = scmi_imx_bbm_alarm_irq_enable,
+};
+
+static int scmi_imx_bbm_rtc_notifier(struct notifier_block *nb, unsigned long event, void *data)
+{
+ struct scmi_imx_bbm *bbnsm = container_of(nb, struct scmi_imx_bbm, nb);
+ struct scmi_imx_bbm_notif_report *r = data;
+
+ if (r->is_rtc)
+ rtc_update_irq(bbnsm->rtc_dev, 1, RTC_AF | RTC_IRQF);
+ else
+ pr_err("Unexpected bbm event: %s\n", __func__);
+
+ return 0;
+}
+
+static int scmi_imx_bbm_rtc_init(struct scmi_device *sdev)
+{
+ const struct scmi_handle *handle = sdev->handle;
+ struct device *dev = &sdev->dev;
+ struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
+ int ret;
+
+ bbnsm->rtc_dev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(bbnsm->rtc_dev))
+ return PTR_ERR(bbnsm->rtc_dev);
+
+ bbnsm->rtc_dev->ops = &smci_imx_bbm_rtc_ops;
+ bbnsm->rtc_dev->range_max = U32_MAX;
+
+ bbnsm->nb.notifier_call = &scmi_imx_bbm_rtc_notifier;
+ ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_BBM,
+ SCMI_EVENT_IMX_BBM_RTC,
+ NULL, &bbnsm->nb);
+ if (ret)
+ return ret;
+
+ return devm_rtc_register_device(bbnsm->rtc_dev);
+}
+
+static int scmi_imx_bbm_rtc_probe(struct scmi_device *sdev)
+{
+ const struct scmi_handle *handle = sdev->handle;
+ struct device *dev = &sdev->dev;
+ struct scmi_protocol_handle *ph;
+ struct scmi_imx_bbm *bbnsm;
+ int ret;
+
+ if (!handle)
+ return -ENODEV;
+
+ bbnsm = devm_kzalloc(dev, sizeof(*bbnsm), GFP_KERNEL);
+ if (!bbnsm)
+ return -ENOMEM;
+
+ bbnsm->ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_BBM, &ph);
+ if (IS_ERR(bbnsm->ops))
+ return PTR_ERR(bbnsm->ops);
+
+ bbnsm->ph = ph;
+
+ device_init_wakeup(dev, true);
+
+ dev_set_drvdata(dev, bbnsm);
+
+ ret = scmi_imx_bbm_rtc_init(sdev);
+ if (ret)
+ device_init_wakeup(dev, false);
+
+ return ret;
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+ { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-rtc" },
+ { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_imx_bbm_rtc_driver = {
+ .name = "scmi-imx-bbm-rtc",
+ .probe = scmi_imx_bbm_rtc_probe,
+ .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_imx_bbm_rtc_driver);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("IMX SM BBM RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 4b712e5ab08a..ca4a0af95e8c 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -830,7 +830,7 @@ err:
return rc;
}
-static int __exit dryice_rtc_remove(struct platform_device *pdev)
+static void __exit dryice_rtc_remove(struct platform_device *pdev)
{
struct imxdi_dev *imxdi = platform_get_drvdata(pdev);
@@ -840,8 +840,6 @@ static int __exit dryice_rtc_remove(struct platform_device *pdev)
writel(0, imxdi->ioaddr + DIER);
clk_disable_unprepare(imxdi->clk);
-
- return 0;
}
static const struct of_device_id dryice_dt_ids[] = {
@@ -851,7 +849,13 @@ static const struct of_device_id dryice_dt_ids[] = {
MODULE_DEVICE_TABLE(of, dryice_dt_ids);
-static struct platform_driver dryice_rtc_driver = {
+/*
+ * dryice_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver dryice_rtc_driver __refdata = {
.driver = {
.name = "imxdi_rtc",
.of_match_table = dryice_dt_ids,
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index a3b0de3393f5..5fc52dc64213 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -8,18 +8,20 @@
* by Alessandro Zummo <a.zummo@towertech.it>.
*/
-#include <linux/i2c.h>
#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
-/* ISL register offsets */
+/* RTC - Real time clock registers */
#define ISL12022_REG_SC 0x00
#define ISL12022_REG_MN 0x01
#define ISL12022_REG_HR 0x02
@@ -28,19 +30,44 @@
#define ISL12022_REG_YR 0x05
#define ISL12022_REG_DW 0x06
+/* CSR - Control and status registers */
#define ISL12022_REG_SR 0x07
#define ISL12022_REG_INT 0x08
-
+#define ISL12022_REG_PWR_VBAT 0x0a
#define ISL12022_REG_BETA 0x0d
+
+/* ALARM - Alarm registers */
+#define ISL12022_REG_SCA0 0x10
+#define ISL12022_REG_MNA0 0x11
+#define ISL12022_REG_HRA0 0x12
+#define ISL12022_REG_DTA0 0x13
+#define ISL12022_REG_MOA0 0x14
+#define ISL12022_REG_DWA0 0x15
+#define ISL12022_ALARM ISL12022_REG_SCA0
+#define ISL12022_ALARM_LEN (ISL12022_REG_DWA0 - ISL12022_REG_SCA0 + 1)
+
+/* TEMP - Temperature sensor registers */
#define ISL12022_REG_TEMP_L 0x28
/* ISL register bits */
#define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */
+#define ISL12022_SR_ALM (1 << 4)
#define ISL12022_SR_LBAT85 (1 << 2)
#define ISL12022_SR_LBAT75 (1 << 1)
+#define ISL12022_INT_ARST (1 << 7)
#define ISL12022_INT_WRTC (1 << 6)
+#define ISL12022_INT_IM (1 << 5)
+#define ISL12022_INT_FOBATB (1 << 4)
+#define ISL12022_INT_FO_MASK GENMASK(3, 0)
+#define ISL12022_INT_FO_OFF 0x0
+#define ISL12022_INT_FO_32K 0x1
+
+#define ISL12022_REG_VB85_MASK GENMASK(5, 3)
+#define ISL12022_REG_VB75_MASK GENMASK(2, 0)
+
+#define ISL12022_ALARM_ENABLE (1 << 7) /* for all ALARM registers */
#define ISL12022_BETA_TSE (1 << 7)
@@ -49,6 +76,8 @@ static struct i2c_driver isl12022_driver;
struct isl12022 {
struct rtc_device *rtc;
struct regmap *regmap;
+ int irq;
+ bool irq_enabled;
};
static umode_t isl12022_hwmon_is_visible(const void *data,
@@ -67,19 +96,17 @@ static umode_t isl12022_hwmon_is_visible(const void *data,
*/
static int isl12022_hwmon_read_temp(struct device *dev, long *mC)
{
- struct isl12022 *isl12022 = dev_get_drvdata(dev);
- struct regmap *regmap = isl12022->regmap;
- u8 temp_buf[2];
+ struct regmap *regmap = dev_get_drvdata(dev);
int temp, ret;
+ __le16 buf;
- ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L,
- temp_buf, sizeof(temp_buf));
+ ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L, &buf, sizeof(buf));
if (ret)
return ret;
/*
* Temperature is represented as a 10-bit number, unit half-Kelvins.
*/
- temp = (temp_buf[1] << 8) | temp_buf[0];
+ temp = le16_to_cpu(buf);
temp *= 500;
temp -= 273000;
@@ -98,7 +125,7 @@ static int isl12022_hwmon_read(struct device *dev,
return -EOPNOTSUPP;
}
-static const struct hwmon_channel_info *isl12022_hwmon_info[] = {
+static const struct hwmon_channel_info * const isl12022_hwmon_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
NULL
};
@@ -115,23 +142,22 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = {
static void isl12022_hwmon_register(struct device *dev)
{
- struct isl12022 *isl12022;
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
struct device *hwmon;
int ret;
if (!IS_REACHABLE(CONFIG_HWMON))
return;
- isl12022 = dev_get_drvdata(dev);
-
- ret = regmap_update_bits(isl12022->regmap, ISL12022_REG_BETA,
+ ret = regmap_update_bits(regmap, ISL12022_REG_BETA,
ISL12022_BETA_TSE, ISL12022_BETA_TSE);
if (ret) {
dev_warn(dev, "unable to enable temperature sensor\n");
return;
}
- hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", isl12022,
+ hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", regmap,
&isl12022_hwmon_chip_info,
NULL);
if (IS_ERR(hwmon))
@@ -146,25 +172,15 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
- uint8_t buf[ISL12022_REG_INT + 1];
+ u8 buf[ISL12022_REG_INT + 1];
int ret;
ret = regmap_bulk_read(regmap, ISL12022_REG_SC, buf, sizeof(buf));
if (ret)
return ret;
- if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) {
- dev_warn(dev,
- "voltage dropped below %u%%, "
- "date and time is not reliable.\n",
- buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
- }
-
dev_dbg(dev,
- "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
- "mday=%02x, mon=%02x, year=%02x, wday=%02x, "
- "sr=%02x, int=%02x",
- __func__,
+ "raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x",
buf[ISL12022_REG_SC],
buf[ISL12022_REG_MN],
buf[ISL12022_REG_HR],
@@ -193,7 +209,7 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
int ret;
- uint8_t buf[ISL12022_REG_DW + 1];
+ u8 buf[ISL12022_REG_DW + 1];
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
@@ -218,13 +234,232 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
- return regmap_bulk_write(isl12022->regmap, ISL12022_REG_SC,
- buf, sizeof(buf));
+ return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf));
+}
+
+static int isl12022_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *tm = &alarm->time;
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ u8 buf[ISL12022_ALARM_LEN];
+ unsigned int i, yr;
+ int ret;
+
+ ret = regmap_bulk_read(regmap, ISL12022_ALARM, buf, sizeof(buf));
+ if (ret) {
+ dev_dbg(dev, "%s: reading ALARM registers failed\n",
+ __func__);
+ return ret;
+ }
+
+ /* The alarm doesn't store the year so get it from the rtc section */
+ ret = regmap_read(regmap, ISL12022_REG_YR, &yr);
+ if (ret) {
+ dev_dbg(dev, "%s: reading YR register failed\n", __func__);
+ return ret;
+ }
+
+ dev_dbg(dev,
+ "%s: sc=%02x, mn=%02x, hr=%02x, dt=%02x, mo=%02x, dw=%02x yr=%u\n",
+ __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], yr);
+
+ tm->tm_sec = bcd2bin(buf[ISL12022_REG_SCA0 - ISL12022_ALARM] & 0x7F);
+ tm->tm_min = bcd2bin(buf[ISL12022_REG_MNA0 - ISL12022_ALARM] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[ISL12022_REG_HRA0 - ISL12022_ALARM] & 0x3F);
+ tm->tm_mday = bcd2bin(buf[ISL12022_REG_DTA0 - ISL12022_ALARM] & 0x3F);
+ tm->tm_mon = bcd2bin(buf[ISL12022_REG_MOA0 - ISL12022_ALARM] & 0x1F) - 1;
+ tm->tm_wday = buf[ISL12022_REG_DWA0 - ISL12022_ALARM] & 0x07;
+ tm->tm_year = bcd2bin(yr) + 100;
+
+ for (i = 0; i < ISL12022_ALARM_LEN; i++) {
+ if (buf[i] & ISL12022_ALARM_ENABLE) {
+ alarm->enabled = 1;
+ break;
+ }
+ }
+
+ dev_dbg(dev, "%s: %ptR\n", __func__, tm);
+
+ return 0;
+}
+
+static int isl12022_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *alarm_tm = &alarm->time;
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ u8 regs[ISL12022_ALARM_LEN] = { 0, };
+ struct rtc_time rtc_tm;
+ int ret, enable, dw;
+
+ ret = isl12022_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ return ret;
+
+ /* If the alarm time is before the current time disable the alarm */
+ if (!alarm->enabled || rtc_tm_sub(alarm_tm, &rtc_tm) <= 0)
+ enable = 0;
+ else
+ enable = ISL12022_ALARM_ENABLE;
+
+ /*
+ * Set non-matching day of the week to safeguard against early false
+ * matching while setting all the alarm registers (this rtc lacks a
+ * general alarm/irq enable/disable bit).
+ */
+ ret = regmap_read(regmap, ISL12022_REG_DW, &dw);
+ if (ret) {
+ dev_dbg(dev, "%s: reading DW failed\n", __func__);
+ return ret;
+ }
+ /* ~4 days into the future should be enough to avoid match */
+ dw = ((dw + 4) % 7) | ISL12022_ALARM_ENABLE;
+ ret = regmap_write(regmap, ISL12022_REG_DWA0, dw);
+ if (ret) {
+ dev_dbg(dev, "%s: writing DWA0 failed\n", __func__);
+ return ret;
+ }
+
+ /* Program the alarm and enable it for each setting */
+ regs[ISL12022_REG_SCA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_sec) | enable;
+ regs[ISL12022_REG_MNA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_min) | enable;
+ regs[ISL12022_REG_HRA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_hour) | enable;
+ regs[ISL12022_REG_DTA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mday) | enable;
+ regs[ISL12022_REG_MOA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mon + 1) | enable;
+ regs[ISL12022_REG_DWA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_wday & 7) | enable;
+
+ /* write ALARM registers */
+ ret = regmap_bulk_write(regmap, ISL12022_ALARM, &regs, sizeof(regs));
+ if (ret) {
+ dev_dbg(dev, "%s: writing ALARM registers failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static irqreturn_t isl12022_rtc_interrupt(int irq, void *data)
+{
+ struct isl12022 *isl12022 = data;
+ struct rtc_device *rtc = isl12022->rtc;
+ struct device *dev = &rtc->dev;
+ struct regmap *regmap = isl12022->regmap;
+ u32 val = 0;
+ unsigned long events = 0;
+ int ret;
+
+ ret = regmap_read(regmap, ISL12022_REG_SR, &val);
+ if (ret) {
+ dev_dbg(dev, "%s: reading SR failed\n", __func__);
+ return IRQ_HANDLED;
+ }
+
+ if (val & ISL12022_SR_ALM)
+ events |= RTC_IRQF | RTC_AF;
+
+ if (events & RTC_AF)
+ dev_dbg(dev, "alarm!\n");
+
+ if (!events)
+ return IRQ_NONE;
+
+ rtc_update_irq(rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+static int isl12022_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+
+ /* Make sure enabled is 0 or 1 */
+ enabled = !!enabled;
+
+ if (isl12022->irq_enabled == enabled)
+ return 0;
+
+ if (enabled)
+ enable_irq(isl12022->irq);
+ else
+ disable_irq(isl12022->irq);
+
+ isl12022->irq_enabled = enabled;
+
+ return 0;
+}
+
+static int isl12022_setup_irq(struct device *dev, int irq)
+{
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ unsigned int reg_mask, reg_val;
+ u8 buf[ISL12022_ALARM_LEN] = { 0, };
+ int ret;
+
+ /* Clear and disable all alarm registers */
+ ret = regmap_bulk_write(regmap, ISL12022_ALARM, buf, sizeof(buf));
+ if (ret)
+ return ret;
+
+ /*
+ * Enable automatic reset of ALM bit and enable single event interrupt
+ * mode.
+ */
+ reg_mask = ISL12022_INT_ARST | ISL12022_INT_IM | ISL12022_INT_FO_MASK;
+ reg_val = ISL12022_INT_ARST | ISL12022_INT_FO_OFF;
+ ret = regmap_write_bits(regmap, ISL12022_REG_INT,
+ reg_mask, reg_val);
+ if (ret)
+ return ret;
+
+ isl12022->irq_enabled = true;
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ isl12022_rtc_interrupt,
+ IRQF_SHARED | IRQF_ONESHOT,
+ isl12022_driver.driver.name,
+ isl12022);
+ if (ret)
+ return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
+
+ isl12022->irq = irq;
+ return 0;
+}
+
+static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ u32 user, val;
+ int ret;
+
+ switch (cmd) {
+ case RTC_VL_READ:
+ ret = regmap_read(regmap, ISL12022_REG_SR, &val);
+ if (ret)
+ return ret;
+
+ user = 0;
+ if (val & ISL12022_SR_LBAT85)
+ user |= RTC_VL_BACKUP_LOW;
+
+ if (val & ISL12022_SR_LBAT75)
+ user |= RTC_VL_BACKUP_EMPTY;
+
+ return put_user(user, (u32 __user *)arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
}
static const struct rtc_class_ops isl12022_rtc_ops = {
+ .ioctl = isl12022_rtc_ioctl,
.read_time = isl12022_rtc_read_time,
.set_time = isl12022_rtc_set_time,
+ .read_alarm = isl12022_rtc_read_alarm,
+ .set_alarm = isl12022_rtc_set_alarm,
+ .alarm_irq_enable = isl12022_rtc_alarm_irq_enable,
};
static const struct regmap_config regmap_config = {
@@ -233,49 +468,143 @@ static const struct regmap_config regmap_config = {
.use_single_write = true,
};
+static int isl12022_register_clock(struct device *dev)
+{
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ struct clk_hw *hw;
+ int ret;
+
+ if (!device_property_present(dev, "#clock-cells")) {
+ /*
+ * Disabling the F_OUT pin reduces the power
+ * consumption in battery mode by ~25%.
+ */
+ regmap_update_bits(regmap, ISL12022_REG_INT, ISL12022_INT_FO_MASK,
+ ISL12022_INT_FO_OFF);
+
+ return 0;
+ }
+
+ if (!IS_ENABLED(CONFIG_COMMON_CLK))
+ return 0;
+
+ /*
+ * For now, only support a fixed clock of 32768Hz (the reset default).
+ */
+ ret = regmap_update_bits(regmap, ISL12022_REG_INT,
+ ISL12022_INT_FO_MASK, ISL12022_INT_FO_32K);
+ if (ret)
+ return ret;
+
+ hw = devm_clk_hw_register_fixed_rate(dev, "isl12022", NULL, 0, 32768);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+}
+
+static const u32 trip_levels[2][7] = {
+ { 2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000 },
+ { 1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000 },
+};
+
+static void isl12022_set_trip_levels(struct device *dev)
+{
+ struct isl12022 *isl12022 = dev_get_drvdata(dev);
+ struct regmap *regmap = isl12022->regmap;
+ u32 levels[2] = {0, 0};
+ int ret, i, j, x[2];
+ u8 val, mask;
+
+ device_property_read_u32_array(dev, "isil,battery-trip-levels-microvolt",
+ levels, 2);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < ARRAY_SIZE(trip_levels[i]) - 1; j++) {
+ if (levels[i] <= trip_levels[i][j])
+ break;
+ }
+ x[i] = j;
+ }
+
+ val = FIELD_PREP(ISL12022_REG_VB85_MASK, x[0]) |
+ FIELD_PREP(ISL12022_REG_VB75_MASK, x[1]);
+ mask = ISL12022_REG_VB85_MASK | ISL12022_REG_VB75_MASK;
+
+ ret = regmap_update_bits(regmap, ISL12022_REG_PWR_VBAT, mask, val);
+ if (ret)
+ dev_warn(dev, "unable to set battery alarm levels: %d\n", ret);
+
+ /*
+ * Force a write of the TSE bit in the BETA register, in order
+ * to trigger an update of the LBAT75 and LBAT85 bits in the
+ * status register. In battery backup mode, those bits have
+ * another meaning, so without this, they may contain stale
+ * values for up to a minute after power-on.
+ */
+ regmap_write_bits(regmap, ISL12022_REG_BETA,
+ ISL12022_BETA_TSE, ISL12022_BETA_TSE);
+}
+
static int isl12022_probe(struct i2c_client *client)
{
struct isl12022 *isl12022;
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022),
- GFP_KERNEL);
+ /* Allocate driver state */
+ isl12022 = devm_kzalloc(&client->dev, sizeof(*isl12022), GFP_KERNEL);
if (!isl12022)
return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap), "regmap allocation failed\n");
+ isl12022->regmap = regmap;
+
dev_set_drvdata(&client->dev, isl12022);
- isl12022->regmap = devm_regmap_init_i2c(client, &regmap_config);
- if (IS_ERR(isl12022->regmap)) {
- dev_err(&client->dev, "regmap allocation failed\n");
- return PTR_ERR(isl12022->regmap);
- }
+ ret = isl12022_register_clock(&client->dev);
+ if (ret)
+ return ret;
+ isl12022_set_trip_levels(&client->dev);
isl12022_hwmon_register(&client->dev);
- isl12022->rtc = devm_rtc_allocate_device(&client->dev);
- if (IS_ERR(isl12022->rtc))
- return PTR_ERR(isl12022->rtc);
-
- isl12022->rtc->ops = &isl12022_rtc_ops;
- isl12022->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
- isl12022->rtc->range_max = RTC_TIMESTAMP_END_2099;
+ rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+ isl12022->rtc = rtc;
+
+ rtc->ops = &isl12022_rtc_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+ if (client->irq > 0) {
+ ret = isl12022_setup_irq(&client->dev, client->irq);
+ if (ret)
+ return ret;
+ } else {
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
+ }
- return devm_rtc_register_device(isl12022->rtc);
+ return devm_rtc_register_device(rtc);
}
-#ifdef CONFIG_OF
static const struct of_device_id isl12022_dt_match[] = {
{ .compatible = "isl,isl12022" }, /* for backward compat., don't use */
{ .compatible = "isil,isl12022" },
{ },
};
MODULE_DEVICE_TABLE(of, isl12022_dt_match);
-#endif
static const struct i2c_device_id isl12022_id[] = {
- { "isl12022", 0 },
+ { "isl12022" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl12022_id);
@@ -283,11 +612,9 @@ MODULE_DEVICE_TABLE(i2c, isl12022_id);
static struct i2c_driver isl12022_driver = {
.driver = {
.name = "rtc-isl12022",
-#ifdef CONFIG_OF
- .of_match_table = of_match_ptr(isl12022_dt_match),
-#endif
+ .of_match_table = isl12022_dt_match,
},
- .probe_new = isl12022_probe,
+ .probe = isl12022_probe,
.id_table = isl12022_id,
};
diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c
index 1bfca39079d4..2aabb9151d4c 100644
--- a/drivers/rtc/rtc-isl12026.c
+++ b/drivers/rtc/rtc-isl12026.c
@@ -11,7 +11,6 @@
#include <linux/mutex.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@@ -429,7 +428,7 @@ static void isl12026_force_power_modes(struct i2c_client *client)
}
}
-static int isl12026_probe_new(struct i2c_client *client)
+static int isl12026_probe(struct i2c_client *client)
{
struct isl12026 *priv;
int ret;
@@ -490,7 +489,7 @@ static struct i2c_driver isl12026_driver = {
.name = "rtc-isl12026",
.of_match_table = isl12026_dt_match,
},
- .probe_new = isl12026_probe_new,
+ .probe = isl12026_probe,
.remove = isl12026_remove,
};
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index 73cc6aaf9b8b..f71a6bb77b2a 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -6,9 +6,11 @@
*/
#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/rtc.h>
@@ -68,42 +70,60 @@
static struct i2c_driver isl1208_driver;
-/* ISL1208 various variants */
-enum isl1208_id {
- TYPE_ISL1208 = 0,
- TYPE_ISL1209,
- TYPE_ISL1218,
- TYPE_ISL1219,
- ISL_LAST_ID
-};
-
/* Chip capabilities table */
-static const struct isl1208_config {
- const char name[8];
+struct isl1208_config {
unsigned int nvmem_length;
unsigned has_tamper:1;
unsigned has_timestamp:1;
-} isl1208_configs[] = {
- [TYPE_ISL1208] = { "isl1208", 2, false, false },
- [TYPE_ISL1209] = { "isl1209", 2, true, false },
- [TYPE_ISL1218] = { "isl1218", 8, false, false },
- [TYPE_ISL1219] = { "isl1219", 2, true, true },
+ unsigned has_inverted_osc_bit:1;
+};
+
+static const struct isl1208_config config_isl1208 = {
+ .nvmem_length = 2,
+ .has_tamper = false,
+ .has_timestamp = false
+};
+
+static const struct isl1208_config config_isl1209 = {
+ .nvmem_length = 2,
+ .has_tamper = true,
+ .has_timestamp = false
+};
+
+static const struct isl1208_config config_isl1218 = {
+ .nvmem_length = 8,
+ .has_tamper = false,
+ .has_timestamp = false
+};
+
+static const struct isl1208_config config_isl1219 = {
+ .nvmem_length = 2,
+ .has_tamper = true,
+ .has_timestamp = true
+};
+
+static const struct isl1208_config config_raa215300_a0 = {
+ .nvmem_length = 2,
+ .has_tamper = false,
+ .has_timestamp = false,
+ .has_inverted_osc_bit = true
};
static const struct i2c_device_id isl1208_id[] = {
- { "isl1208", TYPE_ISL1208 },
- { "isl1209", TYPE_ISL1209 },
- { "isl1218", TYPE_ISL1218 },
- { "isl1219", TYPE_ISL1219 },
+ { "isl1208", .driver_data = (kernel_ulong_t)&config_isl1208 },
+ { "isl1209", .driver_data = (kernel_ulong_t)&config_isl1209 },
+ { "isl1218", .driver_data = (kernel_ulong_t)&config_isl1218 },
+ { "isl1219", .driver_data = (kernel_ulong_t)&config_isl1219 },
+ { "raa215300_a0", .driver_data = (kernel_ulong_t)&config_raa215300_a0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl1208_id);
static const __maybe_unused struct of_device_id isl1208_of_match[] = {
- { .compatible = "isil,isl1208", .data = &isl1208_configs[TYPE_ISL1208] },
- { .compatible = "isil,isl1209", .data = &isl1208_configs[TYPE_ISL1209] },
- { .compatible = "isil,isl1218", .data = &isl1208_configs[TYPE_ISL1218] },
- { .compatible = "isil,isl1219", .data = &isl1208_configs[TYPE_ISL1219] },
+ { .compatible = "isil,isl1208", .data = &config_isl1208 },
+ { .compatible = "isil,isl1209", .data = &config_isl1209 },
+ { .compatible = "isil,isl1218", .data = &config_isl1218 },
+ { .compatible = "isil,isl1219", .data = &config_isl1219 },
{ }
};
MODULE_DEVICE_TABLE(of, isl1208_of_match);
@@ -166,6 +186,20 @@ isl1208_i2c_validate_client(struct i2c_client *client)
return 0;
}
+static int isl1208_set_xtoscb(struct i2c_client *client, int sr, int xtosb_val)
+{
+ /* Do nothing if bit is already set to desired value */
+ if (!!(sr & ISL1208_REG_SR_XTOSCB) == xtosb_val)
+ return 0;
+
+ if (xtosb_val)
+ sr |= ISL1208_REG_SR_XTOSCB;
+ else
+ sr &= ~ISL1208_REG_SR_XTOSCB;
+
+ return i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
+}
+
static int
isl1208_i2c_get_sr(struct i2c_client *client)
{
@@ -502,7 +536,6 @@ isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
return 0;
}
-
static int
isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
@@ -596,6 +629,18 @@ isl1208_rtc_interrupt(int irq, void *data)
struct isl1208_state *isl1208 = i2c_get_clientdata(client);
int handled = 0, sr, err;
+ if (!isl1208->config->has_tamper) {
+ /*
+ * The INT# output is pulled low 250ms after the alarm is
+ * triggered. After the INT# output is pulled low, it is low for
+ * at least 250ms, even if the correct action is taken to clear
+ * it. It is impossible to clear ALM if it is still active. The
+ * host must wait for the RTC to progress past the alarm time
+ * plus the 250ms delay before clearing ALM.
+ */
+ msleep(250);
+ }
+
/*
* I2C reads get NAK'ed if we read straight away after an interrupt?
* Using a mdelay/msleep didn't seem to help either, so we work around
@@ -618,6 +663,13 @@ isl1208_rtc_interrupt(int irq, void *data)
rtc_update_irq(isl1208->rtc, 1, RTC_IRQF | RTC_AF);
+ /* Disable the alarm */
+ err = isl1208_rtc_toggle_alarm(client, 0);
+ if (err)
+ return err;
+
+ fsleep(275);
+
/* Clear the alarm */
sr &= ~ISL1208_REG_SR_ALM;
sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
@@ -626,11 +678,6 @@ isl1208_rtc_interrupt(int irq, void *data)
__func__);
else
handled = 1;
-
- /* Disable the alarm */
- err = isl1208_rtc_toggle_alarm(client, 0);
- if (err)
- return err;
}
if (isl1208->config->has_tamper && (sr & ISL1208_REG_SR_EVT)) {
@@ -743,14 +790,13 @@ static int isl1208_nvmem_read(void *priv, unsigned int off, void *buf,
{
struct isl1208_state *isl1208 = priv;
struct i2c_client *client = to_i2c_client(isl1208->rtc->dev.parent);
- int ret;
/* nvmem sanitizes offset/count for us, but count==0 is possible */
if (!count)
return count;
- ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1 + off, buf,
+
+ return isl1208_i2c_read_regs(client, ISL1208_REG_USR1 + off, buf,
count);
- return ret == 0 ? count : ret;
}
static int isl1208_nvmem_write(void *priv, unsigned int off, void *buf,
@@ -758,15 +804,13 @@ static int isl1208_nvmem_write(void *priv, unsigned int off, void *buf,
{
struct isl1208_state *isl1208 = priv;
struct i2c_client *client = to_i2c_client(isl1208->rtc->dev.parent);
- int ret;
/* nvmem sanitizes off/count for us, but count==0 is possible */
if (!count)
return count;
- ret = isl1208_i2c_set_regs(client, ISL1208_REG_USR1 + off, buf,
- count);
- return ret == 0 ? count : ret;
+ return isl1208_i2c_set_regs(client, ISL1208_REG_USR1 + off, buf,
+ count);
}
static const struct nvmem_config isl1208_nvmem_config = {
@@ -786,7 +830,7 @@ static int isl1208_setup_irq(struct i2c_client *client, int irq)
isl1208_driver.driver.name,
client);
if (!rc) {
- device_init_wakeup(&client->dev, 1);
+ device_init_wakeup(&client->dev, true);
enable_irq_wake(irq);
} else {
dev_err(&client->dev,
@@ -797,11 +841,25 @@ static int isl1208_setup_irq(struct i2c_client *client, int irq)
}
static int
+isl1208_clk_present(struct i2c_client *client, const char *name)
+{
+ struct clk *clk;
+
+ clk = devm_clk_get_optional(&client->dev, name);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return !!clk;
+}
+
+static int
isl1208_probe(struct i2c_client *client)
{
- int rc = 0;
struct isl1208_state *isl1208;
int evdet_irq = -1;
+ int xtosb_val = 0;
+ int rc = 0;
+ int sr;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
@@ -816,16 +874,21 @@ isl1208_probe(struct i2c_client *client)
i2c_set_clientdata(client, isl1208);
/* Determine which chip we have */
- if (client->dev.of_node) {
- isl1208->config = of_device_get_match_data(&client->dev);
- if (!isl1208->config)
- return -ENODEV;
- } else {
- const struct i2c_device_id *id = i2c_match_id(isl1208_id, client);
+ isl1208->config = i2c_get_match_data(client);
+ if (!isl1208->config)
+ return -ENODEV;
- if (id->driver_data >= ISL_LAST_ID)
- return -ENODEV;
- isl1208->config = &isl1208_configs[id->driver_data];
+ rc = isl1208_clk_present(client, "xin");
+ if (rc < 0)
+ return rc;
+
+ if (!rc) {
+ rc = isl1208_clk_present(client, "clkin");
+ if (rc < 0)
+ return rc;
+
+ if (rc)
+ xtosb_val = 1;
}
isl1208->rtc = devm_rtc_allocate_device(&client->dev);
@@ -839,13 +902,20 @@ isl1208_probe(struct i2c_client *client)
isl1208->nvmem_config.size = isl1208->config->nvmem_length;
isl1208->nvmem_config.priv = isl1208;
- rc = isl1208_i2c_get_sr(client);
- if (rc < 0) {
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
dev_err(&client->dev, "reading status failed\n");
- return rc;
+ return sr;
}
- if (rc & ISL1208_REG_SR_RTCF)
+ if (isl1208->config->has_inverted_osc_bit)
+ xtosb_val = !xtosb_val;
+
+ rc = isl1208_set_xtoscb(client, sr, xtosb_val);
+ if (rc)
+ return rc;
+
+ if (sr & ISL1208_REG_SR_RTCF)
dev_warn(&client->dev, "rtc power failure detected, "
"please set clock.\n");
@@ -886,7 +956,6 @@ isl1208_probe(struct i2c_client *client)
rc = isl1208_setup_irq(client, client->irq);
if (rc)
return rc;
-
} else {
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, isl1208->rtc->features);
}
@@ -908,7 +977,7 @@ static struct i2c_driver isl1208_driver = {
.name = "rtc-isl1208",
.of_match_table = of_match_ptr(isl1208_of_match),
},
- .probe_new = isl1208_probe,
+ .probe = isl1208_probe,
.id_table = isl1208_id,
};
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
index c383719292c7..11fce47be780 100644
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -6,12 +6,15 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
+#include <linux/property.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@@ -25,6 +28,7 @@
#define JZ_REG_RTC_WAKEUP_FILTER 0x24
#define JZ_REG_RTC_RESET_COUNTER 0x28
#define JZ_REG_RTC_SCRATCHPAD 0x34
+#define JZ_REG_RTC_CKPCR 0x40
/* The following are present on the jz4780 */
#define JZ_REG_RTC_WENR 0x3C
@@ -44,6 +48,9 @@
#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0
+#define JZ_RTC_CKPCR_CK32PULL_DIS BIT(4)
+#define JZ_RTC_CKPCR_CK32CTL_EN (BIT(2) | BIT(1))
+
enum jz4740_rtc_type {
ID_JZ4740,
ID_JZ4760,
@@ -56,6 +63,8 @@ struct jz4740_rtc {
struct rtc_device *rtc;
+ struct clk_hw clk32k;
+
spinlock_t lock;
};
@@ -69,19 +78,15 @@ static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
- int timeout = 10000;
- do {
- ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
- } while (!(ctrl & JZ_RTC_CTRL_WRDY) && --timeout);
-
- return timeout ? 0 : -EIO;
+ return readl_poll_timeout(rtc->base + JZ_REG_RTC_CTRL, ctrl,
+ ctrl & JZ_RTC_CTRL_WRDY, 0, 1000);
}
static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
- int ret, timeout = 10000;
+ int ret;
ret = jz4740_rtc_wait_write_ready(rtc);
if (ret != 0)
@@ -89,11 +94,8 @@ static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR);
- do {
- ctrl = readl(rtc->base + JZ_REG_RTC_WENR);
- } while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
-
- return timeout ? 0 : -EIO;
+ return readl_poll_timeout(rtc->base + JZ_REG_RTC_WENR, ctrl,
+ ctrl & JZ_RTC_WENR_WEN, 0, 1000);
}
static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
@@ -260,6 +262,7 @@ static void jz4740_rtc_power_off(void)
static const struct of_device_id jz4740_rtc_of_match[] = {
{ .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
{ .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 },
+ { .compatible = "ingenic,jz4770-rtc", .data = (void *)ID_JZ4780 },
{ .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
{},
};
@@ -301,6 +304,38 @@ static void jz4740_rtc_set_wakeup_params(struct jz4740_rtc *rtc,
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_RESET_COUNTER, reset_ticks);
}
+static int jz4740_rtc_clk32k_enable(struct clk_hw *hw)
+{
+ struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
+
+ return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR,
+ JZ_RTC_CKPCR_CK32PULL_DIS |
+ JZ_RTC_CKPCR_CK32CTL_EN);
+}
+
+static void jz4740_rtc_clk32k_disable(struct clk_hw *hw)
+{
+ struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
+
+ jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR, 0);
+}
+
+static int jz4740_rtc_clk32k_is_enabled(struct clk_hw *hw)
+{
+ struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
+ u32 ckpcr;
+
+ ckpcr = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CKPCR);
+
+ return !!(ckpcr & JZ_RTC_CKPCR_CK32CTL_EN);
+}
+
+static const struct clk_ops jz4740_rtc_clk32k_ops = {
+ .enable = jz4740_rtc_clk32k_enable,
+ .disable = jz4740_rtc_clk32k_disable,
+ .is_enabled = jz4740_rtc_clk32k_is_enabled,
+};
+
static int jz4740_rtc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -314,7 +349,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
if (!rtc)
return -ENOMEM;
- rtc->type = (enum jz4740_rtc_type)device_get_match_data(dev);
+ rtc->type = (uintptr_t)device_get_match_data(dev);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -332,20 +367,16 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
- device_init_wakeup(dev, 1);
+ device_init_wakeup(dev, true);
ret = dev_pm_set_wake_irq(dev, irq);
- if (ret) {
- dev_err(dev, "Failed to set wake irq: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set wake irq\n");
rtc->rtc = devm_rtc_allocate_device(dev);
- if (IS_ERR(rtc->rtc)) {
- ret = PTR_ERR(rtc->rtc);
- dev_err(dev, "Failed to allocate rtc device: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(rtc->rtc))
+ return dev_err_probe(dev, PTR_ERR(rtc->rtc),
+ "Failed to allocate rtc device\n");
rtc->rtc->ops = &jz4740_rtc_ops;
rtc->rtc->range_max = U32_MAX;
@@ -362,10 +393,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, jz4740_rtc_irq, 0,
pdev->name, rtc);
- if (ret) {
- dev_err(dev, "Failed to request rtc irq: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request rtc irq\n");
if (of_device_is_system_power_controller(np)) {
dev_for_power_off = dev;
@@ -376,6 +405,22 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
dev_warn(dev, "Poweroff handler already present!\n");
}
+ if (device_property_present(dev, "#clock-cells")) {
+ rtc->clk32k.init = CLK_HW_INIT_HW("clk32k", __clk_get_hw(clk),
+ &jz4740_rtc_clk32k_ops, 0);
+
+ ret = devm_clk_hw_register(dev, &rtc->clk32k);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Unable to register clk32k clock\n");
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &rtc->clk32k);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Unable to register clk32k clock provider\n");
+ }
+
return 0;
}
@@ -392,4 +437,3 @@ module_platform_driver(jz4740_rtc_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
-MODULE_ALIAS("platform:jz4740-rtc");
diff --git a/drivers/rtc/rtc-loongson.c b/drivers/rtc/rtc-loongson.c
new file mode 100644
index 000000000000..2ca7ffd5d7a9
--- /dev/null
+++ b/drivers/rtc/rtc-loongson.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Loongson RTC driver
+ *
+ * Maintained out-of-tree by Huacai Chen <chenhuacai@kernel.org>.
+ * Rewritten for mainline by WANG Xuerui <git@xen0n.name>.
+ * Binbin Zhou <zhoubinbin@loongson.cn>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/acpi.h>
+
+/* Time Of Year(TOY) counters registers */
+#define TOY_TRIM_REG 0x20 /* Must be initialized to 0 */
+#define TOY_WRITE0_REG 0x24 /* TOY low 32-bits value (write-only) */
+#define TOY_WRITE1_REG 0x28 /* TOY high 32-bits value (write-only) */
+#define TOY_READ0_REG 0x2c /* TOY low 32-bits value (read-only) */
+#define TOY_READ1_REG 0x30 /* TOY high 32-bits value (read-only) */
+#define TOY_MATCH0_REG 0x34 /* TOY timing interrupt 0 */
+#define TOY_MATCH1_REG 0x38 /* TOY timing interrupt 1 */
+#define TOY_MATCH2_REG 0x3c /* TOY timing interrupt 2 */
+
+/* RTC counters registers */
+#define RTC_CTRL_REG 0x40 /* TOY and RTC control register */
+#define RTC_TRIM_REG 0x60 /* Must be initialized to 0 */
+#define RTC_WRITE0_REG 0x64 /* RTC counters value (write-only) */
+#define RTC_READ0_REG 0x68 /* RTC counters value (read-only) */
+#define RTC_MATCH0_REG 0x6c /* RTC timing interrupt 0 */
+#define RTC_MATCH1_REG 0x70 /* RTC timing interrupt 1 */
+#define RTC_MATCH2_REG 0x74 /* RTC timing interrupt 2 */
+
+/* bitmask of TOY_WRITE0_REG */
+#define TOY_MON GENMASK(31, 26)
+#define TOY_DAY GENMASK(25, 21)
+#define TOY_HOUR GENMASK(20, 16)
+#define TOY_MIN GENMASK(15, 10)
+#define TOY_SEC GENMASK(9, 4)
+#define TOY_MSEC GENMASK(3, 0)
+
+/* bitmask of TOY_MATCH0/1/2_REG */
+#define TOY_MATCH_YEAR GENMASK(31, 26)
+#define TOY_MATCH_MON GENMASK(25, 22)
+#define TOY_MATCH_DAY GENMASK(21, 17)
+#define TOY_MATCH_HOUR GENMASK(16, 12)
+#define TOY_MATCH_MIN GENMASK(11, 6)
+#define TOY_MATCH_SEC GENMASK(5, 0)
+
+/* bitmask of RTC_CTRL_REG */
+#define RTC_ENABLE BIT(13) /* 1: RTC counters enable */
+#define TOY_ENABLE BIT(11) /* 1: TOY counters enable */
+#define OSC_ENABLE BIT(8) /* 1: 32.768k crystal enable */
+#define TOY_ENABLE_MASK (TOY_ENABLE | OSC_ENABLE)
+
+/* PM domain registers */
+#define PM1_STS_REG 0x0c /* Power management 1 status register */
+#define RTC_STS BIT(10) /* RTC status */
+#define PM1_EN_REG 0x10 /* Power management 1 enable register */
+#define RTC_EN BIT(10) /* RTC event enable */
+
+/*
+ * According to the LS1C manual, RTC_CTRL and alarm-related registers are not defined.
+ * Accessing the relevant registers will cause the system to hang.
+ */
+#define LS1C_RTC_CTRL_WORKAROUND BIT(0)
+
+struct loongson_rtc_config {
+ u32 pm_offset; /* Offset of PM domain, for RTC alarm wakeup */
+ u32 flags; /* Workaround bits */
+};
+
+struct loongson_rtc_priv {
+ spinlock_t lock; /* protects PM registers access */
+ u32 fix_year; /* RTC alarm year compensation value */
+ struct rtc_device *rtcdev;
+ struct regmap *regmap;
+ void __iomem *pm_base; /* PM domain base, for RTC alarm wakeup */
+ const struct loongson_rtc_config *config;
+};
+
+static const struct loongson_rtc_config ls1b_rtc_config = {
+ .pm_offset = 0,
+ .flags = 0,
+};
+
+static const struct loongson_rtc_config ls1c_rtc_config = {
+ .pm_offset = 0,
+ .flags = LS1C_RTC_CTRL_WORKAROUND,
+};
+
+static const struct loongson_rtc_config generic_rtc_config = {
+ .pm_offset = 0x100,
+ .flags = 0,
+};
+
+static const struct loongson_rtc_config ls2k1000_rtc_config = {
+ .pm_offset = 0x800,
+ .flags = 0,
+};
+
+static const struct regmap_config loongson_rtc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+/* RTC alarm irq handler */
+static irqreturn_t loongson_rtc_isr(int irq, void *id)
+{
+ struct loongson_rtc_priv *priv = (struct loongson_rtc_priv *)id;
+
+ rtc_update_irq(priv->rtcdev, 1, RTC_AF | RTC_IRQF);
+
+ /*
+ * The TOY_MATCH0_REG should be cleared 0 here,
+ * otherwise the interrupt cannot be cleared.
+ */
+ regmap_write(priv->regmap, TOY_MATCH0_REG, 0);
+
+ return IRQ_HANDLED;
+}
+
+/* For ACPI fixed event handler */
+static u32 loongson_rtc_handler(void *id)
+{
+ struct loongson_rtc_priv *priv = (struct loongson_rtc_priv *)id;
+
+ rtc_update_irq(priv->rtcdev, 1, RTC_AF | RTC_IRQF);
+
+ /*
+ * The TOY_MATCH0_REG should be cleared 0 here,
+ * otherwise the interrupt cannot be cleared.
+ */
+ regmap_write(priv->regmap, TOY_MATCH0_REG, 0);
+
+ spin_lock(&priv->lock);
+ /* Disable RTC alarm wakeup and interrupt */
+ writel(readl(priv->pm_base + PM1_EN_REG) & ~RTC_EN,
+ priv->pm_base + PM1_EN_REG);
+
+ /* Clear RTC interrupt status */
+ writel(RTC_STS, priv->pm_base + PM1_STS_REG);
+ spin_unlock(&priv->lock);
+
+ return ACPI_INTERRUPT_HANDLED;
+}
+
+static int loongson_rtc_set_enabled(struct device *dev)
+{
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND)
+ return 0;
+
+ /* Enable RTC TOY counters and crystal */
+ return regmap_update_bits(priv->regmap, RTC_CTRL_REG, TOY_ENABLE_MASK,
+ TOY_ENABLE_MASK);
+}
+
+static bool loongson_rtc_get_enabled(struct device *dev)
+{
+ int ret;
+ u32 ctrl_data;
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ if (priv->config->flags & LS1C_RTC_CTRL_WORKAROUND)
+ return true;
+
+ ret = regmap_read(priv->regmap, RTC_CTRL_REG, &ctrl_data);
+ if (ret < 0)
+ return false;
+
+ return ctrl_data & TOY_ENABLE_MASK;
+}
+
+static int loongson_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ int ret;
+ u32 rtc_data[2];
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ if (!loongson_rtc_get_enabled(dev))
+ return -EINVAL;
+
+ ret = regmap_bulk_read(priv->regmap, TOY_READ0_REG, rtc_data,
+ ARRAY_SIZE(rtc_data));
+ if (ret < 0)
+ return ret;
+
+ tm->tm_sec = FIELD_GET(TOY_SEC, rtc_data[0]);
+ tm->tm_min = FIELD_GET(TOY_MIN, rtc_data[0]);
+ tm->tm_hour = FIELD_GET(TOY_HOUR, rtc_data[0]);
+ tm->tm_mday = FIELD_GET(TOY_DAY, rtc_data[0]);
+ tm->tm_mon = FIELD_GET(TOY_MON, rtc_data[0]) - 1;
+ tm->tm_year = rtc_data[1];
+
+ /* Prepare for RTC alarm year compensation value. */
+ priv->fix_year = tm->tm_year / 64 * 64;
+ return 0;
+}
+
+static int loongson_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ int ret;
+ u32 rtc_data[2];
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ rtc_data[0] = FIELD_PREP(TOY_SEC, tm->tm_sec)
+ | FIELD_PREP(TOY_MIN, tm->tm_min)
+ | FIELD_PREP(TOY_HOUR, tm->tm_hour)
+ | FIELD_PREP(TOY_DAY, tm->tm_mday)
+ | FIELD_PREP(TOY_MON, tm->tm_mon + 1);
+ rtc_data[1] = tm->tm_year;
+
+ ret = regmap_bulk_write(priv->regmap, TOY_WRITE0_REG, rtc_data,
+ ARRAY_SIZE(rtc_data));
+ if (ret < 0)
+ return ret;
+
+ return loongson_rtc_set_enabled(dev);
+}
+
+static int loongson_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ u32 alarm_data;
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ ret = regmap_read(priv->regmap, TOY_MATCH0_REG, &alarm_data);
+ if (ret < 0)
+ return ret;
+
+ alrm->time.tm_sec = FIELD_GET(TOY_MATCH_SEC, alarm_data);
+ alrm->time.tm_min = FIELD_GET(TOY_MATCH_MIN, alarm_data);
+ alrm->time.tm_hour = FIELD_GET(TOY_MATCH_HOUR, alarm_data);
+ alrm->time.tm_mday = FIELD_GET(TOY_MATCH_DAY, alarm_data);
+ alrm->time.tm_mon = FIELD_GET(TOY_MATCH_MON, alarm_data) - 1;
+ /*
+ * This is a hardware bug: the year field of SYS_TOYMATCH is only 6 bits,
+ * making it impossible to save year values larger than 64.
+ *
+ * SYS_TOYMATCH is used to match the alarm time value and determine if
+ * an alarm is triggered, so we must keep the lower 6 bits of the year
+ * value constant during the value conversion.
+ *
+ * In summary, we need to manually add 64(or a multiple of 64) to the
+ * year value to avoid the invalid alarm prompt at startup.
+ */
+ alrm->time.tm_year = FIELD_GET(TOY_MATCH_YEAR, alarm_data) + priv->fix_year;
+
+ alrm->enabled = !!(readl(priv->pm_base + PM1_EN_REG) & RTC_EN);
+ return 0;
+}
+
+static int loongson_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ u32 val;
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ spin_lock(&priv->lock);
+ val = readl(priv->pm_base + PM1_EN_REG);
+ /* Enable RTC alarm wakeup */
+ writel(enabled ? val | RTC_EN : val & ~RTC_EN,
+ priv->pm_base + PM1_EN_REG);
+ spin_unlock(&priv->lock);
+
+ return 0;
+}
+
+static int loongson_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ u32 alarm_data;
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ alarm_data = FIELD_PREP(TOY_MATCH_SEC, alrm->time.tm_sec)
+ | FIELD_PREP(TOY_MATCH_MIN, alrm->time.tm_min)
+ | FIELD_PREP(TOY_MATCH_HOUR, alrm->time.tm_hour)
+ | FIELD_PREP(TOY_MATCH_DAY, alrm->time.tm_mday)
+ | FIELD_PREP(TOY_MATCH_MON, alrm->time.tm_mon + 1)
+ | FIELD_PREP(TOY_MATCH_YEAR, alrm->time.tm_year - priv->fix_year);
+
+ ret = regmap_write(priv->regmap, TOY_MATCH0_REG, alarm_data);
+ if (ret < 0)
+ return ret;
+
+ return loongson_rtc_alarm_irq_enable(dev, alrm->enabled);
+}
+
+static const struct rtc_class_ops loongson_rtc_ops = {
+ .read_time = loongson_rtc_read_time,
+ .set_time = loongson_rtc_set_time,
+ .read_alarm = loongson_rtc_read_alarm,
+ .set_alarm = loongson_rtc_set_alarm,
+ .alarm_irq_enable = loongson_rtc_alarm_irq_enable,
+};
+
+static int loongson_rtc_probe(struct platform_device *pdev)
+{
+ int ret, alarm_irq;
+ void __iomem *regs;
+ struct loongson_rtc_priv *priv;
+ struct device *dev = &pdev->dev;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return dev_err_probe(dev, PTR_ERR(regs),
+ "devm_platform_ioremap_resource failed\n");
+
+ priv->regmap = devm_regmap_init_mmio(dev, regs,
+ &loongson_rtc_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(priv->regmap),
+ "devm_regmap_init_mmio failed\n");
+
+ priv->config = device_get_match_data(dev);
+ spin_lock_init(&priv->lock);
+ platform_set_drvdata(pdev, priv);
+
+ priv->rtcdev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(priv->rtcdev))
+ return dev_err_probe(dev, PTR_ERR(priv->rtcdev),
+ "devm_rtc_allocate_device failed\n");
+
+ /* Get RTC alarm irq */
+ alarm_irq = platform_get_irq(pdev, 0);
+ if (alarm_irq > 0) {
+ ret = devm_request_irq(dev, alarm_irq, loongson_rtc_isr,
+ 0, "loongson-alarm", priv);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Unable to request irq %d\n",
+ alarm_irq);
+
+ priv->pm_base = regs - priv->config->pm_offset;
+ device_init_wakeup(dev, true);
+
+ if (has_acpi_companion(dev))
+ acpi_install_fixed_event_handler(ACPI_EVENT_RTC,
+ loongson_rtc_handler, priv);
+ } else {
+ /* Loongson-1C RTC does not support alarm */
+ clear_bit(RTC_FEATURE_ALARM, priv->rtcdev->features);
+ }
+
+ /* Loongson RTC does not support UIE */
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, priv->rtcdev->features);
+ priv->rtcdev->ops = &loongson_rtc_ops;
+ priv->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ priv->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
+
+ return devm_rtc_register_device(priv->rtcdev);
+}
+
+static void loongson_rtc_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct loongson_rtc_priv *priv = dev_get_drvdata(dev);
+
+ if (!test_bit(RTC_FEATURE_ALARM, priv->rtcdev->features))
+ return;
+
+ if (has_acpi_companion(dev))
+ acpi_remove_fixed_event_handler(ACPI_EVENT_RTC,
+ loongson_rtc_handler);
+
+ device_init_wakeup(dev, false);
+ loongson_rtc_alarm_irq_enable(dev, 0);
+}
+
+static const struct of_device_id loongson_rtc_of_match[] = {
+ { .compatible = "loongson,ls1b-rtc", .data = &ls1b_rtc_config },
+ { .compatible = "loongson,ls1c-rtc", .data = &ls1c_rtc_config },
+ { .compatible = "loongson,ls7a-rtc", .data = &generic_rtc_config },
+ { .compatible = "loongson,ls2k1000-rtc", .data = &ls2k1000_rtc_config },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, loongson_rtc_of_match);
+
+static const struct acpi_device_id loongson_rtc_acpi_match[] = {
+ { "LOON0001", .driver_data = (kernel_ulong_t)&generic_rtc_config },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, loongson_rtc_acpi_match);
+
+static struct platform_driver loongson_rtc_driver = {
+ .probe = loongson_rtc_probe,
+ .remove = loongson_rtc_remove,
+ .driver = {
+ .name = "loongson-rtc",
+ .of_match_table = loongson_rtc_of_match,
+ .acpi_match_table = loongson_rtc_acpi_match,
+ },
+};
+module_platform_driver(loongson_rtc_driver);
+
+MODULE_DESCRIPTION("Loongson RTC driver");
+MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>");
+MODULE_AUTHOR("WANG Xuerui <git@xen0n.name>");
+MODULE_AUTHOR("Huacai Chen <chenhuacai@kernel.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c
index c0b8fbce1082..0793d70507f7 100644
--- a/drivers/rtc/rtc-lp8788.c
+++ b/drivers/rtc/rtc-lp8788.c
@@ -293,7 +293,7 @@ static int lp8788_rtc_probe(struct platform_device *pdev)
rtc->alarm = lp->pdata ? lp->pdata->alarm_sel : DEFAULT_ALARM_SEL;
platform_set_drvdata(pdev, rtc);
- device_init_wakeup(dev, 1);
+ device_init_wakeup(dev, true);
rtc->rdev = devm_rtc_device_register(dev, "lp8788_rtc",
&lp8788_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c
index eec881a81067..2dcdc77ff646 100644
--- a/drivers/rtc/rtc-lpc24xx.c
+++ b/drivers/rtc/rtc-lpc24xx.c
@@ -9,9 +9,8 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
@@ -264,7 +263,7 @@ disable_rtc_clk:
return ret;
}
-static int lpc24xx_rtc_remove(struct platform_device *pdev)
+static void lpc24xx_rtc_remove(struct platform_device *pdev)
{
struct lpc24xx_rtc *rtc = platform_get_drvdata(pdev);
@@ -276,8 +275,6 @@ static int lpc24xx_rtc_remove(struct platform_device *pdev)
clk_disable_unprepare(rtc->clk_rtc);
clk_disable_unprepare(rtc->clk_reg);
-
- return 0;
}
static const struct of_device_id lpc24xx_rtc_match[] = {
@@ -288,7 +285,7 @@ MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match);
static struct platform_driver lpc24xx_rtc_driver = {
.probe = lpc24xx_rtc_probe,
- .remove = lpc24xx_rtc_remove,
+ .remove = lpc24xx_rtc_remove,
.driver = {
.name = "lpc24xx-rtc",
.of_match_table = lpc24xx_rtc_match,
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
index 76ad7031a13d..74280bffe1b0 100644
--- a/drivers/rtc/rtc-lpc32xx.c
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -257,7 +257,7 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Can't request interrupt.\n");
rtc->irq = -1;
} else {
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
}
}
diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c
deleted file mode 100644
index 5af26dc5c2a3..000000000000
--- a/drivers/rtc/rtc-ls1x.c
+++ /dev/null
@@ -1,192 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2011 Zhao Zhang <zhzhl555@gmail.com>
- *
- * Derived from driver/rtc/rtc-au1xxx.c
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/rtc.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <loongson1.h>
-
-#define LS1X_RTC_REG_OFFSET (LS1X_RTC_BASE + 0x20)
-#define LS1X_RTC_REGS(x) \
- ((void __iomem *)KSEG1ADDR(LS1X_RTC_REG_OFFSET + (x)))
-
-/*RTC programmable counters 0 and 1*/
-#define SYS_COUNTER_CNTRL (LS1X_RTC_REGS(0x20))
-#define SYS_CNTRL_ERS (1 << 23)
-#define SYS_CNTRL_RTS (1 << 20)
-#define SYS_CNTRL_RM2 (1 << 19)
-#define SYS_CNTRL_RM1 (1 << 18)
-#define SYS_CNTRL_RM0 (1 << 17)
-#define SYS_CNTRL_RS (1 << 16)
-#define SYS_CNTRL_BP (1 << 14)
-#define SYS_CNTRL_REN (1 << 13)
-#define SYS_CNTRL_BRT (1 << 12)
-#define SYS_CNTRL_TEN (1 << 11)
-#define SYS_CNTRL_BTT (1 << 10)
-#define SYS_CNTRL_E0 (1 << 8)
-#define SYS_CNTRL_ETS (1 << 7)
-#define SYS_CNTRL_32S (1 << 5)
-#define SYS_CNTRL_TTS (1 << 4)
-#define SYS_CNTRL_TM2 (1 << 3)
-#define SYS_CNTRL_TM1 (1 << 2)
-#define SYS_CNTRL_TM0 (1 << 1)
-#define SYS_CNTRL_TS (1 << 0)
-
-/* Programmable Counter 0 Registers */
-#define SYS_TOYTRIM (LS1X_RTC_REGS(0))
-#define SYS_TOYWRITE0 (LS1X_RTC_REGS(4))
-#define SYS_TOYWRITE1 (LS1X_RTC_REGS(8))
-#define SYS_TOYREAD0 (LS1X_RTC_REGS(0xC))
-#define SYS_TOYREAD1 (LS1X_RTC_REGS(0x10))
-#define SYS_TOYMATCH0 (LS1X_RTC_REGS(0x14))
-#define SYS_TOYMATCH1 (LS1X_RTC_REGS(0x18))
-#define SYS_TOYMATCH2 (LS1X_RTC_REGS(0x1C))
-
-/* Programmable Counter 1 Registers */
-#define SYS_RTCTRIM (LS1X_RTC_REGS(0x40))
-#define SYS_RTCWRITE0 (LS1X_RTC_REGS(0x44))
-#define SYS_RTCREAD0 (LS1X_RTC_REGS(0x48))
-#define SYS_RTCMATCH0 (LS1X_RTC_REGS(0x4C))
-#define SYS_RTCMATCH1 (LS1X_RTC_REGS(0x50))
-#define SYS_RTCMATCH2 (LS1X_RTC_REGS(0x54))
-
-#define LS1X_SEC_OFFSET (4)
-#define LS1X_MIN_OFFSET (10)
-#define LS1X_HOUR_OFFSET (16)
-#define LS1X_DAY_OFFSET (21)
-#define LS1X_MONTH_OFFSET (26)
-
-
-#define LS1X_SEC_MASK (0x3f)
-#define LS1X_MIN_MASK (0x3f)
-#define LS1X_HOUR_MASK (0x1f)
-#define LS1X_DAY_MASK (0x1f)
-#define LS1X_MONTH_MASK (0x3f)
-#define LS1X_YEAR_MASK (0xffffffff)
-
-#define ls1x_get_sec(t) (((t) >> LS1X_SEC_OFFSET) & LS1X_SEC_MASK)
-#define ls1x_get_min(t) (((t) >> LS1X_MIN_OFFSET) & LS1X_MIN_MASK)
-#define ls1x_get_hour(t) (((t) >> LS1X_HOUR_OFFSET) & LS1X_HOUR_MASK)
-#define ls1x_get_day(t) (((t) >> LS1X_DAY_OFFSET) & LS1X_DAY_MASK)
-#define ls1x_get_month(t) (((t) >> LS1X_MONTH_OFFSET) & LS1X_MONTH_MASK)
-
-#define RTC_CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
-
-static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm)
-{
- unsigned long v;
- time64_t t;
-
- v = readl(SYS_TOYREAD0);
- t = readl(SYS_TOYREAD1);
-
- memset(rtm, 0, sizeof(struct rtc_time));
- t = mktime64((t & LS1X_YEAR_MASK), ls1x_get_month(v),
- ls1x_get_day(v), ls1x_get_hour(v),
- ls1x_get_min(v), ls1x_get_sec(v));
- rtc_time64_to_tm(t, rtm);
-
- return 0;
-}
-
-static int ls1x_rtc_set_time(struct device *dev, struct rtc_time *rtm)
-{
- unsigned long v, t, c;
- int ret = -ETIMEDOUT;
-
- v = ((rtm->tm_mon + 1) << LS1X_MONTH_OFFSET)
- | (rtm->tm_mday << LS1X_DAY_OFFSET)
- | (rtm->tm_hour << LS1X_HOUR_OFFSET)
- | (rtm->tm_min << LS1X_MIN_OFFSET)
- | (rtm->tm_sec << LS1X_SEC_OFFSET);
-
- writel(v, SYS_TOYWRITE0);
- c = 0x10000;
- /* add timeout check counter, for more safe */
- while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c)
- usleep_range(1000, 3000);
-
- if (!c) {
- dev_err(dev, "set time timeout!\n");
- goto err;
- }
-
- t = rtm->tm_year + 1900;
- writel(t, SYS_TOYWRITE1);
- c = 0x10000;
- while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c)
- usleep_range(1000, 3000);
-
- if (!c) {
- dev_err(dev, "set time timeout!\n");
- goto err;
- }
- return 0;
-err:
- return ret;
-}
-
-static const struct rtc_class_ops ls1x_rtc_ops = {
- .read_time = ls1x_rtc_read_time,
- .set_time = ls1x_rtc_set_time,
-};
-
-static int ls1x_rtc_probe(struct platform_device *pdev)
-{
- struct rtc_device *rtcdev;
- unsigned long v;
-
- v = readl(SYS_COUNTER_CNTRL);
- if (!(v & RTC_CNTR_OK)) {
- dev_err(&pdev->dev, "rtc counters not working\n");
- return -ENODEV;
- }
-
- /* set to 1 HZ if needed */
- if (readl(SYS_TOYTRIM) != 32767) {
- v = 0x100000;
- while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) && --v)
- usleep_range(1000, 3000);
-
- if (!v) {
- dev_err(&pdev->dev, "time out\n");
- return -ETIMEDOUT;
- }
- writel(32767, SYS_TOYTRIM);
- }
- /* this loop coundn't be endless */
- while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS)
- usleep_range(1000, 3000);
-
- rtcdev = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(rtcdev))
- return PTR_ERR(rtcdev);
-
- platform_set_drvdata(pdev, rtcdev);
- rtcdev->ops = &ls1x_rtc_ops;
- rtcdev->range_min = RTC_TIMESTAMP_BEGIN_1900;
- rtcdev->range_max = RTC_TIMESTAMP_END_2099;
-
- return devm_rtc_register_device(rtcdev);
-}
-
-static struct platform_driver ls1x_rtc_driver = {
- .driver = {
- .name = "ls1x-rtc",
- },
- .probe = ls1x_rtc_probe,
-};
-
-module_platform_driver(ls1x_rtc_driver);
-
-MODULE_AUTHOR("zhao zhang <zhzhl555@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 494052dbd39f..740cab013f59 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -17,11 +17,12 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/string.h>
+#include <linux/delay.h>
#ifdef CONFIG_RTC_DRV_M41T80_WDT
#include <linux/fs.h>
#include <linux/ioctl.h>
@@ -71,7 +72,7 @@
static const struct i2c_device_id m41t80_id[] = {
{ "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
- { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
+ { "m41t65", M41T80_FEATURE_WD },
{ "m41t80", M41T80_FEATURE_SQ },
{ "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
{ "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
@@ -92,7 +93,7 @@ static const __maybe_unused struct of_device_id m41t80_of_match[] = {
},
{
.compatible = "st,m41t65",
- .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_WD)
+ .data = (void *)(M41T80_FEATURE_WD)
},
{
.compatible = "st,m41t80",
@@ -204,14 +205,14 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
return flags;
if (flags & M41T80_FLAGS_OF) {
- dev_err(&client->dev, "Oscillator failure, data is invalid.\n");
+ dev_err(&client->dev, "Oscillator failure, time may not be accurate, write time to RTC to fix it.\n");
return -EINVAL;
}
err = i2c_smbus_read_i2c_block_data(client, M41T80_REG_SSEC,
sizeof(buf), buf);
if (err < 0) {
- dev_err(&client->dev, "Unable to read date\n");
+ dev_dbg(&client->dev, "Unable to read date\n");
return err;
}
@@ -227,21 +228,31 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
return 0;
}
-static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *in_tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct m41t80_data *clientdata = i2c_get_clientdata(client);
+ struct rtc_time tm = *in_tm;
unsigned char buf[8];
int err, flags;
+ time64_t time = 0;
+ flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
+ if (flags < 0)
+ return flags;
+ if (flags & M41T80_FLAGS_OF) {
+ /* add 4sec of oscillator stablize time otherwise we are behind 4sec */
+ time = rtc_tm_to_time64(&tm);
+ rtc_time64_to_tm(time + 4, &tm);
+ }
buf[M41T80_REG_SSEC] = 0;
- buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec);
- buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min);
- buf[M41T80_REG_HOUR] = bin2bcd(tm->tm_hour);
- buf[M41T80_REG_DAY] = bin2bcd(tm->tm_mday);
- buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1);
- buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
- buf[M41T80_REG_WDAY] = tm->tm_wday;
+ buf[M41T80_REG_SEC] = bin2bcd(tm.tm_sec);
+ buf[M41T80_REG_MIN] = bin2bcd(tm.tm_min);
+ buf[M41T80_REG_HOUR] = bin2bcd(tm.tm_hour);
+ buf[M41T80_REG_DAY] = bin2bcd(tm.tm_mday);
+ buf[M41T80_REG_MON] = bin2bcd(tm.tm_mon + 1);
+ buf[M41T80_REG_YEAR] = bin2bcd(tm.tm_year - 100);
+ buf[M41T80_REG_WDAY] = tm.tm_wday;
/* If the square wave output is controlled in the weekday register */
if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
@@ -257,20 +268,37 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
sizeof(buf), buf);
if (err < 0) {
- dev_err(&client->dev, "Unable to write to date registers\n");
+ dev_dbg(&client->dev, "Unable to write to date registers\n");
return err;
}
-
- /* Clear the OF bit of Flags Register */
- flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
- if (flags < 0)
- return flags;
-
- err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
- flags & ~M41T80_FLAGS_OF);
- if (err < 0) {
- dev_err(&client->dev, "Unable to write flags register\n");
- return err;
+ if (flags & M41T80_FLAGS_OF) {
+ /* OF cannot be immediately reset: oscillator has to be restarted. */
+ dev_warn(&client->dev, "OF bit is still set, kickstarting clock.\n");
+ err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, M41T80_SEC_ST);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Can't set ST bit\n");
+ return err;
+ }
+ err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, flags & ~M41T80_SEC_ST);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Can't clear ST bit\n");
+ return err;
+ }
+ /* oscillator must run for 4sec before we attempt to reset OF bit */
+ msleep(4000);
+ /* Clear the OF bit of Flags Register */
+ err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, flags & ~M41T80_FLAGS_OF);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Unable to write flags register\n");
+ return err;
+ }
+ flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
+ if (flags < 0) {
+ return flags;
+ } else if (flags & M41T80_FLAGS_OF) {
+ dev_dbg(&client->dev, "Can't clear the OF bit check battery\n");
+ return err;
+ }
}
return err;
@@ -308,7 +336,7 @@ static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
if (retval < 0) {
- dev_err(dev, "Unable to enable alarm IRQ %d\n", retval);
+ dev_dbg(dev, "Unable to enable alarm IRQ %d\n", retval);
return retval;
}
return 0;
@@ -333,7 +361,7 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
ret & ~(M41T80_ALMON_AFE));
if (err < 0) {
- dev_err(dev, "Unable to clear AFE bit\n");
+ dev_dbg(dev, "Unable to clear AFE bit\n");
return err;
}
@@ -347,7 +375,7 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
ret & ~(M41T80_FLAGS_AF));
if (err < 0) {
- dev_err(dev, "Unable to clear AF bit\n");
+ dev_dbg(dev, "Unable to clear AF bit\n");
return err;
}
@@ -456,16 +484,17 @@ static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
return sqw_to_m41t80_data(hw)->freq;
}
-static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int m41t80_sqw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- if (rate >= M41T80_SQW_MAX_FREQ)
- return M41T80_SQW_MAX_FREQ;
- if (rate >= M41T80_SQW_MAX_FREQ / 4)
- return M41T80_SQW_MAX_FREQ / 4;
- if (!rate)
- return 0;
- return 1 << ilog2(rate);
+ if (req->rate >= M41T80_SQW_MAX_FREQ)
+ req->rate = M41T80_SQW_MAX_FREQ;
+ else if (req->rate >= M41T80_SQW_MAX_FREQ / 4)
+ req->rate = M41T80_SQW_MAX_FREQ / 4;
+ else if (req->rate)
+ req->rate = 1 << ilog2(req->rate);
+
+ return 0;
}
static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -536,7 +565,7 @@ static const struct clk_ops m41t80_sqw_ops = {
.unprepare = m41t80_sqw_unprepare,
.is_prepared = m41t80_sqw_is_prepared,
.recalc_rate = m41t80_sqw_recalc_rate,
- .round_rate = m41t80_sqw_round_rate,
+ .determine_rate = m41t80_sqw_determine_rate,
.set_rate = m41t80_sqw_set_rate,
};
@@ -850,7 +879,6 @@ static const struct file_operations wdt_fops = {
.write = wdt_write,
.open = wdt_open,
.release = wdt_release,
- .llseek = no_llseek,
};
static struct miscdevice wdt_dev = {
@@ -909,14 +937,16 @@ static int m41t80_probe(struct i2c_client *client)
if (IS_ERR(m41t80_data->rtc))
return PTR_ERR(m41t80_data->rtc);
-#ifdef CONFIG_OF
- wakeup_source = of_property_read_bool(client->dev.of_node,
- "wakeup-source");
-#endif
+ wakeup_source = device_property_read_bool(&client->dev, "wakeup-source");
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
rc = devm_request_threaded_irq(&client->dev, client->irq,
NULL, m41t80_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"m41t80", client);
if (rc) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
@@ -1008,7 +1038,7 @@ static struct i2c_driver m41t80_driver = {
.of_match_table = of_match_ptr(m41t80_of_match),
.pm = &m41t80_pm,
},
- .probe_new = m41t80_probe,
+ .probe = m41t80_probe,
.remove = m41t80_remove,
.id_table = m41t80_id,
};
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index f0f6b9b6daec..4e608bc8bbd3 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -71,7 +71,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
- tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
+ tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset;
/* tm_mon is 0-11 */
tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY));
@@ -82,10 +82,6 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
dev_dbg(dev, "Century bit is enabled\n");
tm->tm_year += 100; /* one century */
}
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- tm->tm_year += 68;
-#endif
tm->tm_wday = bcd2bin(val & 0x07);
tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F);
@@ -106,12 +102,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
unsigned long flags;
u8 val = 0;
- int year = tm->tm_year;
-
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- year -= 68;
-#endif
+ int year = tm->tm_year - pdata->yy_offset;
dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n",
year + 1900, tm->tm_mon, tm->tm_mday,
@@ -132,7 +123,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
M48T59_WRITE(bin2bcd(year % 100), M48T59_YEAR);
- if (pdata->type == M48T59RTC_TYPE_M48T59 && (year / 100))
+ if (pdata->type == M48T59RTC_TYPE_M48T59 && (year >= 100))
val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
val |= (bin2bcd(tm->tm_wday) & 0x07);
M48T59_WRITE(val, M48T59_WDAY);
@@ -162,11 +153,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
/* Issue the READ command */
M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
- tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- tm->tm_year += 68;
-#endif
+ tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset;
/* tm_mon is 0-11 */
tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
@@ -197,12 +184,7 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time;
u8 mday, hour, min, sec;
unsigned long flags;
- int year = tm->tm_year;
-
-#ifdef CONFIG_SPARC
- /* Sun SPARC machines count years since 1968 */
- year -= 68;
-#endif
+ int year = tm->tm_year - pdata->yy_offset;
/* If no irq, we don't support ALARM */
if (m48t59->irq == NO_IRQ)
@@ -458,6 +440,8 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, m48t59);
m48t59->rtc->ops = &m48t59_rtc_ops;
+ m48t59->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900;
+ m48t59->rtc->range_max = RTC_TIMESTAMP_END_2099;
nvmem_cfg.size = pdata->offset;
ret = devm_rtc_nvmem_register(m48t59->rtc, &nvmem_cfg);
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index 481c9525b1dd..10cd054fe86f 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/bcd.h>
@@ -40,7 +41,6 @@
struct m48t86_rtc_info {
void __iomem *index_reg;
void __iomem *data_reg;
- struct rtc_device *rtc;
};
static unsigned char m48t86_readb(struct device *dev, unsigned long addr)
@@ -218,6 +218,7 @@ static bool m48t86_verify_chip(struct platform_device *pdev)
static int m48t86_rtc_probe(struct platform_device *pdev)
{
struct m48t86_rtc_info *info;
+ struct rtc_device *rtc;
unsigned char reg;
int err;
struct nvmem_config m48t86_nvmem_cfg = {
@@ -249,17 +250,17 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
return -ENODEV;
}
- info->rtc = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(info->rtc))
- return PTR_ERR(info->rtc);
+ rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- info->rtc->ops = &m48t86_rtc_ops;
+ rtc->ops = &m48t86_rtc_ops;
- err = devm_rtc_register_device(info->rtc);
+ err = devm_rtc_register_device(rtc);
if (err)
return err;
- devm_rtc_nvmem_register(info->rtc, &m48t86_nvmem_cfg);
+ devm_rtc_nvmem_register(rtc, &m48t86_nvmem_cfg);
/* read battery status */
reg = m48t86_readb(&pdev->dev, M48T86_D);
@@ -269,9 +270,16 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id m48t86_rtc_of_ids[] = {
+ { .compatible = "st,m48t86" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, m48t86_rtc_of_ids);
+
static struct platform_driver m48t86_rtc_platform_driver = {
.driver = {
.name = "rtc-m48t86",
+ .of_match_table = m48t86_rtc_of_ids,
},
.probe = m48t86_rtc_probe,
};
diff --git a/drivers/rtc/rtc-ma35d1.c b/drivers/rtc/rtc-ma35d1.c
new file mode 100644
index 000000000000..cfcfc28060f6
--- /dev/null
+++ b/drivers/rtc/rtc-ma35d1.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RTC driver for Nuvoton MA35D1
+ *
+ * Copyright (C) 2023 Nuvoton Technology Corp.
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+/* MA35D1 RTC Control Registers */
+#define MA35_REG_RTC_INIT 0x00
+#define MA35_REG_RTC_SINFASTS 0x04
+#define MA35_REG_RTC_FREQADJ 0x08
+#define MA35_REG_RTC_TIME 0x0c
+#define MA35_REG_RTC_CAL 0x10
+#define MA35_REG_RTC_CLKFMT 0x14
+#define MA35_REG_RTC_WEEKDAY 0x18
+#define MA35_REG_RTC_TALM 0x1c
+#define MA35_REG_RTC_CALM 0x20
+#define MA35_REG_RTC_LEAPYEAR 0x24
+#define MA35_REG_RTC_INTEN 0x28
+#define MA35_REG_RTC_INTSTS 0x2c
+
+/* register MA35_REG_RTC_INIT */
+#define RTC_INIT_ACTIVE BIT(0)
+#define RTC_INIT_MAGIC_CODE 0xa5eb1357
+
+/* register MA35_REG_RTC_CLKFMT */
+#define RTC_CLKFMT_24HEN BIT(0)
+#define RTC_CLKFMT_DCOMPEN BIT(16)
+
+/* register MA35_REG_RTC_INTEN */
+#define RTC_INTEN_ALMIEN BIT(0)
+#define RTC_INTEN_UIEN BIT(1)
+#define RTC_INTEN_CLKFIEN BIT(24)
+#define RTC_INTEN_CLKSTIEN BIT(25)
+
+/* register MA35_REG_RTC_INTSTS */
+#define RTC_INTSTS_ALMIF BIT(0)
+#define RTC_INTSTS_UIF BIT(1)
+#define RTC_INTSTS_CLKFIF BIT(24)
+#define RTC_INTSTS_CLKSTIF BIT(25)
+
+#define RTC_INIT_TIMEOUT 250
+
+struct ma35_rtc {
+ int irq_num;
+ void __iomem *rtc_reg;
+ struct rtc_device *rtcdev;
+};
+
+static u32 rtc_reg_read(struct ma35_rtc *p, u32 offset)
+{
+ return __raw_readl(p->rtc_reg + offset);
+}
+
+static inline void rtc_reg_write(struct ma35_rtc *p, u32 offset, u32 value)
+{
+ __raw_writel(value, p->rtc_reg + offset);
+}
+
+static irqreturn_t ma35d1_rtc_interrupt(int irq, void *data)
+{
+ struct ma35_rtc *rtc = (struct ma35_rtc *)data;
+ unsigned long events = 0, rtc_irq;
+
+ rtc_irq = rtc_reg_read(rtc, MA35_REG_RTC_INTSTS);
+
+ if (rtc_irq & RTC_INTSTS_ALMIF) {
+ rtc_reg_write(rtc, MA35_REG_RTC_INTSTS, RTC_INTSTS_ALMIF);
+ events |= RTC_AF | RTC_IRQF;
+ }
+
+ rtc_update_irq(rtc->rtcdev, 1, events);
+
+ return IRQ_HANDLED;
+}
+
+static int ma35d1_rtc_init(struct ma35_rtc *rtc, u32 ms_timeout)
+{
+ const unsigned long timeout = jiffies + msecs_to_jiffies(ms_timeout);
+
+ do {
+ if (rtc_reg_read(rtc, MA35_REG_RTC_INIT) & RTC_INIT_ACTIVE)
+ return 0;
+
+ rtc_reg_write(rtc, MA35_REG_RTC_INIT, RTC_INIT_MAGIC_CODE);
+
+ mdelay(1);
+
+ } while (time_before(jiffies, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static int ma35d1_alarm_irq_enable(struct device *dev, u32 enabled)
+{
+ struct ma35_rtc *rtc = dev_get_drvdata(dev);
+ u32 reg_ien;
+
+ reg_ien = rtc_reg_read(rtc, MA35_REG_RTC_INTEN);
+
+ if (enabled)
+ rtc_reg_write(rtc, MA35_REG_RTC_INTEN, reg_ien | RTC_INTEN_ALMIEN);
+ else
+ rtc_reg_write(rtc, MA35_REG_RTC_INTEN, reg_ien & ~RTC_INTEN_ALMIEN);
+
+ return 0;
+}
+
+static int ma35d1_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ma35_rtc *rtc = dev_get_drvdata(dev);
+ u32 time, cal, wday;
+
+ do {
+ time = rtc_reg_read(rtc, MA35_REG_RTC_TIME);
+ cal = rtc_reg_read(rtc, MA35_REG_RTC_CAL);
+ wday = rtc_reg_read(rtc, MA35_REG_RTC_WEEKDAY);
+ } while (time != rtc_reg_read(rtc, MA35_REG_RTC_TIME) ||
+ cal != rtc_reg_read(rtc, MA35_REG_RTC_CAL));
+
+ tm->tm_mday = bcd2bin(cal >> 0);
+ tm->tm_wday = wday;
+ tm->tm_mon = bcd2bin(cal >> 8);
+ tm->tm_mon = tm->tm_mon - 1;
+ tm->tm_year = bcd2bin(cal >> 16) + 100;
+
+ tm->tm_sec = bcd2bin(time >> 0);
+ tm->tm_min = bcd2bin(time >> 8);
+ tm->tm_hour = bcd2bin(time >> 16);
+
+ return rtc_valid_tm(tm);
+}
+
+static int ma35d1_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ma35_rtc *rtc = dev_get_drvdata(dev);
+ u32 val;
+
+ val = bin2bcd(tm->tm_mday) << 0 | bin2bcd(tm->tm_mon + 1) << 8 |
+ bin2bcd(tm->tm_year - 100) << 16;
+ rtc_reg_write(rtc, MA35_REG_RTC_CAL, val);
+
+ val = bin2bcd(tm->tm_sec) << 0 | bin2bcd(tm->tm_min) << 8 |
+ bin2bcd(tm->tm_hour) << 16;
+ rtc_reg_write(rtc, MA35_REG_RTC_TIME, val);
+
+ val = tm->tm_wday;
+ rtc_reg_write(rtc, MA35_REG_RTC_WEEKDAY, val);
+
+ return 0;
+}
+
+static int ma35d1_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct ma35_rtc *rtc = dev_get_drvdata(dev);
+ u32 talm, calm;
+
+ talm = rtc_reg_read(rtc, MA35_REG_RTC_TALM);
+ calm = rtc_reg_read(rtc, MA35_REG_RTC_CALM);
+
+ alrm->time.tm_mday = bcd2bin(calm >> 0);
+ alrm->time.tm_mon = bcd2bin(calm >> 8);
+ alrm->time.tm_mon = alrm->time.tm_mon - 1;
+
+ alrm->time.tm_year = bcd2bin(calm >> 16) + 100;
+
+ alrm->time.tm_sec = bcd2bin(talm >> 0);
+ alrm->time.tm_min = bcd2bin(talm >> 8);
+ alrm->time.tm_hour = bcd2bin(talm >> 16);
+
+ return rtc_valid_tm(&alrm->time);
+}
+
+static int ma35d1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct ma35_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long val;
+
+ val = bin2bcd(alrm->time.tm_mday) << 0 | bin2bcd(alrm->time.tm_mon + 1) << 8 |
+ bin2bcd(alrm->time.tm_year - 100) << 16;
+ rtc_reg_write(rtc, MA35_REG_RTC_CALM, val);
+
+ val = bin2bcd(alrm->time.tm_sec) << 0 | bin2bcd(alrm->time.tm_min) << 8 |
+ bin2bcd(alrm->time.tm_hour) << 16;
+ rtc_reg_write(rtc, MA35_REG_RTC_TALM, val);
+
+ ma35d1_alarm_irq_enable(dev, alrm->enabled);
+
+ return 0;
+}
+
+static const struct rtc_class_ops ma35d1_rtc_ops = {
+ .read_time = ma35d1_rtc_read_time,
+ .set_time = ma35d1_rtc_set_time,
+ .read_alarm = ma35d1_rtc_read_alarm,
+ .set_alarm = ma35d1_rtc_set_alarm,
+ .alarm_irq_enable = ma35d1_alarm_irq_enable,
+};
+
+static int ma35d1_rtc_probe(struct platform_device *pdev)
+{
+ struct ma35_rtc *rtc;
+ struct clk *clk;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->rtc_reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rtc->rtc_reg))
+ return PTR_ERR(rtc->rtc_reg);
+
+ clk = of_clk_get(pdev->dev.of_node, 0);
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk), "failed to find rtc clock\n");
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+
+ if (!(rtc_reg_read(rtc, MA35_REG_RTC_INIT) & RTC_INIT_ACTIVE)) {
+ ret = ma35d1_rtc_init(rtc, RTC_INIT_TIMEOUT);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "rtc init failed\n");
+ }
+
+ rtc->irq_num = platform_get_irq(pdev, 0);
+
+ ret = devm_request_irq(&pdev->dev, rtc->irq_num, ma35d1_rtc_interrupt,
+ IRQF_NO_SUSPEND, "ma35d1rtc", rtc);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to request rtc irq\n");
+
+ platform_set_drvdata(pdev, rtc);
+
+ device_init_wakeup(&pdev->dev, true);
+
+ rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc->rtcdev))
+ return PTR_ERR(rtc->rtcdev);
+
+ rtc->rtcdev->ops = &ma35d1_rtc_ops;
+ rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
+
+ ret = devm_rtc_register_device(rtc->rtcdev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to register rtc device\n");
+
+ return 0;
+}
+
+static int ma35d1_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ma35_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(rtc->irq_num);
+
+ return 0;
+}
+
+static int ma35d1_rtc_resume(struct platform_device *pdev)
+{
+ struct ma35_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(rtc->irq_num);
+
+ return 0;
+}
+
+static const struct of_device_id ma35d1_rtc_of_match[] = {
+ { .compatible = "nuvoton,ma35d1-rtc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ma35d1_rtc_of_match);
+
+static struct platform_driver ma35d1_rtc_driver = {
+ .suspend = ma35d1_rtc_suspend,
+ .resume = ma35d1_rtc_resume,
+ .probe = ma35d1_rtc_probe,
+ .driver = {
+ .name = "rtc-ma35d1",
+ .of_match_table = ma35d1_rtc_of_match,
+ },
+};
+
+module_platform_driver(ma35d1_rtc_driver);
+
+MODULE_AUTHOR("Ming-Jen Chen <mjchen@nuvoton.com>");
+MODULE_DESCRIPTION("MA35D1 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c
new file mode 100644
index 000000000000..dfb5bad3a369
--- /dev/null
+++ b/drivers/rtc/rtc-max31335.c
@@ -0,0 +1,778 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RTC driver for the MAX31335
+ *
+ * Copyright (C) 2023 Analog Devices
+ *
+ * Antoniu Miclaus <antoniu.miclaus@analog.com>
+ *
+ */
+
+#include <linux/unaligned.h>
+#include <linux/bcd.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/util_macros.h>
+
+/* MAX31335 Register Map */
+#define MAX31335_STATUS1 0x00
+#define MAX31335_INT_EN1 0x01
+#define MAX31335_STATUS2 0x02
+#define MAX31335_INT_EN2 0x03
+#define MAX31335_RTC_RESET 0x04
+#define MAX31335_RTC_CONFIG 0x05
+#define MAX31335_RTC_CONFIG2 0x06
+#define MAX31335_TIMESTAMP_CONFIG 0x07
+#define MAX31335_TIMER_CONFIG 0x08
+#define MAX31335_SECONDS_1_128 0x09
+#define MAX31335_SECONDS 0x0A
+#define MAX31335_MINUTES 0x0B
+#define MAX31335_HOURS 0x0C
+#define MAX31335_DAY 0x0D
+#define MAX31335_DATE 0x0E
+#define MAX31335_MONTH 0x0F
+#define MAX31335_YEAR 0x0F
+#define MAX31335_ALM1_SEC 0x11
+#define MAX31335_ALM1_MIN 0x12
+#define MAX31335_ALM1_HRS 0x13
+#define MAX31335_ALM1_DAY_DATE 0x14
+#define MAX31335_ALM1_MON 0x15
+#define MAX31335_ALM1_YEAR 0x16
+#define MAX31335_ALM2_MIN 0x17
+#define MAX31335_ALM2_HRS 0x18
+#define MAX31335_ALM2_DAY_DATE 0x19
+#define MAX31335_TIMER_COUNT 0x1A
+#define MAX31335_TIMER_INIT 0x1B
+#define MAX31335_PWR_MGMT 0x1C
+#define MAX31335_TRICKLE_REG 0x1D
+#define MAX31335_AGING_OFFSET 0x1E
+#define MAX31335_TS_CONFIG 0x30
+#define MAX31335_TEMP_ALARM_HIGH_MSB 0x31
+#define MAX31335_TEMP_ALARM_HIGH_LSB 0x32
+#define MAX31335_TEMP_ALARM_LOW_MSB 0x33
+#define MAX31335_TEMP_ALARM_LOW_LSB 0x34
+#define MAX31335_TEMP_DATA_MSB 0x35
+#define MAX31335_TEMP_DATA_LSB 0x36
+#define MAX31335_TS0_SEC_1_128 0x40
+#define MAX31335_TS0_SEC 0x41
+#define MAX31335_TS0_MIN 0x42
+#define MAX31335_TS0_HOUR 0x43
+#define MAX31335_TS0_DATE 0x44
+#define MAX31335_TS0_MONTH 0x45
+#define MAX31335_TS0_YEAR 0x46
+#define MAX31335_TS0_FLAGS 0x47
+#define MAX31335_TS1_SEC_1_128 0x48
+#define MAX31335_TS1_SEC 0x49
+#define MAX31335_TS1_MIN 0x4A
+#define MAX31335_TS1_HOUR 0x4B
+#define MAX31335_TS1_DATE 0x4C
+#define MAX31335_TS1_MONTH 0x4D
+#define MAX31335_TS1_YEAR 0x4E
+#define MAX31335_TS1_FLAGS 0x4F
+#define MAX31335_TS2_SEC_1_128 0x50
+#define MAX31335_TS2_SEC 0x51
+#define MAX31335_TS2_MIN 0x52
+#define MAX31335_TS2_HOUR 0x53
+#define MAX31335_TS2_DATE 0x54
+#define MAX31335_TS2_MONTH 0x55
+#define MAX31335_TS2_YEAR 0x56
+#define MAX31335_TS2_FLAGS 0x57
+#define MAX31335_TS3_SEC_1_128 0x58
+#define MAX31335_TS3_SEC 0x59
+#define MAX31335_TS3_MIN 0x5A
+#define MAX31335_TS3_HOUR 0x5B
+#define MAX31335_TS3_DATE 0x5C
+#define MAX31335_TS3_MONTH 0x5D
+#define MAX31335_TS3_YEAR 0x5E
+#define MAX31335_TS3_FLAGS 0x5F
+
+/* MAX31335_STATUS1 Bit Definitions */
+#define MAX31335_STATUS1_PSDECT BIT(7)
+#define MAX31335_STATUS1_OSF BIT(6)
+#define MAX31335_STATUS1_PFAIL BIT(5)
+#define MAX31335_STATUS1_VBATLOW BIT(4)
+#define MAX31335_STATUS1_DIF BIT(3)
+#define MAX31335_STATUS1_TIF BIT(2)
+#define MAX31335_STATUS1_A2F BIT(1)
+#define MAX31335_STATUS1_A1F BIT(0)
+
+/* MAX31335_INT_EN1 Bit Definitions */
+#define MAX31335_INT_EN1_DOSF BIT(6)
+#define MAX31335_INT_EN1_PFAILE BIT(5)
+#define MAX31335_INT_EN1_VBATLOWE BIT(4)
+#define MAX31335_INT_EN1_DIE BIT(3)
+#define MAX31335_INT_EN1_TIE BIT(2)
+#define MAX31335_INT_EN1_A2IE BIT(1)
+#define MAX31335_INT_EN1_A1IE BIT(0)
+
+/* MAX31335_STATUS2 Bit Definitions */
+#define MAX31335_STATUS2_TEMP_RDY BIT(2)
+#define MAX31335_STATUS2_OTF BIT(1)
+#define MAX31335_STATUS2_UTF BIT(0)
+
+/* MAX31335_INT_EN2 Bit Definitions */
+#define MAX31335_INT_EN2_TEMP_RDY_EN BIT(2)
+#define MAX31335_INT_EN2_OTIE BIT(1)
+#define MAX31335_INT_EN2_UTIE BIT(0)
+
+/* MAX31335_RTC_RESET Bit Definitions */
+#define MAX31335_RTC_RESET_SWRST BIT(0)
+
+/* MAX31335_RTC_CONFIG1 Bit Definitions */
+#define MAX31335_RTC_CONFIG1_EN_IO BIT(6)
+#define MAX31335_RTC_CONFIG1_A1AC GENMASK(5, 4)
+#define MAX31335_RTC_CONFIG1_DIP BIT(3)
+#define MAX31335_RTC_CONFIG1_I2C_TIMEOUT BIT(1)
+#define MAX31335_RTC_CONFIG1_EN_OSC BIT(0)
+
+/* MAX31335_RTC_CONFIG2 Bit Definitions */
+#define MAX31335_RTC_CONFIG2_ENCLKO BIT(2)
+#define MAX31335_RTC_CONFIG2_CLKO_HZ GENMASK(1, 0)
+
+/* MAX31335_TIMESTAMP_CONFIG Bit Definitions */
+#define MAX31335_TIMESTAMP_CONFIG_TSVLOW BIT(5)
+#define MAX31335_TIMESTAMP_CONFIG_TSPWM BIT(4)
+#define MAX31335_TIMESTAMP_CONFIG_TSDIN BIT(3)
+#define MAX31335_TIMESTAMP_CONFIG_TSOW BIT(2)
+#define MAX31335_TIMESTAMP_CONFIG_TSR BIT(1)
+#define MAX31335_TIMESTAMP_CONFIG_TSE BIT(0)
+
+/* MAX31335_TIMER_CONFIG Bit Definitions */
+#define MAX31335_TIMER_CONFIG_TE BIT(4)
+#define MAX31335_TIMER_CONFIG_TPAUSE BIT(3)
+#define MAX31335_TIMER_CONFIG_TRPT BIT(2)
+#define MAX31335_TIMER_CONFIG_TFS GENMASK(1, 0)
+
+/* MAX31335_HOURS Bit Definitions */
+#define MAX31335_HOURS_F_24_12 BIT(6)
+#define MAX31335_HOURS_HR_20_AM_PM BIT(5)
+
+/* MAX31335_MONTH Bit Definitions */
+#define MAX31335_MONTH_CENTURY BIT(7)
+
+/* MAX31335_PWR_MGMT Bit Definitions */
+#define MAX31335_PWR_MGMT_PFVT BIT(0)
+
+/* MAX31335_TRICKLE_REG Bit Definitions */
+#define MAX31335_TRICKLE_REG_TRICKLE GENMASK(3, 1)
+#define MAX31335_TRICKLE_REG_EN_TRICKLE BIT(0)
+
+/* MAX31335_TS_CONFIG Bit Definitions */
+#define MAX31335_TS_CONFIG_AUTO BIT(4)
+#define MAX31335_TS_CONFIG_CONVERT_T BIT(3)
+#define MAX31335_TS_CONFIG_TSINT GENMASK(2, 0)
+
+/* MAX31335_TS_FLAGS Bit Definitions */
+#define MAX31335_TS_FLAGS_VLOWF BIT(3)
+#define MAX31335_TS_FLAGS_VBATF BIT(2)
+#define MAX31335_TS_FLAGS_VCCF BIT(1)
+#define MAX31335_TS_FLAGS_DINF BIT(0)
+
+/* MAX31335 Miscellaneous Definitions */
+#define MAX31335_TRICKLE_SCHOTTKY_DIODE 1
+#define MAX31335_TRICKLE_STANDARD_DIODE 4
+#define MAX31335_RAM_SIZE 32
+#define MAX31335_TIME_SIZE 0x07
+
+/* MAX31331 Register Map */
+#define MAX31331_RTC_CONFIG2 0x04
+
+#define clk_hw_to_max31335(_hw) container_of(_hw, struct max31335_data, clkout)
+
+/* Supported Maxim RTC */
+enum max_rtc_ids {
+ ID_MAX31331,
+ ID_MAX31335,
+ MAX_RTC_ID_NR
+};
+
+struct chip_desc {
+ u8 sec_reg;
+ u8 alarm1_sec_reg;
+
+ u8 int_en_reg;
+ u8 int_status_reg;
+
+ u8 ram_reg;
+ u8 ram_size;
+
+ u8 temp_reg;
+
+ u8 trickle_reg;
+
+ u8 clkout_reg;
+
+ enum max_rtc_ids id;
+};
+
+struct max31335_data {
+ struct regmap *regmap;
+ struct rtc_device *rtc;
+ struct clk_hw clkout;
+ struct clk *clkin;
+ const struct chip_desc *chip;
+ int irq;
+};
+
+static const int max31335_clkout_freq[] = { 1, 64, 1024, 32768 };
+
+static const struct chip_desc chip[MAX_RTC_ID_NR] = {
+ [ID_MAX31331] = {
+ .id = ID_MAX31331,
+ .int_en_reg = 0x01,
+ .int_status_reg = 0x00,
+ .sec_reg = 0x08,
+ .alarm1_sec_reg = 0x0F,
+ .ram_reg = 0x20,
+ .ram_size = 32,
+ .trickle_reg = 0x1B,
+ .clkout_reg = 0x04,
+ },
+ [ID_MAX31335] = {
+ .id = ID_MAX31335,
+ .int_en_reg = 0x01,
+ .int_status_reg = 0x00,
+ .sec_reg = 0x0A,
+ .alarm1_sec_reg = 0x11,
+ .ram_reg = 0x40,
+ .ram_size = 32,
+ .temp_reg = 0x35,
+ .trickle_reg = 0x1D,
+ .clkout_reg = 0x06,
+ },
+};
+
+static const u16 max31335_trickle_resistors[] = {3000, 6000, 11000};
+
+static bool max31335_volatile_reg(struct device *dev, unsigned int reg)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+ const struct chip_desc *chip = max31335->chip;
+
+ /* time keeping registers */
+ if (reg >= chip->sec_reg && reg < chip->sec_reg + MAX31335_TIME_SIZE)
+ return true;
+
+ /* interrupt status register */
+ if (reg == chip->int_status_reg)
+ return true;
+
+ /* temperature registers if valid */
+ if (chip->temp_reg && (reg == chip->temp_reg || reg == chip->temp_reg + 1))
+ return true;
+
+ return false;
+}
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x5F,
+ .volatile_reg = max31335_volatile_reg,
+};
+
+static int max31335_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+ u8 date[7];
+ int ret;
+
+ ret = regmap_bulk_read(max31335->regmap, max31335->chip->sec_reg, date,
+ sizeof(date));
+ if (ret)
+ return ret;
+
+ tm->tm_sec = bcd2bin(date[0] & 0x7f);
+ tm->tm_min = bcd2bin(date[1] & 0x7f);
+ tm->tm_hour = bcd2bin(date[2] & 0x3f);
+ tm->tm_wday = bcd2bin(date[3] & 0x7) - 1;
+ tm->tm_mday = bcd2bin(date[4] & 0x3f);
+ tm->tm_mon = bcd2bin(date[5] & 0x1f) - 1;
+ tm->tm_year = bcd2bin(date[6]) + 100;
+
+ if (FIELD_GET(MAX31335_MONTH_CENTURY, date[5]))
+ tm->tm_year += 100;
+
+ return 0;
+}
+
+static int max31335_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+ u8 date[7];
+
+ date[0] = bin2bcd(tm->tm_sec);
+ date[1] = bin2bcd(tm->tm_min);
+ date[2] = bin2bcd(tm->tm_hour);
+ date[3] = bin2bcd(tm->tm_wday + 1);
+ date[4] = bin2bcd(tm->tm_mday);
+ date[5] = bin2bcd(tm->tm_mon + 1);
+ date[6] = bin2bcd(tm->tm_year % 100);
+
+ if (tm->tm_year >= 200)
+ date[5] |= FIELD_PREP(MAX31335_MONTH_CENTURY, 1);
+
+ return regmap_bulk_write(max31335->regmap, max31335->chip->sec_reg, date,
+ sizeof(date));
+}
+
+static int max31335_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+ int ret, ctrl, status;
+ struct rtc_time time;
+ u8 regs[6];
+
+ ret = regmap_bulk_read(max31335->regmap, max31335->chip->alarm1_sec_reg, regs,
+ sizeof(regs));
+ if (ret)
+ return ret;
+
+ alrm->time.tm_sec = bcd2bin(regs[0] & 0x7f);
+ alrm->time.tm_min = bcd2bin(regs[1] & 0x7f);
+ alrm->time.tm_hour = bcd2bin(regs[2] & 0x3f);
+ alrm->time.tm_mday = bcd2bin(regs[3] & 0x3f);
+ alrm->time.tm_mon = bcd2bin(regs[4] & 0x1f) - 1;
+ alrm->time.tm_year = bcd2bin(regs[5]) + 100;
+
+ ret = max31335_read_time(dev, &time);
+ if (ret)
+ return ret;
+
+ if (time.tm_year >= 200)
+ alrm->time.tm_year += 100;
+
+ ret = regmap_read(max31335->regmap, max31335->chip->int_en_reg, &ctrl);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(max31335->regmap, max31335->chip->int_status_reg, &status);
+ if (ret)
+ return ret;
+
+ alrm->enabled = FIELD_GET(MAX31335_INT_EN1_A1IE, ctrl);
+ alrm->pending = FIELD_GET(MAX31335_STATUS1_A1F, status);
+
+ return 0;
+}
+
+static int max31335_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+ unsigned int reg;
+ u8 regs[6];
+ int ret;
+
+ regs[0] = bin2bcd(alrm->time.tm_sec);
+ regs[1] = bin2bcd(alrm->time.tm_min);
+ regs[2] = bin2bcd(alrm->time.tm_hour);
+ regs[3] = bin2bcd(alrm->time.tm_mday);
+ regs[4] = bin2bcd(alrm->time.tm_mon + 1);
+ regs[5] = bin2bcd(alrm->time.tm_year % 100);
+
+ ret = regmap_bulk_write(max31335->regmap, max31335->chip->alarm1_sec_reg,
+ regs, sizeof(regs));
+ if (ret)
+ return ret;
+
+ reg = FIELD_PREP(MAX31335_INT_EN1_A1IE, alrm->enabled);
+ ret = regmap_update_bits(max31335->regmap, max31335->chip->int_en_reg,
+ MAX31335_INT_EN1_A1IE, reg);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg,
+ MAX31335_STATUS1_A1F, 0);
+
+ return 0;
+}
+
+static int max31335_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+
+ return regmap_update_bits(max31335->regmap, max31335->chip->int_en_reg,
+ MAX31335_INT_EN1_A1IE, enabled);
+}
+
+static irqreturn_t max31335_handle_irq(int irq, void *dev_id)
+{
+ struct max31335_data *max31335 = dev_id;
+ struct mutex *lock = &max31335->rtc->ops_lock;
+ int ret, status;
+
+ mutex_lock(lock);
+
+ ret = regmap_read(max31335->regmap, max31335->chip->int_status_reg, &status);
+ if (ret)
+ goto exit;
+
+ if (FIELD_GET(MAX31335_STATUS1_A1F, status)) {
+ ret = regmap_update_bits(max31335->regmap, max31335->chip->int_status_reg,
+ MAX31335_STATUS1_A1F, 0);
+ if (ret)
+ goto exit;
+
+ rtc_update_irq(max31335->rtc, 1, RTC_AF | RTC_IRQF);
+ }
+
+exit:
+ mutex_unlock(lock);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops max31335_rtc_ops = {
+ .read_time = max31335_read_time,
+ .set_time = max31335_set_time,
+ .read_alarm = max31335_read_alarm,
+ .set_alarm = max31335_set_alarm,
+ .alarm_irq_enable = max31335_alarm_irq_enable,
+};
+
+static int max31335_trickle_charger_setup(struct device *dev,
+ struct max31335_data *max31335)
+{
+ u32 ohms, chargeable;
+ int i, trickle_cfg;
+ const char *diode;
+
+ if (device_property_read_u32(dev, "aux-voltage-chargeable",
+ &chargeable))
+ return 0;
+
+ if (device_property_read_u32(dev, "trickle-resistor-ohms", &ohms))
+ return 0;
+
+ if (device_property_read_string(dev, "adi,tc-diode", &diode))
+ return 0;
+
+ if (!strcmp(diode, "schottky"))
+ trickle_cfg = MAX31335_TRICKLE_SCHOTTKY_DIODE;
+ else if (!strcmp(diode, "standard+schottky"))
+ trickle_cfg = MAX31335_TRICKLE_STANDARD_DIODE;
+ else
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid tc-diode value: %s\n", diode);
+
+ for (i = 0; i < ARRAY_SIZE(max31335_trickle_resistors); i++)
+ if (ohms == max31335_trickle_resistors[i])
+ break;
+
+ if (i >= ARRAY_SIZE(max31335_trickle_resistors))
+ return 0;
+
+ i = i + trickle_cfg;
+
+ return regmap_write(max31335->regmap, max31335->chip->trickle_reg,
+ FIELD_PREP(MAX31335_TRICKLE_REG_TRICKLE, i) |
+ FIELD_PREP(MAX31335_TRICKLE_REG_EN_TRICKLE,
+ chargeable));
+}
+
+static unsigned long max31335_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct max31335_data *max31335 = clk_hw_to_max31335(hw);
+ unsigned int freq_mask;
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(max31335->regmap, max31335->chip->clkout_reg, &reg);
+ if (ret)
+ return 0;
+
+ freq_mask = __roundup_pow_of_two(ARRAY_SIZE(max31335_clkout_freq)) - 1;
+
+ return max31335_clkout_freq[reg & freq_mask];
+}
+
+static int max31335_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ int index;
+
+ index = find_closest(req->rate, max31335_clkout_freq,
+ ARRAY_SIZE(max31335_clkout_freq));
+
+ req->rate = max31335_clkout_freq[index];
+
+ return 0;
+}
+
+static int max31335_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct max31335_data *max31335 = clk_hw_to_max31335(hw);
+ unsigned int freq_mask;
+ int index;
+
+ index = find_closest(rate, max31335_clkout_freq,
+ ARRAY_SIZE(max31335_clkout_freq));
+ freq_mask = __roundup_pow_of_two(ARRAY_SIZE(max31335_clkout_freq)) - 1;
+
+ return regmap_update_bits(max31335->regmap, max31335->chip->clkout_reg,
+ freq_mask, index);
+}
+
+static int max31335_clkout_enable(struct clk_hw *hw)
+{
+ struct max31335_data *max31335 = clk_hw_to_max31335(hw);
+
+ return regmap_set_bits(max31335->regmap, max31335->chip->clkout_reg,
+ MAX31335_RTC_CONFIG2_ENCLKO);
+}
+
+static void max31335_clkout_disable(struct clk_hw *hw)
+{
+ struct max31335_data *max31335 = clk_hw_to_max31335(hw);
+
+ regmap_clear_bits(max31335->regmap, max31335->chip->clkout_reg,
+ MAX31335_RTC_CONFIG2_ENCLKO);
+}
+
+static int max31335_clkout_is_enabled(struct clk_hw *hw)
+{
+ struct max31335_data *max31335 = clk_hw_to_max31335(hw);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(max31335->regmap, max31335->chip->clkout_reg, &reg);
+ if (ret)
+ return ret;
+
+ return !!(reg & MAX31335_RTC_CONFIG2_ENCLKO);
+}
+
+static const struct clk_ops max31335_clkout_ops = {
+ .recalc_rate = max31335_clkout_recalc_rate,
+ .determine_rate = max31335_clkout_determine_rate,
+ .set_rate = max31335_clkout_set_rate,
+ .enable = max31335_clkout_enable,
+ .disable = max31335_clkout_disable,
+ .is_enabled = max31335_clkout_is_enabled,
+};
+
+static struct clk_init_data max31335_clk_init = {
+ .name = "max31335-clkout",
+ .ops = &max31335_clkout_ops,
+};
+
+static int max31335_nvmem_reg_read(void *priv, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct max31335_data *max31335 = priv;
+ unsigned int reg = max31335->chip->ram_reg + offset;
+
+ return regmap_bulk_read(max31335->regmap, reg, val, bytes);
+}
+
+static int max31335_nvmem_reg_write(void *priv, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct max31335_data *max31335 = priv;
+ unsigned int reg = max31335->chip->ram_reg + offset;
+
+ return regmap_bulk_write(max31335->regmap, reg, val, bytes);
+}
+
+static struct nvmem_config max31335_nvmem_cfg = {
+ .reg_read = max31335_nvmem_reg_read,
+ .reg_write = max31335_nvmem_reg_write,
+ .word_size = 8,
+ .size = MAX31335_RAM_SIZE,
+};
+
+#if IS_REACHABLE(HWMON)
+static int max31335_read_temp(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+ u8 reg[2];
+ s16 temp;
+ int ret;
+
+ if (type != hwmon_temp || attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+ ret = regmap_bulk_read(max31335->regmap, max31335->chip->temp_reg,
+ reg, 2);
+ if (ret)
+ return ret;
+
+ temp = get_unaligned_be16(reg);
+
+ *val = (temp / 64) * 250;
+
+ return 0;
+}
+
+static umode_t max31335_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ if (type == hwmon_temp && attr == hwmon_temp_input)
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_channel_info *max31335_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ NULL
+};
+
+static const struct hwmon_ops max31335_hwmon_ops = {
+ .is_visible = max31335_is_visible,
+ .read = max31335_read_temp,
+};
+
+static const struct hwmon_chip_info max31335_chip_info = {
+ .ops = &max31335_hwmon_ops,
+ .info = max31335_info,
+};
+#endif
+
+static int max31335_clkout_register(struct device *dev)
+{
+ struct max31335_data *max31335 = dev_get_drvdata(dev);
+ int ret;
+
+ if (!device_property_present(dev, "#clock-cells"))
+ return regmap_clear_bits(max31335->regmap, max31335->chip->clkout_reg,
+ MAX31335_RTC_CONFIG2_ENCLKO);
+
+ max31335->clkout.init = &max31335_clk_init;
+
+ ret = devm_clk_hw_register(dev, &max31335->clkout);
+ if (ret)
+ return dev_err_probe(dev, ret, "cannot register clock\n");
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &max31335->clkout);
+ if (ret)
+ return dev_err_probe(dev, ret, "cannot add hw provider\n");
+
+ max31335->clkout.clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(max31335->clkout.clk))
+ return dev_err_probe(dev, PTR_ERR(max31335->clkout.clk),
+ "cannot enable clkout\n");
+
+ return 0;
+}
+
+static int max31335_probe(struct i2c_client *client)
+{
+ struct max31335_data *max31335;
+#if IS_REACHABLE(HWMON)
+ struct device *hwmon;
+#endif
+ const struct chip_desc *match;
+ int ret;
+
+ max31335 = devm_kzalloc(&client->dev, sizeof(*max31335), GFP_KERNEL);
+ if (!max31335)
+ return -ENOMEM;
+
+ max31335->regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(max31335->regmap))
+ return PTR_ERR(max31335->regmap);
+
+ i2c_set_clientdata(client, max31335);
+ match = i2c_get_match_data(client);
+ if (!match)
+ return -ENODEV;
+ max31335->chip = match;
+ max31335->rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(max31335->rtc))
+ return PTR_ERR(max31335->rtc);
+
+ max31335->rtc->ops = &max31335_rtc_ops;
+ max31335->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ max31335->rtc->range_max = RTC_TIMESTAMP_END_2199;
+ max31335->rtc->alarm_offset_max = 24 * 60 * 60;
+
+ ret = max31335_clkout_register(&client->dev);
+ if (ret)
+ return ret;
+
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, max31335_handle_irq,
+ IRQF_ONESHOT,
+ "max31335", max31335);
+ if (ret) {
+ dev_warn(&client->dev,
+ "unable to request IRQ, alarm max31335 disabled\n");
+ client->irq = 0;
+ } else {
+ max31335->irq = client->irq;
+ }
+ }
+
+ if (!client->irq)
+ clear_bit(RTC_FEATURE_ALARM, max31335->rtc->features);
+
+ max31335_nvmem_cfg.priv = max31335;
+ ret = devm_rtc_nvmem_register(max31335->rtc, &max31335_nvmem_cfg);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "cannot register rtc nvmem\n");
+
+#if IS_REACHABLE(HWMON)
+ if (max31335->chip->temp_reg) {
+ hwmon = devm_hwmon_device_register_with_info(&client->dev, client->name, max31335,
+ &max31335_chip_info, NULL);
+ if (IS_ERR(hwmon))
+ return dev_err_probe(&client->dev, PTR_ERR(hwmon),
+ "cannot register hwmon device\n");
+ }
+#endif
+
+ ret = max31335_trickle_charger_setup(&client->dev, max31335);
+ if (ret)
+ return ret;
+
+ return devm_rtc_register_device(max31335->rtc);
+}
+
+static const struct i2c_device_id max31335_id[] = {
+ { "max31331", (kernel_ulong_t)&chip[ID_MAX31331] },
+ { "max31335", (kernel_ulong_t)&chip[ID_MAX31335] },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, max31335_id);
+
+static const struct of_device_id max31335_of_match[] = {
+ { .compatible = "adi,max31331", .data = &chip[ID_MAX31331] },
+ { .compatible = "adi,max31335", .data = &chip[ID_MAX31335] },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, max31335_of_match);
+
+static struct i2c_driver max31335_driver = {
+ .driver = {
+ .name = "rtc-max31335",
+ .of_match_table = max31335_of_match,
+ },
+ .probe = max31335_probe,
+ .id_table = max31335_id,
+};
+module_i2c_driver(max31335_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_AUTHOR("Saket Kumar Purwar <Saket.Kumarpurwar@analog.com>");
+MODULE_DESCRIPTION("MAX31335 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index 0a33851cc51f..7be31fce5bc7 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -215,7 +215,7 @@ static int max6900_probe(struct i2c_client *client)
}
static const struct i2c_device_id max6900_id[] = {
- { "max6900", 0 },
+ { "max6900" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6900_id);
@@ -224,7 +224,7 @@ static struct i2c_driver max6900_driver = {
.driver = {
.name = "rtc-max6900",
},
- .probe_new = max6900_probe,
+ .probe = max6900_probe,
.id_table = max6900_id,
};
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index b0250d91fb00..69ea3ce75b5a 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -85,7 +85,6 @@ struct max77686_rtc_driver_data {
struct max77686_rtc_info {
struct device *dev;
- struct i2c_client *rtc;
struct rtc_device *rtc_dev;
struct mutex lock;
@@ -691,6 +690,7 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
{
struct device *parent = info->dev->parent;
struct i2c_client *parent_i2c = to_i2c_client(parent);
+ struct i2c_client *client;
int ret;
if (info->drv_data->rtc_irq_from_platform) {
@@ -704,40 +704,35 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
}
info->regmap = dev_get_regmap(parent, NULL);
- if (!info->regmap) {
- dev_err(info->dev, "Failed to get rtc regmap\n");
- return -ENODEV;
- }
+ if (!info->regmap)
+ return dev_err_probe(info->dev, -ENODEV,
+ "Failed to get rtc regmap\n");
if (info->drv_data->rtc_i2c_addr == MAX77686_INVALID_I2C_ADDR) {
info->rtc_regmap = info->regmap;
goto add_rtc_irq;
}
- info->rtc = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter,
- info->drv_data->rtc_i2c_addr);
- if (IS_ERR(info->rtc)) {
- dev_err(info->dev, "Failed to allocate I2C device for RTC\n");
- return PTR_ERR(info->rtc);
- }
+ client = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter,
+ info->drv_data->rtc_i2c_addr);
+ if (IS_ERR(client))
+ return dev_err_probe(info->dev, PTR_ERR(client),
+ "Failed to allocate I2C device for RTC\n");
- info->rtc_regmap = devm_regmap_init_i2c(info->rtc,
+ info->rtc_regmap = devm_regmap_init_i2c(client,
info->drv_data->regmap_config);
- if (IS_ERR(info->rtc_regmap)) {
- ret = PTR_ERR(info->rtc_regmap);
- dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(info->rtc_regmap))
+ return dev_err_probe(info->dev, PTR_ERR(info->rtc_regmap),
+ "Failed to allocate RTC regmap\n");
add_rtc_irq:
ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq,
IRQF_ONESHOT | IRQF_SHARED,
0, info->drv_data->rtc_irq_chip,
&info->rtc_irq_data);
- if (ret < 0) {
- dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(info->dev, ret,
+ "Failed to add RTC irq chip\n");
return 0;
}
@@ -770,7 +765,7 @@ static int max77686_rtc_probe(struct platform_device *pdev)
goto err_rtc;
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
info->rtc_dev = devm_rtc_device_register(&pdev->dev, id->name,
&max77686_rtc_ops, THIS_MODULE);
@@ -806,14 +801,12 @@ err_rtc:
return ret;
}
-static int max77686_rtc_remove(struct platform_device *pdev)
+static void max77686_rtc_remove(struct platform_device *pdev)
{
struct max77686_rtc_info *info = platform_get_drvdata(pdev);
free_irq(info->virq, info);
regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c
index db3495d10274..af97140dd00a 100644
--- a/drivers/rtc/rtc-max8907.c
+++ b/drivers/rtc/rtc-max8907.c
@@ -9,7 +9,6 @@
*/
#include <linux/bcd.h>
-#include <linux/i2c.h>
#include <linux/mfd/max8907.h>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c
index 64bb8ac6ef62..6ce8afbeac68 100644
--- a/drivers/rtc/rtc-max8925.c
+++ b/drivers/rtc/rtc-max8925.c
@@ -270,7 +270,7 @@ static int max8925_rtc_probe(struct platform_device *pdev)
/* XXX - isn't this redundant? */
platform_set_drvdata(pdev, info);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8925-rtc",
&max8925_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c
index 20e50d9fdf88..e7618d715bd8 100644
--- a/drivers/rtc/rtc-max8997.c
+++ b/drivers/rtc/rtc-max8997.c
@@ -473,7 +473,7 @@ static int max8997_rtc_probe(struct platform_device *pdev)
max8997_rtc_enable_wtsr(info, true);
max8997_rtc_enable_smpl(info, true);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8997-rtc",
&max8997_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c
index d4234e78497e..2494d13fd767 100644
--- a/drivers/rtc/rtc-mc13xxx.c
+++ b/drivers/rtc/rtc-mc13xxx.c
@@ -137,10 +137,6 @@ static int mc13xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
}
if (!priv->valid) {
- ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
- if (unlikely(ret))
- goto out;
-
ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
}
@@ -208,10 +204,6 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
if (unlikely(ret))
goto out;
- ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TODA);
- if (unlikely(ret))
- goto out;
-
s1970 = rtc_tm_to_time64(&alarm->time);
dev_dbg(dev, "%s: %s %lld\n", __func__, alarm->enabled ? "on" : "off",
@@ -239,12 +231,9 @@ out:
static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)
{
struct mc13xxx_rtc *priv = dev;
- struct mc13xxx *mc13xxx = priv->mc13xxx;
rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
- mc13xxx_irq_ack(mc13xxx, irq);
-
return IRQ_HANDLED;
}
@@ -293,8 +282,6 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
mc13xxx_lock(mc13xxx);
- mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST);
-
ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST,
mc13xxx_rtc_reset_handler, DRIVER_NAME, priv);
if (ret)
@@ -324,7 +311,7 @@ err_irq_request:
return ret;
}
-static int mc13xxx_rtc_remove(struct platform_device *pdev)
+static void mc13xxx_rtc_remove(struct platform_device *pdev)
{
struct mc13xxx_rtc *priv = platform_get_drvdata(pdev);
@@ -334,8 +321,6 @@ static int mc13xxx_rtc_remove(struct platform_device *pdev)
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv);
mc13xxx_unlock(priv->mc13xxx);
-
- return 0;
}
static const struct platform_device_id mc13xxx_rtc_idtable[] = {
diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c
index f1c09f1db044..dbd2d5835f00 100644
--- a/drivers/rtc/rtc-mc146818-lib.c
+++ b/drivers/rtc/rtc-mc146818-lib.c
@@ -8,26 +8,31 @@
#include <linux/acpi.h>
#endif
+#define UIP_RECHECK_DELAY 100 /* usec */
+#define UIP_RECHECK_DELAY_MS (USEC_PER_MSEC / UIP_RECHECK_DELAY)
+#define UIP_RECHECK_LOOPS_MS(x) (x / UIP_RECHECK_DELAY_MS)
+
/*
* Execute a function while the UIP (Update-in-progress) bit of the RTC is
- * unset.
+ * unset. The timeout is configurable by the caller in ms.
*
* Warning: callback may be executed more then once.
*/
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
+ int timeout,
void *param)
{
int i;
unsigned long flags;
unsigned char seconds;
- for (i = 0; i < 100; i++) {
+ for (i = 0; UIP_RECHECK_LOOPS_MS(i) < timeout; i++) {
spin_lock_irqsave(&rtc_lock, flags);
/*
* Check whether there is an update in progress during which the
* readout is unspecified. The maximum update time is ~2ms. Poll
- * every 100 usec for completion.
+ * for completion.
*
* Store the second value before checking UIP so a long lasting
* NMI which happens to hit after the UIP check cannot make
@@ -37,7 +42,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
- udelay(100);
+ udelay(UIP_RECHECK_DELAY);
continue;
}
@@ -56,7 +61,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
*/
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
- udelay(100);
+ udelay(UIP_RECHECK_DELAY);
continue;
}
@@ -72,6 +77,10 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
}
spin_unlock_irqrestore(&rtc_lock, flags);
+ if (UIP_RECHECK_LOOPS_MS(i) >= 100)
+ pr_warn("Reading current time from RTC took around %li ms\n",
+ UIP_RECHECK_LOOPS_MS(i));
+
return true;
}
return false;
@@ -84,7 +93,7 @@ EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
*/
bool mc146818_does_rtc_work(void)
{
- return mc146818_avoid_UIP(NULL, NULL);
+ return mc146818_avoid_UIP(NULL, 1000, NULL);
}
EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
@@ -130,15 +139,27 @@ static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
p->ctrl = CMOS_READ(RTC_CONTROL);
}
-int mc146818_get_time(struct rtc_time *time)
+/**
+ * mc146818_get_time - Get the current time from the RTC
+ * @time: pointer to struct rtc_time to store the current time
+ * @timeout: timeout value in ms
+ *
+ * This function reads the current time from the RTC and stores it in the
+ * provided struct rtc_time. The timeout parameter specifies the maximum
+ * time to wait for the RTC to become ready.
+ *
+ * Return: 0 on success, -ETIMEDOUT if the RTC did not become ready within
+ * the specified timeout, or another error code if an error occurred.
+ */
+int mc146818_get_time(struct rtc_time *time, int timeout)
{
struct mc146818_get_time_callback_param p = {
.time = time
};
- if (!mc146818_avoid_UIP(mc146818_get_time_callback, &p)) {
+ if (!mc146818_avoid_UIP(mc146818_get_time_callback, timeout, &p)) {
memset(time, 0, sizeof(*time));
- return -EIO;
+ return -ETIMEDOUT;
}
if (!(p.ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
@@ -195,7 +216,7 @@ int mc146818_set_time(struct rtc_time *time)
unsigned char save_control, save_freq_select;
unsigned int yrs;
#ifdef CONFIG_MACH_DECSTATION
- unsigned int real_yrs, leap_yr;
+ unsigned int real_yrs;
#endif
unsigned char century = 0;
@@ -211,8 +232,6 @@ int mc146818_set_time(struct rtc_time *time)
#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
- leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
- !((yrs + 1900) % 400));
yrs = 72;
/*
@@ -220,7 +239,7 @@ int mc146818_set_time(struct rtc_time *time)
* for non-leap years, so that Feb, 29th is handled
* correctly.
*/
- if (!leap_yr && mon < 3) {
+ if (!is_leap_year(real_yrs + 1900) && mon < 3) {
real_yrs--;
yrs = 73;
}
diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c
index 0d515b3df571..e12f0f806ec4 100644
--- a/drivers/rtc/rtc-mcp795.c
+++ b/drivers/rtc/rtc-mcp795.c
@@ -450,4 +450,3 @@ module_spi_driver(mcp795_driver);
MODULE_DESCRIPTION("MCP795 RTC SPI Driver");
MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:mcp795");
diff --git a/drivers/rtc/rtc-meson-vrtc.c b/drivers/rtc/rtc-meson-vrtc.c
index 1463c8621561..7d38258cbe37 100644
--- a/drivers/rtc/rtc-meson-vrtc.c
+++ b/drivers/rtc/rtc-meson-vrtc.c
@@ -13,7 +13,6 @@
struct meson_vrtc_data {
void __iomem *io_alarm;
- struct rtc_device *rtc;
unsigned long alarm_time;
bool enabled;
};
@@ -23,7 +22,7 @@ static int meson_vrtc_read_time(struct device *dev, struct rtc_time *tm)
struct timespec64 time;
dev_dbg(dev, "%s\n", __func__);
- ktime_get_raw_ts64(&time);
+ ktime_get_real_ts64(&time);
rtc_time64_to_tm(time.tv_sec, tm);
return 0;
@@ -65,6 +64,7 @@ static const struct rtc_class_ops meson_vrtc_ops = {
static int meson_vrtc_probe(struct platform_device *pdev)
{
struct meson_vrtc_data *vrtc;
+ struct rtc_device *rtc;
vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL);
if (!vrtc)
@@ -74,16 +74,16 @@ static int meson_vrtc_probe(struct platform_device *pdev)
if (IS_ERR(vrtc->io_alarm))
return PTR_ERR(vrtc->io_alarm);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
platform_set_drvdata(pdev, vrtc);
- vrtc->rtc = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(vrtc->rtc))
- return PTR_ERR(vrtc->rtc);
+ rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- vrtc->rtc->ops = &meson_vrtc_ops;
- return devm_rtc_register_device(vrtc->rtc);
+ rtc->ops = &meson_vrtc_ops;
+ return devm_rtc_register_device(rtc);
}
static int __maybe_unused meson_vrtc_suspend(struct device *dev)
@@ -96,7 +96,7 @@ static int __maybe_unused meson_vrtc_suspend(struct device *dev)
long alarm_secs;
struct timespec64 time;
- ktime_get_raw_ts64(&time);
+ ktime_get_real_ts64(&time);
local_time = time.tv_sec;
dev_dbg(dev, "alarm_time = %lus, local_time=%lus\n",
diff --git a/drivers/rtc/rtc-meson.c b/drivers/rtc/rtc-meson.c
index db1d626edca5..21eceb9e2e13 100644
--- a/drivers/rtc/rtc-meson.c
+++ b/drivers/rtc/rtc-meson.c
@@ -59,7 +59,6 @@
#define MESON_STATIC_DEFAULT (MESON_STATIC_BIAS_CUR | MESON_STATIC_VOLTAGE)
struct meson_rtc {
- struct rtc_device *rtc; /* rtc device we created */
struct device *dev; /* device we bound from */
struct reset_control *reset; /* reset source */
struct regulator *vdd; /* voltage input */
@@ -73,7 +72,6 @@ static const struct regmap_config meson_rtc_peripheral_regmap_config = {
.val_bits = 32,
.reg_stride = 4,
.max_register = RTC_REG4,
- .fast_io = true,
};
/* RTC front-end serialiser controls */
@@ -292,6 +290,7 @@ static int meson_rtc_probe(struct platform_device *pdev)
};
struct device *dev = &pdev->dev;
struct meson_rtc *rtc;
+ struct rtc_device *rtc_dev;
void __iomem *base;
int ret;
u32 tm;
@@ -300,16 +299,16 @@ static int meson_rtc_probe(struct platform_device *pdev)
if (!rtc)
return -ENOMEM;
- rtc->rtc = devm_rtc_allocate_device(dev);
- if (IS_ERR(rtc->rtc))
- return PTR_ERR(rtc->rtc);
+ rtc_dev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc_dev))
+ return PTR_ERR(rtc_dev);
platform_set_drvdata(pdev, rtc);
rtc->dev = dev;
- rtc->rtc->ops = &meson_rtc_ops;
- rtc->rtc->range_max = U32_MAX;
+ rtc_dev->ops = &meson_rtc_ops;
+ rtc_dev->range_max = U32_MAX;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -365,11 +364,11 @@ static int meson_rtc_probe(struct platform_device *pdev)
}
meson_rtc_nvmem_config.priv = rtc;
- ret = devm_rtc_nvmem_register(rtc->rtc, &meson_rtc_nvmem_config);
+ ret = devm_rtc_nvmem_register(rtc_dev, &meson_rtc_nvmem_config);
if (ret)
goto out_disable_vdd;
- ret = devm_rtc_register_device(rtc->rtc);
+ ret = devm_rtc_register_device(rtc_dev);
if (ret)
goto out_disable_vdd;
diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c
index 6b24ac9e1cfa..2247dd39ee4b 100644
--- a/drivers/rtc/rtc-moxart.c
+++ b/drivers/rtc/rtc-moxart.c
@@ -10,14 +10,15 @@
* Moxa Technology Co., Ltd. <www.moxa.com>
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/gpio/consumer.h>
#define GPIO_RTC_RESERVED 0x0C
#define GPIO_RTC_DATA_SET 0x10
@@ -55,7 +56,9 @@
struct moxart_rtc {
struct rtc_device *rtc;
spinlock_t rtc_lock;
- int gpio_data, gpio_sclk, gpio_reset;
+ struct gpio_desc *gpio_data;
+ struct gpio_desc *gpio_sclk;
+ struct gpio_desc *gpio_reset;
};
static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181,
@@ -67,10 +70,10 @@ static void moxart_rtc_write_byte(struct device *dev, u8 data)
int i;
for (i = 0; i < 8; i++, data >>= 1) {
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
- gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
udelay(GPIO_RTC_DELAY_TIME);
- gpio_set_value(moxart_rtc->gpio_sclk, 1);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 1);
udelay(GPIO_RTC_DELAY_TIME);
}
}
@@ -82,11 +85,11 @@ static u8 moxart_rtc_read_byte(struct device *dev)
u8 data = 0;
for (i = 0; i < 8; i++) {
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
udelay(GPIO_RTC_DELAY_TIME);
- gpio_set_value(moxart_rtc->gpio_sclk, 1);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 1);
udelay(GPIO_RTC_DELAY_TIME);
- if (gpio_get_value(moxart_rtc->gpio_data))
+ if (gpiod_get_value(moxart_rtc->gpio_data))
data |= (1 << i);
udelay(GPIO_RTC_DELAY_TIME);
}
@@ -101,15 +104,15 @@ static u8 moxart_rtc_read_register(struct device *dev, u8 cmd)
local_irq_save(flags);
- gpio_direction_output(moxart_rtc->gpio_data, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 1);
+ gpiod_direction_output(moxart_rtc->gpio_data, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME);
moxart_rtc_write_byte(dev, cmd);
- gpio_direction_input(moxart_rtc->gpio_data);
+ gpiod_direction_input(moxart_rtc->gpio_data);
udelay(GPIO_RTC_DELAY_TIME);
data = moxart_rtc_read_byte(dev);
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 0);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags);
@@ -124,13 +127,13 @@ static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data)
local_irq_save(flags);
- gpio_direction_output(moxart_rtc->gpio_data, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 1);
+ gpiod_direction_output(moxart_rtc->gpio_data, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME);
moxart_rtc_write_byte(dev, cmd);
moxart_rtc_write_byte(dev, data);
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 0);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags);
@@ -247,53 +250,33 @@ static int moxart_rtc_probe(struct platform_device *pdev)
if (!moxart_rtc)
return -ENOMEM;
- moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node,
- "gpio-rtc-data", 0);
- if (!gpio_is_valid(moxart_rtc->gpio_data)) {
- dev_err(&pdev->dev, "invalid gpio (data): %d\n",
- moxart_rtc->gpio_data);
- return moxart_rtc->gpio_data;
- }
-
- moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node,
- "gpio-rtc-sclk", 0);
- if (!gpio_is_valid(moxart_rtc->gpio_sclk)) {
- dev_err(&pdev->dev, "invalid gpio (sclk): %d\n",
- moxart_rtc->gpio_sclk);
- return moxart_rtc->gpio_sclk;
- }
-
- moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node,
- "gpio-rtc-reset", 0);
- if (!gpio_is_valid(moxart_rtc->gpio_reset)) {
- dev_err(&pdev->dev, "invalid gpio (reset): %d\n",
- moxart_rtc->gpio_reset);
- return moxart_rtc->gpio_reset;
- }
-
- spin_lock_init(&moxart_rtc->rtc_lock);
- platform_set_drvdata(pdev, moxart_rtc);
-
- ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data");
+ moxart_rtc->gpio_data = devm_gpiod_get(&pdev->dev, "rtc-data",
+ GPIOD_IN);
+ ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_data);
if (ret) {
- dev_err(&pdev->dev, "can't get rtc_data gpio\n");
+ dev_err(&pdev->dev, "can't get rtc data gpio: %d\n", ret);
return ret;
}
- ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk,
- GPIOF_DIR_OUT, "rtc_sclk");
+ moxart_rtc->gpio_sclk = devm_gpiod_get(&pdev->dev, "rtc-sclk",
+ GPIOD_ASIS);
+ ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_sclk);
if (ret) {
- dev_err(&pdev->dev, "can't get rtc_sclk gpio\n");
+ dev_err(&pdev->dev, "can't get rtc sclk gpio: %d\n", ret);
return ret;
}
- ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset,
- GPIOF_DIR_OUT, "rtc_reset");
+ moxart_rtc->gpio_reset = devm_gpiod_get(&pdev->dev, "rtc-reset",
+ GPIOD_ASIS);
+ ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_reset);
if (ret) {
- dev_err(&pdev->dev, "can't get rtc_reset gpio\n");
+ dev_err(&pdev->dev, "can't get rtc reset gpio: %d\n", ret);
return ret;
}
+ spin_lock_init(&moxart_rtc->rtc_lock);
+ platform_set_drvdata(pdev, moxart_rtc);
+
moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&moxart_rtc_ops,
THIS_MODULE);
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index 6d7656a75cae..b90f8337a7e6 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -11,10 +11,8 @@
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
@@ -305,7 +303,7 @@ static int mpc5121_rtc_probe(struct platform_device *op)
return PTR_ERR(rtc->regs);
}
- device_init_wakeup(&op->dev, 1);
+ device_init_wakeup(&op->dev, true);
platform_set_drvdata(op, rtc);
@@ -372,7 +370,7 @@ out_dispose:
return err;
}
-static int mpc5121_rtc_remove(struct platform_device *op)
+static void mpc5121_rtc_remove(struct platform_device *op)
{
struct mpc5121_rtc_data *rtc = platform_get_drvdata(op);
struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
@@ -383,8 +381,6 @@ static int mpc5121_rtc_remove(struct platform_device *op)
irq_dispose_mapping(rtc->irq);
irq_dispose_mapping(rtc->irq_periodic);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -407,5 +403,6 @@ static struct platform_driver mpc5121_rtc_driver = {
module_platform_driver(mpc5121_rtc_driver);
+MODULE_DESCRIPTION("Freescale MPC5121 built-in RTC driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
index 2a479d44f198..6aa3eae575d2 100644
--- a/drivers/rtc/rtc-mpfs.c
+++ b/drivers/rtc/rtc-mpfs.c
@@ -266,21 +266,14 @@ static int mpfs_rtc_probe(struct platform_device *pdev)
writel(prescaler, rtcdev->base + PRESCALER_REG);
dev_info(&pdev->dev, "prescaler set to: %lu\n", prescaler);
- device_init_wakeup(&pdev->dev, true);
- ret = dev_pm_set_wake_irq(&pdev->dev, wakeup_irq);
+ devm_device_init_wakeup(&pdev->dev);
+ ret = devm_pm_set_wake_irq(&pdev->dev, wakeup_irq);
if (ret)
dev_err(&pdev->dev, "failed to enable irq wake\n");
return devm_rtc_register_device(rtcdev->rtc);
}
-static int mpfs_rtc_remove(struct platform_device *pdev)
-{
- dev_pm_clear_wake_irq(&pdev->dev);
-
- return 0;
-}
-
static const struct of_device_id mpfs_rtc_of_match[] = {
{ .compatible = "microchip,mpfs-rtc" },
{ }
@@ -290,7 +283,6 @@ MODULE_DEVICE_TABLE(of, mpfs_rtc_of_match);
static struct platform_driver mpfs_rtc_driver = {
.probe = mpfs_rtc_probe,
- .remove = mpfs_rtc_remove,
.driver = {
.name = "mpfs_rtc",
.of_match_table = mpfs_rtc_of_match,
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 1d297af80f87..692c00ff544b 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -9,7 +9,7 @@
#include <linux/mfd/mt6397/core.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
@@ -75,6 +75,7 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
tm->tm_min = data[RTC_OFFSET_MIN];
tm->tm_hour = data[RTC_OFFSET_HOUR];
tm->tm_mday = data[RTC_OFFSET_DOM];
+ tm->tm_wday = data[RTC_OFFSET_DOW];
tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK;
tm->tm_year = data[RTC_OFFSET_YEAR];
@@ -86,9 +87,8 @@ exit:
static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- time64_t time;
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
- int days, sec, ret;
+ int sec, ret;
do {
ret = __mtk_rtc_read_time(rtc, tm, &sec);
@@ -96,21 +96,9 @@ static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
goto exit;
} while (sec < tm->tm_sec);
- /* HW register use 7 bits to store year data, minus
- * RTC_MIN_YEAR_OFFSET before write year data to register, and plus
- * RTC_MIN_YEAR_OFFSET back after read year from register
- */
- tm->tm_year += RTC_MIN_YEAR_OFFSET;
-
- /* HW register start mon from one, but tm_mon start from zero. */
+ /* HW register start mon/wday from one, but tm_mon/tm_wday start from zero. */
tm->tm_mon--;
- time = rtc_tm_to_time64(tm);
-
- /* rtc_tm_to_time64 covert Gregorian date to seconds since
- * 01-01-1970 00:00:00, and this date is Thursday.
- */
- days = div_s64(time, 86400);
- tm->tm_wday = (days + 4) % 7;
+ tm->tm_wday--;
exit:
return ret;
@@ -122,13 +110,14 @@ static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
int ret;
u16 data[RTC_OFFSET_COUNT];
- tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++;
+ tm->tm_wday++;
data[RTC_OFFSET_SEC] = tm->tm_sec;
data[RTC_OFFSET_MIN] = tm->tm_min;
data[RTC_OFFSET_HOUR] = tm->tm_hour;
data[RTC_OFFSET_DOM] = tm->tm_mday;
+ data[RTC_OFFSET_DOW] = tm->tm_wday;
data[RTC_OFFSET_MTH] = tm->tm_mon;
data[RTC_OFFSET_YEAR] = tm->tm_year;
@@ -178,7 +167,6 @@ static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK;
tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK;
- tm->tm_year += RTC_MIN_YEAR_OFFSET;
tm->tm_mon--;
return 0;
@@ -194,7 +182,6 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
int ret;
u16 data[RTC_OFFSET_COUNT];
- tm->tm_year -= RTC_MIN_YEAR_OFFSET;
tm->tm_mon++;
mutex_lock(&rtc->lock);
@@ -299,9 +286,13 @@ static int mtk_rtc_probe(struct platform_device *pdev)
return ret;
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
rtc->rtc_dev->ops = &mtk_rtc_ops;
+ rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
+ rtc->rtc_dev->range_max = mktime64(2027, 12, 31, 23, 59, 59);
+ rtc->rtc_dev->start_secs = mktime64(1968, 1, 2, 0, 0, 0);
+ rtc->rtc_dev->set_start_time = true;
return devm_rtc_register_device(rtc->rtc_dev);
}
@@ -341,6 +332,7 @@ static const struct mtk_rtc_data mt6397_rtc_data = {
static const struct of_device_id mt6397_rtc_of_match[] = {
{ .compatible = "mediatek,mt6323-rtc", .data = &mt6397_rtc_data },
+ { .compatible = "mediatek,mt6357-rtc", .data = &mt6358_rtc_data },
{ .compatible = "mediatek,mt6358-rtc", .data = &mt6358_rtc_data },
{ .compatible = "mediatek,mt6397-rtc", .data = &mt6397_rtc_data },
{ }
diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c
index f1e356394814..4cf0cbb31a31 100644
--- a/drivers/rtc/rtc-mt7622.c
+++ b/drivers/rtc/rtc-mt7622.c
@@ -7,9 +7,9 @@
#include <linux/clk.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
@@ -357,13 +357,11 @@ err:
return ret;
}
-static int mtk_rtc_remove(struct platform_device *pdev)
+static void mtk_rtc_remove(struct platform_device *pdev)
{
struct mtk_rtc *hw = platform_get_drvdata(pdev);
clk_disable_unprepare(hw->clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -396,7 +394,7 @@ static SIMPLE_DEV_PM_OPS(mtk_rtc_pm_ops, mtk_rtc_suspend, mtk_rtc_resume);
static struct platform_driver mtk_rtc_driver = {
.probe = mtk_rtc_probe,
- .remove = mtk_rtc_remove,
+ .remove = mtk_rtc_remove,
.driver = {
.name = MTK_RTC_DEV,
.of_match_table = mtk_rtc_match,
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index 6c526e2ec56d..c27ad626d09f 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -264,7 +264,7 @@ static int __init mv_rtc_probe(struct platform_device *pdev)
}
if (pdata->irq >= 0)
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
else
clear_bit(RTC_FEATURE_ALARM, pdata->rtc->features);
@@ -282,17 +282,15 @@ out:
return ret;
}
-static int __exit mv_rtc_remove(struct platform_device *pdev)
+static void __exit mv_rtc_remove(struct platform_device *pdev)
{
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
if (pdata->irq >= 0)
- device_init_wakeup(&pdev->dev, 0);
+ device_init_wakeup(&pdev->dev, false);
if (!IS_ERR(pdata->clk))
clk_disable_unprepare(pdata->clk);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -303,7 +301,13 @@ static const struct of_device_id rtc_mv_of_match_table[] = {
MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table);
#endif
-static struct platform_driver mv_rtc_driver = {
+/*
+ * mv_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver mv_rtc_driver __refdata = {
.remove = __exit_p(mv_rtc_remove),
.driver = {
.name = "rtc-mv",
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
index 762cf03345f1..608db97d450c 100644
--- a/drivers/rtc/rtc-mxc.c
+++ b/drivers/rtc/rtc-mxc.c
@@ -11,7 +11,6 @@
#include <linux/pm_wakeirq.h>
#include <linux/clk.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#define RTC_INPUT_CLK_32768HZ (0x00 << 5)
#define RTC_INPUT_CLK_32000HZ (0x01 << 5)
@@ -378,7 +377,7 @@ static int mxc_rtc_probe(struct platform_device *pdev)
}
if (pdata->irq >= 0) {
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
ret = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
if (ret)
dev_err(&pdev->dev, "failed to enable irq wake\n");
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
index f6d2ad91ff7a..570f27af4732 100644
--- a/drivers/rtc/rtc-mxc_v2.c
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -302,7 +302,7 @@ static int mxc_rtc_probe(struct platform_device *pdev)
if (pdata->irq < 0)
return pdata->irq;
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
ret = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
if (ret)
dev_err(&pdev->dev, "failed to enable irq wake\n");
@@ -362,12 +362,11 @@ static int mxc_rtc_probe(struct platform_device *pdev)
return ret;
}
-static int mxc_rtc_remove(struct platform_device *pdev)
+static void mxc_rtc_remove(struct platform_device *pdev)
{
struct mxc_rtc_data *pdata = platform_get_drvdata(pdev);
clk_disable_unprepare(pdata->clk);
- return 0;
}
static const struct of_device_id mxc_ids[] = {
diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c
index 0a3b14c95d90..cd4b1db902e9 100644
--- a/drivers/rtc/rtc-nct3018y.c
+++ b/drivers/rtc/rtc-nct3018y.c
@@ -23,6 +23,7 @@
#define NCT3018Y_REG_CTRL 0x0A /* timer control */
#define NCT3018Y_REG_ST 0x0B /* status */
#define NCT3018Y_REG_CLKO 0x0C /* clock out */
+#define NCT3018Y_REG_PART 0x21 /* part info */
#define NCT3018Y_BIT_AF BIT(7)
#define NCT3018Y_BIT_ST BIT(7)
@@ -37,10 +38,12 @@
#define NCT3018Y_REG_BAT_MASK 0x07
#define NCT3018Y_REG_CLKO_F_MASK 0x03 /* frequenc mask */
#define NCT3018Y_REG_CLKO_CKE 0x80 /* clock out enabled */
+#define NCT3018Y_REG_PART_NCT3018Y 0x02
struct nct3018y {
struct rtc_device *rtc;
struct i2c_client *client;
+ int part_num;
#ifdef CONFIG_COMMON_CLK
struct clk_hw clkout_hw;
#endif
@@ -99,6 +102,8 @@ static int nct3018y_get_alarm_mode(struct i2c_client *client, unsigned char *ala
if (flags < 0)
return flags;
*alarm_enable = flags & NCT3018Y_BIT_AIE;
+ dev_dbg(&client->dev, "%s:alarm_enable:%x\n", __func__, *alarm_enable);
+
}
if (alarm_flag) {
@@ -107,11 +112,9 @@ static int nct3018y_get_alarm_mode(struct i2c_client *client, unsigned char *ala
if (flags < 0)
return flags;
*alarm_flag = flags & NCT3018Y_BIT_AF;
+ dev_dbg(&client->dev, "%s:alarm_flag:%x\n", __func__, *alarm_flag);
}
- dev_dbg(&client->dev, "%s:alarm_enable:%x alarm_flag:%x\n",
- __func__, *alarm_enable, *alarm_flag);
-
return 0;
}
@@ -177,8 +180,27 @@ static int nct3018y_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int nct3018y_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct nct3018y *nct3018y = dev_get_drvdata(dev);
unsigned char buf[4] = {0};
- int err;
+ int err, flags;
+ int restore_flags = 0;
+
+ flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CTRL);
+ if (flags < 0) {
+ dev_dbg(&client->dev, "Failed to read NCT3018Y_REG_CTRL.\n");
+ return flags;
+ }
+
+ /* Check and set TWO bit */
+ if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y && !(flags & NCT3018Y_BIT_TWO)) {
+ restore_flags = 1;
+ flags |= NCT3018Y_BIT_TWO;
+ err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
+ return err;
+ }
+ }
buf[0] = bin2bcd(tm->tm_sec);
err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_SC, buf[0]);
@@ -212,6 +234,18 @@ static int nct3018y_rtc_set_time(struct device *dev, struct rtc_time *tm)
return -EIO;
}
+ /* Restore TWO bit */
+ if (restore_flags) {
+ if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y)
+ flags &= ~NCT3018Y_BIT_TWO;
+
+ err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
+ return err;
+ }
+ }
+
return err;
}
@@ -333,14 +367,19 @@ static unsigned long nct3018y_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[flags];
}
-static long nct3018y_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int nct3018y_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -412,7 +451,7 @@ static const struct clk_ops nct3018y_clkout_ops = {
.unprepare = nct3018y_clkout_unprepare,
.is_prepared = nct3018y_clkout_is_prepared,
.recalc_rate = nct3018y_clkout_recalc_rate,
- .round_rate = nct3018y_clkout_round_rate,
+ .determine_rate = nct3018y_clkout_determine_rate,
.set_rate = nct3018y_clkout_set_rate,
};
@@ -479,11 +518,20 @@ static int nct3018y_probe(struct i2c_client *client)
dev_dbg(&client->dev, "%s: NCT3018Y_BIT_TWO is set\n", __func__);
}
- flags = NCT3018Y_BIT_TWO;
- err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
- if (err < 0) {
- dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL\n");
- return err;
+ nct3018y->part_num = i2c_smbus_read_byte_data(client, NCT3018Y_REG_PART);
+ if (nct3018y->part_num < 0) {
+ dev_dbg(&client->dev, "Failed to read NCT3018Y_REG_PART.\n");
+ return nct3018y->part_num;
+ } else {
+ nct3018y->part_num &= 0x03; /* Part number is corresponding to bit 0 and 1 */
+ if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y) {
+ flags = NCT3018Y_BIT_HF;
+ err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
+ return err;
+ }
+ }
}
flags = 0;
@@ -524,7 +572,7 @@ static int nct3018y_probe(struct i2c_client *client)
}
static const struct i2c_device_id nct3018y_id[] = {
- { "nct3018y", 0 },
+ { "nct3018y" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nct3018y_id);
@@ -538,9 +586,9 @@ MODULE_DEVICE_TABLE(of, nct3018y_of_match);
static struct i2c_driver nct3018y_driver = {
.driver = {
.name = "rtc-nct3018y",
- .of_match_table = of_match_ptr(nct3018y_of_match),
+ .of_match_table = nct3018y_of_match,
},
- .probe_new = nct3018y_probe,
+ .probe = nct3018y_probe,
.id_table = nct3018y_id,
};
diff --git a/drivers/rtc/rtc-nct6694.c b/drivers/rtc/rtc-nct6694.c
new file mode 100644
index 000000000000..35401a0d9cf5
--- /dev/null
+++ b/drivers/rtc/rtc-nct6694.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nuvoton NCT6694 RTC driver based on USB interface.
+ *
+ * Copyright (C) 2025 Nuvoton Technology Corp.
+ */
+
+#include <linux/bcd.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/mfd/nct6694.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+/*
+ * USB command module type for NCT6694 RTC controller.
+ * This defines the module type used for communication with the NCT6694
+ * RTC controller over the USB interface.
+ */
+#define NCT6694_RTC_MOD 0x08
+
+/* Command 00h - RTC Time */
+#define NCT6694_RTC_TIME 0x0000
+#define NCT6694_RTC_TIME_SEL 0x00
+
+/* Command 01h - RTC Alarm */
+#define NCT6694_RTC_ALARM 0x01
+#define NCT6694_RTC_ALARM_SEL 0x00
+
+/* Command 02h - RTC Status */
+#define NCT6694_RTC_STATUS 0x02
+#define NCT6694_RTC_STATUS_SEL 0x00
+
+#define NCT6694_RTC_IRQ_INT_EN BIT(0) /* Transmit a USB INT-in when RTC alarm */
+#define NCT6694_RTC_IRQ_GPO_EN BIT(5) /* Trigger a GPO Low Pulse when RTC alarm */
+
+#define NCT6694_RTC_IRQ_EN (NCT6694_RTC_IRQ_INT_EN | NCT6694_RTC_IRQ_GPO_EN)
+#define NCT6694_RTC_IRQ_STS BIT(0) /* Write 1 clear IRQ status */
+
+struct __packed nct6694_rtc_time {
+ u8 sec;
+ u8 min;
+ u8 hour;
+ u8 week;
+ u8 day;
+ u8 month;
+ u8 year;
+};
+
+struct __packed nct6694_rtc_alarm {
+ u8 sec;
+ u8 min;
+ u8 hour;
+ u8 alarm_en;
+ u8 alarm_pend;
+};
+
+struct __packed nct6694_rtc_status {
+ u8 irq_en;
+ u8 irq_pend;
+};
+
+union __packed nct6694_rtc_msg {
+ struct nct6694_rtc_time time;
+ struct nct6694_rtc_alarm alarm;
+ struct nct6694_rtc_status sts;
+};
+
+struct nct6694_rtc_data {
+ struct nct6694 *nct6694;
+ struct rtc_device *rtc;
+ union nct6694_rtc_msg *msg;
+ int irq;
+};
+
+static int nct6694_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct nct6694_rtc_data *data = dev_get_drvdata(dev);
+ struct nct6694_rtc_time *time = &data->msg->time;
+ static const struct nct6694_cmd_header cmd_hd = {
+ .mod = NCT6694_RTC_MOD,
+ .cmd = NCT6694_RTC_TIME,
+ .sel = NCT6694_RTC_TIME_SEL,
+ .len = cpu_to_le16(sizeof(*time))
+ };
+ int ret;
+
+ ret = nct6694_read_msg(data->nct6694, &cmd_hd, time);
+ if (ret)
+ return ret;
+
+ tm->tm_sec = bcd2bin(time->sec); /* tm_sec expect 0 ~ 59 */
+ tm->tm_min = bcd2bin(time->min); /* tm_min expect 0 ~ 59 */
+ tm->tm_hour = bcd2bin(time->hour); /* tm_hour expect 0 ~ 23 */
+ tm->tm_wday = bcd2bin(time->week) - 1; /* tm_wday expect 0 ~ 6 */
+ tm->tm_mday = bcd2bin(time->day); /* tm_mday expect 1 ~ 31 */
+ tm->tm_mon = bcd2bin(time->month) - 1; /* tm_month expect 0 ~ 11 */
+ tm->tm_year = bcd2bin(time->year) + 100; /* tm_year expect since 1900 */
+
+ return ret;
+}
+
+static int nct6694_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct nct6694_rtc_data *data = dev_get_drvdata(dev);
+ struct nct6694_rtc_time *time = &data->msg->time;
+ static const struct nct6694_cmd_header cmd_hd = {
+ .mod = NCT6694_RTC_MOD,
+ .cmd = NCT6694_RTC_TIME,
+ .sel = NCT6694_RTC_TIME_SEL,
+ .len = cpu_to_le16(sizeof(*time))
+ };
+
+ time->sec = bin2bcd(tm->tm_sec);
+ time->min = bin2bcd(tm->tm_min);
+ time->hour = bin2bcd(tm->tm_hour);
+ time->week = bin2bcd(tm->tm_wday + 1);
+ time->day = bin2bcd(tm->tm_mday);
+ time->month = bin2bcd(tm->tm_mon + 1);
+ time->year = bin2bcd(tm->tm_year - 100);
+
+ return nct6694_write_msg(data->nct6694, &cmd_hd, time);
+}
+
+static int nct6694_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct nct6694_rtc_data *data = dev_get_drvdata(dev);
+ struct nct6694_rtc_alarm *alarm = &data->msg->alarm;
+ static const struct nct6694_cmd_header cmd_hd = {
+ .mod = NCT6694_RTC_MOD,
+ .cmd = NCT6694_RTC_ALARM,
+ .sel = NCT6694_RTC_ALARM_SEL,
+ .len = cpu_to_le16(sizeof(*alarm))
+ };
+ int ret;
+
+ ret = nct6694_read_msg(data->nct6694, &cmd_hd, alarm);
+ if (ret)
+ return ret;
+
+ alrm->time.tm_sec = bcd2bin(alarm->sec);
+ alrm->time.tm_min = bcd2bin(alarm->min);
+ alrm->time.tm_hour = bcd2bin(alarm->hour);
+ alrm->enabled = alarm->alarm_en;
+ alrm->pending = alarm->alarm_pend;
+
+ return ret;
+}
+
+static int nct6694_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct nct6694_rtc_data *data = dev_get_drvdata(dev);
+ struct nct6694_rtc_alarm *alarm = &data->msg->alarm;
+ static const struct nct6694_cmd_header cmd_hd = {
+ .mod = NCT6694_RTC_MOD,
+ .cmd = NCT6694_RTC_ALARM,
+ .sel = NCT6694_RTC_ALARM_SEL,
+ .len = cpu_to_le16(sizeof(*alarm))
+ };
+
+ alarm->sec = bin2bcd(alrm->time.tm_sec);
+ alarm->min = bin2bcd(alrm->time.tm_min);
+ alarm->hour = bin2bcd(alrm->time.tm_hour);
+ alarm->alarm_en = alrm->enabled ? NCT6694_RTC_IRQ_EN : 0;
+ alarm->alarm_pend = 0;
+
+ return nct6694_write_msg(data->nct6694, &cmd_hd, alarm);
+}
+
+static int nct6694_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct nct6694_rtc_data *data = dev_get_drvdata(dev);
+ struct nct6694_rtc_status *sts = &data->msg->sts;
+ static const struct nct6694_cmd_header cmd_hd = {
+ .mod = NCT6694_RTC_MOD,
+ .cmd = NCT6694_RTC_STATUS,
+ .sel = NCT6694_RTC_STATUS_SEL,
+ .len = cpu_to_le16(sizeof(*sts))
+ };
+
+ if (enabled)
+ sts->irq_en |= NCT6694_RTC_IRQ_EN;
+ else
+ sts->irq_en &= ~NCT6694_RTC_IRQ_EN;
+
+ sts->irq_pend = 0;
+
+ return nct6694_write_msg(data->nct6694, &cmd_hd, sts);
+}
+
+static const struct rtc_class_ops nct6694_rtc_ops = {
+ .read_time = nct6694_rtc_read_time,
+ .set_time = nct6694_rtc_set_time,
+ .read_alarm = nct6694_rtc_read_alarm,
+ .set_alarm = nct6694_rtc_set_alarm,
+ .alarm_irq_enable = nct6694_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t nct6694_irq(int irq, void *dev_id)
+{
+ struct nct6694_rtc_data *data = dev_id;
+ struct nct6694_rtc_status *sts = &data->msg->sts;
+ static const struct nct6694_cmd_header cmd_hd = {
+ .mod = NCT6694_RTC_MOD,
+ .cmd = NCT6694_RTC_STATUS,
+ .sel = NCT6694_RTC_STATUS_SEL,
+ .len = cpu_to_le16(sizeof(*sts))
+ };
+ int ret;
+
+ rtc_lock(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);
+ return IRQ_NONE;
+ }
+
+ rtc_update_irq(data->rtc, 1, RTC_IRQF | RTC_AF);
+
+ rtc_unlock(data->rtc);
+
+ return IRQ_HANDLED;
+}
+
+static void nct6694_irq_dispose_mapping(void *d)
+{
+ struct nct6694_rtc_data *data = d;
+
+ irq_dispose_mapping(data->irq);
+}
+
+static int nct6694_rtc_probe(struct platform_device *pdev)
+{
+ struct nct6694_rtc_data *data;
+ struct nct6694 *nct6694 = dev_get_drvdata(pdev->dev.parent);
+ int ret;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->msg = devm_kzalloc(&pdev->dev, sizeof(union nct6694_rtc_msg),
+ GFP_KERNEL);
+ if (!data->msg)
+ return -ENOMEM;
+
+ data->irq = irq_create_mapping(nct6694->domain, NCT6694_IRQ_RTC);
+ if (!data->irq)
+ return -EINVAL;
+
+ ret = devm_add_action_or_reset(&pdev->dev, nct6694_irq_dispose_mapping,
+ data);
+ if (ret)
+ return ret;
+
+ ret = devm_device_init_wakeup(&pdev->dev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to init wakeup\n");
+
+ data->rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(data->rtc))
+ return PTR_ERR(data->rtc);
+
+ data->nct6694 = nct6694;
+ data->rtc->ops = &nct6694_rtc_ops;
+ data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ data->rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+ platform_set_drvdata(pdev, data);
+
+ ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
+ nct6694_irq, IRQF_ONESHOT,
+ "rtc-nct6694", data);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "Failed to request irq\n");
+
+ return devm_rtc_register_device(data->rtc);
+}
+
+static struct platform_driver nct6694_rtc_driver = {
+ .driver = {
+ .name = "nct6694-rtc",
+ },
+ .probe = nct6694_rtc_probe,
+};
+
+module_platform_driver(nct6694_rtc_driver);
+
+MODULE_DESCRIPTION("USB-RTC driver for NCT6694");
+MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nct6694-rtc");
diff --git a/drivers/rtc/rtc-nxp-bbnsm.c b/drivers/rtc/rtc-nxp-bbnsm.c
new file mode 100644
index 000000000000..d4fc9dc583d3
--- /dev/null
+++ b/drivers/rtc/rtc-nxp-bbnsm.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2022 NXP.
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#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>
+
+#define BBNSM_CTRL 0x8
+#define BBNSM_INT_EN 0x10
+#define BBNSM_EVENTS 0x14
+#define BBNSM_RTC_LS 0x40
+#define BBNSM_RTC_MS 0x44
+#define BBNSM_TA 0x50
+
+#define RTC_EN 0x2
+#define RTC_EN_MSK 0x3
+#define TA_EN (0x2 << 2)
+#define TA_DIS (0x1 << 2)
+#define TA_EN_MSK (0x3 << 2)
+#define RTC_INT_EN 0x2
+#define TA_INT_EN (0x2 << 2)
+
+#define BBNSM_EVENT_TA (0x2 << 2)
+
+#define CNTR_TO_SECS_SH 15
+
+struct bbnsm_rtc {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ int irq;
+ struct clk *clk;
+};
+
+static u32 bbnsm_read_counter(struct bbnsm_rtc *bbnsm)
+{
+ u32 rtc_msb, rtc_lsb;
+ unsigned int timeout = 100;
+ u32 time;
+ u32 tmp = 0;
+
+ do {
+ time = tmp;
+ /* read the msb */
+ regmap_read(bbnsm->regmap, BBNSM_RTC_MS, &rtc_msb);
+ /* read the lsb */
+ regmap_read(bbnsm->regmap, BBNSM_RTC_LS, &rtc_lsb);
+ /* convert to seconds */
+ tmp = (rtc_msb << 17) | (rtc_lsb >> 15);
+ } while (tmp != time && --timeout);
+
+ return time;
+}
+
+static int bbnsm_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ unsigned long time;
+ u32 val;
+
+ regmap_read(bbnsm->regmap, BBNSM_CTRL, &val);
+ if ((val & RTC_EN_MSK) != RTC_EN)
+ return -EINVAL;
+
+ time = bbnsm_read_counter(bbnsm);
+ rtc_time64_to_tm(time, tm);
+
+ return 0;
+}
+
+static int bbnsm_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ unsigned long time = rtc_tm_to_time64(tm);
+
+ /* disable the RTC first */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, 0);
+
+ /* write the 32bit sec time to 47 bit timer counter, leaving 15 LSBs blank */
+ regmap_write(bbnsm->regmap, BBNSM_RTC_LS, time << CNTR_TO_SECS_SH);
+ regmap_write(bbnsm->regmap, BBNSM_RTC_MS, time >> (32 - CNTR_TO_SECS_SH));
+
+ /* Enable the RTC again */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, RTC_EN);
+
+ return 0;
+}
+
+static int bbnsm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ u32 bbnsm_events, bbnsm_ta;
+
+ regmap_read(bbnsm->regmap, BBNSM_TA, &bbnsm_ta);
+ rtc_time64_to_tm(bbnsm_ta, &alrm->time);
+
+ regmap_read(bbnsm->regmap, BBNSM_EVENTS, &bbnsm_events);
+ alrm->pending = (bbnsm_events & BBNSM_EVENT_TA) ? 1 : 0;
+
+ return 0;
+}
+
+static int bbnsm_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+
+ /* enable the alarm event */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN_MSK, enable ? TA_EN : TA_DIS);
+ /* enable the alarm interrupt */
+ regmap_update_bits(bbnsm->regmap, BBNSM_INT_EN, TA_EN_MSK, enable ? TA_EN : TA_DIS);
+
+ return 0;
+}
+
+static int bbnsm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ unsigned long time = rtc_tm_to_time64(&alrm->time);
+
+ /* disable the alarm */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN, TA_EN);
+
+ /* write the seconds to TA */
+ regmap_write(bbnsm->regmap, BBNSM_TA, time);
+
+ return bbnsm_rtc_alarm_irq_enable(dev, alrm->enabled);
+}
+
+static const struct rtc_class_ops bbnsm_rtc_ops = {
+ .read_time = bbnsm_rtc_read_time,
+ .set_time = bbnsm_rtc_set_time,
+ .read_alarm = bbnsm_rtc_read_alarm,
+ .set_alarm = bbnsm_rtc_set_alarm,
+ .alarm_irq_enable = bbnsm_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t bbnsm_rtc_irq_handler(int irq, void *dev_id)
+{
+ struct device *dev = dev_id;
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ u32 val;
+
+ regmap_read(bbnsm->regmap, BBNSM_EVENTS, &val);
+ if (val & BBNSM_EVENT_TA) {
+ bbnsm_rtc_alarm_irq_enable(dev, false);
+ /* clear the alarm event */
+ regmap_write_bits(bbnsm->regmap, BBNSM_EVENTS, TA_EN_MSK, BBNSM_EVENT_TA);
+ rtc_update_irq(bbnsm->rtc, 1, RTC_AF | RTC_IRQF);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int bbnsm_rtc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct bbnsm_rtc *bbnsm;
+ int ret;
+
+ bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL);
+ if (!bbnsm)
+ return -ENOMEM;
+
+ bbnsm->rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(bbnsm->rtc))
+ return PTR_ERR(bbnsm->rtc);
+
+ bbnsm->regmap = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(bbnsm->regmap)) {
+ dev_dbg(&pdev->dev, "bbnsm get regmap failed\n");
+ return PTR_ERR(bbnsm->regmap);
+ }
+
+ bbnsm->irq = platform_get_irq(pdev, 0);
+ if (bbnsm->irq < 0)
+ return bbnsm->irq;
+
+ platform_set_drvdata(pdev, bbnsm);
+
+ /* clear all the pending events */
+ regmap_write(bbnsm->regmap, BBNSM_EVENTS, 0x7A);
+
+ ret = devm_device_init_wakeup(&pdev->dev);
+ if (ret)
+ dev_err(&pdev->dev, "failed to init wakeup, %d\n", ret);
+
+ ret = devm_pm_set_wake_irq(&pdev->dev, bbnsm->irq);
+ if (ret)
+ dev_err(&pdev->dev, "failed to set wake irq, %d\n", ret);
+
+ ret = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_rtc_irq_handler,
+ IRQF_SHARED, "rtc alarm", &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq %d: %d\n",
+ bbnsm->irq, ret);
+ return ret;
+ }
+
+ bbnsm->rtc->ops = &bbnsm_rtc_ops;
+ bbnsm->rtc->range_max = U32_MAX;
+
+ return devm_rtc_register_device(bbnsm->rtc);
+}
+
+static const struct of_device_id bbnsm_dt_ids[] = {
+ { .compatible = "nxp,imx93-bbnsm-rtc" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, bbnsm_dt_ids);
+
+static struct platform_driver bbnsm_rtc_driver = {
+ .driver = {
+ .name = "bbnsm_rtc",
+ .of_match_table = bbnsm_dt_ids,
+ },
+ .probe = bbnsm_rtc_probe,
+};
+module_platform_driver(bbnsm_rtc_driver);
+
+MODULE_AUTHOR("Jacky Bai <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("NXP BBNSM RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 4d4f3b1a7309..0f90065e352c 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -18,13 +18,14 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/rtc.h>
+#include <linux/rtc/rtc-omap.h>
/*
* The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
@@ -728,16 +729,14 @@ static int omap_rtc_probe(struct platform_device *pdev)
struct omap_rtc *rtc;
u8 reg, mask, new_ctrl;
const struct platform_device_id *id_entry;
- const struct of_device_id *of_id;
int ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
- of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
- if (of_id) {
- rtc->type = of_id->data;
+ rtc->type = device_get_match_data(&pdev->dev);
+ if (rtc->type) {
rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
of_device_is_system_power_controller(pdev->dev.of_node);
} else {
@@ -746,12 +745,12 @@ static int omap_rtc_probe(struct platform_device *pdev)
}
rtc->irq_timer = platform_get_irq(pdev, 0);
- if (rtc->irq_timer <= 0)
- return -ENOENT;
+ if (rtc->irq_timer < 0)
+ return rtc->irq_timer;
rtc->irq_alarm = platform_get_irq(pdev, 1);
- if (rtc->irq_alarm <= 0)
- return -ENOENT;
+ if (rtc->irq_alarm < 0)
+ return rtc->irq_alarm;
rtc->clk = devm_clk_get(&pdev->dev, "ext-clk");
if (!IS_ERR(rtc->clk))
@@ -910,7 +909,7 @@ err:
return ret;
}
-static int omap_rtc_remove(struct platform_device *pdev)
+static void omap_rtc_remove(struct platform_device *pdev)
{
struct omap_rtc *rtc = platform_get_drvdata(pdev);
u8 reg;
@@ -921,7 +920,7 @@ static int omap_rtc_remove(struct platform_device *pdev)
omap_rtc_power_off_rtc = NULL;
}
- device_init_wakeup(&pdev->dev, 0);
+ device_init_wakeup(&pdev->dev, false);
if (!IS_ERR(rtc->clk))
clk_disable_unprepare(rtc->clk);
@@ -941,8 +940,6 @@ static int omap_rtc_remove(struct platform_device *pdev)
/* Disable the clock/module */
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static int __maybe_unused omap_rtc_suspend(struct device *dev)
@@ -1030,4 +1027,5 @@ static struct platform_driver omap_rtc_driver = {
module_platform_driver(omap_rtc_driver);
MODULE_AUTHOR("George G. Davis (and others)");
+MODULE_DESCRIPTION("TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c
index 9f8b5d4a8f6b..184c6d142801 100644
--- a/drivers/rtc/rtc-optee.c
+++ b/drivers/rtc/rtc-optee.c
@@ -5,19 +5,104 @@
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/tee_drv.h>
-#define RTC_INFO_VERSION 0x1
+#define RTC_INFO_VERSION 0x1
-#define TA_CMD_RTC_GET_INFO 0x0
-#define TA_CMD_RTC_GET_TIME 0x1
-#define TA_CMD_RTC_SET_TIME 0x2
-#define TA_CMD_RTC_GET_OFFSET 0x3
-#define TA_CMD_RTC_SET_OFFSET 0x4
+#define TA_RTC_FEATURE_CORRECTION BIT(0)
+#define TA_RTC_FEATURE_ALARM BIT(1)
+#define TA_RTC_FEATURE_WAKEUP_ALARM BIT(2)
-#define TA_RTC_FEATURE_CORRECTION BIT(0)
+enum rtc_optee_pta_cmd {
+ /* PTA_CMD_RTC_GET_INFO - Get RTC information
+ *
+ * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_info
+ */
+ PTA_CMD_RTC_GET_INF = 0x0,
+
+ /*
+ * PTA_CMD_RTC_GET_TIME - Get time from RTC
+ *
+ * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_time
+ */
+ PTA_CMD_RTC_GET_TIME = 0x1,
+
+ /*
+ * PTA_CMD_RTC_SET_TIME - Set time from RTC
+ *
+ * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_time to be
+ * used as RTC time
+ */
+ PTA_CMD_RTC_SET_TIME = 0x2,
+
+ /*
+ * PTA_CMD_RTC_GET_OFFSET - Get RTC offset
+ *
+ * [out] value[0].a RTC offset (signed 32bit value)
+ */
+ PTA_CMD_RTC_GET_OFFSET = 0x3,
+
+ /*
+ * PTA_CMD_RTC_SET_OFFSET - Set RTC offset
+ *
+ * [in] value[0].a RTC offset to be set (signed 32bit value)
+ */
+ PTA_CMD_RTC_SET_OFFSET = 0x4,
+
+ /*
+ * PTA_CMD_RTC_READ_ALARM - Read RTC alarm
+ *
+ * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm
+ */
+ PTA_CMD_RTC_READ_ALARM = 0x5,
+
+ /*
+ * PTA_CMD_RTC_SET_ALARM - Set RTC alarm
+ *
+ * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm to be
+ * used as RTC alarm
+ */
+ PTA_CMD_RTC_SET_ALARM = 0x6,
+
+ /*
+ * PTA_CMD_RTC_ENABLE_ALARM - Enable Alarm
+ *
+ * [in] value[0].a RTC IRQ flag (uint32_t), 0 to disable the alarm, 1 to enable
+ */
+ PTA_CMD_RTC_ENABLE_ALARM = 0x7,
+
+ /*
+ * PTA_CMD_RTC_WAIT_ALARM - Get alarm event
+ *
+ * [out] value[0].a RTC wait alarm return status (uint32_t):
+ * - 0: No alarm event
+ * - 1: Alarm event occurred
+ * - 2: Alarm event canceled
+ */
+ PTA_CMD_RTC_WAIT_ALARM = 0x8,
+
+ /*
+ * PTA_CMD_RTC_CANCEL_WAIT - Cancel wait for alarm event
+ */
+ PTA_CMD_RTC_CANCEL_WAIT = 0x9,
+
+ /*
+ * PTA_CMD_RTC_SET_WAKE_ALARM_STATUS - Set RTC wake alarm status flag
+ *
+ * [in] value[0].a RTC IRQ wake alarm flag (uint32_t), 0 to disable the wake up
+ * capability, 1 to enable.
+ */
+ PTA_CMD_RTC_SET_WAKE_ALARM_STATUS = 0xA,
+};
+
+enum rtc_wait_alarm_status {
+ WAIT_ALARM_RESET = 0x0,
+ WAIT_ALARM_ALARM_OCCURRED = 0x1,
+ WAIT_ALARM_CANCELED = 0x2,
+};
struct optee_rtc_time {
u32 tm_sec;
@@ -29,6 +114,12 @@ struct optee_rtc_time {
u32 tm_wday;
};
+struct optee_rtc_alarm {
+ u8 enabled;
+ u8 pending;
+ struct optee_rtc_time time;
+};
+
struct optee_rtc_info {
u64 version;
u64 features;
@@ -41,15 +132,21 @@ struct optee_rtc_info {
* @dev: OP-TEE based RTC device.
* @ctx: OP-TEE context handler.
* @session_id: RTC TA session identifier.
+ * @session2_id: RTC wait alarm session identifier.
* @shm: Memory pool shared with RTC device.
* @features: Bitfield of RTC features
+ * @alarm_task: RTC wait alamr task.
+ * @rtc: RTC device.
*/
struct optee_rtc {
struct device *dev;
struct tee_context *ctx;
u32 session_id;
+ u32 session2_id;
struct tee_shm *shm;
u64 features;
+ struct task_struct *alarm_task;
+ struct rtc_device *rtc;
};
static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm)
@@ -60,7 +157,7 @@ static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm)
struct tee_param param[4] = {0};
int ret;
- inv_arg.func = TA_CMD_RTC_GET_TIME;
+ inv_arg.func = PTA_CMD_RTC_GET_TIME;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -97,19 +194,10 @@ static int optee_rtc_settime(struct device *dev, struct rtc_time *tm)
struct optee_rtc *priv = dev_get_drvdata(dev);
struct tee_ioctl_invoke_arg inv_arg = {0};
struct tee_param param[4] = {0};
- struct optee_rtc_time optee_tm;
- void *rtc_data;
+ struct optee_rtc_time *optee_tm;
int ret;
- optee_tm.tm_sec = tm->tm_sec;
- optee_tm.tm_min = tm->tm_min;
- optee_tm.tm_hour = tm->tm_hour;
- optee_tm.tm_mday = tm->tm_mday;
- optee_tm.tm_mon = tm->tm_mon;
- optee_tm.tm_year = tm->tm_year + 1900;
- optee_tm.tm_wday = tm->tm_wday;
-
- inv_arg.func = TA_CMD_RTC_SET_TIME;
+ inv_arg.func = PTA_CMD_RTC_SET_TIME;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -117,11 +205,17 @@ static int optee_rtc_settime(struct device *dev, struct rtc_time *tm)
param[0].u.memref.shm = priv->shm;
param[0].u.memref.size = sizeof(struct optee_rtc_time);
- rtc_data = tee_shm_get_va(priv->shm, 0);
- if (IS_ERR(rtc_data))
- return PTR_ERR(rtc_data);
+ optee_tm = tee_shm_get_va(priv->shm, 0);
+ if (IS_ERR(optee_tm))
+ return PTR_ERR(optee_tm);
- memcpy(rtc_data, &optee_tm, sizeof(struct optee_rtc_time));
+ optee_tm->tm_min = tm->tm_min;
+ optee_tm->tm_sec = tm->tm_sec;
+ optee_tm->tm_hour = tm->tm_hour;
+ optee_tm->tm_mday = tm->tm_mday;
+ optee_tm->tm_mon = tm->tm_mon;
+ optee_tm->tm_year = tm->tm_year + 1900;
+ optee_tm->tm_wday = tm->tm_wday;
ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
if (ret < 0 || inv_arg.ret != 0)
@@ -140,7 +234,7 @@ static int optee_rtc_readoffset(struct device *dev, long *offset)
if (!(priv->features & TA_RTC_FEATURE_CORRECTION))
return -EOPNOTSUPP;
- inv_arg.func = TA_CMD_RTC_GET_OFFSET;
+ inv_arg.func = PTA_CMD_RTC_GET_OFFSET;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -165,7 +259,7 @@ static int optee_rtc_setoffset(struct device *dev, long offset)
if (!(priv->features & TA_RTC_FEATURE_CORRECTION))
return -EOPNOTSUPP;
- inv_arg.func = TA_CMD_RTC_SET_OFFSET;
+ inv_arg.func = PTA_CMD_RTC_SET_OFFSET;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -179,13 +273,228 @@ static int optee_rtc_setoffset(struct device *dev, long offset)
return 0;
}
+static int optee_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct optee_rtc_alarm *optee_alarm;
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_READ_ALARM;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ /* Fill invoke cmd params */
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+ param[0].u.memref.shm = priv->shm;
+ param[0].u.memref.size = sizeof(struct optee_rtc_alarm);
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ optee_alarm = tee_shm_get_va(priv->shm, 0);
+ if (IS_ERR(optee_alarm))
+ return PTR_ERR(optee_alarm);
+
+ if (param[0].u.memref.size != sizeof(*optee_alarm))
+ return -EPROTO;
+
+ alarm->enabled = optee_alarm->enabled;
+ alarm->pending = optee_alarm->pending;
+ alarm->time.tm_sec = optee_alarm->time.tm_sec;
+ alarm->time.tm_min = optee_alarm->time.tm_min;
+ alarm->time.tm_hour = optee_alarm->time.tm_hour;
+ alarm->time.tm_mday = optee_alarm->time.tm_mday;
+ alarm->time.tm_mon = optee_alarm->time.tm_mon;
+ alarm->time.tm_year = optee_alarm->time.tm_year - 1900;
+ alarm->time.tm_wday = optee_alarm->time.tm_wday;
+ alarm->time.tm_yday = rtc_year_days(alarm->time.tm_mday,
+ alarm->time.tm_mon,
+ alarm->time.tm_year);
+
+ return 0;
+}
+
+static int optee_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct optee_rtc_alarm *optee_alarm;
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_SET_ALARM;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[0].u.memref.shm = priv->shm;
+ param[0].u.memref.size = sizeof(struct optee_rtc_alarm);
+
+ optee_alarm = tee_shm_get_va(priv->shm, 0);
+ if (IS_ERR(optee_alarm))
+ return PTR_ERR(optee_alarm);
+
+ optee_alarm->enabled = alarm->enabled;
+ optee_alarm->pending = alarm->pending;
+ optee_alarm->time.tm_sec = alarm->time.tm_sec;
+ optee_alarm->time.tm_min = alarm->time.tm_min;
+ optee_alarm->time.tm_hour = alarm->time.tm_hour;
+ optee_alarm->time.tm_mday = alarm->time.tm_mday;
+ optee_alarm->time.tm_mon = alarm->time.tm_mon;
+ optee_alarm->time.tm_year = alarm->time.tm_year + 1900;
+ optee_alarm->time.tm_wday = alarm->time.tm_wday;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
+static int optee_rtc_enable_alarm(struct device *dev, unsigned int enabled)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_ENABLE_ALARM;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = (bool)enabled;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
static const struct rtc_class_ops optee_rtc_ops = {
- .read_time = optee_rtc_readtime,
- .set_time = optee_rtc_settime,
- .set_offset = optee_rtc_setoffset,
- .read_offset = optee_rtc_readoffset,
+ .read_time = optee_rtc_readtime,
+ .set_time = optee_rtc_settime,
+ .set_offset = optee_rtc_setoffset,
+ .read_offset = optee_rtc_readoffset,
+ .read_alarm = optee_rtc_read_alarm,
+ .set_alarm = optee_rtc_set_alarm,
+ .alarm_irq_enable = optee_rtc_enable_alarm,
};
+static int optee_rtc_wait_alarm(struct device *dev, int *return_status)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_WAIT_ALARM;
+ inv_arg.session = priv->session2_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ *return_status = param[0].u.value.a;
+
+ return 0;
+}
+
+static int optee_rtc_cancel_wait_alarm(struct device *dev)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_CANCEL_WAIT;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 0;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
+static int optee_rtc_set_alarm_wake_status(struct device *dev, bool status)
+{
+ struct optee_rtc *priv = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ int ret;
+
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ return -EOPNOTSUPP;
+
+ inv_arg.func = PTA_CMD_RTC_SET_WAKE_ALARM_STATUS;
+ inv_arg.session = priv->session_id;
+ inv_arg.num_params = 1;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = status;
+
+ ret = tee_client_invoke_func(priv->ctx, &inv_arg, param);
+
+ if (ret < 0 || inv_arg.ret != 0)
+ return ret ? ret : -EPROTO;
+
+ return 0;
+}
+
+static int optee_rtc_handle_alarm_event(void *data)
+{
+ struct optee_rtc *priv = (struct optee_rtc *)data;
+ int wait_alarm_return_status = 0;
+ int ret;
+
+ while (!kthread_should_stop()) {
+ ret = optee_rtc_wait_alarm(priv->dev, &wait_alarm_return_status);
+ if (ret) {
+ dev_err(priv->dev, "Failed to wait for alarm: %d\n", ret);
+ return ret;
+ }
+ switch (wait_alarm_return_status) {
+ case WAIT_ALARM_ALARM_OCCURRED:
+ dev_dbg(priv->dev, "Alarm occurred\n");
+ rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
+ break;
+ case WAIT_ALARM_CANCELED:
+ dev_dbg(priv->dev, "Alarm canceled\n");
+ break;
+ default:
+ dev_warn(priv->dev, "Unknown return status: %d\n",
+ wait_alarm_return_status);
+ break;
+ }
+ }
+
+ return 0;
+}
+
static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc,
u64 *features)
{
@@ -196,7 +505,7 @@ static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc,
struct optee_rtc_time *tm;
int ret;
- inv_arg.func = TA_CMD_RTC_GET_INFO;
+ inv_arg.func = PTA_CMD_RTC_GET_INF;
inv_arg.session = priv->session_id;
inv_arg.num_params = 4;
@@ -241,14 +550,13 @@ static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
static int optee_rtc_probe(struct device *dev)
{
struct tee_client_device *rtc_device = to_tee_client_device(dev);
- struct tee_ioctl_open_session_arg sess_arg;
+ struct tee_ioctl_open_session_arg sess2_arg = {0};
+ struct tee_ioctl_open_session_arg sess_arg = {0};
struct optee_rtc *priv;
struct rtc_device *rtc;
struct tee_shm *shm;
int ret, err;
- memset(&sess_arg, 0, sizeof(sess_arg));
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -257,12 +565,14 @@ static int optee_rtc_probe(struct device *dev)
if (IS_ERR(rtc))
return PTR_ERR(rtc);
+ priv->rtc = rtc;
+
/* Open context with TEE driver */
priv->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
if (IS_ERR(priv->ctx))
return -ENODEV;
- /* Open session with rtc Trusted App */
+ /* Open first session with rtc Pseudo Trusted App */
export_uuid(sess_arg.uuid, &rtc_device->id.uuid);
sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
@@ -274,6 +584,11 @@ static int optee_rtc_probe(struct device *dev)
}
priv->session_id = sess_arg.session;
+ /*
+ * Shared memory is used for passing an instance of either struct optee_rtc_info,
+ * struct optee_rtc_time or struct optee_rtc_alarm to OP-TEE service.
+ * The former is by definition large enough to cover both parameter cases.
+ */
shm = tee_shm_alloc_kernel_buf(priv->ctx, sizeof(struct optee_rtc_info));
if (IS_ERR(shm)) {
dev_err(priv->dev, "tee_shm_alloc_kernel_buf failed\n");
@@ -293,19 +608,70 @@ static int optee_rtc_probe(struct device *dev)
goto out_shm;
}
+ /* Handle feature's related setup before registering to rtc framework */
+ if (priv->features & TA_RTC_FEATURE_ALARM) {
+ priv->alarm_task = kthread_create(optee_rtc_handle_alarm_event,
+ priv, "rtc_alarm_evt");
+ if (IS_ERR(priv->alarm_task)) {
+ dev_err(dev, "Failed to create alarm thread\n");
+ err = PTR_ERR(priv->alarm_task);
+ goto out_shm;
+ }
+
+ /*
+ * In case of supported alarm feature on optee side, we create a kthread
+ * that will, in a new optee session, call a PTA interface "rtc_wait_alarm".
+ * This call return in case of alarm and in case of canceled alarm.
+ * The new optee session is therefore only needed in this case as we cannot
+ * use the same session for parallel calls to optee PTA.
+ * Hence one session is reserved to wait for alarms and the other to make
+ * standard calls to RTC PTA.
+ */
+
+ /* Open second session with rtc Trusted App */
+ export_uuid(sess2_arg.uuid, &rtc_device->id.uuid);
+ sess2_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+
+ ret = tee_client_open_session(priv->ctx, &sess2_arg, NULL);
+ if (ret < 0 || sess2_arg.ret != 0) {
+ dev_err(dev, "tee_client_open_session failed, err: %x\n", sess2_arg.ret);
+ err = -EINVAL;
+ goto out_thrd;
+ }
+ priv->session2_id = sess2_arg.session;
+
+ if (priv->features & TA_RTC_FEATURE_WAKEUP_ALARM)
+ device_init_wakeup(dev, true);
+ }
+
err = devm_rtc_register_device(rtc);
if (err)
- goto out_shm;
+ goto out_wk;
/*
- * We must clear this bit after registering because rtc_register_device
- * will set it if it sees that .set_offset is provided.
+ * We must clear those bits after registering because registering a rtc_device
+ * will set them if it sees that .set_offset and .set_alarm are provided.
*/
if (!(priv->features & TA_RTC_FEATURE_CORRECTION))
clear_bit(RTC_FEATURE_CORRECTION, rtc->features);
+ if (!(priv->features & TA_RTC_FEATURE_ALARM))
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
- return 0;
+ /* Start the thread after the rtc is setup */
+ if (priv->alarm_task) {
+ wake_up_process(priv->alarm_task);
+ dev_dbg(dev, "Wait alarm thread successfully started\n");
+ }
+ return 0;
+out_wk:
+ if (priv->features & TA_RTC_FEATURE_ALARM) {
+ device_init_wakeup(dev, false);
+ tee_client_close_session(priv->ctx, priv->session2_id);
+ }
+out_thrd:
+ if (priv->features & TA_RTC_FEATURE_ALARM)
+ kthread_stop(priv->alarm_task);
out_shm:
tee_shm_free(priv->shm);
out_sess:
@@ -320,12 +686,34 @@ static int optee_rtc_remove(struct device *dev)
{
struct optee_rtc *priv = dev_get_drvdata(dev);
+ if (priv->features & TA_RTC_FEATURE_ALARM) {
+ optee_rtc_cancel_wait_alarm(dev);
+ kthread_stop(priv->alarm_task);
+ device_init_wakeup(dev, false);
+ tee_client_close_session(priv->ctx, priv->session2_id);
+ }
+
+ tee_shm_free(priv->shm);
tee_client_close_session(priv->ctx, priv->session_id);
tee_client_close_context(priv->ctx);
return 0;
}
+static int optee_rtc_suspend(struct device *dev)
+{
+ int res = optee_rtc_set_alarm_wake_status(dev, device_may_wakeup(dev));
+
+ if (res) {
+ dev_err(dev, "Unable to transmit wakeup information to optee rtc\n");
+ return res;
+ }
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(optee_rtc_pm_ops, optee_rtc_suspend, NULL);
+
static const struct tee_client_device_id optee_rtc_id_table[] = {
{UUID_INIT(0xf389f8c8, 0x845f, 0x496c,
0x8b, 0xbe, 0xd6, 0x4b, 0xd2, 0x4c, 0x92, 0xfd)},
@@ -341,6 +729,7 @@ static struct tee_client_driver optee_rtc_driver = {
.bus = &tee_bus_type,
.probe = optee_rtc_probe,
.remove = optee_rtc_remove,
+ .pm = pm_sleep_ptr(&optee_rtc_pm_ops),
},
};
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
index 67571f7f0bbc..aecada6bcf8b 100644
--- a/drivers/rtc/rtc-palmas.c
+++ b/drivers/rtc/rtc-palmas.c
@@ -287,7 +287,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
palmas_rtc->irq = platform_get_irq(pdev, 0);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&palmas_rtc_ops, THIS_MODULE);
if (IS_ERR(palmas_rtc->rtc)) {
@@ -308,10 +308,9 @@ static int palmas_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int palmas_rtc_remove(struct platform_device *pdev)
+static void palmas_rtc_remove(struct platform_device *pdev)
{
palmas_rtc_alarm_irq_enable(&pdev->dev, 0);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c
index 8c7a98a5452c..d6651611a0c6 100644
--- a/drivers/rtc/rtc-pcap.c
+++ b/drivers/rtc/rtc-pcap.c
@@ -166,13 +166,7 @@ static int __init pcap_rtc_probe(struct platform_device *pdev)
return devm_rtc_register_device(pcap_rtc->rtc);
}
-static int __exit pcap_rtc_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver pcap_rtc_driver = {
- .remove = __exit_p(pcap_rtc_remove),
.driver = {
.name = "pcap-rtc",
},
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index e13b5e695d06..e714661e61a9 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -413,9 +413,14 @@ static int pcf2123_probe(struct spi_device *spi)
/* Register alarm irq */
if (spi->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&spi->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
pcf2123_rtc_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
pcf2123_driver.driver.name, &spi->dev);
if (!ret)
device_init_wakeup(&spi->dev, true);
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 87f4fc9df68b..bb4fe81d3d62 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * An I2C and SPI driver for the NXP PCF2127/29 RTC
+ * An I2C and SPI driver for the NXP PCF2127/29/31 RTC
* Copyright 2013 Til-Technologies
*
* Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
@@ -8,19 +8,25 @@
* Watchdog and tamper functions
* Author: Bruno Thomsen <bruno.thomsen@gmail.com>
*
+ * PCF2131 support
+ * Author: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+ *
* based on the other drivers in this same directory.
*
- * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf
+ * Datasheets: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf
+ * https://www.nxp.com/docs/en/data-sheet/PCF2131DS.pdf
*/
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/bcd.h>
+#include <linux/bitfield.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/watchdog.h>
@@ -28,6 +34,7 @@
#define PCF2127_REG_CTRL1 0x00
#define PCF2127_BIT_CTRL1_POR_OVRD BIT(3)
#define PCF2127_BIT_CTRL1_TSF1 BIT(4)
+#define PCF2127_BIT_CTRL1_STOP BIT(5)
/* Control register 2 */
#define PCF2127_REG_CTRL2 0x01
#define PCF2127_BIT_CTRL2_AIE BIT(1)
@@ -35,6 +42,7 @@
#define PCF2127_BIT_CTRL2_AF BIT(4)
#define PCF2127_BIT_CTRL2_TSF2 BIT(5)
#define PCF2127_BIT_CTRL2_WDTF BIT(6)
+#define PCF2127_BIT_CTRL2_MSF BIT(7)
/* Control register 3 */
#define PCF2127_REG_CTRL3 0x02
#define PCF2127_BIT_CTRL3_BLIE BIT(0)
@@ -42,21 +50,12 @@
#define PCF2127_BIT_CTRL3_BLF BIT(2)
#define PCF2127_BIT_CTRL3_BF BIT(3)
#define PCF2127_BIT_CTRL3_BTSE BIT(4)
+#define PCF2127_CTRL3_PM GENMASK(7, 5)
/* Time and date registers */
-#define PCF2127_REG_SC 0x03
+#define PCF2127_REG_TIME_BASE 0x03
#define PCF2127_BIT_SC_OSF BIT(7)
-#define PCF2127_REG_MN 0x04
-#define PCF2127_REG_HR 0x05
-#define PCF2127_REG_DM 0x06
-#define PCF2127_REG_DW 0x07
-#define PCF2127_REG_MO 0x08
-#define PCF2127_REG_YR 0x09
/* Alarm registers */
-#define PCF2127_REG_ALARM_SC 0x0A
-#define PCF2127_REG_ALARM_MN 0x0B
-#define PCF2127_REG_ALARM_HR 0x0C
-#define PCF2127_REG_ALARM_DM 0x0D
-#define PCF2127_REG_ALARM_DW 0x0E
+#define PCF2127_REG_ALARM_BASE 0x0A
#define PCF2127_BIT_ALARM_AE BIT(7)
/* CLKOUT control register */
#define PCF2127_REG_CLKOUT 0x0f
@@ -68,21 +67,15 @@
#define PCF2127_BIT_WD_CTL_CD0 BIT(6)
#define PCF2127_BIT_WD_CTL_CD1 BIT(7)
#define PCF2127_REG_WD_VAL 0x11
-/* Tamper timestamp registers */
-#define PCF2127_REG_TS_CTRL 0x12
+/* Tamper timestamp1 registers */
+#define PCF2127_REG_TS1_BASE 0x12
#define PCF2127_BIT_TS_CTRL_TSOFF BIT(6)
#define PCF2127_BIT_TS_CTRL_TSM BIT(7)
-#define PCF2127_REG_TS_SC 0x13
-#define PCF2127_REG_TS_MN 0x14
-#define PCF2127_REG_TS_HR 0x15
-#define PCF2127_REG_TS_DM 0x16
-#define PCF2127_REG_TS_MO 0x17
-#define PCF2127_REG_TS_YR 0x18
/*
* RAM registers
* PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is
* battery backed and can survive a power outage.
- * PCF2129 doesn't have this feature.
+ * PCF2129/31 doesn't have this feature.
*/
#define PCF2127_REG_RAM_ADDR_MSB 0x1A
#define PCF2127_REG_RAM_WRT_CMD 0x1C
@@ -90,24 +83,134 @@
/* Watchdog timer value constants */
#define PCF2127_WD_VAL_STOP 0
-#define PCF2127_WD_VAL_MIN 2
-#define PCF2127_WD_VAL_MAX 255
-#define PCF2127_WD_VAL_DEFAULT 60
+/* PCF2127/29 watchdog timer value constants */
+#define PCF2127_WD_CLOCK_HZ_X1000 1000 /* 1Hz */
+#define PCF2127_WD_MIN_HW_HEARTBEAT_MS 500
+/* PCF2131 watchdog timer value constants */
+#define PCF2131_WD_CLOCK_HZ_X1000 250 /* 1/4Hz */
+#define PCF2131_WD_MIN_HW_HEARTBEAT_MS 4000
+
+#define PCF2127_WD_DEFAULT_TIMEOUT_S 60
/* Mask for currently enabled interrupts */
#define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1)
#define PCF2127_CTRL2_IRQ_MASK ( \
PCF2127_BIT_CTRL2_AF | \
PCF2127_BIT_CTRL2_WDTF | \
- PCF2127_BIT_CTRL2_TSF2)
+ PCF2127_BIT_CTRL2_TSF2 | \
+ PCF2127_BIT_CTRL2_MSF)
+
+#define PCF2127_MAX_TS_SUPPORTED 4
+
+/* Control register 4 */
+#define PCF2131_REG_CTRL4 0x03
+#define PCF2131_BIT_CTRL4_TSF4 BIT(4)
+#define PCF2131_BIT_CTRL4_TSF3 BIT(5)
+#define PCF2131_BIT_CTRL4_TSF2 BIT(6)
+#define PCF2131_BIT_CTRL4_TSF1 BIT(7)
+/* Control register 5 */
+#define PCF2131_REG_CTRL5 0x04
+#define PCF2131_BIT_CTRL5_TSIE4 BIT(4)
+#define PCF2131_BIT_CTRL5_TSIE3 BIT(5)
+#define PCF2131_BIT_CTRL5_TSIE2 BIT(6)
+#define PCF2131_BIT_CTRL5_TSIE1 BIT(7)
+/* Software reset register */
+#define PCF2131_REG_SR_RESET 0x05
+#define PCF2131_SR_RESET_READ_PATTERN (BIT(2) | BIT(5))
+#define PCF2131_SR_RESET_CPR_CMD (PCF2131_SR_RESET_READ_PATTERN | BIT(7))
+/* Time and date registers */
+#define PCF2131_REG_TIME_BASE 0x07
+/* Alarm registers */
+#define PCF2131_REG_ALARM_BASE 0x0E
+/* CLKOUT control register */
+#define PCF2131_REG_CLKOUT 0x13
+/* Watchdog registers */
+#define PCF2131_REG_WD_CTL 0x35
+#define PCF2131_REG_WD_VAL 0x36
+/* Tamper timestamp1 registers */
+#define PCF2131_REG_TS1_BASE 0x14
+/* Tamper timestamp2 registers */
+#define PCF2131_REG_TS2_BASE 0x1B
+/* Tamper timestamp3 registers */
+#define PCF2131_REG_TS3_BASE 0x22
+/* Tamper timestamp4 registers */
+#define PCF2131_REG_TS4_BASE 0x29
+/* Interrupt mask registers */
+#define PCF2131_REG_INT_A_MASK1 0x31
+#define PCF2131_REG_INT_A_MASK2 0x32
+#define PCF2131_REG_INT_B_MASK1 0x33
+#define PCF2131_REG_INT_B_MASK2 0x34
+#define PCF2131_BIT_INT_BLIE BIT(0)
+#define PCF2131_BIT_INT_BIE BIT(1)
+#define PCF2131_BIT_INT_AIE BIT(2)
+#define PCF2131_BIT_INT_WD_CD BIT(3)
+#define PCF2131_BIT_INT_SI BIT(4)
+#define PCF2131_BIT_INT_MI BIT(5)
+#define PCF2131_CTRL2_IRQ_MASK ( \
+ PCF2127_BIT_CTRL2_AF | \
+ PCF2127_BIT_CTRL2_WDTF)
+#define PCF2131_CTRL4_IRQ_MASK ( \
+ PCF2131_BIT_CTRL4_TSF4 | \
+ PCF2131_BIT_CTRL4_TSF3 | \
+ PCF2131_BIT_CTRL4_TSF2 | \
+ PCF2131_BIT_CTRL4_TSF1)
+
+enum pcf21xx_type {
+ PCF2127,
+ PCF2129,
+ PCF2131,
+ PCF21XX_LAST_ID
+};
+
+struct pcf21xx_ts_config {
+ u8 reg_base; /* Base register to read timestamp values. */
+
+ /*
+ * If the TS input pin is driven to GND, an interrupt can be generated
+ * (supported by all variants).
+ */
+ u8 gnd_detect_reg; /* Interrupt control register address. */
+ u8 gnd_detect_bit; /* Interrupt bit. */
+
+ /*
+ * If the TS input pin is driven to an intermediate level between GND
+ * and supply, an interrupt can be generated (optional feature depending
+ * on variant).
+ */
+ u8 inter_detect_reg; /* Interrupt control register address. */
+ u8 inter_detect_bit; /* Interrupt bit. */
+
+ u8 ie_reg; /* Interrupt enable control register. */
+ u8 ie_bit; /* Interrupt enable bit. */
+};
+
+struct pcf21xx_config {
+ int type; /* IC variant */
+ int max_register;
+ unsigned int has_nvmem:1;
+ unsigned int has_bit_wd_ctl_cd0:1;
+ unsigned int wd_val_reg_readable:1; /* If watchdog value register can be read. */
+ unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */
+ u8 reg_time_base; /* Time/date base register. */
+ u8 regs_alarm_base; /* Alarm function base registers. */
+ u8 reg_wd_ctl; /* Watchdog control register. */
+ u8 reg_wd_val; /* Watchdog value register. */
+ u8 reg_clkout; /* Clkout register. */
+ int wdd_clock_hz_x1000; /* Watchdog clock in Hz multiplicated by 1000 */
+ int wdd_min_hw_heartbeat_ms;
+ unsigned int ts_count;
+ struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED];
+ struct attribute_group attribute_group;
+};
struct pcf2127 {
struct rtc_device *rtc;
struct watchdog_device wdd;
struct regmap *regmap;
- time64_t ts;
- bool ts_valid;
+ const struct pcf21xx_config *cfg;
bool irq_enabled;
+ time64_t ts[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp values. */
+ bool ts_valid[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp valid indication. */
};
/*
@@ -117,27 +220,22 @@ struct pcf2127 {
static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
- unsigned char buf[10];
+ unsigned char buf[7];
int ret;
/*
* Avoid reading CTRL2 register as it causes WD_VAL register
* value to reset to 0 which means watchdog is stopped.
*/
- ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3,
- (buf + PCF2127_REG_CTRL3),
- ARRAY_SIZE(buf) - PCF2127_REG_CTRL3);
+ ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->reg_time_base,
+ buf, sizeof(buf));
if (ret) {
dev_err(dev, "%s: read error\n", __func__);
return ret;
}
- if (buf[PCF2127_REG_CTRL3] & PCF2127_BIT_CTRL3_BLF)
- dev_info(dev,
- "low voltage detected, check/replace RTC battery.\n");
-
/* Clock integrity is not guaranteed when OSF flag is set. */
- if (buf[PCF2127_REG_SC] & PCF2127_BIT_SC_OSF) {
+ if (buf[0] & PCF2127_BIT_SC_OSF) {
/*
* no need clear the flag here,
* it will be cleared once the new date is saved
@@ -148,20 +246,17 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
}
dev_dbg(dev,
- "%s: raw data is cr3=%02x, sec=%02x, min=%02x, hr=%02x, "
+ "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
- __func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC],
- buf[PCF2127_REG_MN], buf[PCF2127_REG_HR],
- buf[PCF2127_REG_DM], buf[PCF2127_REG_DW],
- buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]);
-
- tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F);
- tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F);
- tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */
- tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F);
- tm->tm_wday = buf[PCF2127_REG_DW] & 0x07;
- tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]);
+ __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+ tm->tm_sec = bcd2bin(buf[0] & 0x7F);
+ tm->tm_min = bcd2bin(buf[1] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[2] & 0x3F);
+ tm->tm_mday = bcd2bin(buf[3] & 0x3F);
+ tm->tm_wday = buf[4] & 0x07;
+ tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1;
+ tm->tm_year = bcd2bin(buf[6]);
tm->tm_year += 100;
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
@@ -198,14 +293,123 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* year */
buf[i++] = bin2bcd(tm->tm_year - 100);
- /* write register's data */
- err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i);
+ /* Write access to time registers:
+ * PCF2127/29: no special action required.
+ * PCF2131: requires setting the STOP and CPR bits. STOP bit needs to
+ * be cleared after time registers are updated.
+ */
+ if (pcf2127->cfg->type == PCF2131) {
+ err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
+ PCF2127_BIT_CTRL1_STOP,
+ PCF2127_BIT_CTRL1_STOP);
+ if (err) {
+ dev_dbg(dev, "setting STOP bit failed\n");
+ return err;
+ }
+
+ err = regmap_write(pcf2127->regmap, PCF2131_REG_SR_RESET,
+ PCF2131_SR_RESET_CPR_CMD);
+ if (err) {
+ dev_dbg(dev, "sending CPR cmd failed\n");
+ return err;
+ }
+ }
+
+ /* write time register's data */
+ err = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->reg_time_base, buf, i);
if (err) {
- dev_err(dev,
- "%s: err=%d", __func__, err);
+ dev_dbg(dev, "%s: err=%d", __func__, err);
return err;
}
+ if (pcf2127->cfg->type == PCF2131) {
+ /* Clear STOP bit (PCF2131 only) after write is completed. */
+ err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
+ PCF2127_BIT_CTRL1_STOP, 0);
+ if (err) {
+ dev_dbg(dev, "clearing STOP bit failed\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int pcf2127_param_get(struct device *dev, struct rtc_param *param)
+{
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ u32 value;
+ int ret;
+
+ switch (param->param) {
+ case RTC_PARAM_BACKUP_SWITCH_MODE:
+ ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &value);
+ if (ret < 0)
+ return ret;
+
+ value = FIELD_GET(PCF2127_CTRL3_PM, value);
+
+ if (value < 0x3)
+ param->uvalue = RTC_BSM_LEVEL;
+ else if (value < 0x6)
+ param->uvalue = RTC_BSM_DIRECT;
+ else
+ param->uvalue = RTC_BSM_DISABLED;
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pcf2127_param_set(struct device *dev, struct rtc_param *param)
+{
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ u8 mode = 0;
+ u32 value;
+ int ret;
+
+ switch (param->param) {
+ case RTC_PARAM_BACKUP_SWITCH_MODE:
+ ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &value);
+ if (ret < 0)
+ return ret;
+
+ value = FIELD_GET(PCF2127_CTRL3_PM, value);
+
+ if (value > 5)
+ value -= 5;
+ else if (value > 2)
+ value -= 3;
+
+ switch (param->uvalue) {
+ case RTC_BSM_LEVEL:
+ break;
+ case RTC_BSM_DIRECT:
+ mode = 3;
+ break;
+ case RTC_BSM_DISABLED:
+ if (value == 0)
+ value = 1;
+ mode = 5;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL3,
+ PCF2127_CTRL3_PM,
+ FIELD_PREP(PCF2127_CTRL3_PM, mode + value));
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
return 0;
}
@@ -275,9 +479,16 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset,
static int pcf2127_wdt_ping(struct watchdog_device *wdd)
{
+ int wd_val;
struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd);
- return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, wdd->timeout);
+ /*
+ * Compute counter value of WATCHDG_TIM_VAL to obtain desired period
+ * in seconds, depending on the source clock frequency.
+ */
+ wd_val = ((wdd->timeout * pcf2127->cfg->wdd_clock_hz_x1000) / 1000) + 1;
+
+ return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wd_val);
}
/*
@@ -311,7 +522,7 @@ static int pcf2127_wdt_stop(struct watchdog_device *wdd)
{
struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd);
- return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL,
+ return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val,
PCF2127_WD_VAL_STOP);
}
@@ -339,9 +550,25 @@ static const struct watchdog_ops pcf2127_watchdog_ops = {
.set_timeout = pcf2127_wdt_set_timeout,
};
+/*
+ * Compute watchdog period, t, in seconds, from the WATCHDG_TIM_VAL register
+ * value, n, and the clock frequency, f1000, in Hz x 1000.
+ *
+ * The PCF2127/29 datasheet gives t as:
+ * t = n / f
+ * The PCF2131 datasheet gives t as:
+ * t = (n - 1) / f
+ * For both variants, the watchdog is triggered when the WATCHDG_TIM_VAL reaches
+ * the value 1, and not zero. Consequently, the equation from the PCF2131
+ * datasheet seems to be the correct one for both variants.
+ */
+static int pcf2127_watchdog_get_period(int n, int f1000)
+{
+ return (1000 * (n - 1)) / f1000;
+}
+
static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
{
- u32 wdd_timeout;
int ret;
if (!IS_ENABLED(CONFIG_WATCHDOG) ||
@@ -351,21 +578,50 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
pcf2127->wdd.parent = dev;
pcf2127->wdd.info = &pcf2127_wdt_info;
pcf2127->wdd.ops = &pcf2127_watchdog_ops;
- pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN;
- pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX;
- pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT;
- pcf2127->wdd.min_hw_heartbeat_ms = 500;
+
+ pcf2127->wdd.min_timeout =
+ pcf2127_watchdog_get_period(
+ 2, pcf2127->cfg->wdd_clock_hz_x1000);
+ pcf2127->wdd.max_timeout =
+ pcf2127_watchdog_get_period(
+ 255, pcf2127->cfg->wdd_clock_hz_x1000);
+ pcf2127->wdd.timeout = PCF2127_WD_DEFAULT_TIMEOUT_S;
+
+ dev_dbg(dev, "%s clock = %d Hz / 1000\n", __func__,
+ pcf2127->cfg->wdd_clock_hz_x1000);
+
+ pcf2127->wdd.min_hw_heartbeat_ms = pcf2127->cfg->wdd_min_hw_heartbeat_ms;
pcf2127->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
watchdog_set_drvdata(&pcf2127->wdd, pcf2127);
/* Test if watchdog timer is started by bootloader */
- ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout);
- if (ret)
- return ret;
+ if (pcf2127->cfg->wd_val_reg_readable) {
+ u32 wdd_timeout;
- if (wdd_timeout)
- set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status);
+ ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val,
+ &wdd_timeout);
+ if (ret)
+ return ret;
+
+ if (wdd_timeout)
+ set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status);
+ }
+
+ /*
+ * When using interrupt pin (INT A) as watchdog output, only allow
+ * watchdog interrupt (PCF2131_BIT_INT_WD_CD) and disable (mask) all
+ * other interrupts.
+ */
+ if (pcf2127->cfg->type == PCF2131) {
+ ret = regmap_write(pcf2127->regmap,
+ PCF2131_REG_INT_A_MASK1,
+ PCF2131_BIT_INT_BLIE |
+ PCF2131_BIT_INT_BIE |
+ PCF2131_BIT_INT_AIE |
+ PCF2131_BIT_INT_SI |
+ PCF2131_BIT_INT_MI);
+ }
return devm_watchdog_register_device(dev, &pcf2127->wdd);
}
@@ -386,8 +642,8 @@ static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret)
return ret;
- ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf,
- sizeof(buf));
+ ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->regs_alarm_base,
+ buf, sizeof(buf));
if (ret)
return ret;
@@ -437,8 +693,8 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
buf[3] = bin2bcd(alrm->time.tm_mday);
buf[4] = PCF2127_BIT_ALARM_AE; /* Do not match on week day */
- ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf,
- sizeof(buf));
+ ret = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->regs_alarm_base,
+ buf, sizeof(buf));
if (ret)
return ret;
@@ -446,38 +702,35 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
}
/*
- * This function reads ctrl2 register, caller is responsible for calling
- * pcf2127_wdt_active_ping()
+ * This function reads one timestamp function data, caller is responsible for
+ * calling pcf2127_wdt_active_ping()
*/
-static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts)
+static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts,
+ int ts_id)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
struct rtc_time tm;
int ret;
- unsigned char data[25];
+ unsigned char data[7];
- ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data,
- sizeof(data));
+ ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->ts[ts_id].reg_base,
+ data, sizeof(data));
if (ret) {
dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
return ret;
}
dev_dbg(dev,
- "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
- __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2],
- data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC],
- data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR],
- data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO],
- data[PCF2127_REG_TS_YR]);
-
- tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F);
- tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F);
- tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F);
- tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F);
+ "%s: raw data is ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
+ __func__, data[1], data[2], data[3], data[4], data[5], data[6]);
+
+ tm.tm_sec = bcd2bin(data[1] & 0x7F);
+ tm.tm_min = bcd2bin(data[2] & 0x7F);
+ tm.tm_hour = bcd2bin(data[3] & 0x3F);
+ tm.tm_mday = bcd2bin(data[4] & 0x3F);
/* TS_MO register (month) value range: 1-12 */
- tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1;
- tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]);
+ tm.tm_mon = bcd2bin(data[5] & 0x1F) - 1;
+ tm.tm_year = bcd2bin(data[6]);
if (tm.tm_year < 70)
tm.tm_year += 100; /* assume we are in 1970...2069 */
@@ -491,47 +744,84 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts)
return 0;
};
-static void pcf2127_rtc_ts_snapshot(struct device *dev)
+static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
int ret;
+ if (ts_id >= pcf2127->cfg->ts_count)
+ return;
+
/* Let userspace read the first timestamp */
- if (pcf2127->ts_valid)
+ if (pcf2127->ts_valid[ts_id])
return;
- ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts);
+ ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts[ts_id], ts_id);
if (!ret)
- pcf2127->ts_valid = true;
+ pcf2127->ts_valid[ts_id] = true;
}
static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
- unsigned int ctrl1, ctrl2;
+ unsigned int ctrl2;
int ret = 0;
- ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
- if (ret)
- return IRQ_NONE;
-
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
if (ret)
return IRQ_NONE;
- if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK))
- return IRQ_NONE;
+ if (pcf2127->cfg->ts_count == 1) {
+ /* PCF2127/29 */
+ unsigned int ctrl1;
- if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2)
- pcf2127_rtc_ts_snapshot(dev);
+ ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
+ if (ret)
+ return IRQ_NONE;
+
+ if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK))
+ return IRQ_NONE;
+
+ if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2)
+ pcf2127_rtc_ts_snapshot(dev, 0);
+
+ if (ctrl1 & PCF2127_CTRL1_IRQ_MASK)
+ regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1,
+ ctrl1 & ~PCF2127_CTRL1_IRQ_MASK);
+
+ if (ctrl2 & PCF2127_CTRL2_IRQ_MASK)
+ regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
+ ctrl2 & ~PCF2127_CTRL2_IRQ_MASK);
+ } else {
+ /* PCF2131. */
+ unsigned int ctrl4;
+
+ ret = regmap_read(pcf2127->regmap, PCF2131_REG_CTRL4, &ctrl4);
+ if (ret)
+ return IRQ_NONE;
+
+ if (!(ctrl4 & PCF2131_CTRL4_IRQ_MASK || ctrl2 & PCF2131_CTRL2_IRQ_MASK))
+ return IRQ_NONE;
+
+ if (ctrl4 & PCF2131_CTRL4_IRQ_MASK) {
+ int i;
+ int tsf_bit = PCF2131_BIT_CTRL4_TSF1; /* Start at bit 7. */
+
+ for (i = 0; i < pcf2127->cfg->ts_count; i++) {
+ if (ctrl4 & tsf_bit)
+ pcf2127_rtc_ts_snapshot(dev, i);
- if (ctrl1 & PCF2127_CTRL1_IRQ_MASK)
- regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1,
- ctrl1 & ~PCF2127_CTRL1_IRQ_MASK);
+ tsf_bit = tsf_bit >> 1;
+ }
- if (ctrl2 & PCF2127_CTRL2_IRQ_MASK)
- regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
- ctrl2 & ~PCF2127_CTRL2_IRQ_MASK);
+ regmap_write(pcf2127->regmap, PCF2131_REG_CTRL4,
+ ctrl4 & ~PCF2131_CTRL4_IRQ_MASK);
+ }
+
+ if (ctrl2 & PCF2131_CTRL2_IRQ_MASK)
+ regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2,
+ ctrl2 & ~PCF2131_CTRL2_IRQ_MASK);
+ }
if (ctrl2 & PCF2127_BIT_CTRL2_AF)
rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF);
@@ -548,32 +838,47 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
.read_alarm = pcf2127_rtc_read_alarm,
.set_alarm = pcf2127_rtc_set_alarm,
.alarm_irq_enable = pcf2127_rtc_alarm_irq_enable,
+ .param_get = pcf2127_param_get,
+ .param_set = pcf2127_param_set,
};
/* sysfs interface */
-static ssize_t timestamp0_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t timestamp_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count, int ts_id)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
int ret;
+ if (ts_id >= pcf2127->cfg->ts_count)
+ return 0;
+
if (pcf2127->irq_enabled) {
- pcf2127->ts_valid = false;
+ pcf2127->ts_valid[ts_id] = false;
} else {
- ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
- PCF2127_BIT_CTRL1_TSF1, 0);
+ /* Always clear GND interrupt bit. */
+ ret = regmap_update_bits(pcf2127->regmap,
+ pcf2127->cfg->ts[ts_id].gnd_detect_reg,
+ pcf2127->cfg->ts[ts_id].gnd_detect_bit,
+ 0);
+
if (ret) {
- dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
+ dev_err(dev, "%s: update TS gnd detect ret=%d\n", __func__, ret);
return ret;
}
- ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
- PCF2127_BIT_CTRL2_TSF2, 0);
- if (ret) {
- dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret);
- return ret;
+ if (pcf2127->cfg->ts[ts_id].inter_detect_bit) {
+ /* Clear intermediate level interrupt bit if supported. */
+ ret = regmap_update_bits(pcf2127->regmap,
+ pcf2127->cfg->ts[ts_id].inter_detect_reg,
+ pcf2127->cfg->ts[ts_id].inter_detect_bit,
+ 0);
+ if (ret) {
+ dev_err(dev, "%s: update TS intermediate level detect ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
}
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
@@ -582,34 +887,84 @@ static ssize_t timestamp0_store(struct device *dev,
}
return count;
+}
+
+static ssize_t timestamp0_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return timestamp_store(dev, attr, buf, count, 0);
};
-static ssize_t timestamp0_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t timestamp1_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return timestamp_store(dev, attr, buf, count, 1);
+};
+
+static ssize_t timestamp2_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return timestamp_store(dev, attr, buf, count, 2);
+};
+
+static ssize_t timestamp3_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return timestamp_store(dev, attr, buf, count, 3);
+};
+
+static ssize_t timestamp_show(struct device *dev,
+ struct device_attribute *attr, char *buf,
+ int ts_id)
{
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
- unsigned int ctrl1, ctrl2;
int ret;
time64_t ts;
+ if (ts_id >= pcf2127->cfg->ts_count)
+ return 0;
+
if (pcf2127->irq_enabled) {
- if (!pcf2127->ts_valid)
+ if (!pcf2127->ts_valid[ts_id])
return 0;
- ts = pcf2127->ts;
+ ts = pcf2127->ts[ts_id];
} else {
- ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
- if (ret)
- return 0;
+ u8 valid_low = 0;
+ u8 valid_inter = 0;
+ unsigned int ctrl;
- ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
+ /* Check if TS input pin is driven to GND, supported by all
+ * variants.
+ */
+ ret = regmap_read(pcf2127->regmap,
+ pcf2127->cfg->ts[ts_id].gnd_detect_reg,
+ &ctrl);
if (ret)
return 0;
- if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) &&
- !(ctrl2 & PCF2127_BIT_CTRL2_TSF2))
+ valid_low = ctrl & pcf2127->cfg->ts[ts_id].gnd_detect_bit;
+
+ if (pcf2127->cfg->ts[ts_id].inter_detect_bit) {
+ /* Check if TS input pin is driven to intermediate level
+ * between GND and supply, if supported by variant.
+ */
+ ret = regmap_read(pcf2127->regmap,
+ pcf2127->cfg->ts[ts_id].inter_detect_reg,
+ &ctrl);
+ if (ret)
+ return 0;
+
+ valid_inter = ctrl & pcf2127->cfg->ts[ts_id].inter_detect_bit;
+ }
+
+ if (!valid_low && !valid_inter)
return 0;
- ret = pcf2127_rtc_ts_read(dev->parent, &ts);
+ ret = pcf2127_rtc_ts_read(dev->parent, &ts, ts_id);
if (ret)
return 0;
@@ -618,21 +973,227 @@ static ssize_t timestamp0_show(struct device *dev,
return ret;
}
return sprintf(buf, "%llu\n", (unsigned long long)ts);
+}
+
+static ssize_t timestamp0_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return timestamp_show(dev, attr, buf, 0);
+};
+
+static ssize_t timestamp1_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return timestamp_show(dev, attr, buf, 1);
+};
+
+static ssize_t timestamp2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return timestamp_show(dev, attr, buf, 2);
+};
+
+static ssize_t timestamp3_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return timestamp_show(dev, attr, buf, 3);
};
static DEVICE_ATTR_RW(timestamp0);
+static DEVICE_ATTR_RW(timestamp1);
+static DEVICE_ATTR_RW(timestamp2);
+static DEVICE_ATTR_RW(timestamp3);
static struct attribute *pcf2127_attrs[] = {
&dev_attr_timestamp0.attr,
NULL
};
-static const struct attribute_group pcf2127_attr_group = {
- .attrs = pcf2127_attrs,
+static struct attribute *pcf2131_attrs[] = {
+ &dev_attr_timestamp0.attr,
+ &dev_attr_timestamp1.attr,
+ &dev_attr_timestamp2.attr,
+ &dev_attr_timestamp3.attr,
+ NULL
+};
+
+static struct pcf21xx_config pcf21xx_cfg[] = {
+ [PCF2127] = {
+ .type = PCF2127,
+ .max_register = 0x1d,
+ .has_nvmem = 1,
+ .has_bit_wd_ctl_cd0 = 1,
+ .wd_val_reg_readable = 1,
+ .has_int_a_b = 0,
+ .reg_time_base = PCF2127_REG_TIME_BASE,
+ .regs_alarm_base = PCF2127_REG_ALARM_BASE,
+ .reg_wd_ctl = PCF2127_REG_WD_CTL,
+ .reg_wd_val = PCF2127_REG_WD_VAL,
+ .reg_clkout = PCF2127_REG_CLKOUT,
+ .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000,
+ .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS,
+ .ts_count = 1,
+ .ts[0] = {
+ .reg_base = PCF2127_REG_TS1_BASE,
+ .gnd_detect_reg = PCF2127_REG_CTRL1,
+ .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1,
+ .inter_detect_reg = PCF2127_REG_CTRL2,
+ .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2,
+ .ie_reg = PCF2127_REG_CTRL2,
+ .ie_bit = PCF2127_BIT_CTRL2_TSIE,
+ },
+ .attribute_group = {
+ .attrs = pcf2127_attrs,
+ },
+ },
+ [PCF2129] = {
+ .type = PCF2129,
+ .max_register = 0x19,
+ .has_nvmem = 0,
+ .has_bit_wd_ctl_cd0 = 0,
+ .wd_val_reg_readable = 1,
+ .has_int_a_b = 0,
+ .reg_time_base = PCF2127_REG_TIME_BASE,
+ .regs_alarm_base = PCF2127_REG_ALARM_BASE,
+ .reg_wd_ctl = PCF2127_REG_WD_CTL,
+ .reg_wd_val = PCF2127_REG_WD_VAL,
+ .reg_clkout = PCF2127_REG_CLKOUT,
+ .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000,
+ .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS,
+ .ts_count = 1,
+ .ts[0] = {
+ .reg_base = PCF2127_REG_TS1_BASE,
+ .gnd_detect_reg = PCF2127_REG_CTRL1,
+ .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1,
+ .inter_detect_reg = PCF2127_REG_CTRL2,
+ .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2,
+ .ie_reg = PCF2127_REG_CTRL2,
+ .ie_bit = PCF2127_BIT_CTRL2_TSIE,
+ },
+ .attribute_group = {
+ .attrs = pcf2127_attrs,
+ },
+ },
+ [PCF2131] = {
+ .type = PCF2131,
+ .max_register = 0x36,
+ .has_nvmem = 0,
+ .has_bit_wd_ctl_cd0 = 0,
+ .wd_val_reg_readable = 0,
+ .has_int_a_b = 1,
+ .reg_time_base = PCF2131_REG_TIME_BASE,
+ .regs_alarm_base = PCF2131_REG_ALARM_BASE,
+ .reg_wd_ctl = PCF2131_REG_WD_CTL,
+ .reg_wd_val = PCF2131_REG_WD_VAL,
+ .reg_clkout = PCF2131_REG_CLKOUT,
+ .wdd_clock_hz_x1000 = PCF2131_WD_CLOCK_HZ_X1000,
+ .wdd_min_hw_heartbeat_ms = PCF2131_WD_MIN_HW_HEARTBEAT_MS,
+ .ts_count = 4,
+ .ts[0] = {
+ .reg_base = PCF2131_REG_TS1_BASE,
+ .gnd_detect_reg = PCF2131_REG_CTRL4,
+ .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF1,
+ .inter_detect_bit = 0,
+ .ie_reg = PCF2131_REG_CTRL5,
+ .ie_bit = PCF2131_BIT_CTRL5_TSIE1,
+ },
+ .ts[1] = {
+ .reg_base = PCF2131_REG_TS2_BASE,
+ .gnd_detect_reg = PCF2131_REG_CTRL4,
+ .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF2,
+ .inter_detect_bit = 0,
+ .ie_reg = PCF2131_REG_CTRL5,
+ .ie_bit = PCF2131_BIT_CTRL5_TSIE2,
+ },
+ .ts[2] = {
+ .reg_base = PCF2131_REG_TS3_BASE,
+ .gnd_detect_reg = PCF2131_REG_CTRL4,
+ .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF3,
+ .inter_detect_bit = 0,
+ .ie_reg = PCF2131_REG_CTRL5,
+ .ie_bit = PCF2131_BIT_CTRL5_TSIE3,
+ },
+ .ts[3] = {
+ .reg_base = PCF2131_REG_TS4_BASE,
+ .gnd_detect_reg = PCF2131_REG_CTRL4,
+ .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF4,
+ .inter_detect_bit = 0,
+ .ie_reg = PCF2131_REG_CTRL5,
+ .ie_bit = PCF2131_BIT_CTRL5_TSIE4,
+ },
+ .attribute_group = {
+ .attrs = pcf2131_attrs,
+ },
+ },
};
+/*
+ * Enable timestamp function and corresponding interrupt(s).
+ */
+static int pcf2127_enable_ts(struct device *dev, int ts_id)
+{
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ int ret;
+
+ if (ts_id >= pcf2127->cfg->ts_count) {
+ dev_err(dev, "%s: invalid tamper detection ID (%d)\n",
+ __func__, ts_id);
+ return -EINVAL;
+ }
+
+ /* Enable timestamp function. */
+ ret = regmap_update_bits(pcf2127->regmap,
+ pcf2127->cfg->ts[ts_id].reg_base,
+ PCF2127_BIT_TS_CTRL_TSOFF |
+ PCF2127_BIT_TS_CTRL_TSM,
+ PCF2127_BIT_TS_CTRL_TSM);
+ if (ret) {
+ dev_err(dev, "%s: tamper detection config (ts%d_ctrl) failed\n",
+ __func__, ts_id);
+ return ret;
+ }
+
+ /*
+ * Enable interrupt generation when TSF timestamp flag is set.
+ * Interrupt signals are open-drain outputs and can be left floating if
+ * unused.
+ */
+ ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->ts[ts_id].ie_reg,
+ pcf2127->cfg->ts[ts_id].ie_bit,
+ pcf2127->cfg->ts[ts_id].ie_bit);
+ if (ret) {
+ dev_err(dev, "%s: tamper detection TSIE%d config failed\n",
+ __func__, ts_id);
+ return ret;
+ }
+
+ return ret;
+}
+
+/* Route all interrupt sources to INT A pin. */
+static int pcf2127_configure_interrupt_pins(struct device *dev)
+{
+ struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
+ int ret;
+
+ /* Mask bits need to be cleared to enable corresponding
+ * interrupt source.
+ */
+ ret = regmap_write(pcf2127->regmap,
+ PCF2131_REG_INT_A_MASK1, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(pcf2127->regmap,
+ PCF2131_REG_INT_A_MASK2, 0);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
- int alarm_irq, const char *name, bool is_pcf2127)
+ int alarm_irq, const struct pcf21xx_config *config)
{
struct pcf2127 *pcf2127;
int ret = 0;
@@ -645,6 +1206,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
return -ENOMEM;
pcf2127->regmap = regmap;
+ pcf2127->cfg = config;
dev_set_drvdata(dev, pcf2127);
@@ -656,8 +1218,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
pcf2127->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099;
pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */
- set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features);
- clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features);
+
+ /*
+ * PCF2127/29 do not work correctly when setting alarms at 1s intervals.
+ * PCF2131 is ok.
+ */
+ if (pcf2127->cfg->type == PCF2127 || pcf2127->cfg->type == PCF2129) {
+ set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features);
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features);
+ }
+
clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features);
if (alarm_irq > 0) {
@@ -688,7 +1258,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features);
}
- if (is_pcf2127) {
+ if (pcf2127->cfg->has_int_a_b) {
+ /* Configure int A/B pins, independently of alarm_irq. */
+ ret = pcf2127_configure_interrupt_pins(dev);
+ if (ret) {
+ dev_err(dev, "failed to configure interrupt pins\n");
+ return ret;
+ }
+ }
+
+ if (pcf2127->cfg->has_nvmem) {
struct nvmem_config nvmem_cfg = {
.priv = pcf2127,
.reg_read = pcf2127_nvmem_read,
@@ -703,15 +1282,17 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
* The "Power-On Reset Override" facility prevents the RTC to do a reset
* after power on. For normal operation the PORO must be disabled.
*/
- regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
+ ret = regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
PCF2127_BIT_CTRL1_POR_OVRD);
+ if (ret < 0)
+ return ret;
- ret = regmap_read(pcf2127->regmap, PCF2127_REG_CLKOUT, &val);
+ ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_clkout, &val);
if (ret < 0)
return ret;
if (!(val & PCF2127_BIT_CLKOUT_OTPR)) {
- ret = regmap_set_bits(pcf2127->regmap, PCF2127_REG_CLKOUT,
+ ret = regmap_set_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout,
PCF2127_BIT_CLKOUT_OTPR);
if (ret < 0)
return ret;
@@ -721,20 +1302,20 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
/*
* Watchdog timer enabled and reset pin /RST activated when timed out.
- * Select 1Hz clock source for watchdog timer.
+ * Select 1Hz clock source for watchdog timer (1/4Hz for PCF2131).
* Note: Countdown timer disabled and not available.
- * For pca2129, pcf2129, only bit[7] is for Symbol WD_CD
+ * For pca2129, pcf2129 and pcf2131, only bit[7] is for Symbol WD_CD
* of register watchdg_tim_ctl. The bit[6] is labeled
* as T. Bits labeled as T must always be written with
* logic 0.
*/
- ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL,
+ ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_wd_ctl,
PCF2127_BIT_WD_CTL_CD1 |
PCF2127_BIT_WD_CTL_CD0 |
PCF2127_BIT_WD_CTL_TF1 |
PCF2127_BIT_WD_CTL_TF0,
PCF2127_BIT_WD_CTL_CD1 |
- (is_pcf2127 ? PCF2127_BIT_WD_CTL_CD0 : 0) |
+ (pcf2127->cfg->has_bit_wd_ctl_cd0 ? PCF2127_BIT_WD_CTL_CD0 : 0) |
PCF2127_BIT_WD_CTL_TF1);
if (ret) {
dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__);
@@ -760,34 +1341,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
}
/*
- * Enable timestamp function and store timestamp of first trigger
- * event until TSF1 and TSF2 interrupt flags are cleared.
- */
- ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL,
- PCF2127_BIT_TS_CTRL_TSOFF |
- PCF2127_BIT_TS_CTRL_TSM,
- PCF2127_BIT_TS_CTRL_TSM);
- if (ret) {
- dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n",
- __func__);
- return ret;
- }
-
- /*
- * Enable interrupt generation when TSF1 or TSF2 timestamp flags
- * are set. Interrupt signal is an open-drain output and can be
- * left floating if unused.
+ * Enable timestamp functions 1 to 4.
*/
- ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
- PCF2127_BIT_CTRL2_TSIE,
- PCF2127_BIT_CTRL2_TSIE);
- if (ret) {
- dev_err(dev, "%s: tamper detection config (ctrl2) failed\n",
- __func__);
- return ret;
+ for (int i = 0; i < pcf2127->cfg->ts_count; i++) {
+ ret = pcf2127_enable_ts(dev, i);
+ if (ret)
+ return ret;
}
- ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group);
+ ret = rtc_add_group(pcf2127->rtc, &pcf2127->cfg->attribute_group);
if (ret) {
dev_err(dev, "%s: tamper sysfs registering failed\n",
__func__);
@@ -799,9 +1361,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
#ifdef CONFIG_OF
static const struct of_device_id pcf2127_of_match[] = {
- { .compatible = "nxp,pcf2127" },
- { .compatible = "nxp,pcf2129" },
- { .compatible = "nxp,pca2129" },
+ { .compatible = "nxp,pcf2127", .data = &pcf21xx_cfg[PCF2127] },
+ { .compatible = "nxp,pcf2129", .data = &pcf21xx_cfg[PCF2129] },
+ { .compatible = "nxp,pca2129", .data = &pcf21xx_cfg[PCF2129] },
+ { .compatible = "nxp,pcf2131", .data = &pcf21xx_cfg[PCF2131] },
{}
};
MODULE_DEVICE_TABLE(of, pcf2127_of_match);
@@ -886,26 +1449,41 @@ static const struct regmap_bus pcf2127_i2c_regmap = {
static struct i2c_driver pcf2127_i2c_driver;
static const struct i2c_device_id pcf2127_i2c_id[] = {
- { "pcf2127", 1 },
- { "pcf2129", 0 },
- { "pca2129", 0 },
+ { "pcf2127", PCF2127 },
+ { "pcf2129", PCF2129 },
+ { "pca2129", PCF2129 },
+ { "pcf2131", PCF2131 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);
static int pcf2127_i2c_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_match_id(pcf2127_i2c_id, client);
struct regmap *regmap;
- static const struct regmap_config config = {
+ static struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = 0x1d,
};
+ const struct pcf21xx_config *variant;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
+ if (client->dev.of_node) {
+ variant = of_device_get_match_data(&client->dev);
+ if (!variant)
+ return -ENODEV;
+ } else {
+ enum pcf21xx_type type =
+ i2c_match_id(pcf2127_i2c_id, client)->driver_data;
+
+ if (type >= PCF21XX_LAST_ID)
+ return -ENODEV;
+ variant = &pcf21xx_cfg[type];
+ }
+
+ config.max_register = variant->max_register,
+
regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap,
&client->dev, &config);
if (IS_ERR(regmap)) {
@@ -914,8 +1492,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client)
return PTR_ERR(regmap);
}
- return pcf2127_probe(&client->dev, regmap, client->irq,
- pcf2127_i2c_driver.driver.name, id->driver_data);
+ return pcf2127_probe(&client->dev, regmap, client->irq, variant);
}
static struct i2c_driver pcf2127_i2c_driver = {
@@ -923,7 +1500,7 @@ static struct i2c_driver pcf2127_i2c_driver = {
.name = "rtc-pcf2127-i2c",
.of_match_table = of_match_ptr(pcf2127_of_match),
},
- .probe_new = pcf2127_i2c_probe,
+ .probe = pcf2127_i2c_probe,
.id_table = pcf2127_i2c_id,
};
@@ -953,17 +1530,37 @@ static void pcf2127_i2c_unregister_driver(void)
#if IS_ENABLED(CONFIG_SPI_MASTER)
static struct spi_driver pcf2127_spi_driver;
+static const struct spi_device_id pcf2127_spi_id[];
static int pcf2127_spi_probe(struct spi_device *spi)
{
- static const struct regmap_config config = {
+ static struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
.read_flag_mask = 0xa0,
.write_flag_mask = 0x20,
- .max_register = 0x1d,
};
struct regmap *regmap;
+ const struct pcf21xx_config *variant;
+
+ if (spi->dev.of_node) {
+ variant = of_device_get_match_data(&spi->dev);
+ if (!variant)
+ return -ENODEV;
+ } else {
+ enum pcf21xx_type type = spi_get_device_id(spi)->driver_data;
+
+ if (type >= PCF21XX_LAST_ID)
+ return -ENODEV;
+ variant = &pcf21xx_cfg[type];
+ }
+
+ if (variant->type == PCF2131) {
+ config.read_flag_mask = 0x0;
+ config.write_flag_mask = 0x0;
+ }
+
+ config.max_register = variant->max_register;
regmap = devm_regmap_init_spi(spi, &config);
if (IS_ERR(regmap)) {
@@ -972,15 +1569,14 @@ static int pcf2127_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap);
}
- return pcf2127_probe(&spi->dev, regmap, spi->irq,
- pcf2127_spi_driver.driver.name,
- spi_get_device_id(spi)->driver_data);
+ return pcf2127_probe(&spi->dev, regmap, spi->irq, variant);
}
static const struct spi_device_id pcf2127_spi_id[] = {
- { "pcf2127", 1 },
- { "pcf2129", 0 },
- { "pca2129", 0 },
+ { "pcf2127", PCF2127 },
+ { "pcf2129", PCF2129 },
+ { "pca2129", PCF2129 },
+ { "pcf2131", PCF2131 },
{ }
};
MODULE_DEVICE_TABLE(spi, pcf2127_spi_id);
@@ -1045,5 +1641,5 @@ static void __exit pcf2127_exit(void)
module_exit(pcf2127_exit)
MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>");
-MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver");
+MODULE_DESCRIPTION("NXP PCF2127/29/31 RTC driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
deleted file mode 100644
index 48951a16d65d..000000000000
--- a/drivers/rtc/rtc-pcf50633.c
+++ /dev/null
@@ -1,286 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* NXP PCF50633 RTC Driver
- *
- * (C) 2006-2008 by Openmoko, Inc.
- * Author: Balaji Rao <balajirrao@openmoko.org>
- * All rights reserved.
- *
- * Broken down from monstrous PCF50633 driver mainly by
- * Harald Welte, Andy Green and Werner Almesberger
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/err.h>
-
-#include <linux/mfd/pcf50633/core.h>
-
-#define PCF50633_REG_RTCSC 0x59 /* Second */
-#define PCF50633_REG_RTCMN 0x5a /* Minute */
-#define PCF50633_REG_RTCHR 0x5b /* Hour */
-#define PCF50633_REG_RTCWD 0x5c /* Weekday */
-#define PCF50633_REG_RTCDT 0x5d /* Day */
-#define PCF50633_REG_RTCMT 0x5e /* Month */
-#define PCF50633_REG_RTCYR 0x5f /* Year */
-#define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */
-#define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */
-#define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */
-#define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */
-#define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */
-#define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */
-#define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */
-
-enum pcf50633_time_indexes {
- PCF50633_TI_SEC,
- PCF50633_TI_MIN,
- PCF50633_TI_HOUR,
- PCF50633_TI_WKDAY,
- PCF50633_TI_DAY,
- PCF50633_TI_MONTH,
- PCF50633_TI_YEAR,
- PCF50633_TI_EXTENT /* always last */
-};
-
-struct pcf50633_time {
- u_int8_t time[PCF50633_TI_EXTENT];
-};
-
-struct pcf50633_rtc {
- int alarm_enabled;
- int alarm_pending;
-
- struct pcf50633 *pcf;
- struct rtc_device *rtc_dev;
-};
-
-static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)
-{
- rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]);
- rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]);
- rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);
- rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);
- rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]);
- rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]) - 1;
- rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;
-}
-
-static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)
-{
- pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec);
- pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min);
- pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);
- pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);
- pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday);
- pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon + 1);
- pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);
-}
-
-static int
-pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
-{
- struct pcf50633_rtc *rtc = dev_get_drvdata(dev);
- int err;
-
- if (enabled)
- err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
- else
- err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
-
- if (err < 0)
- return err;
-
- rtc->alarm_enabled = enabled;
-
- return 0;
-}
-
-static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
- struct pcf50633_rtc *rtc;
- struct pcf50633_time pcf_tm;
- int ret;
-
- rtc = dev_get_drvdata(dev);
-
- ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC,
- PCF50633_TI_EXTENT,
- &pcf_tm.time[0]);
- if (ret != PCF50633_TI_EXTENT) {
- dev_err(dev, "Failed to read time\n");
- return -EIO;
- }
-
- dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
- pcf_tm.time[PCF50633_TI_DAY],
- pcf_tm.time[PCF50633_TI_MONTH],
- pcf_tm.time[PCF50633_TI_YEAR],
- pcf_tm.time[PCF50633_TI_HOUR],
- pcf_tm.time[PCF50633_TI_MIN],
- pcf_tm.time[PCF50633_TI_SEC]);
-
- pcf2rtc_time(tm, &pcf_tm);
-
- dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
-
- return 0;
-}
-
-static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
-{
- struct pcf50633_rtc *rtc;
- struct pcf50633_time pcf_tm;
- int alarm_masked, ret = 0;
-
- rtc = dev_get_drvdata(dev);
-
- dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
-
- rtc2pcf_time(&pcf_tm, tm);
-
- dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
- pcf_tm.time[PCF50633_TI_DAY],
- pcf_tm.time[PCF50633_TI_MONTH],
- pcf_tm.time[PCF50633_TI_YEAR],
- pcf_tm.time[PCF50633_TI_HOUR],
- pcf_tm.time[PCF50633_TI_MIN],
- pcf_tm.time[PCF50633_TI_SEC]);
-
-
- alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
-
- if (!alarm_masked)
- pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
-
- /* Returns 0 on success */
- ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC,
- PCF50633_TI_EXTENT,
- &pcf_tm.time[0]);
-
- if (!alarm_masked)
- pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
-
- return ret;
-}
-
-static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-{
- struct pcf50633_rtc *rtc;
- struct pcf50633_time pcf_tm;
- int ret = 0;
-
- rtc = dev_get_drvdata(dev);
-
- alrm->enabled = rtc->alarm_enabled;
- alrm->pending = rtc->alarm_pending;
-
- ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
- PCF50633_TI_EXTENT, &pcf_tm.time[0]);
- if (ret != PCF50633_TI_EXTENT) {
- dev_err(dev, "Failed to read time\n");
- return -EIO;
- }
-
- pcf2rtc_time(&alrm->time, &pcf_tm);
-
- return rtc_valid_tm(&alrm->time);
-}
-
-static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-{
- struct pcf50633_rtc *rtc;
- struct pcf50633_time pcf_tm;
- int alarm_masked, ret = 0;
-
- rtc = dev_get_drvdata(dev);
-
- rtc2pcf_time(&pcf_tm, &alrm->time);
-
- /* do like mktime does and ignore tm_wday */
- pcf_tm.time[PCF50633_TI_WKDAY] = 7;
-
- alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
-
- /* disable alarm interrupt */
- if (!alarm_masked)
- pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
-
- /* Returns 0 on success */
- ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,
- PCF50633_TI_EXTENT, &pcf_tm.time[0]);
- if (!alrm->enabled)
- rtc->alarm_pending = 0;
-
- if (!alarm_masked || alrm->enabled)
- pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
- rtc->alarm_enabled = alrm->enabled;
-
- return ret;
-}
-
-static const struct rtc_class_ops pcf50633_rtc_ops = {
- .read_time = pcf50633_rtc_read_time,
- .set_time = pcf50633_rtc_set_time,
- .read_alarm = pcf50633_rtc_read_alarm,
- .set_alarm = pcf50633_rtc_set_alarm,
- .alarm_irq_enable = pcf50633_rtc_alarm_irq_enable,
-};
-
-static void pcf50633_rtc_irq(int irq, void *data)
-{
- struct pcf50633_rtc *rtc = data;
-
- rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
- rtc->alarm_pending = 1;
-}
-
-static int pcf50633_rtc_probe(struct platform_device *pdev)
-{
- struct pcf50633_rtc *rtc;
-
- rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
- if (!rtc)
- return -ENOMEM;
-
- rtc->pcf = dev_to_pcf50633(pdev->dev.parent);
- platform_set_drvdata(pdev, rtc);
- rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "pcf50633-rtc",
- &pcf50633_rtc_ops, THIS_MODULE);
-
- if (IS_ERR(rtc->rtc_dev))
- return PTR_ERR(rtc->rtc_dev);
-
- pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
- pcf50633_rtc_irq, rtc);
- return 0;
-}
-
-static int pcf50633_rtc_remove(struct platform_device *pdev)
-{
- struct pcf50633_rtc *rtc;
-
- rtc = platform_get_drvdata(pdev);
- pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
-
- return 0;
-}
-
-static struct platform_driver pcf50633_rtc_driver = {
- .driver = {
- .name = "pcf50633-rtc",
- },
- .probe = pcf50633_rtc_probe,
- .remove = pcf50633_rtc_remove,
-};
-
-module_platform_driver(pcf50633_rtc_driver);
-
-MODULE_DESCRIPTION("PCF50633 RTC driver");
-MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 754e03984f98..f643e0bd7351 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -14,9 +14,10 @@
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
+#include <linux/spi/spi.h>
/*
* Information for this driver was pulled from the following datasheets.
@@ -29,12 +30,16 @@
*
* https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8263-C7_App-Manual.pdf
* RV8263 -- Rev. 1.0 — January 2019
+ *
+ * https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8063-C7_App-Manual.pdf
+ * RV8063 -- Rev. 1.1 - October 2018
*/
#define PCF85063_REG_CTRL1 0x00 /* status */
#define PCF85063_REG_CTRL1_CAP_SEL BIT(0)
#define PCF85063_REG_CTRL1_STOP BIT(5)
#define PCF85063_REG_CTRL1_EXT_TEST BIT(7)
+#define PCF85063_REG_CTRL1_SWR 0x58
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_CTRL2_AF BIT(6)
@@ -322,7 +327,16 @@ static const struct rtc_class_ops pcf85063_rtc_ops = {
static int pcf85063_nvmem_read(void *priv, unsigned int offset,
void *val, size_t bytes)
{
- return regmap_read(priv, PCF85063_REG_RAM, val);
+ unsigned int tmp;
+ int ret;
+
+ ret = regmap_read(priv, PCF85063_REG_RAM, &tmp);
+ if (ret < 0)
+ return ret;
+
+ *(u8 *)val = tmp;
+
+ return 0;
}
static int pcf85063_nvmem_write(void *priv, unsigned int offset,
@@ -391,14 +405,19 @@ static unsigned long pcf85063_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[buf];
}
-static long pcf85063_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int pcf85063_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -472,7 +491,7 @@ static const struct clk_ops pcf85063_clkout_ops = {
.unprepare = pcf85063_clkout_unprepare,
.is_prepared = pcf85063_clkout_is_prepared,
.recalc_rate = pcf85063_clkout_recalc_rate,
- .round_rate = pcf85063_clkout_round_rate,
+ .determine_rate = pcf85063_clkout_determine_rate,
.set_rate = pcf85063_clkout_set_rate,
};
@@ -514,56 +533,12 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
}
#endif
-enum pcf85063_type {
- PCF85063,
- PCF85063TP,
- PCF85063A,
- RV8263,
- PCF85063_LAST_ID
-};
-
-static struct pcf85063_config pcf85063_cfg[] = {
- [PCF85063] = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x0a,
- },
- },
- [PCF85063TP] = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x0a,
- },
- },
- [PCF85063A] = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x11,
- },
- .has_alarms = 1,
- },
- [RV8263] = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x11,
- },
- .has_alarms = 1,
- .force_cap_7000 = 1,
- },
-};
-
-static const struct i2c_device_id pcf85063_ids[];
-
-static int pcf85063_probe(struct i2c_client *client)
+static int pcf85063_probe(struct device *dev, struct regmap *regmap, int irq,
+ const struct pcf85063_config *config)
{
struct pcf85063 *pcf85063;
unsigned int tmp;
int err;
- const struct pcf85063_config *config;
struct nvmem_config nvmem_cfg = {
.name = "pcf85063_nvram",
.reg_read = pcf85063_nvmem_read,
@@ -572,45 +547,43 @@ static int pcf85063_probe(struct i2c_client *client)
.size = 1,
};
- dev_dbg(&client->dev, "%s\n", __func__);
+ dev_dbg(dev, "%s\n", __func__);
- pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063),
+ pcf85063 = devm_kzalloc(dev, sizeof(struct pcf85063),
GFP_KERNEL);
if (!pcf85063)
return -ENOMEM;
- if (client->dev.of_node) {
- config = of_device_get_match_data(&client->dev);
- if (!config)
- return -ENODEV;
- } else {
- enum pcf85063_type type =
- i2c_match_id(pcf85063_ids, client)->driver_data;
- if (type >= PCF85063_LAST_ID)
- return -ENODEV;
- config = &pcf85063_cfg[type];
- }
-
- pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap);
- if (IS_ERR(pcf85063->regmap))
- return PTR_ERR(pcf85063->regmap);
+ pcf85063->regmap = regmap;
- i2c_set_clientdata(client, pcf85063);
+ dev_set_drvdata(dev, pcf85063);
- err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp);
- if (err) {
- dev_err(&client->dev, "RTC chip is not present\n");
- return err;
- }
+ err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp);
+ if (err)
+ return dev_err_probe(dev, err, "RTC chip is not present\n");
- pcf85063->rtc = devm_rtc_allocate_device(&client->dev);
+ pcf85063->rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(pcf85063->rtc))
return PTR_ERR(pcf85063->rtc);
- err = pcf85063_load_capacitance(pcf85063, client->dev.of_node,
+ /*
+ * If a Power loss is detected, SW reset the device.
+ * From PCF85063A datasheet:
+ * There is a low probability that some devices will have corruption
+ * of the registers after the automatic power-on reset...
+ */
+ if (tmp & PCF85063_REG_SC_OS) {
+ dev_warn(dev, "POR issue detected, sending a SW reset\n");
+ err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1,
+ PCF85063_REG_CTRL1_SWR);
+ if (err < 0)
+ dev_warn(dev, "SW reset failed, trying to continue\n");
+ }
+
+ err = pcf85063_load_capacitance(pcf85063, dev->of_node,
config->force_cap_7000 ? 7000 : 0);
if (err < 0)
- dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
+ dev_warn(dev, "failed to set xtal load capacitance: %d",
err);
pcf85063->rtc->ops = &pcf85063_rtc_ops;
@@ -620,18 +593,23 @@ static int pcf85063_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features);
clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
- if (config->has_alarms && client->irq > 0) {
- err = devm_request_threaded_irq(&client->dev, client->irq,
+ if (config->has_alarms && irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(dev))
+ irqflags = 0;
+
+ err = devm_request_threaded_irq(dev, irq,
NULL, pcf85063_rtc_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"pcf85063", pcf85063);
if (err) {
dev_warn(&pcf85063->rtc->dev,
"unable to request IRQ, alarms disabled\n");
} else {
set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
- device_init_wakeup(&client->dev, true);
- err = dev_pm_set_wake_irq(&client->dev, client->irq);
+ device_init_wakeup(dev, true);
+ err = dev_pm_set_wake_irq(dev, irq);
if (err)
dev_err(&pcf85063->rtc->dev,
"failed to enable irq wake\n");
@@ -649,38 +627,205 @@ static int pcf85063_probe(struct i2c_client *client)
return devm_rtc_register_device(pcf85063->rtc);
}
+#if IS_ENABLED(CONFIG_I2C)
+
+static const struct pcf85063_config config_pcf85063 = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x0a,
+ },
+};
+
+static const struct pcf85063_config config_pcf85063tp = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x0a,
+ },
+};
+
+static const struct pcf85063_config config_pcf85063a = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x11,
+ },
+ .has_alarms = 1,
+};
+
+static const struct pcf85063_config config_rv8263 = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x11,
+ },
+ .has_alarms = 1,
+ .force_cap_7000 = 1,
+};
+
static const struct i2c_device_id pcf85063_ids[] = {
- { "pca85073a", PCF85063A },
- { "pcf85063", PCF85063 },
- { "pcf85063tp", PCF85063TP },
- { "pcf85063a", PCF85063A },
- { "rv8263", RV8263 },
+ { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
+ { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 },
+ { "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp },
+ { "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
+ { "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 },
{}
};
MODULE_DEVICE_TABLE(i2c, pcf85063_ids);
#ifdef CONFIG_OF
static const struct of_device_id pcf85063_of_match[] = {
- { .compatible = "nxp,pca85073a", .data = &pcf85063_cfg[PCF85063A] },
- { .compatible = "nxp,pcf85063", .data = &pcf85063_cfg[PCF85063] },
- { .compatible = "nxp,pcf85063tp", .data = &pcf85063_cfg[PCF85063TP] },
- { .compatible = "nxp,pcf85063a", .data = &pcf85063_cfg[PCF85063A] },
- { .compatible = "microcrystal,rv8263", .data = &pcf85063_cfg[RV8263] },
+ { .compatible = "nxp,pca85073a", .data = &config_pcf85063a },
+ { .compatible = "nxp,pcf85063", .data = &config_pcf85063 },
+ { .compatible = "nxp,pcf85063tp", .data = &config_pcf85063tp },
+ { .compatible = "nxp,pcf85063a", .data = &config_pcf85063a },
+ { .compatible = "microcrystal,rv8263", .data = &config_rv8263 },
{}
};
MODULE_DEVICE_TABLE(of, pcf85063_of_match);
#endif
+static int pcf85063_i2c_probe(struct i2c_client *client)
+{
+ const struct pcf85063_config *config;
+ struct regmap *regmap;
+
+ config = i2c_get_match_data(client);
+ if (!config)
+ return -ENODEV;
+
+ regmap = devm_regmap_init_i2c(client, &config->regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcf85063_probe(&client->dev, regmap, client->irq, config);
+}
+
static struct i2c_driver pcf85063_driver = {
.driver = {
.name = "rtc-pcf85063",
.of_match_table = of_match_ptr(pcf85063_of_match),
},
- .probe_new = pcf85063_probe,
+ .probe = pcf85063_i2c_probe,
.id_table = pcf85063_ids,
};
-module_i2c_driver(pcf85063_driver);
+static int pcf85063_register_driver(void)
+{
+ return i2c_add_driver(&pcf85063_driver);
+}
+
+static void pcf85063_unregister_driver(void)
+{
+ i2c_del_driver(&pcf85063_driver);
+}
+
+#else
+
+static int pcf85063_register_driver(void)
+{
+ return 0;
+}
+
+static void pcf85063_unregister_driver(void)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_I2C) */
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static const struct pcf85063_config config_rv8063 = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x11,
+ .read_flag_mask = BIT(7) | BIT(5),
+ .write_flag_mask = BIT(5),
+ },
+ .has_alarms = 1,
+ .force_cap_7000 = 1,
+};
+
+static const struct spi_device_id rv8063_id[] = {
+ { "rv8063" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, rv8063_id);
+
+static const struct of_device_id rv8063_of_match[] = {
+ { .compatible = "microcrystal,rv8063" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rv8063_of_match);
+
+static int rv8063_probe(struct spi_device *spi)
+{
+ const struct pcf85063_config *config = &config_rv8063;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &config->regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcf85063_probe(&spi->dev, regmap, spi->irq, config);
+}
+
+static struct spi_driver rv8063_driver = {
+ .driver = {
+ .name = "rv8063",
+ .of_match_table = rv8063_of_match,
+ },
+ .probe = rv8063_probe,
+ .id_table = rv8063_id,
+};
+
+static int __init rv8063_register_driver(void)
+{
+ return spi_register_driver(&rv8063_driver);
+}
+
+static void __exit rv8063_unregister_driver(void)
+{
+ spi_unregister_driver(&rv8063_driver);
+}
+
+#else
+
+static int __init rv8063_register_driver(void)
+{
+ return 0;
+}
+
+static void __exit rv8063_unregister_driver(void)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_SPI_MASTER) */
+
+static int __init pcf85063_init(void)
+{
+ int ret;
+
+ ret = pcf85063_register_driver();
+ if (ret)
+ return ret;
+
+ ret = rv8063_register_driver();
+ if (ret)
+ pcf85063_unregister_driver();
+
+ return ret;
+}
+module_init(pcf85063_init);
+
+static void __exit pcf85063_exit(void)
+{
+ rv8063_unregister_driver();
+ pcf85063_unregister_driver();
+}
+module_exit(pcf85063_exit);
MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>");
MODULE_DESCRIPTION("PCF85063 RTC driver");
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index 92de99f11a7a..2c63c0ffd05a 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -21,7 +21,7 @@
#define PCF8523_CONTROL2_AF BIT(3)
#define PCF8523_REG_CONTROL3 0x02
-#define PCF8523_CONTROL3_PM GENMASK(7,5)
+#define PCF8523_CONTROL3_PM GENMASK(7, 5)
#define PCF8523_PM_STANDBY 0x7
#define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */
#define PCF8523_CONTROL3_BSF BIT(3)
@@ -65,7 +65,7 @@ static int pcf8523_load_capacitance(struct pcf8523 *pcf8523, struct device_node
load);
fallthrough;
case 12500:
- value |= PCF8523_CONTROL1_CAP_SEL;
+ value = PCF8523_CONTROL1_CAP_SEL;
break;
case 7000:
break;
@@ -234,8 +234,7 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param)
int ret;
u32 value;
- switch(param->param) {
-
+ switch (param->param) {
case RTC_PARAM_BACKUP_SWITCH_MODE:
ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value);
if (ret < 0)
@@ -243,7 +242,7 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param)
value = FIELD_GET(PCF8523_CONTROL3_PM, value);
- switch(value) {
+ switch (value) {
case 0x0:
case 0x4:
param->uvalue = RTC_BSM_LEVEL;
@@ -273,7 +272,7 @@ static int pcf8523_param_set(struct device *dev, struct rtc_param *param)
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
u8 mode;
- switch(param->param) {
+ switch (param->param) {
case RTC_PARAM_BACKUP_SWITCH_MODE:
switch (param->uvalue) {
case RTC_BSM_DISABLED:
@@ -371,6 +370,30 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset)
return regmap_write(pcf8523->regmap, PCF8523_REG_OFFSET, value);
}
+#ifdef CONFIG_PM_SLEEP
+static int pcf8523_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (client->irq > 0 && device_may_wakeup(dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+static int pcf8523_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (client->irq > 0 && device_may_wakeup(dev))
+ disable_irq_wake(client->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pcf8523_pm, pcf8523_suspend, pcf8523_resume);
+
static const struct rtc_class_ops pcf8523_rtc_ops = {
.read_time = pcf8523_rtc_read_time,
.set_time = pcf8523_rtc_set_time,
@@ -385,9 +408,9 @@ static const struct rtc_class_ops pcf8523_rtc_ops = {
};
static const struct regmap_config regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x13,
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x13,
};
static int pcf8523_probe(struct i2c_client *client)
@@ -445,13 +468,18 @@ static int pcf8523_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38);
if (err < 0)
return err;
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8523_irq,
- IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ IRQF_SHARED | IRQF_ONESHOT | irqflags,
dev_name(&rtc->dev), pcf8523);
if (err)
return err;
@@ -467,7 +495,7 @@ static int pcf8523_probe(struct i2c_client *client)
}
static const struct i2c_device_id pcf8523_id[] = {
- { "pcf8523", 0 },
+ { "pcf8523" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8523_id);
@@ -483,8 +511,9 @@ static struct i2c_driver pcf8523_driver = {
.driver = {
.name = "rtc-pcf8523",
.of_match_table = pcf8523_of_match,
+ .pm = &pcf8523_pm,
},
- .probe_new = pcf8523_probe,
+ .probe = pcf8523_probe,
.id_table = pcf8523_id,
};
module_i2c_driver(pcf8523_driver);
diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c
index c05b722f0060..540042b9eec8 100644
--- a/drivers/rtc/rtc-pcf85363.c
+++ b/drivers/rtc/rtc-pcf85363.c
@@ -15,7 +15,6 @@
#include <linux/errno.h>
#include <linux/bcd.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
/*
@@ -101,6 +100,10 @@
#define PIN_IO_INTA_OUT 2
#define PIN_IO_INTA_HIZ 3
+#define OSC_CAP_SEL GENMASK(1, 0)
+#define OSC_CAP_6000 0x01
+#define OSC_CAP_12500 0x02
+
#define STOP_EN_STOP BIT(0)
#define RESET_CPR 0xa4
@@ -117,6 +120,32 @@ struct pcf85x63_config {
unsigned int num_nvram;
};
+static int pcf85363_load_capacitance(struct pcf85363 *pcf85363, struct device_node *node)
+{
+ u32 load = 7000;
+ u8 value = 0;
+
+ of_property_read_u32(node, "quartz-load-femtofarads", &load);
+
+ switch (load) {
+ default:
+ dev_warn(&pcf85363->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
+ load);
+ fallthrough;
+ case 7000:
+ break;
+ case 6000:
+ value = OSC_CAP_6000;
+ break;
+ case 12500:
+ value = OSC_CAP_12500;
+ break;
+ }
+
+ return regmap_update_bits(pcf85363->regmap, CTRL_OSCILLATOR,
+ OSC_CAP_SEL, value);
+}
+
static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
@@ -372,7 +401,8 @@ static int pcf85363_probe(struct i2c_client *client)
.reg_write = pcf85363_nvram_write,
},
};
- int ret, i;
+ int ret, i, err;
+ bool wakeup_source;
if (data)
config = data;
@@ -394,23 +424,44 @@ static int pcf85363_probe(struct i2c_client *client)
if (IS_ERR(pcf85363->rtc))
return PTR_ERR(pcf85363->rtc);
+ err = pcf85363_load_capacitance(pcf85363, client->dev.of_node);
+ if (err < 0)
+ dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
+ err);
+
pcf85363->rtc->ops = &rtc_ops;
pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099;
- clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
- if (client->irq > 0) {
+ wakeup_source = device_property_read_bool(&client->dev,
+ "wakeup-source");
+ if (client->irq > 0 || wakeup_source) {
regmap_write(pcf85363->regmap, CTRL_FLAGS, 0);
regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO,
- PIN_IO_INTA_OUT, PIN_IO_INTAPM);
+ PIN_IO_INTAPM, PIN_IO_INTA_OUT);
+ }
+
+ if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf85363_rtc_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"pcf85363", client);
- if (ret)
- dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
- else
- set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
+ if (ret) {
+ dev_warn(&client->dev,
+ "unable to request IRQ, alarms disabled\n");
+ client->irq = 0;
+ }
+ }
+
+ if (client->irq > 0 || wakeup_source) {
+ device_init_wakeup(&client->dev, true);
+ set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
+ } else {
+ clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
}
ret = devm_rtc_register_device(pcf85363->rtc);
@@ -435,7 +486,7 @@ static struct i2c_driver pcf85363_driver = {
.name = "pcf85363",
.of_match_table = of_match_ptr(dev_ids),
},
- .probe_new = pcf85363_probe,
+ .probe = pcf85363_probe,
};
module_i2c_driver(pcf85363_driver);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 0a7fd9478465..4e61011fb7a9 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -11,14 +11,15 @@
* https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf
*/
+#include <linux/bcd.h>
#include <linux/clk-provider.h>
+#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
#define PCF8563_REG_ST1 0x00 /* status */
#define PCF8563_REG_ST2 0x01
@@ -77,64 +78,18 @@ struct pcf8563 {
*/
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
- struct i2c_client *client;
+ struct regmap *regmap;
#ifdef CONFIG_COMMON_CLK
struct clk_hw clkout_hw;
#endif
};
-static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg,
- unsigned char length, unsigned char *buf)
-{
- struct i2c_msg msgs[] = {
- {/* setup read ptr */
- .addr = client->addr,
- .len = 1,
- .buf = &reg,
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = buf
- },
- };
-
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
- return -EIO;
- }
-
- return 0;
-}
-
-static int pcf8563_write_block_data(struct i2c_client *client,
- unsigned char reg, unsigned char length,
- unsigned char *buf)
+static int pcf8563_set_alarm_mode(struct pcf8563 *pcf8563, bool on)
{
- int i, err;
-
- for (i = 0; i < length; i++) {
- unsigned char data[2] = { reg + i, buf[i] };
-
- err = i2c_master_send(client, data, sizeof(data));
- if (err != sizeof(data)) {
- dev_err(&client->dev,
- "%s: err=%d addr=%02x, data=%02x\n",
- __func__, err, data[0], data[1]);
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
-{
- unsigned char buf;
+ u32 buf;
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
+ err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf);
if (err < 0)
return err;
@@ -145,23 +100,17 @@ static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N);
- err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
- if (err < 0) {
- dev_err(&client->dev, "%s: write error\n", __func__);
- return -EIO;
- }
-
- return 0;
+ return regmap_write(pcf8563->regmap, PCF8563_REG_ST2, buf);
}
-static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en,
+static int pcf8563_get_alarm_mode(struct pcf8563 *pcf8563, unsigned char *en,
unsigned char *pen)
{
- unsigned char buf;
+ u32 buf;
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
- if (err)
+ err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf);
+ if (err < 0)
return err;
if (en)
@@ -174,17 +123,17 @@ static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en,
static irqreturn_t pcf8563_irq(int irq, void *dev_id)
{
- struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id);
- int err;
+ struct pcf8563 *pcf8563 = dev_id;
char pending;
+ int err;
- err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending);
+ err = pcf8563_get_alarm_mode(pcf8563, NULL, &pending);
if (err)
return IRQ_NONE;
if (pending) {
rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF);
- pcf8563_set_alarm_mode(pcf8563->client, 1);
+ pcf8563_set_alarm_mode(pcf8563, 1);
return IRQ_HANDLED;
}
@@ -197,22 +146,22 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id)
*/
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[9];
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST1, 9, buf);
- if (err)
+ err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_ST1, buf,
+ sizeof(buf));
+ if (err < 0)
return err;
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
- dev_err(&client->dev,
+ dev_err(dev,
"low voltage detected, date/time is not reliable.\n");
return -EINVAL;
}
- dev_dbg(&client->dev,
+ dev_dbg(dev,
"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
__func__,
@@ -220,7 +169,6 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
buf[4], buf[5], buf[6], buf[7],
buf[8]);
-
tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
@@ -232,7 +180,7 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
(tm->tm_year >= 100) : (tm->tm_year < 100);
- dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
@@ -243,11 +191,10 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[9];
- dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
@@ -270,22 +217,24 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
- return pcf8563_write_block_data(client, PCF8563_REG_SC,
- 9 - PCF8563_REG_SC, buf + PCF8563_REG_SC);
+ return regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC,
+ buf + PCF8563_REG_SC,
+ sizeof(buf) - PCF8563_REG_SC);
}
static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
int ret;
switch (cmd) {
case RTC_VL_READ:
- ret = i2c_smbus_read_byte_data(client, PCF8563_REG_SC);
+ ret = regmap_test_bits(pcf8563->regmap, PCF8563_REG_SC,
+ PCF8563_SC_LV);
if (ret < 0)
return ret;
- return put_user(ret & PCF8563_SC_LV ? RTC_VL_DATA_INVALID : 0,
+ return put_user(ret ? RTC_VL_DATA_INVALID : 0,
(unsigned int __user *)arg);
default:
return -ENOIOCTLCMD;
@@ -294,15 +243,16 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4];
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf);
- if (err)
+ err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_AMN, buf,
+ sizeof(buf));
+ if (err < 0)
return err;
- dev_dbg(&client->dev,
+ dev_dbg(dev,
"%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
__func__, buf[0], buf[1], buf[2], buf[3]);
@@ -312,11 +262,11 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
- err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending);
+ err = pcf8563_get_alarm_mode(pcf8563, &tm->enabled, &tm->pending);
if (err < 0)
return err;
- dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d,"
+ dev_dbg(dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d,"
" enabled=%d, pending=%d\n", __func__, tm->time.tm_min,
tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday,
tm->enabled, tm->pending);
@@ -326,7 +276,7 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
unsigned char buf[4];
int err;
@@ -335,17 +285,20 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
buf[2] = bin2bcd(tm->time.tm_mday);
buf[3] = tm->time.tm_wday & 0x07;
- err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf);
+ err = regmap_bulk_write(pcf8563->regmap, PCF8563_REG_AMN, buf,
+ sizeof(buf));
if (err)
return err;
- return pcf8563_set_alarm_mode(client, !!tm->enabled);
+ return pcf8563_set_alarm_mode(pcf8563, !!tm->enabled);
}
static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
{
+ struct pcf8563 *pcf8563 = dev_get_drvdata(dev);
+
dev_dbg(dev, "%s: en=%d\n", __func__, enabled);
- return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled);
+ return pcf8563_set_alarm_mode(pcf8563, !!enabled);
}
#ifdef CONFIG_COMMON_CLK
@@ -366,10 +319,10 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ u32 buf;
+ int ret;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return 0;
@@ -377,14 +330,19 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[buf];
}
-static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int pcf8563_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -393,11 +351,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
- int i;
+ int i, ret;
+ u32 buf;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@@ -405,10 +362,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] == rate) {
buf &= ~PCF8563_REG_CLKO_F_MASK;
buf |= i;
- ret = pcf8563_write_block_data(client,
- PCF8563_REG_CLKO, 1,
- &buf);
- return ret;
+ return regmap_update_bits(pcf8563->regmap,
+ PCF8563_REG_CLKO,
+ PCF8563_REG_CLKO_F_MASK,
+ buf);
}
return -EINVAL;
@@ -417,10 +374,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ u32 buf;
+ int ret;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@@ -429,8 +386,8 @@ static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
else
buf &= ~PCF8563_REG_CLKO_FE;
- ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
- return ret;
+ return regmap_update_bits(pcf8563->regmap, PCF8563_REG_CLKO,
+ PCF8563_REG_CLKO_FE, buf);
}
static int pcf8563_clkout_prepare(struct clk_hw *hw)
@@ -446,10 +403,10 @@ static void pcf8563_clkout_unprepare(struct clk_hw *hw)
static int pcf8563_clkout_is_prepared(struct clk_hw *hw)
{
struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
- struct i2c_client *client = pcf8563->client;
- unsigned char buf;
- int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ u32 buf;
+ int ret;
+ ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf);
if (ret < 0)
return ret;
@@ -461,22 +418,20 @@ static const struct clk_ops pcf8563_clkout_ops = {
.unprepare = pcf8563_clkout_unprepare,
.is_prepared = pcf8563_clkout_is_prepared,
.recalc_rate = pcf8563_clkout_recalc_rate,
- .round_rate = pcf8563_clkout_round_rate,
+ .determine_rate = pcf8563_clkout_determine_rate,
.set_rate = pcf8563_clkout_set_rate,
};
static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
{
- struct i2c_client *client = pcf8563->client;
- struct device_node *node = client->dev.of_node;
- struct clk *clk;
+ struct device_node *node = pcf8563->rtc->dev.of_node;
struct clk_init_data init;
+ struct clk *clk;
int ret;
- unsigned char buf;
/* disable the clkout output */
- buf = 0;
- ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
+ ret = regmap_clear_bits(pcf8563->regmap, PCF8563_REG_CLKO,
+ PCF8563_REG_CLKO_FE);
if (ret < 0)
return ERR_PTR(ret);
@@ -491,7 +446,7 @@ static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
of_property_read_string(node, "clock-output-names", &init.name);
/* register the clock */
- clk = devm_clk_register(&client->dev, &pcf8563->clkout_hw);
+ clk = devm_clk_register(&pcf8563->rtc->dev, &pcf8563->clkout_hw);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
@@ -509,11 +464,16 @@ static const struct rtc_class_ops pcf8563_rtc_ops = {
.alarm_irq_enable = pcf8563_irq_enable,
};
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xF,
+};
+
static int pcf8563_probe(struct i2c_client *client)
{
struct pcf8563 *pcf8563;
int err;
- unsigned char buf;
dev_dbg(&client->dev, "%s\n", __func__);
@@ -525,21 +485,23 @@ static int pcf8563_probe(struct i2c_client *client)
if (!pcf8563)
return -ENOMEM;
+ pcf8563->regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(pcf8563->regmap))
+ return PTR_ERR(pcf8563->regmap);
+
i2c_set_clientdata(client, pcf8563);
- pcf8563->client = client;
device_set_wakeup_capable(&client->dev, 1);
/* Set timer to lowest frequency to save power (ref Haoyu datasheet) */
- buf = PCF8563_TMRC_1_60;
- err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf);
+ err = regmap_set_bits(pcf8563->regmap, PCF8563_REG_TMRC,
+ PCF8563_TMRC_1_60);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return err;
}
/* Clear flags and disable interrupts */
- buf = 0;
- err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
+ err = regmap_write(pcf8563->regmap, PCF8563_REG_ST2, 0);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return err;
@@ -553,14 +515,20 @@ static int pcf8563_probe(struct i2c_client *client)
/* the pcf8563 alarm only supports a minute accuracy */
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, pcf8563->rtc->features);
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf8563->rtc->features);
+ clear_bit(RTC_FEATURE_ALARM, pcf8563->rtc->features);
pcf8563->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
pcf8563->rtc->range_max = RTC_TIMESTAMP_END_2099;
pcf8563->rtc->set_start_time = true;
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8563_irq,
- IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ IRQF_SHARED | IRQF_ONESHOT | irqflags,
pcf8563_driver.driver.name, client);
if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n",
@@ -568,7 +536,12 @@ static int pcf8563_probe(struct i2c_client *client)
return err;
}
} else {
- clear_bit(RTC_FEATURE_ALARM, pcf8563->rtc->features);
+ client->irq = 0;
+ }
+
+ if (client->irq > 0 || device_property_read_bool(&client->dev, "wakeup-source")) {
+ device_init_wakeup(&client->dev, true);
+ set_bit(RTC_FEATURE_ALARM, pcf8563->rtc->features);
}
err = devm_rtc_register_device(pcf8563->rtc);
@@ -584,9 +557,9 @@ static int pcf8563_probe(struct i2c_client *client)
}
static const struct i2c_device_id pcf8563_id[] = {
- { "pcf8563", 0 },
- { "rtc8564", 0 },
- { "pca8565", 0 },
+ { "pcf8563" },
+ { "rtc8564" },
+ { "pca8565" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8563_id);
@@ -607,7 +580,7 @@ static struct i2c_driver pcf8563_driver = {
.name = "rtc-pcf8563",
.of_match_table = of_match_ptr(pcf8563_of_match),
},
- .probe_new = pcf8563_probe,
+ .probe = pcf8563_probe,
.id_table = pcf8563_id,
};
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 87074d178274..652b9dfa7566 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -297,7 +297,7 @@ static int pcf8583_probe(struct i2c_client *client)
}
static const struct i2c_device_id pcf8583_id[] = {
- { "pcf8583", 0 },
+ { "pcf8583" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8583_id);
@@ -306,7 +306,7 @@ static struct i2c_driver pcf8583_driver = {
.driver = {
.name = "pcf8583",
},
- .probe_new = pcf8583_probe,
+ .probe = pcf8583_probe,
.id_table = pcf8583_id,
};
diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c
index fa351ac20158..2812da2c50c5 100644
--- a/drivers/rtc/rtc-pic32.c
+++ b/drivers/rtc/rtc-pic32.c
@@ -284,15 +284,13 @@ static void pic32_rtc_enable(struct pic32_rtc_dev *pdata, int en)
clk_disable(pdata->clk);
}
-static int pic32_rtc_remove(struct platform_device *pdev)
+static void pic32_rtc_remove(struct platform_device *pdev)
{
struct pic32_rtc_dev *pdata = platform_get_drvdata(pdev);
pic32_rtc_setaie(&pdev->dev, 0);
clk_unprepare(pdata->clk);
pdata->clk = NULL;
-
- return 0;
}
static int pic32_rtc_probe(struct platform_device *pdev)
@@ -332,7 +330,7 @@ static int pic32_rtc_probe(struct platform_device *pdev)
pic32_rtc_enable(pdata, 1);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
pdata->rtc->ops = &pic32_rtcops;
pdata->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index 39038c0754ee..5caaa714f448 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -21,7 +21,6 @@
#define RTC_CR_MIE (1 << 0)
struct pl030_rtc {
- struct rtc_device *rtc;
void __iomem *base;
};
@@ -86,6 +85,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
{
struct pl030_rtc *rtc;
int ret;
+ struct rtc_device *rtc_dev;
ret = amba_request_regions(dev, NULL);
if (ret)
@@ -97,14 +97,14 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
goto err_rtc;
}
- rtc->rtc = devm_rtc_allocate_device(&dev->dev);
- if (IS_ERR(rtc->rtc)) {
- ret = PTR_ERR(rtc->rtc);
+ rtc_dev = devm_rtc_allocate_device(&dev->dev);
+ if (IS_ERR(rtc_dev)) {
+ ret = PTR_ERR(rtc_dev);
goto err_rtc;
}
- rtc->rtc->ops = &pl030_ops;
- rtc->rtc->range_max = U32_MAX;
+ rtc_dev->ops = &pl030_ops;
+ rtc_dev->range_max = U32_MAX;
rtc->base = ioremap(dev->res.start, resource_size(&dev->res));
if (!rtc->base) {
ret = -ENOMEM;
@@ -121,7 +121,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
if (ret)
goto err_irq;
- ret = devm_rtc_register_device(rtc->rtc);
+ ret = devm_rtc_register_device(rtc_dev);
if (ret)
goto err_reg;
@@ -148,7 +148,7 @@ static void pl030_remove(struct amba_device *dev)
amba_release_regions(dev);
}
-static struct amba_id pl030_ids[] = {
+static const struct amba_id pl030_ids[] = {
{
.id = 0x00041030,
.mask = 0x000fffff,
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index bad6a5d9c683..eab39dfa4e5f 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -74,6 +74,8 @@
* @st_weekday: if this is an ST Microelectronics silicon version that need
* the weekday fix
* @irqflags: special IRQ flags per variant
+ * @range_min: minimum date/time supported by the RTC
+ * @range_max: maximum date/time supported by the RTC
*/
struct pl031_vendor_data {
struct rtc_class_ops ops;
@@ -284,8 +286,6 @@ static void pl031_remove(struct amba_device *adev)
{
struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
- dev_pm_clear_wake_irq(&adev->dev);
- device_init_wakeup(&adev->dev, false);
if (adev->irq[0])
free_irq(adev->irq[0], ldata);
amba_release_regions(adev);
@@ -350,7 +350,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
}
}
- device_init_wakeup(&adev->dev, true);
+ devm_device_init_wakeup(&adev->dev);
ldata->rtc = devm_rtc_allocate_device(&adev->dev);
if (IS_ERR(ldata->rtc)) {
ret = PTR_ERR(ldata->rtc);
@@ -373,7 +373,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
vendor->irqflags, "rtc-pl031", ldata);
if (ret)
goto out;
- dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
+ devm_pm_set_wake_irq(&adev->dev, adev->irq[0]);
}
return 0;
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 716e5d9ad74d..e624f848c22b 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -1,8 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/*
+ * pm8xxx RTC driver
+ *
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
*/
+#include <linux/efi.h>
#include <linux/of.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/init.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
@@ -11,12 +17,9 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/unaligned.h>
-/* RTC Register offsets from RTC CTRL REG */
-#define PM8XXX_ALARM_CTRL_OFFSET 0x01
-#define PM8XXX_RTC_WRITE_OFFSET 0x02
-#define PM8XXX_RTC_READ_OFFSET 0x06
-#define PM8XXX_ALARM_RW_OFFSET 0x0A
+#include <asm/byteorder.h>
/* RTC_CTRL register bit fields */
#define PM8xxx_RTC_ENABLE BIT(7)
@@ -27,13 +30,13 @@
/**
* struct pm8xxx_rtc_regs - describe RTC registers per PMIC versions
- * @ctrl: base address of control register
- * @write: base address of write register
- * @read: base address of read register
- * @alarm_ctrl: base address of alarm control register
- * @alarm_ctrl2: base address of alarm control2 register
- * @alarm_rw: base address of alarm read-write register
- * @alarm_en: alarm enable mask
+ * @ctrl: address of control register
+ * @write: base address of write registers
+ * @read: base address of read registers
+ * @alarm_ctrl: address of alarm control register
+ * @alarm_ctrl2: address of alarm control2 register
+ * @alarm_rw: base address of alarm read-write registers
+ * @alarm_en: alarm enable mask
*/
struct pm8xxx_rtc_regs {
unsigned int ctrl;
@@ -45,26 +48,240 @@ struct pm8xxx_rtc_regs {
unsigned int alarm_en;
};
+struct qcom_uefi_rtc_info {
+ __le32 offset_gps;
+ u8 reserved[8];
+} __packed;
+
/**
- * struct pm8xxx_rtc - rtc driver internal structure
- * @rtc: rtc device for this driver.
- * @regmap: regmap used to access RTC registers
- * @allow_set_time: indicates whether writing to the RTC is allowed
- * @rtc_alarm_irq: rtc alarm irq number.
- * @regs: rtc registers description.
- * @rtc_dev: device structure.
- * @ctrl_reg_lock: spinlock protecting access to ctrl_reg.
+ * struct pm8xxx_rtc - RTC driver internal structure
+ * @rtc: RTC device
+ * @regmap: regmap used to access registers
+ * @allow_set_time: whether the time can be set
+ * @use_uefi: use UEFI variable as fallback for offset
+ * @alarm_irq: alarm irq number
+ * @regs: register description
+ * @dev: device structure
+ * @rtc_info: qcom uefi rtc-info structure
+ * @nvmem_cell: nvmem cell for offset
+ * @offset: offset from epoch in seconds
+ * @offset_dirty: offset needs to be stored on shutdown
*/
struct pm8xxx_rtc {
struct rtc_device *rtc;
struct regmap *regmap;
bool allow_set_time;
- int rtc_alarm_irq;
+ bool use_uefi;
+ int alarm_irq;
const struct pm8xxx_rtc_regs *regs;
- struct device *rtc_dev;
- spinlock_t ctrl_reg_lock;
+ struct device *dev;
+ struct qcom_uefi_rtc_info rtc_info;
+ struct nvmem_cell *nvmem_cell;
+ u32 offset;
+ bool offset_dirty;
};
+#ifdef CONFIG_EFI
+
+MODULE_IMPORT_NS("EFIVAR");
+
+#define QCOM_UEFI_NAME L"RTCInfo"
+#define QCOM_UEFI_GUID EFI_GUID(0x882f8c2b, 0x9646, 0x435f, \
+ 0x8d, 0xe5, 0xf2, 0x08, 0xff, 0x80, 0xc1, 0xbd)
+#define QCOM_UEFI_ATTRS (EFI_VARIABLE_NON_VOLATILE | \
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS)
+
+static int pm8xxx_rtc_read_uefi_offset(struct pm8xxx_rtc *rtc_dd)
+{
+ struct qcom_uefi_rtc_info *rtc_info = &rtc_dd->rtc_info;
+ unsigned long size = sizeof(*rtc_info);
+ struct device *dev = rtc_dd->dev;
+ efi_status_t status;
+ u32 offset_gps;
+ int rc;
+
+ rc = efivar_lock();
+ if (rc)
+ return rc;
+
+ status = efivar_get_variable(QCOM_UEFI_NAME, &QCOM_UEFI_GUID, NULL,
+ &size, rtc_info);
+ efivar_unlock();
+
+ if (status != EFI_SUCCESS) {
+ dev_dbg(dev, "failed to read UEFI offset: %lu\n", status);
+ return efi_status_to_err(status);
+ }
+
+ if (size != sizeof(*rtc_info)) {
+ dev_dbg(dev, "unexpected UEFI structure size %lu\n", size);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "uefi_rtc_info = %*ph\n", (int)size, rtc_info);
+
+ /* Convert from GPS to Unix time offset */
+ offset_gps = le32_to_cpu(rtc_info->offset_gps);
+ rtc_dd->offset = offset_gps + (u32)RTC_TIMESTAMP_EPOCH_GPS;
+
+ return 0;
+}
+
+static int pm8xxx_rtc_write_uefi_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
+{
+ struct qcom_uefi_rtc_info *rtc_info = &rtc_dd->rtc_info;
+ unsigned long size = sizeof(*rtc_info);
+ struct device *dev = rtc_dd->dev;
+ efi_status_t status;
+ u32 offset_gps;
+
+ /* Convert from Unix to GPS time offset */
+ offset_gps = offset - (u32)RTC_TIMESTAMP_EPOCH_GPS;
+
+ rtc_info->offset_gps = cpu_to_le32(offset_gps);
+
+ dev_dbg(dev, "efi_rtc_info = %*ph\n", (int)size, rtc_info);
+
+ status = efivar_set_variable(QCOM_UEFI_NAME, &QCOM_UEFI_GUID,
+ QCOM_UEFI_ATTRS, size, rtc_info);
+ if (status != EFI_SUCCESS) {
+ dev_dbg(dev, "failed to write UEFI offset: %lx\n", status);
+ return efi_status_to_err(status);
+ }
+
+ return 0;
+}
+
+#else /* CONFIG_EFI */
+
+static int pm8xxx_rtc_read_uefi_offset(struct pm8xxx_rtc *rtc_dd)
+{
+ return -ENODEV;
+}
+
+static int pm8xxx_rtc_write_uefi_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_EFI */
+
+static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd)
+{
+ size_t len;
+ void *buf;
+ int rc;
+
+ buf = nvmem_cell_read(rtc_dd->nvmem_cell, &len);
+ if (IS_ERR(buf)) {
+ rc = PTR_ERR(buf);
+ dev_dbg(rtc_dd->dev, "failed to read nvmem offset: %d\n", rc);
+ return rc;
+ }
+
+ if (len != sizeof(u32)) {
+ dev_dbg(rtc_dd->dev, "unexpected nvmem cell size %zu\n", len);
+ kfree(buf);
+ return -EINVAL;
+ }
+
+ rtc_dd->offset = get_unaligned_le32(buf);
+
+ kfree(buf);
+
+ return 0;
+}
+
+static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
+{
+ u8 buf[sizeof(u32)];
+ int rc;
+
+ put_unaligned_le32(offset, buf);
+
+ rc = nvmem_cell_write(rtc_dd->nvmem_cell, buf, sizeof(buf));
+ if (rc < 0) {
+ dev_dbg(rtc_dd->dev, "failed to write nvmem offset: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
+{
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ unsigned int reg;
+ int rc;
+
+ rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value));
+ if (rc)
+ return rc;
+
+ /*
+ * Read the LSB again and check if there has been a carry over.
+ * If there has, redo the read operation.
+ */
+ rc = regmap_read(rtc_dd->regmap, regs->read, &reg);
+ if (rc < 0)
+ return rc;
+
+ if (reg < value[0]) {
+ rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value,
+ sizeof(value));
+ if (rc)
+ return rc;
+ }
+
+ *secs = get_unaligned_le32(value);
+
+ return 0;
+}
+
+static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
+{
+ u32 raw_secs;
+ u32 offset;
+ int rc;
+
+ if (!rtc_dd->nvmem_cell && !rtc_dd->use_uefi)
+ return -ENODEV;
+
+ rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs);
+ if (rc)
+ return rc;
+
+ offset = secs - raw_secs;
+
+ if (offset == rtc_dd->offset)
+ return 0;
+
+ /*
+ * Reduce flash wear by deferring updates due to clock drift until
+ * shutdown.
+ */
+ if (abs_diff(offset, rtc_dd->offset) < 30) {
+ rtc_dd->offset_dirty = true;
+ goto out;
+ }
+
+ if (rtc_dd->nvmem_cell)
+ rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
+ else
+ rc = pm8xxx_rtc_write_uefi_offset(rtc_dd, offset);
+
+ if (rc)
+ return rc;
+
+ rtc_dd->offset_dirty = false;
+out:
+ rtc_dd->offset = offset;
+
+ return 0;
+}
+
/*
* Steps to write the RTC registers.
* 1. Disable alarm if enabled.
@@ -74,269 +291,186 @@ struct pm8xxx_rtc {
* 5. Enable rtc if disabled in step 2.
* 6. Enable alarm if disabled in step 1.
*/
-static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int __pm8xxx_rtc_set_time(struct pm8xxx_rtc *rtc_dd, u32 secs)
{
- int rc, i;
- unsigned long secs, irq_flags;
- u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0;
- unsigned int ctrl_reg, rtc_ctrl_reg;
- struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ bool alarm_enabled;
+ int rc;
- if (!rtc_dd->allow_set_time)
- return -ENODEV;
-
- secs = rtc_tm_to_time64(tm);
-
- dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
-
- for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
- value[i] = secs & 0xFF;
- secs >>= 8;
- }
-
- spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+ put_unaligned_le32(secs, value);
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
+ rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, 0, &alarm_enabled);
if (rc)
- goto rtc_rw_fail;
-
- if (ctrl_reg & regs->alarm_en) {
- alarm_enabled = 1;
- ctrl_reg &= ~regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC Alarm control register failed\n");
- goto rtc_rw_fail;
- }
- }
+ return rc;
- /* Disable RTC H/w before writing on RTC register */
- rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg);
+ /* Disable RTC */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, 0);
if (rc)
- goto rtc_rw_fail;
-
- if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) {
- rtc_disabled = 1;
- rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC control register failed\n");
- goto rtc_rw_fail;
- }
- }
+ return rc;
/* Write 0 to Byte[0] */
rc = regmap_write(rtc_dd->regmap, regs->write, 0);
- if (rc) {
- dev_err(dev, "Write to RTC write data register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
/* Write Byte[1], Byte[2], Byte[3] */
rc = regmap_bulk_write(rtc_dd->regmap, regs->write + 1,
&value[1], sizeof(value) - 1);
- if (rc) {
- dev_err(dev, "Write to RTC write data register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
/* Write Byte[0] */
rc = regmap_write(rtc_dd->regmap, regs->write, value[0]);
- if (rc) {
- dev_err(dev, "Write to RTC write data register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
- /* Enable RTC H/w after writing on RTC register */
- if (rtc_disabled) {
- rtc_ctrl_reg |= PM8xxx_RTC_ENABLE;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC control register failed\n");
- goto rtc_rw_fail;
- }
- }
+ /* Enable RTC */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE,
+ PM8xxx_RTC_ENABLE);
+ if (rc)
+ return rc;
if (alarm_enabled) {
- ctrl_reg |= regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC Alarm control register failed\n");
- goto rtc_rw_fail;
- }
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, regs->alarm_en);
+ if (rc)
+ return rc;
}
-rtc_rw_fail:
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
-
- return rc;
+ return 0;
}
-static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- int rc;
- u8 value[NUM_8_BIT_RTC_REGS];
- unsigned long secs;
- unsigned int reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
- const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u32 secs;
+ int rc;
- rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value));
- if (rc) {
- dev_err(dev, "RTC read data register failed\n");
- return rc;
- }
+ secs = rtc_tm_to_time64(tm);
- /*
- * Read the LSB again and check if there has been a carry over.
- * If there is, redo the read operation.
- */
- rc = regmap_read(rtc_dd->regmap, regs->read, &reg);
- if (rc < 0) {
- dev_err(dev, "RTC read data register failed\n");
+ if (rtc_dd->allow_set_time)
+ rc = __pm8xxx_rtc_set_time(rtc_dd, secs);
+ else
+ rc = pm8xxx_rtc_update_offset(rtc_dd, secs);
+
+ if (rc)
return rc;
- }
- if (unlikely(reg < value[0])) {
- rc = regmap_bulk_read(rtc_dd->regmap, regs->read,
- value, sizeof(value));
- if (rc) {
- dev_err(dev, "RTC read data register failed\n");
- return rc;
- }
- }
+ dev_dbg(dev, "set time: %ptRd %ptRt (%u + %u)\n", tm, tm,
+ secs - rtc_dd->offset, rtc_dd->offset);
+ return 0;
+}
- secs = value[0] | (value[1] << 8) | (value[2] << 16) |
- ((unsigned long)value[3] << 24);
+static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ u32 secs;
+ int rc;
- rtc_time64_to_tm(secs, tm);
+ rc = pm8xxx_rtc_read_raw(rtc_dd, &secs);
+ if (rc)
+ return rc;
- dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm);
+ secs += rtc_dd->offset;
+ rtc_time64_to_tm(secs, tm);
+ dev_dbg(dev, "read time: %ptRd %ptRt (%u + %u)\n", tm, tm,
+ secs - rtc_dd->offset, rtc_dd->offset);
return 0;
}
static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- int rc, i;
- u8 value[NUM_8_BIT_RTC_REGS];
- unsigned int ctrl_reg;
- unsigned long secs, irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ u32 secs;
+ int rc;
secs = rtc_tm_to_time64(&alarm->time);
+ secs -= rtc_dd->offset;
+ put_unaligned_le32(secs, value);
- for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
- value[i] = secs & 0xFF;
- secs >>= 8;
- }
-
- spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, 0);
+ if (rc)
+ return rc;
rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
- if (rc) {
- dev_err(dev, "Write to RTC ALARM register failed\n");
- goto rtc_rw_fail;
- }
-
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc)
- goto rtc_rw_fail;
-
- if (alarm->enabled)
- ctrl_reg |= regs->alarm_en;
- else
- ctrl_reg &= ~regs->alarm_en;
+ return rc;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC alarm control register failed\n");
- goto rtc_rw_fail;
+ if (alarm->enabled) {
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, regs->alarm_en);
+ if (rc)
+ return rc;
}
- dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n",
- &alarm->time, &alarm->time);
-rtc_rw_fail:
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
- return rc;
+ dev_dbg(dev, "set alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time);
+
+ return 0;
}
static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- int rc;
- unsigned int ctrl_reg;
- u8 value[NUM_8_BIT_RTC_REGS];
- unsigned long secs;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ unsigned int ctrl_reg;
+ u32 secs;
+ int rc;
rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
- if (rc) {
- dev_err(dev, "RTC alarm time read failed\n");
+ if (rc)
return rc;
- }
-
- secs = value[0] | (value[1] << 8) | (value[2] << 16) |
- ((unsigned long)value[3] << 24);
+ secs = get_unaligned_le32(value);
+ secs += rtc_dd->offset;
rtc_time64_to_tm(secs, &alarm->time);
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
- if (rc) {
- dev_err(dev, "Read from RTC alarm control register failed\n");
+ if (rc)
return rc;
- }
+
alarm->enabled = !!(ctrl_reg & PM8xxx_RTC_ALARM_ENABLE);
- dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n",
- &alarm->time, &alarm->time);
+ dev_dbg(dev, "read alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time);
return 0;
}
static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
- int rc;
- unsigned long irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- unsigned int ctrl_reg;
u8 value[NUM_8_BIT_RTC_REGS] = {0};
-
- spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
-
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
- if (rc)
- goto rtc_rw_fail;
+ unsigned int val;
+ int rc;
if (enable)
- ctrl_reg |= regs->alarm_en;
+ val = regs->alarm_en;
else
- ctrl_reg &= ~regs->alarm_en;
+ val = 0;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC control register failed\n");
- goto rtc_rw_fail;
- }
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, val);
+ if (rc)
+ return rc;
- /* Clear Alarm register */
+ /* Clear alarm register */
if (!enable) {
rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
- if (rc) {
- dev_err(dev, "Clear RTC ALARM register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
}
-rtc_rw_fail:
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
- return rc;
+ return 0;
}
static const struct rtc_class_ops pm8xxx_rtc_ops = {
@@ -351,69 +485,31 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
{
struct pm8xxx_rtc *rtc_dd = dev_id;
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- unsigned int ctrl_reg;
int rc;
rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF);
- spin_lock(&rtc_dd->ctrl_reg_lock);
-
- /* Clear the alarm enable bit */
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
- if (rc) {
- spin_unlock(&rtc_dd->ctrl_reg_lock);
- goto rtc_alarm_handled;
- }
-
- ctrl_reg &= ~regs->alarm_en;
-
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- spin_unlock(&rtc_dd->ctrl_reg_lock);
- dev_err(rtc_dd->rtc_dev,
- "Write to alarm control register failed\n");
- goto rtc_alarm_handled;
- }
-
- spin_unlock(&rtc_dd->ctrl_reg_lock);
-
- /* Clear RTC alarm register */
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl2, &ctrl_reg);
- if (rc) {
- dev_err(rtc_dd->rtc_dev,
- "RTC Alarm control2 register read failed\n");
- goto rtc_alarm_handled;
- }
+ /* Disable alarm */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, 0);
+ if (rc)
+ return IRQ_NONE;
- ctrl_reg |= PM8xxx_RTC_ALARM_CLEAR;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl2, ctrl_reg);
+ /* Clear alarm status */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2,
+ PM8xxx_RTC_ALARM_CLEAR, 0);
if (rc)
- dev_err(rtc_dd->rtc_dev,
- "Write to RTC Alarm control2 register failed\n");
+ return IRQ_NONE;
-rtc_alarm_handled:
return IRQ_HANDLED;
}
static int pm8xxx_rtc_enable(struct pm8xxx_rtc *rtc_dd)
{
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- unsigned int ctrl_reg;
- int rc;
- /* Check if the RTC is on, else turn it on */
- rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
- if (rc)
- return rc;
-
- if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
- ctrl_reg |= PM8xxx_RTC_ENABLE;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
- if (rc)
- return rc;
- }
-
- return 0;
+ return regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE,
+ PM8xxx_RTC_ENABLE);
}
static const struct pm8xxx_rtc_regs pm8921_regs = {
@@ -456,9 +552,6 @@ static const struct pm8xxx_rtc_regs pmk8350_regs = {
.alarm_en = BIT(7),
};
-/*
- * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out
- */
static const struct of_device_id pm8xxx_id_table[] = {
{ .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs },
{ .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs },
@@ -468,11 +561,42 @@ static const struct of_device_id pm8xxx_id_table[] = {
};
MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
-static int pm8xxx_rtc_probe(struct platform_device *pdev)
+static int pm8xxx_rtc_probe_offset(struct pm8xxx_rtc *rtc_dd)
{
int rc;
- struct pm8xxx_rtc *rtc_dd;
+
+ rtc_dd->nvmem_cell = devm_nvmem_cell_get(rtc_dd->dev, "offset");
+ if (IS_ERR(rtc_dd->nvmem_cell)) {
+ rc = PTR_ERR(rtc_dd->nvmem_cell);
+ if (rc != -ENOENT)
+ return rc;
+ rtc_dd->nvmem_cell = NULL;
+ } else {
+ return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
+ }
+
+ /* Use UEFI storage as fallback if available */
+ rtc_dd->use_uefi = of_property_read_bool(rtc_dd->dev->of_node,
+ "qcom,uefi-rtc-info");
+ if (!rtc_dd->use_uefi)
+ return 0;
+
+ if (!efivar_is_available()) {
+ if (IS_ENABLED(CONFIG_EFI))
+ return -EPROBE_DEFER;
+
+ dev_warn(rtc_dd->dev, "efivars not available\n");
+ rtc_dd->use_uefi = false;
+ }
+
+ return pm8xxx_rtc_read_uefi_offset(rtc_dd);
+}
+
+static int pm8xxx_rtc_probe(struct platform_device *pdev)
+{
const struct of_device_id *match;
+ struct pm8xxx_rtc *rtc_dd;
+ int rc;
match = of_match_node(pm8xxx_id_table, pdev->dev.of_node);
if (!match)
@@ -482,24 +606,26 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
if (rtc_dd == NULL)
return -ENOMEM;
- /* Initialise spinlock to protect RTC control register */
- spin_lock_init(&rtc_dd->ctrl_reg_lock);
+ rtc_dd->regs = match->data;
+ rtc_dd->dev = &pdev->dev;
rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!rtc_dd->regmap) {
- dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+ if (!rtc_dd->regmap)
return -ENXIO;
- }
- rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
- if (rtc_dd->rtc_alarm_irq < 0)
- return -ENXIO;
+ if (!of_property_read_bool(pdev->dev.of_node, "qcom,no-alarm")) {
+ rtc_dd->alarm_irq = platform_get_irq(pdev, 0);
+ if (rtc_dd->alarm_irq < 0)
+ return -ENXIO;
+ }
rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
"allow-set-time");
-
- rtc_dd->regs = match->data;
- rtc_dd->rtc_dev = &pdev->dev;
+ if (!rtc_dd->allow_set_time) {
+ rc = pm8xxx_rtc_probe_offset(rtc_dd);
+ if (rc)
+ return rc;
+ }
rc = pm8xxx_rtc_enable(rtc_dd);
if (rc)
@@ -507,9 +633,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc_dd);
- device_init_wakeup(&pdev->dev, 1);
-
- /* Register the RTC device */
rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc_dd->rtc))
return PTR_ERR(rtc_dd->rtc);
@@ -517,36 +640,41 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
rtc_dd->rtc->ops = &pm8xxx_rtc_ops;
rtc_dd->rtc->range_max = U32_MAX;
- /* Request the alarm IRQ */
- rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq,
- pm8xxx_alarm_trigger,
- IRQF_TRIGGER_RISING,
- "pm8xxx_rtc_alarm", rtc_dd);
- if (rc < 0) {
- dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
- return rc;
- }
+ if (rtc_dd->alarm_irq) {
+ rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq,
+ pm8xxx_alarm_trigger,
+ IRQF_TRIGGER_RISING,
+ "pm8xxx_rtc_alarm", rtc_dd);
+ if (rc < 0)
+ return rc;
- rc = devm_rtc_register_device(rtc_dd->rtc);
- if (rc)
- return rc;
+ rc = devm_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq);
+ if (rc)
+ return rc;
- rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->rtc_alarm_irq);
- if (rc)
- return rc;
+ devm_device_init_wakeup(&pdev->dev);
+ } else {
+ clear_bit(RTC_FEATURE_ALARM, rtc_dd->rtc->features);
+ }
- return 0;
+ return devm_rtc_register_device(rtc_dd->rtc);
}
-static int pm8xxx_remove(struct platform_device *pdev)
+static void pm8xxx_shutdown(struct platform_device *pdev)
{
- dev_pm_clear_wake_irq(&pdev->dev);
- return 0;
+ struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
+
+ if (rtc_dd->offset_dirty) {
+ if (rtc_dd->nvmem_cell)
+ pm8xxx_rtc_write_nvmem_offset(rtc_dd, rtc_dd->offset);
+ else
+ pm8xxx_rtc_write_uefi_offset(rtc_dd, rtc_dd->offset);
+ }
}
static struct platform_driver pm8xxx_rtc_driver = {
.probe = pm8xxx_rtc_probe,
- .remove = pm8xxx_remove,
+ .shutdown = pm8xxx_shutdown,
.driver = {
.name = "rtc-pm8xxx",
.of_match_table = pm8xxx_id_table,
@@ -555,7 +683,7 @@ static struct platform_driver pm8xxx_rtc_driver = {
module_platform_driver(pm8xxx_rtc_driver);
-MODULE_ALIAS("platform:rtc-pm8xxx");
MODULE_DESCRIPTION("PMIC8xxx RTC driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>");
+MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index eeacf480cf36..62ee6b8f9bcd 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -14,7 +14,6 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include "rtc-sa1100.h"
@@ -361,17 +360,16 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
return ret;
}
- device_init_wakeup(dev, 1);
+ device_init_wakeup(dev, true);
return 0;
}
-static int __exit pxa_rtc_remove(struct platform_device *pdev)
+static void __exit pxa_rtc_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
pxa_rtc_release(dev);
- return 0;
}
#ifdef CONFIG_OF
@@ -404,7 +402,13 @@ static int pxa_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pxa_rtc_pm_ops, pxa_rtc_suspend, pxa_rtc_resume);
-static struct platform_driver pxa_rtc_driver = {
+/*
+ * pxa_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver pxa_rtc_driver __refdata = {
.remove = __exit_p(pxa_rtc_remove),
.driver = {
.name = "pxa-rtc",
diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c
index 5dbaeb7af648..ef913cf8593f 100644
--- a/drivers/rtc/rtc-r7301.c
+++ b/drivers/rtc/rtc-r7301.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
@@ -55,12 +56,23 @@ struct rtc7301_priv {
u8 bank;
};
-static const struct regmap_config rtc7301_regmap_config = {
+/*
+ * When the device is memory-mapped, some platforms pack the registers into
+ * 32-bit access using the lower 8 bits at each 4-byte stride, while others
+ * expose them as simply consecutive bytes.
+ */
+static const struct regmap_config rtc7301_regmap_32_config = {
.reg_bits = 32,
.val_bits = 8,
.reg_stride = 4,
};
+static const struct regmap_config rtc7301_regmap_8_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_stride = 1,
+};
+
static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg)
{
int reg_stride = regmap_get_reg_stride(priv->regmap);
@@ -356,7 +368,9 @@ static int __init rtc7301_rtc_probe(struct platform_device *dev)
void __iomem *regs;
struct rtc7301_priv *priv;
struct rtc_device *rtc;
+ static const struct regmap_config *mapconf;
int ret;
+ u32 val;
priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -366,8 +380,25 @@ static int __init rtc7301_rtc_probe(struct platform_device *dev)
if (IS_ERR(regs))
return PTR_ERR(regs);
+ ret = device_property_read_u32(&dev->dev, "reg-io-width", &val);
+ if (ret)
+ /* Default to 32bit accesses */
+ val = 4;
+
+ switch (val) {
+ case 1:
+ mapconf = &rtc7301_regmap_8_config;
+ break;
+ case 4:
+ mapconf = &rtc7301_regmap_32_config;
+ break;
+ default:
+ dev_err(&dev->dev, "invalid reg-io-width %d\n", val);
+ return -EINVAL;
+ }
+
priv->regmap = devm_regmap_init_mmio(&dev->dev, regs,
- &rtc7301_regmap_config);
+ mapconf);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c
index 18684a7026c4..8ba9cda74acf 100644
--- a/drivers/rtc/rtc-rc5t583.c
+++ b/drivers/rtc/rtc-rc5t583.c
@@ -245,7 +245,7 @@ static int rc5t583_rtc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "IRQ is not free.\n");
return ret;
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
ricoh_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&rc5t583_rtc_ops, THIS_MODULE);
@@ -262,12 +262,11 @@ static int rc5t583_rtc_probe(struct platform_device *pdev)
* Disable rc5t583 RTC interrupts.
* Sets status flag to free.
*/
-static int rc5t583_rtc_remove(struct platform_device *pdev)
+static void rc5t583_rtc_remove(struct platform_device *pdev)
{
struct rc5t583_rtc *rc5t583_rtc = platform_get_drvdata(pdev);
rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -309,4 +308,5 @@ static struct platform_driver rc5t583_rtc_driver = {
module_platform_driver(rc5t583_rtc_driver);
MODULE_ALIAS("platform:rtc-rc5t583");
MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_DESCRIPTION("RICOH 5T583 RTC driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-rc5t619.c b/drivers/rtc/rtc-rc5t619.c
index e73102a39f1b..74d169102074 100644
--- a/drivers/rtc/rtc-rc5t619.c
+++ b/drivers/rtc/rtc-rc5t619.c
@@ -414,7 +414,7 @@ static int rc5t619_rtc_probe(struct platform_device *pdev)
} else {
/* enable wake */
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
enable_irq_wake(rtc->irq);
}
} else {
@@ -429,14 +429,23 @@ static int rc5t619_rtc_probe(struct platform_device *pdev)
return devm_rtc_register_device(rtc->rtc);
}
+static const struct platform_device_id rc5t619_rtc_id[] = {
+ {
+ .name = "rc5t619-rtc",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, rc5t619_rtc_id);
+
static struct platform_driver rc5t619_rtc_driver = {
.driver = {
.name = "rc5t619-rtc",
},
.probe = rc5t619_rtc_probe,
+ .id_table = rc5t619_rtc_id,
};
-
module_platform_driver(rc5t619_rtc_driver);
-MODULE_ALIAS("platform:rc5t619-rtc");
+
MODULE_DESCRIPTION("RICOH RC5T619 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
new file mode 100644
index 000000000000..ab816bdf0d77
--- /dev/null
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -0,0 +1,897 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * On-Chip RTC Support available on RZ/G3S SoC
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+#include <linux/bcd.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/rtc.h>
+
+/* Counter registers. */
+#define RTCA3_RSECCNT 0x2
+#define RTCA3_RSECCNT_SEC GENMASK(6, 0)
+#define RTCA3_RMINCNT 0x4
+#define RTCA3_RMINCNT_MIN GENMASK(6, 0)
+#define RTCA3_RHRCNT 0x6
+#define RTCA3_RHRCNT_HR GENMASK(5, 0)
+#define RTCA3_RHRCNT_PM BIT(6)
+#define RTCA3_RWKCNT 0x8
+#define RTCA3_RWKCNT_WK GENMASK(2, 0)
+#define RTCA3_RDAYCNT 0xa
+#define RTCA3_RDAYCNT_DAY GENMASK(5, 0)
+#define RTCA3_RMONCNT 0xc
+#define RTCA3_RMONCNT_MONTH GENMASK(4, 0)
+#define RTCA3_RYRCNT 0xe
+#define RTCA3_RYRCNT_YEAR GENMASK(7, 0)
+
+/* Alarm registers. */
+#define RTCA3_RSECAR 0x10
+#define RTCA3_RSECAR_SEC GENMASK(6, 0)
+#define RTCA3_RMINAR 0x12
+#define RTCA3_RMINAR_MIN GENMASK(6, 0)
+#define RTCA3_RHRAR 0x14
+#define RTCA3_RHRAR_HR GENMASK(5, 0)
+#define RTCA3_RHRAR_PM BIT(6)
+#define RTCA3_RWKAR 0x16
+#define RTCA3_RWKAR_DAYW GENMASK(2, 0)
+#define RTCA3_RDAYAR 0x18
+#define RTCA3_RDAYAR_DATE GENMASK(5, 0)
+#define RTCA3_RMONAR 0x1a
+#define RTCA3_RMONAR_MON GENMASK(4, 0)
+#define RTCA3_RYRAR 0x1c
+#define RTCA3_RYRAR_YR GENMASK(7, 0)
+#define RTCA3_RYRAREN 0x1e
+
+/* Alarm enable bit (for all alarm registers). */
+#define RTCA3_AR_ENB BIT(7)
+
+/* Control registers. */
+#define RTCA3_RCR1 0x22
+#define RTCA3_RCR1_AIE BIT(0)
+#define RTCA3_RCR1_CIE BIT(1)
+#define RTCA3_RCR1_PIE BIT(2)
+#define RTCA3_RCR1_PES GENMASK(7, 4)
+#define RTCA3_RCR1_PES_1_64_SEC 0x8
+#define RTCA3_RCR2 0x24
+#define RTCA3_RCR2_START BIT(0)
+#define RTCA3_RCR2_RESET BIT(1)
+#define RTCA3_RCR2_AADJE BIT(4)
+#define RTCA3_RCR2_ADJP BIT(5)
+#define RTCA3_RCR2_HR24 BIT(6)
+#define RTCA3_RCR2_CNTMD BIT(7)
+#define RTCA3_RSR 0x20
+#define RTCA3_RSR_AF BIT(0)
+#define RTCA3_RSR_CF BIT(1)
+#define RTCA3_RSR_PF BIT(2)
+#define RTCA3_RADJ 0x2e
+#define RTCA3_RADJ_ADJ GENMASK(5, 0)
+#define RTCA3_RADJ_ADJ_MAX 0x3f
+#define RTCA3_RADJ_PMADJ GENMASK(7, 6)
+#define RTCA3_RADJ_PMADJ_NONE 0
+#define RTCA3_RADJ_PMADJ_ADD 1
+#define RTCA3_RADJ_PMADJ_SUB 2
+
+/* Polling operation timeouts. */
+#define RTCA3_DEFAULT_TIMEOUT_US 150
+#define RTCA3_IRQSET_TIMEOUT_US 5000
+#define RTCA3_START_TIMEOUT_US 150000
+#define RTCA3_RESET_TIMEOUT_US 200000
+
+/**
+ * enum rtca3_alrm_set_step - RTCA3 alarm set steps
+ * @RTCA3_ALRM_SSTEP_DONE: alarm setup done step
+ * @RTCA3_ALRM_SSTEP_IRQ: two 1/64 periodic IRQs were generated step
+ * @RTCA3_ALRM_SSTEP_INIT: alarm setup initialization step
+ */
+enum rtca3_alrm_set_step {
+ RTCA3_ALRM_SSTEP_DONE = 0,
+ RTCA3_ALRM_SSTEP_IRQ = 1,
+ RTCA3_ALRM_SSTEP_INIT = 3,
+};
+
+/**
+ * struct rtca3_ppb_per_cycle - PPB per cycle
+ * @ten_sec: PPB per cycle in 10 seconds adjutment mode
+ * @sixty_sec: PPB per cycle in 60 seconds adjustment mode
+ */
+struct rtca3_ppb_per_cycle {
+ int ten_sec;
+ int sixty_sec;
+};
+
+/**
+ * struct rtca3_priv - RTCA3 private data structure
+ * @base: base address
+ * @rtc_dev: RTC device
+ * @rstc: reset control
+ * @set_alarm_completion: alarm setup completion
+ * @alrm_sstep: alarm setup step (see enum rtca3_alrm_set_step)
+ * @lock: device lock
+ * @ppb: ppb per cycle for each the available adjustment modes
+ * @wakeup_irq: wakeup IRQ
+ */
+struct rtca3_priv {
+ void __iomem *base;
+ struct rtc_device *rtc_dev;
+ struct reset_control *rstc;
+ struct completion set_alarm_completion;
+ atomic_t alrm_sstep;
+ spinlock_t lock;
+ struct rtca3_ppb_per_cycle ppb;
+ int wakeup_irq;
+};
+
+static void rtca3_byte_update_bits(struct rtca3_priv *priv, u8 off, u8 mask, u8 val)
+{
+ u8 tmp;
+
+ tmp = readb(priv->base + off);
+ tmp &= ~mask;
+ tmp |= (val & mask);
+ writeb(tmp, priv->base + off);
+}
+
+static u8 rtca3_alarm_handler_helper(struct rtca3_priv *priv)
+{
+ u8 val, pending;
+
+ val = readb(priv->base + RTCA3_RSR);
+ pending = val & RTCA3_RSR_AF;
+ writeb(val & ~pending, priv->base + RTCA3_RSR);
+
+ if (pending)
+ rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);
+
+ return pending;
+}
+
+static irqreturn_t rtca3_alarm_handler(int irq, void *dev_id)
+{
+ struct rtca3_priv *priv = dev_id;
+ u8 pending;
+
+ guard(spinlock)(&priv->lock);
+
+ pending = rtca3_alarm_handler_helper(priv);
+
+ return IRQ_RETVAL(pending);
+}
+
+static irqreturn_t rtca3_periodic_handler(int irq, void *dev_id)
+{
+ struct rtca3_priv *priv = dev_id;
+ u8 val, pending;
+
+ guard(spinlock)(&priv->lock);
+
+ val = readb(priv->base + RTCA3_RSR);
+ pending = val & RTCA3_RSR_PF;
+
+ if (pending) {
+ writeb(val & ~pending, priv->base + RTCA3_RSR);
+
+ if (atomic_read(&priv->alrm_sstep) > RTCA3_ALRM_SSTEP_IRQ) {
+ /* Alarm setup in progress. */
+ atomic_dec(&priv->alrm_sstep);
+
+ if (atomic_read(&priv->alrm_sstep) == RTCA3_ALRM_SSTEP_IRQ) {
+ /*
+ * We got 2 * 1/64 periodic interrupts. Disable
+ * interrupt and let alarm setup continue.
+ */
+ rtca3_byte_update_bits(priv, RTCA3_RCR1,
+ RTCA3_RCR1_PIE, 0);
+ readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, val,
+ !(val & RTCA3_RCR1_PIE),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ complete(&priv->set_alarm_completion);
+ }
+ }
+ }
+
+ return IRQ_RETVAL(pending);
+}
+
+static void rtca3_prepare_cntalrm_regs_for_read(struct rtca3_priv *priv, bool cnt)
+{
+ /* Offset b/w time and alarm registers. */
+ u8 offset = cnt ? 0 : 0xe;
+
+ /*
+ * According to HW manual (section 22.6.4. Notes on writing to and
+ * reading from registers) after writing to count registers, alarm
+ * registers, year alarm enable register, bits RCR2.AADJE, AADJP,
+ * and HR24 register, we need to do 3 empty reads before being
+ * able to fetch the registers content.
+ */
+ for (u8 i = 0; i < 3; i++) {
+ readb(priv->base + RTCA3_RSECCNT + offset);
+ readb(priv->base + RTCA3_RMINCNT + offset);
+ readb(priv->base + RTCA3_RHRCNT + offset);
+ readb(priv->base + RTCA3_RWKCNT + offset);
+ readb(priv->base + RTCA3_RDAYCNT + offset);
+ readw(priv->base + RTCA3_RYRCNT + offset);
+ if (!cnt)
+ readb(priv->base + RTCA3_RYRAREN);
+ }
+}
+
+static int rtca3_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 sec, min, hour, wday, mday, month, tmp;
+ u8 trials = 0;
+ u32 year100;
+ u16 year;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ tmp = readb(priv->base + RTCA3_RCR2);
+ if (!(tmp & RTCA3_RCR2_START))
+ return -EINVAL;
+
+ do {
+ /* Clear carry interrupt. */
+ rtca3_byte_update_bits(priv, RTCA3_RSR, RTCA3_RSR_CF, 0);
+
+ /* Read counters. */
+ sec = readb(priv->base + RTCA3_RSECCNT);
+ min = readb(priv->base + RTCA3_RMINCNT);
+ hour = readb(priv->base + RTCA3_RHRCNT);
+ wday = readb(priv->base + RTCA3_RWKCNT);
+ mday = readb(priv->base + RTCA3_RDAYCNT);
+ month = readb(priv->base + RTCA3_RMONCNT);
+ year = readw(priv->base + RTCA3_RYRCNT);
+
+ tmp = readb(priv->base + RTCA3_RSR);
+
+ /*
+ * We cannot generate carries due to reading 64Hz counter as
+ * the driver doesn't implement carry, thus, carries will be
+ * generated once per seconds. Add a timeout of 5 trials here
+ * to avoid infinite loop, if any.
+ */
+ } while ((tmp & RTCA3_RSR_CF) && ++trials < 5);
+
+ if (trials >= 5)
+ return -ETIMEDOUT;
+
+ tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECCNT_SEC, sec));
+ tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINCNT_MIN, min));
+ tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRCNT_HR, hour));
+ tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKCNT_WK, wday));
+ tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYCNT_DAY, mday));
+ tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONCNT_MONTH, month)) - 1;
+ year = FIELD_GET(RTCA3_RYRCNT_YEAR, year);
+ year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
+ tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+
+ return 0;
+}
+
+static int rtca3_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 rcr2, tmp;
+ int ret;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ /* Stop the RTC. */
+ rcr2 = readb(priv->base + RTCA3_RCR2);
+ writeb(rcr2 & ~RTCA3_RCR2_START, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
+ !(tmp & RTCA3_RCR2_START),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Update time. */
+ writeb(bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECCNT);
+ writeb(bin2bcd(tm->tm_min), priv->base + RTCA3_RMINCNT);
+ writeb(bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRCNT);
+ writeb(bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKCNT);
+ writeb(bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYCNT);
+ writeb(bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONCNT);
+ writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRCNT);
+
+ /* Make sure we can read back the counters. */
+ rtca3_prepare_cntalrm_regs_for_read(priv, true);
+
+ /* Start RTC. */
+ writeb(rcr2 | RTCA3_RCR2_START, priv->base + RTCA3_RCR2);
+ return readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
+ (tmp & RTCA3_RCR2_START),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+}
+
+static int rtca3_alarm_irq_set_helper(struct rtca3_priv *priv,
+ u8 interrupts,
+ unsigned int enabled)
+{
+ u8 tmp, val;
+
+ if (enabled) {
+ /*
+ * AIE, CIE, PIE bit indexes in RSR corresponds with
+ * those on RCR1. Same interrupts mask can be used.
+ */
+ rtca3_byte_update_bits(priv, RTCA3_RSR, interrupts, 0);
+ val = interrupts;
+ } else {
+ val = 0;
+ }
+
+ rtca3_byte_update_bits(priv, RTCA3_RCR1, interrupts, val);
+ return readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
+ ((tmp & interrupts) == val),
+ 10, RTCA3_IRQSET_TIMEOUT_US);
+}
+
+static int rtca3_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ return rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, enabled);
+}
+
+static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 sec, min, hour, wday, mday, month;
+ struct rtc_time *tm = &wkalrm->time;
+ u32 year100;
+ u16 year;
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ sec = readb(priv->base + RTCA3_RSECAR);
+ min = readb(priv->base + RTCA3_RMINAR);
+ hour = readb(priv->base + RTCA3_RHRAR);
+ wday = readb(priv->base + RTCA3_RWKAR);
+ mday = readb(priv->base + RTCA3_RDAYAR);
+ month = readb(priv->base + RTCA3_RMONAR);
+ year = readw(priv->base + RTCA3_RYRAR);
+
+ tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECAR_SEC, sec));
+ tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINAR_MIN, min));
+ tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRAR_HR, hour));
+ tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKAR_DAYW, wday));
+ tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYAR_DATE, mday));
+ tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONAR_MON, month)) - 1;
+ year = FIELD_GET(RTCA3_RYRAR_YR, year);
+ year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
+ tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+
+ wkalrm->enabled = !!(readb(priv->base + RTCA3_RCR1) & RTCA3_RCR1_AIE);
+
+ return 0;
+}
+
+static int rtca3_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ struct rtc_time *tm = &wkalrm->time;
+ u8 rcr1, tmp;
+ int ret;
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ tmp = readb(priv->base + RTCA3_RCR2);
+ if (!(tmp & RTCA3_RCR2_START))
+ return -EPERM;
+
+ /* Disable AIE to prevent false interrupts. */
+ rcr1 = readb(priv->base + RTCA3_RCR1);
+ rcr1 &= ~RTCA3_RCR1_AIE;
+ writeb(rcr1, priv->base + RTCA3_RCR1);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
+ !(tmp & RTCA3_RCR1_AIE),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Set the time and enable the alarm. */
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_min), priv->base + RTCA3_RMINAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYAR);
+ writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONAR);
+
+ writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRAR);
+ writeb(RTCA3_AR_ENB, priv->base + RTCA3_RYRAREN);
+
+ /* Make sure we can read back the counters. */
+ rtca3_prepare_cntalrm_regs_for_read(priv, false);
+
+ /* Need to wait for 2 * 1/64 periodic interrupts to be generated. */
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_INIT);
+ reinit_completion(&priv->set_alarm_completion);
+
+ /* Enable periodic interrupt. */
+ rcr1 |= RTCA3_RCR1_PIE;
+ writeb(rcr1, priv->base + RTCA3_RCR1);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
+ (tmp & RTCA3_RCR1_PIE),
+ 10, RTCA3_IRQSET_TIMEOUT_US);
+ }
+
+ if (ret)
+ goto setup_failed;
+
+ /* Wait for the 2 * 1/64 periodic interrupts. */
+ ret = wait_for_completion_interruptible_timeout(&priv->set_alarm_completion,
+ msecs_to_jiffies(500));
+ if (ret <= 0) {
+ ret = -ETIMEDOUT;
+ goto setup_failed;
+ }
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ ret = rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, wkalrm->enabled);
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
+ }
+
+ return ret;
+
+setup_failed:
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ /*
+ * Disable PIE to avoid interrupt storm in case HW needed more than
+ * specified timeout for setup.
+ */
+ writeb(rcr1 & ~RTCA3_RCR1_PIE, priv->base + RTCA3_RCR1);
+ readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & ~RTCA3_RCR1_PIE),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
+ }
+
+ return ret;
+}
+
+static int rtca3_read_offset(struct device *dev, long *offset)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ u8 val, radj, cycles;
+ u32 ppb_per_cycle;
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ radj = readb(priv->base + RTCA3_RADJ);
+ val = readb(priv->base + RTCA3_RCR2);
+ }
+
+ cycles = FIELD_GET(RTCA3_RADJ_ADJ, radj);
+
+ if (!cycles) {
+ *offset = 0;
+ return 0;
+ }
+
+ if (val & RTCA3_RCR2_ADJP)
+ ppb_per_cycle = priv->ppb.ten_sec;
+ else
+ ppb_per_cycle = priv->ppb.sixty_sec;
+
+ *offset = cycles * ppb_per_cycle;
+ val = FIELD_GET(RTCA3_RADJ_PMADJ, radj);
+ if (val == RTCA3_RADJ_PMADJ_SUB)
+ *offset = -(*offset);
+
+ return 0;
+}
+
+static int rtca3_set_offset(struct device *dev, long offset)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ int cycles, cycles10, cycles60;
+ u8 radj, adjp, tmp;
+ int ret;
+
+ /*
+ * Automatic time error adjustment could be set at intervals of 10
+ * or 60 seconds.
+ */
+ cycles10 = DIV_ROUND_CLOSEST(offset, priv->ppb.ten_sec);
+ cycles60 = DIV_ROUND_CLOSEST(offset, priv->ppb.sixty_sec);
+
+ /* We can set b/w 1 and 63 clock cycles. */
+ if (cycles60 >= -RTCA3_RADJ_ADJ_MAX &&
+ cycles60 <= RTCA3_RADJ_ADJ_MAX) {
+ cycles = cycles60;
+ adjp = 0;
+ } else if (cycles10 >= -RTCA3_RADJ_ADJ_MAX &&
+ cycles10 <= RTCA3_RADJ_ADJ_MAX) {
+ cycles = cycles10;
+ adjp = RTCA3_RCR2_ADJP;
+ } else {
+ return -ERANGE;
+ }
+
+ radj = FIELD_PREP(RTCA3_RADJ_ADJ, abs(cycles));
+ if (!cycles)
+ radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_NONE);
+ else if (cycles > 0)
+ radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_ADD);
+ else
+ radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_SUB);
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ tmp = readb(priv->base + RTCA3_RCR2);
+
+ if ((tmp & RTCA3_RCR2_ADJP) != adjp) {
+ /* RADJ.PMADJ need to be set to zero before setting RCR2.ADJP. */
+ writeb(0, priv->base + RTCA3_RADJ);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, !tmp,
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ rtca3_byte_update_bits(priv, RTCA3_RCR2, RTCA3_RCR2_ADJP, adjp);
+ ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
+ ((tmp & RTCA3_RCR2_ADJP) == adjp),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+ }
+
+ writeb(radj, priv->base + RTCA3_RADJ);
+ return readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, (tmp == radj),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+}
+
+static const struct rtc_class_ops rtca3_ops = {
+ .read_time = rtca3_read_time,
+ .set_time = rtca3_set_time,
+ .read_alarm = rtca3_read_alarm,
+ .set_alarm = rtca3_set_alarm,
+ .alarm_irq_enable = rtca3_alarm_irq_enable,
+ .set_offset = rtca3_set_offset,
+ .read_offset = rtca3_read_offset,
+};
+
+static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv)
+{
+ unsigned long osc32k_rate;
+ u8 val, tmp, mask;
+ u32 sleep_us;
+ int ret;
+
+ osc32k_rate = clk_get_rate(clk);
+ if (!osc32k_rate)
+ return -EINVAL;
+
+ sleep_us = DIV_ROUND_UP_ULL(1000000ULL, osc32k_rate) * 6;
+
+ priv->ppb.ten_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 10));
+ priv->ppb.sixty_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 60));
+
+ /*
+ * According to HW manual (section 22.4.2. Clock and count mode setting procedure)
+ * we need to wait at least 6 cycles of the 32KHz clock after clock was enabled.
+ */
+ usleep_range(sleep_us, sleep_us + 10);
+
+ mask = RTCA3_RCR2_START | RTCA3_RCR2_HR24;
+ val = readb(priv->base + RTCA3_RCR2);
+ /* Only disable the interrupts if already started in 24 hours and calendar count mode. */
+ if ((val & mask) == mask) {
+ /* Disable all interrupts. */
+ mask = RTCA3_RCR1_AIE | RTCA3_RCR1_CIE | RTCA3_RCR1_PIE;
+ return rtca3_alarm_irq_set_helper(priv, mask, 0);
+ }
+
+ /* Reconfigure the RTC in 24 hours and calendar count mode. */
+ mask = RTCA3_RCR2_START | RTCA3_RCR2_CNTMD;
+ writeb(0, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * Set 24 hours mode. According to HW manual (section 22.3.19. RTC Control
+ * Register 2) this needs to be done separate from stop operation.
+ */
+ mask = RTCA3_RCR2_HR24;
+ val = RTCA3_RCR2_HR24;
+ writeb(val, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, (tmp & mask),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Execute reset. */
+ mask = RTCA3_RCR2_RESET;
+ writeb(val | RTCA3_RCR2_RESET, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask),
+ 10, RTCA3_RESET_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * According to HW manual (section 22.6.3. Notes on writing to and reading
+ * from registers) after reset we need to wait 6 clock cycles before
+ * writing to RTC registers.
+ */
+ usleep_range(sleep_us, sleep_us + 10);
+
+ /* Set no adjustment. */
+ writeb(0, priv->base + RTCA3_RADJ);
+ ret = readb_poll_timeout(priv->base + RTCA3_RADJ, tmp, !tmp, 10,
+ RTCA3_DEFAULT_TIMEOUT_US);
+
+ /* Start the RTC and enable automatic time error adjustment. */
+ mask = RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
+ val |= RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
+ writeb(val, priv->base + RTCA3_RCR2);
+ ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, ((tmp & mask) == mask),
+ 10, RTCA3_START_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * According to HW manual (section 22.6.4. Notes on writing to and reading
+ * from registers) we need to wait 1/128 seconds while the clock is operating
+ * (RCR2.START bit = 1) to be able to read the counters after a return from
+ * reset.
+ */
+ usleep_range(8000, 9000);
+
+ /* Set period interrupt to 1/64 seconds. It is necessary for alarm setup. */
+ val = FIELD_PREP(RTCA3_RCR1_PES, RTCA3_RCR1_PES_1_64_SEC);
+ rtca3_byte_update_bits(priv, RTCA3_RCR1, RTCA3_RCR1_PES, val);
+ return readb_poll_timeout(priv->base + RTCA3_RCR1, tmp, ((tmp & RTCA3_RCR1_PES) == val),
+ 10, RTCA3_DEFAULT_TIMEOUT_US);
+}
+
+static int rtca3_request_irqs(struct platform_device *pdev, struct rtca3_priv *priv)
+{
+ struct device *dev = &pdev->dev;
+ int ret, irq;
+
+ irq = platform_get_irq_byname(pdev, "alarm");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get alarm IRQ!\n");
+
+ ret = devm_request_irq(dev, irq, rtca3_alarm_handler, 0, "rtca3-alarm", priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request alarm IRQ!\n");
+ priv->wakeup_irq = irq;
+
+ irq = platform_get_irq_byname(pdev, "period");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get period IRQ!\n");
+
+ ret = devm_request_irq(dev, irq, rtca3_periodic_handler, 0, "rtca3-period", priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request period IRQ!\n");
+
+ /*
+ * Driver doesn't implement carry handler. Just get the IRQ here
+ * for backward compatibility, in case carry support will be added later.
+ */
+ irq = platform_get_irq_byname(pdev, "carry");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get carry IRQ!\n");
+
+ return 0;
+}
+
+static void rtca3_action(void *data)
+{
+ struct device *dev = data;
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_assert(priv->rstc);
+ if (ret)
+ dev_err(dev, "Failed to de-assert reset!");
+
+ ret = pm_runtime_put_sync(dev);
+ if (ret < 0)
+ dev_err(dev, "Failed to runtime suspend!");
+}
+
+static int rtca3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtca3_priv *priv;
+ struct clk *clk;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ priv->rstc = devm_reset_control_get_shared(dev, NULL);
+ if (IS_ERR(priv->rstc))
+ return PTR_ERR(priv->rstc);
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(priv->rstc);
+ if (ret) {
+ pm_runtime_put_sync(dev);
+ return ret;
+ }
+
+ dev_set_drvdata(dev, priv);
+ ret = devm_add_action_or_reset(dev, rtca3_action, dev);
+ if (ret)
+ return ret;
+
+ /*
+ * This must be an always-on clock to keep the RTC running even after
+ * driver is unbinded.
+ */
+ clk = devm_clk_get_enabled(dev, "counter");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ spin_lock_init(&priv->lock);
+ atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
+ init_completion(&priv->set_alarm_completion);
+
+ ret = rtca3_initial_setup(clk, priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup the RTC!\n");
+
+ ret = rtca3_request_irqs(pdev, priv);
+ if (ret)
+ return ret;
+
+ device_init_wakeup(&pdev->dev, true);
+
+ priv->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(priv->rtc_dev))
+ return PTR_ERR(priv->rtc_dev);
+
+ priv->rtc_dev->ops = &rtca3_ops;
+ priv->rtc_dev->max_user_freq = 256;
+ priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
+
+ return devm_rtc_register_device(priv->rtc_dev);
+}
+
+static void rtca3_remove(struct platform_device *pdev)
+{
+ struct rtca3_priv *priv = platform_get_drvdata(pdev);
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ /*
+ * Disable alarm, periodic interrupts. The RTC device cannot
+ * power up the system.
+ */
+ rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE | RTCA3_RCR1_PIE, 0);
+}
+
+static int rtca3_suspend(struct device *dev)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+
+ if (!device_may_wakeup(dev))
+ return 0;
+
+ /* Alarm setup in progress. */
+ if (atomic_read(&priv->alrm_sstep) != RTCA3_ALRM_SSTEP_DONE)
+ return -EBUSY;
+
+ enable_irq_wake(priv->wakeup_irq);
+
+ return 0;
+}
+
+static int rtca3_clean_alarm(struct rtca3_priv *priv)
+{
+ struct rtc_device *rtc_dev = priv->rtc_dev;
+ time64_t alarm_time, now;
+ struct rtc_wkalrm alarm;
+ struct rtc_time tm;
+ u8 pending;
+ int ret;
+
+ ret = rtc_read_alarm(rtc_dev, &alarm);
+ if (ret)
+ return ret;
+
+ if (!alarm.enabled)
+ return 0;
+
+ ret = rtc_read_time(rtc_dev, &tm);
+ if (ret)
+ return ret;
+
+ alarm_time = rtc_tm_to_time64(&alarm.time);
+ now = rtc_tm_to_time64(&tm);
+ if (alarm_time >= now)
+ return 0;
+
+ /*
+ * Heuristically, it has been determined that when returning from deep
+ * sleep state the RTCA3_RSR.AF is zero even though the alarm expired.
+ * Call again the rtc_update_irq() if alarm helper detects this.
+ */
+
+ guard(spinlock_irqsave)(&priv->lock);
+
+ pending = rtca3_alarm_handler_helper(priv);
+ if (!pending)
+ rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);
+
+ return 0;
+}
+
+static int rtca3_resume(struct device *dev)
+{
+ struct rtca3_priv *priv = dev_get_drvdata(dev);
+
+ if (!device_may_wakeup(dev))
+ return 0;
+
+ disable_irq_wake(priv->wakeup_irq);
+
+ /*
+ * According to the HW manual (section 22.6.4 Notes on writing to
+ * and reading from registers) we need to wait 1/128 seconds while
+ * RCR2.START = 1 to be able to read the counters after a return from low
+ * power consumption state.
+ */
+ mdelay(8);
+
+ /*
+ * The alarm cannot wake the system from deep sleep states. In case
+ * we return from deep sleep states and the alarm expired we need
+ * to disable it to avoid failures when setting another alarm.
+ */
+ return rtca3_clean_alarm(priv);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rtca3_pm_ops, rtca3_suspend, rtca3_resume);
+
+static const struct of_device_id rtca3_of_match[] = {
+ { .compatible = "renesas,rz-rtca3", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rtca3_of_match);
+
+static struct platform_driver rtca3_platform_driver = {
+ .driver = {
+ .name = "rtc-rtca3",
+ .pm = pm_ptr(&rtca3_pm_ops),
+ .of_match_table = rtca3_of_match,
+ },
+ .probe = rtca3_probe,
+ .remove = rtca3_remove,
+};
+module_platform_driver(rtca3_platform_driver);
+
+MODULE_DESCRIPTION("Renesas RTCA-3 RTC driver");
+MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c
index 2d9bcb3ce1e3..59b8e9a30fe6 100644
--- a/drivers/rtc/rtc-rk808.c
+++ b/drivers/rtc/rtc-rk808.c
@@ -418,7 +418,7 @@ static int rk808_rtc_probe(struct platform_device *pdev)
return ret;
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
rk808_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rk808_rtc->rtc))
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index b4c5d016eca3..f8fab0205f8c 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -12,7 +12,7 @@
#include <linux/bcd.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
/*
* Ricoh has a family of I2C based RTCs, which differ only slightly from
@@ -826,8 +826,7 @@ static int rs5c372_probe(struct i2c_client *client)
rs5c372->client = client;
i2c_set_clientdata(client, rs5c372);
if (client->dev.of_node) {
- rs5c372->type = (enum rtc_type)
- of_device_get_match_data(&client->dev);
+ rs5c372->type = (uintptr_t)of_device_get_match_data(&client->dev);
} else {
const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client);
rs5c372->type = id->driver_data;
@@ -921,7 +920,7 @@ static struct i2c_driver rs5c372_driver = {
.name = "rtc-rs5c372",
.of_match_table = of_match_ptr(rs5c372_of_match),
},
- .probe_new = rs5c372_probe,
+ .probe = rs5c372_probe,
.remove = rs5c372_remove,
.id_table = rs5c372_id,
};
diff --git a/drivers/rtc/rtc-rtd119x.c b/drivers/rtc/rtc-rtd119x.c
index 8f9abd65846c..85a138db81d7 100644
--- a/drivers/rtc/rtc-rtd119x.c
+++ b/drivers/rtc/rtc-rtd119x.c
@@ -216,7 +216,7 @@ static int rtd119x_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int rtd119x_rtc_remove(struct platform_device *pdev)
+static void rtd119x_rtc_remove(struct platform_device *pdev)
{
struct rtd119x_rtc *data = platform_get_drvdata(pdev);
@@ -224,8 +224,6 @@ static int rtd119x_rtc_remove(struct platform_device *pdev)
clk_disable_unprepare(data->clk);
clk_put(data->clk);
-
- return 0;
}
static struct platform_driver rtd119x_rtc_driver = {
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index b0099e26e3b0..c2a531f0e125 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -17,7 +17,7 @@
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
@@ -120,8 +120,9 @@ static ssize_t timestamp0_show(struct device *dev,
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
struct rtc_time tm;
- int ret, count;
+ unsigned int count;
u8 date[6];
+ int ret;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret)
@@ -156,7 +157,8 @@ static ssize_t timestamp0_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
- int ret, count;
+ unsigned int count;
+ int ret;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret)
@@ -729,14 +731,19 @@ static unsigned long rv3028_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[clkout];
}
-static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int rv3028_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -800,7 +807,7 @@ static const struct clk_ops rv3028_clkout_ops = {
.unprepare = rv3028_clkout_unprepare,
.is_prepared = rv3028_clkout_is_prepared,
.recalc_rate = rv3028_clkout_recalc_rate,
- .round_rate = rv3028_clkout_round_rate,
+ .determine_rate = rv3028_clkout_determine_rate,
.set_rate = rv3028_clkout_set_rate,
};
@@ -855,11 +862,68 @@ static const struct regmap_config regmap_config = {
.max_register = 0x37,
};
+static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028,
+ struct i2c_client *client)
+{
+ int ret, val_old, val;
+ u32 ohms, chargeable;
+
+ ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old);
+ if (ret < 0)
+ return ret;
+
+ /* mask out only trickle charger bits */
+ val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK);
+ val = val_old;
+
+ /* setup trickle charger */
+ if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
+ &ohms)) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
+ if (ohms == rv3028_trickle_resistors[i])
+ break;
+
+ if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
+ /* enable trickle charger and its resistor */
+ val = RV3028_BACKUP_TCE | i;
+ } else {
+ dev_warn(&client->dev, "invalid trickle resistor value\n");
+ }
+ }
+
+ if (!device_property_read_u32(&client->dev, "aux-voltage-chargeable",
+ &chargeable)) {
+ switch (chargeable) {
+ case 0:
+ val &= ~RV3028_BACKUP_TCE;
+ break;
+ case 1:
+ val |= RV3028_BACKUP_TCE;
+ break;
+ default:
+ dev_warn(&client->dev,
+ "unsupported aux-voltage-chargeable value\n");
+ break;
+ }
+ }
+
+ /* only update EEPROM if changes are necessary */
+ if (val_old != val) {
+ ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE |
+ RV3028_BACKUP_TCR_MASK, val);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
static int rv3028_probe(struct i2c_client *client)
{
struct rv3028_data *rv3028;
int ret, status;
- u32 ohms;
struct nvmem_config nvmem_cfg = {
.name = "rv3028_nvram",
.word_size = 1,
@@ -937,24 +1001,9 @@ static int rv3028_probe(struct i2c_client *client)
if (ret)
return ret;
- /* setup trickle charger */
- if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
- &ohms)) {
- int i;
-
- for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
- if (ohms == rv3028_trickle_resistors[i])
- break;
-
- if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
- ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE |
- RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i);
- if (ret)
- return ret;
- } else {
- dev_warn(&client->dev, "invalid trickle resistor value\n");
- }
- }
+ ret = rv3028_set_trickle_charger(rv3028, client);
+ if (ret)
+ return ret;
ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
if (ret)
@@ -982,18 +1031,32 @@ static int rv3028_probe(struct i2c_client *client)
return 0;
}
+static const struct acpi_device_id rv3028_i2c_acpi_match[] = {
+ { "MCRY3028" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, rv3028_i2c_acpi_match);
+
static const __maybe_unused struct of_device_id rv3028_of_match[] = {
{ .compatible = "microcrystal,rv3028", },
{ }
};
MODULE_DEVICE_TABLE(of, rv3028_of_match);
+static const struct i2c_device_id rv3028_id_table[] = {
+ { .name = "rv3028", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rv3028_id_table);
+
static struct i2c_driver rv3028_driver = {
.driver = {
.name = "rtc-rv3028",
+ .acpi_match_table = rv3028_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3028_of_match),
},
- .probe_new = rv3028_probe,
+ .id_table = rv3028_id_table,
+ .probe = rv3028_probe,
};
module_i2c_driver(rv3028_driver);
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index e4fdd47ae066..83331d1fcab0 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -735,9 +735,14 @@ static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq,
return PTR_ERR(rv3029->rtc);
if (rv3029->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(dev))
+ irqflags = 0;
+
rc = devm_request_threaded_irq(dev, rv3029->irq,
NULL, rv3029_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rv3029", dev);
if (rc) {
dev_warn(dev, "unable to request IRQ, alarms disabled\n");
@@ -802,8 +807,8 @@ static int rv3029_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id rv3029_id[] = {
- { "rv3029", 0 },
- { "rv3029c2", 0 },
+ { "rv3029" },
+ { "rv3029c2" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rv3029_id);
@@ -819,7 +824,7 @@ static struct i2c_driver rv3029_driver = {
.name = "rv3029",
.of_match_table = of_match_ptr(rv3029_of_match),
},
- .probe_new = rv3029_i2c_probe,
+ .probe = rv3029_i2c_probe,
.id_table = rv3029_id,
};
diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
index c3bee305eacc..b8376bd1d905 100644
--- a/drivers/rtc/rtc-rv3032.c
+++ b/drivers/rtc/rtc-rv3032.c
@@ -19,7 +19,7 @@
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
@@ -69,8 +69,7 @@
#define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5)
#define RV3032_CLKOUT2_OS BIT(7)
-#define RV3032_CTRL1_EERD BIT(3)
-#define RV3032_CTRL1_WADA BIT(5)
+#define RV3032_CTRL1_EERD BIT(2)
#define RV3032_CTRL2_STOP BIT(0)
#define RV3032_CTRL2_EIE BIT(2)
@@ -647,19 +646,24 @@ static unsigned long rv3032_clkout_recalc_rate(struct clk_hw *hw,
return clkout_xtal_rates[FIELD_GET(RV3032_CLKOUT2_FD_MSK, clkout)];
}
-static long rv3032_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int rv3032_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i, hfd;
- if (rate < RV3032_HFD_STEP)
+ if (req->rate < RV3032_HFD_STEP)
for (i = 0; i < ARRAY_SIZE(clkout_xtal_rates); i++)
- if (clkout_xtal_rates[i] <= rate)
- return clkout_xtal_rates[i];
+ if (clkout_xtal_rates[i] <= req->rate) {
+ req->rate = clkout_xtal_rates[i];
- hfd = DIV_ROUND_CLOSEST(rate, RV3032_HFD_STEP);
+ return 0;
+ }
+
+ hfd = DIV_ROUND_CLOSEST(req->rate, RV3032_HFD_STEP);
- return RV3032_HFD_STEP * clamp(hfd, 0, 8192);
+ req->rate = RV3032_HFD_STEP * clamp(hfd, 0, 8192);
+
+ return 0;
}
static int rv3032_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -739,7 +743,7 @@ static const struct clk_ops rv3032_clkout_ops = {
.unprepare = rv3032_clkout_unprepare,
.is_prepared = rv3032_clkout_is_prepared,
.recalc_rate = rv3032_clkout_recalc_rate,
- .round_rate = rv3032_clkout_round_rate,
+ .determine_rate = rv3032_clkout_determine_rate,
.set_rate = rv3032_clkout_set_rate,
};
@@ -842,7 +846,7 @@ static int rv3032_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
return err;
}
-static const struct hwmon_channel_info *rv3032_hwmon_info[] = {
+static const struct hwmon_channel_info * const rv3032_hwmon_info[] = {
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST),
NULL
@@ -930,9 +934,14 @@ static int rv3032_probe(struct i2c_client *client)
return PTR_ERR(rv3032->rtc);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv3032_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rv3032", rv3032);
if (ret) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
@@ -942,11 +951,6 @@ static int rv3032_probe(struct i2c_client *client)
if (!client->irq)
clear_bit(RTC_FEATURE_ALARM, rv3032->rtc->features);
- ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL1,
- RV3032_CTRL1_WADA, RV3032_CTRL1_WADA);
- if (ret)
- return ret;
-
rv3032_trickle_charger_setup(&client->dev, rv3032);
set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3032->rtc->features);
@@ -975,6 +979,12 @@ static int rv3032_probe(struct i2c_client *client)
return 0;
}
+static const struct acpi_device_id rv3032_i2c_acpi_match[] = {
+ { "MCRY3032" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, rv3032_i2c_acpi_match);
+
static const __maybe_unused struct of_device_id rv3032_of_match[] = {
{ .compatible = "microcrystal,rv3032", },
{ }
@@ -984,9 +994,10 @@ MODULE_DEVICE_TABLE(of, rv3032_of_match);
static struct i2c_driver rv3032_driver = {
.driver = {
.name = "rtc-rv3032",
+ .acpi_match_table = rv3032_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3032_of_match),
},
- .probe_new = rv3032_probe,
+ .probe = rv3032_probe,
};
module_i2c_driver(rv3032_driver);
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index b581b6d5ad73..1327251e527c 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -15,8 +15,9 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/rtc.h>
+#include <linux/pm_wakeirq.h>
#define RV8803_I2C_TRY_COUNT 4
@@ -70,6 +71,7 @@ struct rv8803_data {
struct mutex flags_lock;
u8 ctrl;
u8 backup;
+ u8 alarm_invalid:1;
enum rv8803_type type;
};
@@ -165,13 +167,13 @@ static int rv8803_regs_init(struct rv8803_data *rv8803)
static int rv8803_regs_configure(struct rv8803_data *rv8803);
-static int rv8803_regs_reset(struct rv8803_data *rv8803)
+static int rv8803_regs_reset(struct rv8803_data *rv8803, bool full)
{
/*
* The RV-8803 resets all registers to POR defaults after voltage-loss,
* the Epson RTCs don't, so we manually reset the remainder here.
*/
- if (rv8803->type == rx_8803 || rv8803->type == rx_8900) {
+ if (full || rv8803->type == rx_8803 || rv8803->type == rx_8900) {
int ret = rv8803_regs_init(rv8803);
if (ret)
return ret;
@@ -238,6 +240,11 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
u8 *date = date1;
int ret, flags;
+ if (rv8803->alarm_invalid) {
+ dev_warn(dev, "Corruption detected, data may be invalid.\n");
+ return -EINVAL;
+ }
+
flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
if (flags < 0)
return flags;
@@ -313,12 +320,19 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
return flags;
}
- if (flags & RV8803_FLAG_V2F) {
- ret = rv8803_regs_reset(rv8803);
+ if ((flags & RV8803_FLAG_V2F) || rv8803->alarm_invalid) {
+ /*
+ * If we sense corruption in the alarm registers, but see no
+ * voltage loss flag, we can't rely on other registers having
+ * sensible values. Reset them fully.
+ */
+ ret = rv8803_regs_reset(rv8803, rv8803->alarm_invalid);
if (ret) {
mutex_unlock(&rv8803->flags_lock);
return ret;
}
+
+ rv8803->alarm_invalid = false;
}
ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
@@ -344,15 +358,33 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (flags < 0)
return flags;
+ alarmvals[0] &= 0x7f;
+ alarmvals[1] &= 0x3f;
+ alarmvals[2] &= 0x3f;
+
+ if (!bcd_is_valid(alarmvals[0]) ||
+ !bcd_is_valid(alarmvals[1]) ||
+ !bcd_is_valid(alarmvals[2]))
+ goto err_invalid;
+
alrm->time.tm_sec = 0;
- alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
- alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
- alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
+ alrm->time.tm_min = bcd2bin(alarmvals[0]);
+ alrm->time.tm_hour = bcd2bin(alarmvals[1]);
+ alrm->time.tm_mday = bcd2bin(alarmvals[2]);
alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled;
+ if ((unsigned int)alrm->time.tm_mday > 31 ||
+ (unsigned int)alrm->time.tm_hour >= 24 ||
+ (unsigned int)alrm->time.tm_min >= 60)
+ goto err_invalid;
+
return 0;
+
+err_invalid:
+ rv8803->alarm_invalid = true;
+ return -EINVAL;
}
static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -576,6 +608,28 @@ static int rv8803_regs_configure(struct rv8803_data *rv8803)
return 0;
}
+static int rv8803_resume(struct device *dev)
+{
+ struct rv8803_data *rv8803 = dev_get_drvdata(dev);
+
+ if (rv8803->client->irq > 0 && device_may_wakeup(dev))
+ disable_irq_wake(rv8803->client->irq);
+
+ return 0;
+}
+
+static int rv8803_suspend(struct device *dev)
+{
+ struct rv8803_data *rv8803 = dev_get_drvdata(dev);
+
+ if (rv8803->client->irq > 0 && device_may_wakeup(dev))
+ enable_irq_wake(rv8803->client->irq);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rv8803_pm_ops, rv8803_suspend, rv8803_resume);
+
static const struct i2c_device_id rv8803_id[] = {
{ "rv8803", rv_8803 },
{ "rv8804", rx_8804 },
@@ -614,8 +668,7 @@ static int rv8803_probe(struct i2c_client *client)
mutex_init(&rv8803->flags_lock);
rv8803->client = client;
if (client->dev.of_node) {
- rv8803->type = (enum rv8803_type)
- of_device_get_match_data(&client->dev);
+ rv8803->type = (uintptr_t)of_device_get_match_data(&client->dev);
} else {
const struct i2c_device_id *id = i2c_match_id(rv8803_id, client);
@@ -641,17 +694,30 @@ static int rv8803_probe(struct i2c_client *client)
return PTR_ERR(rv8803->rtc);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv8803_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rv8803", client);
if (err) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
client->irq = 0;
+ } else {
+ device_init_wakeup(&client->dev, true);
+ err = dev_pm_set_wake_irq(&client->dev, client->irq);
+ if (err)
+ dev_err(&client->dev, "failed to set wake IRQ\n");
}
+ } else {
+ if (device_property_read_bool(&client->dev, "wakeup-source"))
+ device_init_wakeup(&client->dev, true);
+ else
+ clear_bit(RTC_FEATURE_ALARM, rv8803->rtc->features);
}
- if (!client->irq)
- clear_bit(RTC_FEATURE_ALARM, rv8803->rtc->features);
if (of_property_read_bool(client->dev.of_node, "epson,vdet-disable"))
rv8803->backup |= RX8900_FLAG_VDETOFF;
@@ -702,8 +768,9 @@ static struct i2c_driver rv8803_driver = {
.driver = {
.name = "rtc-rv8803",
.of_match_table = of_match_ptr(rv8803_of_match),
+ .pm = &rv8803_pm_ops,
},
- .probe_new = rv8803_probe,
+ .probe = rv8803_probe,
.id_table = rv8803_id,
};
module_i2c_driver(rv8803_driver);
diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c
index 76a49838014b..7c423d672adb 100644
--- a/drivers/rtc/rtc-rx6110.c
+++ b/drivers/rtc/rtc-rx6110.c
@@ -10,11 +10,9 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
@@ -332,7 +330,7 @@ static int rx6110_probe(struct rx6110_data *rx6110, struct device *dev)
}
#if IS_ENABLED(CONFIG_SPI_MASTER)
-static struct regmap_config regmap_spi_config = {
+static const struct regmap_config regmap_spi_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RX6110_REG_IRQ,
@@ -412,7 +410,7 @@ static void rx6110_spi_unregister(void)
#endif /* CONFIG_SPI_MASTER */
#if IS_ENABLED(CONFIG_I2C)
-static struct regmap_config regmap_i2c_config = {
+static const struct regmap_config regmap_i2c_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RX6110_REG_IRQ,
@@ -453,7 +451,7 @@ static const struct acpi_device_id rx6110_i2c_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rx6110_i2c_acpi_match);
static const struct i2c_device_id rx6110_i2c_id[] = {
- { "rx6110", 0 },
+ { "rx6110" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx6110_i2c_id);
@@ -463,7 +461,7 @@ static struct i2c_driver rx6110_i2c_driver = {
.name = RX6110_DRIVER_NAME,
.acpi_match_table = rx6110_i2c_acpi_match,
},
- .probe_new = rx6110_i2c_probe,
+ .probe = rx6110_i2c_probe,
.id_table = rx6110_i2c_id,
};
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
index d09056570739..2b6198d1cf81 100644
--- a/drivers/rtc/rtc-rx8010.c
+++ b/drivers/rtc/rtc-rx8010.c
@@ -50,7 +50,7 @@
#define RX8010_ALARM_AE BIT(7)
static const struct i2c_device_id rx8010_id[] = {
- { "rx8010", 0 },
+ { "rx8010" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8010_id);
@@ -394,10 +394,14 @@ static int rx8010_probe(struct i2c_client *client)
return PTR_ERR(rx8010->rtc);
if (client->irq > 0) {
- dev_info(dev, "IRQ %d supplied\n", client->irq);
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = devm_request_threaded_irq(dev, client->irq, NULL,
rx8010_irq_1_handler,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rx8010", client);
if (err) {
dev_err(dev, "unable to request IRQ\n");
@@ -420,7 +424,7 @@ static struct i2c_driver rx8010_driver = {
.name = "rtc-rx8010",
.of_match_table = of_match_ptr(rx8010_of_match),
},
- .probe_new = rx8010_probe,
+ .probe = rx8010_probe,
.id_table = rx8010_id,
};
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index 331c20d4d843..7e9f7cb90c28 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -316,7 +316,7 @@ static int rx8025_init_client(struct i2c_client *client)
return hour_reg;
rx8025->is_24 = (hour_reg & RX8035_BIT_HOUR_1224);
} else {
- rx8025->is_24 = (ctrl[1] & RX8025_BIT_CTRL1_1224);
+ rx8025->is_24 = (ctrl[0] & RX8025_BIT_CTRL1_1224);
}
out:
return err;
@@ -581,7 +581,7 @@ static struct i2c_driver rx8025_driver = {
.driver = {
.name = "rtc-rx8025",
},
- .probe_new = rx8025_probe,
+ .probe = rx8025_probe,
.id_table = rx8025_id,
};
diff --git a/drivers/rtc/rtc-rx8111.c b/drivers/rtc/rtc-rx8111.c
new file mode 100644
index 000000000000..8450d9f0b566
--- /dev/null
+++ b/drivers/rtc/rtc-rx8111.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Epson RX8111 RTC.
+ *
+ * Copyright (C) 2023 Axis Communications AB
+ */
+
+#include <linux/bcd.h>
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <linux/rtc.h>
+
+#define RX8111_REG_SEC 0x10 /* Second counter. */
+#define RX8111_REG_MIN 0x11 /* Minute counter */
+#define RX8111_REG_HOUR 0x12 /* Hour counter. */
+#define RX8111_REG_WEEK 0x13 /* Week day counter. */
+#define RX8111_REG_DAY 0x14 /* Month day counter. */
+#define RX8111_REG_MONTH 0x15 /* Month counter. */
+#define RX8111_REG_YEAR 0x16 /* Year counter. */
+
+#define RX8111_REG_ALARM_MIN 0x17 /* Alarm minute. */
+#define RX8111_REG_ALARM_HOUR 0x18 /* Alarm hour. */
+#define RX8111_REG_ALARM_WEEK_DAY 0x19 /* Alarm week or month day. */
+
+#define RX8111_REG_TIMER_COUNTER0 0x1a /* Timer counter LSB. */
+#define RX8111_REG_TIMER_COUNTER1 0x1b /* Timer counter. */
+#define RX8111_REG_TIMER_COUNTER2 0x1c /* Timer counter MSB. */
+
+#define RX8111_REG_EXT 0x1d /* Extension register. */
+#define RX8111_REG_FLAG 0x1e /* Flag register. */
+#define RX8111_REG_CTRL 0x1f /* Control register. */
+
+#define RX8111_REG_TS_1_1000_SEC 0x20 /* Timestamp 256 or 512 Hz . */
+#define RX8111_REG_TS_1_100_SEC 0x21 /* Timestamp 1 - 128 Hz. */
+#define RX8111_REG_TS_SEC 0x22 /* Timestamp second. */
+#define RX8111_REG_TS_MIN 0x23 /* Timestamp minute. */
+#define RX8111_REG_TS_HOUR 0x24 /* Timestamp hour. */
+#define RX8111_REG_TS_WEEK 0x25 /* Timestamp week day. */
+#define RX8111_REG_TS_DAY 0x26 /* Timestamp month day. */
+#define RX8111_REG_TS_MONTH 0x27 /* Timestamp month. */
+#define RX8111_REG_TS_YEAR 0x28 /* Timestamp year. */
+#define RX8111_REG_TS_STATUS 0x29 /* Timestamp status. */
+
+#define RX8111_REG_EVIN_SETTING 0x2b /* Timestamp trigger setting. */
+#define RX8111_REG_ALARM_SEC 0x2c /* Alarm second. */
+#define RX8111_REG_TIMER_CTRL 0x2d /* Timer control. */
+#define RX8111_REG_TS_CTRL0 0x2e /* Timestamp control 0. */
+#define RX8111_REG_CMD_TRIGGER 0x2f /* Timestamp trigger. */
+#define RX8111_REG_PWR_SWITCH_CTRL 0x32 /* Power switch control. */
+#define RX8111_REG_STATUS_MON 0x33 /* Status monitor. */
+#define RX8111_REG_TS_CTRL1 0x34 /* Timestamp control 1. */
+#define RX8111_REG_TS_CTRL2 0x35 /* Timestamp control 2. */
+#define RX8111_REG_TS_CTRL3 0x36 /* Timestamp control 3. */
+
+#define RX8111_FLAG_XST_BIT BIT(0)
+#define RX8111_FLAG_VLF_BIT BIT(1)
+
+#define RX8111_TIME_BUF_SZ (RX8111_REG_YEAR - RX8111_REG_SEC + 1)
+
+enum rx8111_regfield {
+ /* RX8111_REG_EXT. */
+ RX8111_REGF_TSEL0,
+ RX8111_REGF_TSEL1,
+ RX8111_REGF_ETS,
+ RX8111_REGF_WADA,
+ RX8111_REGF_TE,
+ RX8111_REGF_USEL,
+ RX8111_REGF_FSEL0,
+ RX8111_REGF_FSEL1,
+
+ /* RX8111_REG_FLAG. */
+ RX8111_REGF_XST,
+ RX8111_REGF_VLF,
+ RX8111_REGF_EVF,
+ RX8111_REGF_AF,
+ RX8111_REGF_TF,
+ RX8111_REGF_UF,
+ RX8111_REGF_POR,
+
+ /* RX8111_REG_CTRL. */
+ RX8111_REGF_STOP,
+ RX8111_REGF_EIE,
+ RX8111_REGF_AIE,
+ RX8111_REGF_TIE,
+ RX8111_REGF_UIE,
+
+ /* RX8111_REG_PWR_SWITCH_CTRL. */
+ RX8111_REGF_SMPT0,
+ RX8111_REGF_SMPT1,
+ RX8111_REGF_SWSEL0,
+ RX8111_REGF_SWSEL1,
+ RX8111_REGF_INIEN,
+ RX8111_REGF_CHGEN,
+
+ /* RX8111_REG_STATUS_MON. */
+ RX8111_REGF_VLOW,
+
+ /* Sentinel value. */
+ RX8111_REGF_MAX
+};
+
+static const struct reg_field rx8111_regfields[] = {
+ [RX8111_REGF_TSEL0] = REG_FIELD(RX8111_REG_EXT, 0, 0),
+ [RX8111_REGF_TSEL1] = REG_FIELD(RX8111_REG_EXT, 1, 1),
+ [RX8111_REGF_ETS] = REG_FIELD(RX8111_REG_EXT, 2, 2),
+ [RX8111_REGF_WADA] = REG_FIELD(RX8111_REG_EXT, 3, 3),
+ [RX8111_REGF_TE] = REG_FIELD(RX8111_REG_EXT, 4, 4),
+ [RX8111_REGF_USEL] = REG_FIELD(RX8111_REG_EXT, 5, 5),
+ [RX8111_REGF_FSEL0] = REG_FIELD(RX8111_REG_EXT, 6, 6),
+ [RX8111_REGF_FSEL1] = REG_FIELD(RX8111_REG_EXT, 7, 7),
+
+ [RX8111_REGF_XST] = REG_FIELD(RX8111_REG_FLAG, 0, 0),
+ [RX8111_REGF_VLF] = REG_FIELD(RX8111_REG_FLAG, 1, 1),
+ [RX8111_REGF_EVF] = REG_FIELD(RX8111_REG_FLAG, 2, 2),
+ [RX8111_REGF_AF] = REG_FIELD(RX8111_REG_FLAG, 3, 3),
+ [RX8111_REGF_TF] = REG_FIELD(RX8111_REG_FLAG, 4, 4),
+ [RX8111_REGF_UF] = REG_FIELD(RX8111_REG_FLAG, 5, 5),
+ [RX8111_REGF_POR] = REG_FIELD(RX8111_REG_FLAG, 7, 7),
+
+ [RX8111_REGF_STOP] = REG_FIELD(RX8111_REG_CTRL, 0, 0),
+ [RX8111_REGF_EIE] = REG_FIELD(RX8111_REG_CTRL, 2, 2),
+ [RX8111_REGF_AIE] = REG_FIELD(RX8111_REG_CTRL, 3, 3),
+ [RX8111_REGF_TIE] = REG_FIELD(RX8111_REG_CTRL, 4, 4),
+ [RX8111_REGF_UIE] = REG_FIELD(RX8111_REG_CTRL, 5, 5),
+
+ [RX8111_REGF_SMPT0] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 0, 0),
+ [RX8111_REGF_SMPT1] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 1, 1),
+ [RX8111_REGF_SWSEL0] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 2, 2),
+ [RX8111_REGF_SWSEL1] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 3, 3),
+ [RX8111_REGF_INIEN] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 6, 6),
+ [RX8111_REGF_CHGEN] = REG_FIELD(RX8111_REG_PWR_SWITCH_CTRL, 7, 7),
+
+ [RX8111_REGF_VLOW] = REG_FIELD(RX8111_REG_STATUS_MON, 1, 1),
+};
+
+static const struct regmap_config rx8111_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RX8111_REG_TS_CTRL3,
+};
+
+struct rx8111_data {
+ struct regmap *regmap;
+ struct regmap_field *regfields[RX8111_REGF_MAX];
+ struct device *dev;
+ struct rtc_device *rtc;
+};
+
+static int rx8111_read_vl_flag(struct rx8111_data *data, unsigned int *vlval)
+{
+ int ret;
+
+ ret = regmap_field_read(data->regfields[RX8111_REGF_VLF], vlval);
+ if (ret)
+ dev_dbg(data->dev, "Could not read VL flag (%d)", ret);
+
+ return ret;
+}
+
+static int rx8111_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rx8111_data *data = dev_get_drvdata(dev);
+ u8 buf[RX8111_TIME_BUF_SZ];
+ unsigned int regval;
+ int ret;
+
+ /* Check status. */
+ ret = regmap_read(data->regmap, RX8111_REG_FLAG, &regval);
+ if (ret) {
+ dev_dbg(data->dev, "Could not read flag register (%d)\n", ret);
+ return ret;
+ }
+
+ if (FIELD_GET(RX8111_FLAG_XST_BIT, regval)) {
+ dev_dbg(data->dev,
+ "Crystal oscillation stopped, time is not reliable\n");
+ return -EINVAL;
+ }
+
+ if (FIELD_GET(RX8111_FLAG_VLF_BIT, regval)) {
+ dev_dbg(data->dev,
+ "Low voltage detected, time is not reliable\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_field_read(data->regfields[RX8111_REGF_STOP], &regval);
+ if (ret) {
+ dev_dbg(data->dev, "Could not read clock status (%d)\n", ret);
+ return ret;
+ }
+
+ if (regval) {
+ dev_dbg(data->dev, "Clock stopped, time is not reliable\n");
+ return -EINVAL;
+ }
+
+ /* Read time. */
+ ret = regmap_bulk_read(data->regmap, RX8111_REG_SEC, buf,
+ ARRAY_SIZE(buf));
+ if (ret) {
+ dev_dbg(data->dev, "Could not bulk read time (%d)\n", ret);
+ return ret;
+ }
+
+ tm->tm_sec = bcd2bin(buf[0]);
+ tm->tm_min = bcd2bin(buf[1]);
+ tm->tm_hour = bcd2bin(buf[2]);
+ tm->tm_wday = ffs(buf[3]) - 1;
+ tm->tm_mday = bcd2bin(buf[4]);
+ tm->tm_mon = bcd2bin(buf[5]) - 1;
+ tm->tm_year = bcd2bin(buf[6]) + 100;
+
+ return 0;
+}
+
+static int rx8111_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rx8111_data *data = dev_get_drvdata(dev);
+ u8 buf[RX8111_TIME_BUF_SZ];
+ int ret;
+
+ buf[0] = bin2bcd(tm->tm_sec);
+ buf[1] = bin2bcd(tm->tm_min);
+ buf[2] = bin2bcd(tm->tm_hour);
+ buf[3] = BIT(tm->tm_wday);
+ buf[4] = bin2bcd(tm->tm_mday);
+ buf[5] = bin2bcd(tm->tm_mon + 1);
+ buf[6] = bin2bcd(tm->tm_year - 100);
+
+ ret = regmap_clear_bits(data->regmap, RX8111_REG_FLAG,
+ RX8111_FLAG_XST_BIT | RX8111_FLAG_VLF_BIT);
+ if (ret)
+ return ret;
+
+ /* Stop the clock. */
+ ret = regmap_field_write(data->regfields[RX8111_REGF_STOP], 1);
+ if (ret) {
+ dev_dbg(data->dev, "Could not stop the clock (%d)\n", ret);
+ return ret;
+ }
+
+ /* Set the time. */
+ ret = regmap_bulk_write(data->regmap, RX8111_REG_SEC, buf,
+ ARRAY_SIZE(buf));
+ if (ret) {
+ dev_dbg(data->dev, "Could not bulk write time (%d)\n", ret);
+
+ /*
+ * We don't bother with trying to start the clock again. We
+ * check for this in rx8111_read_time() (and thus force user to
+ * call rx8111_set_time() to try again).
+ */
+ return ret;
+ }
+
+ /* Start the clock. */
+ ret = regmap_field_write(data->regfields[RX8111_REGF_STOP], 0);
+ if (ret) {
+ dev_dbg(data->dev, "Could not start the clock (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rx8111_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct rx8111_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ unsigned int vlval;
+ int ret;
+
+ switch (cmd) {
+ case RTC_VL_READ:
+ ret = rx8111_read_vl_flag(data, &regval);
+ if (ret)
+ return ret;
+
+ vlval = regval ? RTC_VL_DATA_INVALID : 0;
+
+ ret = regmap_field_read(data->regfields[RX8111_REGF_VLOW],
+ &regval);
+ if (ret)
+ return ret;
+
+ vlval |= regval ? RTC_VL_BACKUP_LOW : 0;
+
+ return put_user(vlval, (typeof(vlval) __user *)arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static const struct rtc_class_ops rx8111_rtc_ops = {
+ .read_time = rx8111_read_time,
+ .set_time = rx8111_set_time,
+ .ioctl = rx8111_ioctl,
+};
+
+static int rx8111_probe(struct i2c_client *client)
+{
+ struct rx8111_data *data;
+ struct rtc_device *rtc;
+ size_t i;
+
+ data = devm_kmalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_dbg(&client->dev, "Could not allocate device data\n");
+ return -ENOMEM;
+ }
+
+ data->dev = &client->dev;
+ dev_set_drvdata(data->dev, data);
+
+ data->regmap = devm_regmap_init_i2c(client, &rx8111_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_dbg(data->dev, "Could not initialize regmap\n");
+ return PTR_ERR(data->regmap);
+ }
+
+ for (i = 0; i < RX8111_REGF_MAX; ++i) {
+ data->regfields[i] = devm_regmap_field_alloc(
+ data->dev, data->regmap, rx8111_regfields[i]);
+ if (IS_ERR(data->regfields[i])) {
+ dev_dbg(data->dev,
+ "Could not allocate register field %zu\n", i);
+ return PTR_ERR(data->regfields[i]);
+ }
+ }
+
+ rtc = devm_rtc_allocate_device(data->dev);
+ if (IS_ERR(rtc)) {
+ dev_dbg(data->dev, "Could not allocate rtc device\n");
+ return PTR_ERR(rtc);
+ }
+
+ rtc->ops = &rx8111_rtc_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
+
+ return devm_rtc_register_device(rtc);
+}
+
+static const struct of_device_id rx8111_of_match[] = {
+ {
+ .compatible = "epson,rx8111",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rx8111_of_match);
+
+static struct i2c_driver rx8111_driver = {
+ .driver = {
+ .name = "rtc-rx8111",
+ .of_match_table = rx8111_of_match,
+ },
+ .probe = rx8111_probe,
+};
+module_i2c_driver(rx8111_driver);
+
+MODULE_AUTHOR("Waqar Hameed <waqar.hameed@axis.com>");
+MODULE_DESCRIPTION("Epson RX8111 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c
index 14edb7534c97..20c2dff01bae 100644
--- a/drivers/rtc/rtc-rx8581.c
+++ b/drivers/rtc/rtc-rx8581.c
@@ -13,7 +13,6 @@
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/log2.h>
@@ -53,11 +52,6 @@
#define RX8571_USER_RAM 0x10
#define RX8571_NVRAM_SIZE 0x10
-struct rx8581 {
- struct regmap *regmap;
- struct rtc_device *rtc;
-};
-
struct rx85x1_config {
struct regmap_config regmap;
unsigned int num_nvram;
@@ -73,14 +67,14 @@ static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm)
unsigned char date[7];
unsigned int data;
int err;
- struct rx8581 *rx8581 = i2c_get_clientdata(client);
+ struct regmap *regmap = i2c_get_clientdata(client);
/* First we ensure that the "update flag" is not set, we read the
* time and date then re-read the "update flag". If the update flag
* has been set, we know that the time has changed during the read so
* we repeat the whole process again.
*/
- err = regmap_read(rx8581->regmap, RX8581_REG_FLAG, &data);
+ err = regmap_read(regmap, RX8581_REG_FLAG, &data);
if (err < 0)
return err;
@@ -93,20 +87,20 @@ static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm)
do {
/* If update flag set, clear it */
if (data & RX8581_FLAG_UF) {
- err = regmap_write(rx8581->regmap, RX8581_REG_FLAG,
- data & ~RX8581_FLAG_UF);
+ err = regmap_write(regmap, RX8581_REG_FLAG,
+ data & ~RX8581_FLAG_UF);
if (err < 0)
return err;
}
/* Now read time and date */
- err = regmap_bulk_read(rx8581->regmap, RX8581_REG_SC, date,
+ err = regmap_bulk_read(regmap, RX8581_REG_SC, date,
sizeof(date));
if (err < 0)
return err;
/* Check flag register */
- err = regmap_read(rx8581->regmap, RX8581_REG_FLAG, &data);
+ err = regmap_read(regmap, RX8581_REG_FLAG, &data);
if (err < 0)
return err;
} while (data & RX8581_FLAG_UF);
@@ -138,7 +132,7 @@ static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct i2c_client *client = to_i2c_client(dev);
int err;
unsigned char buf[7];
- struct rx8581 *rx8581 = i2c_get_clientdata(client);
+ struct regmap *regmap = i2c_get_clientdata(client);
dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -161,25 +155,23 @@ static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[RX8581_REG_DW] = (0x1 << tm->tm_wday);
/* Stop the clock */
- err = regmap_update_bits(rx8581->regmap, RX8581_REG_CTRL,
+ err = regmap_update_bits(regmap, RX8581_REG_CTRL,
RX8581_CTRL_STOP, RX8581_CTRL_STOP);
if (err < 0)
return err;
/* write register's data */
- err = regmap_bulk_write(rx8581->regmap, RX8581_REG_SC,
- buf, sizeof(buf));
+ err = regmap_bulk_write(regmap, RX8581_REG_SC, buf, sizeof(buf));
if (err < 0)
return err;
/* get VLF and clear it */
- err = regmap_update_bits(rx8581->regmap, RX8581_REG_FLAG,
- RX8581_FLAG_VLF, 0);
+ err = regmap_update_bits(regmap, RX8581_REG_FLAG, RX8581_FLAG_VLF, 0);
if (err < 0)
return err;
/* Restart the clock */
- return regmap_update_bits(rx8581->regmap, RX8581_REG_CTRL,
+ return regmap_update_bits(regmap, RX8581_REG_CTRL,
RX8581_CTRL_STOP, 0);
}
@@ -191,29 +183,27 @@ static const struct rtc_class_ops rx8581_rtc_ops = {
static int rx8571_nvram_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
- struct rx8581 *rx8581 = priv;
+ struct regmap *regmap = priv;
- return regmap_bulk_read(rx8581->regmap, RX8571_USER_RAM + offset,
- val, bytes);
+ return regmap_bulk_read(regmap, RX8571_USER_RAM + offset, val, bytes);
}
static int rx8571_nvram_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
- struct rx8581 *rx8581 = priv;
+ struct regmap *regmap = priv;
- return regmap_bulk_write(rx8581->regmap, RX8571_USER_RAM + offset,
- val, bytes);
+ return regmap_bulk_write(regmap, RX8571_USER_RAM + offset, val, bytes);
}
static int rx85x1_nvram_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
- struct rx8581 *rx8581 = priv;
+ struct regmap *regmap = priv;
unsigned int tmp_val;
int ret;
- ret = regmap_read(rx8581->regmap, RX8581_REG_RAM, &tmp_val);
+ ret = regmap_read(regmap, RX8581_REG_RAM, &tmp_val);
(*(unsigned char *)val) = (unsigned char) tmp_val;
return ret;
@@ -222,12 +212,11 @@ static int rx85x1_nvram_read(void *priv, unsigned int offset, void *val,
static int rx85x1_nvram_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
- struct rx8581 *rx8581 = priv;
+ struct regmap *regmap = priv;
unsigned char tmp_val;
tmp_val = *((unsigned char *)val);
- return regmap_write(rx8581->regmap, RX8581_REG_RAM,
- (unsigned int)tmp_val);
+ return regmap_write(regmap, RX8581_REG_RAM, (unsigned int)tmp_val);
}
static const struct rx85x1_config rx8581_config = {
@@ -250,9 +239,10 @@ static const struct rx85x1_config rx8571_config = {
static int rx8581_probe(struct i2c_client *client)
{
- struct rx8581 *rx8581;
+ struct regmap *regmap;
const struct rx85x1_config *config = &rx8581_config;
const void *data = of_device_get_match_data(&client->dev);
+ struct rtc_device *rtc;
static struct nvmem_config nvmem_cfg[] = {
{
.name = "rx85x1-",
@@ -277,38 +267,34 @@ static int rx8581_probe(struct i2c_client *client)
if (data)
config = data;
- rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL);
- if (!rx8581)
- return -ENOMEM;
-
- i2c_set_clientdata(client, rx8581);
+ regmap = devm_regmap_init_i2c(client, &config->regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- rx8581->regmap = devm_regmap_init_i2c(client, &config->regmap);
- if (IS_ERR(rx8581->regmap))
- return PTR_ERR(rx8581->regmap);
+ i2c_set_clientdata(client, regmap);
- rx8581->rtc = devm_rtc_allocate_device(&client->dev);
- if (IS_ERR(rx8581->rtc))
- return PTR_ERR(rx8581->rtc);
+ rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- rx8581->rtc->ops = &rx8581_rtc_ops;
- rx8581->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
- rx8581->rtc->range_max = RTC_TIMESTAMP_END_2099;
- rx8581->rtc->start_secs = 0;
- rx8581->rtc->set_start_time = true;
+ rtc->ops = &rx8581_rtc_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
+ rtc->start_secs = 0;
+ rtc->set_start_time = true;
- ret = devm_rtc_register_device(rx8581->rtc);
+ ret = devm_rtc_register_device(rtc);
for (i = 0; i < config->num_nvram; i++) {
- nvmem_cfg[i].priv = rx8581;
- devm_rtc_nvmem_register(rx8581->rtc, &nvmem_cfg[i]);
+ nvmem_cfg[i].priv = regmap;
+ devm_rtc_nvmem_register(rtc, &nvmem_cfg[i]);
}
return ret;
}
static const struct i2c_device_id rx8581_id[] = {
- { "rx8581", 0 },
+ { "rx8581" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8581_id);
@@ -325,7 +311,7 @@ static struct i2c_driver rx8581_driver = {
.name = "rtc-rx8581",
.of_match_table = of_match_ptr(rx8581_of_match),
},
- .probe_new = rx8581_probe,
+ .probe = rx8581_probe,
.id_table = rx8581_id,
};
diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
index 0d36bc50197c..c4ed43735457 100644
--- a/drivers/rtc/rtc-rzn1.c
+++ b/drivers/rtc/rtc-rzn1.c
@@ -7,26 +7,29 @@
* - 2022 Schneider Electric
*
* Authors:
- * - Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
+ * - Michel Pollet <buserror@gmail.com>
* - Miquel Raynal <miquel.raynal@bootlin.com>
*/
#include <linux/bcd.h>
+#include <linux/clk.h>
#include <linux/init.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/rtc.h>
+#include <linux/spinlock.h>
#define RZN1_RTC_CTL0 0x00
-#define RZN1_RTC_CTL0_SLSB_SUBU 0
#define RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
#define RZN1_RTC_CTL0_AMPM BIT(5)
+#define RZN1_RTC_CTL0_CEST BIT(6)
#define RZN1_RTC_CTL0_CE BIT(7)
#define RZN1_RTC_CTL1 0x04
+#define RZN1_RTC_CTL1_1SE BIT(3)
#define RZN1_RTC_CTL1_ALME BIT(4)
#define RZN1_RTC_CTL2 0x08
@@ -35,57 +38,54 @@
#define RZN1_RTC_CTL2_WUST BIT(5)
#define RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST)
-#define RZN1_RTC_SEC 0x14
-#define RZN1_RTC_MIN 0x18
-#define RZN1_RTC_HOUR 0x1c
-#define RZN1_RTC_WEEK 0x20
-#define RZN1_RTC_DAY 0x24
-#define RZN1_RTC_MONTH 0x28
-#define RZN1_RTC_YEAR 0x2c
+#define RZN1_RTC_TIME 0x30
+#define RZN1_RTC_TIME_MIN_SHIFT 8
+#define RZN1_RTC_TIME_HOUR_SHIFT 16
+#define RZN1_RTC_CAL 0x34
+#define RZN1_RTC_CAL_DAY_SHIFT 8
+#define RZN1_RTC_CAL_MON_SHIFT 16
+#define RZN1_RTC_CAL_YEAR_SHIFT 24
#define RZN1_RTC_SUBU 0x38
#define RZN1_RTC_SUBU_DEV BIT(7)
#define RZN1_RTC_SUBU_DECR BIT(6)
+#define RZN1_RTC_SCMP 0x3c
+
#define RZN1_RTC_ALM 0x40
#define RZN1_RTC_ALH 0x44
#define RZN1_RTC_ALW 0x48
#define RZN1_RTC_SECC 0x4c
-#define RZN1_RTC_MINC 0x50
-#define RZN1_RTC_HOURC 0x54
-#define RZN1_RTC_WEEKC 0x58
-#define RZN1_RTC_DAYC 0x5c
-#define RZN1_RTC_MONTHC 0x60
-#define RZN1_RTC_YEARC 0x64
+#define RZN1_RTC_TIMEC 0x68
+#define RZN1_RTC_CALC 0x6c
struct rzn1_rtc {
struct rtc_device *rtcdev;
void __iomem *base;
+ /*
+ * Protects access to RZN1_RTC_CTL1 reg. rtc_lock with threaded_irqs
+ * would introduce race conditions when switching interrupts because
+ * of potential sleeps
+ */
+ spinlock_t ctl1_access_lock;
+ struct rtc_time tm_alarm;
};
static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
{
- tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC);
- tm->tm_min = readl(rtc->base + RZN1_RTC_MINC);
- tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC);
- tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC);
- tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC);
- tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC);
- tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC);
-}
-
-static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm)
-{
- time64_t time;
- unsigned int days;
- u32 secs;
+ u32 val;
- time = rtc_tm_to_time64(tm);
- days = div_s64_rem(time, 86400, &secs);
+ val = readl(rtc->base + RZN1_RTC_TIMEC);
+ tm->tm_sec = bcd2bin(val);
+ tm->tm_min = bcd2bin(val >> RZN1_RTC_TIME_MIN_SHIFT);
+ tm->tm_hour = bcd2bin(val >> RZN1_RTC_TIME_HOUR_SHIFT);
- /* day of the week, 1970-01-01 was a Thursday */
- return (days + 4) % 7;
+ val = readl(rtc->base + RZN1_RTC_CALC);
+ tm->tm_wday = val & 0x0f;
+ tm->tm_mday = bcd2bin(val >> RZN1_RTC_CAL_DAY_SHIFT);
+ tm->tm_mon = bcd2bin(val >> RZN1_RTC_CAL_MON_SHIFT) - 1;
+ tm->tm_year = bcd2bin(val >> RZN1_RTC_CAL_YEAR_SHIFT) + 100;
}
static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -103,17 +103,9 @@ static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
rzn1_rtc_get_time_snapshot(rtc, tm);
secs = readl(rtc->base + RZN1_RTC_SECC);
- if (tm->tm_sec != secs)
+ if (tm->tm_sec != bcd2bin(secs))
rzn1_rtc_get_time_snapshot(rtc, tm);
- tm->tm_sec = bcd2bin(tm->tm_sec);
- tm->tm_min = bcd2bin(tm->tm_min);
- tm->tm_hour = bcd2bin(tm->tm_hour);
- tm->tm_wday = bcd2bin(tm->tm_wday);
- tm->tm_mday = bcd2bin(tm->tm_mday);
- tm->tm_mon = bcd2bin(tm->tm_mon);
- tm->tm_year = bcd2bin(tm->tm_year);
-
return 0;
}
@@ -123,14 +115,6 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
u32 val;
int ret;
- tm->tm_sec = bin2bcd(tm->tm_sec);
- tm->tm_min = bin2bcd(tm->tm_min);
- tm->tm_hour = bin2bcd(tm->tm_hour);
- tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm));
- tm->tm_mday = bin2bcd(tm->tm_mday);
- tm->tm_mon = bin2bcd(tm->tm_mon);
- tm->tm_year = bin2bcd(tm->tm_year);
-
val = readl(rtc->base + RZN1_RTC_CTL2);
if (!(val & RZN1_RTC_CTL2_STOPPED)) {
/* Hold the counter if it was counting up */
@@ -144,13 +128,17 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
return ret;
}
- writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC);
- writel(tm->tm_min, rtc->base + RZN1_RTC_MIN);
- writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR);
- writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK);
- writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY);
- writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH);
- writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR);
+ val = bin2bcd(tm->tm_sec);
+ val |= bin2bcd(tm->tm_min) << RZN1_RTC_TIME_MIN_SHIFT;
+ val |= bin2bcd(tm->tm_hour) << RZN1_RTC_TIME_HOUR_SHIFT;
+ writel(val, rtc->base + RZN1_RTC_TIME);
+
+ val = tm->tm_wday;
+ val |= bin2bcd(tm->tm_mday) << RZN1_RTC_CAL_DAY_SHIFT;
+ val |= bin2bcd(tm->tm_mon + 1) << RZN1_RTC_CAL_MON_SHIFT;
+ val |= bin2bcd(tm->tm_year - 100) << RZN1_RTC_CAL_YEAR_SHIFT;
+ writel(val, rtc->base + RZN1_RTC_CAL);
+
writel(0, rtc->base + RZN1_RTC_CTL2);
return 0;
@@ -159,8 +147,38 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id)
{
struct rzn1_rtc *rtc = dev_id;
+ u32 ctl1, set_irq_bits = 0;
+
+ if (rtc->tm_alarm.tm_sec == 0)
+ rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
+ else
+ /* Switch to 1s interrupts */
+ set_irq_bits = RZN1_RTC_CTL1_1SE;
+
+ guard(spinlock)(&rtc->ctl1_access_lock);
+
+ ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
+ ctl1 &= ~RZN1_RTC_CTL1_ALME;
+ ctl1 |= set_irq_bits;
+ writel(ctl1, rtc->base + RZN1_RTC_CTL1);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rzn1_rtc_1s_irq(int irq, void *dev_id)
+{
+ struct rzn1_rtc *rtc = dev_id;
+ u32 ctl1;
- rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
+ if (readl(rtc->base + RZN1_RTC_SECC) == bin2bcd(rtc->tm_alarm.tm_sec)) {
+ guard(spinlock)(&rtc->ctl1_access_lock);
+
+ ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
+ ctl1 &= ~RZN1_RTC_CTL1_1SE;
+ writel(ctl1, rtc->base + RZN1_RTC_CTL1);
+
+ rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
+ }
return IRQ_HANDLED;
}
@@ -168,14 +186,38 @@ static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id)
static int rzn1_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
struct rzn1_rtc *rtc = dev_get_drvdata(dev);
- u32 ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
+ struct rtc_time *tm = &rtc->tm_alarm, tm_now;
+ u32 ctl1;
+ int ret;
- if (enable)
- ctl1 |= RZN1_RTC_CTL1_ALME;
- else
- ctl1 &= ~RZN1_RTC_CTL1_ALME;
+ guard(spinlock_irqsave)(&rtc->ctl1_access_lock);
- writel(ctl1, rtc->base + RZN1_RTC_CTL1);
+ ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
+
+ if (enable) {
+ /*
+ * Use alarm interrupt if alarm time is at least a minute away
+ * or less than a minute but in the next minute. Otherwise use
+ * 1 second interrupt to wait for the proper second
+ */
+ do {
+ ctl1 &= ~(RZN1_RTC_CTL1_ALME | RZN1_RTC_CTL1_1SE);
+
+ ret = rzn1_rtc_read_time(dev, &tm_now);
+ if (ret)
+ return ret;
+
+ if (rtc_tm_sub(tm, &tm_now) > 59 || tm->tm_min != tm_now.tm_min)
+ ctl1 |= RZN1_RTC_CTL1_ALME;
+ else
+ ctl1 |= RZN1_RTC_CTL1_1SE;
+
+ writel(ctl1, rtc->base + RZN1_RTC_CTL1);
+ } while (readl(rtc->base + RZN1_RTC_SECC) != bin2bcd(tm_now.tm_sec));
+ } else {
+ ctl1 &= ~(RZN1_RTC_CTL1_ALME | RZN1_RTC_CTL1_1SE);
+ writel(ctl1, rtc->base + RZN1_RTC_CTL1);
+ }
return 0;
}
@@ -209,7 +251,7 @@ static int rzn1_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
}
ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
- alrm->enabled = !!(ctl1 & RZN1_RTC_CTL1_ALME);
+ alrm->enabled = !!(ctl1 & (RZN1_RTC_CTL1_ALME | RZN1_RTC_CTL1_1SE));
return 0;
}
@@ -227,7 +269,7 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return ret;
/* We cannot set alarms more than one week ahead */
- farest = rtc_tm_to_time64(&tm_now) + (7 * 86400);
+ farest = rtc_tm_to_time64(&tm_now) + rtc->rtcdev->alarm_offset_max;
alarm = rtc_tm_to_time64(tm);
if (time_after(alarm, farest))
return -ERANGE;
@@ -240,6 +282,8 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
writel(bin2bcd(tm->tm_hour), rtc->base + RZN1_RTC_ALH);
writel(BIT(wday), rtc->base + RZN1_RTC_ALW);
+ rtc->tm_alarm = alrm->time;
+
rzn1_rtc_alarm_irq_enable(dev, alrm->enabled);
return 0;
@@ -315,7 +359,7 @@ static int rzn1_rtc_set_offset(struct device *dev, long offset)
return 0;
}
-static const struct rtc_class_ops rzn1_rtc_ops = {
+static const struct rtc_class_ops rzn1_rtc_ops_subu = {
.read_time = rzn1_rtc_read_time,
.set_time = rzn1_rtc_set_time,
.read_alarm = rzn1_rtc_read_alarm,
@@ -325,11 +369,21 @@ static const struct rtc_class_ops rzn1_rtc_ops = {
.set_offset = rzn1_rtc_set_offset,
};
+static const struct rtc_class_ops rzn1_rtc_ops_scmp = {
+ .read_time = rzn1_rtc_read_time,
+ .set_time = rzn1_rtc_set_time,
+ .read_alarm = rzn1_rtc_read_alarm,
+ .set_alarm = rzn1_rtc_set_alarm,
+ .alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
+};
+
static int rzn1_rtc_probe(struct platform_device *pdev)
{
struct rzn1_rtc *rtc;
- int alarm_irq;
- int ret;
+ u32 val, scmp_val = 0;
+ struct clk *xtal;
+ unsigned long rate;
+ int irq, ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
@@ -341,9 +395,9 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
if (IS_ERR(rtc->base))
return dev_err_probe(&pdev->dev, PTR_ERR(rtc->base), "Missing reg\n");
- alarm_irq = platform_get_irq(pdev, 0);
- if (alarm_irq < 0)
- return alarm_irq;
+ irq = platform_get_irq_byname(pdev, "alarm");
+ if (irq < 0)
+ return irq;
rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc->rtcdev))
@@ -351,9 +405,7 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
- rtc->rtcdev->ops = &rzn1_rtc_ops;
- set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
- clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
+ rtc->rtcdev->alarm_offset_max = 7 * 86400;
ret = devm_pm_runtime_enable(&pdev->dev);
if (ret < 0)
@@ -362,23 +414,66 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- /*
- * Ensure the clock counter is enabled.
- * Set 24-hour mode and possible oscillator offset compensation in SUBU mode.
- */
- writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU,
- rtc->base + RZN1_RTC_CTL0);
+ /* Only switch to scmp if we have an xtal clock with a valid rate and != 32768 */
+ xtal = devm_clk_get_optional(&pdev->dev, "xtal");
+ if (IS_ERR(xtal)) {
+ ret = PTR_ERR(xtal);
+ goto dis_runtime_pm;
+ } else if (xtal) {
+ rate = clk_get_rate(xtal);
+
+ if (rate < 32000 || rate > BIT(22)) {
+ ret = -EOPNOTSUPP;
+ goto dis_runtime_pm;
+ }
+
+ if (rate != 32768)
+ scmp_val = RZN1_RTC_CTL0_SLSB_SCMP;
+ }
+
+ /* Disable controller during SUBU/SCMP setup */
+ val = readl(rtc->base + RZN1_RTC_CTL0) & ~RZN1_RTC_CTL0_CE;
+ writel(val, rtc->base + RZN1_RTC_CTL0);
+ /* Wait 2-4 32k clock cycles for the disabled controller */
+ ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL0, val,
+ !(val & RZN1_RTC_CTL0_CEST), 62, 123);
+ if (ret)
+ goto dis_runtime_pm;
+
+ /* Set desired modes leaving the controller disabled */
+ writel(RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
+
+ if (scmp_val) {
+ writel(rate - 1, rtc->base + RZN1_RTC_SCMP);
+ rtc->rtcdev->ops = &rzn1_rtc_ops_scmp;
+ } else {
+ rtc->rtcdev->ops = &rzn1_rtc_ops_subu;
+ }
+
+ /* Enable controller finally */
+ writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
/* Disable all interrupts */
writel(0, rtc->base + RZN1_RTC_CTL1);
- ret = devm_request_irq(&pdev->dev, alarm_irq, rzn1_rtc_alarm_irq, 0,
- dev_name(&pdev->dev), rtc);
+ spin_lock_init(&rtc->ctl1_access_lock);
+
+ ret = devm_request_irq(&pdev->dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc);
if (ret) {
- dev_err(&pdev->dev, "RTC timer interrupt not available\n");
+ dev_err(&pdev->dev, "RTC alarm interrupt not available\n");
goto dis_runtime_pm;
}
+ irq = platform_get_irq_byname_optional(pdev, "pps");
+ if (irq >= 0)
+ ret = devm_request_irq(&pdev->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(&pdev->dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n");
+ }
+
ret = devm_rtc_register_device(rtc->rtcdev);
if (ret)
goto dis_runtime_pm;
@@ -391,11 +486,14 @@ dis_runtime_pm:
return ret;
}
-static int rzn1_rtc_remove(struct platform_device *pdev)
+static void rzn1_rtc_remove(struct platform_device *pdev)
{
- pm_runtime_put(&pdev->dev);
+ struct rzn1_rtc *rtc = platform_get_drvdata(pdev);
- return 0;
+ /* Disable all interrupts */
+ writel(0, rtc->base + RZN1_RTC_CTL1);
+
+ pm_runtime_put(&pdev->dev);
}
static const struct of_device_id rzn1_rtc_of_match[] = {
@@ -414,7 +512,7 @@ static struct platform_driver rzn1_rtc_driver = {
};
module_platform_driver(rzn1_rtc_driver);
-MODULE_AUTHOR("Michel Pollet <Michel.Pollet@bp.renesas.com");
+MODULE_AUTHOR("Michel Pollet <buserror@gmail.com>");
MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
MODULE_DESCRIPTION("RZ/N1 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s32g.c b/drivers/rtc/rtc-s32g.c
new file mode 100644
index 000000000000..3a0818e972eb
--- /dev/null
+++ b/drivers/rtc/rtc-s32g.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define RTCC_OFFSET 0x4ul
+#define RTCS_OFFSET 0x8ul
+#define APIVAL_OFFSET 0x10ul
+
+/* RTCC fields */
+#define RTCC_CNTEN BIT(31)
+#define RTCC_APIEN BIT(15)
+#define RTCC_APIIE BIT(14)
+#define RTCC_CLKSEL_MASK GENMASK(13, 12)
+#define RTCC_DIV512EN BIT(11)
+#define RTCC_DIV32EN BIT(10)
+
+/* RTCS fields */
+#define RTCS_INV_API BIT(17)
+#define RTCS_APIF BIT(13)
+
+#define APIVAL_MAX_VAL GENMASK(31, 0)
+#define RTC_SYNCH_TIMEOUT (100 * USEC_PER_MSEC)
+
+/*
+ * S32G2 and S32G3 SoCs have RTC clock source1 reserved and
+ * should not be used.
+ */
+#define RTC_CLK_SRC1_RESERVED BIT(1)
+
+/*
+ * S32G RTC module has a 512 value and a 32 value hardware frequency
+ * divisors (DIV512 and DIV32) which could be used to achieve higher
+ * counter ranges by lowering the RTC frequency.
+ */
+enum {
+ DIV1 = 1,
+ DIV32 = 32,
+ DIV512 = 512,
+ DIV512_32 = 16384
+};
+
+static const char *const rtc_clk_src[] = {
+ "source0",
+ "source1",
+ "source2",
+ "source3"
+};
+
+struct rtc_priv {
+ struct rtc_device *rdev;
+ void __iomem *rtc_base;
+ struct clk *ipg;
+ struct clk *clk_src;
+ const struct rtc_soc_data *rtc_data;
+ u64 rtc_hz;
+ time64_t sleep_sec;
+ int irq;
+ u32 clk_src_idx;
+};
+
+struct rtc_soc_data {
+ u32 clk_div;
+ u32 reserved_clk_mask;
+};
+
+static const struct rtc_soc_data rtc_s32g2_data = {
+ .clk_div = DIV512_32,
+ .reserved_clk_mask = RTC_CLK_SRC1_RESERVED,
+};
+
+static irqreturn_t s32g_rtc_handler(int irq, void *dev)
+{
+ struct rtc_priv *priv = platform_get_drvdata(dev);
+ u32 status;
+
+ status = readl(priv->rtc_base + RTCS_OFFSET);
+
+ if (status & RTCS_APIF) {
+ writel(0x0, priv->rtc_base + APIVAL_OFFSET);
+ writel(status | RTCS_APIF, priv->rtc_base + RTCS_OFFSET);
+ }
+
+ rtc_update_irq(priv->rdev, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * The function is not really getting time from the RTC since the S32G RTC
+ * has several limitations. Thus, to setup alarm use system time.
+ */
+static int s32g_rtc_read_time(struct device *dev,
+ struct rtc_time *tm)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ time64_t sec;
+
+ if (check_add_overflow(ktime_get_real_seconds(),
+ priv->sleep_sec, &sec))
+ return -ERANGE;
+
+ rtc_time64_to_tm(sec, tm);
+
+ return 0;
+}
+
+static int s32g_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ u32 rtcc, rtcs;
+
+ rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+ rtcs = readl(priv->rtc_base + RTCS_OFFSET);
+
+ alrm->enabled = rtcc & RTCC_APIIE;
+ if (alrm->enabled)
+ alrm->pending = !(rtcs & RTCS_APIF);
+
+ return 0;
+}
+
+static int s32g_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ u32 rtcc;
+
+ /* RTC API functionality is used both for triggering interrupts
+ * and as a wakeup event. Hence it should always be enabled.
+ */
+ rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+ rtcc |= RTCC_APIEN | RTCC_APIIE;
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+
+ return 0;
+}
+
+static int s32g_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ unsigned long long cycles;
+ long long t_offset;
+ time64_t alrm_time;
+ u32 rtcs;
+ int ret;
+
+ alrm_time = rtc_tm_to_time64(&alrm->time);
+ t_offset = alrm_time - ktime_get_real_seconds() - priv->sleep_sec;
+ if (t_offset < 0)
+ return -ERANGE;
+
+ cycles = t_offset * priv->rtc_hz;
+ if (cycles > APIVAL_MAX_VAL)
+ return -ERANGE;
+
+ /* APIVAL could have been reset from the IRQ handler.
+ * Hence, we wait in case there is a synchronization process.
+ */
+ ret = read_poll_timeout(readl, rtcs, !(rtcs & RTCS_INV_API),
+ 0, RTC_SYNCH_TIMEOUT, false, priv->rtc_base + RTCS_OFFSET);
+ if (ret)
+ return ret;
+
+ writel(cycles, priv->rtc_base + APIVAL_OFFSET);
+
+ return read_poll_timeout(readl, rtcs, !(rtcs & RTCS_INV_API),
+ 0, RTC_SYNCH_TIMEOUT, false, priv->rtc_base + RTCS_OFFSET);
+}
+
+/*
+ * Disable the 32-bit free running counter.
+ * This allows Clock Source and Divisors selection
+ * to be performed without causing synchronization issues.
+ */
+static void s32g_rtc_disable(struct rtc_priv *priv)
+{
+ u32 rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+
+ rtcc &= ~RTCC_CNTEN;
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+}
+
+static void s32g_rtc_enable(struct rtc_priv *priv)
+{
+ u32 rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+
+ rtcc |= RTCC_CNTEN;
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+}
+
+static int rtc_clk_src_setup(struct rtc_priv *priv)
+{
+ u32 rtcc;
+
+ rtcc = FIELD_PREP(RTCC_CLKSEL_MASK, priv->clk_src_idx);
+
+ switch (priv->rtc_data->clk_div) {
+ case DIV512_32:
+ rtcc |= RTCC_DIV512EN;
+ rtcc |= RTCC_DIV32EN;
+ break;
+ case DIV512:
+ rtcc |= RTCC_DIV512EN;
+ break;
+ case DIV32:
+ rtcc |= RTCC_DIV32EN;
+ break;
+ case DIV1:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rtcc |= RTCC_APIEN | RTCC_APIIE;
+ /*
+ * Make sure the CNTEN is 0 before we configure
+ * the clock source and dividers.
+ */
+ s32g_rtc_disable(priv);
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+ s32g_rtc_enable(priv);
+
+ return 0;
+}
+
+static const struct rtc_class_ops rtc_ops = {
+ .read_time = s32g_rtc_read_time,
+ .read_alarm = s32g_rtc_read_alarm,
+ .set_alarm = s32g_rtc_set_alarm,
+ .alarm_irq_enable = s32g_rtc_alarm_irq_enable,
+};
+
+static int rtc_clk_dts_setup(struct rtc_priv *priv,
+ struct device *dev)
+{
+ u32 i;
+
+ priv->ipg = devm_clk_get_enabled(dev, "ipg");
+ if (IS_ERR(priv->ipg))
+ return dev_err_probe(dev, PTR_ERR(priv->ipg),
+ "Failed to get 'ipg' clock\n");
+
+ for (i = 0; i < ARRAY_SIZE(rtc_clk_src); i++) {
+ if (priv->rtc_data->reserved_clk_mask & BIT(i))
+ return -EOPNOTSUPP;
+
+ priv->clk_src = devm_clk_get_enabled(dev, rtc_clk_src[i]);
+ if (!IS_ERR(priv->clk_src)) {
+ priv->clk_src_idx = i;
+ break;
+ }
+ }
+
+ if (IS_ERR(priv->clk_src))
+ return dev_err_probe(dev, PTR_ERR(priv->clk_src),
+ "Failed to get rtc module clock source\n");
+
+ return 0;
+}
+
+static int s32g_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtc_priv *priv;
+ unsigned long rtc_hz;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->rtc_data = of_device_get_match_data(dev);
+ if (!priv->rtc_data)
+ return -ENODEV;
+
+ priv->rtc_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->rtc_base))
+ return PTR_ERR(priv->rtc_base);
+
+ device_init_wakeup(dev, true);
+
+ ret = rtc_clk_dts_setup(priv, dev);
+ if (ret)
+ return ret;
+
+ priv->rdev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(priv->rdev))
+ return PTR_ERR(priv->rdev);
+
+ ret = rtc_clk_src_setup(priv);
+ if (ret)
+ return ret;
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq < 0) {
+ ret = priv->irq;
+ goto disable_rtc;
+ }
+
+ rtc_hz = clk_get_rate(priv->clk_src);
+ if (!rtc_hz) {
+ dev_err(dev, "Failed to get RTC frequency\n");
+ ret = -EINVAL;
+ goto disable_rtc;
+ }
+
+ priv->rtc_hz = DIV_ROUND_UP(rtc_hz, priv->rtc_data->clk_div);
+
+ platform_set_drvdata(pdev, priv);
+ priv->rdev->ops = &rtc_ops;
+
+ ret = devm_request_irq(dev, priv->irq,
+ s32g_rtc_handler, 0, dev_name(dev), pdev);
+ if (ret) {
+ dev_err(dev, "Request interrupt %d failed, error: %d\n",
+ priv->irq, ret);
+ goto disable_rtc;
+ }
+
+ ret = devm_rtc_register_device(priv->rdev);
+ if (ret)
+ goto disable_rtc;
+
+ return 0;
+
+disable_rtc:
+ s32g_rtc_disable(priv);
+ return ret;
+}
+
+static int s32g_rtc_suspend(struct device *dev)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ u32 apival = readl(priv->rtc_base + APIVAL_OFFSET);
+
+ if (check_add_overflow(priv->sleep_sec, div64_u64(apival, priv->rtc_hz),
+ &priv->sleep_sec)) {
+ dev_warn(dev, "Overflow on sleep cycles occurred. Resetting to 0.\n");
+ priv->sleep_sec = 0;
+ }
+
+ return 0;
+}
+
+static int s32g_rtc_resume(struct device *dev)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+
+ /* The transition from resume to run is a reset event.
+ * This leads to the RTC registers being reset after resume from
+ * suspend. It is uncommon, but this behaviour has been observed
+ * on S32G RTC after issuing a Suspend to RAM operation.
+ * Thus, reconfigure RTC registers on the resume path.
+ */
+ return rtc_clk_src_setup(priv);
+}
+
+static const struct of_device_id rtc_dt_ids[] = {
+ { .compatible = "nxp,s32g2-rtc", .data = &rtc_s32g2_data },
+ { /* sentinel */ },
+};
+
+static DEFINE_SIMPLE_DEV_PM_OPS(s32g_rtc_pm_ops,
+ s32g_rtc_suspend, s32g_rtc_resume);
+
+static struct platform_driver s32g_rtc_driver = {
+ .driver = {
+ .name = "s32g-rtc",
+ .pm = pm_sleep_ptr(&s32g_rtc_pm_ops),
+ .of_match_table = rtc_dt_ids,
+ },
+ .probe = s32g_rtc_probe,
+};
+module_platform_driver(s32g_rtc_driver);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("NXP RTC driver for S32G2/S32G3");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index b18daaf72b17..3408d2ab2741 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -50,13 +50,12 @@
#define S35390A_INT2_MODE_PMIN (BIT(3) | BIT(2)) /* INT2FE | INT2ME */
static const struct i2c_device_id s35390a_id[] = {
- { "s35390a", 0 },
+ { "s35390a" },
{ }
};
MODULE_DEVICE_TABLE(i2c, s35390a_id);
static const __maybe_unused struct of_device_id s35390a_of_match[] = {
- { .compatible = "s35390a" },
{ .compatible = "sii,s35390a" },
{ }
};
@@ -64,7 +63,6 @@ MODULE_DEVICE_TABLE(of, s35390a_of_match);
struct s35390a {
struct i2c_client *client[8];
- struct rtc_device *rtc;
int twentyfourhour;
};
@@ -423,6 +421,7 @@ static int s35390a_probe(struct i2c_client *client)
int err, err_read;
unsigned int i;
struct s35390a *s35390a;
+ struct rtc_device *rtc;
char buf, status1;
struct device *dev = &client->dev;
@@ -448,9 +447,9 @@ static int s35390a_probe(struct i2c_client *client)
}
}
- s35390a->rtc = devm_rtc_allocate_device(dev);
- if (IS_ERR(s35390a->rtc))
- return PTR_ERR(s35390a->rtc);
+ rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
err_read = s35390a_read_status(s35390a, &status1);
if (err_read < 0) {
@@ -481,17 +480,17 @@ static int s35390a_probe(struct i2c_client *client)
device_set_wakeup_capable(dev, 1);
- s35390a->rtc->ops = &s35390a_rtc_ops;
- s35390a->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
- s35390a->rtc->range_max = RTC_TIMESTAMP_END_2099;
+ rtc->ops = &s35390a_rtc_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
- set_bit(RTC_FEATURE_ALARM_RES_MINUTE, s35390a->rtc->features);
- clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, s35390a->rtc->features );
+ set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features);
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
if (status1 & S35390A_FLAG_INT2)
- rtc_update_irq(s35390a->rtc, 1, RTC_AF);
+ rtc_update_irq(rtc, 1, RTC_AF);
- return devm_rtc_register_device(s35390a->rtc);
+ return devm_rtc_register_device(rtc);
}
static struct i2c_driver s35390a_driver = {
@@ -499,7 +498,7 @@ static struct i2c_driver s35390a_driver = {
.name = "rtc-s35390a",
.of_match_table = of_match_ptr(s35390a_of_match),
},
- .probe_new = s35390a_probe,
+ .probe = s35390a_probe,
.id_table = s35390a_id,
};
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 8fc5efde3e0b..291c0ccb0acd 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -23,7 +23,6 @@
#include <linux/log2.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
@@ -332,7 +331,7 @@ static const struct rtc_class_ops s3c_rtcops = {
.alarm_irq_enable = s3c_rtc_setaie,
};
-static void s3c24xx_rtc_enable(struct s3c_rtc *info)
+static void s3c6410_rtc_enable(struct s3c_rtc *info)
{
unsigned int con, tmp;
@@ -362,19 +361,6 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
}
}
-static void s3c24xx_rtc_disable(struct s3c_rtc *info)
-{
- unsigned int con;
-
- con = readw(info->base + S3C2410_RTCCON);
- con &= ~S3C2410_RTCCON_RTCEN;
- writew(con, info->base + S3C2410_RTCCON);
-
- con = readb(info->base + S3C2410_TICNT);
- con &= ~S3C2410_TICNT_ENABLE;
- writeb(con, info->base + S3C2410_TICNT);
-}
-
static void s3c6410_rtc_disable(struct s3c_rtc *info)
{
unsigned int con;
@@ -385,7 +371,7 @@ static void s3c6410_rtc_disable(struct s3c_rtc *info)
writew(con, info->base + S3C2410_RTCCON);
}
-static int s3c_rtc_remove(struct platform_device *pdev)
+static void s3c_rtc_remove(struct platform_device *pdev)
{
struct s3c_rtc *info = platform_get_drvdata(pdev);
@@ -394,8 +380,6 @@ static int s3c_rtc_remove(struct platform_device *pdev)
if (info->data->needs_src_clk)
clk_unprepare(info->rtc_src_clk);
clk_unprepare(info->rtc_clk);
-
- return 0;
}
static int s3c_rtc_probe(struct platform_device *pdev)
@@ -459,7 +443,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
readw(info->base + S3C2410_RTCCON));
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
info->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(info->rtc)) {
@@ -541,53 +525,21 @@ static int s3c_rtc_resume(struct device *dev)
#endif
static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
-static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
-{
- rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
-}
-
static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
{
rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
writeb(mask, info->base + S3C2410_INTP);
}
-static struct s3c_rtc_data const s3c2410_rtc_data = {
- .irq_handler = s3c24xx_rtc_irq,
- .enable = s3c24xx_rtc_enable,
- .disable = s3c24xx_rtc_disable,
-};
-
-static struct s3c_rtc_data const s3c2416_rtc_data = {
- .irq_handler = s3c24xx_rtc_irq,
- .enable = s3c24xx_rtc_enable,
- .disable = s3c24xx_rtc_disable,
-};
-
-static struct s3c_rtc_data const s3c2443_rtc_data = {
- .irq_handler = s3c24xx_rtc_irq,
- .enable = s3c24xx_rtc_enable,
- .disable = s3c24xx_rtc_disable,
-};
-
-static struct s3c_rtc_data const s3c6410_rtc_data = {
+static const struct s3c_rtc_data s3c6410_rtc_data = {
.needs_src_clk = true,
.irq_handler = s3c6410_rtc_irq,
- .enable = s3c24xx_rtc_enable,
+ .enable = s3c6410_rtc_enable,
.disable = s3c6410_rtc_disable,
};
static const __maybe_unused struct of_device_id s3c_rtc_dt_match[] = {
{
- .compatible = "samsung,s3c2410-rtc",
- .data = &s3c2410_rtc_data,
- }, {
- .compatible = "samsung,s3c2416-rtc",
- .data = &s3c2416_rtc_data,
- }, {
- .compatible = "samsung,s3c2443-rtc",
- .data = &s3c2443_rtc_data,
- }, {
.compatible = "samsung,s3c6410-rtc",
.data = &s3c6410_rtc_data,
}, {
@@ -612,4 +564,3 @@ module_platform_driver(s3c_rtc_driver);
MODULE_DESCRIPTION("Samsung S3C RTC Driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2410-rtc");
diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h
index 3552914aa611..11d7a1255ce4 100644
--- a/drivers/rtc/rtc-s3c.h
+++ b/drivers/rtc/rtc-s3c.h
@@ -21,25 +21,6 @@
#define S3C2443_RTCCON_TICSEL (1 << 4)
#define S3C64XX_RTCCON_TICEN (1 << 8)
-#define S3C2410_TICNT S3C2410_RTCREG(0x44)
-#define S3C2410_TICNT_ENABLE (1 << 7)
-
-/* S3C2443: tick count is 15 bit wide
- * TICNT[6:0] contains upper 7 bits
- * TICNT1[7:0] contains lower 8 bits
- */
-#define S3C2443_TICNT_PART(x) ((x & 0x7f00) >> 8)
-#define S3C2443_TICNT1 S3C2410_RTCREG(0x4C)
-#define S3C2443_TICNT1_PART(x) (x & 0xff)
-
-/* S3C2416: tick count is 32 bit wide
- * TICNT[6:0] contains bits [14:8]
- * TICNT1[7:0] contains lower 8 bits
- * TICNT2[16:0] contains upper 17 bits
- */
-#define S3C2416_TICNT2 S3C2410_RTCREG(0x48)
-#define S3C2416_TICNT2_PART(x) ((x & 0xffff8000) >> 15)
-
#define S3C2410_RTCALM S3C2410_RTCREG(0x50)
#define S3C2410_RTCALM_ALMEN (1 << 6)
#define S3C2410_RTCALM_YEAREN (1 << 5)
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index 4243fe6d3842..a7220b4d0e8d 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/bcd.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
@@ -53,6 +54,7 @@ enum {
* Device | Write time | Read time | Write alarm
* =================================================
* S5M8767 | UDR + TIME | | UDR
+ * S2MPG10 | WUDR | RUDR | AUDR
* S2MPS11/14 | WUDR | RUDR | WUDR + RUDR
* S2MPS13 | WUDR | RUDR | WUDR + AUDR
* S2MPS15 | WUDR | RUDR | AUDR
@@ -85,7 +87,7 @@ struct s5m_rtc_reg_config {
unsigned int write_alarm_udr_mask;
};
-/* Register map for S5M8763 and S5M8767 */
+/* Register map for S5M8767 */
static const struct s5m_rtc_reg_config s5m_rtc_regs = {
.regs_count = 8,
.time = S5M_RTC_SEC,
@@ -99,6 +101,20 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = {
.write_alarm_udr_mask = S5M_RTC_UDR_MASK,
};
+/* Register map for S2MPG10 */
+static const struct s5m_rtc_reg_config s2mpg10_rtc_regs = {
+ .regs_count = 7,
+ .time = S2MPG10_RTC_SEC,
+ .ctrl = S2MPG10_RTC_CTRL,
+ .alarm0 = S2MPG10_RTC_A0SEC,
+ .alarm1 = S2MPG10_RTC_A1SEC,
+ .udr_update = S2MPG10_RTC_UPDATE,
+ .autoclear_udr_mask = S2MPS15_RTC_WUDR_MASK | S2MPS15_RTC_AUDR_MASK,
+ .read_time_udr_mask = S2MPS_RTC_RUDR_MASK,
+ .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK,
+ .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK,
+};
+
/* Register map for S2MPS13 */
static const struct s5m_rtc_reg_config s2mps13_rtc_regs = {
.regs_count = 7,
@@ -146,7 +162,6 @@ static const struct s5m_rtc_reg_config s2mps15_rtc_regs = {
struct s5m_rtc_info {
struct device *dev;
- struct i2c_client *i2c;
struct sec_pmic_dev *s5m87xx;
struct regmap *regmap;
struct rtc_device *rtc_dev;
@@ -228,18 +243,18 @@ static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
return ret;
}
-static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
- struct rtc_wkalrm *alarm)
+static int s5m_check_pending_alarm_interrupt(struct s5m_rtc_info *info,
+ struct rtc_wkalrm *alarm)
{
int ret;
unsigned int val;
switch (info->device_type) {
case S5M8767X:
- case S5M8763X:
ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val);
val &= S5M_ALARM0_STATUS;
break;
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -264,17 +279,9 @@ static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
{
int ret;
- unsigned int data;
-
- ret = regmap_read(info->regmap, info->regs->udr_update, &data);
- if (ret < 0) {
- dev_err(info->dev, "failed to read update reg(%d)\n", ret);
- return ret;
- }
- data |= info->regs->write_time_udr_mask;
-
- ret = regmap_write(info->regmap, info->regs->udr_update, data);
+ ret = regmap_set_bits(info->regmap, info->regs->udr_update,
+ info->regs->write_time_udr_mask);
if (ret < 0) {
dev_err(info->dev, "failed to write update reg(%d)\n", ret);
return ret;
@@ -288,21 +295,14 @@ static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
{
int ret;
- unsigned int data;
+ unsigned int udr_mask;
- ret = regmap_read(info->regmap, info->regs->udr_update, &data);
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to read update reg(%d)\n",
- __func__, ret);
- return ret;
- }
-
- data |= info->regs->write_alarm_udr_mask;
+ udr_mask = info->regs->write_alarm_udr_mask;
switch (info->device_type) {
- case S5M8763X:
case S5M8767X:
- data &= ~S5M_RTC_TIME_EN_MASK;
+ udr_mask |= S5M_RTC_TIME_EN_MASK;
break;
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -312,7 +312,8 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
return -EINVAL;
}
- ret = regmap_write(info->regmap, info->regs->udr_update, data);
+ ret = regmap_update_bits(info->regmap, info->regs->udr_update,
+ udr_mask, info->regs->write_alarm_udr_mask);
if (ret < 0) {
dev_err(info->dev, "%s: fail to write update reg(%d)\n",
__func__, ret);
@@ -323,44 +324,12 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
/* On S2MPS13 the AUDR is not auto-cleared */
if (info->device_type == S2MPS13X)
- regmap_update_bits(info->regmap, info->regs->udr_update,
- S2MPS13_RTC_AUDR_MASK, 0);
+ regmap_clear_bits(info->regmap, info->regs->udr_update,
+ S2MPS13_RTC_AUDR_MASK);
return ret;
}
-static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm)
-{
- tm->tm_sec = bcd2bin(data[RTC_SEC]);
- tm->tm_min = bcd2bin(data[RTC_MIN]);
-
- if (data[RTC_HOUR] & HOUR_12) {
- tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f);
- if (data[RTC_HOUR] & HOUR_PM)
- tm->tm_hour += 12;
- } else {
- tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f);
- }
-
- tm->tm_wday = data[RTC_WEEKDAY] & 0x07;
- tm->tm_mday = bcd2bin(data[RTC_DATE]);
- tm->tm_mon = bcd2bin(data[RTC_MONTH]);
- tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100;
- tm->tm_year -= 1900;
-}
-
-static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data)
-{
- data[RTC_SEC] = bin2bcd(tm->tm_sec);
- data[RTC_MIN] = bin2bcd(tm->tm_min);
- data[RTC_HOUR] = bin2bcd(tm->tm_hour);
- data[RTC_WEEKDAY] = tm->tm_wday;
- data[RTC_DATE] = bin2bcd(tm->tm_mday);
- data[RTC_MONTH] = bin2bcd(tm->tm_mon);
- data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100);
- data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100);
-}
-
static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct s5m_rtc_info *info = dev_get_drvdata(dev);
@@ -368,10 +337,8 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
int ret;
if (info->regs->read_time_udr_mask) {
- ret = regmap_update_bits(info->regmap,
- info->regs->udr_update,
- info->regs->read_time_udr_mask,
- info->regs->read_time_udr_mask);
+ ret = regmap_set_bits(info->regmap, info->regs->udr_update,
+ info->regs->read_time_udr_mask);
if (ret) {
dev_err(dev,
"Failed to prepare registers for time reading: %d\n",
@@ -385,11 +352,8 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
return ret;
switch (info->device_type) {
- case S5M8763X:
- s5m8763_data_to_tm(data, tm);
- break;
-
case S5M8767X:
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -412,10 +376,8 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
int ret = 0;
switch (info->device_type) {
- case S5M8763X:
- s5m8763_tm_to_data(tm, data);
- break;
case S5M8767X:
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -444,7 +406,6 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct s5m_rtc_info *info = dev_get_drvdata(dev);
u8 data[RTC_MAX_NUM_TIME_REGS];
- unsigned int val;
int ret, i;
ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
@@ -453,16 +414,8 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return ret;
switch (info->device_type) {
- case S5M8763X:
- s5m8763_data_to_tm(data, &alrm->time);
- ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val);
- if (ret < 0)
- return ret;
-
- alrm->enabled = !!val;
- break;
-
case S5M8767X:
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -482,7 +435,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday);
- return s5m_check_peding_alarm_interrupt(info, alrm);
+ return s5m_check_pending_alarm_interrupt(info, alrm);
}
static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
@@ -500,11 +453,8 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday);
switch (info->device_type) {
- case S5M8763X:
- ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0);
- break;
-
case S5M8767X:
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -531,7 +481,6 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
{
int ret;
u8 data[RTC_MAX_NUM_TIME_REGS];
- u8 alarm0_conf;
struct rtc_time tm;
ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
@@ -543,12 +492,8 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday);
switch (info->device_type) {
- case S5M8763X:
- alarm0_conf = 0x77;
- ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf);
- break;
-
case S5M8767X:
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -585,11 +530,8 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
int ret;
switch (info->device_type) {
- case S5M8763X:
- s5m8763_tm_to_data(&alrm->time, data);
- break;
-
case S5M8767X:
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -655,7 +597,6 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
int ret;
switch (info->device_type) {
- case S5M8763X:
case S5M8767X:
/* UDR update time. Default of 7.32 ms is too long. */
ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON,
@@ -671,6 +612,7 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2);
break;
+ case S2MPG10:
case S2MPS15X:
case S2MPS14X:
case S2MPS13X:
@@ -693,85 +635,107 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
}
info->rtc_24hr_mode = 1;
- if (ret < 0) {
- dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
- __func__, ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(info->dev, ret,
+ "%s: fail to write controlm reg\n",
+ __func__);
return ret;
}
+static int s5m_rtc_restart_s2mpg10(struct sys_off_data *data)
+{
+ struct s5m_rtc_info *info = data->cb_data;
+ int ret;
+
+ if (data->mode != REBOOT_COLD && data->mode != REBOOT_HARD)
+ return NOTIFY_DONE;
+
+ /*
+ * Arm watchdog with maximum timeout (2 seconds), and perform full reset
+ * on expiry.
+ */
+ ret = regmap_set_bits(info->regmap, S2MPG10_RTC_WTSR,
+ (S2MPG10_WTSR_COLDTIMER | S2MPG10_WTSR_COLDRST
+ | S2MPG10_WTSR_WTSRT | S2MPG10_WTSR_WTSR_EN));
+
+ return ret ? NOTIFY_BAD : NOTIFY_DONE;
+}
+
static int s5m_rtc_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent);
+ enum sec_device_type device_type =
+ platform_get_device_id(pdev)->driver_data;
struct s5m_rtc_info *info;
- const struct regmap_config *regmap_cfg;
int ret, alarm_irq;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- switch (platform_get_device_id(pdev)->driver_data) {
- case S2MPS15X:
- regmap_cfg = &s2mps14_rtc_regmap_config;
- info->regs = &s2mps15_rtc_regs;
- alarm_irq = S2MPS14_IRQ_RTCA0;
- break;
- case S2MPS14X:
- regmap_cfg = &s2mps14_rtc_regmap_config;
- info->regs = &s2mps14_rtc_regs;
- alarm_irq = S2MPS14_IRQ_RTCA0;
- break;
- case S2MPS13X:
- regmap_cfg = &s2mps14_rtc_regmap_config;
- info->regs = &s2mps13_rtc_regs;
- alarm_irq = S2MPS14_IRQ_RTCA0;
- break;
- case S5M8763X:
- regmap_cfg = &s5m_rtc_regmap_config;
- info->regs = &s5m_rtc_regs;
- alarm_irq = S5M8763_IRQ_ALARM0;
- break;
- case S5M8767X:
- regmap_cfg = &s5m_rtc_regmap_config;
- info->regs = &s5m_rtc_regs;
- alarm_irq = S5M8767_IRQ_RTCA1;
- break;
- default:
- dev_err(&pdev->dev,
- "Device type %lu is not supported by RTC driver\n",
- platform_get_device_id(pdev)->driver_data);
- return -ENODEV;
- }
+ info->regmap = dev_get_regmap(pdev->dev.parent, "rtc");
+ if (!info->regmap) {
+ const struct regmap_config *regmap_cfg;
+ struct i2c_client *i2c;
- info->i2c = devm_i2c_new_dummy_device(&pdev->dev, s5m87xx->i2c->adapter,
- RTC_I2C_ADDR);
- if (IS_ERR(info->i2c)) {
- dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n");
- return PTR_ERR(info->i2c);
- }
+ switch (device_type) {
+ case S2MPS15X:
+ regmap_cfg = &s2mps14_rtc_regmap_config;
+ info->regs = &s2mps15_rtc_regs;
+ alarm_irq = S2MPS14_IRQ_RTCA0;
+ break;
+ case S2MPS14X:
+ regmap_cfg = &s2mps14_rtc_regmap_config;
+ info->regs = &s2mps14_rtc_regs;
+ alarm_irq = S2MPS14_IRQ_RTCA0;
+ break;
+ case S2MPS13X:
+ regmap_cfg = &s2mps14_rtc_regmap_config;
+ info->regs = &s2mps13_rtc_regs;
+ alarm_irq = S2MPS14_IRQ_RTCA0;
+ break;
+ case S5M8767X:
+ regmap_cfg = &s5m_rtc_regmap_config;
+ info->regs = &s5m_rtc_regs;
+ alarm_irq = S5M8767_IRQ_RTCA1;
+ break;
+ default:
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "Unsupported device type %d\n",
+ device_type);
+ }
- info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg);
- if (IS_ERR(info->regmap)) {
- ret = PTR_ERR(info->regmap);
- dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n",
- ret);
- return ret;
+ i2c = devm_i2c_new_dummy_device(&pdev->dev,
+ s5m87xx->i2c->adapter,
+ RTC_I2C_ADDR);
+ if (IS_ERR(i2c))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2c),
+ "Failed to allocate I2C\n");
+
+ info->regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
+ if (IS_ERR(info->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(info->regmap),
+ "Failed to allocate regmap\n");
+ } else if (device_type == S2MPG10) {
+ info->regs = &s2mpg10_rtc_regs;
+ alarm_irq = S2MPG10_IRQ_RTCA0;
+ } else {
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "Unsupported device type %d\n",
+ device_type);
}
info->dev = &pdev->dev;
info->s5m87xx = s5m87xx;
- info->device_type = platform_get_device_id(pdev)->driver_data;
+ info->device_type = device_type;
if (s5m87xx->irq_data) {
info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq);
- if (info->irq <= 0) {
- dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
- alarm_irq);
- return -EINVAL;
- }
+ if (info->irq <= 0)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Failed to get virtual IRQ %d\n",
+ alarm_irq);
}
platform_set_drvdata(pdev, info);
@@ -786,13 +750,8 @@ static int s5m_rtc_probe(struct platform_device *pdev)
info->rtc_dev->ops = &s5m_rtc_ops;
- if (info->device_type == S5M8763X) {
- info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_0000;
- info->rtc_dev->range_max = RTC_TIMESTAMP_END_9999;
- } else {
- info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
- info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
- }
+ info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
if (!info->irq) {
clear_bit(RTC_FEATURE_ALARM, info->rtc_dev->features);
@@ -800,12 +759,27 @@ static int s5m_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
s5m_rtc_alarm_irq, 0, "rtc-alarm0",
info);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
- info->irq, ret);
- return ret;
- }
- device_init_wakeup(&pdev->dev, 1);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to request alarm IRQ %d\n",
+ info->irq);
+
+ ret = devm_device_init_wakeup(&pdev->dev);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to init wakeup\n");
+ }
+
+ if (of_device_is_system_power_controller(pdev->dev.parent->of_node) &&
+ info->device_type == S2MPG10) {
+ ret = devm_register_sys_off_handler(&pdev->dev,
+ SYS_OFF_MODE_RESTART,
+ SYS_OFF_PRIO_HIGH + 1,
+ s5m_rtc_restart_s2mpg10,
+ info);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to register restart handler\n");
}
return devm_rtc_register_device(info->rtc_dev);
@@ -839,6 +813,7 @@ static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume);
static const struct platform_device_id s5m_rtc_id[] = {
{ "s5m-rtc", S5M8767X },
+ { "s2mpg10-rtc", S2MPG10 },
{ "s2mps13-rtc", S2MPS13X },
{ "s2mps14-rtc", S2MPS14X },
{ "s2mps15-rtc", S2MPS15X },
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 1250887e4382..1ad93648d69c 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -292,12 +292,12 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, info);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
return sa1100_rtc_init(pdev, info);
}
-static int sa1100_rtc_remove(struct platform_device *pdev)
+static void sa1100_rtc_remove(struct platform_device *pdev)
{
struct sa1100_rtc *info = platform_get_drvdata(pdev);
@@ -307,8 +307,6 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
spin_unlock_irq(&info->lock);
clk_disable_unprepare(info->clk);
}
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c
index ce7a2ddbbc16..2b83561d4d28 100644
--- a/drivers/rtc/rtc-sc27xx.c
+++ b/drivers/rtc/rtc-sc27xx.c
@@ -613,14 +613,14 @@ static int sprd_rtc_probe(struct platform_device *pdev)
return ret;
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
rtc->rtc->ops = &sprd_rtc_ops;
rtc->rtc->range_min = 0;
rtc->rtc->range_max = 5662310399LL;
ret = devm_rtc_register_device(rtc->rtc);
if (ret) {
- device_init_wakeup(&pdev->dev, 0);
+ device_init_wakeup(&pdev->dev, false);
return ret;
}
diff --git a/drivers/rtc/rtc-sd2405al.c b/drivers/rtc/rtc-sd2405al.c
new file mode 100644
index 000000000000..708ea5d964de
--- /dev/null
+++ b/drivers/rtc/rtc-sd2405al.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RTC driver for the SD2405AL Real-Time Clock
+ *
+ * Datasheet:
+ * https://image.dfrobot.com/image/data/TOY0021/SD2405AL%20datasheet%20(Angelo%20v0.1).pdf
+ *
+ * I2C slave address: 0x32
+ *
+ * Copyright (C) 2024-2025 Tóth János <gomba007@gmail.com>
+ */
+
+#include <linux/bcd.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+/* Real time clock registers */
+#define SD2405AL_REG_T_SEC 0x00
+#define SD2405AL_REG_T_MIN 0x01
+#define SD2405AL_REG_T_HOUR 0x02
+# define SD2405AL_BIT_12H_PM BIT(5)
+# define SD2405AL_BIT_24H BIT(7)
+#define SD2405AL_REG_T_WEEK 0x03
+#define SD2405AL_REG_T_DAY 0x04
+#define SD2405AL_REG_T_MON 0x05
+#define SD2405AL_REG_T_YEAR 0x06
+
+#define SD2405AL_NUM_T_REGS (SD2405AL_REG_T_YEAR - SD2405AL_REG_T_SEC + 1)
+
+/* Control registers */
+#define SD2405AL_REG_CTR1 0x0F
+# define SD2405AL_BIT_WRTC2 BIT(2)
+# define SD2405AL_BIT_WRTC3 BIT(7)
+#define SD2405AL_REG_CTR2 0x10
+# define SD2405AL_BIT_WRTC1 BIT(7)
+#define SD2405AL_REG_CTR3 0x11
+#define SD2405AL_REG_TTF 0x12
+#define SD2405AL_REG_CNTDWN 0x13
+
+/* General RAM */
+#define SD2405AL_REG_M_START 0x14
+#define SD2405AL_REG_M_END 0x1F
+
+struct sd2405al {
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+static int sd2405al_enable_reg_write(struct sd2405al *sd2405al)
+{
+ int ret;
+
+ /* order of writes is important */
+ ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR2,
+ SD2405AL_BIT_WRTC1, SD2405AL_BIT_WRTC1);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR1,
+ SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3,
+ SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int sd2405al_disable_reg_write(struct sd2405al *sd2405al)
+{
+ int ret;
+
+ /* order of writes is important */
+ ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR1,
+ SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR2,
+ SD2405AL_BIT_WRTC1, 0x00);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int sd2405al_read_time(struct device *dev, struct rtc_time *time)
+{
+ u8 data[SD2405AL_NUM_T_REGS] = { 0 };
+ struct sd2405al *sd2405al = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_bulk_read(sd2405al->regmap, SD2405AL_REG_T_SEC, data,
+ SD2405AL_NUM_T_REGS);
+ if (ret < 0)
+ return ret;
+
+ time->tm_sec = bcd2bin(data[SD2405AL_REG_T_SEC] & 0x7F);
+ time->tm_min = bcd2bin(data[SD2405AL_REG_T_MIN] & 0x7F);
+
+ if (data[SD2405AL_REG_T_HOUR] & SD2405AL_BIT_24H)
+ time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR] & 0x3F);
+ else
+ if (data[SD2405AL_REG_T_HOUR] & SD2405AL_BIT_12H_PM)
+ time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR]
+ & 0x1F) + 12;
+ else /* 12 hour mode, AM */
+ time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR]
+ & 0x1F);
+
+ time->tm_wday = bcd2bin(data[SD2405AL_REG_T_WEEK] & 0x07);
+ time->tm_mday = bcd2bin(data[SD2405AL_REG_T_DAY] & 0x3F);
+ time->tm_mon = bcd2bin(data[SD2405AL_REG_T_MON] & 0x1F) - 1;
+ time->tm_year = bcd2bin(data[SD2405AL_REG_T_YEAR]) + 100;
+
+ dev_dbg(sd2405al->dev, "read time: %ptR (%d)\n", time, time->tm_wday);
+
+ return 0;
+}
+
+static int sd2405al_set_time(struct device *dev, struct rtc_time *time)
+{
+ u8 data[SD2405AL_NUM_T_REGS];
+ struct sd2405al *sd2405al = dev_get_drvdata(dev);
+ int ret;
+
+ data[SD2405AL_REG_T_SEC] = bin2bcd(time->tm_sec);
+ data[SD2405AL_REG_T_MIN] = bin2bcd(time->tm_min);
+ data[SD2405AL_REG_T_HOUR] = bin2bcd(time->tm_hour) | SD2405AL_BIT_24H;
+ data[SD2405AL_REG_T_DAY] = bin2bcd(time->tm_mday);
+ data[SD2405AL_REG_T_WEEK] = bin2bcd(time->tm_wday);
+ data[SD2405AL_REG_T_MON] = bin2bcd(time->tm_mon) + 1;
+ data[SD2405AL_REG_T_YEAR] = bin2bcd(time->tm_year - 100);
+
+ ret = sd2405al_enable_reg_write(sd2405al);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_bulk_write(sd2405al->regmap, SD2405AL_REG_T_SEC, data,
+ SD2405AL_NUM_T_REGS);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(sd2405al->regmap, SD2405AL_REG_TTF, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = sd2405al_disable_reg_write(sd2405al);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(sd2405al->dev, "set time: %ptR (%d)\n", time, time->tm_wday);
+
+ return 0;
+}
+
+static const struct rtc_class_ops sd2405al_rtc_ops = {
+ .read_time = sd2405al_read_time,
+ .set_time = sd2405al_set_time,
+};
+
+static const struct regmap_config sd2405al_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = SD2405AL_REG_M_END,
+};
+
+static int sd2405al_probe(struct i2c_client *client)
+{
+ struct sd2405al *sd2405al;
+ struct rtc_device *rtc;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ sd2405al = devm_kzalloc(&client->dev, sizeof(*sd2405al), GFP_KERNEL);
+ if (!sd2405al)
+ return -ENOMEM;
+
+ sd2405al->dev = &client->dev;
+
+ sd2405al->regmap = devm_regmap_init_i2c(client, &sd2405al_regmap_conf);
+ if (IS_ERR(sd2405al->regmap))
+ return PTR_ERR(sd2405al->regmap);
+
+ rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ rtc->ops = &sd2405al_rtc_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+ dev_set_drvdata(&client->dev, sd2405al);
+
+ ret = devm_rtc_register_device(rtc);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct i2c_device_id sd2405al_id[] = {
+ { "sd2405al" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, sd2405al_id);
+
+static const __maybe_unused struct of_device_id sd2405al_of_match[] = {
+ { .compatible = "dfrobot,sd2405al" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sd2405al_of_match);
+
+static struct i2c_driver sd2405al_driver = {
+ .driver = {
+ .name = "sd2405al",
+ .of_match_table = of_match_ptr(sd2405al_of_match),
+ },
+ .probe = sd2405al_probe,
+ .id_table = sd2405al_id,
+};
+
+module_i2c_driver(sd2405al_driver);
+
+MODULE_AUTHOR("Tóth János <gomba007@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SD2405AL RTC driver");
diff --git a/drivers/rtc/rtc-sd3078.c b/drivers/rtc/rtc-sd3078.c
index e2f90d768ca8..10cc1dcfc774 100644
--- a/drivers/rtc/rtc-sd3078.c
+++ b/drivers/rtc/rtc-sd3078.c
@@ -36,11 +36,6 @@
*/
#define WRITE_PROTECT_EN 0
-struct sd3078 {
- struct rtc_device *rtc;
- struct regmap *regmap;
-};
-
/*
* In order to prevent arbitrary modification of the time register,
* when modification of the register,
@@ -49,14 +44,11 @@ struct sd3078 {
* 2. set WRITE2 bit
* 3. set WRITE3 bit
*/
-static void sd3078_enable_reg_write(struct sd3078 *sd3078)
+static void sd3078_enable_reg_write(struct regmap *regmap)
{
- regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
- KEY_WRITE1, KEY_WRITE1);
- regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
- KEY_WRITE2, KEY_WRITE2);
- regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
- KEY_WRITE3, KEY_WRITE3);
+ regmap_update_bits(regmap, SD3078_REG_CTRL2, KEY_WRITE1, KEY_WRITE1);
+ regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE2, KEY_WRITE2);
+ regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE3, KEY_WRITE3);
}
#if WRITE_PROTECT_EN
@@ -69,14 +61,11 @@ static void sd3078_enable_reg_write(struct sd3078 *sd3078)
* 2. clear WRITE3 bit
* 3. clear WRITE1 bit
*/
-static void sd3078_disable_reg_write(struct sd3078 *sd3078)
+static void sd3078_disable_reg_write(struct regmap *regmap)
{
- regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
- KEY_WRITE2, 0);
- regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
- KEY_WRITE3, 0);
- regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
- KEY_WRITE1, 0);
+ regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE2, 0);
+ regmap_update_bits(regmap, SD3078_REG_CTRL1, KEY_WRITE3, 0);
+ regmap_update_bits(regmap, SD3078_REG_CTRL2, KEY_WRITE1, 0);
}
#endif
@@ -85,11 +74,10 @@ static int sd3078_rtc_read_time(struct device *dev, struct rtc_time *tm)
unsigned char hour;
unsigned char rtc_data[NUM_TIME_REGS] = {0};
struct i2c_client *client = to_i2c_client(dev);
- struct sd3078 *sd3078 = i2c_get_clientdata(client);
+ struct regmap *regmap = i2c_get_clientdata(client);
int ret;
- ret = regmap_bulk_read(sd3078->regmap, SD3078_REG_SC, rtc_data,
- NUM_TIME_REGS);
+ ret = regmap_bulk_read(regmap, SD3078_REG_SC, rtc_data, NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "reading from RTC failed with err:%d\n", ret);
return ret;
@@ -123,7 +111,7 @@ static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned char rtc_data[NUM_TIME_REGS];
struct i2c_client *client = to_i2c_client(dev);
- struct sd3078 *sd3078 = i2c_get_clientdata(client);
+ struct regmap *regmap = i2c_get_clientdata(client);
int ret;
rtc_data[SD3078_REG_SC] = bin2bcd(tm->tm_sec);
@@ -135,10 +123,10 @@ static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_data[SD3078_REG_YR] = bin2bcd(tm->tm_year - 100);
#if WRITE_PROTECT_EN
- sd3078_enable_reg_write(sd3078);
+ sd3078_enable_reg_write(regmap);
#endif
- ret = regmap_bulk_write(sd3078->regmap, SD3078_REG_SC, rtc_data,
+ ret = regmap_bulk_write(regmap, SD3078_REG_SC, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "writing to RTC failed with err:%d\n", ret);
@@ -146,7 +134,7 @@ static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
}
#if WRITE_PROTECT_EN
- sd3078_disable_reg_write(sd3078);
+ sd3078_disable_reg_write(regmap);
#endif
return 0;
@@ -166,42 +154,39 @@ static const struct regmap_config regmap_config = {
static int sd3078_probe(struct i2c_client *client)
{
int ret;
- struct sd3078 *sd3078;
+ struct regmap *regmap;
+ struct rtc_device *rtc;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- sd3078 = devm_kzalloc(&client->dev, sizeof(*sd3078), GFP_KERNEL);
- if (!sd3078)
- return -ENOMEM;
-
- sd3078->regmap = devm_regmap_init_i2c(client, &regmap_config);
- if (IS_ERR(sd3078->regmap)) {
+ regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(regmap)) {
dev_err(&client->dev, "regmap allocation failed\n");
- return PTR_ERR(sd3078->regmap);
+ return PTR_ERR(regmap);
}
- i2c_set_clientdata(client, sd3078);
+ i2c_set_clientdata(client, regmap);
- sd3078->rtc = devm_rtc_allocate_device(&client->dev);
- if (IS_ERR(sd3078->rtc))
- return PTR_ERR(sd3078->rtc);
+ rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- sd3078->rtc->ops = &sd3078_rtc_ops;
- sd3078->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
- sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099;
+ rtc->ops = &sd3078_rtc_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
- ret = devm_rtc_register_device(sd3078->rtc);
+ ret = devm_rtc_register_device(rtc);
if (ret)
return ret;
- sd3078_enable_reg_write(sd3078);
+ sd3078_enable_reg_write(regmap);
return 0;
}
static const struct i2c_device_id sd3078_id[] = {
- {"sd3078", 0},
+ { "sd3078" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sd3078_id);
@@ -217,7 +202,7 @@ static struct i2c_driver sd3078_driver = {
.name = "sd3078",
.of_match_table = of_match_ptr(rtc_dt_match),
},
- .probe_new = sd3078_probe,
+ .probe = sd3078_probe,
.id_table = sd3078_id,
};
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index cd146b574143..619800a00479 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -5,6 +5,7 @@
* Copyright (C) 2006 - 2009 Paul Mundt
* Copyright (C) 2006 Jamie Lenehan
* Copyright (C) 2008 Angelo Castello
+ * Copyright (C) 2025 Wolfram Sang, Renesas Electronics Corporation
*
* Based on the old arch/sh/kernel/cpu/rtc.c by:
*
@@ -31,7 +32,7 @@
/* Default values for RZ/A RTC */
#define rtc_reg_size sizeof(u16)
#define RTC_BIT_INVERTED 0 /* no chip bugs */
-#define RTC_CAP_4_DIGIT_YEAR (1 << 0)
+#define RTC_CAP_4_DIGIT_YEAR BIT(0)
#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR
#endif
@@ -70,62 +71,35 @@
*/
/* ALARM Bits - or with BCD encoded value */
-#define AR_ENB 0x80 /* Enable for alarm cmp */
-
-/* Period Bits */
-#define PF_HP 0x100 /* Enable Half Period to support 8,32,128Hz */
-#define PF_COUNT 0x200 /* Half periodic counter */
-#define PF_OXS 0x400 /* Periodic One x Second */
-#define PF_KOU 0x800 /* Kernel or User periodic request 1=kernel */
-#define PF_MASK 0xf00
+#define AR_ENB BIT(7) /* Enable for alarm cmp */
/* RCR1 Bits */
-#define RCR1_CF 0x80 /* Carry Flag */
-#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
-#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
-#define RCR1_AF 0x01 /* Alarm Flag */
+#define RCR1_CF BIT(7) /* Carry Flag */
+#define RCR1_CIE BIT(4) /* Carry Interrupt Enable */
+#define RCR1_AIE BIT(3) /* Alarm Interrupt Enable */
+#define RCR1_AF BIT(0) /* Alarm Flag */
/* RCR2 Bits */
-#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
-#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
-#define RCR2_RTCEN 0x08 /* ENable RTC */
-#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
-#define RCR2_RESET 0x02 /* Reset bit */
-#define RCR2_START 0x01 /* Start bit */
+#define RCR2_RTCEN BIT(3) /* ENable RTC */
+#define RCR2_ADJ BIT(2) /* ADJustment (30-second) */
+#define RCR2_RESET BIT(1) /* Reset bit */
+#define RCR2_START BIT(0) /* Start bit */
struct sh_rtc {
void __iomem *regbase;
- unsigned long regsize;
- struct resource *res;
int alarm_irq;
- int periodic_irq;
- int carry_irq;
struct clk *clk;
struct rtc_device *rtc_dev;
- spinlock_t lock;
+ spinlock_t lock; /* protecting register access */
unsigned long capabilities; /* See asm/rtc.h for cap bits */
- unsigned short periodic_freq;
};
-static int __sh_rtc_interrupt(struct sh_rtc *rtc)
+static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
{
+ struct sh_rtc *rtc = dev_id;
unsigned int tmp, pending;
- tmp = readb(rtc->regbase + RCR1);
- pending = tmp & RCR1_CF;
- tmp &= ~RCR1_CF;
- writeb(tmp, rtc->regbase + RCR1);
-
- /* Users have requested One x Second IRQ */
- if (pending && rtc->periodic_freq & PF_OXS)
- rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
-
- return pending;
-}
-
-static int __sh_rtc_alarm(struct sh_rtc *rtc)
-{
- unsigned int tmp, pending;
+ spin_lock(&rtc->lock);
tmp = readb(rtc->regbase + RCR1);
pending = tmp & RCR1_AF;
@@ -135,84 +109,12 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc)
if (pending)
rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
- return pending;
-}
-
-static int __sh_rtc_periodic(struct sh_rtc *rtc)
-{
- unsigned int tmp, pending;
-
- tmp = readb(rtc->regbase + RCR2);
- pending = tmp & RCR2_PEF;
- tmp &= ~RCR2_PEF;
- writeb(tmp, rtc->regbase + RCR2);
-
- if (!pending)
- return 0;
-
- /* Half period enabled than one skipped and the next notified */
- if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT))
- rtc->periodic_freq &= ~PF_COUNT;
- else {
- if (rtc->periodic_freq & PF_HP)
- rtc->periodic_freq |= PF_COUNT;
- rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
- }
-
- return pending;
-}
-
-static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_interrupt(rtc);
- spin_unlock(&rtc->lock);
-
- return IRQ_RETVAL(ret);
-}
-
-static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_alarm(rtc);
spin_unlock(&rtc->lock);
- return IRQ_RETVAL(ret);
+ return IRQ_RETVAL(pending);
}
-static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_periodic(rtc);
- spin_unlock(&rtc->lock);
-
- return IRQ_RETVAL(ret);
-}
-
-static irqreturn_t sh_rtc_shared(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_interrupt(rtc);
- ret |= __sh_rtc_alarm(rtc);
- ret |= __sh_rtc_periodic(rtc);
- spin_unlock(&rtc->lock);
-
- return IRQ_RETVAL(ret);
-}
-
-static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
+static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
unsigned int tmp;
@@ -229,45 +131,7 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
writeb(tmp, rtc->regbase + RCR1);
spin_unlock_irq(&rtc->lock);
-}
-
-static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
-{
- struct sh_rtc *rtc = dev_get_drvdata(dev);
- unsigned int tmp;
-
- tmp = readb(rtc->regbase + RCR1);
- seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" : "no");
-
- tmp = readb(rtc->regbase + RCR2);
- seq_printf(seq, "periodic_IRQ\t: %s\n",
- (tmp & RCR2_PESMASK) ? "yes" : "no");
-
- return 0;
-}
-
-static inline void sh_rtc_setcie(struct device *dev, unsigned int enable)
-{
- struct sh_rtc *rtc = dev_get_drvdata(dev);
- unsigned int tmp;
-
- spin_lock_irq(&rtc->lock);
-
- tmp = readb(rtc->regbase + RCR1);
-
- if (!enable)
- tmp &= ~RCR1_CIE;
- else
- tmp |= RCR1_CIE;
-
- writeb(tmp, rtc->regbase + RCR1);
-
- spin_unlock_irq(&rtc->lock);
-}
-static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
-{
- sh_rtc_setaie(dev, enabled);
return 0;
}
@@ -320,14 +184,8 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_sec--;
#endif
- /* only keep the carry interrupt enabled if UIE is on */
- if (!(rtc->periodic_freq & PF_OXS))
- sh_rtc_setcie(dev, 0);
-
- dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
- "mday=%d, mon=%d, year=%d, wday=%d\n",
- __func__,
- tm->tm_sec, tm->tm_min, tm->tm_hour,
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ __func__, tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
return 0;
@@ -461,16 +319,17 @@ static const struct rtc_class_ops sh_rtc_ops = {
.set_time = sh_rtc_set_time,
.read_alarm = sh_rtc_read_alarm,
.set_alarm = sh_rtc_set_alarm,
- .proc = sh_rtc_proc,
.alarm_irq_enable = sh_rtc_alarm_irq_enable,
};
static int __init sh_rtc_probe(struct platform_device *pdev)
{
struct sh_rtc *rtc;
- struct resource *res;
- char clk_name[6];
+ struct resource *res, *req_res;
+ char clk_name[14];
int clk_id, ret;
+ unsigned int tmp;
+ resource_size_t regsize;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (unlikely(!rtc))
@@ -478,34 +337,32 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
spin_lock_init(&rtc->lock);
- /* get periodic/carry/alarm irqs */
ret = platform_get_irq(pdev, 0);
if (unlikely(ret <= 0)) {
dev_err(&pdev->dev, "No IRQ resource\n");
return -ENOENT;
}
- rtc->periodic_irq = ret;
- rtc->carry_irq = platform_get_irq(pdev, 1);
- rtc->alarm_irq = platform_get_irq(pdev, 2);
+ if (!pdev->dev.of_node)
+ rtc->alarm_irq = platform_get_irq(pdev, 2);
+ else
+ rtc->alarm_irq = ret;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(res == NULL)) {
+ if (!res) {
dev_err(&pdev->dev, "No IO resource\n");
return -ENOENT;
}
- rtc->regsize = resource_size(res);
-
- rtc->res = devm_request_mem_region(&pdev->dev, res->start,
- rtc->regsize, pdev->name);
- if (unlikely(!rtc->res))
+ regsize = resource_size(res);
+ req_res = devm_request_mem_region(&pdev->dev, res->start, regsize, pdev->name);
+ if (!req_res)
return -EBUSY;
- rtc->regbase = devm_ioremap(&pdev->dev, rtc->res->start, rtc->regsize);
- if (unlikely(!rtc->regbase))
+ rtc->regbase = devm_ioremap(&pdev->dev, req_res->start, regsize);
+ if (!rtc->regbase)
return -EINVAL;
if (!pdev->dev.of_node) {
@@ -515,8 +372,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
clk_id = 0;
snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id);
- } else
+ } else {
snprintf(clk_name, sizeof(clk_name), "fck");
+ }
rtc->clk = devm_clk_get(&pdev->dev, clk_name);
if (IS_ERR(rtc->clk)) {
@@ -550,51 +408,19 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
}
#endif
- if (rtc->carry_irq <= 0) {
- /* register shared periodic/carry/alarm irq */
- ret = devm_request_irq(&pdev->dev, rtc->periodic_irq,
- sh_rtc_shared, 0, "sh-rtc", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request IRQ failed with %d, IRQ %d\n", ret,
- rtc->periodic_irq);
- goto err_unmap;
- }
- } else {
- /* register periodic/carry/alarm irqs */
- ret = devm_request_irq(&pdev->dev, rtc->periodic_irq,
- sh_rtc_periodic, 0, "sh-rtc period", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request period IRQ failed with %d, IRQ %d\n",
- ret, rtc->periodic_irq);
- goto err_unmap;
- }
-
- ret = devm_request_irq(&pdev->dev, rtc->carry_irq,
- sh_rtc_interrupt, 0, "sh-rtc carry", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request carry IRQ failed with %d, IRQ %d\n",
- ret, rtc->carry_irq);
- goto err_unmap;
- }
-
- ret = devm_request_irq(&pdev->dev, rtc->alarm_irq,
- sh_rtc_alarm, 0, "sh-rtc alarm", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request alarm IRQ failed with %d, IRQ %d\n",
- ret, rtc->alarm_irq);
- goto err_unmap;
- }
+ ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, sh_rtc_alarm, 0, "sh-rtc", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "request alarm IRQ failed with %d, IRQ %d\n",
+ ret, rtc->alarm_irq);
+ goto err_unmap;
}
platform_set_drvdata(pdev, rtc);
/* everything disabled by default */
- sh_rtc_setaie(&pdev->dev, 0);
- sh_rtc_setcie(&pdev->dev, 0);
+ tmp = readb(rtc->regbase + RCR1);
+ tmp &= ~(RCR1_CIE | RCR1_AIE);
+ writeb(tmp, rtc->regbase + RCR1);
rtc->rtc_dev->ops = &sh_rtc_ops;
rtc->rtc_dev->max_user_freq = 256;
@@ -611,7 +437,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
if (ret)
goto err_unmap;
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
return 0;
err_unmap:
@@ -620,47 +446,36 @@ err_unmap:
return ret;
}
-static int __exit sh_rtc_remove(struct platform_device *pdev)
+static void __exit sh_rtc_remove(struct platform_device *pdev)
{
struct sh_rtc *rtc = platform_get_drvdata(pdev);
- sh_rtc_setaie(&pdev->dev, 0);
- sh_rtc_setcie(&pdev->dev, 0);
+ sh_rtc_alarm_irq_enable(&pdev->dev, 0);
clk_disable(rtc->clk);
-
- return 0;
}
-static void sh_rtc_set_irq_wake(struct device *dev, int enabled)
+static int sh_rtc_suspend(struct device *dev)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
- irq_set_irq_wake(rtc->periodic_irq, enabled);
-
- if (rtc->carry_irq > 0) {
- irq_set_irq_wake(rtc->carry_irq, enabled);
- irq_set_irq_wake(rtc->alarm_irq, enabled);
- }
-}
-
-static int __maybe_unused sh_rtc_suspend(struct device *dev)
-{
if (device_may_wakeup(dev))
- sh_rtc_set_irq_wake(dev, 1);
+ irq_set_irq_wake(rtc->alarm_irq, 1);
return 0;
}
-static int __maybe_unused sh_rtc_resume(struct device *dev)
+static int sh_rtc_resume(struct device *dev)
{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+
if (device_may_wakeup(dev))
- sh_rtc_set_irq_wake(dev, 0);
+ irq_set_irq_wake(rtc->alarm_irq, 0);
return 0;
}
-static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume);
static const struct of_device_id sh_rtc_of_match[] = {
{ .compatible = "renesas,sh-rtc", },
@@ -668,10 +483,16 @@ static const struct of_device_id sh_rtc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sh_rtc_of_match);
-static struct platform_driver sh_rtc_platform_driver = {
+/*
+ * sh_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver sh_rtc_platform_driver __refdata = {
.driver = {
.name = DRV_NAME,
- .pm = &sh_rtc_pm_ops,
+ .pm = pm_sleep_ptr(&sh_rtc_pm_ops),
.of_match_table = sh_rtc_of_match,
},
.remove = __exit_p(sh_rtc_remove),
@@ -680,8 +501,8 @@ static struct platform_driver sh_rtc_platform_driver = {
module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe);
MODULE_DESCRIPTION("SuperH on-chip RTC driver");
-MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, "
- "Jamie Lenehan <lenehan@twibble.org>, "
- "Angelo Castello <angelo.castello@st.com>");
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_AUTHOR("Jamie Lenehan <lenehan@twibble.org>");
+MODULE_AUTHOR("Angelo Castello <angelo.castello@st.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/rtc/rtc-spacemit-p1.c b/drivers/rtc/rtc-spacemit-p1.c
new file mode 100644
index 000000000000..43ab62494bb4
--- /dev/null
+++ b/drivers/rtc/rtc-spacemit-p1.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the RTC found in the SpacemiT P1 PMIC
+ *
+ * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved.
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define MOD_NAME "spacemit-p1-rtc"
+
+/*
+ * Six consecutive 1-byte registers hold the seconds, minutes, hours,
+ * day-of-month, month, and year (respectively).
+ *
+ * The range of values in these registers is:
+ * seconds 0-59
+ * minutes 0-59
+ * hours 0-59
+ * day 0-30 (struct tm is 1-31)
+ * month 0-11
+ * year years since 2000 (struct tm is since 1900)
+ *
+ * Note that the day and month must be converted after reading and
+ * before writing.
+ */
+#define RTC_TIME 0x0d /* Offset of the seconds register */
+
+#define RTC_CTRL 0x1d
+#define RTC_EN BIT(2)
+
+/* Number of attempts to read a consistent time stamp before giving up */
+#define RTC_READ_TRIES 20 /* At least 1 */
+
+struct p1_rtc {
+ struct regmap *regmap;
+ struct rtc_device *rtc;
+};
+
+/*
+ * The P1 hardware documentation states that the register values are
+ * latched to ensure a consistent time snapshot within the registers,
+ * but these are in fact unstable due to a bug in the hardware design.
+ * So we loop until we get two identical readings.
+ */
+static int p1_rtc_read_time(struct device *dev, struct rtc_time *t)
+{
+ struct p1_rtc *p1 = dev_get_drvdata(dev);
+ struct regmap *regmap = p1->regmap;
+ u32 count = RTC_READ_TRIES;
+ u8 seconds;
+ u8 time[6];
+ int ret;
+
+ if (!regmap_test_bits(regmap, RTC_CTRL, RTC_EN))
+ return -EINVAL; /* RTC is disabled */
+
+ ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time));
+ if (ret)
+ return ret;
+
+ do {
+ seconds = time[0];
+ ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time));
+ if (ret)
+ return ret;
+ } while (time[0] != seconds && --count);
+
+ if (!count)
+ return -EIO; /* Unable to get a consistent result */
+
+ t->tm_sec = time[0] & GENMASK(5, 0);
+ t->tm_min = time[1] & GENMASK(5, 0);
+ t->tm_hour = time[2] & GENMASK(4, 0);
+ t->tm_mday = (time[3] & GENMASK(4, 0)) + 1;
+ t->tm_mon = time[4] & GENMASK(3, 0);
+ t->tm_year = (time[5] & GENMASK(5, 0)) + 100;
+
+ return 0;
+}
+
+/*
+ * The P1 hardware documentation states that values in the registers are
+ * latched so when written they represent a consistent time snapshot.
+ * Nevertheless, this is not guaranteed by the implementation, so we must
+ * disable the RTC while updating it.
+ */
+static int p1_rtc_set_time(struct device *dev, struct rtc_time *t)
+{
+ struct p1_rtc *p1 = dev_get_drvdata(dev);
+ struct regmap *regmap = p1->regmap;
+ u8 time[6];
+ int ret;
+
+ time[0] = t->tm_sec;
+ time[1] = t->tm_min;
+ time[2] = t->tm_hour;
+ time[3] = t->tm_mday - 1;
+ time[4] = t->tm_mon;
+ time[5] = t->tm_year - 100;
+
+ /* Disable the RTC to update; re-enable again when done */
+ ret = regmap_clear_bits(regmap, RTC_CTRL, RTC_EN);
+ if (ret)
+ return ret;
+
+ /* If something goes wrong, leave the RTC disabled */
+ ret = regmap_bulk_write(regmap, RTC_TIME, time, sizeof(time));
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(regmap, RTC_CTRL, RTC_EN);
+}
+
+static const struct rtc_class_ops p1_rtc_class_ops = {
+ .read_time = p1_rtc_read_time,
+ .set_time = p1_rtc_set_time,
+};
+
+static int p1_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtc_device *rtc;
+ struct p1_rtc *p1;
+
+ p1 = devm_kzalloc(dev, sizeof(*p1), GFP_KERNEL);
+ if (!p1)
+ return -ENOMEM;
+ dev_set_drvdata(dev, p1);
+
+ p1->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!p1->regmap)
+ return dev_err_probe(dev, -ENODEV, "failed to get regmap\n");
+
+ rtc = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc))
+ return dev_err_probe(dev, PTR_ERR(rtc),
+ "error allocating device\n");
+ p1->rtc = rtc;
+
+ rtc->ops = &p1_rtc_class_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2063;
+
+ clear_bit(RTC_FEATURE_ALARM, rtc->features);
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
+
+ return devm_rtc_register_device(rtc);
+}
+
+static struct platform_driver p1_rtc_driver = {
+ .probe = p1_rtc_probe,
+ .driver = {
+ .name = MOD_NAME,
+ },
+};
+
+module_platform_driver(p1_rtc_driver);
+
+MODULE_DESCRIPTION("SpacemiT P1 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MOD_NAME);
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index 736fe535cd45..959acff8faff 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -395,7 +395,7 @@ static int spear_rtc_probe(struct platform_device *pdev)
goto err_disable_clock;
if (!device_can_wakeup(&pdev->dev))
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
return 0;
@@ -405,15 +405,13 @@ err_disable_clock:
return status;
}
-static int spear_rtc_remove(struct platform_device *pdev)
+static void spear_rtc_remove(struct platform_device *pdev)
{
struct spear_rtc_config *config = platform_get_drvdata(pdev);
spear_rtc_disable_interrupt(config);
clk_disable_unprepare(config->clk);
- device_init_wakeup(&pdev->dev, 0);
-
- return 0;
+ device_init_wakeup(&pdev->dev, false);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-ssd202d.c b/drivers/rtc/rtc-ssd202d.c
new file mode 100644
index 000000000000..ed6493260096
--- /dev/null
+++ b/drivers/rtc/rtc-ssd202d.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Real time clocks driver for MStar/SigmaStar SSD202D SoCs.
+ *
+ * (C) 2021 Daniel Palmer
+ * (C) 2023 Romain Perier
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/regmap.h>
+#include <linux/pm.h>
+
+#define REG_CTRL 0x0
+#define REG_CTRL1 0x4
+#define REG_ISO_CTRL 0xc
+#define REG_WRDATA_L 0x10
+#define REG_WRDATA_H 0x14
+#define REG_ISOACK 0x20
+#define REG_RDDATA_L 0x24
+#define REG_RDDATA_H 0x28
+#define REG_RDCNT_L 0x30
+#define REG_RDCNT_H 0x34
+#define REG_CNT_TRIG 0x38
+#define REG_PWRCTRL 0x3c
+#define REG_RTC_TEST 0x54
+
+#define CNT_RD_TRIG_BIT BIT(0)
+#define CNT_RD_BIT BIT(0)
+#define BASE_WR_BIT BIT(1)
+#define BASE_RD_BIT BIT(2)
+#define CNT_RST_BIT BIT(3)
+#define ISO_CTRL_ACK_MASK BIT(3)
+#define ISO_CTRL_ACK_SHIFT 3
+#define SW0_WR_BIT BIT(5)
+#define SW1_WR_BIT BIT(6)
+#define SW0_RD_BIT BIT(7)
+#define SW1_RD_BIT BIT(8)
+
+#define ISO_CTRL_MASK GENMASK(2, 0)
+
+struct ssd202d_rtc {
+ struct rtc_device *rtc_dev;
+ void __iomem *base;
+};
+
+static u8 read_iso_en(void __iomem *base)
+{
+ return readb(base + REG_RTC_TEST) & 0x1;
+}
+
+static u8 read_iso_ctrl_ack(void __iomem *base)
+{
+ return (readb(base + REG_ISOACK) & ISO_CTRL_ACK_MASK) >> ISO_CTRL_ACK_SHIFT;
+}
+
+static int ssd202d_rtc_isoctrl(struct ssd202d_rtc *priv)
+{
+ static const unsigned int sequence[] = { 0x0, 0x1, 0x3, 0x7, 0x5, 0x1, 0x0 };
+ unsigned int val;
+ struct device *dev = &priv->rtc_dev->dev;
+ int i, ret;
+
+ /*
+ * This gates iso_en by writing a special sequence of bytes to iso_ctrl
+ * and ensuring that it has been correctly applied by reading iso_ctrl_ack
+ */
+ for (i = 0; i < ARRAY_SIZE(sequence); i++) {
+ writeb(sequence[i] & ISO_CTRL_MASK, priv->base + REG_ISO_CTRL);
+
+ ret = read_poll_timeout(read_iso_ctrl_ack, val, val == (i % 2), 100,
+ 20 * 100, true, priv->base);
+ if (ret) {
+ dev_dbg(dev, "Timeout waiting for ack byte %i (%x) of sequence\n", i,
+ sequence[i]);
+ return ret;
+ }
+ }
+
+ /*
+ * At this point iso_en should be raised for 1ms
+ */
+ ret = read_poll_timeout(read_iso_en, val, val, 100, 22 * 100, true, priv->base);
+ if (ret)
+ dev_dbg(dev, "Timeout waiting for iso_en\n");
+ mdelay(2);
+ return 0;
+}
+
+static void ssd202d_rtc_read_reg(struct ssd202d_rtc *priv, unsigned int reg,
+ unsigned int field, unsigned int *base)
+{
+ unsigned int l, h;
+ u16 val;
+
+ /* Ask for the content of an RTC value into RDDATA by gating iso_en,
+ * then iso_en is gated and the content of RDDATA can be read
+ */
+ val = readw(priv->base + reg);
+ writew(val | field, priv->base + reg);
+ ssd202d_rtc_isoctrl(priv);
+ writew(val & ~field, priv->base + reg);
+
+ l = readw(priv->base + REG_RDDATA_L);
+ h = readw(priv->base + REG_RDDATA_H);
+
+ *base = (h << 16) | l;
+}
+
+static void ssd202d_rtc_write_reg(struct ssd202d_rtc *priv, unsigned int reg,
+ unsigned int field, u32 base)
+{
+ u16 val;
+
+ /* Set the content of an RTC value from WRDATA by gating iso_en */
+ val = readw(priv->base + reg);
+ writew(val | field, priv->base + reg);
+ writew(base, priv->base + REG_WRDATA_L);
+ writew(base >> 16, priv->base + REG_WRDATA_H);
+ ssd202d_rtc_isoctrl(priv);
+ writew(val & ~field, priv->base + reg);
+}
+
+static int ssd202d_rtc_read_counter(struct ssd202d_rtc *priv, unsigned int *counter)
+{
+ unsigned int l, h;
+ u16 val;
+
+ val = readw(priv->base + REG_CTRL1);
+ writew(val | CNT_RD_BIT, priv->base + REG_CTRL1);
+ ssd202d_rtc_isoctrl(priv);
+ writew(val & ~CNT_RD_BIT, priv->base + REG_CTRL1);
+
+ val = readw(priv->base + REG_CTRL1);
+ writew(val | CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG);
+ writew(val & ~CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG);
+
+ l = readw(priv->base + REG_RDCNT_L);
+ h = readw(priv->base + REG_RDCNT_H);
+
+ *counter = (h << 16) | l;
+
+ return 0;
+}
+
+static int ssd202d_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ssd202d_rtc *priv = dev_get_drvdata(dev);
+ unsigned int sw0, base, counter;
+ u32 seconds;
+ int ret;
+
+ /* Check that RTC is enabled by SW */
+ ssd202d_rtc_read_reg(priv, REG_CTRL, SW0_RD_BIT, &sw0);
+ if (sw0 != 1)
+ return -EINVAL;
+
+ /* Get RTC base value from RDDATA */
+ ssd202d_rtc_read_reg(priv, REG_CTRL, BASE_RD_BIT, &base);
+ /* Get RTC counter value from RDDATA */
+ ret = ssd202d_rtc_read_counter(priv, &counter);
+ if (ret)
+ return ret;
+
+ seconds = base + counter;
+
+ rtc_time64_to_tm(seconds, tm);
+
+ return 0;
+}
+
+static int ssd202d_rtc_reset_counter(struct ssd202d_rtc *priv)
+{
+ u16 val;
+
+ val = readw(priv->base + REG_CTRL);
+ writew(val | CNT_RST_BIT, priv->base + REG_CTRL);
+ ssd202d_rtc_isoctrl(priv);
+ writew(val & ~CNT_RST_BIT, priv->base + REG_CTRL);
+ ssd202d_rtc_isoctrl(priv);
+
+ return 0;
+}
+
+static int ssd202d_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ssd202d_rtc *priv = dev_get_drvdata(dev);
+ unsigned long seconds = rtc_tm_to_time64(tm);
+
+ ssd202d_rtc_write_reg(priv, REG_CTRL, BASE_WR_BIT, seconds);
+ ssd202d_rtc_reset_counter(priv);
+ ssd202d_rtc_write_reg(priv, REG_CTRL, SW0_WR_BIT, 1);
+
+ return 0;
+}
+
+static const struct rtc_class_ops ssd202d_rtc_ops = {
+ .read_time = ssd202d_rtc_read_time,
+ .set_time = ssd202d_rtc_set_time,
+};
+
+static int ssd202d_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ssd202d_rtc *priv;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct ssd202d_rtc), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->rtc_dev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(priv->rtc_dev))
+ return PTR_ERR(priv->rtc_dev);
+
+ priv->rtc_dev->ops = &ssd202d_rtc_ops;
+ priv->rtc_dev->range_max = U32_MAX;
+
+ platform_set_drvdata(pdev, priv);
+
+ return devm_rtc_register_device(priv->rtc_dev);
+}
+
+static const struct of_device_id ssd202d_rtc_of_match_table[] = {
+ { .compatible = "mstar,ssd202d-rtc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ssd202d_rtc_of_match_table);
+
+static struct platform_driver ssd202d_rtc_driver = {
+ .probe = ssd202d_rtc_probe,
+ .driver = {
+ .name = "ssd202d-rtc",
+ .of_match_table = ssd202d_rtc_of_match_table,
+ },
+};
+module_platform_driver(ssd202d_rtc_driver);
+
+MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
+MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
+MODULE_DESCRIPTION("MStar SSD202D RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c
index 0f8e4231098e..c6d4522411b3 100644
--- a/drivers/rtc/rtc-st-lpc.c
+++ b/drivers/rtc/rtc-st-lpc.c
@@ -218,27 +218,22 @@ static int st_rtc_probe(struct platform_device *pdev)
return -EINVAL;
}
- ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler, 0,
- pdev->name, rtc);
+ ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler,
+ IRQF_NO_AUTOEN, pdev->name, rtc);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq);
return ret;
}
enable_irq_wake(rtc->irq);
- disable_irq(rtc->irq);
- rtc->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(rtc->clk)) {
- dev_err(&pdev->dev, "Unable to request clock\n");
- return PTR_ERR(rtc->clk);
- }
-
- clk_prepare_enable(rtc->clk);
+ rtc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(rtc->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->clk),
+ "Unable to request clock\n");
rtc->clkrate = clk_get_rate(rtc->clk);
if (!rtc->clkrate) {
- clk_disable_unprepare(rtc->clk);
dev_err(&pdev->dev, "Unable to fetch clock rate\n");
return -EINVAL;
}
@@ -252,10 +247,8 @@ static int st_rtc_probe(struct platform_device *pdev)
do_div(rtc->rtc_dev->range_max, rtc->clkrate);
ret = devm_rtc_register_device(rtc->rtc_dev);
- if (ret) {
- clk_disable_unprepare(rtc->clk);
+ if (ret)
return ret;
- }
return 0;
}
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index ac9e228b56d0..d4ebf3eb54aa 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -5,12 +5,19 @@
*/
#include <linux/bcd.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/errno.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
@@ -39,6 +46,12 @@
#define STM32_RTC_CR_FMT BIT(6)
#define STM32_RTC_CR_ALRAE BIT(8)
#define STM32_RTC_CR_ALRAIE BIT(12)
+#define STM32_RTC_CR_OSEL GENMASK(22, 21)
+#define STM32_RTC_CR_OSEL_ALARM_A FIELD_PREP(STM32_RTC_CR_OSEL, 0x01)
+#define STM32_RTC_CR_COE BIT(23)
+#define STM32_RTC_CR_TAMPOE BIT(26)
+#define STM32_RTC_CR_TAMPALRM_TYPE BIT(30)
+#define STM32_RTC_CR_OUT2EN BIT(31)
/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
#define STM32_RTC_ISR_ALRAWF BIT(0)
@@ -75,12 +88,30 @@
/* STM32_RTC_SR/_SCR bit fields */
#define STM32_RTC_SR_ALRA BIT(0)
+/* STM32_RTC_CFGR bit fields */
+#define STM32_RTC_CFGR_OUT2_RMP BIT(0)
+#define STM32_RTC_CFGR_LSCOEN GENMASK(2, 1)
+#define STM32_RTC_CFGR_LSCOEN_OUT1 1
+#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2
+
/* STM32_RTC_VERR bit fields */
#define STM32_RTC_VERR_MINREV_SHIFT 0
#define STM32_RTC_VERR_MINREV GENMASK(3, 0)
#define STM32_RTC_VERR_MAJREV_SHIFT 4
#define STM32_RTC_VERR_MAJREV GENMASK(7, 4)
+/* STM32_RTC_SECCFGR bit fields */
+#define STM32_RTC_SECCFGR 0x20
+#define STM32_RTC_SECCFGR_ALRA_SEC BIT(0)
+#define STM32_RTC_SECCFGR_INIT_SEC BIT(14)
+#define STM32_RTC_SECCFGR_SEC BIT(15)
+
+/* STM32_RTC_RXCIDCFGR bit fields */
+#define STM32_RTC_RXCIDCFGR(x) (0x80 + 0x4 * (x))
+#define STM32_RTC_RXCIDCFGR_CFEN BIT(0)
+#define STM32_RTC_RXCIDCFGR_CID GENMASK(6, 4)
+#define STM32_RTC_RXCIDCFGR_CID1 1
+
/* STM32_RTC_WPR key constants */
#define RTC_WPR_1ST_KEY 0xCA
#define RTC_WPR_2ND_KEY 0x53
@@ -89,6 +120,17 @@
/* Max STM32 RTC register offset is 0x3FC */
#define UNDEF_REG 0xFFFF
+/* STM32 RTC driver time helpers */
+#define SEC_PER_DAY (24 * 60 * 60)
+
+/* STM32 RTC pinctrl helpers */
+#define STM32_RTC_PINMUX(_name, _action, ...) { \
+ .name = (_name), \
+ .action = (_action), \
+ .groups = ((const char *[]){ __VA_ARGS__ }), \
+ .num_groups = ARRAY_SIZE(((const char *[]){ __VA_ARGS__ })), \
+}
+
struct stm32_rtc;
struct stm32_rtc_registers {
@@ -101,6 +143,7 @@ struct stm32_rtc_registers {
u16 wpr;
u16 sr;
u16 scr;
+ u16 cfgr;
u16 verr;
};
@@ -114,7 +157,10 @@ struct stm32_rtc_data {
void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags);
bool has_pclk;
bool need_dbp;
- bool has_wakeirq;
+ bool need_accuracy;
+ bool rif_protected;
+ bool has_lsco;
+ bool has_alarm_out;
};
struct stm32_rtc {
@@ -127,9 +173,17 @@ struct stm32_rtc {
struct clk *rtc_ck;
const struct stm32_rtc_data *data;
int irq_alarm;
- int wakeirq_alarm;
+ struct clk *clk_lsco;
};
+struct stm32_rtc_rif_resource {
+ unsigned int num;
+ u32 bit;
+};
+
+static const struct stm32_rtc_rif_resource STM32_RTC_RES_ALRA = {0, STM32_RTC_SECCFGR_ALRA_SEC};
+static const struct stm32_rtc_rif_resource STM32_RTC_RES_INIT = {5, STM32_RTC_SECCFGR_INIT_SEC};
+
static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
{
const struct stm32_rtc_registers *regs = &rtc->data->regs;
@@ -145,6 +199,209 @@ static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + regs->wpr);
}
+enum stm32_rtc_pin_name {
+ NONE,
+ OUT1,
+ OUT2,
+ OUT2_RMP
+};
+
+static const struct pinctrl_pin_desc stm32_rtc_pinctrl_pins[] = {
+ PINCTRL_PIN(OUT1, "out1"),
+ PINCTRL_PIN(OUT2, "out2"),
+ PINCTRL_PIN(OUT2_RMP, "out2_rmp"),
+};
+
+static int stm32_rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(stm32_rtc_pinctrl_pins);
+}
+
+static const char *stm32_rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ return stm32_rtc_pinctrl_pins[selector].name;
+}
+
+static int stm32_rtc_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ *pins = &stm32_rtc_pinctrl_pins[selector].number;
+ *num_pins = 1;
+ return 0;
+}
+
+static const struct pinctrl_ops stm32_rtc_pinctrl_ops = {
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinconf_generic_dt_free_map,
+ .get_groups_count = stm32_rtc_pinctrl_get_groups_count,
+ .get_group_name = stm32_rtc_pinctrl_get_group_name,
+ .get_group_pins = stm32_rtc_pinctrl_get_group_pins,
+};
+
+struct stm32_rtc_pinmux_func {
+ const char *name;
+ const char * const *groups;
+ const unsigned int num_groups;
+ int (*action)(struct pinctrl_dev *pctl_dev, unsigned int pin);
+};
+
+static int stm32_rtc_pinmux_action_alarm(struct pinctrl_dev *pctldev, unsigned int pin)
+{
+ struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
+ struct stm32_rtc_registers regs = rtc->data->regs;
+ unsigned int cr = readl_relaxed(rtc->base + regs.cr);
+ unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
+
+ if (!rtc->data->has_alarm_out)
+ return -EPERM;
+
+ cr &= ~STM32_RTC_CR_OSEL;
+ cr |= STM32_RTC_CR_OSEL_ALARM_A;
+ cr &= ~STM32_RTC_CR_TAMPOE;
+ cr &= ~STM32_RTC_CR_COE;
+ cr &= ~STM32_RTC_CR_TAMPALRM_TYPE;
+
+ switch (pin) {
+ case OUT1:
+ cr &= ~STM32_RTC_CR_OUT2EN;
+ cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
+ break;
+ case OUT2:
+ cr |= STM32_RTC_CR_OUT2EN;
+ cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
+ break;
+ case OUT2_RMP:
+ cr |= STM32_RTC_CR_OUT2EN;
+ cfgr |= STM32_RTC_CFGR_OUT2_RMP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ stm32_rtc_wpr_unlock(rtc);
+ writel_relaxed(cr, rtc->base + regs.cr);
+ writel_relaxed(cfgr, rtc->base + regs.cfgr);
+ stm32_rtc_wpr_lock(rtc);
+
+ return 0;
+}
+
+static int stm32_rtc_pinmux_lsco_available(struct pinctrl_dev *pctldev, unsigned int pin)
+{
+ struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
+ struct stm32_rtc_registers regs = rtc->data->regs;
+ unsigned int cr = readl_relaxed(rtc->base + regs.cr);
+ unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
+ unsigned int calib = STM32_RTC_CR_COE;
+ unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL;
+
+ switch (pin) {
+ case OUT1:
+ if ((!(cr & STM32_RTC_CR_OUT2EN) &&
+ ((cr & calib) || cr & tampalrm)) ||
+ ((cr & calib) && (cr & tampalrm)))
+ return -EBUSY;
+ break;
+ case OUT2_RMP:
+ if ((cr & STM32_RTC_CR_OUT2EN) &&
+ (cfgr & STM32_RTC_CFGR_OUT2_RMP) &&
+ ((cr & calib) || (cr & tampalrm)))
+ return -EBUSY;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (clk_get_rate(rtc->rtc_ck) != 32768)
+ return -ERANGE;
+
+ return 0;
+}
+
+static int stm32_rtc_pinmux_action_lsco(struct pinctrl_dev *pctldev, unsigned int pin)
+{
+ struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
+ struct stm32_rtc_registers regs = rtc->data->regs;
+ struct device *dev = rtc->rtc_dev->dev.parent;
+ u8 lscoen;
+ int ret;
+
+ if (!rtc->data->has_lsco)
+ return -EPERM;
+
+ ret = stm32_rtc_pinmux_lsco_available(pctldev, pin);
+ if (ret)
+ return ret;
+
+ lscoen = (pin == OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : STM32_RTC_CFGR_LSCOEN_OUT2_RMP;
+
+ rtc->clk_lsco = clk_register_gate(dev, "rtc_lsco", __clk_get_name(rtc->rtc_ck),
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ rtc->base + regs.cfgr, lscoen, 0, NULL);
+ if (IS_ERR(rtc->clk_lsco))
+ return PTR_ERR(rtc->clk_lsco);
+
+ of_clk_add_provider(dev->of_node, of_clk_src_simple_get, rtc->clk_lsco);
+
+ return 0;
+}
+
+static const struct stm32_rtc_pinmux_func stm32_rtc_pinmux_functions[] = {
+ STM32_RTC_PINMUX("lsco", &stm32_rtc_pinmux_action_lsco, "out1", "out2_rmp"),
+ STM32_RTC_PINMUX("alarm-a", &stm32_rtc_pinmux_action_alarm, "out1", "out2", "out2_rmp"),
+};
+
+static int stm32_rtc_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(stm32_rtc_pinmux_functions);
+}
+
+static const char *stm32_rtc_pinmux_get_fname(struct pinctrl_dev *pctldev, unsigned int selector)
+{
+ return stm32_rtc_pinmux_functions[selector].name;
+}
+
+static int stm32_rtc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned int selector,
+ const char * const **groups, unsigned int * const num_groups)
+{
+ *groups = stm32_rtc_pinmux_functions[selector].groups;
+ *num_groups = stm32_rtc_pinmux_functions[selector].num_groups;
+ return 0;
+}
+
+static int stm32_rtc_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
+ unsigned int group)
+{
+ struct stm32_rtc_pinmux_func selected_func = stm32_rtc_pinmux_functions[selector];
+ struct pinctrl_pin_desc pin = stm32_rtc_pinctrl_pins[group];
+
+ /* Call action */
+ if (selected_func.action)
+ return selected_func.action(pctldev, pin.number);
+
+ return -EINVAL;
+}
+
+static const struct pinmux_ops stm32_rtc_pinmux_ops = {
+ .get_functions_count = stm32_rtc_pinmux_get_functions_count,
+ .get_function_name = stm32_rtc_pinmux_get_fname,
+ .get_function_groups = stm32_rtc_pinmux_get_groups,
+ .set_mux = stm32_rtc_pinmux_set_mux,
+ .strict = true,
+};
+
+static const struct pinctrl_desc stm32_rtc_pdesc = {
+ .name = DRIVER_NAME,
+ .pins = stm32_rtc_pinctrl_pins,
+ .npins = ARRAY_SIZE(stm32_rtc_pinctrl_pins),
+ .owner = THIS_MODULE,
+ .pctlops = &stm32_rtc_pinctrl_ops,
+ .pmxops = &stm32_rtc_pinmux_ops,
+};
+
static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
{
const struct stm32_rtc_registers *regs = &rtc->data->regs;
@@ -160,10 +417,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
* slowest rtc_ck frequency may be 32kHz and highest should be
* 1MHz, we poll every 10 us with a timeout of 100ms.
*/
- return readl_relaxed_poll_timeout_atomic(
- rtc->base + regs->isr,
- isr, (isr & STM32_RTC_ISR_INITF),
- 10, 100000);
+ return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr,
+ (isr & STM32_RTC_ISR_INITF),
+ 10, 100000);
}
return 0;
@@ -427,40 +683,42 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
return 0;
}
-static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
+static int stm32_rtc_valid_alrm(struct device *dev, struct rtc_time *tm)
{
- const struct stm32_rtc_registers *regs = &rtc->data->regs;
- int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec;
- unsigned int dr = readl_relaxed(rtc->base + regs->dr);
- unsigned int tr = readl_relaxed(rtc->base + regs->tr);
-
- cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
- cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
- cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
- cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
- cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
- cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+ static struct rtc_time now;
+ time64_t max_alarm_time64;
+ int max_day_forward;
+ int next_month;
+ int next_year;
/*
* Assuming current date is M-D-Y H:M:S.
* RTC alarm can't be set on a specific month and year.
* So the valid alarm range is:
* M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
- * with a specific case for December...
*/
- if ((((tm->tm_year > cur_year) &&
- (tm->tm_mon == 0x1) && (cur_mon == 0x12)) ||
- ((tm->tm_year == cur_year) &&
- (tm->tm_mon <= cur_mon + 1))) &&
- ((tm->tm_mday > cur_day) ||
- ((tm->tm_mday == cur_day) &&
- ((tm->tm_hour > cur_hour) ||
- ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) ||
- ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) &&
- (tm->tm_sec >= cur_sec))))))
- return 0;
+ stm32_rtc_read_time(dev, &now);
- return -EINVAL;
+ /*
+ * Find the next month and the year of the next month.
+ * Note: tm_mon and next_month are from 0 to 11
+ */
+ next_month = now.tm_mon + 1;
+ if (next_month == 12) {
+ next_month = 0;
+ next_year = now.tm_year + 1;
+ } else {
+ next_year = now.tm_year;
+ }
+
+ /* Find the maximum limit of alarm in days. */
+ max_day_forward = rtc_month_days(now.tm_mon, now.tm_year)
+ - now.tm_mday
+ + min(rtc_month_days(next_month, next_year), now.tm_mday);
+
+ /* Convert to timestamp and compare the alarm time and its upper limit */
+ max_alarm_time64 = rtc_tm_to_time64(&now) + max_day_forward * SEC_PER_DAY;
+ return rtc_tm_to_time64(tm) <= max_alarm_time64 ? 0 : -EINVAL;
}
static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -471,17 +729,17 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
unsigned int cr, isr, alrmar;
int ret = 0;
- tm2bcd(tm);
-
/*
* RTC alarm can't be set on a specific date, unless this date is
* up to the same day of month next month.
*/
- if (stm32_rtc_valid_alrm(rtc, tm) < 0) {
+ if (stm32_rtc_valid_alrm(dev, tm) < 0) {
dev_err(dev, "Alarm can be set only on upcoming month.\n");
return -EINVAL;
}
+ tm2bcd(tm);
+
alrmar = 0;
/* tm_year and tm_mon are not used because not supported by RTC */
alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
@@ -547,7 +805,10 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc,
static const struct stm32_rtc_data stm32_rtc_data = {
.has_pclk = false,
.need_dbp = true,
- .has_wakeirq = false,
+ .need_accuracy = false,
+ .rif_protected = false,
+ .has_lsco = false,
+ .has_alarm_out = false,
.regs = {
.tr = 0x00,
.dr = 0x04,
@@ -558,6 +819,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {
.wpr = 0x24,
.sr = 0x0C, /* set to ISR offset to ease alarm management */
.scr = UNDEF_REG,
+ .cfgr = UNDEF_REG,
.verr = UNDEF_REG,
},
.events = {
@@ -569,7 +831,10 @@ static const struct stm32_rtc_data stm32_rtc_data = {
static const struct stm32_rtc_data stm32h7_rtc_data = {
.has_pclk = true,
.need_dbp = true,
- .has_wakeirq = false,
+ .need_accuracy = false,
+ .rif_protected = false,
+ .has_lsco = false,
+ .has_alarm_out = false,
.regs = {
.tr = 0x00,
.dr = 0x04,
@@ -580,6 +845,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
.wpr = 0x24,
.sr = 0x0C, /* set to ISR offset to ease alarm management */
.scr = UNDEF_REG,
+ .cfgr = UNDEF_REG,
.verr = UNDEF_REG,
},
.events = {
@@ -600,7 +866,10 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc,
static const struct stm32_rtc_data stm32mp1_data = {
.has_pclk = true,
.need_dbp = false,
- .has_wakeirq = true,
+ .need_accuracy = true,
+ .rif_protected = false,
+ .has_lsco = true,
+ .has_alarm_out = true,
.regs = {
.tr = 0x00,
.dr = 0x04,
@@ -611,6 +880,33 @@ static const struct stm32_rtc_data stm32mp1_data = {
.wpr = 0x24,
.sr = 0x50,
.scr = 0x5C,
+ .cfgr = 0x60,
+ .verr = 0x3F4,
+ },
+ .events = {
+ .alra = STM32_RTC_SR_ALRA,
+ },
+ .clear_events = stm32mp1_rtc_clear_events,
+};
+
+static const struct stm32_rtc_data stm32mp25_data = {
+ .has_pclk = true,
+ .need_dbp = false,
+ .need_accuracy = true,
+ .rif_protected = true,
+ .has_lsco = true,
+ .has_alarm_out = true,
+ .regs = {
+ .tr = 0x00,
+ .dr = 0x04,
+ .cr = 0x18,
+ .isr = 0x0C, /* named RTC_ICSR on stm32mp25 */
+ .prer = 0x10,
+ .alrmar = 0x40,
+ .wpr = 0x24,
+ .sr = 0x50,
+ .scr = 0x5C,
+ .cfgr = 0x60,
.verr = 0x3F4,
},
.events = {
@@ -623,17 +919,61 @@ static const struct of_device_id stm32_rtc_of_match[] = {
{ .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },
{ .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },
{ .compatible = "st,stm32mp1-rtc", .data = &stm32mp1_data },
+ { .compatible = "st,stm32mp25-rtc", .data = &stm32mp25_data },
{}
};
MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
+static void stm32_rtc_clean_outs(struct stm32_rtc *rtc)
+{
+ struct stm32_rtc_registers regs = rtc->data->regs;
+ unsigned int cr = readl_relaxed(rtc->base + regs.cr);
+
+ cr &= ~STM32_RTC_CR_OSEL;
+ cr &= ~STM32_RTC_CR_TAMPOE;
+ cr &= ~STM32_RTC_CR_COE;
+ cr &= ~STM32_RTC_CR_TAMPALRM_TYPE;
+ cr &= ~STM32_RTC_CR_OUT2EN;
+
+ stm32_rtc_wpr_unlock(rtc);
+ writel_relaxed(cr, rtc->base + regs.cr);
+ stm32_rtc_wpr_lock(rtc);
+
+ if (regs.cfgr != UNDEF_REG) {
+ unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
+
+ cfgr &= ~STM32_RTC_CFGR_LSCOEN;
+ cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
+ writel_relaxed(cfgr, rtc->base + regs.cfgr);
+ }
+}
+
+static int stm32_rtc_check_rif(struct stm32_rtc *stm32_rtc,
+ struct stm32_rtc_rif_resource res)
+{
+ u32 rxcidcfgr = readl_relaxed(stm32_rtc->base + STM32_RTC_RXCIDCFGR(res.num));
+ u32 seccfgr;
+
+ /* Check if RTC available for our CID */
+ if ((rxcidcfgr & STM32_RTC_RXCIDCFGR_CFEN) &&
+ (FIELD_GET(STM32_RTC_RXCIDCFGR_CID, rxcidcfgr) != STM32_RTC_RXCIDCFGR_CID1))
+ return -EACCES;
+
+ /* Check if RTC available for non secure world */
+ seccfgr = readl_relaxed(stm32_rtc->base + STM32_RTC_SECCFGR);
+ if ((seccfgr & STM32_RTC_SECCFGR_SEC) | (seccfgr & res.bit))
+ return -EACCES;
+
+ return 0;
+}
+
static int stm32_rtc_init(struct platform_device *pdev,
struct stm32_rtc *rtc)
{
const struct stm32_rtc_registers *regs = &rtc->data->regs;
unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
unsigned int rate;
- int ret = 0;
+ int ret;
rate = clk_get_rate(rtc->rtc_ck);
@@ -641,18 +981,32 @@ static int stm32_rtc_init(struct platform_device *pdev,
pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
- for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
- pred_s = (rate / (pred_a + 1)) - 1;
+ if (rate > (pred_a_max + 1) * (pred_s_max + 1)) {
+ dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate);
+ return -EINVAL;
+ }
+
+ if (rtc->data->need_accuracy) {
+ for (pred_a = 0; pred_a <= pred_a_max; pred_a++) {
+ pred_s = (rate / (pred_a + 1)) - 1;
- if (((pred_s + 1) * (pred_a + 1)) == rate)
- break;
+ if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate)
+ break;
+ }
+ } else {
+ for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
+ pred_s = (rate / (pred_a + 1)) - 1;
+
+ if (((pred_s + 1) * (pred_a + 1)) == rate)
+ break;
+ }
}
/*
* Can't find a 1Hz, so give priority to RTC power consumption
* by choosing the higher possible value for prediv_a
*/
- if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
+ if (pred_s > pred_s_max || pred_a > pred_a_max) {
pred_a = pred_a_max;
pred_s = (rate / (pred_a + 1)) - 1;
@@ -661,6 +1015,20 @@ static int stm32_rtc_init(struct platform_device *pdev,
"fast" : "slow");
}
+ cr = readl_relaxed(rtc->base + regs->cr);
+
+ prer = readl_relaxed(rtc->base + regs->prer);
+ prer &= STM32_RTC_PRER_PRED_S | STM32_RTC_PRER_PRED_A;
+
+ pred_s = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) &
+ STM32_RTC_PRER_PRED_S;
+ pred_a = (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) &
+ STM32_RTC_PRER_PRED_A;
+
+ /* quit if there is nothing to initialize */
+ if ((cr & STM32_RTC_CR_FMT) == 0 && prer == (pred_s | pred_a))
+ return 0;
+
stm32_rtc_wpr_unlock(rtc);
ret = stm32_rtc_enter_init_mode(rtc);
@@ -670,13 +1038,10 @@ static int stm32_rtc_init(struct platform_device *pdev,
goto end;
}
- prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
- writel_relaxed(prer, rtc->base + regs->prer);
- prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
- writel_relaxed(prer, rtc->base + regs->prer);
+ writel_relaxed(pred_s, rtc->base + regs->prer);
+ writel_relaxed(pred_a | pred_s, rtc->base + regs->prer);
/* Force 24h time format */
- cr = readl_relaxed(rtc->base + regs->cr);
cr &= ~STM32_RTC_CR_FMT;
writel_relaxed(cr, rtc->base + regs->cr);
@@ -693,6 +1058,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
{
struct stm32_rtc *rtc;
const struct stm32_rtc_registers *regs;
+ struct pinctrl_dev *pctl;
int ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
@@ -708,26 +1074,18 @@ static int stm32_rtc_probe(struct platform_device *pdev)
regs = &rtc->data->regs;
if (rtc->data->need_dbp) {
- rtc->dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "st,syscfg");
+ unsigned int args[2];
+
+ rtc->dbp = syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node,
+ "st,syscfg",
+ 2, args);
if (IS_ERR(rtc->dbp)) {
dev_err(&pdev->dev, "no st,syscfg\n");
return PTR_ERR(rtc->dbp);
}
- ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg",
- 1, &rtc->dbp_reg);
- if (ret) {
- dev_err(&pdev->dev, "can't read DBP register offset\n");
- return ret;
- }
-
- ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg",
- 2, &rtc->dbp_mask);
- if (ret) {
- dev_err(&pdev->dev, "can't read DBP register mask\n");
- return ret;
- }
+ rtc->dbp_reg = args[0];
+ rtc->dbp_mask = args[1];
}
if (!rtc->data->has_pclk) {
@@ -735,16 +1093,13 @@ static int stm32_rtc_probe(struct platform_device *pdev)
rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL);
} else {
rtc->pclk = devm_clk_get(&pdev->dev, "pclk");
- if (IS_ERR(rtc->pclk)) {
- dev_err(&pdev->dev, "no pclk clock");
- return PTR_ERR(rtc->pclk);
- }
+ if (IS_ERR(rtc->pclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->pclk), "no pclk clock");
+
rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck");
}
- if (IS_ERR(rtc->rtc_ck)) {
- dev_err(&pdev->dev, "no rtc_ck clock");
- return PTR_ERR(rtc->rtc_ck);
- }
+ if (IS_ERR(rtc->rtc_ck))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_ck), "no rtc_ck clock");
if (rtc->data->has_pclk) {
ret = clk_prepare_enable(rtc->pclk);
@@ -760,6 +1115,16 @@ static int stm32_rtc_probe(struct platform_device *pdev)
regmap_update_bits(rtc->dbp, rtc->dbp_reg,
rtc->dbp_mask, rtc->dbp_mask);
+ if (rtc->data->rif_protected) {
+ ret = stm32_rtc_check_rif(rtc, STM32_RTC_RES_INIT);
+ if (!ret)
+ ret = stm32_rtc_check_rif(rtc, STM32_RTC_RES_ALRA);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to probe RTC due to RIF configuration\n");
+ goto err;
+ }
+ }
+
/*
* After a system reset, RTC_ISR.INITS flag can be read to check if
* the calendar has been initialized or not. INITS flag is reset by a
@@ -778,20 +1143,13 @@ static int stm32_rtc_probe(struct platform_device *pdev)
goto err;
}
- ret = device_init_wakeup(&pdev->dev, true);
- if (rtc->data->has_wakeirq) {
- rtc->wakeirq_alarm = platform_get_irq(pdev, 1);
- if (rtc->wakeirq_alarm > 0) {
- ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
- rtc->wakeirq_alarm);
- } else {
- ret = rtc->wakeirq_alarm;
- if (rtc->wakeirq_alarm == -EPROBE_DEFER)
- goto err;
- }
- }
+ ret = devm_device_init_wakeup(&pdev->dev);
if (ret)
- dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret);
+ goto err;
+
+ ret = devm_pm_set_wake_irq(&pdev->dev, rtc->irq_alarm);
+ if (ret)
+ goto err;
platform_set_drvdata(pdev, rtc);
@@ -814,6 +1172,16 @@ static int stm32_rtc_probe(struct platform_device *pdev)
goto err;
}
+ stm32_rtc_clean_outs(rtc);
+
+ ret = devm_pinctrl_register_and_init(&pdev->dev, &stm32_rtc_pdesc, rtc, &pctl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "pinctrl register failed");
+
+ ret = pinctrl_enable(pctl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "pinctrl enable failed");
+
/*
* If INITS flag is reset (calendar year field set to 0x00), calendar
* must be initialized
@@ -840,18 +1208,18 @@ err_no_rtc_ck:
if (rtc->data->need_dbp)
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
- dev_pm_clear_wake_irq(&pdev->dev);
- device_init_wakeup(&pdev->dev, false);
-
return ret;
}
-static int stm32_rtc_remove(struct platform_device *pdev)
+static void stm32_rtc_remove(struct platform_device *pdev)
{
struct stm32_rtc *rtc = platform_get_drvdata(pdev);
const struct stm32_rtc_registers *regs = &rtc->data->regs;
unsigned int cr;
+ if (!IS_ERR_OR_NULL(rtc->clk_lsco))
+ clk_unregister_gate(rtc->clk_lsco);
+
/* Disable interrupts */
stm32_rtc_wpr_unlock(rtc);
cr = readl_relaxed(rtc->base + regs->cr);
@@ -866,14 +1234,8 @@ static int stm32_rtc_remove(struct platform_device *pdev)
/* Enable backup domain write protection if needed */
if (rtc->data->need_dbp)
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
-
- dev_pm_clear_wake_irq(&pdev->dev);
- device_init_wakeup(&pdev->dev, false);
-
- return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int stm32_rtc_suspend(struct device *dev)
{
struct stm32_rtc *rtc = dev_get_drvdata(dev);
@@ -881,9 +1243,6 @@ static int stm32_rtc_suspend(struct device *dev)
if (rtc->data->has_pclk)
clk_disable_unprepare(rtc->pclk);
- if (device_may_wakeup(dev))
- return enable_irq_wake(rtc->irq_alarm);
-
return 0;
}
@@ -905,15 +1264,12 @@ static int stm32_rtc_resume(struct device *dev)
return ret;
}
- if (device_may_wakeup(dev))
- return disable_irq_wake(rtc->irq_alarm);
-
return ret;
}
-#endif
-static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
- stm32_rtc_suspend, stm32_rtc_resume);
+static const struct dev_pm_ops stm32_rtc_pm_ops = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume)
+};
static struct platform_driver stm32_rtc_driver = {
.probe = stm32_rtc_probe,
@@ -927,7 +1283,6 @@ static struct platform_driver stm32_rtc_driver = {
module_platform_driver(stm32_rtc_driver);
-MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index aae40d20d086..7afcd14aeee5 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -18,7 +18,6 @@
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/slab.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/stmp_device.h>
#include <linux/stmp3xxx_rtc_wdt.h>
@@ -232,17 +231,15 @@ static const struct rtc_class_ops stmp3xxx_rtc_ops = {
.set_alarm = stmp3xxx_rtc_set_alarm,
};
-static int stmp3xxx_rtc_remove(struct platform_device *pdev)
+static void stmp3xxx_rtc_remove(struct platform_device *pdev)
{
struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(pdev);
if (!rtc_data)
- return 0;
+ return;
writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR);
-
- return 0;
}
static int stmp3xxx_rtc_probe(struct platform_device *pdev)
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index ed5516089e9a..e5e6013d080e 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@@ -136,7 +135,6 @@ struct sun6i_rtc_clk_data {
unsigned int fixed_prescaler : 16;
unsigned int has_prescaler : 1;
unsigned int has_out_clk : 1;
- unsigned int export_iosc : 1;
unsigned int has_losc_en : 1;
unsigned int has_auto_swt : 1;
};
@@ -215,6 +213,7 @@ static int sun6i_rtc_osc_set_parent(struct clk_hw *hw, u8 index)
static const struct clk_ops sun6i_rtc_osc_ops = {
.recalc_rate = sun6i_rtc_osc_recalc_rate,
+ .determine_rate = clk_hw_determine_rate_no_reparent,
.get_parent = sun6i_rtc_osc_get_parent,
.set_parent = sun6i_rtc_osc_set_parent,
@@ -261,7 +260,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
}
/* Switch to the external, more precise, oscillator, if present */
- if (of_get_property(node, "clocks", NULL)) {
+ if (of_property_present(node, "clocks")) {
reg |= SUN6I_LOSC_CTRL_EXT_OSC;
if (rtc->data->has_losc_en)
reg |= SUN6I_LOSC_CTRL_EXT_LOSC_EN;
@@ -271,10 +270,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
/* Yes, I know, this is ugly. */
sun6i_rtc = rtc;
- /* Only read IOSC name from device tree if it is exported */
- if (rtc->data->export_iosc)
- of_property_read_string_index(node, "clock-output-names", 2,
- &iosc_name);
+ of_property_read_string_index(node, "clock-output-names", 2,
+ &iosc_name);
rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL,
iosc_name,
@@ -315,13 +312,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
goto err_register;
}
- clk_data->num = 2;
+ clk_data->num = 3;
clk_data->hws[0] = &rtc->hw;
clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
- if (rtc->data->export_iosc) {
- clk_data->hws[2] = rtc->int_osc;
- clk_data->num = 3;
- }
+ clk_data->hws[2] = rtc->int_osc;
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
return;
@@ -361,7 +355,6 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = {
.fixed_prescaler = 32,
.has_prescaler = 1,
.has_out_clk = 1,
- .export_iosc = 1,
};
static void __init sun8i_h3_rtc_clk_init(struct device_node *node)
@@ -379,7 +372,6 @@ static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = {
.fixed_prescaler = 32,
.has_prescaler = 1,
.has_out_clk = 1,
- .export_iosc = 1,
.has_losc_en = 1,
.has_auto_swt = 1,
};
@@ -410,6 +402,7 @@ CLK_OF_DECLARE_DRIVER(sun8i_r40_rtc_clk, "allwinner,sun8i-r40-rtc",
static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = {
.rc_osc_rate = 32000,
.has_out_clk = 1,
+ .has_auto_swt = 1,
};
static void __init sun8i_v3_rtc_clk_init(struct device_node *node)
@@ -833,7 +826,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
clk_prepare_enable(chip->losc);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
chip->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(chip->rtc))
@@ -854,8 +847,6 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
if (ret)
return ret;
- dev_info(&pdev->dev, "RTC enabled\n");
-
return 0;
}
diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c
index e8e2ab1103fc..519a06e728d6 100644
--- a/drivers/rtc/rtc-sunplus.c
+++ b/drivers/rtc/rtc-sunplus.c
@@ -235,17 +235,16 @@ static int sp_rtc_probe(struct platform_device *plat_dev)
if (!sp_rtc)
return -ENOMEM;
- sp_rtc->res = platform_get_resource_byname(plat_dev, IORESOURCE_MEM, RTC_REG_NAME);
- sp_rtc->reg_base = devm_ioremap_resource(&plat_dev->dev, sp_rtc->res);
+ sp_rtc->reg_base = devm_platform_ioremap_resource_byname(plat_dev, RTC_REG_NAME);
if (IS_ERR(sp_rtc->reg_base))
return dev_err_probe(&plat_dev->dev, PTR_ERR(sp_rtc->reg_base),
"%s devm_ioremap_resource fail\n", RTC_REG_NAME);
- dev_dbg(&plat_dev->dev, "res = 0x%x, reg_base = 0x%lx\n",
- sp_rtc->res->start, (unsigned long)sp_rtc->reg_base);
+ dev_dbg(&plat_dev->dev, "res = %pR, reg_base = %p\n",
+ sp_rtc->res, sp_rtc->reg_base);
sp_rtc->irq = platform_get_irq(plat_dev, 0);
if (sp_rtc->irq < 0)
- return dev_err_probe(&plat_dev->dev, sp_rtc->irq, "platform_get_irq failed\n");
+ return sp_rtc->irq;
ret = devm_request_irq(&plat_dev->dev, sp_rtc->irq, sp_rtc_irq_handler,
IRQF_TRIGGER_RISING, "rtc irq", plat_dev);
@@ -270,7 +269,7 @@ static int sp_rtc_probe(struct platform_device *plat_dev)
if (ret)
goto free_reset_assert;
- device_init_wakeup(&plat_dev->dev, 1);
+ device_init_wakeup(&plat_dev->dev, true);
dev_set_drvdata(&plat_dev->dev, sp_rtc);
sp_rtc->rtc = devm_rtc_allocate_device(&plat_dev->dev);
@@ -304,15 +303,13 @@ free_clk:
return ret;
}
-static int sp_rtc_remove(struct platform_device *plat_dev)
+static void sp_rtc_remove(struct platform_device *plat_dev)
{
struct sunplus_rtc *sp_rtc = dev_get_drvdata(&plat_dev->dev);
- device_init_wakeup(&plat_dev->dev, 0);
+ device_init_wakeup(&plat_dev->dev, false);
reset_control_assert(sp_rtc->rstc);
clk_disable_unprepare(sp_rtc->rtcclk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -347,7 +344,7 @@ static SIMPLE_DEV_PM_OPS(sp_rtc_pm_ops, sp_rtc_suspend, sp_rtc_resume);
static struct platform_driver sp_rtc_driver = {
.probe = sp_rtc_probe,
- .remove = sp_rtc_remove,
+ .remove = sp_rtc_remove,
.driver = {
.name = "sp7021-rtc",
.of_match_table = sp_rtc_of_match,
diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c
index 5d019e3a835a..5cab9953c44f 100644
--- a/drivers/rtc/rtc-sunxi.c
+++ b/drivers/rtc/rtc-sunxi.c
@@ -14,8 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/types.h>
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 85f7ad5d5390..46788db89953 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -319,7 +319,7 @@ static int tegra_rtc_probe(struct platform_device *pdev)
writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
@@ -342,13 +342,11 @@ disable_clk:
return ret;
}
-static int tegra_rtc_remove(struct platform_device *pdev)
+static void tegra_rtc_remove(struct platform_device *pdev)
{
struct tegra_rtc_info *info = platform_get_drvdata(pdev);
clk_disable_unprepare(info->clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index 7e0d8fb26465..94f995febe5b 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -44,7 +44,7 @@ static int test_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
timeout = rtc_tm_to_time64(&alrm->time) - ktime_get_real_seconds();
timeout -= rtd->offset;
- del_timer(&rtd->alarm);
+ timer_delete(&rtd->alarm);
expires = jiffies + timeout * HZ;
if (expires > U32_MAX)
@@ -86,7 +86,7 @@ static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
if (enable)
add_timer(&rtd->alarm);
else
- del_timer(&rtd->alarm);
+ timer_delete(&rtd->alarm);
return 0;
}
@@ -107,7 +107,7 @@ static const struct rtc_class_ops test_rtc_ops = {
static void test_rtc_alarm_handler(struct timer_list *t)
{
- struct rtc_test_data *rtd = from_timer(rtd, t, alarm);
+ struct rtc_test_data *rtd = timer_container_of(rtd, t, alarm);
rtc_update_irq(rtd->rtc, 1, RTC_AF | RTC_IRQF);
}
@@ -132,7 +132,7 @@ static int test_probe(struct platform_device *plat_dev)
break;
default:
rtd->rtc->ops = &test_rtc_ops;
- device_init_wakeup(&plat_dev->dev, 1);
+ device_init_wakeup(&plat_dev->dev, true);
}
timer_setup(&rtd->alarm, test_rtc_alarm_handler, 0);
diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c
index ba23163cc042..ec759d8f7023 100644
--- a/drivers/rtc/rtc-ti-k3.c
+++ b/drivers/rtc/rtc-ti-k3.c
@@ -9,7 +9,7 @@
#include <linux/delay.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sys_soc.h>
#include <linux/property.h>
@@ -632,7 +632,8 @@ static int __maybe_unused ti_k3_rtc_suspend(struct device *dev)
struct ti_k3_rtc *priv = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
- enable_irq_wake(priv->irq);
+ return enable_irq_wake(priv->irq);
+
return 0;
}
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 52093e7ba22d..54c8429b16bf 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -241,7 +241,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
return ret;
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
platform_set_drvdata(pdev, rtc);
rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
@@ -252,6 +252,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
rtc->rtc->ops = &tps6586x_rtc_ops;
rtc->rtc->range_max = (1ULL << 30) - 1; /* 30-bit seconds */
+ rtc->rtc->alarm_offset_max = ALM1_VALID_RANGE_IN_SEC;
rtc->rtc->start_secs = mktime64(2009, 1, 1, 0, 0, 0);
rtc->rtc->set_start_time = true;
@@ -279,13 +280,12 @@ fail_rtc_register:
return ret;
};
-static int tps6586x_rtc_remove(struct platform_device *pdev)
+static void tps6586x_rtc_remove(struct platform_device *pdev)
{
struct device *tps_dev = to_tps6586x_dev(&pdev->dev);
tps6586x_update(tps_dev, RTC_CTRL, 0,
RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -317,7 +317,7 @@ static struct platform_driver tps6586x_rtc_driver = {
.pm = &tps6586x_pm_ops,
},
.probe = tps6586x_rtc_probe,
- .remove = tps6586x_rtc_remove,
+ .remove = tps6586x_rtc_remove,
};
module_platform_driver(tps6586x_rtc_driver);
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
index 75e4c2d777b9..284aa2f0392b 100644
--- a/drivers/rtc/rtc-tps65910.c
+++ b/drivers/rtc/rtc-tps65910.c
@@ -406,11 +406,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tps_rtc);
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
- irq);
- return -ENXIO;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
@@ -421,7 +418,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
tps_rtc->irq = irq;
if (irq != -1) {
if (device_property_present(tps65910->dev, "wakeup-source"))
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
else
device_set_wakeup_capable(&pdev->dev, 1);
} else {
@@ -469,4 +466,5 @@ static struct platform_driver tps65910_rtc_driver = {
module_platform_driver(tps65910_rtc_driver);
MODULE_ALIAS("platform:tps65910-rtc");
MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_DESCRIPTION("TI TPS65910 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-tps6594.c b/drivers/rtc/rtc-tps6594.c
new file mode 100644
index 000000000000..7c6246e3f029
--- /dev/null
+++ b/drivers/rtc/rtc-tps6594.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RTC driver for tps6594 PMIC
+ *
+ * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
+ */
+
+#include <linux/bcd.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/property.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <linux/mfd/tps6594.h>
+
+// Total number of RTC registers needed to set time
+#define NUM_TIME_REGS (TPS6594_REG_RTC_WEEKS - TPS6594_REG_RTC_SECONDS + 1)
+
+// Total number of RTC alarm registers
+#define NUM_TIME_ALARM_REGS (NUM_TIME_REGS - 1)
+
+/*
+ * Min and max values supported by 'offset' interface (swapped sign).
+ * After conversion, the values do not exceed the range [-32767, 33767]
+ * which COMP_REG must conform to.
+ */
+#define MIN_OFFSET (-277774)
+#define MAX_OFFSET (277774)
+
+// Number of ticks per hour
+#define TICKS_PER_HOUR (32768 * 3600LL)
+
+// Multiplier for ppb conversions
+#define PPB_MULT NANO
+
+struct tps6594_rtc {
+ struct rtc_device *rtc_dev;
+ int irq;
+};
+
+static int tps6594_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ u8 val;
+
+ val = enabled ? TPS6594_BIT_IT_ALARM : 0;
+
+ return regmap_update_bits(tps->regmap, TPS6594_REG_RTC_INTERRUPTS,
+ TPS6594_BIT_IT_ALARM, val);
+}
+
+/* Pulse GET_TIME field of RTC_CTRL_1 to store a timestamp in shadow registers. */
+static int tps6594_rtc_shadow_timestamp(struct device *dev, struct tps6594 *tps)
+{
+ int ret;
+
+ /*
+ * Set GET_TIME to 0. Next time we set GET_TIME to 1 we will be sure to store
+ * an up-to-date timestamp.
+ */
+ ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
+ TPS6594_BIT_GET_TIME);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Copy content of RTC registers to shadow registers or latches to read
+ * a coherent timestamp.
+ */
+ return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
+ TPS6594_BIT_GET_TIME);
+}
+
+static int tps6594_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned char rtc_data[NUM_TIME_REGS];
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ int ret;
+
+ // Check if RTC is running.
+ ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS,
+ TPS6594_BIT_RUN);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -EINVAL;
+
+ ret = tps6594_rtc_shadow_timestamp(dev, tps);
+ if (ret < 0)
+ return ret;
+
+ // Read shadowed RTC registers.
+ ret = regmap_bulk_read(tps->regmap, TPS6594_REG_RTC_SECONDS, rtc_data,
+ NUM_TIME_REGS);
+ if (ret < 0)
+ return ret;
+
+ tm->tm_sec = bcd2bin(rtc_data[0]);
+ tm->tm_min = bcd2bin(rtc_data[1]);
+ tm->tm_hour = bcd2bin(rtc_data[2]);
+ tm->tm_mday = bcd2bin(rtc_data[3]);
+ tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
+ tm->tm_year = bcd2bin(rtc_data[5]) + 100;
+ tm->tm_wday = bcd2bin(rtc_data[6]);
+
+ return 0;
+}
+
+static int tps6594_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned char rtc_data[NUM_TIME_REGS];
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ int ret;
+
+ rtc_data[0] = bin2bcd(tm->tm_sec);
+ rtc_data[1] = bin2bcd(tm->tm_min);
+ rtc_data[2] = bin2bcd(tm->tm_hour);
+ rtc_data[3] = bin2bcd(tm->tm_mday);
+ rtc_data[4] = bin2bcd(tm->tm_mon + 1);
+ rtc_data[5] = bin2bcd(tm->tm_year - 100);
+ rtc_data[6] = bin2bcd(tm->tm_wday);
+
+ // Stop RTC while updating the RTC time registers.
+ ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
+ TPS6594_BIT_STOP_RTC);
+ if (ret < 0)
+ return ret;
+
+ // Update all the time registers in one shot.
+ ret = regmap_bulk_write(tps->regmap, TPS6594_REG_RTC_SECONDS, rtc_data,
+ NUM_TIME_REGS);
+ if (ret < 0)
+ return ret;
+
+ // Start back RTC.
+ return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
+ TPS6594_BIT_STOP_RTC);
+}
+
+static int tps6594_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ unsigned char alarm_data[NUM_TIME_ALARM_REGS];
+ u32 int_val;
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ int ret;
+
+ ret = regmap_bulk_read(tps->regmap, TPS6594_REG_ALARM_SECONDS,
+ alarm_data, NUM_TIME_ALARM_REGS);
+ if (ret < 0)
+ return ret;
+
+ alm->time.tm_sec = bcd2bin(alarm_data[0]);
+ alm->time.tm_min = bcd2bin(alarm_data[1]);
+ alm->time.tm_hour = bcd2bin(alarm_data[2]);
+ alm->time.tm_mday = bcd2bin(alarm_data[3]);
+ alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
+ alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
+
+ ret = regmap_read(tps->regmap, TPS6594_REG_RTC_INTERRUPTS, &int_val);
+ if (ret < 0)
+ return ret;
+
+ alm->enabled = int_val & TPS6594_BIT_IT_ALARM;
+
+ return 0;
+}
+
+static int tps6594_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ unsigned char alarm_data[NUM_TIME_ALARM_REGS];
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ int ret;
+
+ // Disable alarm irq before changing the alarm timestamp.
+ ret = tps6594_rtc_alarm_irq_enable(dev, 0);
+ if (ret)
+ return ret;
+
+ alarm_data[0] = bin2bcd(alm->time.tm_sec);
+ alarm_data[1] = bin2bcd(alm->time.tm_min);
+ alarm_data[2] = bin2bcd(alm->time.tm_hour);
+ alarm_data[3] = bin2bcd(alm->time.tm_mday);
+ alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
+ alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
+
+ // Update all the alarm registers in one shot.
+ ret = regmap_bulk_write(tps->regmap, TPS6594_REG_ALARM_SECONDS,
+ alarm_data, NUM_TIME_ALARM_REGS);
+ if (ret < 0)
+ return ret;
+
+ if (alm->enabled)
+ ret = tps6594_rtc_alarm_irq_enable(dev, 1);
+
+ return ret;
+}
+
+static int tps6594_rtc_set_calibration(struct device *dev, int calibration)
+{
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ __le16 value;
+ int ret;
+
+ /*
+ * TPS6594 uses two's complement 16 bit value for compensation of RTC
+ * crystal inaccuracies. One time every hour when seconds counter
+ * increments from 0 to 1 compensation value will be added to internal
+ * RTC counter value.
+ *
+ * Valid range for compensation value: [-32767 .. 32767].
+ */
+ if (calibration < S16_MIN + 1 || calibration > S16_MAX)
+ return -ERANGE;
+
+ value = cpu_to_le16(calibration);
+
+ // Update all the compensation registers in one shot.
+ ret = regmap_bulk_write(tps->regmap, TPS6594_REG_RTC_COMP_LSB, &value,
+ sizeof(value));
+ if (ret < 0)
+ return ret;
+
+ // Enable automatic compensation.
+ return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
+ TPS6594_BIT_AUTO_COMP);
+}
+
+static int tps6594_rtc_get_calibration(struct device *dev, int *calibration)
+{
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ unsigned int ctrl;
+ __le16 value;
+ int ret;
+
+ ret = regmap_read(tps->regmap, TPS6594_REG_RTC_CTRL_1, &ctrl);
+ if (ret < 0)
+ return ret;
+
+ // If automatic compensation is not enabled report back zero.
+ if (!(ctrl & TPS6594_BIT_AUTO_COMP)) {
+ *calibration = 0;
+ return 0;
+ }
+
+ ret = regmap_bulk_read(tps->regmap, TPS6594_REG_RTC_COMP_LSB, &value,
+ sizeof(value));
+ if (ret < 0)
+ return ret;
+
+ *calibration = le16_to_cpu(value);
+
+ return 0;
+}
+
+static int tps6594_rtc_read_offset(struct device *dev, long *offset)
+{
+ int calibration;
+ s64 tmp;
+ int ret;
+
+ ret = tps6594_rtc_get_calibration(dev, &calibration);
+ if (ret < 0)
+ return ret;
+
+ // Convert from RTC calibration register format to ppb format.
+ tmp = calibration * PPB_MULT;
+
+ if (tmp < 0)
+ tmp -= TICKS_PER_HOUR / 2LL;
+ else
+ tmp += TICKS_PER_HOUR / 2LL;
+ tmp = div_s64(tmp, TICKS_PER_HOUR);
+
+ /*
+ * SAFETY:
+ * Computatiion is the reverse operation of the one done in
+ * `tps6594_rtc_set_offset`. The safety remarks applie here too.
+ */
+
+ /*
+ * Offset value operates in negative way, so swap sign.
+ * See 8.3.10.5, (32768 - COMP_REG).
+ */
+ *offset = (long)-tmp;
+
+ return 0;
+}
+
+static int tps6594_rtc_set_offset(struct device *dev, long offset)
+{
+ int calibration;
+ s64 tmp;
+
+ // Make sure offset value is within supported range.
+ if (offset < MIN_OFFSET || offset > MAX_OFFSET)
+ return -ERANGE;
+
+ // Convert from ppb format to RTC calibration register format.
+
+ tmp = offset * TICKS_PER_HOUR;
+ if (tmp < 0)
+ tmp -= PPB_MULT / 2LL;
+ else
+ tmp += PPB_MULT / 2LL;
+ tmp = div_s64(tmp, PPB_MULT);
+
+ /*
+ * SAFETY:
+ * - tmp = offset * TICK_PER_HOUR :
+ * `offset` can't be more than 277774, so `tmp` can't exceed 277774000000000
+ * which is lower than the maximum value in an `s64` (2^63-1). No overflow here.
+ *
+ * - tmp += TICK_PER_HOUR / 2LL :
+ * tmp will have a maximum value of 277774117964800 which is still inferior to 2^63-1.
+ */
+
+ // Offset value operates in negative way, so swap sign.
+ calibration = (int)-tmp;
+
+ return tps6594_rtc_set_calibration(dev, calibration);
+}
+
+static irqreturn_t tps6594_rtc_interrupt(int irq, void *data)
+{
+ struct device *dev = data;
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ struct tps6594_rtc *rtc = dev_get_drvdata(dev);
+ int ret;
+ u32 rtc_reg;
+
+ ret = regmap_read(tps->regmap, TPS6594_REG_RTC_STATUS, &rtc_reg);
+ if (ret)
+ return IRQ_NONE;
+
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops tps6594_rtc_ops = {
+ .read_time = tps6594_rtc_read_time,
+ .set_time = tps6594_rtc_set_time,
+ .read_alarm = tps6594_rtc_read_alarm,
+ .set_alarm = tps6594_rtc_set_alarm,
+ .alarm_irq_enable = tps6594_rtc_alarm_irq_enable,
+ .read_offset = tps6594_rtc_read_offset,
+ .set_offset = tps6594_rtc_set_offset,
+};
+
+static int tps6594_rtc_probe(struct platform_device *pdev)
+{
+ struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct tps6594_rtc *rtc;
+ int irq;
+ int ret;
+
+ rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->rtc_dev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
+ // Enable crystal oscillator.
+ ret = regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_2,
+ TPS6594_BIT_XTAL_EN);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS,
+ TPS6594_BIT_RUN);
+ if (ret < 0)
+ return ret;
+ // RTC not running.
+ if (ret == 0) {
+ ret = regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
+ TPS6594_BIT_STOP_RTC);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * On some boards, a 40 ms delay is needed before BIT_RUN is set.
+ * 80 ms should provide sufficient margin.
+ */
+ mdelay(80);
+
+ /*
+ * RTC should be running now. Check if this is the case.
+ * If not it might be a missing oscillator.
+ */
+ ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS,
+ TPS6594_BIT_RUN);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -ENODEV;
+
+ // Stop RTC until first call to `tps6594_rtc_set_time`.
+ ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
+ TPS6594_BIT_STOP_RTC);
+ if (ret < 0)
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ irq = platform_get_irq_byname(pdev, TPS6594_IRQ_NAME_ALARM);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get irq\n");
+
+ rtc->irq = irq;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, tps6594_rtc_interrupt,
+ IRQF_ONESHOT, TPS6594_IRQ_NAME_ALARM,
+ dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to request_threaded_irq\n");
+
+ ret = device_init_wakeup(dev, true);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to init rtc as wakeup source\n");
+
+ rtc->rtc_dev->ops = &tps6594_rtc_ops;
+ rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
+
+ return devm_rtc_register_device(rtc->rtc_dev);
+}
+
+static int tps6594_rtc_resume(struct device *dev)
+{
+ struct tps6594 *tps = dev_get_drvdata(dev->parent);
+ struct tps6594_rtc *rtc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_test_bits(tps->regmap, TPS6594_REG_INT_STARTUP,
+ TPS6594_BIT_RTC_INT);
+ if (ret < 0) {
+ dev_err(dev, "failed to read REG_INT_STARTUP: %d\n", ret);
+ goto out;
+ }
+
+ if (ret > 0) {
+ /*
+ * If the alarm bit is set, it means that the IRQ has been
+ * fired. But, the kernel may not have woke up yet when it
+ * happened. So, we have to clear it.
+ */
+ ret = regmap_write(tps->regmap, TPS6594_REG_RTC_STATUS,
+ TPS6594_BIT_ALARM);
+ if (ret < 0)
+ dev_err(dev, "error clearing alarm bit: %d", ret);
+
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+ }
+out:
+ disable_irq_wake(rtc->irq);
+
+ return 0;
+}
+
+static int tps6594_rtc_suspend(struct device *dev)
+{
+ struct tps6594_rtc *rtc = dev_get_drvdata(dev);
+
+ enable_irq_wake(rtc->irq);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(tps6594_rtc_pm_ops, tps6594_rtc_suspend, tps6594_rtc_resume);
+
+static const struct platform_device_id tps6594_rtc_id_table[] = {
+ { "tps6594-rtc", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, tps6594_rtc_id_table);
+
+static struct platform_driver tps6594_rtc_driver = {
+ .probe = tps6594_rtc_probe,
+ .driver = {
+ .name = "tps6594-rtc",
+ .pm = pm_sleep_ptr(&tps6594_rtc_pm_ops),
+ },
+ .id_table = tps6594_rtc_id_table,
+};
+
+module_platform_driver(tps6594_rtc_driver);
+MODULE_AUTHOR("Esteban Blanc <eblanc@baylibre.com>");
+MODULE_DESCRIPTION("TPS6594 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index c24d1e18f56c..e6106e67e1f4 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -487,11 +487,24 @@ static const struct rtc_class_ops twl_rtc_ops = {
.alarm_irq_enable = twl_rtc_alarm_irq_enable,
};
+static int twl_nvram_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ return twl_i2c_read((long)priv, val, offset, bytes);
+}
+
+static int twl_nvram_write(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ return twl_i2c_write((long)priv, val, offset, bytes);
+}
+
/*----------------------------------------------------------------------*/
static int twl_rtc_probe(struct platform_device *pdev)
{
struct twl_rtc *twl_rtc;
+ struct nvmem_config nvmem_cfg;
struct device_node *np = pdev->dev.of_node;
int ret = -EINVAL;
int irq = platform_get_irq(pdev, 0);
@@ -542,7 +555,6 @@ static int twl_rtc_probe(struct platform_device *pdev)
REG_INT_MSK_STS_A);
}
- dev_info(&pdev->dev, "Enabling TWL-RTC\n");
ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
REG_RTC_CTRL_REG);
if (ret < 0)
@@ -560,15 +572,12 @@ static int twl_rtc_probe(struct platform_device *pdev)
return ret;
platform_set_drvdata(pdev, twl_rtc);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&twl_rtc_ops, THIS_MODULE);
- if (IS_ERR(twl_rtc->rtc)) {
- dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
- PTR_ERR(twl_rtc->rtc));
+ if (IS_ERR(twl_rtc->rtc))
return PTR_ERR(twl_rtc->rtc);
- }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl_rtc_interrupt,
@@ -579,6 +588,30 @@ static int twl_rtc_probe(struct platform_device *pdev)
return ret;
}
+ memset(&nvmem_cfg, 0, sizeof(nvmem_cfg));
+ nvmem_cfg.name = "twl-secured-";
+ nvmem_cfg.type = NVMEM_TYPE_BATTERY_BACKED;
+ nvmem_cfg.reg_read = twl_nvram_read;
+ nvmem_cfg.reg_write = twl_nvram_write;
+ nvmem_cfg.word_size = 1;
+ nvmem_cfg.stride = 1;
+ if (twl_class_is_4030()) {
+ /* 20 bytes SECURED_REG area */
+ nvmem_cfg.size = 20;
+ nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG;
+ devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg);
+ /* 8 bytes BACKUP area */
+ nvmem_cfg.name = "twl-backup-";
+ nvmem_cfg.size = 8;
+ nvmem_cfg.priv = (void *)TWL4030_MODULE_BACKUP;
+ devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg);
+ } else {
+ /* 8 bytes SECURED_REG area */
+ nvmem_cfg.size = 8;
+ nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG;
+ devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg);
+ }
+
return 0;
}
@@ -586,7 +619,7 @@ static int twl_rtc_probe(struct platform_device *pdev)
* Disable all TWL RTC module interrupts.
* Sets status flag to free.
*/
-static int twl_rtc_remove(struct platform_device *pdev)
+static void twl_rtc_remove(struct platform_device *pdev)
{
struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
@@ -599,8 +632,6 @@ static int twl_rtc_remove(struct platform_device *pdev)
twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_STS_A);
}
-
- return 0;
}
static void twl_rtc_shutdown(struct platform_device *pdev)
@@ -654,4 +685,5 @@ static struct platform_driver twl4030rtc_driver = {
module_platform_driver(twl4030rtc_driver);
MODULE_AUTHOR("Texas Instruments, MontaVista Software");
+MODULE_DESCRIPTION("TI TWL4030/TWL5030/TWL6030/TPS659x0 RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
deleted file mode 100644
index 4e8341c49f51..000000000000
--- a/drivers/rtc/rtc-v3020.c
+++ /dev/null
@@ -1,369 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* drivers/rtc/rtc-v3020.c
- *
- * Copyright (C) 2006 8D Technologies inc.
- * Copyright (C) 2004 Compulab Ltd.
- *
- * Driver for the V3020 RTC
- *
- * Changelog:
- *
- * 10-May-2006: Raphael Assenat <raph@8d.com>
- * - Converted to platform driver
- * - Use the generic rtc class
- *
- * ??-???-2004: Someone at Compulab
- * - Initial driver creation.
- */
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/rtc.h>
-#include <linux/types.h>
-#include <linux/bcd.h>
-#include <linux/platform_data/rtc-v3020.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-
-#include <linux/io.h>
-
-#undef DEBUG
-
-struct v3020;
-
-struct v3020_chip_ops {
- int (*map_io)(struct v3020 *chip, struct platform_device *pdev,
- struct v3020_platform_data *pdata);
- void (*unmap_io)(struct v3020 *chip);
- unsigned char (*read_bit)(struct v3020 *chip);
- void (*write_bit)(struct v3020 *chip, unsigned char bit);
-};
-
-#define V3020_CS 0
-#define V3020_WR 1
-#define V3020_RD 2
-#define V3020_IO 3
-
-struct v3020 {
- /* MMIO access */
- void __iomem *ioaddress;
- int leftshift;
-
- /* GPIO access */
- struct gpio *gpio;
-
- const struct v3020_chip_ops *ops;
-
- struct rtc_device *rtc;
-};
-
-
-static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev,
- struct v3020_platform_data *pdata)
-{
- if (pdev->num_resources != 1)
- return -EBUSY;
-
- if (pdev->resource[0].flags != IORESOURCE_MEM)
- return -EBUSY;
-
- chip->leftshift = pdata->leftshift;
- chip->ioaddress = ioremap(pdev->resource[0].start, 1);
- if (chip->ioaddress == NULL)
- return -EBUSY;
-
- return 0;
-}
-
-static void v3020_mmio_unmap(struct v3020 *chip)
-{
- iounmap(chip->ioaddress);
-}
-
-static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit)
-{
- writel(bit << chip->leftshift, chip->ioaddress);
-}
-
-static unsigned char v3020_mmio_read_bit(struct v3020 *chip)
-{
- return !!(readl(chip->ioaddress) & (1 << chip->leftshift));
-}
-
-static const struct v3020_chip_ops v3020_mmio_ops = {
- .map_io = v3020_mmio_map,
- .unmap_io = v3020_mmio_unmap,
- .read_bit = v3020_mmio_read_bit,
- .write_bit = v3020_mmio_write_bit,
-};
-
-static struct gpio v3020_gpio[] = {
- { 0, GPIOF_OUT_INIT_HIGH, "RTC CS"},
- { 0, GPIOF_OUT_INIT_HIGH, "RTC WR"},
- { 0, GPIOF_OUT_INIT_HIGH, "RTC RD"},
- { 0, GPIOF_OUT_INIT_HIGH, "RTC IO"},
-};
-
-static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev,
- struct v3020_platform_data *pdata)
-{
- int err;
-
- v3020_gpio[V3020_CS].gpio = pdata->gpio_cs;
- v3020_gpio[V3020_WR].gpio = pdata->gpio_wr;
- v3020_gpio[V3020_RD].gpio = pdata->gpio_rd;
- v3020_gpio[V3020_IO].gpio = pdata->gpio_io;
-
- err = gpio_request_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
-
- if (!err)
- chip->gpio = v3020_gpio;
-
- return err;
-}
-
-static void v3020_gpio_unmap(struct v3020 *chip)
-{
- gpio_free_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
-}
-
-static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit)
-{
- gpio_direction_output(chip->gpio[V3020_IO].gpio, bit);
- gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
- gpio_set_value(chip->gpio[V3020_WR].gpio, 0);
- udelay(1);
- gpio_set_value(chip->gpio[V3020_WR].gpio, 1);
- gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
-}
-
-static unsigned char v3020_gpio_read_bit(struct v3020 *chip)
-{
- int bit;
-
- gpio_direction_input(chip->gpio[V3020_IO].gpio);
- gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
- gpio_set_value(chip->gpio[V3020_RD].gpio, 0);
- udelay(1);
- bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio);
- udelay(1);
- gpio_set_value(chip->gpio[V3020_RD].gpio, 1);
- gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
-
- return bit;
-}
-
-static const struct v3020_chip_ops v3020_gpio_ops = {
- .map_io = v3020_gpio_map,
- .unmap_io = v3020_gpio_unmap,
- .read_bit = v3020_gpio_read_bit,
- .write_bit = v3020_gpio_write_bit,
-};
-
-static void v3020_set_reg(struct v3020 *chip, unsigned char address,
- unsigned char data)
-{
- int i;
- unsigned char tmp;
-
- tmp = address;
- for (i = 0; i < 4; i++) {
- chip->ops->write_bit(chip, (tmp & 1));
- tmp >>= 1;
- udelay(1);
- }
-
- /* Commands dont have data */
- if (!V3020_IS_COMMAND(address)) {
- for (i = 0; i < 8; i++) {
- chip->ops->write_bit(chip, (data & 1));
- data >>= 1;
- udelay(1);
- }
- }
-}
-
-static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
-{
- unsigned int data = 0;
- int i;
-
- for (i = 0; i < 4; i++) {
- chip->ops->write_bit(chip, (address & 1));
- address >>= 1;
- udelay(1);
- }
-
- for (i = 0; i < 8; i++) {
- data >>= 1;
- if (chip->ops->read_bit(chip))
- data |= 0x80;
- udelay(1);
- }
-
- return data;
-}
-
-static int v3020_read_time(struct device *dev, struct rtc_time *dt)
-{
- struct v3020 *chip = dev_get_drvdata(dev);
- int tmp;
-
- /* Copy the current time to ram... */
- v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0);
-
- /* ...and then read constant values. */
- tmp = v3020_get_reg(chip, V3020_SECONDS);
- dt->tm_sec = bcd2bin(tmp);
- tmp = v3020_get_reg(chip, V3020_MINUTES);
- dt->tm_min = bcd2bin(tmp);
- tmp = v3020_get_reg(chip, V3020_HOURS);
- dt->tm_hour = bcd2bin(tmp);
- tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
- dt->tm_mday = bcd2bin(tmp);
- tmp = v3020_get_reg(chip, V3020_MONTH);
- dt->tm_mon = bcd2bin(tmp) - 1;
- tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
- dt->tm_wday = bcd2bin(tmp);
- tmp = v3020_get_reg(chip, V3020_YEAR);
- dt->tm_year = bcd2bin(tmp)+100;
-
- dev_dbg(dev, "\n%s : Read RTC values\n", __func__);
- dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
- dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
- dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
- dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
- dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
- dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
- dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
-
- return 0;
-}
-
-
-static int v3020_set_time(struct device *dev, struct rtc_time *dt)
-{
- struct v3020 *chip = dev_get_drvdata(dev);
-
- dev_dbg(dev, "\n%s : Setting RTC values\n", __func__);
- dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
- dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
- dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
- dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
- dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
- dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
-
- /* Write all the values to ram... */
- v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec));
- v3020_set_reg(chip, V3020_MINUTES, bin2bcd(dt->tm_min));
- v3020_set_reg(chip, V3020_HOURS, bin2bcd(dt->tm_hour));
- v3020_set_reg(chip, V3020_MONTH_DAY, bin2bcd(dt->tm_mday));
- v3020_set_reg(chip, V3020_MONTH, bin2bcd(dt->tm_mon + 1));
- v3020_set_reg(chip, V3020_WEEK_DAY, bin2bcd(dt->tm_wday));
- v3020_set_reg(chip, V3020_YEAR, bin2bcd(dt->tm_year % 100));
-
- /* ...and set the clock. */
- v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
-
- /* Compulab used this delay here. I dont know why,
- * the datasheet does not specify a delay. */
- /*mdelay(5);*/
-
- return 0;
-}
-
-static const struct rtc_class_ops v3020_rtc_ops = {
- .read_time = v3020_read_time,
- .set_time = v3020_set_time,
-};
-
-static int rtc_probe(struct platform_device *pdev)
-{
- struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct v3020 *chip;
- int retval;
- int i;
-
- chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- if (pdata->use_gpio)
- chip->ops = &v3020_gpio_ops;
- else
- chip->ops = &v3020_mmio_ops;
-
- retval = chip->ops->map_io(chip, pdev, pdata);
- if (retval)
- return retval;
-
- /* Make sure the v3020 expects a communication cycle
- * by reading 8 times */
- for (i = 0; i < 8; i++)
- chip->ops->read_bit(chip);
-
- /* Test chip by doing a write/read sequence
- * to the chip ram */
- v3020_set_reg(chip, V3020_SECONDS, 0x33);
- if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
- retval = -ENODEV;
- goto err_io;
- }
-
- /* Make sure frequency measurement mode, test modes, and lock
- * are all disabled */
- v3020_set_reg(chip, V3020_STATUS_0, 0x0);
-
- if (pdata->use_gpio)
- dev_info(&pdev->dev, "Chip available at GPIOs "
- "%d, %d, %d, %d\n",
- chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio,
- chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio);
- else
- dev_info(&pdev->dev, "Chip available at "
- "physical address 0x%llx,"
- "data connected to D%d\n",
- (unsigned long long)pdev->resource[0].start,
- chip->leftshift);
-
- platform_set_drvdata(pdev, chip);
-
- chip->rtc = devm_rtc_device_register(&pdev->dev, "v3020",
- &v3020_rtc_ops, THIS_MODULE);
- if (IS_ERR(chip->rtc)) {
- retval = PTR_ERR(chip->rtc);
- goto err_io;
- }
-
- return 0;
-
-err_io:
- chip->ops->unmap_io(chip);
-
- return retval;
-}
-
-static int rtc_remove(struct platform_device *dev)
-{
- struct v3020 *chip = platform_get_drvdata(dev);
-
- chip->ops->unmap_io(chip);
-
- return 0;
-}
-
-static struct platform_driver rtc_device_driver = {
- .probe = rtc_probe,
- .remove = rtc_remove,
- .driver = {
- .name = "v3020",
- },
-};
-
-module_platform_driver(rtc_device_driver);
-
-MODULE_DESCRIPTION("V3020 RTC");
-MODULE_AUTHOR("Raphael Assenat");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:v3020");
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
index 197b649cd629..c8b568498016 100644
--- a/drivers/rtc/rtc-vt8500.c
+++ b/drivers/rtc/rtc-vt8500.c
@@ -235,14 +235,12 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
return devm_rtc_register_device(vt8500_rtc->rtc);
}
-static int vt8500_rtc_remove(struct platform_device *pdev)
+static void vt8500_rtc_remove(struct platform_device *pdev)
{
struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
/* Disable alarm matching */
writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
-
- return 0;
}
static const struct of_device_id wmt_dt_ids[] = {
diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c
index 640833e21057..218316be942a 100644
--- a/drivers/rtc/rtc-wm831x.c
+++ b/drivers/rtc/rtc-wm831x.c
@@ -420,7 +420,7 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
if (ret & WM831X_RTC_ALM_ENA)
wm831x_rtc->alarm_enabled = 1;
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
wm831x_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(wm831x_rtc->rtc))
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
index 6eaa9321c074..3bd60d067a5e 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -386,8 +386,6 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
/* enable the RTC if it's not already enabled */
power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
if (!(power5 & WM8350_RTC_TICK_ENA)) {
- dev_info(wm8350->dev, "Starting RTC\n");
-
wm8350_reg_unlock(wm8350);
ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5,
@@ -422,15 +420,12 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
}
}
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350",
&wm8350_rtc_ops, THIS_MODULE);
- if (IS_ERR(wm_rtc->rtc)) {
- ret = PTR_ERR(wm_rtc->rtc);
- dev_err(&pdev->dev, "failed to register RTC: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(wm_rtc->rtc))
+ return PTR_ERR(wm_rtc->rtc);
ret = wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC,
wm8350_rtc_update_handler, 0,
@@ -451,14 +446,12 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int wm8350_rtc_remove(struct platform_device *pdev)
+static void wm8350_rtc_remove(struct platform_device *pdev)
{
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350);
wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350);
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(wm8350_rtc_pm_ops, wm8350_rtc_suspend,
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index f587afa84357..b8a0fccef14e 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -663,13 +663,13 @@ static void x1205_remove(struct i2c_client *client)
}
static const struct i2c_device_id x1205_id[] = {
- { "x1205", 0 },
+ { "x1205" },
{ }
};
MODULE_DEVICE_TABLE(i2c, x1205_id);
static const struct of_device_id x1205_dt_ids[] = {
- { .compatible = "xircom,x1205", },
+ { .compatible = "xicor,x1205", },
{},
};
MODULE_DEVICE_TABLE(of, x1205_dt_ids);
@@ -679,7 +679,7 @@ static struct i2c_driver x1205_driver = {
.name = "rtc-x1205",
.of_match_table = x1205_dt_ids,
},
- .probe_new = x1205_probe,
+ .probe = x1205_probe,
.remove = x1205_remove,
.id_table = x1205_id,
};
diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c
index d3d0054e21fd..6660b664e8dd 100644
--- a/drivers/rtc/rtc-xgene.c
+++ b/drivers/rtc/rtc-xgene.c
@@ -174,7 +174,7 @@ static int xgene_rtc_probe(struct platform_device *pdev)
/* Turn on the clock and the crystal */
writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR);
- ret = device_init_wakeup(&pdev->dev, 1);
+ ret = device_init_wakeup(&pdev->dev, true);
if (ret) {
clk_disable_unprepare(pdata->clk);
return ret;
@@ -192,14 +192,13 @@ static int xgene_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int xgene_rtc_remove(struct platform_device *pdev)
+static void xgene_rtc_remove(struct platform_device *pdev)
{
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
xgene_rtc_alarm_irq_enable(&pdev->dev, 0);
- device_init_wakeup(&pdev->dev, 0);
+ device_init_wakeup(&pdev->dev, false);
clk_disable_unprepare(pdata->clk);
- return 0;
}
static int __maybe_unused xgene_rtc_suspend(struct device *dev)
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index c9b85c838ebe..3baa2b481d9f 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -277,6 +277,10 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
static int xlnx_rtc_probe(struct platform_device *pdev)
{
struct xlnx_rtc_dev *xrtcdev;
+ bool is_alarm_set = false;
+ u32 pending_alrm_irq;
+ u32 current_time;
+ u32 alarm_time;
int ret;
xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
@@ -296,6 +300,17 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
if (IS_ERR(xrtcdev->reg_base))
return PTR_ERR(xrtcdev->reg_base);
+ /* Clear any pending alarm interrupts from previous kernel/boot */
+ pending_alrm_irq = readl(xrtcdev->reg_base + RTC_INT_STS) & RTC_INT_ALRM;
+ if (pending_alrm_irq)
+ writel(pending_alrm_irq, xrtcdev->reg_base + RTC_INT_STS);
+
+ /* Check if a valid alarm is already set from previous kernel/boot */
+ alarm_time = readl(xrtcdev->reg_base + RTC_ALRM);
+ current_time = readl(xrtcdev->reg_base + RTC_CUR_TM);
+ if (alarm_time > current_time && alarm_time != 0)
+ is_alarm_set = true;
+
xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm");
if (xrtcdev->alarm_irq < 0)
return xrtcdev->alarm_irq;
@@ -318,8 +333,8 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
return ret;
}
- /* Getting the rtc_clk info */
- xrtcdev->rtc_clk = devm_clk_get_optional(&pdev->dev, "rtc_clk");
+ /* Getting the rtc info */
+ xrtcdev->rtc_clk = devm_clk_get_optional(&pdev->dev, "rtc");
if (IS_ERR(xrtcdev->rtc_clk)) {
if (PTR_ERR(xrtcdev->rtc_clk) != -EPROBE_DEFER)
dev_warn(&pdev->dev, "Device clock not found.\n");
@@ -337,17 +352,19 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
xlnx_init_rtc(xrtcdev);
- device_init_wakeup(&pdev->dev, 1);
+ /* Re-enable alarm interrupt if a valid alarm was found */
+ if (is_alarm_set)
+ writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN);
+
+ device_init_wakeup(&pdev->dev, true);
return devm_rtc_register_device(xrtcdev->rtc);
}
-static int xlnx_rtc_remove(struct platform_device *pdev)
+static void xlnx_rtc_remove(struct platform_device *pdev)
{
xlnx_rtc_alarm_irq_enable(&pdev->dev, 0);
- device_init_wakeup(&pdev->dev, 0);
-
- return 0;
+ device_init_wakeup(&pdev->dev, false);
}
static int __maybe_unused xlnx_rtc_suspend(struct device *dev)
diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c
index e3062c4d3f2c..4ab05e105a76 100644
--- a/drivers/rtc/sysfs.c
+++ b/drivers/rtc/sysfs.c
@@ -24,8 +24,8 @@
static ssize_t
name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent),
- dev_name(dev->parent));
+ return sysfs_emit(buf, "%s %s\n", dev_driver_string(dev->parent),
+ dev_name(dev->parent));
}
static DEVICE_ATTR_RO(name);
@@ -39,7 +39,7 @@ date_show(struct device *dev, struct device_attribute *attr, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%ptRd\n", &tm);
+ return sysfs_emit(buf, "%ptRd\n", &tm);
}
static DEVICE_ATTR_RO(date);
@@ -53,7 +53,7 @@ time_show(struct device *dev, struct device_attribute *attr, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%ptRt\n", &tm);
+ return sysfs_emit(buf, "%ptRt\n", &tm);
}
static DEVICE_ATTR_RO(time);
@@ -64,21 +64,17 @@ since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf)
struct rtc_time tm;
retval = rtc_read_time(to_rtc_device(dev), &tm);
- if (retval == 0) {
- time64_t time;
-
- time = rtc_tm_to_time64(&tm);
- retval = sprintf(buf, "%lld\n", time);
- }
+ if (retval)
+ return retval;
- return retval;
+ return sysfs_emit(buf, "%lld\n", rtc_tm_to_time64(&tm));
}
static DEVICE_ATTR_RO(since_epoch);
static ssize_t
max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
+ return sysfs_emit(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
}
static ssize_t
@@ -118,9 +114,9 @@ hctosys_show(struct device *dev, struct device_attribute *attr, char *buf)
if (rtc_hctosys_ret == 0 &&
strcmp(dev_name(&to_rtc_device(dev)->dev),
CONFIG_RTC_HCTOSYS_DEVICE) == 0)
- return sprintf(buf, "1\n");
+ return sysfs_emit(buf, "1\n");
#endif
- return sprintf(buf, "0\n");
+ return sysfs_emit(buf, "0\n");
}
static DEVICE_ATTR_RO(hctosys);
@@ -128,7 +124,6 @@ static ssize_t
wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
- time64_t alarm;
struct rtc_wkalrm alm;
/* Don't show disabled alarms. For uniformity, RTC alarms are
@@ -140,12 +135,13 @@ wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
* alarms after they trigger, to ensure one-shot semantics.
*/
retval = rtc_read_alarm(to_rtc_device(dev), &alm);
- if (retval == 0 && alm.enabled) {
- alarm = rtc_tm_to_time64(&alm.time);
- retval = sprintf(buf, "%lld\n", alarm);
- }
+ if (retval)
+ return retval;
- return retval;
+ if (alm.enabled)
+ return sysfs_emit(buf, "%lld\n", rtc_tm_to_time64(&alm.time));
+
+ return 0;
}
static ssize_t
@@ -222,10 +218,10 @@ offset_show(struct device *dev, struct device_attribute *attr, char *buf)
long offset;
retval = rtc_read_offset(to_rtc_device(dev), &offset);
- if (retval == 0)
- retval = sprintf(buf, "%ld\n", offset);
+ if (retval)
+ return retval;
- return retval;
+ return sysfs_emit(buf, "%ld\n", offset);
}
static ssize_t
@@ -246,8 +242,8 @@ static DEVICE_ATTR_RW(offset);
static ssize_t
range_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min,
- to_rtc_device(dev)->range_max);
+ return sysfs_emit(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min,
+ to_rtc_device(dev)->range_max);
}
static DEVICE_ATTR_RO(range);
@@ -302,11 +298,7 @@ static struct attribute_group rtc_attr_group = {
.is_visible = rtc_attr_is_visible,
.attrs = rtc_attrs,
};
-
-static const struct attribute_group *rtc_attr_groups[] = {
- &rtc_attr_group,
- NULL
-};
+__ATTRIBUTE_GROUPS(rtc_attr);
const struct attribute_group **rtc_get_dev_attribute_groups(void)
{
@@ -318,17 +310,21 @@ int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
size_t old_cnt = 0, add_cnt = 0, new_cnt;
const struct attribute_group **groups, **old;
- if (!grps)
+ if (grps) {
+ for (groups = grps; *groups; groups++)
+ add_cnt++;
+ /* No need to modify current groups if nothing new is provided */
+ if (add_cnt == 0)
+ return 0;
+ } else {
return -EINVAL;
+ }
groups = rtc->dev.groups;
if (groups)
for (; *groups; groups++)
old_cnt++;
- for (groups = grps; *groups; groups++)
- add_cnt++;
-
new_cnt = old_cnt + add_cnt + 1;
groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL);
if (!groups)
diff --git a/drivers/rtc/test_rtc_lib.c b/drivers/rtc/test_rtc_lib.c
new file mode 100644
index 000000000000..0eebad1fe2a0
--- /dev/null
+++ b/drivers/rtc/test_rtc_lib.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#include <kunit/test.h>
+#include <linux/rtc.h>
+
+/*
+ * Advance a date by one day.
+ */
+static void advance_date(int *year, int *month, int *mday, int *yday, int *wday)
+{
+ *wday = (*wday + 1) % 7;
+
+ if (*mday != rtc_month_days(*month - 1, *year)) {
+ ++*mday;
+ ++*yday;
+ return;
+ }
+
+ *mday = 1;
+ if (*month != 12) {
+ ++*month;
+ ++*yday;
+ return;
+ }
+
+ *month = 1;
+ *yday = 1;
+ ++*year;
+}
+
+/*
+ * Check every day in specified number of years interval starting on 1970-01-01
+ * against the expected result.
+ */
+static void rtc_time64_to_tm_test_date_range(struct kunit *test, int years)
+{
+ /*
+ * years = (years / 400) * 400 years
+ * = (years / 400) * 146097 days
+ * = (years / 400) * 146097 * 86400 seconds
+ */
+ time64_t total_secs = ((time64_t)years) / 400 * 146097 * 86400;
+
+ int year = 1900;
+ int month = 1;
+ int mday = 1;
+ int yday = 1;
+ int wday = 1; /* Jan 1st 1900 was a Monday */
+
+ struct rtc_time result;
+ time64_t secs;
+ const time64_t sec_offset = RTC_TIMESTAMP_BEGIN_1900 + ((1 * 60) + 2) * 60 + 3;
+
+ for (secs = 0; secs <= total_secs; secs += 86400) {
+
+ rtc_time64_to_tm(secs + sec_offset, &result);
+
+ #define FAIL_MSG "%d/%02d/%02d (%2d, %d) : %lld", \
+ year, month, mday, yday, wday, secs + sec_offset
+
+ KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, month - 1, result.tm_mon, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, mday, result.tm_mday, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, yday, result.tm_yday, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, 1, result.tm_hour, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, 2, result.tm_min, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, 3, result.tm_sec, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, wday, result.tm_wday, FAIL_MSG);
+
+ advance_date(&year, &month, &mday, &yday, &wday);
+ }
+}
+
+/*
+ * Checks every day in a 160000 years interval starting on 1900-01-01
+ * against the expected result.
+ */
+static void rtc_time64_to_tm_test_date_range_160000(struct kunit *test)
+{
+ rtc_time64_to_tm_test_date_range(test, 160000);
+}
+
+/*
+ * Checks every day in a 1000 years interval starting on 1900-01-01
+ * against the expected result.
+ */
+static void rtc_time64_to_tm_test_date_range_1000(struct kunit *test)
+{
+ rtc_time64_to_tm_test_date_range(test, 1000);
+}
+
+static struct kunit_case rtc_lib_test_cases[] = {
+ KUNIT_CASE(rtc_time64_to_tm_test_date_range_1000),
+ KUNIT_CASE_SLOW(rtc_time64_to_tm_test_date_range_160000),
+ {}
+};
+
+static struct kunit_suite rtc_lib_test_suite = {
+ .name = "rtc_lib_test_cases",
+ .test_cases = rtc_lib_test_cases,
+};
+
+kunit_test_suite(rtc_lib_test_suite);
+
+MODULE_DESCRIPTION("KUnit test for RTC lib functions");
+MODULE_LICENSE("GPL");