forked from luck/tmp_suning_uos_patched
RTC for 5.3
Drivers: - ds1307: properly handle oscillator failure flags - imx-sc: alarm support - pcf2123: alarm support, correct offset handling - sun6i: add R40 support - simplify getting the adapter of an i2c client -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEycoQi/giopmpPgB12wIijOdRNOUFAl0tl5UACgkQ2wIijOdR NOVMig/8C7o1tBpm1Kfs3GYjZ5o2SI7m6425OypONOa9U2rFVnFHxVogtIHTC7wa SXVFdV+L/MT/xHEbQ3Mfv36cRB0h3Q89NqcVWFkjSGvoqliTIA2F2zsLDHYLDyEO AdOc8ztzrTCmlPjrg7d64qxA/l/dPChIhDW1nsMTJY7EXO0lBywcEP0KQsnOrjzD lNDskhLuYaL0h1OL2KSrx/81ZZW1MXEyTU5nl4e2JowVYFB0f75P7h79MChmjM35 wE5WVDH8LqhYHOoVR9fW5sjRpNgdKfFsH8Sh5DGVU3jLGA72v0Eo/c1BHHegumoI 6X+09nv9D3j4l2z5on5TzXMhvwuLdZQ2VRBdpI1XcVjtYA18UTIXZA8wDRgLTb3b MZE31s1WM0vxSiGyaL+hfI9APfX0xSd+BIqVvxhUVPvCGCwWvfLJgQfmlsW4eWOk LdmifkLb0Mjf+ym+WH8GvXND+ZeNJ9eUUwVZkGHPhb6SfkLiEAnw3f1czOT1fLDR q6i0hG9/+BsiwZMCJt86rDZd1D51FjkNzUH1d///iURvaDhoi41nKaFR45kc5Foc WVmnWDWw1yg7K6kUQ3kXsyBkbw0jhdCXGN539rrvbElyL5e5XDUo+3gAEi25CkVe DCpxICWO+jvOrjJBHdH3T3HJDa7NbFXWkXOwLXe5M42q7rrgZwY= =aJ54 -----END PGP SIGNATURE----- Merge tag 'rtc-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "A quiet cycle this time. - ds1307: properly handle oscillator failure flags - imx-sc: alarm support - pcf2123: alarm support, correct offset handling - sun6i: add R40 support - simplify getting the adapter of an i2c client" * tag 'rtc-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (37 commits) rtc: wm831x: Add IRQF_ONESHOT flag rtc: stm32: remove one condition check in stm32_rtc_set_alarm() rtc: pcf2123: Fix build error rtc: interface: Change type of 'count' from int to u64 rtc: pcf8563: Clear event flags and disable interrupts before requesting irq rtc: pcf8563: Fix interrupt trigger method rtc: pcf2123: fix negative offset rounding rtc: pcf2123: add alarm support rtc: pcf2123: use %ptR rtc: pcf2123: port to regmap rtc: pcf2123: remove sysfs register view rtc: rx8025: simplify getting the adapter of a client rtc: rx8010: simplify getting the adapter of a client rtc: rv8803: simplify getting the adapter of a client rtc: m41t80: simplify getting the adapter of a client rtc: fm3130: simplify getting the adapter of a client rtc: tegra: Drop MODULE_ALIAS rtc: sun6i: Add R40 compatible dt-bindings: rtc: sun6i: Add the R40 RTC compatible dt-bindings: rtc: Convert Allwinner A31 RTC to a schema ...
This commit is contained in:
commit
edafb6fe42
|
@ -0,0 +1,43 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/allwinner,sun4i-a10-rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A10 RTC Device Tree Bindings
|
||||
|
||||
allOf:
|
||||
- $ref: "rtc.yaml#"
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-rtc
|
||||
- allwinner,sun7i-a20-rtc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
rtc: rtc@1c20d00 {
|
||||
compatible = "allwinner,sun4i-a10-rtc";
|
||||
reg = <0x01c20d00 0x20>;
|
||||
interrupts = <24>;
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,134 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/allwinner,sun6i-a31-rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A31 RTC Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
|
||||
properties:
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: allwinner,sun6i-a31-rtc
|
||||
- const: allwinner,sun8i-a23-rtc
|
||||
- const: allwinner,sun8i-h3-rtc
|
||||
- const: allwinner,sun8i-r40-rtc
|
||||
- const: allwinner,sun8i-v3-rtc
|
||||
- const: allwinner,sun50i-h5-rtc
|
||||
- items:
|
||||
- const: allwinner,sun50i-a64-rtc
|
||||
- const: allwinner,sun8i-h3-rtc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: RTC Alarm 0
|
||||
- description: RTC Alarm 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-output-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
description:
|
||||
The RTC provides up to three clocks
|
||||
- the Low Frequency Oscillator or LOSC, at index 0,
|
||||
- the Low Frequency Oscillator External output (X32KFOUT in
|
||||
the datasheet), at index 1,
|
||||
- the Internal Oscillator, at index 2.
|
||||
|
||||
allOf:
|
||||
- $ref: "rtc.yaml#"
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun6i-a31-rtc
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-output-names:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun8i-a23-rtc
|
||||
- allwinner,sun8i-r40-rtc
|
||||
- allwinner,sun8i-v3-rtc
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-output-names:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun8i-h3-rtc
|
||||
- allwinner,sun50i-h5-rtc
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-output-names:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun8i-r40-rtc
|
||||
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
|
||||
else:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
required:
|
||||
- "#clock-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-output-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
rtc: rtc@1f00000 {
|
||||
compatible = "allwinner,sun6i-a31-rtc";
|
||||
reg = <0x01f00000 0x400>;
|
||||
interrupts = <0 40 4>, <0 41 4>;
|
||||
clock-output-names = "osc32k";
|
||||
clocks = <&ext_osc32k>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
|
@ -1,72 +1 @@
|
|||
Generic device tree bindings for Real Time Clock devices
|
||||
========================================================
|
||||
|
||||
This document describes generic bindings which can be used to describe Real Time
|
||||
Clock devices in a device tree.
|
||||
|
||||
Required properties
|
||||
-------------------
|
||||
|
||||
- compatible : name of RTC device following generic names recommended practice.
|
||||
|
||||
For other required properties e.g. to describe register sets,
|
||||
clocks, etc. check the binding documentation of the specific driver.
|
||||
|
||||
Optional properties
|
||||
-------------------
|
||||
|
||||
- start-year : if provided, the default hardware range supported by the RTC is
|
||||
shifted so the first usable year is the specified one.
|
||||
|
||||
The following properties may not be supported by all drivers. However, if a
|
||||
driver wants to support one of the below features, it should adapt the bindings
|
||||
below.
|
||||
- trickle-resistor-ohms : Selected resistor for trickle charger. Should be given
|
||||
if trickle charger should be enabled
|
||||
- trickle-diode-disable : Do not use internal trickle charger diode Should be
|
||||
given if internal trickle charger diode should be
|
||||
disabled
|
||||
- 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
|
||||
------------
|
||||
|
||||
This is a list of trivial RTC devices that have simple device tree
|
||||
bindings, consisting only of a compatible field, an address and
|
||||
possibly an interrupt line.
|
||||
|
||||
|
||||
Compatible Vendor / Chip
|
||||
========== =============
|
||||
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,ds1672 Dallas DS1672 Real-time Clock
|
||||
dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM
|
||||
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
|
||||
emmicro,em3027 EM Microelectronic EM3027 Real-time Clock
|
||||
isil,isl1208 Intersil ISL1208 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
|
||||
microcrystal,rv3028 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,pcf2129 Real-time clock
|
||||
nxp,pcf8563 Real-time clock/calendar
|
||||
pericom,pt7c4338 Real-time Clock Module
|
||||
ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
ricoh,rs5c372b 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
|
||||
sii,s35390a 2-wire CMOS real-time clock
|
||||
whwave,sd3078 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
xircom,x1205 Xircom X1205 I2C RTC
|
||||
This file has been moved to rtc.yaml.
|
||||
|
|
50
Documentation/devicetree/bindings/rtc/rtc.yaml
Normal file
50
Documentation/devicetree/bindings/rtc/rtc.yaml
Normal file
|
@ -0,0 +1,50 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: RTC Generic Binding
|
||||
|
||||
maintainers:
|
||||
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
|
||||
description: |
|
||||
This document describes generic bindings which can be used to
|
||||
describe Real Time Clock devices in a device tree.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^rtc(@.*|-[0-9a-f])*$"
|
||||
|
||||
quartz-load-femtofarads:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
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.
|
||||
|
||||
start-year:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
If provided, the default hardware range supported by the RTC is
|
||||
shifted so the first usable year is the specified one.
|
||||
|
||||
trickle-diode-disable:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Do not use internal trickle charger diode. Should be given if
|
||||
internal trickle charger diode should be disabled.
|
||||
|
||||
trickle-resistor-ohms:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Selected resistor for trickle charger. Should be given
|
||||
if trickle charger should be enabled.
|
||||
|
||||
wakeup-source:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Enables wake up of host system on alarm.
|
||||
|
||||
...
|
|
@ -1,46 +0,0 @@
|
|||
* sun6i Real Time Clock
|
||||
|
||||
RTC controller for the Allwinner A31
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be one of the following combinations:
|
||||
- "allwinner,sun6i-a31-rtc"
|
||||
- "allwinner,sun8i-a23-rtc"
|
||||
- "allwinner,sun8i-h3-rtc"
|
||||
- "allwinner,sun8i-r40-rtc", "allwinner,sun8i-h3-rtc"
|
||||
- "allwinner,sun8i-v3-rtc"
|
||||
- "allwinner,sun50i-a64-rtc", "allwinner,sun8i-h3-rtc"
|
||||
- "allwinner,sun50i-h5-rtc"
|
||||
|
||||
Where there are two or more compatible strings, this
|
||||
denotes the hardware covered by the most specific one
|
||||
is backward-compatible with the latter ones, and the
|
||||
implementation for the latter ones can be used, albeit
|
||||
with reduced functionality.
|
||||
|
||||
- reg : physical base address of the controller and length of
|
||||
memory mapped region.
|
||||
- interrupts : IRQ lines for the RTC alarm 0 and alarm 1, in that order.
|
||||
|
||||
Required properties for new device trees
|
||||
- clocks : phandle to the 32kHz external oscillator
|
||||
- clock-output-names : names of up to three clock outputs. See below.
|
||||
- #clock-cells : must be equal to 1.
|
||||
|
||||
The RTC provides the following clocks at the given indices:
|
||||
- 0: LOSC
|
||||
- 1: LOSC external output, known as X32KFOUT in the datasheet.
|
||||
This clock is not available on the A31 and is deprecated for old
|
||||
device trees still using the "allwinner,sun6i-a31-rtc" compatible.
|
||||
- 2: InternalOSC, or internal RC oscillator (A64/H3/H5 only)
|
||||
|
||||
Example:
|
||||
|
||||
rtc: rtc@1f00000 {
|
||||
compatible = "allwinner,sun6i-a31-rtc";
|
||||
reg = <0x01f00000 0x400>;
|
||||
interrupts = <0 40 4>, <0 41 4>;
|
||||
clock-output-names = "osc32k";
|
||||
clocks = <&ext_osc32k>;
|
||||
#clock-cells = <1>;
|
||||
};
|
|
@ -1,17 +0,0 @@
|
|||
* sun4i/sun7i Real Time Clock
|
||||
|
||||
RTC controller for the Allwinner A10/A20
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "allwinner,sun4i-a10-rtc" or "allwinner,sun7i-a20-rtc"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: IRQ line for the RTC.
|
||||
|
||||
Example:
|
||||
|
||||
rtc: rtc@1c20d00 {
|
||||
compatible = "allwinner,sun4i-a10-rtc";
|
||||
reg = <0x01c20d00 0x20>;
|
||||
interrupts = <24>;
|
||||
};
|
92
Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
Normal file
92
Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
Normal file
|
@ -0,0 +1,92 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/trivial-rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Trivial RTCs
|
||||
|
||||
maintainers:
|
||||
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
|
||||
description: |
|
||||
This is a list of trivial RTC devices that have simple device tree
|
||||
bindings, consisting only of a compatible field, an address and
|
||||
possibly an interrupt line.
|
||||
|
||||
allOf:
|
||||
- $ref: "rtc.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface
|
||||
- abracon,abb5zes3
|
||||
# AB-RTCMC-32.768kHz-EOZ9: Real Time Clock/Calendar Module with I2C Interface
|
||||
- abracon,abeoz9
|
||||
# I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
|
||||
- dallas,ds1374
|
||||
# Dallas DS1672 Real-time Clock
|
||||
- dallas,ds1672
|
||||
# Extremely Accurate I²C RTC with Integrated Crystal and SRAM
|
||||
- dallas,ds3232
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
- epson,rx8010
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM
|
||||
- epson,rx8571
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
- epson,rx8581
|
||||
# Intersil ISL1208 Low Power RTC with Battery Backed SRAM
|
||||
- isil,isl1208
|
||||
# Intersil ISL1218 Low Power RTC with Battery Backed SRAM
|
||||
- isil,isl1218
|
||||
# Intersil ISL12022 Real-time Clock
|
||||
- isil,isl12022
|
||||
# Real Time Clock Module with I2C-Bus
|
||||
- microcrystal,rv3028
|
||||
# Real Time Clock Module with I2C-Bus
|
||||
- microcrystal,rv3029
|
||||
# Real Time Clock
|
||||
- microcrystal,rv8523
|
||||
# Real-time clock
|
||||
- nxp,pcf2127
|
||||
# Real-time clock
|
||||
- nxp,pcf2129
|
||||
# Real-time clock/calendar
|
||||
- nxp,pcf8563
|
||||
# Real-time Clock Module
|
||||
- pericom,pt7c4338
|
||||
# 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,rs5c372a
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
- ricoh,rs5c372b
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
- ricoh,rv5c386
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
- ricoh,rv5c387a
|
||||
# 2-wire CMOS real-time clock
|
||||
- sii,s35390a
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
- whwave,sd3078
|
||||
# Xircom X1205 I2C RTC
|
||||
- xircom,x1205
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
start-year: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
...
|
|
@ -562,7 +562,7 @@ config RTC_DRV_TPS6586X
|
|||
|
||||
config RTC_DRV_TPS65910
|
||||
tristate "TI TPS65910 RTC driver"
|
||||
depends on RTC_CLASS && MFD_TPS65910
|
||||
depends on MFD_TPS65910
|
||||
help
|
||||
If you say yes here you get support for the RTC on the
|
||||
TPS65910 chips.
|
||||
|
@ -820,6 +820,7 @@ config RTC_DRV_MAX6902
|
|||
|
||||
config RTC_DRV_PCF2123
|
||||
tristate "NXP PCF2123"
|
||||
select REGMAP_SPI
|
||||
help
|
||||
If you say yes here you get support for the NXP PCF2123
|
||||
RTC chip.
|
||||
|
|
|
@ -633,7 +633,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
|
|||
{
|
||||
struct rtc_device *rtc;
|
||||
ktime_t period;
|
||||
int count;
|
||||
u64 count;
|
||||
|
||||
rtc = container_of(timer, struct rtc_device, pie_timer);
|
||||
|
||||
|
|
|
@ -222,6 +222,45 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp = regs[DS1307_REG_SECS];
|
||||
switch (ds1307->type) {
|
||||
case ds_1307:
|
||||
case m41t0:
|
||||
case m41t00:
|
||||
case m41t11:
|
||||
if (tmp & DS1307_BIT_CH)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case ds_1308:
|
||||
case ds_1338:
|
||||
if (tmp & DS1307_BIT_CH)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp & DS1338_BIT_OSF)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case ds_1340:
|
||||
if (tmp & DS1340_BIT_nEOSC)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp & DS1340_BIT_OSF)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case mcp794xx:
|
||||
if (!(tmp & MCP794XX_BIT_ST))
|
||||
return -EINVAL;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f);
|
||||
t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f);
|
||||
tmp = regs[DS1307_REG_HOUR] & 0x3f;
|
||||
|
@ -286,7 +325,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
|
|||
if (t->tm_year > 199 && chip->century_bit)
|
||||
regs[chip->century_reg] |= chip->century_bit;
|
||||
|
||||
if (ds1307->type == mcp794xx) {
|
||||
switch (ds1307->type) {
|
||||
case ds_1308:
|
||||
case ds_1338:
|
||||
regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
|
||||
DS1338_BIT_OSF, 0);
|
||||
break;
|
||||
case ds_1340:
|
||||
regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG,
|
||||
DS1340_BIT_OSF, 0);
|
||||
break;
|
||||
case mcp794xx:
|
||||
/*
|
||||
* these bits were cleared when preparing the date/time
|
||||
* values and need to be set again before writing the
|
||||
|
@ -294,6 +343,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
|
|||
*/
|
||||
regs[DS1307_REG_SECS] |= MCP794XX_BIT_ST;
|
||||
regs[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s: %7ph\n", "write", regs);
|
||||
|
@ -1702,7 +1754,6 @@ static int ds1307_probe(struct i2c_client *client,
|
|||
break;
|
||||
}
|
||||
|
||||
read_rtc:
|
||||
/* read RTC registers */
|
||||
err = regmap_bulk_read(ds1307->regmap, chip->offset, regs,
|
||||
sizeof(regs));
|
||||
|
@ -1711,75 +1762,11 @@ static int ds1307_probe(struct i2c_client *client,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* minimal sanity checking; some chips (like DS1340) don't
|
||||
* specify the extra bits as must-be-zero, but there are
|
||||
* still a few values that are clearly out-of-range.
|
||||
*/
|
||||
tmp = regs[DS1307_REG_SECS];
|
||||
switch (ds1307->type) {
|
||||
case ds_1307:
|
||||
case m41t0:
|
||||
case m41t00:
|
||||
case m41t11:
|
||||
/* clock halted? turn it on, so clock can tick. */
|
||||
if (tmp & DS1307_BIT_CH) {
|
||||
regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
|
||||
dev_warn(ds1307->dev, "SET TIME!\n");
|
||||
goto read_rtc;
|
||||
}
|
||||
break;
|
||||
case ds_1308:
|
||||
case ds_1338:
|
||||
/* clock halted? turn it on, so clock can tick. */
|
||||
if (tmp & DS1307_BIT_CH)
|
||||
regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
|
||||
|
||||
/* oscillator fault? clear flag, and warn */
|
||||
if (regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
|
||||
regmap_write(ds1307->regmap, DS1307_REG_CONTROL,
|
||||
regs[DS1307_REG_CONTROL] &
|
||||
~DS1338_BIT_OSF);
|
||||
dev_warn(ds1307->dev, "SET TIME!\n");
|
||||
goto read_rtc;
|
||||
}
|
||||
break;
|
||||
case ds_1340:
|
||||
/* clock halted? turn it on, so clock can tick. */
|
||||
if (tmp & DS1340_BIT_nEOSC)
|
||||
regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
|
||||
|
||||
err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
|
||||
if (err) {
|
||||
dev_dbg(ds1307->dev, "read error %d\n", err);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* oscillator fault? clear flag, and warn */
|
||||
if (tmp & DS1340_BIT_OSF) {
|
||||
regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0);
|
||||
dev_warn(ds1307->dev, "SET TIME!\n");
|
||||
}
|
||||
break;
|
||||
case mcp794xx:
|
||||
/* make sure that the backup battery is enabled */
|
||||
if (!(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
|
||||
regmap_write(ds1307->regmap, DS1307_REG_WDAY,
|
||||
regs[DS1307_REG_WDAY] |
|
||||
MCP794XX_BIT_VBATEN);
|
||||
}
|
||||
|
||||
/* clock halted? turn it on, so clock can tick. */
|
||||
if (!(tmp & MCP794XX_BIT_ST)) {
|
||||
regmap_write(ds1307->regmap, DS1307_REG_SECS,
|
||||
MCP794XX_BIT_ST);
|
||||
dev_warn(ds1307->dev, "SET TIME!\n");
|
||||
goto read_rtc;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (ds1307->type == mcp794xx &&
|
||||
!(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
|
||||
regmap_write(ds1307->regmap, DS1307_REG_WDAY,
|
||||
regs[DS1307_REG_WDAY] |
|
||||
MCP794XX_BIT_VBATEN);
|
||||
}
|
||||
|
||||
tmp = regs[DS1307_REG_HOUR];
|
||||
|
|
|
@ -182,9 +182,10 @@ static void ds2404_enable_osc(struct device *dev)
|
|||
static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
|
||||
{
|
||||
unsigned long time = 0;
|
||||
__le32 hw_time = 0;
|
||||
|
||||
ds2404_read_memory(dev, 0x203, 4, (u8 *)&time);
|
||||
time = le32_to_cpu(time);
|
||||
ds2404_read_memory(dev, 0x203, 4, (u8 *)&hw_time);
|
||||
time = le32_to_cpu(hw_time);
|
||||
|
||||
rtc_time64_to_tm(time, dt);
|
||||
return 0;
|
||||
|
|
|
@ -104,8 +104,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
|
|||
fm3130_rtc_mode(dev, FM3130_MODE_READ);
|
||||
|
||||
/* read the RTC date and time registers all at once */
|
||||
tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
|
||||
fm3130->msg, 2);
|
||||
tmp = i2c_transfer(fm3130->client->adapter, fm3130->msg, 2);
|
||||
if (tmp != 2) {
|
||||
dev_err(dev, "%s error %d\n", "read", tmp);
|
||||
return -EIO;
|
||||
|
@ -197,8 +196,7 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
}
|
||||
|
||||
/* read the RTC alarm registers all at once */
|
||||
tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
|
||||
&fm3130->msg[2], 2);
|
||||
tmp = i2c_transfer(fm3130->client->adapter, &fm3130->msg[2], 2);
|
||||
if (tmp != 2) {
|
||||
dev_err(dev, "%s error %d\n", "read", tmp);
|
||||
return -EIO;
|
||||
|
@ -348,7 +346,7 @@ static int fm3130_probe(struct i2c_client *client,
|
|||
struct fm3130 *fm3130;
|
||||
int err = -ENODEV;
|
||||
int tmp;
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
|
||||
if (!i2c_check_functionality(adapter,
|
||||
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright 2018 NXP.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/firmware/imx/sci.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -11,11 +12,15 @@
|
|||
#include <linux/rtc.h>
|
||||
|
||||
#define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9
|
||||
#define IMX_SC_TIMER_FUNC_SET_RTC_ALARM 8
|
||||
#define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6
|
||||
|
||||
#define IMX_SIP_SRTC 0xC2000002
|
||||
#define IMX_SIP_SRTC_SET_TIME 0x0
|
||||
|
||||
#define SC_IRQ_GROUP_RTC 2
|
||||
#define SC_IRQ_RTC 1
|
||||
|
||||
static struct imx_sc_ipc *rtc_ipc_handle;
|
||||
static struct rtc_device *imx_sc_rtc;
|
||||
|
||||
|
@ -24,6 +29,16 @@ struct imx_sc_msg_timer_get_rtc_time {
|
|||
u32 time;
|
||||
} __packed;
|
||||
|
||||
struct imx_sc_msg_timer_rtc_set_alarm {
|
||||
struct imx_sc_rpc_msg hdr;
|
||||
u16 year;
|
||||
u8 mon;
|
||||
u8 day;
|
||||
u8 hour;
|
||||
u8 min;
|
||||
u8 sec;
|
||||
} __packed;
|
||||
|
||||
static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct imx_sc_msg_timer_get_rtc_time msg;
|
||||
|
@ -60,9 +75,77 @@ static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
return res.a0;
|
||||
}
|
||||
|
||||
static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
return imx_scu_irq_group_enable(SC_IRQ_GROUP_RTC, SC_IRQ_RTC, enable);
|
||||
}
|
||||
|
||||
static int imx_sc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
/*
|
||||
* SCU firmware does NOT provide read alarm API, but .read_alarm
|
||||
* callback is required by RTC framework to support alarm function,
|
||||
* so just return here.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct imx_sc_msg_timer_rtc_set_alarm msg;
|
||||
struct imx_sc_rpc_msg *hdr = &msg.hdr;
|
||||
int ret;
|
||||
struct rtc_time *alrm_tm = &alrm->time;
|
||||
|
||||
hdr->ver = IMX_SC_RPC_VERSION;
|
||||
hdr->svc = IMX_SC_RPC_SVC_TIMER;
|
||||
hdr->func = IMX_SC_TIMER_FUNC_SET_RTC_ALARM;
|
||||
hdr->size = 3;
|
||||
|
||||
msg.year = alrm_tm->tm_year + 1900;
|
||||
msg.mon = alrm_tm->tm_mon + 1;
|
||||
msg.day = alrm_tm->tm_mday;
|
||||
msg.hour = alrm_tm->tm_hour;
|
||||
msg.min = alrm_tm->tm_min;
|
||||
msg.sec = alrm_tm->tm_sec;
|
||||
|
||||
ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "set rtc alarm failed, ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = imx_sc_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
if (ret) {
|
||||
dev_err(dev, "enable rtc alarm failed, ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops imx_sc_rtc_ops = {
|
||||
.read_time = imx_sc_rtc_read_time,
|
||||
.set_time = imx_sc_rtc_set_time,
|
||||
.read_alarm = imx_sc_rtc_read_alarm,
|
||||
.set_alarm = imx_sc_rtc_set_alarm,
|
||||
.alarm_irq_enable = imx_sc_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int imx_sc_rtc_alarm_notify(struct notifier_block *nb,
|
||||
unsigned long event, void *group)
|
||||
{
|
||||
/* ignore non-rtc irq */
|
||||
if (!((event & SC_IRQ_RTC) && (*(u8 *)group == SC_IRQ_GROUP_RTC)))
|
||||
return 0;
|
||||
|
||||
rtc_update_irq(imx_sc_rtc, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block imx_sc_rtc_alarm_sc_notifier = {
|
||||
.notifier_call = imx_sc_rtc_alarm_notify,
|
||||
};
|
||||
|
||||
static int imx_sc_rtc_probe(struct platform_device *pdev)
|
||||
|
@ -73,6 +156,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(imx_sc_rtc))
|
||||
return PTR_ERR(imx_sc_rtc);
|
||||
|
@ -87,6 +172,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -872,7 +872,7 @@ static struct notifier_block wdt_notifier = {
|
|||
static int m41t80_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
int rc = 0;
|
||||
struct rtc_time tm;
|
||||
struct m41t80_data *m41t80_data = NULL;
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* REGISTERS */
|
||||
#define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */
|
||||
|
@ -95,6 +95,7 @@
|
|||
#define OFFSET_SIGN_BIT 6 /* 2's complement sign bit */
|
||||
#define OFFSET_COARSE BIT(7) /* Coarse mode offset */
|
||||
#define OFFSET_STEP (2170) /* Offset step in parts per billion */
|
||||
#define OFFSET_MASK GENMASK(6, 0) /* Offset value */
|
||||
|
||||
/* READ/WRITE ADDRESS BITS */
|
||||
#define PCF2123_WRITE BIT(4)
|
||||
|
@ -103,120 +104,35 @@
|
|||
|
||||
static struct spi_driver pcf2123_driver;
|
||||
|
||||
struct pcf2123_sysfs_reg {
|
||||
struct device_attribute attr;
|
||||
char name[2];
|
||||
};
|
||||
|
||||
struct pcf2123_plat_data {
|
||||
struct rtc_device *rtc;
|
||||
struct pcf2123_sysfs_reg regs[16];
|
||||
struct regmap *map;
|
||||
};
|
||||
|
||||
/*
|
||||
* Causes a 30 nanosecond delay to ensure that the PCF2123 chip select
|
||||
* is released properly after an SPI write. This function should be
|
||||
* called after EVERY read/write call over SPI.
|
||||
*/
|
||||
static inline void pcf2123_delay_trec(void)
|
||||
{
|
||||
ndelay(30);
|
||||
}
|
||||
|
||||
static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
int ret;
|
||||
|
||||
reg |= PCF2123_READ;
|
||||
ret = spi_write_then_read(spi, ®, 1, rxbuf, size);
|
||||
pcf2123_delay_trec();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
int ret;
|
||||
|
||||
txbuf[0] |= PCF2123_WRITE;
|
||||
ret = spi_write(spi, txbuf, size);
|
||||
pcf2123_delay_trec();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val)
|
||||
{
|
||||
u8 txbuf[2];
|
||||
|
||||
txbuf[0] = reg;
|
||||
txbuf[1] = val;
|
||||
return pcf2123_write(dev, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buffer)
|
||||
{
|
||||
struct pcf2123_sysfs_reg *r;
|
||||
u8 rxbuf[1];
|
||||
unsigned long reg;
|
||||
int ret;
|
||||
|
||||
r = container_of(attr, struct pcf2123_sysfs_reg, attr);
|
||||
|
||||
ret = kstrtoul(r->name, 16, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pcf2123_read(dev, reg, rxbuf, 1);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
|
||||
return sprintf(buffer, "0x%x\n", rxbuf[0]);
|
||||
}
|
||||
|
||||
static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buffer, size_t count)
|
||||
{
|
||||
struct pcf2123_sysfs_reg *r;
|
||||
unsigned long reg;
|
||||
unsigned long val;
|
||||
|
||||
int ret;
|
||||
|
||||
r = container_of(attr, struct pcf2123_sysfs_reg, attr);
|
||||
|
||||
ret = kstrtoul(r->name, 16, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtoul(buffer, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pcf2123_write_reg(dev, reg, val);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
return count;
|
||||
}
|
||||
static const struct regmap_config pcf2123_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.read_flag_mask = PCF2123_READ,
|
||||
.write_flag_mask = PCF2123_WRITE,
|
||||
.max_register = PCF2123_REG_CTDWN_TMR,
|
||||
};
|
||||
|
||||
static int pcf2123_read_offset(struct device *dev, long *offset)
|
||||
{
|
||||
int ret;
|
||||
s8 reg;
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
int ret, val;
|
||||
unsigned int reg;
|
||||
|
||||
ret = pcf2123_read(dev, PCF2123_REG_OFFSET, ®, 1);
|
||||
if (ret < 0)
|
||||
ret = regmap_read(pdata->map, PCF2123_REG_OFFSET, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (reg & OFFSET_COARSE)
|
||||
reg <<= 1; /* multiply by 2 and sign extend */
|
||||
else
|
||||
reg = sign_extend32(reg, OFFSET_SIGN_BIT);
|
||||
val = sign_extend32((reg & OFFSET_MASK), OFFSET_SIGN_BIT);
|
||||
|
||||
*offset = ((long)reg) * OFFSET_STEP;
|
||||
if (reg & OFFSET_COARSE)
|
||||
val *= 2;
|
||||
|
||||
*offset = ((long)val) * OFFSET_STEP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -233,6 +149,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset)
|
|||
*/
|
||||
static int pcf2123_set_offset(struct device *dev, long offset)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
s8 reg;
|
||||
|
||||
if (offset > OFFSET_STEP * 127)
|
||||
|
@ -240,7 +157,7 @@ static int pcf2123_set_offset(struct device *dev, long offset)
|
|||
else if (offset < OFFSET_STEP * -128)
|
||||
reg = -128;
|
||||
else
|
||||
reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP);
|
||||
reg = DIV_ROUND_CLOSEST(offset, OFFSET_STEP);
|
||||
|
||||
/* choose fine offset only for odd values in the normal range */
|
||||
if (reg & 1 && reg <= 63 && reg >= -64) {
|
||||
|
@ -252,16 +169,18 @@ static int pcf2123_set_offset(struct device *dev, long offset)
|
|||
reg |= OFFSET_COARSE;
|
||||
}
|
||||
|
||||
return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg);
|
||||
return regmap_write(pdata->map, PCF2123_REG_OFFSET, (unsigned int)reg);
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
u8 rxbuf[7];
|
||||
int ret;
|
||||
|
||||
ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf));
|
||||
if (ret < 0)
|
||||
ret = regmap_bulk_read(pdata->map, PCF2123_REG_SC, rxbuf,
|
||||
sizeof(rxbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rxbuf[0] & OSC_HAS_STOPPED) {
|
||||
|
@ -279,82 +198,168 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100; /* assume we are in 1970...2069 */
|
||||
|
||||
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__func__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 txbuf[8];
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
u8 txbuf[7];
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__func__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
|
||||
|
||||
/* Stop the counter first */
|
||||
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
if (ret < 0)
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set the new time */
|
||||
txbuf[0] = PCF2123_REG_SC;
|
||||
txbuf[1] = bin2bcd(tm->tm_sec & 0x7F);
|
||||
txbuf[2] = bin2bcd(tm->tm_min & 0x7F);
|
||||
txbuf[3] = bin2bcd(tm->tm_hour & 0x3F);
|
||||
txbuf[4] = bin2bcd(tm->tm_mday & 0x3F);
|
||||
txbuf[5] = tm->tm_wday & 0x07;
|
||||
txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
|
||||
txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
|
||||
txbuf[0] = bin2bcd(tm->tm_sec & 0x7F);
|
||||
txbuf[1] = bin2bcd(tm->tm_min & 0x7F);
|
||||
txbuf[2] = bin2bcd(tm->tm_hour & 0x3F);
|
||||
txbuf[3] = bin2bcd(tm->tm_mday & 0x3F);
|
||||
txbuf[4] = tm->tm_wday & 0x07;
|
||||
txbuf[5] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
|
||||
txbuf[6] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
|
||||
|
||||
ret = pcf2123_write(dev, txbuf, sizeof(txbuf));
|
||||
if (ret < 0)
|
||||
ret = regmap_bulk_write(pdata->map, PCF2123_REG_SC, txbuf,
|
||||
sizeof(txbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Start the counter */
|
||||
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
if (ret < 0)
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
u8 rxbuf[4];
|
||||
int ret;
|
||||
unsigned int val = 0;
|
||||
|
||||
ret = regmap_bulk_read(pdata->map, PCF2123_REG_ALRM_MN, rxbuf,
|
||||
sizeof(rxbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
alm->time.tm_min = bcd2bin(rxbuf[0] & 0x7F);
|
||||
alm->time.tm_hour = bcd2bin(rxbuf[1] & 0x3F);
|
||||
alm->time.tm_mday = bcd2bin(rxbuf[2] & 0x3F);
|
||||
alm->time.tm_wday = bcd2bin(rxbuf[3] & 0x07);
|
||||
|
||||
dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
|
||||
|
||||
ret = regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
alm->enabled = !!(val & CTRL2_AIE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
u8 txbuf[4];
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
|
||||
|
||||
/* Ensure alarm flag is clear */
|
||||
ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable alarm interrupt */
|
||||
ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AIE, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set new alarm */
|
||||
txbuf[0] = bin2bcd(alm->time.tm_min & 0x7F);
|
||||
txbuf[1] = bin2bcd(alm->time.tm_hour & 0x3F);
|
||||
txbuf[2] = bin2bcd(alm->time.tm_mday & 0x3F);
|
||||
txbuf[3] = bin2bcd(alm->time.tm_wday & 0x07);
|
||||
|
||||
ret = regmap_bulk_write(pdata->map, PCF2123_REG_ALRM_MN, txbuf,
|
||||
sizeof(txbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable alarm interrupt */
|
||||
if (alm->enabled) {
|
||||
ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2,
|
||||
CTRL2_AIE, CTRL2_AIE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct mutex *lock = &pdata->rtc->ops_lock;
|
||||
unsigned int val = 0;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
mutex_lock(lock);
|
||||
regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
|
||||
|
||||
/* Alarm? */
|
||||
if (val & CTRL2_AF) {
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* Clear alarm flag */
|
||||
regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
|
||||
|
||||
rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
}
|
||||
|
||||
mutex_unlock(lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcf2123_reset(struct device *dev)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
int ret;
|
||||
u8 rxbuf[2];
|
||||
unsigned int val = 0;
|
||||
|
||||
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
|
||||
if (ret < 0)
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Stop the counter */
|
||||
dev_dbg(dev, "stopping RTC\n");
|
||||
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
if (ret < 0)
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* See if the counter was actually stopped */
|
||||
dev_dbg(dev, "checking for presence of RTC\n");
|
||||
ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
|
||||
if (ret < 0)
|
||||
ret = regmap_read(pdata->map, PCF2123_REG_CTRL1, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n",
|
||||
rxbuf[0], rxbuf[1]);
|
||||
if (!(rxbuf[0] & CTRL1_STOP))
|
||||
dev_dbg(dev, "received data from RTC (0x%08X)\n", val);
|
||||
if (!(val & CTRL1_STOP))
|
||||
return -ENODEV;
|
||||
|
||||
/* Start the counter */
|
||||
ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
if (ret < 0)
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
@ -365,7 +370,8 @@ static const struct rtc_class_ops pcf2123_rtc_ops = {
|
|||
.set_time = pcf2123_rtc_set_time,
|
||||
.read_offset = pcf2123_read_offset,
|
||||
.set_offset = pcf2123_set_offset,
|
||||
|
||||
.read_alarm = pcf2123_rtc_read_alarm,
|
||||
.set_alarm = pcf2123_rtc_set_alarm,
|
||||
};
|
||||
|
||||
static int pcf2123_probe(struct spi_device *spi)
|
||||
|
@ -373,7 +379,7 @@ static int pcf2123_probe(struct spi_device *spi)
|
|||
struct rtc_device *rtc;
|
||||
struct rtc_time tm;
|
||||
struct pcf2123_plat_data *pdata;
|
||||
int ret, i;
|
||||
int ret = 0;
|
||||
|
||||
pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
|
||||
GFP_KERNEL);
|
||||
|
@ -381,6 +387,13 @@ static int pcf2123_probe(struct spi_device *spi)
|
|||
return -ENOMEM;
|
||||
spi->dev.platform_data = pdata;
|
||||
|
||||
pdata->map = devm_regmap_init_spi(spi, &pcf2123_regmap_config);
|
||||
|
||||
if (IS_ERR(pdata->map)) {
|
||||
dev_err(&spi->dev, "regmap init failed.\n");
|
||||
goto kfree_exit;
|
||||
}
|
||||
|
||||
ret = pcf2123_rtc_read_time(&spi->dev, &tm);
|
||||
if (ret < 0) {
|
||||
ret = pcf2123_reset(&spi->dev);
|
||||
|
@ -405,47 +418,31 @@ static int pcf2123_probe(struct spi_device *spi)
|
|||
|
||||
pdata->rtc = rtc;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
sysfs_attr_init(&pdata->regs[i].attr.attr);
|
||||
sprintf(pdata->regs[i].name, "%1x", i);
|
||||
pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
|
||||
pdata->regs[i].attr.attr.name = pdata->regs[i].name;
|
||||
pdata->regs[i].attr.show = pcf2123_show;
|
||||
pdata->regs[i].attr.store = pcf2123_store;
|
||||
ret = device_create_file(&spi->dev, &pdata->regs[i].attr);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to create sysfs %s\n",
|
||||
pdata->regs[i].name);
|
||||
goto sysfs_exit;
|
||||
}
|
||||
/* Register alarm irq */
|
||||
if (spi->irq > 0) {
|
||||
ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
|
||||
pcf2123_rtc_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
pcf2123_driver.driver.name, &spi->dev);
|
||||
if (!ret)
|
||||
device_init_wakeup(&spi->dev, true);
|
||||
else
|
||||
dev_err(&spi->dev, "could not request irq.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* The PCF2123's alarm only has minute accuracy. Must add timer
|
||||
* support to this driver to generate interrupts more than once
|
||||
* per minute.
|
||||
*/
|
||||
pdata->rtc->uie_unsupported = 1;
|
||||
|
||||
sysfs_exit:
|
||||
for (i--; i >= 0; i--)
|
||||
device_remove_file(&spi->dev, &pdata->regs[i].attr);
|
||||
return 0;
|
||||
|
||||
kfree_exit:
|
||||
spi->dev.platform_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcf2123_remove(struct spi_device *spi)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(&spi->dev);
|
||||
int i;
|
||||
|
||||
if (pdata) {
|
||||
for (i = 0; i < 16; i++)
|
||||
if (pdata->regs[i].name[0])
|
||||
device_remove_file(&spi->dev,
|
||||
&pdata->regs[i].attr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pcf2123_dt_ids[] = {
|
||||
{ .compatible = "nxp,rtc-pcf2123", },
|
||||
|
@ -461,7 +458,6 @@ static struct spi_driver pcf2123_driver = {
|
|||
.of_match_table = of_match_ptr(pcf2123_dt_ids),
|
||||
},
|
||||
.probe = pcf2123_probe,
|
||||
.remove = pcf2123_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(pcf2123_driver);
|
||||
|
|
|
@ -560,7 +560,6 @@ static int pcf8563_probe(struct i2c_client *client,
|
|||
struct pcf8563 *pcf8563;
|
||||
int err;
|
||||
unsigned char buf;
|
||||
unsigned char alm_pending;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
|
@ -584,13 +583,13 @@ static int pcf8563_probe(struct i2c_client *client,
|
|||
return err;
|
||||
}
|
||||
|
||||
err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "%s: read error\n", __func__);
|
||||
/* Clear flags and disable interrupts */
|
||||
buf = 0;
|
||||
err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "%s: write error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
if (alm_pending)
|
||||
pcf8563_set_alarm_mode(client, 0);
|
||||
|
||||
pcf8563->rtc = devm_rtc_device_register(&client->dev,
|
||||
pcf8563_driver.driver.name,
|
||||
|
@ -602,7 +601,7 @@ static int pcf8563_probe(struct i2c_client *client,
|
|||
if (client->irq > 0) {
|
||||
err = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, pcf8563_irq,
|
||||
IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING,
|
||||
IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
|
||||
pcf8563_driver.driver.name, client);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "unable to request IRQ %d\n",
|
||||
|
|
|
@ -517,7 +517,7 @@ static int rx8900_trickle_charger_init(struct rv8803_data *rv8803)
|
|||
static int rv8803_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct rv8803_data *rv8803;
|
||||
int err, flags;
|
||||
struct nvmem_config nvmem_cfg = {
|
||||
|
|
|
@ -433,7 +433,7 @@ static struct rtc_class_ops rx8010_rtc_ops = {
|
|||
static int rx8010_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct rx8010_data *rx8010;
|
||||
int err = 0;
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ static void rx8025_sysfs_unregister(struct device *dev)
|
|||
static int rx8025_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct rx8025_data *rx8025;
|
||||
int err = 0;
|
||||
|
||||
|
|
|
@ -32,21 +32,22 @@
|
|||
#define S35390A_ALRM_BYTE_MINS 2
|
||||
|
||||
/* flags for STATUS1 */
|
||||
#define S35390A_FLAG_POC 0x01
|
||||
#define S35390A_FLAG_BLD 0x02
|
||||
#define S35390A_FLAG_INT2 0x04
|
||||
#define S35390A_FLAG_24H 0x40
|
||||
#define S35390A_FLAG_RESET 0x80
|
||||
#define S35390A_FLAG_POC BIT(0)
|
||||
#define S35390A_FLAG_BLD BIT(1)
|
||||
#define S35390A_FLAG_INT2 BIT(2)
|
||||
#define S35390A_FLAG_24H BIT(6)
|
||||
#define S35390A_FLAG_RESET BIT(7)
|
||||
|
||||
/* flag for STATUS2 */
|
||||
#define S35390A_FLAG_TEST 0x01
|
||||
|
||||
#define S35390A_INT2_MODE_MASK 0xF0
|
||||
#define S35390A_FLAG_TEST BIT(0)
|
||||
|
||||
/* INT2 pin output mode */
|
||||
#define S35390A_INT2_MODE_MASK 0x0E
|
||||
#define S35390A_INT2_MODE_NOINTR 0x00
|
||||
#define S35390A_INT2_MODE_FREQ 0x10
|
||||
#define S35390A_INT2_MODE_ALARM 0x40
|
||||
#define S35390A_INT2_MODE_PMIN_EDG 0x20
|
||||
#define S35390A_INT2_MODE_ALARM BIT(1) /* INT2AE */
|
||||
#define S35390A_INT2_MODE_PMIN_EDG BIT(2) /* INT2ME */
|
||||
#define S35390A_INT2_MODE_FREQ BIT(3) /* INT2FE */
|
||||
#define S35390A_INT2_MODE_PMIN (BIT(3) | BIT(2)) /* INT2FE | INT2ME */
|
||||
|
||||
static const struct i2c_device_id s35390a_id[] = {
|
||||
{ "s35390a", 0 },
|
||||
|
@ -284,6 +285,9 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
|
||||
alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
|
||||
|
||||
if (alm->time.tm_sec != 0)
|
||||
dev_warn(&client->dev, "Alarms are only supported on a per minute basis!\n");
|
||||
|
||||
/* disable interrupt (which deasserts the irq line) */
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
|
||||
if (err < 0)
|
||||
|
@ -299,9 +303,6 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
else
|
||||
sts = S35390A_INT2_MODE_NOINTR;
|
||||
|
||||
/* This chip expects the bits of each byte to be in reverse order */
|
||||
sts = bitrev8(sts);
|
||||
|
||||
/* set interupt mode*/
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
|
||||
if (err < 0)
|
||||
|
@ -339,7 +340,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
|
||||
if ((sts & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
|
||||
/*
|
||||
* When the alarm isn't enabled, the register to configure
|
||||
* the alarm time isn't accessible.
|
||||
|
@ -431,14 +432,14 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
unsigned int i;
|
||||
struct s35390a *s35390a;
|
||||
char buf, status1;
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
err = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s35390a = devm_kzalloc(&client->dev, sizeof(struct s35390a),
|
||||
GFP_KERNEL);
|
||||
s35390a = devm_kzalloc(dev, sizeof(struct s35390a), GFP_KERNEL);
|
||||
if (!s35390a) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
|
@ -452,8 +453,8 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
s35390a->client[i] = i2c_new_dummy(client->adapter,
|
||||
client->addr + i);
|
||||
if (!s35390a->client[i]) {
|
||||
dev_err(&client->dev, "Address %02x unavailable\n",
|
||||
client->addr + i);
|
||||
dev_err(dev, "Address %02x unavailable\n",
|
||||
client->addr + i);
|
||||
err = -EBUSY;
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
@ -462,7 +463,7 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
err_read = s35390a_read_status(s35390a, &status1);
|
||||
if (err_read < 0) {
|
||||
err = err_read;
|
||||
dev_err(&client->dev, "error resetting chip\n");
|
||||
dev_err(dev, "error resetting chip\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
|
@ -476,28 +477,30 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
buf = 0;
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling alarm");
|
||||
dev_err(dev, "error disabling alarm");
|
||||
goto exit_dummy;
|
||||
}
|
||||
} else {
|
||||
err = s35390a_disable_test_mode(s35390a);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling test mode\n");
|
||||
dev_err(dev, "error disabling test mode\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
}
|
||||
|
||||
device_set_wakeup_capable(&client->dev, 1);
|
||||
device_set_wakeup_capable(dev, 1);
|
||||
|
||||
s35390a->rtc = devm_rtc_device_register(&client->dev,
|
||||
s35390a_driver.driver.name,
|
||||
&s35390a_rtc_ops, THIS_MODULE);
|
||||
s35390a->rtc = devm_rtc_device_register(dev, s35390a_driver.driver.name,
|
||||
&s35390a_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(s35390a->rtc)) {
|
||||
err = PTR_ERR(s35390a->rtc);
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
/* supports per-minute alarms only, therefore set uie_unsupported */
|
||||
s35390a->rtc->uie_unsupported = 1;
|
||||
|
||||
if (status1 & S35390A_FLAG_INT2)
|
||||
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
|
||||
|
||||
|
|
|
@ -162,10 +162,6 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
now_secs = rtc_tm_to_time64(&now);
|
||||
alarm_secs = rtc_tm_to_time64(&t->time);
|
||||
|
||||
/* Invalid alarm time */
|
||||
if (now_secs > alarm_secs)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(&rtc->alarm, t, sizeof(struct rtc_wkalrm));
|
||||
|
||||
/* Now many secs to fire */
|
||||
|
|
|
@ -519,11 +519,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
/* Write to Alarm register */
|
||||
writel_relaxed(alrmar, rtc->base + regs->alrmar);
|
||||
|
||||
if (alrm->enabled)
|
||||
stm32_rtc_alarm_irq_enable(dev, 1);
|
||||
else
|
||||
stm32_rtc_alarm_irq_enable(dev, 0);
|
||||
|
||||
stm32_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
end:
|
||||
stm32_rtc_wpr_lock(rtc);
|
||||
|
||||
|
|
|
@ -672,6 +672,7 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
|
|||
{ .compatible = "allwinner,sun6i-a31-rtc" },
|
||||
{ .compatible = "allwinner,sun8i-a23-rtc" },
|
||||
{ .compatible = "allwinner,sun8i-h3-rtc" },
|
||||
{ .compatible = "allwinner,sun8i-r40-rtc" },
|
||||
{ .compatible = "allwinner,sun8i-v3-rtc" },
|
||||
{ .compatible = "allwinner,sun50i-h5-rtc" },
|
||||
{ /* sentinel */ },
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* An RTC driver for the NVIDIA Tegra 200 series internal RTC.
|
||||
*
|
||||
* Copyright (c) 2010, NVIDIA Corporation.
|
||||
* Copyright (c) 2010-2019, NVIDIA Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
@ -18,10 +18,10 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
|
||||
/* Set to 1 = busy every eight 32 kHz clocks during copy of sec+msec to AHB. */
|
||||
#define TEGRA_RTC_REG_BUSY 0x004
|
||||
#define TEGRA_RTC_REG_SECONDS 0x008
|
||||
/* when msec is read, the seconds are buffered into shadow seconds. */
|
||||
/* When msec is read, the seconds are buffered into shadow seconds. */
|
||||
#define TEGRA_RTC_REG_SHADOW_SECONDS 0x00c
|
||||
#define TEGRA_RTC_REG_MILLI_SECONDS 0x010
|
||||
#define TEGRA_RTC_REG_SECONDS_ALARM0 0x014
|
||||
|
@ -46,44 +46,48 @@
|
|||
#define TEGRA_RTC_INTR_STATUS_SEC_ALARM0 (1<<0)
|
||||
|
||||
struct tegra_rtc_info {
|
||||
struct platform_device *pdev;
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *rtc_base; /* NULL if not initialized. */
|
||||
struct clk *clk;
|
||||
int tegra_rtc_irq; /* alarm and periodic irq */
|
||||
spinlock_t tegra_rtc_lock;
|
||||
struct platform_device *pdev;
|
||||
struct rtc_device *rtc;
|
||||
void __iomem *base; /* NULL if not initialized */
|
||||
struct clk *clk;
|
||||
int irq; /* alarm and periodic IRQ */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/* RTC hardware is busy when it is updating its values over AHB once
|
||||
* every eight 32kHz clocks (~250uS).
|
||||
* outside of these updates the CPU is free to write.
|
||||
* CPU is always free to read.
|
||||
/*
|
||||
* RTC hardware is busy when it is updating its values over AHB once every
|
||||
* eight 32 kHz clocks (~250 us). Outside of these updates the CPU is free to
|
||||
* write. CPU is always free to read.
|
||||
*/
|
||||
static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info)
|
||||
{
|
||||
return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1;
|
||||
return readl(info->base + TEGRA_RTC_REG_BUSY) & 1;
|
||||
}
|
||||
|
||||
/* Wait for hardware to be ready for writing.
|
||||
* This function tries to maximize the amount of time before the next update.
|
||||
* It does this by waiting for the RTC to become busy with its periodic update,
|
||||
* then returning once the RTC first becomes not busy.
|
||||
/*
|
||||
* Wait for hardware to be ready for writing. This function tries to maximize
|
||||
* the amount of time before the next update. It does this by waiting for the
|
||||
* RTC to become busy with its periodic update, then returning once the RTC
|
||||
* first becomes not busy.
|
||||
*
|
||||
* This periodic update (where the seconds and milliseconds are copied to the
|
||||
* AHB side) occurs every eight 32kHz clocks (~250uS).
|
||||
* The behavior of this function allows us to make some assumptions without
|
||||
* introducing a race, because 250uS is plenty of time to read/write a value.
|
||||
* AHB side) occurs every eight 32 kHz clocks (~250 us). The behavior of this
|
||||
* function allows us to make some assumptions without introducing a race,
|
||||
* because 250 us is plenty of time to read/write a value.
|
||||
*/
|
||||
static int tegra_rtc_wait_while_busy(struct device *dev)
|
||||
{
|
||||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
int retries = 500; /* ~490 us is the worst case, ~250 us is best */
|
||||
|
||||
int retries = 500; /* ~490 us is the worst case, ~250 us is best. */
|
||||
|
||||
/* first wait for the RTC to become busy. this is when it
|
||||
* posts its updated seconds+msec registers to AHB side. */
|
||||
/*
|
||||
* First wait for the RTC to become busy. This is when it posts its
|
||||
* updated seconds+msec registers to AHB side.
|
||||
*/
|
||||
while (tegra_rtc_check_busy(info)) {
|
||||
if (!retries--)
|
||||
goto retry_failed;
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
|
@ -91,28 +95,30 @@ static int tegra_rtc_wait_while_busy(struct device *dev)
|
|||
return 0;
|
||||
|
||||
retry_failed:
|
||||
dev_err(dev, "write failed:retry count exceeded.\n");
|
||||
dev_err(dev, "write failed: retry count exceeded\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned long sec, msec;
|
||||
unsigned long sl_irq_flags;
|
||||
unsigned long flags;
|
||||
u32 sec, msec;
|
||||
|
||||
/* RTC hardware copies seconds to shadow seconds when a read
|
||||
* of milliseconds occurs. use a lock to keep other threads out. */
|
||||
spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
|
||||
/*
|
||||
* RTC hardware copies seconds to shadow seconds when a read of
|
||||
* milliseconds occurs. use a lock to keep other threads out.
|
||||
*/
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
|
||||
msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
|
||||
sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS);
|
||||
msec = readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS);
|
||||
sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS);
|
||||
|
||||
spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
rtc_time64_to_tm(sec, tm);
|
||||
|
||||
dev_vdbg(dev, "time read as %lu. %ptR\n", sec, tm);
|
||||
dev_vdbg(dev, "time read as %u, %ptR\n", sec, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -120,21 +126,21 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned long sec;
|
||||
u32 sec;
|
||||
int ret;
|
||||
|
||||
/* convert tm to seconds. */
|
||||
/* convert tm to seconds */
|
||||
sec = rtc_tm_to_time64(tm);
|
||||
|
||||
dev_vdbg(dev, "time set to %lu. %ptR\n", sec, tm);
|
||||
dev_vdbg(dev, "time set to %u, %ptR\n", sec, tm);
|
||||
|
||||
/* seconds only written if wait succeeded. */
|
||||
/* seconds only written if wait succeeded */
|
||||
ret = tegra_rtc_wait_while_busy(dev);
|
||||
if (!ret)
|
||||
writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS);
|
||||
writel(sec, info->base + TEGRA_RTC_REG_SECONDS);
|
||||
|
||||
dev_vdbg(dev, "time read back as %d\n",
|
||||
readl(info->rtc_base + TEGRA_RTC_REG_SECONDS));
|
||||
readl(info->base + TEGRA_RTC_REG_SECONDS));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -142,22 +148,21 @@ static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned long sec;
|
||||
unsigned tmp;
|
||||
u32 sec, value;
|
||||
|
||||
sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
|
||||
sec = readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
|
||||
|
||||
if (sec == 0) {
|
||||
/* alarm is disabled. */
|
||||
/* alarm is disabled */
|
||||
alarm->enabled = 0;
|
||||
} else {
|
||||
/* alarm is enabled. */
|
||||
/* alarm is enabled */
|
||||
alarm->enabled = 1;
|
||||
rtc_time64_to_tm(sec, &alarm->time);
|
||||
}
|
||||
|
||||
tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
|
||||
value = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
alarm->pending = (value & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -165,22 +170,22 @@ static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned status;
|
||||
unsigned long sl_irq_flags;
|
||||
unsigned long flags;
|
||||
u32 status;
|
||||
|
||||
tegra_rtc_wait_while_busy(dev);
|
||||
spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
|
||||
/* read the original value, and OR in the flag. */
|
||||
status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
|
||||
/* read the original value, and OR in the flag */
|
||||
status = readl(info->base + TEGRA_RTC_REG_INTR_MASK);
|
||||
if (enabled)
|
||||
status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
|
||||
else
|
||||
status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */
|
||||
|
||||
writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
|
||||
writel(status, info->base + TEGRA_RTC_REG_INTR_MASK);
|
||||
|
||||
spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -188,7 +193,7 @@ static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned long sec;
|
||||
u32 sec;
|
||||
|
||||
if (alarm->enabled)
|
||||
sec = rtc_tm_to_time64(&alarm->time);
|
||||
|
@ -196,16 +201,16 @@ static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
sec = 0;
|
||||
|
||||
tegra_rtc_wait_while_busy(dev);
|
||||
writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
|
||||
writel(sec, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
|
||||
dev_vdbg(dev, "alarm read back as %d\n",
|
||||
readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
|
||||
readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
|
||||
|
||||
/* if successfully written and alarm is enabled ... */
|
||||
if (sec) {
|
||||
tegra_rtc_alarm_irq_enable(dev, 1);
|
||||
dev_vdbg(dev, "alarm set as %lu. %ptR\n", sec, &alarm->time);
|
||||
dev_vdbg(dev, "alarm set as %u, %ptR\n", sec, &alarm->time);
|
||||
} else {
|
||||
/* disable alarm if 0 or write error. */
|
||||
/* disable alarm if 0 or write error */
|
||||
dev_vdbg(dev, "alarm disabled\n");
|
||||
tegra_rtc_alarm_irq_enable(dev, 0);
|
||||
}
|
||||
|
@ -227,39 +232,39 @@ static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
|
|||
{
|
||||
struct device *dev = data;
|
||||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned long events = 0;
|
||||
unsigned status;
|
||||
unsigned long sl_irq_flags;
|
||||
unsigned long events = 0, flags;
|
||||
u32 status;
|
||||
|
||||
status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
status = readl(info->base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
if (status) {
|
||||
/* clear the interrupt masks and status on any irq. */
|
||||
/* clear the interrupt masks and status on any IRQ */
|
||||
tegra_rtc_wait_while_busy(dev);
|
||||
spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
|
||||
writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
|
||||
writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
|
||||
writel(status, info->base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
}
|
||||
|
||||
/* check if Alarm */
|
||||
if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0))
|
||||
/* check if alarm */
|
||||
if (status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)
|
||||
events |= RTC_IRQF | RTC_AF;
|
||||
|
||||
/* check if Periodic */
|
||||
if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM))
|
||||
/* check if periodic */
|
||||
if (status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)
|
||||
events |= RTC_IRQF | RTC_PF;
|
||||
|
||||
rtc_update_irq(info->rtc_dev, 1, events);
|
||||
rtc_update_irq(info->rtc, 1, events);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops tegra_rtc_ops = {
|
||||
.read_time = tegra_rtc_read_time,
|
||||
.set_time = tegra_rtc_set_time,
|
||||
.read_alarm = tegra_rtc_read_alarm,
|
||||
.set_alarm = tegra_rtc_set_alarm,
|
||||
.proc = tegra_rtc_proc,
|
||||
.read_time = tegra_rtc_read_time,
|
||||
.set_time = tegra_rtc_set_time,
|
||||
.read_alarm = tegra_rtc_read_alarm,
|
||||
.set_alarm = tegra_rtc_set_alarm,
|
||||
.proc = tegra_rtc_proc,
|
||||
.alarm_irq_enable = tegra_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
|
@ -269,21 +274,20 @@ static const struct of_device_id tegra_rtc_dt_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
|
||||
|
||||
static int __init tegra_rtc_probe(struct platform_device *pdev)
|
||||
static int tegra_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_rtc_info *info;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct tegra_rtc_info),
|
||||
GFP_KERNEL);
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
info->rtc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(info->rtc_base))
|
||||
return PTR_ERR(info->rtc_base);
|
||||
info->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(info->base))
|
||||
return PTR_ERR(info->base);
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
|
@ -291,14 +295,14 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
info->tegra_rtc_irq = ret;
|
||||
info->irq = ret;
|
||||
|
||||
info->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(info->rtc_dev))
|
||||
return PTR_ERR(info->rtc_dev);
|
||||
info->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(info->rtc))
|
||||
return PTR_ERR(info->rtc);
|
||||
|
||||
info->rtc_dev->ops = &tegra_rtc_ops;
|
||||
info->rtc_dev->range_max = U32_MAX;
|
||||
info->rtc->ops = &tegra_rtc_ops;
|
||||
info->rtc->range_max = U32_MAX;
|
||||
|
||||
info->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(info->clk))
|
||||
|
@ -308,33 +312,30 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set context info. */
|
||||
/* set context info */
|
||||
info->pdev = pdev;
|
||||
spin_lock_init(&info->tegra_rtc_lock);
|
||||
spin_lock_init(&info->lock);
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
/* clear out the hardware. */
|
||||
writel(0, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
|
||||
writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
|
||||
/* clear out the hardware */
|
||||
writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
|
||||
writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
|
||||
tegra_rtc_irq_handler, IRQF_TRIGGER_HIGH,
|
||||
dev_name(&pdev->dev), &pdev->dev);
|
||||
ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
|
||||
IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
|
||||
&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to request interrupt for device (err=%d).\n",
|
||||
ret);
|
||||
dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
ret = rtc_register_device(info->rtc_dev);
|
||||
ret = rtc_register_device(info->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
|
||||
ret);
|
||||
dev_err(&pdev->dev, "failed to register device: %d\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
|
@ -363,20 +364,20 @@ static int tegra_rtc_suspend(struct device *dev)
|
|||
|
||||
tegra_rtc_wait_while_busy(dev);
|
||||
|
||||
/* only use ALARM0 as a wake source. */
|
||||
writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
/* only use ALARM0 as a wake source */
|
||||
writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
|
||||
writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0,
|
||||
info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
|
||||
info->base + TEGRA_RTC_REG_INTR_MASK);
|
||||
|
||||
dev_vdbg(dev, "alarm sec = %d\n",
|
||||
readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
|
||||
readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0));
|
||||
|
||||
dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n",
|
||||
device_may_wakeup(dev), info->tegra_rtc_irq);
|
||||
dev_vdbg(dev, "Suspend (device_may_wakeup=%d) IRQ:%d\n",
|
||||
device_may_wakeup(dev), info->irq);
|
||||
|
||||
/* leave the alarms on as a wake source. */
|
||||
/* leave the alarms on as a wake source */
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(info->tegra_rtc_irq);
|
||||
enable_irq_wake(info->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -386,10 +387,11 @@ static int tegra_rtc_resume(struct device *dev)
|
|||
struct tegra_rtc_info *info = dev_get_drvdata(dev);
|
||||
|
||||
dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n",
|
||||
device_may_wakeup(dev));
|
||||
/* alarms were left on as a wake source, turn them off. */
|
||||
device_may_wakeup(dev));
|
||||
|
||||
/* alarms were left on as a wake source, turn them off */
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(info->tegra_rtc_irq);
|
||||
disable_irq_wake(info->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -399,22 +401,21 @@ static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
|
|||
|
||||
static void tegra_rtc_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
dev_vdbg(&pdev->dev, "disabling interrupts.\n");
|
||||
dev_vdbg(&pdev->dev, "disabling interrupts\n");
|
||||
tegra_rtc_alarm_irq_enable(&pdev->dev, 0);
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:tegra_rtc");
|
||||
static struct platform_driver tegra_rtc_driver = {
|
||||
.remove = tegra_rtc_remove,
|
||||
.shutdown = tegra_rtc_shutdown,
|
||||
.driver = {
|
||||
.name = "tegra_rtc",
|
||||
.probe = tegra_rtc_probe,
|
||||
.remove = tegra_rtc_remove,
|
||||
.shutdown = tegra_rtc_shutdown,
|
||||
.driver = {
|
||||
.name = "tegra_rtc",
|
||||
.of_match_table = tegra_rtc_dt_match,
|
||||
.pm = &tegra_rtc_pm_ops,
|
||||
.pm = &tegra_rtc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(tegra_rtc_driver, tegra_rtc_probe);
|
||||
module_platform_driver(tegra_rtc_driver);
|
||||
|
||||
MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
|
||||
MODULE_DESCRIPTION("driver for Tegra internal RTC");
|
||||
|
|
|
@ -133,6 +133,7 @@ static int test_probe(struct platform_device *plat_dev)
|
|||
break;
|
||||
default:
|
||||
rtd->rtc->ops = &test_rtc_ops;
|
||||
device_init_wakeup(&plat_dev->dev, 1);
|
||||
}
|
||||
|
||||
timer_setup(&rtd->alarm, test_rtc_alarm_handler, 0);
|
||||
|
|
|
@ -143,7 +143,7 @@ static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
struct tps65910 *tps = dev_get_drvdata(dev->parent);
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, alarm_data,
|
||||
ret = regmap_bulk_read(tps->regmap, TPS65910_ALARM_SECONDS, alarm_data,
|
||||
NUM_TIME_REGS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "rtc_read_alarm error %d\n", ret);
|
||||
|
|
|
@ -435,7 +435,8 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
|
||||
wm831x_alm_irq,
|
||||
IRQF_TRIGGER_RISING, "RTC alarm",
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"RTC alarm",
|
||||
wm831x_rtc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
|
||||
|
|
Loading…
Reference in New Issue
Block a user