Commit f8d35403 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rtc-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "There is an unusual amount of new drivers this cycle, and this
  explains the number of insertions.

  Other than that, the changes are the usual fixes and feature addition.

  Subsystem updates:
   - new quartz-load-femtofarads DT property for quartz load capacitance
   - remove rtc_class_ops.read_callback

  New drivers:
   - Abracon AB-RTCMC-32.768kHz-EOZ9
   - Amlogic Meson RTC
   - Cadence RTC IP
   - Microcrystal RV3028
   - Whwave sd3078

  Driver updates:
   - cmos: ignore bogus century byte
   - ds1307: rework rx8130 support
   - isl1208: add isl1209 support, nvmem support
   - rs5C372: report invalid time when the oscillator stopped
   - rx8581: add rx8571 support"

* tag 'rtc-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (66 commits)
  rtc: pic32: convert to SPDX identifier
  rtc: pic32: let the core handle range
  rtc: pic32: convert to devm_rtc_allocate_device
  rtc: update my email address
  rtc: rv8803: convert to SPDX identifier
  rtc: rv8803: let the core handle range
  rtc: tx4939: convert to SPDX identifier
  rtc: tx4939: use .set_time
  rtc: tx4939: switch to rtc_time64_to_tm/rtc_tm_to_time64
  rtc: tx4939: set range
  rtc: tx4939: remove useless test
  rtc: zynqmp: let the core handle range
  rtc: zynqmp: fix possible race condition
  rtc: imx-sc: use rtc_time64_to_tm
  rtc: rx8581: Add support for Epson rx8571 RTC
  dt-bindings: rtc: add rx8571 compatible
  rtc: pcf85063: remove dead code
  rtc: remove rtc_class_ops.read_callback
  rtc: add AB-RTCMC-32.768kHz-EOZ9 RTC support
  dt-bindings: rtc: add ABEOZ9
  ...
