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);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Real Time Clock driver for AB-RTCMC-32.768kHz-EOZ9 chip.
* Copyright (C) 2019 Orolia
*
*/
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#define ABEOZ9_REG_CTRL1 0x00
#define ABEOZ9_REG_CTRL1_MASK GENMASK(7, 0)
#define ABEOZ9_REG_CTRL1_WE BIT(0)
#define ABEOZ9_REG_CTRL1_TE BIT(1)
#define ABEOZ9_REG_CTRL1_TAR BIT(2)
#define ABEOZ9_REG_CTRL1_EERE BIT(3)
#define ABEOZ9_REG_CTRL1_SRON BIT(4)
#define ABEOZ9_REG_CTRL1_TD0 BIT(5)
#define ABEOZ9_REG_CTRL1_TD1 BIT(6)
#define ABEOZ9_REG_CTRL1_CLKINT BIT(7)
#define ABEOZ9_REG_CTRL_INT 0x01
#define ABEOZ9_REG_CTRL_INT_AIE BIT(0)
#define ABEOZ9_REG_CTRL_INT_TIE BIT(1)
#define ABEOZ9_REG_CTRL_INT_V1IE BIT(2)
#define ABEOZ9_REG_CTRL_INT_V2IE BIT(3)
#define ABEOZ9_REG_CTRL_INT_SRIE BIT(4)
#define ABEOZ9_REG_CTRL_INT_FLAG 0x02
#define ABEOZ9_REG_CTRL_INT_FLAG_AF BIT(0)
#define ABEOZ9_REG_CTRL_INT_FLAG_TF BIT(1)
#define ABEOZ9_REG_CTRL_INT_FLAG_V1IF BIT(2)
#define ABEOZ9_REG_CTRL_INT_FLAG_V2IF BIT(3)
#define ABEOZ9_REG_CTRL_INT_FLAG_SRF BIT(4)
#define ABEOZ9_REG_CTRL_STATUS 0x03
#define ABEOZ9_REG_CTRL_STATUS_V1F BIT(2)
#define ABEOZ9_REG_CTRL_STATUS_V2F BIT(3)
#define ABEOZ9_REG_CTRL_STATUS_SR BIT(4)
#define ABEOZ9_REG_CTRL_STATUS_PON BIT(5)
#define ABEOZ9_REG_CTRL_STATUS_EEBUSY BIT(7)
#define ABEOZ9_REG_SEC 0x08
#define ABEOZ9_REG_MIN 0x09
#define ABEOZ9_REG_HOURS 0x0A
#define ABEOZ9_HOURS_PM BIT(6)
#define ABEOZ9_REG_DAYS 0x0B
#define ABEOZ9_REG_WEEKDAYS 0x0C
#define ABEOZ9_REG_MONTHS 0x0D
#define ABEOZ9_REG_YEARS 0x0E
#define ABEOZ9_SEC_LEN 7
#define ABEOZ9_REG_REG_TEMP 0x20
#define ABEOZ953_TEMP_MAX 120
#define ABEOZ953_TEMP_MIN -60
#define ABEOZ9_REG_EEPROM 0x30
#define ABEOZ9_REG_EEPROM_MASK GENMASK(8, 0)
#define ABEOZ9_REG_EEPROM_THP BIT(0)
#define ABEOZ9_REG_EEPROM_THE BIT(1)
#define ABEOZ9_REG_EEPROM_FD0 BIT(2)
#define ABEOZ9_REG_EEPROM_FD1 BIT(3)
#define ABEOZ9_REG_EEPROM_R1K BIT(4)
#define ABEOZ9_REG_EEPROM_R5K BIT(5)
#define ABEOZ9_REG_EEPROM_R20K BIT(6)
#define ABEOZ9_REG_EEPROM_R80K BIT(7)
struct abeoz9_rtc_data {
struct rtc_device *rtc;
struct regmap *regmap;
struct device *hwmon_dev;
};
static int abeoz9_check_validity(struct device *dev)
{
struct abeoz9_rtc_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
int ret;
int val;
ret = regmap_read(regmap, ABEOZ9_REG_CTRL_STATUS, &val);
if (ret < 0) {
dev_err(dev,
"unable to get CTRL_STATUS register (%d)\n", ret);
return ret;
}
if (val & ABEOZ9_REG_CTRL_STATUS_PON) {
dev_warn(dev, "power-on reset detected, date is invalid\n");
return -EINVAL;
}
if (val & ABEOZ9_REG_CTRL_STATUS_V1F) {
dev_warn(dev,
"voltage drops below VLOW1 threshold, date is invalid\n");
return -EINVAL;
}
if ((val & ABEOZ9_REG_CTRL_STATUS_V2F)) {
dev_warn(dev,
"voltage drops below VLOW2 threshold, date is invalid\n");
return -EINVAL;
}
return 0;
}
static int abeoz9_reset_validity(struct regmap *regmap)
{
return regmap_update_bits(regmap, ABEOZ9_REG_CTRL_STATUS,
ABEOZ9_REG_CTRL_STATUS_V1F |
ABEOZ9_REG_CTRL_STATUS_V2F |
ABEOZ9_REG_CTRL_STATUS_PON,
0);
}
static int abeoz9_rtc_get_time(struct device *dev, struct rtc_time *tm)
{
struct abeoz9_rtc_data *data = dev_get_drvdata(dev);
u8 regs[ABEOZ9_SEC_LEN];
int ret;
ret = abeoz9_check_validity(dev);
if (ret)
return ret;
ret = regmap_bulk_read(data->regmap, ABEOZ9_REG_SEC,
regs,
sizeof(regs));
if (ret) {
dev_err(dev, "reading RTC time failed (%d)\n", ret);
return ret;
}
tm->tm_sec = bcd2bin(regs[ABEOZ9_REG_SEC - ABEOZ9_REG_SEC] & 0x7F);
tm->tm_min = bcd2bin(regs[ABEOZ9_REG_MIN - ABEOZ9_REG_SEC] & 0x7F);
if (regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] & ABEOZ9_HOURS_PM) {
tm->tm_hour =
bcd2bin(regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] & 0x1f);
if (regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] & ABEOZ9_HOURS_PM)
tm->tm_hour += 12;
} else {
tm->tm_hour = bcd2bin(regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC]);
}
tm->tm_mday = bcd2bin(regs[ABEOZ9_REG_DAYS - ABEOZ9_REG_SEC]);
tm->tm_wday = bcd2bin(regs[ABEOZ9_REG_WEEKDAYS - ABEOZ9_REG_SEC]);
tm->tm_mon = bcd2bin(regs[ABEOZ9_REG_MONTHS - ABEOZ9_REG_SEC]) - 1;
tm->tm_year = bcd2bin(regs[ABEOZ9_REG_YEARS - ABEOZ9_REG_SEC]) + 100;
return ret;
}
static int abeoz9_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct abeoz9_rtc_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
u8 regs[ABEOZ9_SEC_LEN];
int ret;
regs[ABEOZ9_REG_SEC - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_sec);
regs[ABEOZ9_REG_MIN - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_min);
regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_hour);
regs[ABEOZ9_REG_DAYS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_mday);
regs[ABEOZ9_REG_WEEKDAYS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_wday);
regs[ABEOZ9_REG_MONTHS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_mon + 1);
regs[ABEOZ9_REG_YEARS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_year - 100);
ret = regmap_bulk_write(data->regmap, ABEOZ9_REG_SEC,
regs,
sizeof(regs));
if (ret) {
dev_err(dev, "set RTC time failed (%d)\n", ret);
return ret;
}
return abeoz9_reset_validity(regmap);
}
static int abeoz9_trickle_parse_dt(struct device_node *node)
{
u32 ohms = 0;
if (of_property_read_u32(node, "trickle-resistor-ohms", &ohms))
return 0;
switch (ohms) {
case 1000:
return ABEOZ9_REG_EEPROM_R1K;
case 5000:
return ABEOZ9_REG_EEPROM_R5K;
case 20000:
return ABEOZ9_REG_EEPROM_R20K;
case 80000:
return ABEOZ9_REG_EEPROM_R80K;
default:
return 0;
}
}
static int abeoz9_rtc_setup(struct device *dev, struct device_node *node)
{
struct abeoz9_rtc_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
int ret;
/* Enable Self Recovery, Clock for Watch and EEPROM refresh functions */
ret = regmap_update_bits(regmap, ABEOZ9_REG_CTRL1,
ABEOZ9_REG_CTRL1_MASK,
ABEOZ9_REG_CTRL1_WE |
ABEOZ9_REG_CTRL1_EERE |
ABEOZ9_REG_CTRL1_SRON);
if (ret < 0) {
dev_err(dev, "unable to set CTRL_1 register (%d)\n", ret);
return ret;
}
ret = regmap_write(regmap, ABEOZ9_REG_CTRL_INT, 0);
if (ret < 0) {
dev_err(dev,
"unable to set control CTRL_INT register (%d)\n",
ret);
return ret;
}
ret = regmap_write(regmap, ABEOZ9_REG_CTRL_INT_FLAG, 0);
if (ret < 0) {
dev_err(dev,
"unable to set control CTRL_INT_FLAG register (%d)\n",
ret);
return ret;
}
ret = abeoz9_trickle_parse_dt(node);
/* Enable built-in termometer */
ret |= ABEOZ9_REG_EEPROM_THE;
ret = regmap_update_bits(regmap, ABEOZ9_REG_EEPROM,
ABEOZ9_REG_EEPROM_MASK,
ret);
if (ret < 0) {
dev_err(dev, "unable to set EEPROM register (%d)\n", ret);
return ret;
}
return ret;
}
static const struct rtc_class_ops rtc_ops = {
.read_time = abeoz9_rtc_get_time,
.set_time = abeoz9_rtc_set_time,
};
static const struct regmap_config abeoz9_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
#if IS_REACHABLE(CONFIG_HWMON)
static int abeoz9z3_temp_read(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel, long *temp)
{
struct abeoz9_rtc_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
int ret;
unsigned int val;
ret = regmap_read(regmap, ABEOZ9_REG_CTRL_STATUS, &val);
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);
if (ret < 0)
return ret;
*temp = 1000 * (val + ABEOZ953_TEMP_MIN);
return 0;
case hwmon_temp_max:
*temp = 1000 * ABEOZ953_TEMP_MAX;
return 0;
case hwmon_temp_min:
*temp = 1000 * ABEOZ953_TEMP_MIN;
return 0;
default:
return -EOPNOTSUPP;
}
}
static umode_t abeoz9_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
switch (attr) {
case hwmon_temp_input:
case hwmon_temp_max:
case hwmon_temp_min:
return 0444;
default:
return 0;
}
}
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,
NULL
};
static const struct hwmon_ops abeoz9_hwmon_ops = {
.is_visible = abeoz9_is_visible,
.read = abeoz9z3_temp_read,
};
static const struct hwmon_chip_info abeoz9_chip_info = {
.ops = &abeoz9_hwmon_ops,
.info = abeoz9_info,
};
static void abeoz9_hwmon_register(struct device *dev,
struct abeoz9_rtc_data *data)
{
data->hwmon_dev =
devm_hwmon_device_register_with_info(dev,
"abeoz9",
data,
&abeoz9_chip_info,
NULL);
if (IS_ERR(data->hwmon_dev)) {
dev_warn(dev, "unable to register hwmon device %ld\n",
PTR_ERR(data->hwmon_dev));
}
}
#else
static void abeoz9_hwmon_register(struct device *dev,
struct abeoz9_rtc_data *data)
{
}
#endif
static int abeoz9_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct abeoz9_rtc_data *data = NULL;
struct device *dev = &client->dev;
struct regmap *regmap;
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK)) {
ret = -ENODEV;
goto err;
}
regmap = devm_regmap_init_i2c(client, &abeoz9_rtc_regmap_config);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(dev, "regmap allocation failed: %d\n", ret);
goto err;
}
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto err;
}
data->regmap = regmap;
dev_set_drvdata(dev, data);
ret = abeoz9_rtc_setup(dev, client->dev.of_node);
if (ret)
goto err;
data->rtc = devm_rtc_allocate_device(dev);
ret = PTR_ERR_OR_ZERO(data->rtc);
if (ret)
goto err;
data->rtc->ops = &rtc_ops;
data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
data->rtc->range_max = RTC_TIMESTAMP_END_2099;
ret = rtc_register_device(data->rtc);
if (ret)
goto err;
abeoz9_hwmon_register(dev, data);
return 0;
err:
dev_err(dev, "unable to register RTC device (%d)\n", ret);
return ret;
}
#ifdef CONFIG_OF
static const struct of_device_id abeoz9_dt_match[] = {
{ .compatible = "abracon,abeoz9" },
{ },
};
MODULE_DEVICE_TABLE(of, abeoz9_dt_match);
#endif
static const struct i2c_device_id abeoz9_id[] = {
{ "abeoz9", 0 },
{ }
};
static struct i2c_driver abeoz9_driver = {
.driver = {
.name = "rtc-ab-eoz9",
.of_match_table = of_match_ptr(abeoz9_dt_match),
},
.probe = abeoz9_probe,
.id_table = abeoz9_id,
};
module_i2c_driver(abeoz9_driver);
MODULE_AUTHOR("Artem Panfilov <panfilov.artyom@gmail.com>");
MODULE_DESCRIPTION("Abracon AB-RTCMC-32.768kHz-EOZ9 RTC driver");
MODULE_LICENSE("GPL");
...@@ -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");
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 Cadence
*
* Authors:
* Jan Kotas <jank@cadence.com>
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/rtc.h>
#include <linux/clk.h>
#include <linux/bcd.h>
#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/pm_wakeirq.h>
/* Registers */
#define CDNS_RTC_CTLR 0x00
#define CDNS_RTC_HMR 0x04
#define CDNS_RTC_TIMR 0x08
#define CDNS_RTC_CALR 0x0C
#define CDNS_RTC_TIMAR 0x10
#define CDNS_RTC_CALAR 0x14
#define CDNS_RTC_AENR 0x18
#define CDNS_RTC_EFLR 0x1C
#define CDNS_RTC_IENR 0x20
#define CDNS_RTC_IDISR 0x24
#define CDNS_RTC_IMSKR 0x28
#define CDNS_RTC_STSR 0x2C
#define CDNS_RTC_KRTCR 0x30
/* Control */
#define CDNS_RTC_CTLR_TIME BIT(0)
#define CDNS_RTC_CTLR_CAL BIT(1)
#define CDNS_RTC_CTLR_TIME_CAL (CDNS_RTC_CTLR_TIME | CDNS_RTC_CTLR_CAL)
/* Status */
#define CDNS_RTC_STSR_VT BIT(0)
#define CDNS_RTC_STSR_VC BIT(1)
#define CDNS_RTC_STSR_VTA BIT(2)
#define CDNS_RTC_STSR_VCA BIT(3)
#define CDNS_RTC_STSR_VT_VC (CDNS_RTC_STSR_VT | CDNS_RTC_STSR_VC)
#define CDNS_RTC_STSR_VTA_VCA (CDNS_RTC_STSR_VTA | CDNS_RTC_STSR_VCA)
/* Keep RTC */
#define CDNS_RTC_KRTCR_KRTC BIT(0)
/* Alarm, Event, Interrupt */
#define CDNS_RTC_AEI_HOS BIT(0)
#define CDNS_RTC_AEI_SEC BIT(1)
#define CDNS_RTC_AEI_MIN BIT(2)
#define CDNS_RTC_AEI_HOUR BIT(3)
#define CDNS_RTC_AEI_DATE BIT(4)
#define CDNS_RTC_AEI_MNTH BIT(5)
#define CDNS_RTC_AEI_ALRM BIT(6)
/* Time */
#define CDNS_RTC_TIME_H GENMASK(7, 0)
#define CDNS_RTC_TIME_S GENMASK(14, 8)
#define CDNS_RTC_TIME_M GENMASK(22, 16)
#define CDNS_RTC_TIME_HR GENMASK(29, 24)
#define CDNS_RTC_TIME_PM BIT(30)
#define CDNS_RTC_TIME_CH BIT(31)
/* Calendar */
#define CDNS_RTC_CAL_DAY GENMASK(2, 0)
#define CDNS_RTC_CAL_M GENMASK(7, 3)
#define CDNS_RTC_CAL_D GENMASK(13, 8)
#define CDNS_RTC_CAL_Y GENMASK(23, 16)
#define CDNS_RTC_CAL_C GENMASK(29, 24)
#define CDNS_RTC_CAL_CH BIT(31)
#define CDNS_RTC_MAX_REGS_TRIES 3
struct cdns_rtc {
struct rtc_device *rtc_dev;
struct clk *pclk;
struct clk *ref_clk;
void __iomem *regs;
int irq;
};
static void cdns_rtc_set_enabled(struct cdns_rtc *crtc, bool enabled)
{
u32 reg = enabled ? 0x0 : CDNS_RTC_CTLR_TIME_CAL;
writel(reg, crtc->regs + CDNS_RTC_CTLR);
}
static bool cdns_rtc_get_enabled(struct cdns_rtc *crtc)
{
return !(readl(crtc->regs + CDNS_RTC_CTLR) & CDNS_RTC_CTLR_TIME_CAL);
}
static irqreturn_t cdns_rtc_irq_handler(int irq, void *id)
{
struct device *dev = id;
struct cdns_rtc *crtc = dev_get_drvdata(dev);
/* Reading the register clears it */
if (!(readl(crtc->regs + CDNS_RTC_EFLR) & CDNS_RTC_AEI_ALRM))
return IRQ_NONE;
rtc_update_irq(crtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static u32 cdns_rtc_time2reg(struct rtc_time *tm)
{
return FIELD_PREP(CDNS_RTC_TIME_S, bin2bcd(tm->tm_sec))
| FIELD_PREP(CDNS_RTC_TIME_M, bin2bcd(tm->tm_min))
| FIELD_PREP(CDNS_RTC_TIME_HR, bin2bcd(tm->tm_hour));
}
static void cdns_rtc_reg2time(u32 reg, struct rtc_time *tm)
{
tm->tm_sec = bcd2bin(FIELD_GET(CDNS_RTC_TIME_S, reg));
tm->tm_min = bcd2bin(FIELD_GET(CDNS_RTC_TIME_M, reg));
tm->tm_hour = bcd2bin(FIELD_GET(CDNS_RTC_TIME_HR, reg));
}
static int cdns_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct cdns_rtc *crtc = dev_get_drvdata(dev);
u32 reg;
/* If the RTC is disabled, assume the values are invalid */
if (!cdns_rtc_get_enabled(crtc))
return -EINVAL;
cdns_rtc_set_enabled(crtc, false);
reg = readl(crtc->regs + CDNS_RTC_TIMR);
cdns_rtc_reg2time(reg, tm);
reg = readl(crtc->regs + CDNS_RTC_CALR);
tm->tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
tm->tm_mon = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
tm->tm_year = bcd2bin(FIELD_GET(CDNS_RTC_CAL_Y, reg))
+ bcd2bin(FIELD_GET(CDNS_RTC_CAL_C, reg)) * 100 - 1900;
tm->tm_wday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_DAY, reg)) - 1;
cdns_rtc_set_enabled(crtc, true);
return 0;
}
static int cdns_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct cdns_rtc *crtc = dev_get_drvdata(dev);
u32 timr, calr, stsr;
int ret = -EIO;
int year = tm->tm_year + 1900;
int tries;
cdns_rtc_set_enabled(crtc, false);
timr = cdns_rtc_time2reg(tm);
calr = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(tm->tm_mday))
| FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(tm->tm_mon + 1))
| FIELD_PREP(CDNS_RTC_CAL_Y, bin2bcd(year % 100))
| FIELD_PREP(CDNS_RTC_CAL_C, bin2bcd(year / 100))
| FIELD_PREP(CDNS_RTC_CAL_DAY, tm->tm_wday + 1);
/* Update registers, check valid flags */
for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
writel(timr, crtc->regs + CDNS_RTC_TIMR);
writel(calr, crtc->regs + CDNS_RTC_CALR);
stsr = readl(crtc->regs + CDNS_RTC_STSR);
if ((stsr & CDNS_RTC_STSR_VT_VC) == CDNS_RTC_STSR_VT_VC) {
ret = 0;
break;
}
}
cdns_rtc_set_enabled(crtc, true);
return ret;
}
static int cdns_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct cdns_rtc *crtc = dev_get_drvdata(dev);
if (enabled) {
writel((CDNS_RTC_AEI_SEC | CDNS_RTC_AEI_MIN | CDNS_RTC_AEI_HOUR
| CDNS_RTC_AEI_DATE | CDNS_RTC_AEI_MNTH),
crtc->regs + CDNS_RTC_AENR);
writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IENR);
} else {
writel(0, crtc->regs + CDNS_RTC_AENR);
writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IDISR);
}
return 0;
}
static int cdns_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct cdns_rtc *crtc = dev_get_drvdata(dev);
u32 reg;
reg = readl(crtc->regs + CDNS_RTC_TIMAR);
cdns_rtc_reg2time(reg, &alarm->time);
reg = readl(crtc->regs + CDNS_RTC_CALAR);
alarm->time.tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
alarm->time.tm_mon = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
return 0;
}
static int cdns_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct cdns_rtc *crtc = dev_get_drvdata(dev);
int ret = -EIO;
int tries;
u32 timar, calar, stsr;
cdns_rtc_alarm_irq_enable(dev, 0);
timar = cdns_rtc_time2reg(&alarm->time);
calar = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(alarm->time.tm_mday))
| FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(alarm->time.tm_mon + 1));
/* Update registers, check valid alarm flags */
for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
writel(timar, crtc->regs + CDNS_RTC_TIMAR);
writel(calar, crtc->regs + CDNS_RTC_CALAR);
stsr = readl(crtc->regs + CDNS_RTC_STSR);
if ((stsr & CDNS_RTC_STSR_VTA_VCA) == CDNS_RTC_STSR_VTA_VCA) {
ret = 0;
break;
}
}
if (!ret)
cdns_rtc_alarm_irq_enable(dev, alarm->enabled);
return ret;
}
static const struct rtc_class_ops cdns_rtc_ops = {
.read_time = cdns_rtc_read_time,
.set_time = cdns_rtc_set_time,
.read_alarm = cdns_rtc_read_alarm,
.set_alarm = cdns_rtc_set_alarm,
.alarm_irq_enable = cdns_rtc_alarm_irq_enable,
};
static int cdns_rtc_probe(struct platform_device *pdev)
{
struct cdns_rtc *crtc;
struct resource *res;
int ret;
unsigned long ref_clk_freq;
crtc = devm_kzalloc(&pdev->dev, sizeof(*crtc), GFP_KERNEL);
if (!crtc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
crtc->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(crtc->regs))
return PTR_ERR(crtc->regs);
crtc->irq = platform_get_irq(pdev, 0);
if (crtc->irq < 0)
return -EINVAL;
crtc->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(crtc->pclk)) {
ret = PTR_ERR(crtc->pclk);
dev_err(&pdev->dev,
"Failed to retrieve the peripheral clock, %d\n", ret);
return ret;
}
crtc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
if (IS_ERR(crtc->ref_clk)) {
ret = PTR_ERR(crtc->ref_clk);
dev_err(&pdev->dev,
"Failed to retrieve the reference clock, %d\n", ret);
return ret;
}
crtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(crtc->rtc_dev)) {
ret = PTR_ERR(crtc->rtc_dev);
dev_err(&pdev->dev,
"Failed to allocate the RTC device, %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, crtc);
ret = clk_prepare_enable(crtc->pclk);
if (ret) {
dev_err(&pdev->dev,
"Failed to enable the peripheral clock, %d\n", ret);
return ret;
}
ret = clk_prepare_enable(crtc->ref_clk);
if (ret) {
dev_err(&pdev->dev,
"Failed to enable the reference clock, %d\n", ret);
goto err_disable_pclk;
}
ref_clk_freq = clk_get_rate(crtc->ref_clk);
if ((ref_clk_freq != 1) && (ref_clk_freq != 100)) {
dev_err(&pdev->dev,
"Invalid reference clock frequency %lu Hz.\n",
ref_clk_freq);
ret = -EINVAL;
goto err_disable_ref_clk;
}
ret = devm_request_irq(&pdev->dev, crtc->irq,
cdns_rtc_irq_handler, 0,
dev_name(&pdev->dev), &pdev->dev);
if (ret) {
dev_err(&pdev->dev,
"Failed to request interrupt for the device, %d\n",
ret);
goto err_disable_ref_clk;
}
/* The RTC supports 01.01.1900 - 31.12.2999 */
crtc->rtc_dev->range_min = mktime64(1900, 1, 1, 0, 0, 0);
crtc->rtc_dev->range_max = mktime64(2999, 12, 31, 23, 59, 59);
crtc->rtc_dev->ops = &cdns_rtc_ops;
device_init_wakeup(&pdev->dev, true);
/* Always use 24-hour mode and keep the RTC values */
writel(0, crtc->regs + CDNS_RTC_HMR);
writel(CDNS_RTC_KRTCR_KRTC, crtc->regs + CDNS_RTC_KRTCR);
ret = rtc_register_device(crtc->rtc_dev);
if (ret) {
dev_err(&pdev->dev,
"Failed to register the RTC device, %d\n", ret);
goto err_disable_wakeup;
}
return 0;
err_disable_wakeup:
device_init_wakeup(&pdev->dev, false);
err_disable_ref_clk:
clk_disable_unprepare(crtc->ref_clk);
err_disable_pclk:
clk_disable_unprepare(crtc->pclk);
return ret;
}
static int 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);
clk_disable_unprepare(crtc->pclk);
clk_disable_unprepare(crtc->ref_clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int cdns_rtc_suspend(struct device *dev)
{
struct cdns_rtc *crtc = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(crtc->irq);
return 0;
}
static int cdns_rtc_resume(struct device *dev)
{
struct cdns_rtc *crtc = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(crtc->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(cdns_rtc_pm_ops, cdns_rtc_suspend, cdns_rtc_resume);
static const struct of_device_id cdns_rtc_of_match[] = {
{ .compatible = "cdns,rtc-r109v3" },
{ },
};
MODULE_DEVICE_TABLE(of, cdns_rtc_of_match);
static struct platform_driver cdns_rtc_driver = {
.driver = {
.name = "cdns-rtc",
.of_match_table = cdns_rtc_of_match,
.pm = &cdns_rtc_pm_ops,
},
.probe = cdns_rtc_probe,
.remove = cdns_rtc_remove,
};
module_platform_driver(cdns_rtc_driver);
MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
MODULE_DESCRIPTION("Cadence RTC driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:cdns-rtc");
...@@ -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 {
......
...@@ -114,6 +114,33 @@ enum ds_type { ...@@ -114,6 +114,33 @@ enum ds_type {
# define RX8025_BIT_VDET 0x40 # define RX8025_BIT_VDET 0x40
# define RX8025_BIT_XST 0x20 # define RX8025_BIT_XST 0x20
#define RX8130_REG_ALARM_MIN 0x17
#define RX8130_REG_ALARM_HOUR 0x18
#define RX8130_REG_ALARM_WEEK_OR_DAY 0x19
#define RX8130_REG_EXTENSION 0x1c
#define RX8130_REG_EXTENSION_WADA BIT(3)
#define RX8130_REG_FLAG 0x1d
#define RX8130_REG_FLAG_VLF BIT(1)
#define RX8130_REG_FLAG_AF BIT(3)
#define RX8130_REG_CONTROL0 0x1e
#define RX8130_REG_CONTROL0_AIE BIT(3)
#define MCP794XX_REG_CONTROL 0x07
# define MCP794XX_BIT_ALM0_EN 0x10
# define MCP794XX_BIT_ALM1_EN 0x20
#define MCP794XX_REG_ALARM0_BASE 0x0a
#define MCP794XX_REG_ALARM0_CTRL 0x0d
#define MCP794XX_REG_ALARM1_BASE 0x11
#define MCP794XX_REG_ALARM1_CTRL 0x14
# define MCP794XX_BIT_ALMX_IF BIT(3)
# define MCP794XX_BIT_ALMX_C0 BIT(4)
# define MCP794XX_BIT_ALMX_C1 BIT(5)
# define MCP794XX_BIT_ALMX_C2 BIT(6)
# define MCP794XX_BIT_ALMX_POL BIT(7)
# define MCP794XX_MSK_ALMX_MATCH (MCP794XX_BIT_ALMX_C0 | \
MCP794XX_BIT_ALMX_C1 | \
MCP794XX_BIT_ALMX_C2)
#define M41TXX_REG_CONTROL 0x07 #define M41TXX_REG_CONTROL 0x07
# define M41TXX_BIT_OUT BIT(7) # define M41TXX_BIT_OUT BIT(7)
# define M41TXX_BIT_FT BIT(6) # define M41TXX_BIT_FT BIT(6)
...@@ -158,313 +185,45 @@ struct chip_desc { ...@@ -158,313 +185,45 @@ struct chip_desc {
bool); bool);
}; };
static int ds1307_get_time(struct device *dev, struct rtc_time *t); static const struct chip_desc chips[last_ds_type];
static int ds1307_set_time(struct device *dev, struct rtc_time *t);
static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t);
static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t);
static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled);
static u8 do_trickle_setup_ds1339(struct ds1307 *, u32 ohms, bool diode);
static irqreturn_t rx8130_irq(int irq, void *dev_id);
static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t);
static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t);
static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled);
static irqreturn_t mcp794xx_irq(int irq, void *dev_id);
static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t);
static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t);
static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled);
static int m41txx_rtc_read_offset(struct device *dev, long *offset);
static int m41txx_rtc_set_offset(struct device *dev, long offset);
static const struct rtc_class_ops rx8130_rtc_ops = { static int ds1307_get_time(struct device *dev, struct rtc_time *t)
.read_time = ds1307_get_time, {
.set_time = ds1307_set_time, struct ds1307 *ds1307 = dev_get_drvdata(dev);
.read_alarm = rx8130_read_alarm, int tmp, ret;
.set_alarm = rx8130_set_alarm, const struct chip_desc *chip = &chips[ds1307->type];
.alarm_irq_enable = rx8130_alarm_irq_enable, u8 regs[7];
};
static const struct rtc_class_ops mcp794xx_rtc_ops = { if (ds1307->type == rx_8130) {
.read_time = ds1307_get_time, unsigned int regflag;
.set_time = ds1307_set_time, ret = regmap_read(ds1307->regmap, RX8130_REG_FLAG, &regflag);
.read_alarm = mcp794xx_read_alarm, if (ret) {
.set_alarm = mcp794xx_set_alarm, dev_err(dev, "%s error %d\n", "read", ret);
.alarm_irq_enable = mcp794xx_alarm_irq_enable, return ret;
}; }
static const struct rtc_class_ops m41txx_rtc_ops = { if (regflag & RX8130_REG_FLAG_VLF) {
.read_time = ds1307_get_time, dev_warn_once(dev, "oscillator failed, set time!\n");
.set_time = ds1307_set_time, return -EINVAL;
.read_alarm = ds1337_read_alarm, }
.set_alarm = ds1337_set_alarm, }
.alarm_irq_enable = ds1307_alarm_irq_enable,
.read_offset = m41txx_rtc_read_offset,
.set_offset = m41txx_rtc_set_offset,
};
static const struct chip_desc chips[last_ds_type] = { /* read the RTC date and time registers all at once */
[ds_1307] = { ret = regmap_bulk_read(ds1307->regmap, chip->offset, regs,
.nvram_offset = 8, sizeof(regs));
.nvram_size = 56, if (ret) {
}, dev_err(dev, "%s error %d\n", "read", ret);
[ds_1308] = { return ret;
.nvram_offset = 8, }
.nvram_size = 56,
},
[ds_1337] = {
.alarm = 1,
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
},
[ds_1338] = {
.nvram_offset = 8,
.nvram_size = 56,
},
[ds_1339] = {
.alarm = 1,
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
.bbsqi_bit = DS1339_BIT_BBSQI,
.trickle_charger_reg = 0x10,
.do_trickle_setup = &do_trickle_setup_ds1339,
},
[ds_1340] = {
.century_reg = DS1307_REG_HOUR,
.century_enable_bit = DS1340_BIT_CENTURY_EN,
.century_bit = DS1340_BIT_CENTURY,
.do_trickle_setup = &do_trickle_setup_ds1339,
.trickle_charger_reg = 0x08,
},
[ds_1341] = {
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
},
[ds_1388] = {
.offset = 1,
.trickle_charger_reg = 0x0a,
},
[ds_3231] = {
.alarm = 1,
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
.bbsqi_bit = DS3231_BIT_BBSQW,
},
[rx_8130] = {
.alarm = 1,
/* this is battery backed SRAM */
.nvram_offset = 0x20,
.nvram_size = 4, /* 32bit (4 word x 8 bit) */
.offset = 0x10,
.irq_handler = rx8130_irq,
.rtc_ops = &rx8130_rtc_ops,
},
[m41t0] = {
.rtc_ops = &m41txx_rtc_ops,
},
[m41t00] = {
.rtc_ops = &m41txx_rtc_ops,
},
[m41t11] = {
/* this is battery backed SRAM */
.nvram_offset = 8,
.nvram_size = 56,
.rtc_ops = &m41txx_rtc_ops,
},
[mcp794xx] = {
.alarm = 1,
/* this is battery backed SRAM */
.nvram_offset = 0x20,
.nvram_size = 0x40,
.irq_handler = mcp794xx_irq,
.rtc_ops = &mcp794xx_rtc_ops,
},
};
static const struct i2c_device_id ds1307_id[] = { dev_dbg(dev, "%s: %7ph\n", "read", regs);
{ "ds1307", ds_1307 },
{ "ds1308", ds_1308 },
{ "ds1337", ds_1337 },
{ "ds1338", ds_1338 },
{ "ds1339", ds_1339 },
{ "ds1388", ds_1388 },
{ "ds1340", ds_1340 },
{ "ds1341", ds_1341 },
{ "ds3231", ds_3231 },
{ "m41t0", m41t0 },
{ "m41t00", m41t00 },
{ "m41t11", m41t11 },
{ "mcp7940x", mcp794xx },
{ "mcp7941x", mcp794xx },
{ "pt7c4338", ds_1307 },
{ "rx8025", rx_8025 },
{ "isl12057", ds_1337 },
{ "rx8130", rx_8130 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);
#ifdef CONFIG_OF /* if oscillator fail bit is set, no data can be trusted */
static const struct of_device_id ds1307_of_match[] = { if (ds1307->type == m41t0 &&
{ regs[DS1307_REG_MIN] & M41T0_BIT_OF) {
.compatible = "dallas,ds1307", dev_warn_once(dev, "oscillator failed, set time!\n");
.data = (void *)ds_1307 return -EINVAL;
}, }
{
.compatible = "dallas,ds1308",
.data = (void *)ds_1308
},
{
.compatible = "dallas,ds1337",
.data = (void *)ds_1337
},
{
.compatible = "dallas,ds1338",
.data = (void *)ds_1338
},
{
.compatible = "dallas,ds1339",
.data = (void *)ds_1339
},
{
.compatible = "dallas,ds1388",
.data = (void *)ds_1388
},
{
.compatible = "dallas,ds1340",
.data = (void *)ds_1340
},
{
.compatible = "dallas,ds1341",
.data = (void *)ds_1341
},
{
.compatible = "maxim,ds3231",
.data = (void *)ds_3231
},
{
.compatible = "st,m41t0",
.data = (void *)m41t0
},
{
.compatible = "st,m41t00",
.data = (void *)m41t00
},
{
.compatible = "st,m41t11",
.data = (void *)m41t11
},
{
.compatible = "microchip,mcp7940x",
.data = (void *)mcp794xx
},
{
.compatible = "microchip,mcp7941x",
.data = (void *)mcp794xx
},
{
.compatible = "pericom,pt7c4338",
.data = (void *)ds_1307
},
{
.compatible = "epson,rx8025",
.data = (void *)rx_8025
},
{
.compatible = "isil,isl12057",
.data = (void *)ds_1337
},
{
.compatible = "epson,rx8130",
.data = (void *)rx_8130
},
{ }
};
MODULE_DEVICE_TABLE(of, ds1307_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id ds1307_acpi_ids[] = {
{ .id = "DS1307", .driver_data = ds_1307 },
{ .id = "DS1308", .driver_data = ds_1308 },
{ .id = "DS1337", .driver_data = ds_1337 },
{ .id = "DS1338", .driver_data = ds_1338 },
{ .id = "DS1339", .driver_data = ds_1339 },
{ .id = "DS1388", .driver_data = ds_1388 },
{ .id = "DS1340", .driver_data = ds_1340 },
{ .id = "DS1341", .driver_data = ds_1341 },
{ .id = "DS3231", .driver_data = ds_3231 },
{ .id = "M41T0", .driver_data = m41t0 },
{ .id = "M41T00", .driver_data = m41t00 },
{ .id = "M41T11", .driver_data = m41t11 },
{ .id = "MCP7940X", .driver_data = mcp794xx },
{ .id = "MCP7941X", .driver_data = mcp794xx },
{ .id = "PT7C4338", .driver_data = ds_1307 },
{ .id = "RX8025", .driver_data = rx_8025 },
{ .id = "ISL12057", .driver_data = ds_1337 },
{ .id = "RX8130", .driver_data = rx_8130 },
{ }
};
MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
#endif
/*
* The ds1337 and ds1339 both have two alarms, but we only use the first
* one (with a "seconds" field). For ds1337 we expect nINTA is our alarm
* signal; ds1339 chips have only one alarm signal.
*/
static irqreturn_t ds1307_irq(int irq, void *dev_id)
{
struct ds1307 *ds1307 = dev_id;
struct mutex *lock = &ds1307->rtc->ops_lock;
int stat, ret;
mutex_lock(lock);
ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &stat);
if (ret)
goto out;
if (stat & DS1337_BIT_A1I) {
stat &= ~DS1337_BIT_A1I;
regmap_write(ds1307->regmap, DS1337_REG_STATUS, stat);
ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
DS1337_BIT_A1IE, 0);
if (ret)
goto out;
rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
}
out:
mutex_unlock(lock);
return IRQ_HANDLED;
}
/*----------------------------------------------------------------------*/
static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
int tmp, ret;
const struct chip_desc *chip = &chips[ds1307->type];
u8 regs[7];
/* read the RTC date and time registers all at once */
ret = regmap_bulk_read(ds1307->regmap, chip->offset, regs,
sizeof(regs));
if (ret) {
dev_err(dev, "%s error %d\n", "read", ret);
return ret;
}
dev_dbg(dev, "%s: %7ph\n", "read", regs);
/* if oscillator fail bit is set, no data can be trusted */
if (ds1307->type == m41t0 &&
regs[DS1307_REG_MIN] & M41T0_BIT_OF) {
dev_warn_once(dev, "oscillator failed, set time!\n");
return -EINVAL;
}
t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f); t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f);
t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f); t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f);
...@@ -548,6 +307,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) ...@@ -548,6 +307,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
dev_err(dev, "%s error %d\n", "write", result); dev_err(dev, "%s error %d\n", "write", result);
return result; return result;
} }
if (ds1307->type == rx_8130) {
/* clear Voltage Loss Flag as data is available now */
result = regmap_write(ds1307->regmap, RX8130_REG_FLAG,
~(u8)RX8130_REG_FLAG_VLF);
if (result) {
dev_err(dev, "%s error %d\n", "write", result);
return result;
}
}
return 0; return 0;
} }
...@@ -666,29 +436,28 @@ static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled) ...@@ -666,29 +436,28 @@ static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled)
enabled ? DS1337_BIT_A1IE : 0); enabled ? DS1337_BIT_A1IE : 0);
} }
static const struct rtc_class_ops ds13xx_rtc_ops = { static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307, u32 ohms, bool diode)
.read_time = ds1307_get_time, {
.set_time = ds1307_set_time, u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE :
.read_alarm = ds1337_read_alarm, DS1307_TRICKLE_CHARGER_NO_DIODE;
.set_alarm = ds1337_set_alarm,
.alarm_irq_enable = ds1307_alarm_irq_enable,
};
/*----------------------------------------------------------------------*/
/*
* Alarm support for rx8130 devices.
*/
#define RX8130_REG_ALARM_MIN 0x07 switch (ohms) {
#define RX8130_REG_ALARM_HOUR 0x08 case 250:
#define RX8130_REG_ALARM_WEEK_OR_DAY 0x09 setup |= DS1307_TRICKLE_CHARGER_250_OHM;
#define RX8130_REG_EXTENSION 0x0c break;
#define RX8130_REG_EXTENSION_WADA BIT(3) case 2000:
#define RX8130_REG_FLAG 0x0d setup |= DS1307_TRICKLE_CHARGER_2K_OHM;
#define RX8130_REG_FLAG_AF BIT(3) break;
#define RX8130_REG_CONTROL0 0x0e case 4000:
#define RX8130_REG_CONTROL0_AIE BIT(3) setup |= DS1307_TRICKLE_CHARGER_4K_OHM;
break;
default:
dev_warn(ds1307->dev,
"Unsupported ohm value %u in dt\n", ohms);
return 0;
}
return setup;
}
static irqreturn_t rx8130_irq(int irq, void *dev_id) static irqreturn_t rx8130_irq(int irq, void *dev_id)
{ {
...@@ -785,8 +554,8 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -785,8 +554,8 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (ret < 0) if (ret < 0)
return ret; return ret;
ctl[0] &= ~RX8130_REG_EXTENSION_WADA; ctl[0] &= RX8130_REG_EXTENSION_WADA;
ctl[1] |= RX8130_REG_FLAG_AF; ctl[1] &= ~RX8130_REG_FLAG_AF;
ctl[2] &= ~RX8130_REG_CONTROL0_AIE; ctl[2] &= ~RX8130_REG_CONTROL0_AIE;
ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl,
...@@ -809,8 +578,7 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -809,8 +578,7 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t)
ctl[2] |= RX8130_REG_CONTROL0_AIE; ctl[2] |= RX8130_REG_CONTROL0_AIE;
return regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, ctl[2]);
sizeof(ctl));
} }
static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled) static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled)
...@@ -833,54 +601,459 @@ static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled) ...@@ -833,54 +601,459 @@ static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled)
return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, reg); return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, reg);
} }
/*----------------------------------------------------------------------*/ static irqreturn_t mcp794xx_irq(int irq, void *dev_id)
{
struct ds1307 *ds1307 = dev_id;
struct mutex *lock = &ds1307->rtc->ops_lock;
int reg, ret;
mutex_lock(lock);
/* Check and clear alarm 0 interrupt flag. */
ret = regmap_read(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, &reg);
if (ret)
goto out;
if (!(reg & MCP794XX_BIT_ALMX_IF))
goto out;
reg &= ~MCP794XX_BIT_ALMX_IF;
ret = regmap_write(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, reg);
if (ret)
goto out;
/* Disable alarm 0. */
ret = regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL,
MCP794XX_BIT_ALM0_EN, 0);
if (ret)
goto out;
rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
out:
mutex_unlock(lock);
return IRQ_HANDLED;
}
static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
u8 regs[10];
int ret;
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
/* Read control and alarm 0 registers. */
ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs,
sizeof(regs));
if (ret)
return ret;
t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN);
/* Report alarm 0 time assuming 24-hour and day-of-month modes. */
t->time.tm_sec = bcd2bin(regs[3] & 0x7f);
t->time.tm_min = bcd2bin(regs[4] & 0x7f);
t->time.tm_hour = bcd2bin(regs[5] & 0x3f);
t->time.tm_wday = bcd2bin(regs[6] & 0x7) - 1;
t->time.tm_mday = bcd2bin(regs[7] & 0x3f);
t->time.tm_mon = bcd2bin(regs[8] & 0x1f) - 1;
t->time.tm_year = -1;
t->time.tm_yday = -1;
t->time.tm_isdst = -1;
dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
"enabled=%d polarity=%d irq=%d match=%lu\n", __func__,
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
!!(regs[6] & MCP794XX_BIT_ALMX_POL),
!!(regs[6] & MCP794XX_BIT_ALMX_IF),
(regs[6] & MCP794XX_MSK_ALMX_MATCH) >> 4);
return 0;
}
/*
* We may have a random RTC weekday, therefore calculate alarm weekday based
* on current weekday we read from the RTC timekeeping regs
*/
static int mcp794xx_alm_weekday(struct device *dev, struct rtc_time *tm_alarm)
{
struct rtc_time tm_now;
int days_now, days_alarm, ret;
ret = ds1307_get_time(dev, &tm_now);
if (ret)
return ret;
days_now = div_s64(rtc_tm_to_time64(&tm_now), 24 * 60 * 60);
days_alarm = div_s64(rtc_tm_to_time64(tm_alarm), 24 * 60 * 60);
return (tm_now.tm_wday + days_alarm - days_now) % 7 + 1;
}
static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
unsigned char regs[10];
int wday, ret;
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
wday = mcp794xx_alm_weekday(dev, &t->time);
if (wday < 0)
return wday;
dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
"enabled=%d pending=%d\n", __func__,
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
t->enabled, t->pending);
/* Read control and alarm 0 registers. */
ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs,
sizeof(regs));
if (ret)
return ret;
/* Set alarm 0, using 24-hour and day-of-month modes. */
regs[3] = bin2bcd(t->time.tm_sec);
regs[4] = bin2bcd(t->time.tm_min);
regs[5] = bin2bcd(t->time.tm_hour);
regs[6] = wday;
regs[7] = bin2bcd(t->time.tm_mday);
regs[8] = bin2bcd(t->time.tm_mon + 1);
/* Clear the alarm 0 interrupt flag. */
regs[6] &= ~MCP794XX_BIT_ALMX_IF;
/* Set alarm match: second, minute, hour, day, date, month. */
regs[6] |= MCP794XX_MSK_ALMX_MATCH;
/* Disable interrupt. We will not enable until completely programmed */
regs[0] &= ~MCP794XX_BIT_ALM0_EN;
ret = regmap_bulk_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs,
sizeof(regs));
if (ret)
return ret;
if (!t->enabled)
return 0;
regs[0] |= MCP794XX_BIT_ALM0_EN;
return regmap_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs[0]);
}
static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
return regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL,
MCP794XX_BIT_ALM0_EN,
enabled ? MCP794XX_BIT_ALM0_EN : 0);
}
static int m41txx_rtc_read_offset(struct device *dev, long *offset)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
unsigned int ctrl_reg;
u8 val;
regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
val = ctrl_reg & M41TXX_M_CALIBRATION;
/* check if positive */
if (ctrl_reg & M41TXX_BIT_CALIB_SIGN)
*offset = (val * M41TXX_POS_OFFSET_STEP_PPB);
else
*offset = -(val * M41TXX_NEG_OFFSET_STEP_PPB);
return 0;
}
static int m41txx_rtc_set_offset(struct device *dev, long offset)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
unsigned int ctrl_reg;
if ((offset < M41TXX_MIN_OFFSET) || (offset > M41TXX_MAX_OFFSET))
return -ERANGE;
if (offset >= 0) {
ctrl_reg = DIV_ROUND_CLOSEST(offset,
M41TXX_POS_OFFSET_STEP_PPB);
ctrl_reg |= M41TXX_BIT_CALIB_SIGN;
} else {
ctrl_reg = DIV_ROUND_CLOSEST(abs(offset),
M41TXX_NEG_OFFSET_STEP_PPB);
}
return regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL,
M41TXX_M_CALIBRATION | M41TXX_BIT_CALIB_SIGN,
ctrl_reg);
}
static const struct rtc_class_ops rx8130_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
.read_alarm = rx8130_read_alarm,
.set_alarm = rx8130_set_alarm,
.alarm_irq_enable = rx8130_alarm_irq_enable,
};
static const struct rtc_class_ops mcp794xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
.read_alarm = mcp794xx_read_alarm,
.set_alarm = mcp794xx_set_alarm,
.alarm_irq_enable = mcp794xx_alarm_irq_enable,
};
static const struct rtc_class_ops m41txx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
.read_alarm = ds1337_read_alarm,
.set_alarm = ds1337_set_alarm,
.alarm_irq_enable = ds1307_alarm_irq_enable,
.read_offset = m41txx_rtc_read_offset,
.set_offset = m41txx_rtc_set_offset,
};
static const struct chip_desc chips[last_ds_type] = {
[ds_1307] = {
.nvram_offset = 8,
.nvram_size = 56,
},
[ds_1308] = {
.nvram_offset = 8,
.nvram_size = 56,
},
[ds_1337] = {
.alarm = 1,
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
},
[ds_1338] = {
.nvram_offset = 8,
.nvram_size = 56,
},
[ds_1339] = {
.alarm = 1,
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
.bbsqi_bit = DS1339_BIT_BBSQI,
.trickle_charger_reg = 0x10,
.do_trickle_setup = &do_trickle_setup_ds1339,
},
[ds_1340] = {
.century_reg = DS1307_REG_HOUR,
.century_enable_bit = DS1340_BIT_CENTURY_EN,
.century_bit = DS1340_BIT_CENTURY,
.do_trickle_setup = &do_trickle_setup_ds1339,
.trickle_charger_reg = 0x08,
},
[ds_1341] = {
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
},
[ds_1388] = {
.offset = 1,
.trickle_charger_reg = 0x0a,
},
[ds_3231] = {
.alarm = 1,
.century_reg = DS1307_REG_MONTH,
.century_bit = DS1337_BIT_CENTURY,
.bbsqi_bit = DS3231_BIT_BBSQW,
},
[rx_8130] = {
.alarm = 1,
/* this is battery backed SRAM */
.nvram_offset = 0x20,
.nvram_size = 4, /* 32bit (4 word x 8 bit) */
.offset = 0x10,
.irq_handler = rx8130_irq,
.rtc_ops = &rx8130_rtc_ops,
},
[m41t0] = {
.rtc_ops = &m41txx_rtc_ops,
},
[m41t00] = {
.rtc_ops = &m41txx_rtc_ops,
},
[m41t11] = {
/* this is battery backed SRAM */
.nvram_offset = 8,
.nvram_size = 56,
.rtc_ops = &m41txx_rtc_ops,
},
[mcp794xx] = {
.alarm = 1,
/* this is battery backed SRAM */
.nvram_offset = 0x20,
.nvram_size = 0x40,
.irq_handler = mcp794xx_irq,
.rtc_ops = &mcp794xx_rtc_ops,
},
};
static const struct i2c_device_id ds1307_id[] = {
{ "ds1307", ds_1307 },
{ "ds1308", ds_1308 },
{ "ds1337", ds_1337 },
{ "ds1338", ds_1338 },
{ "ds1339", ds_1339 },
{ "ds1388", ds_1388 },
{ "ds1340", ds_1340 },
{ "ds1341", ds_1341 },
{ "ds3231", ds_3231 },
{ "m41t0", m41t0 },
{ "m41t00", m41t00 },
{ "m41t11", m41t11 },
{ "mcp7940x", mcp794xx },
{ "mcp7941x", mcp794xx },
{ "pt7c4338", ds_1307 },
{ "rx8025", rx_8025 },
{ "isl12057", ds_1337 },
{ "rx8130", rx_8130 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);
#ifdef CONFIG_OF
static const struct of_device_id ds1307_of_match[] = {
{
.compatible = "dallas,ds1307",
.data = (void *)ds_1307
},
{
.compatible = "dallas,ds1308",
.data = (void *)ds_1308
},
{
.compatible = "dallas,ds1337",
.data = (void *)ds_1337
},
{
.compatible = "dallas,ds1338",
.data = (void *)ds_1338
},
{
.compatible = "dallas,ds1339",
.data = (void *)ds_1339
},
{
.compatible = "dallas,ds1388",
.data = (void *)ds_1388
},
{
.compatible = "dallas,ds1340",
.data = (void *)ds_1340
},
{
.compatible = "dallas,ds1341",
.data = (void *)ds_1341
},
{
.compatible = "maxim,ds3231",
.data = (void *)ds_3231
},
{
.compatible = "st,m41t0",
.data = (void *)m41t0
},
{
.compatible = "st,m41t00",
.data = (void *)m41t00
},
{
.compatible = "st,m41t11",
.data = (void *)m41t11
},
{
.compatible = "microchip,mcp7940x",
.data = (void *)mcp794xx
},
{
.compatible = "microchip,mcp7941x",
.data = (void *)mcp794xx
},
{
.compatible = "pericom,pt7c4338",
.data = (void *)ds_1307
},
{
.compatible = "epson,rx8025",
.data = (void *)rx_8025
},
{
.compatible = "isil,isl12057",
.data = (void *)ds_1337
},
{
.compatible = "epson,rx8130",
.data = (void *)rx_8130
},
{ }
};
MODULE_DEVICE_TABLE(of, ds1307_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id ds1307_acpi_ids[] = {
{ .id = "DS1307", .driver_data = ds_1307 },
{ .id = "DS1308", .driver_data = ds_1308 },
{ .id = "DS1337", .driver_data = ds_1337 },
{ .id = "DS1338", .driver_data = ds_1338 },
{ .id = "DS1339", .driver_data = ds_1339 },
{ .id = "DS1388", .driver_data = ds_1388 },
{ .id = "DS1340", .driver_data = ds_1340 },
{ .id = "DS1341", .driver_data = ds_1341 },
{ .id = "DS3231", .driver_data = ds_3231 },
{ .id = "M41T0", .driver_data = m41t0 },
{ .id = "M41T00", .driver_data = m41t00 },
{ .id = "M41T11", .driver_data = m41t11 },
{ .id = "MCP7940X", .driver_data = mcp794xx },
{ .id = "MCP7941X", .driver_data = mcp794xx },
{ .id = "PT7C4338", .driver_data = ds_1307 },
{ .id = "RX8025", .driver_data = rx_8025 },
{ .id = "ISL12057", .driver_data = ds_1337 },
{ .id = "RX8130", .driver_data = rx_8130 },
{ }
};
MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
#endif
/* /*
* Alarm support for mcp794xx devices. * The ds1337 and ds1339 both have two alarms, but we only use the first
* one (with a "seconds" field). For ds1337 we expect nINTA is our alarm
* signal; ds1339 chips have only one alarm signal.
*/ */
static irqreturn_t ds1307_irq(int irq, void *dev_id)
#define MCP794XX_REG_CONTROL 0x07
# define MCP794XX_BIT_ALM0_EN 0x10
# define MCP794XX_BIT_ALM1_EN 0x20
#define MCP794XX_REG_ALARM0_BASE 0x0a
#define MCP794XX_REG_ALARM0_CTRL 0x0d
#define MCP794XX_REG_ALARM1_BASE 0x11
#define MCP794XX_REG_ALARM1_CTRL 0x14
# define MCP794XX_BIT_ALMX_IF BIT(3)
# define MCP794XX_BIT_ALMX_C0 BIT(4)
# define MCP794XX_BIT_ALMX_C1 BIT(5)
# define MCP794XX_BIT_ALMX_C2 BIT(6)
# define MCP794XX_BIT_ALMX_POL BIT(7)
# define MCP794XX_MSK_ALMX_MATCH (MCP794XX_BIT_ALMX_C0 | \
MCP794XX_BIT_ALMX_C1 | \
MCP794XX_BIT_ALMX_C2)
static irqreturn_t mcp794xx_irq(int irq, void *dev_id)
{ {
struct ds1307 *ds1307 = dev_id; struct ds1307 *ds1307 = dev_id;
struct mutex *lock = &ds1307->rtc->ops_lock; struct mutex *lock = &ds1307->rtc->ops_lock;
int reg, ret; int stat, ret;
mutex_lock(lock); mutex_lock(lock);
ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &stat);
/* Check and clear alarm 0 interrupt flag. */
ret = regmap_read(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, &reg);
if (ret)
goto out;
if (!(reg & MCP794XX_BIT_ALMX_IF))
goto out;
reg &= ~MCP794XX_BIT_ALMX_IF;
ret = regmap_write(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, reg);
if (ret) if (ret)
goto out; goto out;
/* Disable alarm 0. */ if (stat & DS1337_BIT_A1I) {
ret = regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL, stat &= ~DS1337_BIT_A1I;
MCP794XX_BIT_ALM0_EN, 0); regmap_write(ds1307->regmap, DS1337_REG_STATUS, stat);
ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
DS1337_BIT_A1IE, 0);
if (ret) if (ret)
goto out; goto out;
rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
}
out: out:
mutex_unlock(lock); mutex_unlock(lock);
...@@ -888,167 +1061,15 @@ static irqreturn_t mcp794xx_irq(int irq, void *dev_id) ...@@ -888,167 +1061,15 @@ static irqreturn_t mcp794xx_irq(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) /*----------------------------------------------------------------------*/
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
u8 regs[10];
int ret;
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
/* Read control and alarm 0 registers. */
ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs,
sizeof(regs));
if (ret)
return ret;
t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN);
/* Report alarm 0 time assuming 24-hour and day-of-month modes. */
t->time.tm_sec = bcd2bin(regs[3] & 0x7f);
t->time.tm_min = bcd2bin(regs[4] & 0x7f);
t->time.tm_hour = bcd2bin(regs[5] & 0x3f);
t->time.tm_wday = bcd2bin(regs[6] & 0x7) - 1;
t->time.tm_mday = bcd2bin(regs[7] & 0x3f);
t->time.tm_mon = bcd2bin(regs[8] & 0x1f) - 1;
t->time.tm_year = -1;
t->time.tm_yday = -1;
t->time.tm_isdst = -1;
dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
"enabled=%d polarity=%d irq=%d match=%lu\n", __func__,
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
!!(regs[6] & MCP794XX_BIT_ALMX_POL),
!!(regs[6] & MCP794XX_BIT_ALMX_IF),
(regs[6] & MCP794XX_MSK_ALMX_MATCH) >> 4);
return 0;
}
/*
* We may have a random RTC weekday, therefore calculate alarm weekday based
* on current weekday we read from the RTC timekeeping regs
*/
static int mcp794xx_alm_weekday(struct device *dev, struct rtc_time *tm_alarm)
{
struct rtc_time tm_now;
int days_now, days_alarm, ret;
ret = ds1307_get_time(dev, &tm_now);
if (ret)
return ret;
days_now = div_s64(rtc_tm_to_time64(&tm_now), 24 * 60 * 60);
days_alarm = div_s64(rtc_tm_to_time64(tm_alarm), 24 * 60 * 60);
return (tm_now.tm_wday + days_alarm - days_now) % 7 + 1;
}
static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
unsigned char regs[10];
int wday, ret;
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
wday = mcp794xx_alm_weekday(dev, &t->time);
if (wday < 0)
return wday;
dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
"enabled=%d pending=%d\n", __func__,
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
t->enabled, t->pending);
/* Read control and alarm 0 registers. */
ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs,
sizeof(regs));
if (ret)
return ret;
/* Set alarm 0, using 24-hour and day-of-month modes. */
regs[3] = bin2bcd(t->time.tm_sec);
regs[4] = bin2bcd(t->time.tm_min);
regs[5] = bin2bcd(t->time.tm_hour);
regs[6] = wday;
regs[7] = bin2bcd(t->time.tm_mday);
regs[8] = bin2bcd(t->time.tm_mon + 1);
/* Clear the alarm 0 interrupt flag. */
regs[6] &= ~MCP794XX_BIT_ALMX_IF;
/* Set alarm match: second, minute, hour, day, date, month. */
regs[6] |= MCP794XX_MSK_ALMX_MATCH;
/* Disable interrupt. We will not enable until completely programmed */
regs[0] &= ~MCP794XX_BIT_ALM0_EN;
ret = regmap_bulk_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs,
sizeof(regs));
if (ret)
return ret;
if (!t->enabled)
return 0;
regs[0] |= MCP794XX_BIT_ALM0_EN;
return regmap_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs[0]);
}
static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
return regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL,
MCP794XX_BIT_ALM0_EN,
enabled ? MCP794XX_BIT_ALM0_EN : 0);
}
static int m41txx_rtc_read_offset(struct device *dev, long *offset)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
unsigned int ctrl_reg;
u8 val;
regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
val = ctrl_reg & M41TXX_M_CALIBRATION;
/* check if positive */
if (ctrl_reg & M41TXX_BIT_CALIB_SIGN)
*offset = (val * M41TXX_POS_OFFSET_STEP_PPB);
else
*offset = -(val * M41TXX_NEG_OFFSET_STEP_PPB);
return 0;
}
static int m41txx_rtc_set_offset(struct device *dev, long offset)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
unsigned int ctrl_reg;
if ((offset < M41TXX_MIN_OFFSET) || (offset > M41TXX_MAX_OFFSET))
return -ERANGE;
if (offset >= 0) {
ctrl_reg = DIV_ROUND_CLOSEST(offset,
M41TXX_POS_OFFSET_STEP_PPB);
ctrl_reg |= M41TXX_BIT_CALIB_SIGN;
} else {
ctrl_reg = DIV_ROUND_CLOSEST(abs(offset),
M41TXX_NEG_OFFSET_STEP_PPB);
}
return regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL, static const struct rtc_class_ops ds13xx_rtc_ops = {
M41TXX_M_CALIBRATION | M41TXX_BIT_CALIB_SIGN, .read_time = ds1307_get_time,
ctrl_reg); .set_time = ds1307_set_time,
} .read_alarm = ds1337_read_alarm,
.set_alarm = ds1337_set_alarm,
.alarm_irq_enable = ds1307_alarm_irq_enable,
};
static ssize_t frequency_test_store(struct device *dev, static ssize_t frequency_test_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
...@@ -1137,30 +1158,6 @@ static int ds1307_nvram_write(void *priv, unsigned int offset, void *val, ...@@ -1137,30 +1158,6 @@ static int ds1307_nvram_write(void *priv, unsigned int offset, void *val,
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307,
u32 ohms, bool diode)
{
u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE :
DS1307_TRICKLE_CHARGER_NO_DIODE;
switch (ohms) {
case 250:
setup |= DS1307_TRICKLE_CHARGER_250_OHM;
break;
case 2000:
setup |= DS1307_TRICKLE_CHARGER_2K_OHM;
break;
case 4000:
setup |= DS1307_TRICKLE_CHARGER_4K_OHM;
break;
default:
dev_warn(ds1307->dev,
"Unsupported ohm value %u in dt\n", ohms);
return 0;
}
return setup;
}
static u8 ds1307_trickle_init(struct ds1307 *ds1307, static u8 ds1307_trickle_init(struct ds1307 *ds1307,
const struct chip_desc *chip) const struct chip_desc *chip)
{ {
......
...@@ -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;
/* /*
......
// SPDX-License-Identifier: GPL-2.0
/*
* RTC driver for the interal RTC block in the Amlogic Meson6, Meson8,
* Meson8b and Meson8m2 SoCs.
*
* The RTC is split in to two parts, the AHB front end and a simple serial
* connection to the actual registers. This driver manages both parts.
*
* Copyright (c) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
* Copyright (c) 2015 Ben Dooks <ben.dooks@codethink.co.uk> for Codethink Ltd
* Based on origin by Carlo Caione <carlo@endlessm.com>
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/rtc.h>
/* registers accessed from cpu bus */
#define RTC_ADDR0 0x00
#define RTC_ADDR0_LINE_SCLK BIT(0)
#define RTC_ADDR0_LINE_SEN BIT(1)
#define RTC_ADDR0_LINE_SDI BIT(2)
#define RTC_ADDR0_START_SER BIT(17)
#define RTC_ADDR0_WAIT_SER BIT(22)
#define RTC_ADDR0_DATA GENMASK(31, 24)
#define RTC_ADDR1 0x04
#define RTC_ADDR1_SDO BIT(0)
#define RTC_ADDR1_S_READY BIT(1)
#define RTC_ADDR2 0x08
#define RTC_ADDR3 0x0c
#define RTC_REG4 0x10
#define RTC_REG4_STATIC_VALUE GENMASK(7, 0)
/* rtc registers accessed via rtc-serial interface */
#define RTC_COUNTER (0)
#define RTC_SEC_ADJ (2)
#define RTC_REGMEM_0 (4)
#define RTC_REGMEM_1 (5)
#define RTC_REGMEM_2 (6)
#define RTC_REGMEM_3 (7)
#define RTC_ADDR_BITS (3) /* number of address bits to send */
#define RTC_DATA_BITS (32) /* number of data bits to tx/rx */
#define MESON_STATIC_BIAS_CUR (0x5 << 1)
#define MESON_STATIC_VOLTAGE (0x3 << 11)
#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 */
struct regmap *peripheral; /* peripheral registers */
struct regmap *serial; /* serial registers */
};
static const struct regmap_config meson_rtc_peripheral_regmap_config = {
.name = "peripheral-registers",
.reg_bits = 8,
.val_bits = 32,
.reg_stride = 4,
.max_register = RTC_REG4,
.fast_io = true,
};
/* RTC front-end serialiser controls */
static void meson_rtc_sclk_pulse(struct meson_rtc *rtc)
{
udelay(5);
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SCLK, 0);
udelay(5);
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SCLK,
RTC_ADDR0_LINE_SCLK);
}
static void meson_rtc_send_bit(struct meson_rtc *rtc, unsigned int bit)
{
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SDI,
bit ? RTC_ADDR0_LINE_SDI : 0);
meson_rtc_sclk_pulse(rtc);
}
static void meson_rtc_send_bits(struct meson_rtc *rtc, u32 data,
unsigned int nr)
{
u32 bit = 1 << (nr - 1);
while (bit) {
meson_rtc_send_bit(rtc, data & bit);
bit >>= 1;
}
}
static void meson_rtc_set_dir(struct meson_rtc *rtc, u32 mode)
{
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SEN, 0);
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SDI, 0);
meson_rtc_send_bit(rtc, mode);
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SDI, 0);
}
static u32 meson_rtc_get_data(struct meson_rtc *rtc)
{
u32 tmp, val = 0;
int bit;
for (bit = 0; bit < RTC_DATA_BITS; bit++) {
meson_rtc_sclk_pulse(rtc);
val <<= 1;
regmap_read(rtc->peripheral, RTC_ADDR1, &tmp);
val |= tmp & RTC_ADDR1_SDO;
}
return val;
}
static int meson_rtc_get_bus(struct meson_rtc *rtc)
{
int ret, retries = 3;
u32 val;
/* prepare bus for transfers, set all lines low */
val = RTC_ADDR0_LINE_SDI | RTC_ADDR0_LINE_SEN | RTC_ADDR0_LINE_SCLK;
regmap_update_bits(rtc->peripheral, RTC_ADDR0, val, 0);
for (retries = 0; retries < 3; retries++) {
/* wait for the bus to be ready */
if (!regmap_read_poll_timeout(rtc->peripheral, RTC_ADDR1, val,
val & RTC_ADDR1_S_READY, 10,
10000))
return 0;
dev_warn(rtc->dev, "failed to get bus, resetting RTC\n");
ret = reset_control_reset(rtc->reset);
if (ret)
return ret;
}
dev_err(rtc->dev, "bus is not ready\n");
return -ETIMEDOUT;
}
static int meson_rtc_serial_bus_reg_read(void *context, unsigned int reg,
unsigned int *data)
{
struct meson_rtc *rtc = context;
int ret;
ret = meson_rtc_get_bus(rtc);
if (ret)
return ret;
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SEN,
RTC_ADDR0_LINE_SEN);
meson_rtc_send_bits(rtc, reg, RTC_ADDR_BITS);
meson_rtc_set_dir(rtc, 0);
*data = meson_rtc_get_data(rtc);
return 0;
}
static int meson_rtc_serial_bus_reg_write(void *context, unsigned int reg,
unsigned int data)
{
struct meson_rtc *rtc = context;
int ret;
ret = meson_rtc_get_bus(rtc);
if (ret)
return ret;
regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SEN,
RTC_ADDR0_LINE_SEN);
meson_rtc_send_bits(rtc, data, RTC_DATA_BITS);
meson_rtc_send_bits(rtc, reg, RTC_ADDR_BITS);
meson_rtc_set_dir(rtc, 1);
return 0;
}
static const struct regmap_bus meson_rtc_serial_bus = {
.reg_read = meson_rtc_serial_bus_reg_read,
.reg_write = meson_rtc_serial_bus_reg_write,
};
static const struct regmap_config meson_rtc_serial_regmap_config = {
.name = "serial-registers",
.reg_bits = 4,
.reg_stride = 1,
.val_bits = 32,
.max_register = RTC_REGMEM_3,
.fast_io = false,
};
static int meson_rtc_write_static(struct meson_rtc *rtc, u32 data)
{
u32 tmp;
regmap_write(rtc->peripheral, RTC_REG4,
FIELD_PREP(RTC_REG4_STATIC_VALUE, (data >> 8)));
/* write the static value and start the auto serializer */
tmp = FIELD_PREP(RTC_ADDR0_DATA, (data & 0xff)) | RTC_ADDR0_START_SER;
regmap_update_bits(rtc->peripheral, RTC_ADDR0,
RTC_ADDR0_DATA | RTC_ADDR0_START_SER, tmp);
/* wait for the auto serializer to complete */
return regmap_read_poll_timeout(rtc->peripheral, RTC_REG4, tmp,
!(tmp & RTC_ADDR0_WAIT_SER), 10,
10000);
}
/* RTC interface layer functions */
static int meson_rtc_gettime(struct device *dev, struct rtc_time *tm)
{
struct meson_rtc *rtc = dev_get_drvdata(dev);
u32 time;
int ret;
ret = regmap_read(rtc->serial, RTC_COUNTER, &time);
if (!ret)
rtc_time64_to_tm(time, tm);
return ret;
}
static int meson_rtc_settime(struct device *dev, struct rtc_time *tm)
{
struct meson_rtc *rtc = dev_get_drvdata(dev);
return regmap_write(rtc->serial, RTC_COUNTER, rtc_tm_to_time64(tm));
}
static const struct rtc_class_ops meson_rtc_ops = {
.read_time = meson_rtc_gettime,
.set_time = meson_rtc_settime,
};
/* NVMEM interface layer functions */
static int meson_rtc_regmem_read(void *context, unsigned int offset,
void *buf, size_t bytes)
{
struct meson_rtc *rtc = context;
unsigned int read_offset, read_size;
read_offset = RTC_REGMEM_0 + (offset / 4);
read_size = bytes / 4;
return regmap_bulk_read(rtc->serial, read_offset, buf, read_size);
}
static int meson_rtc_regmem_write(void *context, unsigned int offset,
void *buf, size_t bytes)
{
struct meson_rtc *rtc = context;
unsigned int write_offset, write_size;
write_offset = RTC_REGMEM_0 + (offset / 4);
write_size = bytes / 4;
return regmap_bulk_write(rtc->serial, write_offset, buf, write_size);
}
static int meson_rtc_probe(struct platform_device *pdev)
{
struct nvmem_config meson_rtc_nvmem_config = {
.name = "meson-rtc-regmem",
.type = NVMEM_TYPE_BATTERY_BACKED,
.word_size = 4,
.stride = 4,
.size = 4 * 4,
.reg_read = meson_rtc_regmem_read,
.reg_write = meson_rtc_regmem_write,
};
struct device *dev = &pdev->dev;
struct meson_rtc *rtc;
struct resource *res;
void __iomem *base;
int ret;
u32 tm;
rtc = devm_kzalloc(dev, sizeof(struct meson_rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc->rtc))
return PTR_ERR(rtc->rtc);
platform_set_drvdata(pdev, rtc);
rtc->dev = dev;
rtc->rtc->ops = &meson_rtc_ops;
rtc->rtc->range_max = U32_MAX;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
rtc->peripheral = devm_regmap_init_mmio(dev, base,
&meson_rtc_peripheral_regmap_config);
if (IS_ERR(rtc->peripheral)) {
dev_err(dev, "failed to create peripheral regmap\n");
return PTR_ERR(rtc->peripheral);
}
rtc->reset = devm_reset_control_get(dev, NULL);
if (IS_ERR(rtc->reset)) {
dev_err(dev, "missing reset line\n");
return PTR_ERR(rtc->reset);
}
rtc->vdd = devm_regulator_get(dev, "vdd");
if (IS_ERR(rtc->vdd)) {
dev_err(dev, "failed to get the vdd-supply\n");
return PTR_ERR(rtc->vdd);
}
ret = regulator_enable(rtc->vdd);
if (ret) {
dev_err(dev, "failed to enable vdd-supply\n");
return ret;
}
ret = meson_rtc_write_static(rtc, MESON_STATIC_DEFAULT);
if (ret) {
dev_err(dev, "failed to set static values\n");
goto out_disable_vdd;
}
rtc->serial = devm_regmap_init(dev, &meson_rtc_serial_bus, rtc,
&meson_rtc_serial_regmap_config);
if (IS_ERR(rtc->serial)) {
dev_err(dev, "failed to create serial regmap\n");
ret = PTR_ERR(rtc->serial);
goto out_disable_vdd;
}
/*
* check if we can read RTC counter, if not then the RTC is probably
* not functional. If it isn't probably best to not bind.
*/
ret = regmap_read(rtc->serial, RTC_COUNTER, &tm);
if (ret) {
dev_err(dev, "cannot read RTC counter, RTC not functional\n");
goto out_disable_vdd;
}
meson_rtc_nvmem_config.priv = rtc;
ret = rtc_nvmem_register(rtc->rtc, &meson_rtc_nvmem_config);
if (ret)
goto out_disable_vdd;
ret = rtc_register_device(rtc->rtc);
if (ret)
goto out_disable_vdd;
return 0;
out_disable_vdd:
regulator_disable(rtc->vdd);
return ret;
}
static const struct of_device_id meson_rtc_dt_match[] = {
{ .compatible = "amlogic,meson6-rtc", },
{ .compatible = "amlogic,meson8-rtc", },
{ .compatible = "amlogic,meson8b-rtc", },
{ .compatible = "amlogic,meson8m2-rtc", },
{ },
};
MODULE_DEVICE_TABLE(of, meson_rtc_dt_match);
static struct platform_driver meson_rtc_driver = {
.probe = meson_rtc_probe,
.driver = {
.name = "meson-rtc",
.of_match_table = of_match_ptr(meson_rtc_dt_match),
},
};
module_platform_driver(meson_rtc_driver);
MODULE_DESCRIPTION("Amlogic Meson RTC Driver");
MODULE_AUTHOR("Ben Dooks <ben.doosk@codethink.co.uk>");
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:meson-rtc");
...@@ -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:
......
// SPDX-License-Identifier: GPL-2.0
/*
* RTC driver for the Micro Crystal RV3028
*
* Copyright (C) 2019 Micro Crystal SA
*
* Alexandre Belloni <alexandre.belloni@bootlin.com>
*
*/
#include <linux/bcd.h>
#include <linux/bitops.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#define RV3028_SEC 0x00
#define RV3028_MIN 0x01
#define RV3028_HOUR 0x02
#define RV3028_WDAY 0x03
#define RV3028_DAY 0x04
#define RV3028_MONTH 0x05
#define RV3028_YEAR 0x06
#define RV3028_ALARM_MIN 0x07
#define RV3028_ALARM_HOUR 0x08
#define RV3028_ALARM_DAY 0x09
#define RV3028_STATUS 0x0E
#define RV3028_CTRL1 0x0F
#define RV3028_CTRL2 0x10
#define RV3028_EVT_CTRL 0x13
#define RV3028_TS_COUNT 0x14
#define RV3028_TS_SEC 0x15
#define RV3028_RAM1 0x1F
#define RV3028_EEPROM_ADDR 0x25
#define RV3028_EEPROM_DATA 0x26
#define RV3028_EEPROM_CMD 0x27
#define RV3028_CLKOUT 0x35
#define RV3028_OFFSET 0x36
#define RV3028_BACKUP 0x37
#define RV3028_STATUS_PORF BIT(0)
#define RV3028_STATUS_EVF BIT(1)
#define RV3028_STATUS_AF BIT(2)
#define RV3028_STATUS_TF BIT(3)
#define RV3028_STATUS_UF BIT(4)
#define RV3028_STATUS_BSF BIT(5)
#define RV3028_STATUS_CLKF BIT(6)
#define RV3028_STATUS_EEBUSY BIT(7)
#define RV3028_CTRL1_EERD BIT(3)
#define RV3028_CTRL1_WADA BIT(5)
#define RV3028_CTRL2_RESET BIT(0)
#define RV3028_CTRL2_12_24 BIT(1)
#define RV3028_CTRL2_EIE BIT(2)
#define RV3028_CTRL2_AIE BIT(3)
#define RV3028_CTRL2_TIE BIT(4)
#define RV3028_CTRL2_UIE BIT(5)
#define RV3028_CTRL2_TSE BIT(7)
#define RV3028_EVT_CTRL_TSR BIT(2)
#define RV3028_EEPROM_CMD_WRITE 0x21
#define RV3028_EEPROM_CMD_READ 0x22
#define RV3028_EEBUSY_POLL 10000
#define RV3028_EEBUSY_TIMEOUT 100000
#define RV3028_BACKUP_TCE BIT(5)
#define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
#define OFFSET_STEP_PPT 953674
enum rv3028_type {
rv_3028,
};
struct rv3028_data {
struct regmap *regmap;
struct rtc_device *rtc;
enum rv3028_type type;
};
static u16 rv3028_trickle_resistors[] = {1000, 3000, 6000, 11000};
static ssize_t timestamp0_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
regmap_update_bits(rv3028->regmap, RV3028_EVT_CTRL, RV3028_EVT_CTRL_TSR,
RV3028_EVT_CTRL_TSR);
return count;
};
static ssize_t timestamp0_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent);
struct rtc_time tm;
int ret, count;
u8 date[6];
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret)
return ret;
if (!count)
return 0;
ret = regmap_bulk_read(rv3028->regmap, RV3028_TS_SEC, date,
sizeof(date));
if (ret)
return ret;
tm.tm_sec = bcd2bin(date[0]);
tm.tm_min = bcd2bin(date[1]);
tm.tm_hour = bcd2bin(date[2]);
tm.tm_mday = bcd2bin(date[3]);
tm.tm_mon = bcd2bin(date[4]) - 1;
tm.tm_year = bcd2bin(date[5]) + 100;
ret = rtc_valid_tm(&tm);
if (ret)
return ret;
return sprintf(buf, "%llu\n",
(unsigned long long)rtc_tm_to_time64(&tm));
};
static DEVICE_ATTR_RW(timestamp0);
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;
ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count);
if (ret)
return ret;
return sprintf(buf, "%u\n", count);
};
static DEVICE_ATTR_RO(timestamp0_count);
static struct attribute *rv3028_attrs[] = {
&dev_attr_timestamp0.attr,
&dev_attr_timestamp0_count.attr,
NULL
};
static const struct attribute_group rv3028_attr_group = {
.attrs = rv3028_attrs,
};
static irqreturn_t rv3028_handle_irq(int irq, void *dev_id)
{
struct rv3028_data *rv3028 = dev_id;
unsigned long events = 0;
u32 status = 0, ctrl = 0;
if (regmap_read(rv3028->regmap, RV3028_STATUS, &status) < 0 ||
status == 0) {
return IRQ_NONE;
}
if (status & RV3028_STATUS_PORF)
dev_warn(&rv3028->rtc->dev, "Voltage low, data loss detected.\n");
if (status & RV3028_STATUS_TF) {
status |= RV3028_STATUS_TF;
ctrl |= RV3028_CTRL2_TIE;
events |= RTC_PF;
}
if (status & RV3028_STATUS_AF) {
status |= RV3028_STATUS_AF;
ctrl |= RV3028_CTRL2_AIE;
events |= RTC_AF;
}
if (status & RV3028_STATUS_UF) {
status |= RV3028_STATUS_UF;
ctrl |= RV3028_CTRL2_UIE;
events |= RTC_UF;
}
if (events) {
rtc_update_irq(rv3028->rtc, 1, events);
regmap_update_bits(rv3028->regmap, RV3028_STATUS, status, 0);
regmap_update_bits(rv3028->regmap, RV3028_CTRL2, ctrl, 0);
}
if (status & RV3028_STATUS_EVF) {
sysfs_notify(&rv3028->rtc->dev.kobj, NULL,
dev_attr_timestamp0.attr.name);
dev_warn(&rv3028->rtc->dev, "event detected");
}
return IRQ_HANDLED;
}
static int rv3028_get_time(struct device *dev, struct rtc_time *tm)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
u8 date[7];
int ret, status;
ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
if (ret < 0)
return ret;
if (status & RV3028_STATUS_PORF) {
dev_warn(dev, "Voltage low, data is invalid.\n");
return -EINVAL;
}
ret = regmap_bulk_read(rv3028->regmap, RV3028_SEC, date, sizeof(date));
if (ret)
return ret;
tm->tm_sec = bcd2bin(date[RV3028_SEC] & 0x7f);
tm->tm_min = bcd2bin(date[RV3028_MIN] & 0x7f);
tm->tm_hour = bcd2bin(date[RV3028_HOUR] & 0x3f);
tm->tm_wday = ilog2(date[RV3028_WDAY] & 0x7f);
tm->tm_mday = bcd2bin(date[RV3028_DAY] & 0x3f);
tm->tm_mon = bcd2bin(date[RV3028_MONTH] & 0x1f) - 1;
tm->tm_year = bcd2bin(date[RV3028_YEAR]) + 100;
return 0;
}
static int rv3028_set_time(struct device *dev, struct rtc_time *tm)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
u8 date[7];
int ret;
date[RV3028_SEC] = bin2bcd(tm->tm_sec);
date[RV3028_MIN] = bin2bcd(tm->tm_min);
date[RV3028_HOUR] = bin2bcd(tm->tm_hour);
date[RV3028_WDAY] = 1 << (tm->tm_wday);
date[RV3028_DAY] = bin2bcd(tm->tm_mday);
date[RV3028_MONTH] = bin2bcd(tm->tm_mon + 1);
date[RV3028_YEAR] = bin2bcd(tm->tm_year - 100);
/*
* Writing to the Seconds register has the same effect as setting RESET
* bit to 1
*/
ret = regmap_bulk_write(rv3028->regmap, RV3028_SEC, date,
sizeof(date));
if (ret)
return ret;
ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
RV3028_STATUS_PORF, 0);
return ret;
}
static int rv3028_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
u8 alarmvals[3];
int status, ctrl, ret;
ret = regmap_bulk_read(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
sizeof(alarmvals));
if (ret)
return ret;
ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
if (ret < 0)
return ret;
ret = regmap_read(rv3028->regmap, RV3028_CTRL2, &ctrl);
if (ret < 0)
return ret;
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->enabled = !!(ctrl & RV3028_CTRL2_AIE);
alrm->pending = (status & RV3028_STATUS_AF) && alrm->enabled;
return 0;
}
static int rv3028_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
u8 alarmvals[3];
u8 ctrl = 0;
int ret;
/* The alarm has no seconds, round up to nearest minute */
if (alrm->time.tm_sec) {
time64_t alarm_time = rtc_tm_to_time64(&alrm->time);
alarm_time += 60 - alrm->time.tm_sec;
rtc_time64_to_tm(alarm_time, &alrm->time);
}
ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
RV3028_CTRL2_AIE | RV3028_CTRL2_UIE, 0);
if (ret)
return ret;
alarmvals[0] = bin2bcd(alrm->time.tm_min);
alarmvals[1] = bin2bcd(alrm->time.tm_hour);
alarmvals[2] = bin2bcd(alrm->time.tm_mday);
ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
RV3028_STATUS_AF, 0);
if (ret)
return ret;
ret = regmap_bulk_write(rv3028->regmap, RV3028_ALARM_MIN, alarmvals,
sizeof(alarmvals));
if (ret)
return ret;
if (alrm->enabled) {
if (rv3028->rtc->uie_rtctimer.enabled)
ctrl |= RV3028_CTRL2_UIE;
if (rv3028->rtc->aie_timer.enabled)
ctrl |= RV3028_CTRL2_AIE;
}
ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
return ret;
}
static int rv3028_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
int ctrl = 0, ret;
if (enabled) {
if (rv3028->rtc->uie_rtctimer.enabled)
ctrl |= RV3028_CTRL2_UIE;
if (rv3028->rtc->aie_timer.enabled)
ctrl |= RV3028_CTRL2_AIE;
}
ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
RV3028_STATUS_AF | RV3028_STATUS_UF, 0);
if (ret)
return ret;
ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl);
if (ret)
return ret;
return 0;
}
static int rv3028_read_offset(struct device *dev, long *offset)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
int ret, value, steps;
ret = regmap_read(rv3028->regmap, RV3028_OFFSET, &value);
if (ret < 0)
return ret;
steps = sign_extend32(value << 1, 8);
ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
if (ret < 0)
return ret;
steps += value >> 7;
*offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000);
return 0;
}
static int rv3028_set_offset(struct device *dev, long offset)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
int ret;
offset = clamp(offset, -244141L, 243187L) * 1000;
offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT);
ret = regmap_write(rv3028->regmap, RV3028_OFFSET, offset >> 1);
if (ret < 0)
return ret;
return regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7),
offset << 7);
}
static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct rv3028_data *rv3028 = dev_get_drvdata(dev);
int status, ret = 0;
switch (cmd) {
case RTC_VL_READ:
ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
if (ret < 0)
return ret;
if (status & RV3028_STATUS_PORF)
dev_warn(&rv3028->rtc->dev, "Voltage low, data loss detected.\n");
status &= RV3028_STATUS_PORF;
if (copy_to_user((void __user *)arg, &status, sizeof(int)))
return -EFAULT;
return 0;
case RTC_VL_CLR:
ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS,
RV3028_STATUS_PORF, 0);
return ret;
default:
return -ENOIOCTLCMD;
}
}
static int rv3028_nvram_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
return regmap_bulk_write(priv, RV3028_RAM1 + offset, val, bytes);
}
static int rv3028_nvram_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
return regmap_bulk_read(priv, RV3028_RAM1 + offset, val, bytes);
}
static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
u32 status, ctrl1;
int i, ret, err;
u8 *buf = val;
ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
if (ret)
return ret;
if (!(ctrl1 & RV3028_CTRL1_EERD)) {
ret = regmap_update_bits(priv, RV3028_CTRL1,
RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
if (ret)
return ret;
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
if (ret)
goto restore_eerd;
}
for (i = 0; i < bytes; i++) {
ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_DATA, buf[i]);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD,
RV3028_EEPROM_CMD_WRITE);
if (ret)
goto restore_eerd;
usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT);
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
if (ret)
goto restore_eerd;
}
restore_eerd:
if (!(ctrl1 & RV3028_CTRL1_EERD))
{
err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
0);
if (err && !ret)
ret = err;
}
return ret;
}
static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
u32 status, ctrl1, data;
int i, ret, err;
u8 *buf = val;
ret = regmap_read(priv, RV3028_CTRL1, &ctrl1);
if (ret)
return ret;
if (!(ctrl1 & RV3028_CTRL1_EERD)) {
ret = regmap_update_bits(priv, RV3028_CTRL1,
RV3028_CTRL1_EERD, RV3028_CTRL1_EERD);
if (ret)
return ret;
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
if (ret)
goto restore_eerd;
}
for (i = 0; i < bytes; i++) {
ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0);
if (ret)
goto restore_eerd;
ret = regmap_write(priv, RV3028_EEPROM_CMD,
RV3028_EEPROM_CMD_READ);
if (ret)
goto restore_eerd;
ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status,
!(status & RV3028_STATUS_EEBUSY),
RV3028_EEBUSY_POLL,
RV3028_EEBUSY_TIMEOUT);
if (ret)
goto restore_eerd;
ret = regmap_read(priv, RV3028_EEPROM_DATA, &data);
if (ret)
goto restore_eerd;
buf[i] = data;
}
restore_eerd:
if (!(ctrl1 & RV3028_CTRL1_EERD))
{
err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD,
0);
if (err && !ret)
ret = err;
}
return ret;
}
static struct rtc_class_ops rv3028_rtc_ops = {
.read_time = rv3028_get_time,
.set_time = rv3028_set_time,
.read_offset = rv3028_read_offset,
.set_offset = rv3028_set_offset,
.ioctl = rv3028_ioctl,
};
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x37,
};
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,
.stride = 1,
.size = 2,
.type = NVMEM_TYPE_BATTERY_BACKED,
.reg_read = rv3028_nvram_read,
.reg_write = rv3028_nvram_write,
};
struct nvmem_config eeprom_cfg = {
.name = "rv3028_eeprom",
.word_size = 1,
.stride = 1,
.size = 43,
.type = NVMEM_TYPE_EEPROM,
.reg_read = rv3028_eeprom_read,
.reg_write = rv3028_eeprom_write,
};
rv3028 = devm_kzalloc(&client->dev, sizeof(struct rv3028_data),
GFP_KERNEL);
if (!rv3028)
return -ENOMEM;
rv3028->regmap = devm_regmap_init_i2c(client, &regmap_config);
i2c_set_clientdata(client, rv3028);
ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status);
if (ret < 0)
return ret;
if (status & RV3028_STATUS_PORF)
dev_warn(&client->dev, "Voltage low, data loss detected.\n");
if (status & RV3028_STATUS_AF)
dev_warn(&client->dev, "An alarm may have been missed.\n");
rv3028->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(rv3028->rtc)) {
return PTR_ERR(rv3028->rtc);
}
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv3028_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"rv3028", rv3028);
if (ret) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
client->irq = 0;
} else {
rv3028_rtc_ops.read_alarm = rv3028_get_alarm;
rv3028_rtc_ops.set_alarm = rv3028_set_alarm;
rv3028_rtc_ops.alarm_irq_enable = rv3028_alarm_irq_enable;
}
}
ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1,
RV3028_CTRL1_WADA, RV3028_CTRL1_WADA);
if (ret)
return ret;
/* setup timestamping */
ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2,
RV3028_CTRL2_EIE | RV3028_CTRL2_TSE,
RV3028_CTRL2_EIE | RV3028_CTRL2_TSE);
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 = regmap_update_bits(rv3028->regmap, 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 = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
if (ret)
return ret;
rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099;
rv3028->rtc->ops = &rv3028_rtc_ops;
ret = rtc_register_device(rv3028->rtc);
if (ret)
return ret;
nvmem_cfg.priv = rv3028->regmap;
rtc_nvmem_register(rv3028->rtc, &nvmem_cfg);
eeprom_cfg.priv = rv3028->regmap;
rtc_nvmem_register(rv3028->rtc, &eeprom_cfg);
rv3028->rtc->max_user_freq = 1;
return 0;
}
static const struct of_device_id rv3028_of_match[] = {
{ .compatible = "microcrystal,rv3028", },
{ }
};
MODULE_DEVICE_TABLE(of, rv3028_of_match);
static struct i2c_driver rv3028_driver = {
.driver = {
.name = "rtc-rv3028",
.of_match_table = of_match_ptr(rv3028_of_match),
},
.probe_new = rv3028_probe,
};
module_i2c_driver(rv3028_driver);
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
MODULE_DESCRIPTION("Micro Crystal RV3028 RTC driver");
MODULE_LICENSE("GPL v2");
// 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:
......
// SPDX-License-Identifier: GPL-2.0
/*
* Real Time Clock (RTC) Driver for sd3078
* Copyright (C) 2018 Zoro Li
*/
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#define SD3078_REG_SC 0x00
#define SD3078_REG_MN 0x01
#define SD3078_REG_HR 0x02
#define SD3078_REG_DW 0x03
#define SD3078_REG_DM 0x04
#define SD3078_REG_MO 0x05
#define SD3078_REG_YR 0x06
#define SD3078_REG_CTRL1 0x0f
#define SD3078_REG_CTRL2 0x10
#define SD3078_REG_CTRL3 0x11
#define KEY_WRITE1 0x80
#define KEY_WRITE2 0x04
#define KEY_WRITE3 0x80
#define NUM_TIME_REGS (SD3078_REG_YR - SD3078_REG_SC + 1)
/*
* The sd3078 has write protection
* and we can choose whether or not to use it.
* Write protection is turned off by default.
*/
#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,
* the "write" bit needs to be written in a certain order.
* 1. set WRITE1 bit
* 2. set WRITE2 bit
* 3. set WRITE3 bit
*/
static void sd3078_enable_reg_write(struct sd3078 *sd3078)
{
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);
}
#if WRITE_PROTECT_EN
/*
* In order to prevent arbitrary modification of the time register,
* we should disable the write function.
* when disable write,
* the "write" bit needs to be clear in a certain order.
* 1. clear WRITE2 bit
* 2. clear WRITE3 bit
* 3. clear WRITE1 bit
*/
static void sd3078_disable_reg_write(struct sd3078 *sd3078)
{
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);
}
#endif
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);
int ret;
ret = regmap_bulk_read(sd3078->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;
}
tm->tm_sec = bcd2bin(rtc_data[SD3078_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(rtc_data[SD3078_REG_MN] & 0x7F);
/*
* The sd3078 supports 12/24 hour mode.
* When getting time,
* we need to convert the 12 hour mode to the 24 hour mode.
*/
hour = rtc_data[SD3078_REG_HR];
if (hour & 0x80) /* 24H MODE */
tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x3F);
else if (hour & 0x20) /* 12H MODE PM */
tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F) + 12;
else /* 12H MODE AM */
tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F);
tm->tm_mday = bcd2bin(rtc_data[SD3078_REG_DM] & 0x3F);
tm->tm_wday = rtc_data[SD3078_REG_DW] & 0x07;
tm->tm_mon = bcd2bin(rtc_data[SD3078_REG_MO] & 0x1F) - 1;
tm->tm_year = bcd2bin(rtc_data[SD3078_REG_YR]) + 100;
return 0;
}
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);
int ret;
rtc_data[SD3078_REG_SC] = bin2bcd(tm->tm_sec);
rtc_data[SD3078_REG_MN] = bin2bcd(tm->tm_min);
rtc_data[SD3078_REG_HR] = bin2bcd(tm->tm_hour) | 0x80;
rtc_data[SD3078_REG_DM] = bin2bcd(tm->tm_mday);
rtc_data[SD3078_REG_DW] = tm->tm_wday & 0x07;
rtc_data[SD3078_REG_MO] = bin2bcd(tm->tm_mon) + 1;
rtc_data[SD3078_REG_YR] = bin2bcd(tm->tm_year - 100);
#if WRITE_PROTECT_EN
sd3078_enable_reg_write(sd3078);
#endif
ret = regmap_bulk_write(sd3078->regmap, SD3078_REG_SC, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "writing to RTC failed with err:%d\n", ret);
return ret;
}
#if WRITE_PROTECT_EN
sd3078_disable_reg_write(sd3078);
#endif
return 0;
}
static const struct rtc_class_ops sd3078_rtc_ops = {
.read_time = sd3078_rtc_read_time,
.set_time = sd3078_rtc_set_time,
};
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x11,
};
static int sd3078_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct sd3078 *sd3078;
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)) {
dev_err(&client->dev, "regmap allocation failed\n");
return PTR_ERR(sd3078->regmap);
}
i2c_set_clientdata(client, sd3078);
sd3078->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(sd3078->rtc))
return PTR_ERR(sd3078->rtc);
sd3078->rtc->ops = &sd3078_rtc_ops;
sd3078->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099;
ret = rtc_register_device(sd3078->rtc);
if (ret) {
dev_err(&client->dev, "failed to register rtc device\n");
return ret;
}
sd3078_enable_reg_write(sd3078);
return 0;
}
static const struct i2c_device_id sd3078_id[] = {
{"sd3078", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, sd3078_id);
static const struct of_device_id rtc_dt_match[] = {
{ .compatible = "whwave,sd3078" },
{},
};
MODULE_DEVICE_TABLE(of, rtc_dt_match);
static struct i2c_driver sd3078_driver = {
.driver = {
.name = "sd3078",
.of_match_table = of_match_ptr(rtc_dt_match),
},
.probe = sd3078_probe,
.id_table = sd3078_id,
};
module_i2c_driver(sd3078_driver);
MODULE_AUTHOR("Dianlong Li <long17.cool@163.com>");
MODULE_DESCRIPTION("SD3078 RTC driver");
MODULE_LICENSE("GPL v2");
...@@ -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