parents 9f24a81e e91b94fd
...@@ -31,6 +31,7 @@ Electricity ...@@ -31,6 +31,7 @@ Electricity
-microwatt-hours: micro Watt-hours -microwatt-hours: micro Watt-hours
-microvolt : micro volts -microvolt : micro volts
-picofarads : picofarads -picofarads : picofarads
-femtofarads : femtofarads
Temperature Temperature
---------------------------------------- ----------------------------------------
......
...@@ -16,6 +16,7 @@ Required properties: ...@@ -16,6 +16,7 @@ Required properties:
"abracon,ab1803" "abracon,ab1803"
"abracon,ab1804" "abracon,ab1804"
"abracon,ab1805" "abracon,ab1805"
"microcrystal,rv1805"
Using "abracon,abx80x" will enable chip autodetection. Using "abracon,abx80x" will enable chip autodetection.
- "reg": I2C bus address of the device - "reg": I2C bus address of the device
......
Cadence Real Time Clock
The Cadence RTC controller with date, time and alarm capabilities.
The alarm may wake the system from low-power state.
Required properties:
- compatible: Should be "cdns,rtc-r109v3"
- reg: Specifies base physical address and size of the register area.
- interrupts: A single interrupt specifier.
- clocks: Must contain two entries:
- pclk: APB registers clock
- ref_clk: reference 1Hz or 100Hz clock, depending on IP configuration
See ../clocks/clock-bindings.txt for details.
Example:
rtc0: rtc@fd080000 {
compatible = "cdns,rtc-r109v3";
reg = <0xfd080000 0x1000>;
clock-names = "pclk", "ref_clk";
clocks = <&sysclock>, <&refclock>;
interrupt-parent = <&gic>;
interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>;
};
Intersil ISL1219 I2C RTC/Alarm chip with event in Intersil ISL1209/19 I2C RTC/Alarm chip with event in
ISL1219 has additional pins EVIN and #EVDET for tamper detection. ISL12X9 have additional pins EVIN and #EVDET for tamper detection, while the
ISL1208 and ISL1218 do not. They are all use the same driver with the bindings
described here, with chip specific properties as noted.
Required properties supported by the device: Required properties supported by the device:
- "compatible": Should be one of the following:
- "compatible": must be "isil,isl1219" - "isil,isl1208"
- "isil,isl1209"
- "isil,isl1218"
- "isil,isl1219"
- "reg": I2C bus address of the device - "reg": I2C bus address of the device
Optional properties: Optional properties:
- "interrupt-names": list which may contains "irq" and "evdet" - "interrupt-names": list which may contains "irq" and "evdet"
evdet applies to isl1209 and isl1219 only
- "interrupts": list of interrupts for "irq" and "evdet" - "interrupts": list of interrupts for "irq" and "evdet"
- "isil,ev-evienb": if present EV.EVIENB bit is set to the specified evdet applies to isl1209 and isl1219 only
value for proper operation. - "isil,ev-evienb": Enable or disable internal pull on EVIN pin
Applies to isl1209 and isl1219 only
Possible values are 0 and 1
Example isl1219 node with #IRQ pin connected to SoC gpio1 pin12 Value 0 enables internal pull-up on evin pin, 1 disables it.
and #EVDET pin connected to SoC gpio2 pin 24: Default will leave the non-volatile configuration of the pullup
as is.
Example isl1219 node with #IRQ pin connected to SoC gpio1 pin12 and #EVDET pin
connected to SoC gpio2 pin 24 and internal pull-up enabled in EVIN pin.
isl1219: rtc@68 { isl1219: rtc@68 {
compatible = "isil,isl1219"; compatible = "isil,isl1219";
......
* NXP PCF85063 Real Time Clock
Required properties:
- compatible: Should contain "nxp,pcf85063".
- reg: I2C address for chip.
Optional property:
- quartz-load-femtofarads: The capacitive load of the quartz(x-tal),
expressed in femto Farad (fF). Valid values are 7000 and 12500.
Default value (if no value is specified) is 7000fF.
Example:
pcf85063: rtc@51 {
compatible = "nxp,pcf85063";
reg = <0x51>;
quartz-load-femtofarads = <12500>;
};
* NXP PCF8523 Real Time Clock
Required properties:
- compatible: Should contain "nxp,pcf8523".
- reg: I2C address for chip.
Optional property:
- quartz-load-femtofarads: The capacitive load of the quartz(x-tal),
expressed in femto Farad (fF). Valid values are 7000 and 12500.
Default value (if no value is specified) is 12500fF.
Example:
pcf8523: rtc@68 {
compatible = "nxp,pcf8523";
reg = <0x68>;
quartz-load-femtofarads = <7000>;
};
* Amlogic Meson6, Meson8, Meson8b and Meson8m2 RTC
Required properties:
- compatible: should be one of the following describing the hardware:
* "amlogic,meson6-rtc"
* "amlogic,meson8-rtc"
* "amlogic,meson8b-rtc"
* "amlogic,meson8m2-rtc"
- reg: physical register space for the controller's memory mapped registers.
- interrupts: the interrupt line of the RTC block.
- clocks: reference to the external 32.768kHz crystal oscillator.
- vdd-supply: reference to the power supply of the RTC block.
- resets: reset controller reference to allow reset of the controller
Optional properties for the battery-backed non-volatile memory:
- #address-cells: should be 1 to address the battery-backed non-volatile memory
- #size-cells: should be 1 to reference the battery-backed non-volatile memory
Optional child nodes:
- see ../nvmem/nvmem.txt
Example:
rtc: rtc@740 {
compatible = "amlogic,meson6-rtc";
reg = <0x740 0x14>;
interrupts = <GIC_SPI 72 IRQ_TYPE_EDGE_RISING>;
clocks = <&rtc32k_xtal>;
vdd-supply = <&rtc_vdd>;
resets = <&reset RESET_RTC>;
#address-cells = <1>;
#size-cells = <1>;
};
...@@ -27,6 +27,10 @@ below. ...@@ -27,6 +27,10 @@ below.
given if internal trickle charger diode should be given if internal trickle charger diode should be
disabled disabled
- wakeup-source : Enables wake up of host system on alarm - wakeup-source : Enables wake up of host system on alarm
- quartz-load-femtofarads : The capacitive load of the quartz(x-tal),
expressed in femto Farad (fF).
The default value shall be listed (if optional),
and likewise all valid values.
Trivial RTCs Trivial RTCs
------------ ------------
...@@ -39,21 +43,23 @@ possibly an interrupt line. ...@@ -39,21 +43,23 @@ possibly an interrupt line.
Compatible Vendor / Chip Compatible Vendor / Chip
========== ============= ========== =============
abracon,abb5zes3 AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface abracon,abb5zes3 AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface
abracon,abeoz9 AB-RTCMC-32.768kHz-EOZ9: Real Time Clock/Calendar Module with I2C Interface
dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
dallas,ds1672 Dallas DS1672 Real-time Clock dallas,ds1672 Dallas DS1672 Real-time Clock
dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM
epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
epson,rx8571 I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM
epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
emmicro,em3027 EM Microelectronic EM3027 Real-time Clock emmicro,em3027 EM Microelectronic EM3027 Real-time Clock
isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM
isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM
isil,isl12022 Intersil ISL12022 Real-time Clock isil,isl12022 Intersil ISL12022 Real-time Clock
microcrystal,rv3028 Real Time Clock Module with I2C-Bus
microcrystal,rv3029 Real Time Clock Module with I2C-Bus microcrystal,rv3029 Real Time Clock Module with I2C-Bus
microcrystal,rv8523 Real Time Clock
nxp,pcf2127 Real-time clock nxp,pcf2127 Real-time clock
nxp,pcf2129 Real-time clock nxp,pcf2129 Real-time clock
nxp,pcf8523 Real-time Clock
nxp,pcf8563 Real-time clock/calendar nxp,pcf8563 Real-time clock/calendar
nxp,pcf85063 Tiny Real-Time Clock
pericom,pt7c4338 Real-time Clock Module pericom,pt7c4338 Real-time Clock Module
ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
...@@ -62,3 +68,4 @@ ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ...@@ -62,3 +68,4 @@ ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
sii,s35390a 2-wire CMOS real-time clock sii,s35390a 2-wire CMOS real-time clock
whwave,sd3078 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
...@@ -439,6 +439,7 @@ vot Vision Optical Technology Co., Ltd. ...@@ -439,6 +439,7 @@ vot Vision Optical Technology Co., Ltd.
wd Western Digital Corp. wd Western Digital Corp.
wetek WeTek Electronics, limited. wetek WeTek Electronics, limited.
wexler Wexler wexler Wexler
whwave Shenzhen whwave Electronics, Inc.
wi2wi Wi2Wi, Inc. wi2wi Wi2Wi, Inc.
winbond Winbond Electronics corp. winbond Winbond Electronics corp.
winstar Winstar Display Corp. winstar Winstar Display Corp.
......
...@@ -16697,6 +16697,12 @@ L: linux-gpio@vger.kernel.org ...@@ -16697,6 +16697,12 @@ L: linux-gpio@vger.kernel.org
S: Maintained S: Maintained
F: drivers/gpio/gpio-wcove.c F: drivers/gpio/gpio-wcove.c
WHWAVE RTC DRIVER
M: Dianlong Li <long17.cool@163.com>
L: linux-rtc@vger.kernel.org
S: Maintained
F: drivers/rtc/rtc-sd3078.c
WIIMOTE HID DRIVER WIIMOTE HID DRIVER
M: David Herrmann <dh.herrmann@googlemail.com> M: David Herrmann <dh.herrmann@googlemail.com>
L: linux-input@vger.kernel.org L: linux-input@vger.kernel.org
......
...@@ -185,6 +185,16 @@ config RTC_DRV_ABB5ZES3 ...@@ -185,6 +185,16 @@ config RTC_DRV_ABB5ZES3
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-ab-b5ze-s3. will be called rtc-ab-b5ze-s3.
config RTC_DRV_ABEOZ9
select REGMAP_I2C
tristate "Abracon AB-RTCMC-32.768kHz-EOZ9"
help
If you say yes here you get support for the Abracon
AB-RTCMC-32.768kHz-EOA9 I2C RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-ab-e0z9.
config RTC_DRV_ABX80X config RTC_DRV_ABX80X
tristate "Abracon ABx80x" tristate "Abracon ABx80x"
select WATCHDOG_CORE if WATCHDOG select WATCHDOG_CORE if WATCHDOG
...@@ -601,9 +611,10 @@ config RTC_DRV_RX8010 ...@@ -601,9 +611,10 @@ config RTC_DRV_RX8010
will be called rtc-rx8010. will be called rtc-rx8010.
config RTC_DRV_RX8581 config RTC_DRV_RX8581
tristate "Epson RX-8581" tristate "Epson RX-8571/RX-8581"
help help
If you say yes here you will get support for the Epson RX-8581. If you say yes here you will get support for the Epson RX-8571/
RX-8581.
This driver can also be built as a module. If so the module This driver can also be built as a module. If so the module
will be called rtc-rx8581. will be called rtc-rx8581.
...@@ -626,6 +637,15 @@ config RTC_DRV_EM3027 ...@@ -626,6 +637,15 @@ config RTC_DRV_EM3027
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-em3027. will be called rtc-em3027.
config RTC_DRV_RV3028
tristate "Micro Crystal RV3028"
help
If you say yes here you get support for the Micro Crystal
RV3028.
This driver can also be built as a module. If so, the module
will be called rtc-rv3028.
config RTC_DRV_RV8803 config RTC_DRV_RV8803
tristate "Micro Crystal RV8803, Epson RX8900" tristate "Micro Crystal RV8803, Epson RX8900"
help help
...@@ -646,6 +666,15 @@ config RTC_DRV_S5M ...@@ -646,6 +666,15 @@ config RTC_DRV_S5M
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-s5m. will be called rtc-s5m.
config RTC_DRV_SD3078
tristate "ZXW Crystal SD3078"
help
If you say yes here you get support for the ZXW Crystal
SD3078 RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-sd3078
endif # I2C endif # I2C
comment "SPI RTC drivers" comment "SPI RTC drivers"
...@@ -1285,6 +1314,17 @@ config RTC_DRV_IMXDI ...@@ -1285,6 +1314,17 @@ config RTC_DRV_IMXDI
This driver can also be built as a module, if so, the module This driver can also be built as a module, if so, the module
will be called "rtc-imxdi". will be called "rtc-imxdi".
config RTC_DRV_MESON
tristate "Amlogic Meson RTC"
depends on (ARM && ARCH_MESON) || COMPILE_TEST
select REGMAP_MMIO
help
Support for the RTC block on the Amlogic Meson6, Meson8, Meson8b
and Meson8m2 SoCs.
This driver can also be built as a module, if so, the module
will be called "rtc-meson".
config RTC_DRV_OMAP config RTC_DRV_OMAP
tristate "TI OMAP Real Time Clock" tristate "TI OMAP Real Time Clock"
depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST
...@@ -1508,6 +1548,16 @@ config RTC_DRV_ARMADA38X ...@@ -1508,6 +1548,16 @@ config RTC_DRV_ARMADA38X
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called armada38x-rtc. will be called armada38x-rtc.
config RTC_DRV_CADENCE
tristate "Cadence RTC driver"
depends on OF && HAS_IOMEM
help
If you say Y here you will get access to Cadence RTC IP
found on certain SOCs.
To compile this driver as a module, choose M here: the
module will be called rtc-cadence.
config RTC_DRV_FTRTC010 config RTC_DRV_FTRTC010
tristate "Faraday Technology FTRTC010 RTC" tristate "Faraday Technology FTRTC010 RTC"
depends on HAS_IOMEM depends on HAS_IOMEM
...@@ -1679,6 +1729,7 @@ config RTC_DRV_SNVS ...@@ -1679,6 +1729,7 @@ config RTC_DRV_SNVS
config RTC_DRV_IMX_SC config RTC_DRV_IMX_SC
depends on IMX_SCU depends on IMX_SCU
depends on HAVE_ARM_SMCCC
tristate "NXP i.MX System Controller RTC support" tristate "NXP i.MX System Controller RTC support"
help help
If you say yes here you get support for the NXP i.MX System If you say yes here you get support for the NXP i.MX System
...@@ -1795,8 +1846,7 @@ comment "HID Sensor RTC drivers" ...@@ -1795,8 +1846,7 @@ comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME config RTC_DRV_HID_SENSOR_TIME
tristate "HID Sensor Time" tristate "HID Sensor Time"
depends on USB_HID depends on USB_HID
select IIO depends on HID_SENSOR_HUB && IIO
select HID_SENSOR_HUB
select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_COMMON
help help
Say yes here to build support for the HID Sensors of type Time. Say yes here to build support for the HID Sensors of type Time.
......
...@@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o ...@@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.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_ABX80X) += rtc-abx80x.o
obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
...@@ -39,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o ...@@ -39,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
obj-$(CONFIG_RTC_DRV_CADENCE) += rtc-cadence.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o
...@@ -100,6 +102,7 @@ obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o ...@@ -100,6 +102,7 @@ obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
...@@ -137,6 +140,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o ...@@ -137,6 +140,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RTD119X) += rtc-rtd119x.o obj-$(CONFIG_RTC_DRV_RTD119X) += rtc-rtd119x.o
obj-$(CONFIG_RTC_DRV_RV3028) += rtc-rv3028.o
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
...@@ -149,6 +153,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o ...@@ -149,6 +153,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
......
...@@ -178,11 +178,6 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ...@@ -178,11 +178,6 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
remove_wait_queue(&rtc->irq_queue, &wait); remove_wait_queue(&rtc->irq_queue, &wait);
if (ret == 0) { if (ret == 0) {
/* Check for any data updates */
if (rtc->ops->read_callback)
data = rtc->ops->read_callback(rtc->dev.parent,
data);
if (sizeof(int) != sizeof(long) && if (sizeof(int) != sizeof(long) &&
count == sizeof(unsigned int)) count == sizeof(unsigned int))
ret = put_user(data, (unsigned int __user *)buf) ?: ret = put_user(data, (unsigned int __user *)buf) ?:
......
...@@ -100,7 +100,7 @@ int rtc_valid_tm(struct rtc_time *tm) ...@@ -100,7 +100,7 @@ int rtc_valid_tm(struct rtc_time *tm)
if (tm->tm_year < 70 if (tm->tm_year < 70
|| ((unsigned)tm->tm_mon) >= 12 || ((unsigned)tm->tm_mon) >= 12
|| tm->tm_mday < 1 || tm->tm_mday < 1
|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) || tm->tm_mday > rtc_month_days(tm->tm_mon, ((unsigned)tm->tm_year + 1900))
|| ((unsigned)tm->tm_hour) >= 24 || ((unsigned)tm->tm_hour) >= 24
|| ((unsigned)tm->tm_min) >= 60 || ((unsigned)tm->tm_min) >= 60
|| ((unsigned)tm->tm_sec) >= 60) || ((unsigned)tm->tm_sec) >= 60)
...@@ -116,8 +116,8 @@ EXPORT_SYMBOL(rtc_valid_tm); ...@@ -116,8 +116,8 @@ EXPORT_SYMBOL(rtc_valid_tm);
*/ */
time64_t rtc_tm_to_time64(struct rtc_time *tm) time64_t rtc_tm_to_time64(struct rtc_time *tm)
{ {
return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, return mktime64(((unsigned)tm->tm_year + 1900), tm->tm_mon + 1,
tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
} }
EXPORT_SYMBOL(rtc_tm_to_time64); EXPORT_SYMBOL(rtc_tm_to_time64);
......
...@@ -114,12 +114,14 @@ static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -114,12 +114,14 @@ static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
unsigned char buf[4]; unsigned char buf[4];
unsigned long ticks, base, data; unsigned long ticks, base, data;
regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
/* load 32-bit read-only counter */ /* load 32-bit read-only counter */
regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
ticks = base + data; ticks = base + data;
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
...@@ -137,7 +139,8 @@ static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -137,7 +139,8 @@ static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* load 32-bit read-only counter */ /* load 32-bit read-only counter */
regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
base = ticks - data; base = ticks - data;
dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
...@@ -158,11 +161,13 @@ static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -158,11 +161,13 @@ static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
int ret; int ret;
regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4); regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
ticks = base + data; ticks = base + data;
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
...@@ -185,12 +190,14 @@ static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -185,12 +190,14 @@ static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0); regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0);
regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
/* load 32-bit read-only counter */ /* load 32-bit read-only counter */
regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
ticks = base + data; ticks = base + data;
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
......
...@@ -115,11 +115,13 @@ static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -115,11 +115,13 @@ static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm)
pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) |
(buf[5] << 8) | buf[7];
/* load 32-bit read-only counter */ /* load 32-bit read-only counter */
pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
ticks = base + data; ticks = base + data;
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
...@@ -145,7 +147,8 @@ static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -145,7 +147,8 @@ static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* load 32-bit read-only counter */ /* load 32-bit read-only counter */
pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
base = ticks - data; base = ticks - data;
dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
...@@ -170,10 +173,12 @@ static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -170,10 +173,12 @@ static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) |
(buf[5] << 8) | buf[7];
pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
ticks = base + data; ticks = base + data;
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
...@@ -198,11 +203,13 @@ static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -198,11 +203,13 @@ static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) |
(buf[5] << 8) | buf[7];
/* load 32-bit read-only counter */ /* load 32-bit read-only counter */
pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
ticks = base + data; ticks = base + data;
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
base, data, ticks); base, data, ticks);
......
This diff is collapsed.
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Copyright 2014-2015 Macq S.A. * Copyright 2014-2015 Macq S.A.
* *
* Author: Philippe De Muyter <phdm@macqel.be> * Author: Philippe De Muyter <phdm@macqel.be>
* Author: Alexandre Belloni <alexandre.belloni@free-electrons.com> * Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -46,6 +46,9 @@ ...@@ -46,6 +46,9 @@
#define ABX8XX_CTRL_ARST BIT(2) #define ABX8XX_CTRL_ARST BIT(2)
#define ABX8XX_CTRL_12_24 BIT(6) #define ABX8XX_CTRL_12_24 BIT(6)
#define ABX8XX_REG_CTRL2 0x11
#define ABX8XX_CTRL2_RSVD BIT(5)
#define ABX8XX_REG_IRQ 0x12 #define ABX8XX_REG_IRQ 0x12
#define ABX8XX_IRQ_AIE BIT(2) #define ABX8XX_IRQ_AIE BIT(2)
#define ABX8XX_IRQ_IM_1_4 (0x3 << 5) #define ABX8XX_IRQ_IM_1_4 (0x3 << 5)
...@@ -78,6 +81,9 @@ ...@@ -78,6 +81,9 @@
#define ABX8XX_REG_ID0 0x28 #define ABX8XX_REG_ID0 0x28
#define ABX8XX_REG_OUT_CTRL 0x30
#define ABX8XX_OUT_CTRL_EXDS BIT(4)
#define ABX8XX_REG_TRICKLE 0x20 #define ABX8XX_REG_TRICKLE 0x20
#define ABX8XX_TRICKLE_CHARGE_ENABLE 0xa0 #define ABX8XX_TRICKLE_CHARGE_ENABLE 0xa0
#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8 #define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
...@@ -86,7 +92,7 @@ ...@@ -86,7 +92,7 @@
static u8 trickle_resistors[] = {0, 3, 6, 11}; static u8 trickle_resistors[] = {0, 3, 6, 11};
enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
AB1801, AB1803, AB1804, AB1805, ABX80X}; AB1801, AB1803, AB1804, AB1805, RV1805, ABX80X};
struct abx80x_cap { struct abx80x_cap {
u16 pn; u16 pn;
...@@ -103,6 +109,7 @@ static struct abx80x_cap abx80x_caps[] = { ...@@ -103,6 +109,7 @@ static struct abx80x_cap abx80x_caps[] = {
[AB1803] = {.pn = 0x1803}, [AB1803] = {.pn = 0x1803},
[AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true}, [AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true},
[AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true}, [AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
[RV1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true},
[ABX80X] = {.pn = 0} [ABX80X] = {.pn = 0}
}; };
...@@ -723,6 +730,62 @@ static int abx80x_probe(struct i2c_client *client, ...@@ -723,6 +730,62 @@ static int abx80x_probe(struct i2c_client *client,
return -EIO; return -EIO;
} }
/* Configure RV1805 specifics */
if (part == RV1805) {
/*
* Avoid accidentally entering test mode. This can happen
* on the RV1805 in case the reserved bit 5 in control2
* register is set. RV-1805-C3 datasheet indicates that
* the bit should be cleared in section 11h - Control2.
*/
data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL2);
if (data < 0) {
dev_err(&client->dev,
"Unable to read control2 register\n");
return -EIO;
}
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL2,
data & ~ABX8XX_CTRL2_RSVD);
if (err < 0) {
dev_err(&client->dev,
"Unable to write control2 register\n");
return -EIO;
}
/*
* Avoid extra power leakage. The RV1805 uses smaller
* 10pin package and the EXTI input is not present.
* Disable it to avoid leakage.
*/
data = i2c_smbus_read_byte_data(client, ABX8XX_REG_OUT_CTRL);
if (data < 0) {
dev_err(&client->dev,
"Unable to read output control register\n");
return -EIO;
}
/*
* Write the configuration key register to enable access to
* the config2 register
*/
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY,
ABX8XX_CFG_KEY_MISC);
if (err < 0) {
dev_err(&client->dev,
"Unable to write configuration key\n");
return -EIO;
}
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OUT_CTRL,
data | ABX8XX_OUT_CTRL_EXDS);
if (err < 0) {
dev_err(&client->dev,
"Unable to write output control register\n");
return -EIO;
}
}
/* part autodetection */ /* part autodetection */
if (part == ABX80X) { if (part == ABX80X) {
for (i = 0; abx80x_caps[i].pn; i++) for (i = 0; abx80x_caps[i].pn; i++)
...@@ -826,7 +889,7 @@ static const struct i2c_device_id abx80x_id[] = { ...@@ -826,7 +889,7 @@ static const struct i2c_device_id abx80x_id[] = {
{ "ab1803", AB1803 }, { "ab1803", AB1803 },
{ "ab1804", AB1804 }, { "ab1804", AB1804 },
{ "ab1805", AB1805 }, { "ab1805", AB1805 },
{ "rv1805", AB1805 }, { "rv1805", RV1805 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, abx80x_id); MODULE_DEVICE_TABLE(i2c, abx80x_id);
...@@ -843,6 +906,6 @@ static struct i2c_driver abx80x_driver = { ...@@ -843,6 +906,6 @@ static struct i2c_driver abx80x_driver = {
module_i2c_driver(abx80x_driver); module_i2c_driver(abx80x_driver);
MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>"); MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
MODULE_DESCRIPTION("Abracon ABX80X RTC driver"); MODULE_DESCRIPTION("Abracon ABX80X RTC driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
This diff is collapsed.
...@@ -235,9 +235,13 @@ static int coh901331_suspend(struct device *dev) ...@@ -235,9 +235,13 @@ static int coh901331_suspend(struct device *dev)
static int coh901331_resume(struct device *dev) static int coh901331_resume(struct device *dev)
{ {
int ret;
struct coh901331_port *rtap = dev_get_drvdata(dev); struct coh901331_port *rtap = dev_get_drvdata(dev);
clk_prepare(rtap->clk); ret = clk_prepare(rtap->clk);
if (ret)
return ret;
if (device_may_wakeup(dev)) { if (device_may_wakeup(dev)) {
disable_irq_wake(rtap->irq); disable_irq_wake(rtap->irq);
} else { } else {
......
This diff is collapsed.
...@@ -58,7 +58,8 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -58,7 +58,8 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
"%s: raw read data - counters=%02x,%02x,%02x,%02x\n", "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
__func__, buf[0], buf[1], buf[2], buf[3]); __func__, buf[0], buf[1], buf[2], buf[3]);
time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; time = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0];
rtc_time_to_tm(time, tm); rtc_time_to_tm(time, tm);
......
...@@ -109,6 +109,8 @@ static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -109,6 +109,8 @@ static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
} }
ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf); ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf);
if (ret < 0)
return ret;
tm->tm_sec = bcd2bin(buf[0] & HYM8563_SEC_MASK); tm->tm_sec = bcd2bin(buf[0] & HYM8563_SEC_MASK);
tm->tm_min = bcd2bin(buf[1] & HYM8563_MIN_MASK); tm->tm_min = bcd2bin(buf[1] & HYM8563_MIN_MASK);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Copyright 2018 NXP. * Copyright 2018 NXP.
*/ */
#include <linux/arm-smccc.h>
#include <linux/firmware/imx/sci.h> #include <linux/firmware/imx/sci.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -12,6 +13,9 @@ ...@@ -12,6 +13,9 @@
#define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9 #define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9
#define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6 #define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6
#define IMX_SIP_SRTC 0xC2000002
#define IMX_SIP_SRTC_SET_TIME 0x0
static struct imx_sc_ipc *rtc_ipc_handle; static struct imx_sc_ipc *rtc_ipc_handle;
static struct rtc_device *imx_sc_rtc; static struct rtc_device *imx_sc_rtc;
...@@ -37,13 +41,28 @@ static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -37,13 +41,28 @@ static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)
return ret; return ret;
} }
rtc_time_to_tm(msg.time, tm); rtc_time64_to_tm(msg.time, tm);
return 0; return 0;
} }
static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct arm_smccc_res res;
/* pack 2 time parameters into 1 register, 16 bits for each */
arm_smccc_smc(IMX_SIP_SRTC, IMX_SIP_SRTC_SET_TIME,
((tm->tm_year + 1900) << 16) | (tm->tm_mon + 1),
(tm->tm_mday << 16) | tm->tm_hour,
(tm->tm_min << 16) | tm->tm_sec,
0, 0, 0, &res);
return res.a0;
}
static const struct rtc_class_ops imx_sc_rtc_ops = { static const struct rtc_class_ops imx_sc_rtc_ops = {
.read_time = imx_sc_rtc_read_time, .read_time = imx_sc_rtc_read_time,
.set_time = imx_sc_rtc_set_time,
}; };
static int imx_sc_rtc_probe(struct platform_device *pdev) static int imx_sc_rtc_probe(struct platform_device *pdev)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -73,10 +74,50 @@ ...@@ -73,10 +74,50 @@
static struct i2c_driver isl1208_driver; static struct i2c_driver isl1208_driver;
/* ISL1208 various variants */ /* ISL1208 various variants */
enum { enum isl1208_id {
TYPE_ISL1208 = 0, TYPE_ISL1208 = 0,
TYPE_ISL1209,
TYPE_ISL1218, TYPE_ISL1218,
TYPE_ISL1219, TYPE_ISL1219,
ISL_LAST_ID
};
/* Chip capabilities table */
static const struct isl1208_config {
const char name[8];
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 },
};
static const struct i2c_device_id isl1208_id[] = {
{ "isl1208", TYPE_ISL1208 },
{ "isl1209", TYPE_ISL1209 },
{ "isl1218", TYPE_ISL1218 },
{ "isl1219", TYPE_ISL1219 },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl1208_id);
static const 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] },
{ }
};
MODULE_DEVICE_TABLE(of, isl1208_of_match);
/* Device state */
struct isl1208_state {
struct nvmem_config nvmem_config;
struct rtc_device *rtc;
const struct isl1208_config *config;
}; };
/* block read */ /* block read */
...@@ -161,6 +202,7 @@ isl1208_i2c_get_atr(struct i2c_client *client) ...@@ -161,6 +202,7 @@ isl1208_i2c_get_atr(struct i2c_client *client)
return atr; return atr;
} }
/* returns adjustment value + 100 */
static int static int
isl1208_i2c_get_dtr(struct i2c_client *client) isl1208_i2c_get_dtr(struct i2c_client *client)
{ {
...@@ -171,7 +213,7 @@ isl1208_i2c_get_dtr(struct i2c_client *client) ...@@ -171,7 +213,7 @@ isl1208_i2c_get_dtr(struct i2c_client *client)
/* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1); dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1);
return dtr; return dtr + 100;
} }
static int static int
...@@ -248,8 +290,8 @@ isl1208_rtc_proc(struct device *dev, struct seq_file *seq) ...@@ -248,8 +290,8 @@ isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
(sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
dtr = isl1208_i2c_get_dtr(client); dtr = isl1208_i2c_get_dtr(client);
if (dtr >= 0 - 1) if (dtr >= 0)
seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); seq_printf(seq, "digital_trim\t: %d ppm\n", dtr - 100);
atr = isl1208_i2c_get_atr(client); atr = isl1208_i2c_get_atr(client);
if (atr >= 0) if (atr >= 0)
...@@ -556,7 +598,7 @@ isl1208_rtc_interrupt(int irq, void *data) ...@@ -556,7 +598,7 @@ isl1208_rtc_interrupt(int irq, void *data)
{ {
unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned long timeout = jiffies + msecs_to_jiffies(1000);
struct i2c_client *client = data; struct i2c_client *client = data;
struct rtc_device *rtc = i2c_get_clientdata(client); struct isl1208_state *isl1208 = i2c_get_clientdata(client);
int handled = 0, sr, err; int handled = 0, sr, err;
/* /*
...@@ -579,7 +621,7 @@ isl1208_rtc_interrupt(int irq, void *data) ...@@ -579,7 +621,7 @@ isl1208_rtc_interrupt(int irq, void *data)
if (sr & ISL1208_REG_SR_ALM) { if (sr & ISL1208_REG_SR_ALM) {
dev_dbg(&client->dev, "alarm!\n"); dev_dbg(&client->dev, "alarm!\n");
rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); rtc_update_irq(isl1208->rtc, 1, RTC_IRQF | RTC_AF);
/* Clear the alarm */ /* Clear the alarm */
sr &= ~ISL1208_REG_SR_ALM; sr &= ~ISL1208_REG_SR_ALM;
...@@ -596,11 +638,12 @@ isl1208_rtc_interrupt(int irq, void *data) ...@@ -596,11 +638,12 @@ isl1208_rtc_interrupt(int irq, void *data)
return err; return err;
} }
if (sr & ISL1208_REG_SR_EVT) { if (isl1208->config->has_tamper && (sr & ISL1208_REG_SR_EVT)) {
sysfs_notify(&rtc->dev.kobj, NULL,
dev_attr_timestamp0.attr.name);
dev_warn(&client->dev, "event detected"); dev_warn(&client->dev, "event detected");
handled = 1; handled = 1;
if (isl1208->config->has_timestamp)
sysfs_notify(&isl1208->rtc->dev.kobj, NULL,
dev_attr_timestamp0.attr.name);
} }
return handled ? IRQ_HANDLED : IRQ_NONE; return handled ? IRQ_HANDLED : IRQ_NONE;
...@@ -637,7 +680,7 @@ isl1208_sysfs_show_dtrim(struct device *dev, ...@@ -637,7 +680,7 @@ isl1208_sysfs_show_dtrim(struct device *dev,
if (dtr < 0) if (dtr < 0)
return dtr; return dtr;
return sprintf(buf, "%d ppm\n", dtr); return sprintf(buf, "%d ppm\n", dtr - 100);
} }
static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
...@@ -700,6 +743,46 @@ static const struct attribute_group isl1219_rtc_sysfs_files = { ...@@ -700,6 +743,46 @@ static const struct attribute_group isl1219_rtc_sysfs_files = {
.attrs = isl1219_rtc_attrs, .attrs = isl1219_rtc_attrs,
}; };
static int isl1208_nvmem_read(void *priv, unsigned int off, void *buf,
size_t count)
{
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,
count);
return ret == 0 ? count : ret;
}
static int isl1208_nvmem_write(void *priv, unsigned int off, void *buf,
size_t count)
{
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;
}
static const struct nvmem_config isl1208_nvmem_config = {
.name = "isl1208_nvram",
.word_size = 1,
.stride = 1,
/* .size from chip specific config */
.reg_read = isl1208_nvmem_read,
.reg_write = isl1208_nvmem_write,
};
static int isl1208_setup_irq(struct i2c_client *client, int irq) static int isl1208_setup_irq(struct i2c_client *client, int irq)
{ {
int rc = devm_request_threaded_irq(&client->dev, irq, NULL, int rc = devm_request_threaded_irq(&client->dev, irq, NULL,
...@@ -722,7 +805,7 @@ static int ...@@ -722,7 +805,7 @@ static int
isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ {
int rc = 0; int rc = 0;
struct rtc_device *rtc; struct isl1208_state *isl1208;
int evdet_irq = -1; int evdet_irq = -1;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
...@@ -731,13 +814,33 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -731,13 +814,33 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (isl1208_i2c_validate_client(client) < 0) if (isl1208_i2c_validate_client(client) < 0)
return -ENODEV; return -ENODEV;
rtc = devm_rtc_allocate_device(&client->dev); /* Allocate driver state, point i2c client data to it */
if (IS_ERR(rtc)) isl1208 = devm_kzalloc(&client->dev, sizeof(*isl1208), GFP_KERNEL);
return PTR_ERR(rtc); if (!isl1208)
return -ENOMEM;
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 {
if (id->driver_data >= ISL_LAST_ID)
return -ENODEV;
isl1208->config = &isl1208_configs[id->driver_data];
}
isl1208->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(isl1208->rtc))
return PTR_ERR(isl1208->rtc);
rtc->ops = &isl1208_rtc_ops; isl1208->rtc->ops = &isl1208_rtc_ops;
i2c_set_clientdata(client, rtc); /* Setup nvmem configuration in driver state struct */
isl1208->nvmem_config = isl1208_nvmem_config;
isl1208->nvmem_config.size = isl1208->config->nvmem_length;
isl1208->nvmem_config.priv = isl1208;
rc = isl1208_i2c_get_sr(client); rc = isl1208_i2c_get_sr(client);
if (rc < 0) { if (rc < 0) {
...@@ -749,7 +852,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -749,7 +852,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_warn(&client->dev, "rtc power failure detected, " dev_warn(&client->dev, "rtc power failure detected, "
"please set clock.\n"); "please set clock.\n");
if (id->driver_data == TYPE_ISL1219) { if (isl1208->config->has_tamper) {
struct device_node *np = client->dev.of_node; struct device_node *np = client->dev.of_node;
u32 evienb; u32 evienb;
...@@ -770,13 +873,15 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -770,13 +873,15 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_err(&client->dev, "could not enable tamper detection\n"); dev_err(&client->dev, "could not enable tamper detection\n");
return rc; return rc;
} }
rc = rtc_add_group(rtc, &isl1219_rtc_sysfs_files); evdet_irq = of_irq_get_byname(np, "evdet");
}
if (isl1208->config->has_timestamp) {
rc = rtc_add_group(isl1208->rtc, &isl1219_rtc_sysfs_files);
if (rc) if (rc)
return rc; return rc;
evdet_irq = of_irq_get_byname(np, "evdet");
} }
rc = rtc_add_group(rtc, &isl1208_rtc_sysfs_files); rc = rtc_add_group(isl1208->rtc, &isl1208_rtc_sysfs_files);
if (rc) if (rc)
return rc; return rc;
...@@ -790,24 +895,12 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -790,24 +895,12 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (rc) if (rc)
return rc; return rc;
return rtc_register_device(rtc); rc = rtc_nvmem_register(isl1208->rtc, &isl1208->nvmem_config);
} if (rc)
return rc;
static const struct i2c_device_id isl1208_id[] = {
{ "isl1208", TYPE_ISL1208 },
{ "isl1218", TYPE_ISL1218 },
{ "isl1219", TYPE_ISL1219 },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl1208_id);
static const struct of_device_id isl1208_of_match[] = { return rtc_register_device(isl1208->rtc);
{ .compatible = "isil,isl1208" }, }
{ .compatible = "isil,isl1218" },
{ .compatible = "isil,isl1219" },
{ }
};
MODULE_DEVICE_TABLE(of, isl1208_of_match);
static struct i2c_driver isl1208_driver = { static struct i2c_driver isl1208_driver = {
.driver = { .driver = {
......
...@@ -82,7 +82,7 @@ unsigned int mc146818_get_time(struct rtc_time *time) ...@@ -82,7 +82,7 @@ unsigned int mc146818_get_time(struct rtc_time *time)
time->tm_year += real_year - 72; time->tm_year += real_year - 72;
#endif #endif
if (century) if (century > 20)
time->tm_year += (century - 19) * 100; time->tm_year += (century - 19) * 100;
/* /*
......
This diff is collapsed.
...@@ -27,17 +27,11 @@ ...@@ -27,17 +27,11 @@
*/ */
#define PCF85063_REG_CTRL1 0x00 /* status */ #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_STOP BIT(5)
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_REG_SC 0x04 /* datetime */ #define PCF85063_REG_SC 0x04 /* datetime */
#define PCF85063_REG_SC_OS 0x80 #define PCF85063_REG_SC_OS 0x80
#define PCF85063_REG_MN 0x05
#define PCF85063_REG_HR 0x06
#define PCF85063_REG_DM 0x07
#define PCF85063_REG_DW 0x08
#define PCF85063_REG_MO 0x09
#define PCF85063_REG_YR 0x0A
static struct i2c_driver pcf85063_driver; static struct i2c_driver pcf85063_driver;
...@@ -180,6 +174,39 @@ static const struct rtc_class_ops pcf85063_rtc_ops = { ...@@ -180,6 +174,39 @@ static const struct rtc_class_ops pcf85063_rtc_ops = {
.set_time = pcf85063_rtc_set_time .set_time = pcf85063_rtc_set_time
}; };
static int pcf85063_load_capacitance(struct i2c_client *client)
{
u32 load;
int rc;
u8 reg;
rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
if (rc < 0)
return rc;
reg = rc;
load = 7000;
of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads",
&load);
switch (load) {
default:
dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
load);
/* fall through */
case 7000:
reg &= ~PCF85063_REG_CTRL1_CAP_SEL;
break;
case 12500:
reg |= PCF85063_REG_CTRL1_CAP_SEL;
break;
}
rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg);
return rc;
}
static int pcf85063_probe(struct i2c_client *client, static int pcf85063_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -197,6 +224,11 @@ static int pcf85063_probe(struct i2c_client *client, ...@@ -197,6 +224,11 @@ static int pcf85063_probe(struct i2c_client *client,
return err; return err;
} }
err = pcf85063_load_capacitance(client);
if (err < 0)
dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
err);
rtc = devm_rtc_device_register(&client->dev, rtc = devm_rtc_device_register(&client->dev,
pcf85063_driver.driver.name, pcf85063_driver.driver.name,
&pcf85063_rtc_ops, THIS_MODULE); &pcf85063_rtc_ops, THIS_MODULE);
......
...@@ -97,8 +97,9 @@ static int pcf8523_voltage_low(struct i2c_client *client) ...@@ -97,8 +97,9 @@ static int pcf8523_voltage_low(struct i2c_client *client)
return !!(value & REG_CONTROL3_BLF); return !!(value & REG_CONTROL3_BLF);
} }
static int pcf8523_select_capacitance(struct i2c_client *client, bool high) static int pcf8523_load_capacitance(struct i2c_client *client)
{ {
u32 load;
u8 value; u8 value;
int err; int err;
...@@ -106,14 +107,24 @@ static int pcf8523_select_capacitance(struct i2c_client *client, bool high) ...@@ -106,14 +107,24 @@ static int pcf8523_select_capacitance(struct i2c_client *client, bool high)
if (err < 0) if (err < 0)
return err; return err;
if (!high) load = 12500;
value &= ~REG_CONTROL1_CAP_SEL; of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads",
else &load);
switch (load) {
default:
dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500",
load);
/* fall through */
case 12500:
value |= REG_CONTROL1_CAP_SEL; value |= REG_CONTROL1_CAP_SEL;
break;
case 7000:
value &= ~REG_CONTROL1_CAP_SEL;
break;
}
err = pcf8523_write(client, REG_CONTROL1, value); err = pcf8523_write(client, REG_CONTROL1, value);
if (err < 0)
return err;
return err; return err;
} }
...@@ -347,9 +358,10 @@ static int pcf8523_probe(struct i2c_client *client, ...@@ -347,9 +358,10 @@ static int pcf8523_probe(struct i2c_client *client,
if (!pcf) if (!pcf)
return -ENOMEM; return -ENOMEM;
err = pcf8523_select_capacitance(client, true); err = pcf8523_load_capacitance(client);
if (err < 0) if (err < 0)
return err; dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
err);
err = pcf8523_set_pm(client, 0); err = pcf8523_set_pm(client, 0);
if (err < 0) if (err < 0)
...@@ -374,6 +386,7 @@ MODULE_DEVICE_TABLE(i2c, pcf8523_id); ...@@ -374,6 +386,7 @@ MODULE_DEVICE_TABLE(i2c, pcf8523_id);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id pcf8523_of_match[] = { static const struct of_device_id pcf8523_of_match[] = {
{ .compatible = "nxp,pcf8523" }, { .compatible = "nxp,pcf8523" },
{ .compatible = "microcrystal,rv8523" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, pcf8523_of_match); MODULE_DEVICE_TABLE(of, pcf8523_of_match);
......
// SPDX-License-Identifier: GPL-2.0+
/* /*
* PIC32 RTC driver * PIC32 RTC driver
* *
* Joshua Henderson <joshua.henderson@microchip.com> * Joshua Henderson <joshua.henderson@microchip.com>
* Copyright (C) 2016 Microchip Technology Inc. All rights reserved. * Copyright (C) 2016 Microchip Technology Inc. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -180,22 +172,16 @@ static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm) ...@@ -180,22 +172,16 @@ static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm)
{ {
struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
void __iomem *base = pdata->reg_base; void __iomem *base = pdata->reg_base;
int year = tm->tm_year - 100;
dev_dbg(dev, "set time %ptR\n", tm); dev_dbg(dev, "set time %ptR\n", tm);
if (year < 0 || year >= 100) {
dev_err(dev, "rtc only supports 100 years\n");
return -EINVAL;
}
clk_enable(pdata->clk); clk_enable(pdata->clk);
writeb(bin2bcd(tm->tm_sec), base + PIC32_RTCSEC); writeb(bin2bcd(tm->tm_sec), base + PIC32_RTCSEC);
writeb(bin2bcd(tm->tm_min), base + PIC32_RTCMIN); writeb(bin2bcd(tm->tm_min), base + PIC32_RTCMIN);
writeb(bin2bcd(tm->tm_hour), base + PIC32_RTCHOUR); writeb(bin2bcd(tm->tm_hour), base + PIC32_RTCHOUR);
writeb(bin2bcd(tm->tm_mday), base + PIC32_RTCDAY); writeb(bin2bcd(tm->tm_mday), base + PIC32_RTCDAY);
writeb(bin2bcd(tm->tm_mon + 1), base + PIC32_RTCMON); writeb(bin2bcd(tm->tm_mon + 1), base + PIC32_RTCMON);
writeb(bin2bcd(year), base + PIC32_RTCYEAR); writeb(bin2bcd(tm->tm_year - 100), base + PIC32_RTCYEAR);
clk_disable(pdata->clk); clk_disable(pdata->clk);
return 0; return 0;
...@@ -348,13 +334,17 @@ static int pic32_rtc_probe(struct platform_device *pdev) ...@@ -348,13 +334,17 @@ static int pic32_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1); device_init_wakeup(&pdev->dev, 1);
pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
&pic32_rtcops, if (IS_ERR(pdata->rtc))
THIS_MODULE); return PTR_ERR(pdata->rtc);
if (IS_ERR(pdata->rtc)) {
ret = PTR_ERR(pdata->rtc); pdata->rtc->ops = &pic32_rtcops;
pdata->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
pdata->rtc->range_max = RTC_TIMESTAMP_END_2099;
ret = rtc_register_device(pdata->rtc);
if (ret)
goto err_nortc; goto err_nortc;
}
pdata->rtc->max_user_freq = 128; pdata->rtc->max_user_freq = 128;
......
...@@ -213,7 +213,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -213,7 +213,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
} }
} }
secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); secs = value[0] | (value[1] << 8) | (value[2] << 16) |
((unsigned long)value[3] << 24);
rtc_time_to_tm(secs, tm); rtc_time_to_tm(secs, tm);
...@@ -284,7 +285,8 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ...@@ -284,7 +285,8 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
return rc; return rc;
} }
secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); secs = value[0] | (value[1] << 8) | (value[2] << 16) |
((unsigned long)value[3] << 24);
rtc_time_to_tm(secs, &alarm->time); rtc_time_to_tm(secs, &alarm->time);
......
...@@ -52,8 +52,10 @@ ...@@ -52,8 +52,10 @@
# define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */ # define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */
#define RS5C_REG_CTRL2 15 #define RS5C_REG_CTRL2 15
# define RS5C372_CTRL2_24 (1 << 5) # define RS5C372_CTRL2_24 (1 << 5)
# define R2025_CTRL2_XST (1 << 5) # define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2x2x */
# define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2025S/D */ # define R2x2x_CTRL2_VDET (1 << 6) /* only if R2x2x */
# define R2x2x_CTRL2_XSTP (1 << 5) /* only if R2x2x */
# define R2x2x_CTRL2_PON (1 << 4) /* only if R2x2x */
# define RS5C_CTRL2_CTFG (1 << 2) # define RS5C_CTRL2_CTFG (1 << 2)
# define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */ # define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */
# define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */ # define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */
...@@ -212,10 +214,27 @@ static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -212,10 +214,27 @@ static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct rs5c372 *rs5c = i2c_get_clientdata(client); struct rs5c372 *rs5c = i2c_get_clientdata(client);
int status = rs5c_get_regs(rs5c); int status = rs5c_get_regs(rs5c);
unsigned char ctrl2 = rs5c->regs[RS5C_REG_CTRL2];
if (status < 0) if (status < 0)
return status; return status;
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
(rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) {
dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
return -EINVAL;
}
break;
default:
if (ctrl2 & RS5C_CTRL2_XSTP) {
dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
return -EINVAL;
}
}
tm->tm_sec = bcd2bin(rs5c->regs[RS5C372_REG_SECS] & 0x7f); tm->tm_sec = bcd2bin(rs5c->regs[RS5C372_REG_SECS] & 0x7f);
tm->tm_min = bcd2bin(rs5c->regs[RS5C372_REG_MINS] & 0x7f); tm->tm_min = bcd2bin(rs5c->regs[RS5C372_REG_MINS] & 0x7f);
tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]); tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]);
...@@ -243,6 +262,7 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -243,6 +262,7 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct rs5c372 *rs5c = i2c_get_clientdata(client); struct rs5c372 *rs5c = i2c_get_clientdata(client);
unsigned char buf[7]; unsigned char buf[7];
unsigned char ctrl2;
int addr; int addr;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
...@@ -261,7 +281,32 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -261,7 +281,32 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[6] = bin2bcd(tm->tm_year - 100); buf[6] = bin2bcd(tm->tm_year - 100);
if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) { if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
dev_err(&client->dev, "%s: write error\n", __func__); dev_dbg(&client->dev, "%s: write error in line %i\n",
__func__, __LINE__);
return -EIO;
}
addr = RS5C_ADDR(RS5C_REG_CTRL2);
ctrl2 = i2c_smbus_read_byte_data(client, addr);
/* clear rtc warning bits */
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
ctrl2 &= ~(R2x2x_CTRL2_VDET | R2x2x_CTRL2_PON);
if (rs5c->type == rtc_r2025sd)
ctrl2 |= R2x2x_CTRL2_XSTP;
else
ctrl2 &= ~R2x2x_CTRL2_XSTP;
break;
default:
ctrl2 &= ~RS5C_CTRL2_XSTP;
break;
}
if (i2c_smbus_write_byte_data(client, addr, ctrl2) < 0) {
dev_dbg(&client->dev, "%s: write error in line %i\n",
__func__, __LINE__);
return -EIO; return -EIO;
} }
...@@ -519,20 +564,25 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372) ...@@ -519,20 +564,25 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
unsigned char buf[2]; unsigned char buf[2];
int addr, i, ret = 0; int addr, i, ret = 0;
if (rs5c372->type == rtc_r2025sd) {
if (rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST)
return ret;
rs5c372->regs[RS5C_REG_CTRL2] |= R2025_CTRL2_XST;
} else {
if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP))
return ret;
rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
}
addr = RS5C_ADDR(RS5C_REG_CTRL1); addr = RS5C_ADDR(RS5C_REG_CTRL1);
buf[0] = rs5c372->regs[RS5C_REG_CTRL1]; buf[0] = rs5c372->regs[RS5C_REG_CTRL1];
buf[1] = rs5c372->regs[RS5C_REG_CTRL2]; buf[1] = rs5c372->regs[RS5C_REG_CTRL2];
switch (rs5c372->type) {
case rtc_r2025sd:
if (buf[1] & R2x2x_CTRL2_XSTP)
return ret;
break;
case rtc_r2221tl:
if (!(buf[1] & R2x2x_CTRL2_XSTP))
return ret;
break;
default:
if (!(buf[1] & RS5C_CTRL2_XSTP))
return ret;
break;
}
/* use 24hr mode */ /* use 24hr mode */
switch (rs5c372->type) { switch (rs5c372->type) {
case rtc_rs5c372a: case rtc_rs5c372a:
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/* /*
* RTC driver for the Micro Crystal RV8803 * RTC driver for the Micro Crystal RV8803
* *
* Copyright (C) 2015 Micro Crystal SA * Copyright (C) 2015 Micro Crystal SA
* * Alexandre Belloni <alexandre.belloni@bootlin.com>
* Alexandre Belloni <alexandre.belloni@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* *
*/ */
...@@ -236,9 +232,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) ...@@ -236,9 +232,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
u8 date[7]; u8 date[7];
int ctrl, flags, ret; int ctrl, flags, ret;
if ((tm->tm_year < 100) || (tm->tm_year > 199))
return -EINVAL;
ctrl = rv8803_read_reg(rv8803->client, RV8803_CTRL); ctrl = rv8803_read_reg(rv8803->client, RV8803_CTRL);
if (ctrl < 0) if (ctrl < 0)
return ctrl; return ctrl;
...@@ -602,6 +595,8 @@ static int rv8803_probe(struct i2c_client *client, ...@@ -602,6 +595,8 @@ static int rv8803_probe(struct i2c_client *client,
rv8803->rtc->ops = &rv8803_rtc_ops; rv8803->rtc->ops = &rv8803_rtc_ops;
rv8803->rtc->nvram_old_abi = true; rv8803->rtc->nvram_old_abi = true;
rv8803->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rv8803->rtc->range_max = RTC_TIMESTAMP_END_2099;
err = rtc_register_device(rv8803->rtc); err = rtc_register_device(rv8803->rtc);
if (err) if (err)
return err; return err;
...@@ -648,6 +643,6 @@ static struct i2c_driver rv8803_driver = { ...@@ -648,6 +643,6 @@ static struct i2c_driver rv8803_driver = {
}; };
module_i2c_driver(rv8803_driver); module_i2c_driver(rv8803_driver);
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
MODULE_DESCRIPTION("Micro Crystal RV8803 RTC driver"); MODULE_DESCRIPTION("Micro Crystal RV8803 RTC driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/log2.h> #include <linux/log2.h>
...@@ -51,11 +53,19 @@ ...@@ -51,11 +53,19 @@
#define RX8581_CTRL_STOP 0x02 /* STOP bit */ #define RX8581_CTRL_STOP 0x02 /* STOP bit */
#define RX8581_CTRL_RESET 0x01 /* RESET bit */ #define RX8581_CTRL_RESET 0x01 /* RESET bit */
#define RX8571_USER_RAM 0x10
#define RX8571_NVRAM_SIZE 0x10
struct rx8581 { struct rx8581 {
struct regmap *regmap; struct regmap *regmap;
struct rtc_device *rtc; struct rtc_device *rtc;
}; };
struct rx85x1_config {
struct regmap_config regmap;
unsigned int num_nvram;
};
/* /*
* In the routines that deal directly with the rx8581 hardware, we use * In the routines that deal directly with the rx8581 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
...@@ -181,25 +191,103 @@ static const struct rtc_class_ops rx8581_rtc_ops = { ...@@ -181,25 +191,103 @@ static const struct rtc_class_ops rx8581_rtc_ops = {
.set_time = rx8581_rtc_set_time, .set_time = rx8581_rtc_set_time,
}; };
static int rx8581_probe(struct i2c_client *client, static int rx8571_nvram_read(void *priv, unsigned int offset, void *val,
const struct i2c_device_id *id) size_t bytes)
{ {
struct rx8581 *rx8581; struct rx8581 *rx8581 = priv;
static const struct regmap_config config = {
return regmap_bulk_read(rx8581->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;
return regmap_bulk_write(rx8581->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;
unsigned int tmp_val;
int ret;
ret = regmap_read(rx8581->regmap, RX8581_REG_RAM, &tmp_val);
(*(unsigned char *)val) = (unsigned char) tmp_val;
return ret;
}
static int rx85x1_nvram_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct rx8581 *rx8581 = priv;
unsigned char tmp_val;
tmp_val = *((unsigned char *)val);
return regmap_write(rx8581->regmap, RX8581_REG_RAM,
(unsigned int)tmp_val);
}
static const struct rx85x1_config rx8581_config = {
.regmap = {
.reg_bits = 8, .reg_bits = 8,
.val_bits = 8, .val_bits = 8,
.max_register = 0xf, .max_register = 0xf,
},
.num_nvram = 1
};
static const struct rx85x1_config rx8571_config = {
.regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x1f,
},
.num_nvram = 2
};
static int rx8581_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rx8581 *rx8581;
const struct rx85x1_config *config = &rx8581_config;
const void *data = of_device_get_match_data(&client->dev);
static struct nvmem_config nvmem_cfg[] = {
{
.name = "rx85x1-",
.word_size = 1,
.stride = 1,
.size = 1,
.reg_read = rx85x1_nvram_read,
.reg_write = rx85x1_nvram_write,
}, {
.name = "rx8571-",
.word_size = 1,
.stride = 1,
.size = RX8571_NVRAM_SIZE,
.reg_read = rx8571_nvram_read,
.reg_write = rx8571_nvram_write,
},
}; };
int ret, i;
dev_dbg(&client->dev, "%s\n", __func__); dev_dbg(&client->dev, "%s\n", __func__);
if (data)
config = data;
rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL); rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL);
if (!rx8581) if (!rx8581)
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(client, rx8581); i2c_set_clientdata(client, rx8581);
rx8581->regmap = devm_regmap_init_i2c(client, &config); rx8581->regmap = devm_regmap_init_i2c(client, &config->regmap);
if (IS_ERR(rx8581->regmap)) if (IS_ERR(rx8581->regmap))
return PTR_ERR(rx8581->regmap); return PTR_ERR(rx8581->regmap);
...@@ -213,7 +301,14 @@ static int rx8581_probe(struct i2c_client *client, ...@@ -213,7 +301,14 @@ static int rx8581_probe(struct i2c_client *client,
rx8581->rtc->start_secs = 0; rx8581->rtc->start_secs = 0;
rx8581->rtc->set_start_time = true; rx8581->rtc->set_start_time = true;
return rtc_register_device(rx8581->rtc); ret = rtc_register_device(rx8581->rtc);
for (i = 0; i < config->num_nvram; i++) {
nvmem_cfg[i].priv = rx8581;
rtc_nvmem_register(rx8581->rtc, &nvmem_cfg[i]);
}
return ret;
} }
static const struct i2c_device_id rx8581_id[] = { static const struct i2c_device_id rx8581_id[] = {
...@@ -223,8 +318,9 @@ static const struct i2c_device_id rx8581_id[] = { ...@@ -223,8 +318,9 @@ static const struct i2c_device_id rx8581_id[] = {
MODULE_DEVICE_TABLE(i2c, rx8581_id); MODULE_DEVICE_TABLE(i2c, rx8581_id);
static const struct of_device_id rx8581_of_match[] = { static const struct of_device_id rx8581_of_match[] = {
{ .compatible = "epson,rx8581" }, { .compatible = "epson,rx8571", .data = &rx8571_config },
{ } { .compatible = "epson,rx8581", .data = &rx8581_config },
{ /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, rx8581_of_match); MODULE_DEVICE_TABLE(of, rx8581_of_match);
...@@ -240,5 +336,5 @@ static struct i2c_driver rx8581_driver = { ...@@ -240,5 +336,5 @@ static struct i2c_driver rx8581_driver = {
module_i2c_driver(rx8581_driver); module_i2c_driver(rx8581_driver);
MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>"); MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
MODULE_DESCRIPTION("Epson RX-8581 RTC driver"); MODULE_DESCRIPTION("Epson RX-8571/RX-8581 RTC driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -39,7 +40,7 @@ struct s3c_rtc { ...@@ -39,7 +40,7 @@ struct s3c_rtc {
void __iomem *base; void __iomem *base;
struct clk *rtc_clk; struct clk *rtc_clk;
struct clk *rtc_src_clk; struct clk *rtc_src_clk;
bool clk_disabled; bool alarm_enabled;
const struct s3c_rtc_data *data; const struct s3c_rtc_data *data;
...@@ -47,7 +48,7 @@ struct s3c_rtc { ...@@ -47,7 +48,7 @@ struct s3c_rtc {
int irq_tick; int irq_tick;
spinlock_t pie_lock; spinlock_t pie_lock;
spinlock_t alarm_clk_lock; spinlock_t alarm_lock;
int ticnt_save; int ticnt_save;
int ticnt_en_save; int ticnt_en_save;
...@@ -70,44 +71,27 @@ struct s3c_rtc_data { ...@@ -70,44 +71,27 @@ struct s3c_rtc_data {
static int s3c_rtc_enable_clk(struct s3c_rtc *info) static int s3c_rtc_enable_clk(struct s3c_rtc *info)
{ {
unsigned long irq_flags; int ret;
int ret = 0;
spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
if (info->clk_disabled) {
ret = clk_enable(info->rtc_clk); ret = clk_enable(info->rtc_clk);
if (ret) if (ret)
goto out; return ret;
if (info->data->needs_src_clk) { if (info->data->needs_src_clk) {
ret = clk_enable(info->rtc_src_clk); ret = clk_enable(info->rtc_src_clk);
if (ret) { if (ret) {
clk_disable(info->rtc_clk); clk_disable(info->rtc_clk);
goto out; return ret;
}
} }
info->clk_disabled = false;
} }
return 0;
out:
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
return ret;
} }
static void s3c_rtc_disable_clk(struct s3c_rtc *info) static void s3c_rtc_disable_clk(struct s3c_rtc *info)
{ {
unsigned long irq_flags;
spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
if (!info->clk_disabled) {
if (info->data->needs_src_clk) if (info->data->needs_src_clk)
clk_disable(info->rtc_src_clk); clk_disable(info->rtc_src_clk);
clk_disable(info->rtc_clk); clk_disable(info->rtc_clk);
info->clk_disabled = true;
}
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
} }
/* IRQ Handlers */ /* IRQ Handlers */
...@@ -135,6 +119,7 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) ...@@ -135,6 +119,7 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
{ {
struct s3c_rtc *info = dev_get_drvdata(dev); struct s3c_rtc *info = dev_get_drvdata(dev);
unsigned long flags;
unsigned int tmp; unsigned int tmp;
int ret; int ret;
...@@ -151,17 +136,19 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) ...@@ -151,17 +136,19 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
writeb(tmp, info->base + S3C2410_RTCALM); writeb(tmp, info->base + S3C2410_RTCALM);
s3c_rtc_disable_clk(info); spin_lock_irqsave(&info->alarm_lock, flags);
if (enabled) { if (info->alarm_enabled && !enabled)
s3c_rtc_disable_clk(info);
else if (!info->alarm_enabled && enabled)
ret = s3c_rtc_enable_clk(info); ret = s3c_rtc_enable_clk(info);
if (ret)
return ret; info->alarm_enabled = enabled;
} else { spin_unlock_irqrestore(&info->alarm_lock, flags);
s3c_rtc_disable_clk(info); s3c_rtc_disable_clk(info);
}
return 0; return ret;
} }
/* Set RTC frequency */ /* Set RTC frequency */
...@@ -357,10 +344,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -357,10 +344,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
writeb(alrm_en, info->base + S3C2410_RTCALM); writeb(alrm_en, info->base + S3C2410_RTCALM);
s3c_rtc_disable_clk(info);
s3c_rtc_setaie(dev, alrm->enabled); s3c_rtc_setaie(dev, alrm->enabled);
s3c_rtc_disable_clk(info);
return 0; return 0;
} }
...@@ -456,16 +443,6 @@ static int s3c_rtc_remove(struct platform_device *pdev) ...@@ -456,16 +443,6 @@ static int s3c_rtc_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id s3c_rtc_dt_match[];
static const struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
return match->data;
}
static int s3c_rtc_probe(struct platform_device *pdev) static int s3c_rtc_probe(struct platform_device *pdev)
{ {
struct s3c_rtc *info = NULL; struct s3c_rtc *info = NULL;
...@@ -485,13 +462,13 @@ static int s3c_rtc_probe(struct platform_device *pdev) ...@@ -485,13 +462,13 @@ static int s3c_rtc_probe(struct platform_device *pdev)
} }
info->dev = &pdev->dev; info->dev = &pdev->dev;
info->data = s3c_rtc_get_data(pdev); info->data = of_device_get_match_data(&pdev->dev);
if (!info->data) { if (!info->data) {
dev_err(&pdev->dev, "failed getting s3c_rtc_data\n"); dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
return -EINVAL; return -EINVAL;
} }
spin_lock_init(&info->pie_lock); spin_lock_init(&info->pie_lock);
spin_lock_init(&info->alarm_clk_lock); spin_lock_init(&info->alarm_lock);
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
...@@ -591,6 +568,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) ...@@ -591,6 +568,8 @@ static int s3c_rtc_probe(struct platform_device *pdev)
s3c_rtc_setfreq(info, 1); s3c_rtc_setfreq(info, 1);
s3c_rtc_disable_clk(info);
return 0; return 0;
err_nortc: err_nortc:
......
This diff is collapsed.
...@@ -239,6 +239,9 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) ...@@ -239,6 +239,9 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id)
u32 lpsr; u32 lpsr;
u32 events = 0; u32 events = 0;
if (data->clk)
clk_enable(data->clk);
regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr);
if (lpsr & SNVS_LPSR_LPTA) { if (lpsr & SNVS_LPSR_LPTA) {
...@@ -253,6 +256,9 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) ...@@ -253,6 +256,9 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id)
/* clear interrupt status */ /* clear interrupt status */
regmap_write(data->regmap, data->offset + SNVS_LPSR, lpsr); regmap_write(data->regmap, data->offset + SNVS_LPSR, lpsr);
if (data->clk)
clk_disable(data->clk);
return events ? IRQ_HANDLED : IRQ_NONE; return events ? IRQ_HANDLED : IRQ_NONE;
} }
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* TX4939 internal RTC driver * TX4939 internal RTC driver
* Based on RBTX49xx patch from CELF patch archive. * Based on RBTX49xx patch from CELF patch archive.
* *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* (C) Copyright TOSHIBA CORPORATION 2005-2007 * (C) Copyright TOSHIBA CORPORATION 2005-2007
*/ */
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -65,10 +62,11 @@ static int tx4939_rtc_cmd(struct tx4939_rtc_reg __iomem *rtcreg, int cmd) ...@@ -65,10 +62,11 @@ static int tx4939_rtc_cmd(struct tx4939_rtc_reg __iomem *rtcreg, int cmd)
return 0; return 0;
} }
static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs) static int tx4939_rtc_set_time(struct device *dev, struct rtc_time *tm)
{ {
struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
unsigned long secs = rtc_tm_to_time64(tm);
int i, ret; int i, ret;
unsigned char buf[6]; unsigned char buf[6];
...@@ -111,7 +109,7 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -111,7 +109,7 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm)
spin_unlock_irq(&pdata->lock); spin_unlock_irq(&pdata->lock);
sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) |
(buf[3] << 8) | buf[2]; (buf[3] << 8) | buf[2];
rtc_time_to_tm(sec, tm); rtc_time64_to_tm(sec, tm);
return 0; return 0;
} }
...@@ -123,14 +121,7 @@ static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -123,14 +121,7 @@ static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
unsigned long sec; unsigned long sec;
unsigned char buf[6]; unsigned char buf[6];
if (alrm->time.tm_sec < 0 || sec = rtc_tm_to_time64(&alrm->time);
alrm->time.tm_min < 0 ||
alrm->time.tm_hour < 0 ||
alrm->time.tm_mday < 0 ||
alrm->time.tm_mon < 0 ||
alrm->time.tm_year < 0)
return -EINVAL;
rtc_tm_to_time(&alrm->time, &sec);
buf[0] = 0; buf[0] = 0;
buf[1] = 0; buf[1] = 0;
buf[2] = sec; buf[2] = sec;
...@@ -173,7 +164,7 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -173,7 +164,7 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
spin_unlock_irq(&pdata->lock); spin_unlock_irq(&pdata->lock);
sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) | sec = ((unsigned long)buf[5] << 24) | (buf[4] << 16) |
(buf[3] << 8) | buf[2]; (buf[3] << 8) | buf[2];
rtc_time_to_tm(sec, &alrm->time); rtc_time64_to_tm(sec, &alrm->time);
return rtc_valid_tm(&alrm->time); return rtc_valid_tm(&alrm->time);
} }
...@@ -210,7 +201,7 @@ static const struct rtc_class_ops tx4939_rtc_ops = { ...@@ -210,7 +201,7 @@ static const struct rtc_class_ops tx4939_rtc_ops = {
.read_time = tx4939_rtc_read_time, .read_time = tx4939_rtc_read_time,
.read_alarm = tx4939_rtc_read_alarm, .read_alarm = tx4939_rtc_read_alarm,
.set_alarm = tx4939_rtc_set_alarm, .set_alarm = tx4939_rtc_set_alarm,
.set_mmss = tx4939_rtc_set_mmss, .set_time = tx4939_rtc_set_time,
.alarm_irq_enable = tx4939_rtc_alarm_irq_enable, .alarm_irq_enable = tx4939_rtc_alarm_irq_enable,
}; };
...@@ -283,6 +274,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) ...@@ -283,6 +274,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
rtc->ops = &tx4939_rtc_ops; rtc->ops = &tx4939_rtc_ops;
rtc->nvram_old_abi = true; rtc->nvram_old_abi = true;
rtc->range_max = U32_MAX;
pdata->rtc = rtc; pdata->rtc = rtc;
...@@ -315,5 +307,5 @@ module_platform_driver_probe(tx4939_rtc_driver, tx4939_rtc_probe); ...@@ -315,5 +307,5 @@ module_platform_driver_probe(tx4939_rtc_driver, tx4939_rtc_probe);
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
MODULE_DESCRIPTION("TX4939 internal RTC driver"); MODULE_DESCRIPTION("TX4939 internal RTC driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:tx4939rtc"); MODULE_ALIAS("platform:tx4939rtc");
...@@ -49,7 +49,6 @@ ...@@ -49,7 +49,6 @@
#define RTC_CALIB_DEF 0x198233 #define RTC_CALIB_DEF 0x198233
#define RTC_CALIB_MASK 0x1FFFFF #define RTC_CALIB_MASK 0x1FFFFF
#define RTC_SEC_MAX_VAL 0xFFFFFFFF
struct xlnx_rtc_dev { struct xlnx_rtc_dev {
struct rtc_device *rtc; struct rtc_device *rtc;
...@@ -71,9 +70,6 @@ static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -71,9 +70,6 @@ static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
*/ */
new_time = rtc_tm_to_time64(tm) + 1; new_time = rtc_tm_to_time64(tm) + 1;
if (new_time > RTC_SEC_MAX_VAL)
return -EINVAL;
/* /*
* Writing into calibration register will clear the Tick Counter and * Writing into calibration register will clear the Tick Counter and
* force the next second to be signaled exactly in 1 second period * force the next second to be signaled exactly in 1 second period
...@@ -154,9 +150,6 @@ static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -154,9 +150,6 @@ static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
alarm_time = rtc_tm_to_time64(&alrm->time); alarm_time = rtc_tm_to_time64(&alrm->time);
if (alarm_time > RTC_SEC_MAX_VAL)
return -EINVAL;
writel((u32)alarm_time, (xrtcdev->reg_base + RTC_ALRM)); writel((u32)alarm_time, (xrtcdev->reg_base + RTC_ALRM));
xlnx_rtc_alarm_irq_enable(dev, alrm->enabled); xlnx_rtc_alarm_irq_enable(dev, alrm->enabled);
...@@ -222,6 +215,13 @@ static int xlnx_rtc_probe(struct platform_device *pdev) ...@@ -222,6 +215,13 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, xrtcdev); platform_set_drvdata(pdev, xrtcdev);
xrtcdev->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(xrtcdev->rtc))
return PTR_ERR(xrtcdev->rtc);
xrtcdev->rtc->ops = &xlnx_rtc_ops;
xrtcdev->rtc->range_max = U32_MAX;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xrtcdev->reg_base = devm_ioremap_resource(&pdev->dev, res); xrtcdev->reg_base = devm_ioremap_resource(&pdev->dev, res);
...@@ -263,9 +263,7 @@ static int xlnx_rtc_probe(struct platform_device *pdev) ...@@ -263,9 +263,7 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1); device_init_wakeup(&pdev->dev, 1);
xrtcdev->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, return rtc_register_device(xrtcdev->rtc);
&xlnx_rtc_ops, THIS_MODULE);
return PTR_ERR_OR_ZERO(xrtcdev->rtc);
} }
static int xlnx_rtc_remove(struct platform_device *pdev) static int xlnx_rtc_remove(struct platform_device *pdev)
......
...@@ -67,7 +67,7 @@ extern struct class *rtc_class; ...@@ -67,7 +67,7 @@ extern struct class *rtc_class;
* *
* The (current) exceptions are mostly filesystem hooks: * The (current) exceptions are mostly filesystem hooks:
* - the proc() hook for procfs * - the proc() hook for procfs
* - non-ioctl() chardev hooks: open(), release(), read_callback() * - non-ioctl() chardev hooks: open(), release()
* *
* REVISIT those periodic irq calls *do* have ops_lock when they're * REVISIT those periodic irq calls *do* have ops_lock when they're
* issued through ioctl() ... * issued through ioctl() ...
...@@ -81,7 +81,6 @@ struct rtc_class_ops { ...@@ -81,7 +81,6 @@ struct rtc_class_ops {
int (*proc)(struct device *, struct seq_file *); int (*proc)(struct device *, struct seq_file *);
int (*set_mmss64)(struct device *, time64_t secs); int (*set_mmss64)(struct device *, time64_t secs);
int (*set_mmss)(struct device *, unsigned long secs); int (*set_mmss)(struct device *, unsigned long secs);
int (*read_callback)(struct device *, int data);
int (*alarm_irq_enable)(struct device *, unsigned int enabled); int (*alarm_irq_enable)(struct device *, unsigned int enabled);
int (*read_offset)(struct device *, long *offset); int (*read_offset)(struct device *, long *offset);
int (*set_offset)(struct device *, long offset); int (*set_offset)(struct device *, long offset);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment