RTC for 7.4

Subsystem:
  - the hctosys limit for 32bit platforms is now configurable
  - introduce lock guard for for rtc_device.ops_lock
  - use sysfs_emit() instead of sprintf() were possible
  - selftest fixes
 
 New driver:
  - Raspberry Pi 5 RTC
 
 Drivers:
  - abx80x: add support for ABX81X
  - bd70528: properly enable wakeup
  - cmos: Fix ACPI RTC alarm handling
  - ds1685: power-off fixes
  - mt6397: add nvmem support
  - pcf85063: add HW UIE support
  - rs5c372: Ricoh R2223x support
  - rzn1: add R-Car X5H support
  - s35390a: allow use of output pin for interrupt signal 1 for wakealarm to
    support synology devices
  - sun6i: add Allwinner B288 support
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmrmdmcACgkQY6TcMGxw
 OjLB/g/9EG6jcs15Ci3pgKQ4g6h6UKHN86WIA64uPMjvuyAvmyccmrlW6AvwOhoH
 kAp77s8hbujENJk4HPvT4kU0G7KlxpxfZwuvicHNBqGQ1L100Ahx22FdrgXxcejk
 MKuN+30H6iJ01eDEmxJ530VlWCRBTusd8HexDh3Q6IY2mNLiphJXJ+moDheKBnAO
 ECh8lc6Qnb5fFRYqUmAK0QLNKjU8kz6FCgj+vnuSaRftEAgniFmHTJHIiTdB0Bwp
 REdpSMuhjM85oeCxcYu1r1ABnE08a3EbkoHelPlDiO/p1NNQ227IbciCG3rX++bJ
 pa5IWkt2nfvC3RIyxuM5pcCSLpRHgji34LLiCkSzP99S3yujVYcZiBYltuYz5rx0
 Jg4hIb1EmyV7AimQ3XZp1Y+/R2NxKVVHl7MEioq/EFYQFDo04EwcJAYIPn/ZPLDG
 sVpbO/o3lmocP7f6n7jZFkuapQwZ68nijiuRby51gUK4uuraPQou4/igsBlJWn0s
 z6MbS/1jtpRbAQ+8m8ev6LP5s7+4iALd4C8DGYEN53JOpx03LNLFpxPR14i8a5kt
 FaXMjA6f12WvKaVcYJv++r/pxho/iSfXRQiSV3algm921Z5hpkCRi8xauI9sJJmG
 IWjp+xZ+svPE+Ch7kn4jHbEGLbJy2sBSG30TKEE9WhUVOaHdhQo=
 =NTHB
 -----END PGP SIGNATURE-----

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

Pull RTC updates from Alexandre Belloni:
 "This introduces a way to lift the hctosys limit for 32-bit systems to
  ensure systems relying on it can pass Y2038. Add a driver for the
  Raspberry Pi 5 RTC and add support for the Abracon abx81x, Ricoh
  R2223x, Renesas R-Car X5H and Allwinner B288 RTCs to existing drivers:

  Subsystem:
   - the hctosys limit for 32bit platforms is now configurable
   - introduce lock guard for for rtc_device.ops_lock
   - use sysfs_emit() instead of sprintf() were possible
   - selftest fixes

  New driver:
   - Raspberry Pi 5 RTC

  Drivers:
   - abx80x: add support for ABX81X
   - bd70528: properly enable wakeup
   - cmos: Fix ACPI RTC alarm handling
   - ds1685: power-off fixes
   - mt6397: add nvmem support
   - pcf85063: add HW UIE support
   - rs5c372: Ricoh R2223x support
   - rzn1: add R-Car X5H support
   - s35390a: allow use of output pin for interrupt signal 1 for wakealarm to
     support synology devices
   - sun6i: add Allwinner B288 support"

* tag 'rtc-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (89 commits)
  rtc: rs5c372: use sysfs_emit() instead of sprintf()
  rtc: ds1307: use sysfs_emit() instead of sprintf()
  rtc: isl1208: use sysfs_emit() instead of sprintf()
  rtc: ds1685: use sysfs_emit() instead of sprintf()
  rtc: ds1343: use sysfs_emit() instead of sprintf()
  rtc: rx8025: use sysfs_emit() instead of sprintf()
  rtc: x1205: use sysfs_emit() instead of sprintf()
  rtc: bq32k: use sysfs_emit() instead of sprintf()
  rtc: ep93xx: use sysfs_emit() instead of sprintf()
  rtc: pcf2127: use sysfs_emit() instead of sprintf()
  rtc: rv3029: use sysfs_emit() instead of sprintf()
  rtc: ds1685: keep setting PAB until power is removed
  rtc: ds1685: do not sleep in the power-off handler
  rtc: ds1685: arm the wake-up alarm at power-off only if an alarm is set
  rtc: rv3028: use sysfs_emit() instead of sprintf()
  rtc: pcf85063: add 1 Hz update interrupt (UIE) support
  rtc: pcf85063: preserve the alarm flag in clkout register updates
  rtc: pcf85063: do not clear AIE in the interrupt handler
  rtc: pcf85063: use devm_of_clk_add_hw_provider() for clkout
  rtc: s35390a: Add synology quirk
  ...
This commit is contained in:
Linus Torvalds 2026-11-01 08:41:03 -08:00
commit 9b6f2eabc8
58 changed files with 2091 additions and 739 deletions

View File

@ -133,6 +133,11 @@ properties:
required:
- compatible
trickle-voltage-millivolt:
$ref: /schemas/rtc/rtc.yaml#/properties/trickle-voltage-millivolt
minimum: 1300
maximum: 5000
required:
- compatible
- mboxes
@ -144,6 +149,7 @@ examples:
firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
mboxes = <&mailbox>;
trickle-voltage-millivolt = <3300>;
firmware_clocks: clocks {
compatible = "raspberrypi,firmware-clocks";

View File

@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/rtc/abracon,abx80x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Abracon ABX80X I2C ultra low power RTC/Alarm chip
title: Abracon ABX80X (I2C) and ABX81X (SPI) ultra low power RTC/Alarm chips
maintainers:
- linux-rtc@vger.kernel.org
@ -21,10 +21,12 @@ properties:
- abracon,ab0803
- abracon,ab0804
- abracon,ab0805
- abracon,ab0815
- abracon,ab1801
- abracon,ab1803
- abracon,ab1804
- abracon,ab1805
- abracon,ab1815
- microcrystal,rv1805
reg:
@ -61,6 +63,7 @@ required:
- reg
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- $ref: rtc.yaml#
- if:
properties:
@ -73,6 +76,8 @@ allOf:
- abracon,ab1804
- abracon,ab0805
- abracon,ab1805
- abracon,ab0815
- abracon,ab1815
then:
properties:
abracon,tc-diode: false
@ -96,3 +101,14 @@ examples:
interrupts = <44 IRQ_TYPE_EDGE_FALLING>;
};
};
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
rtc@0 {
compatible = "abracon,ab1815";
reg = <0>;
};
};

View File

@ -19,6 +19,7 @@ properties:
- enum:
- allwinner,sun6i-a31-rtc
- allwinner,sun8i-a23-rtc
- allwinner,sun8i-b288-rtc
- allwinner,sun8i-h3-rtc
- allwinner,sun8i-r40-rtc
- allwinner,sun8i-v3-rtc
@ -82,6 +83,7 @@ allOf:
contains:
enum:
- allwinner,sun8i-a23-rtc
- allwinner,sun8i-b288-rtc
- allwinner,sun8i-r40-rtc
- allwinner,sun8i-v3-rtc
@ -162,6 +164,7 @@ allOf:
compatible:
contains:
enum:
- allwinner,sun8i-b288-rtc
- allwinner,sun8i-r40-rtc
- allwinner,sun50i-h616-rtc
- allwinner,sun50i-r329-rtc

View File

@ -14,14 +14,16 @@ properties:
oneOf:
- items:
- enum:
- renesas,r9a06g032-rtc
- const: renesas,rzn1-rtc
- renesas,r9a06g032-rtc # RZ/N1D
- const: renesas,rzn1-rtc # RZ/N1
- const: renesas,r9a09g077-rtc
- const: renesas,r9a09g077-rtc # RZ/T2H
- items:
- const: renesas,r9a09g087-rtc
- const: renesas,r9a09g077-rtc
- const: renesas,r9a09g087-rtc # RZ/N2H
- const: renesas,r9a09g077-rtc # RZ/T2H
- const: renesas,r8a78000-rtc # R-Car X5H
reg:
maxItems: 1
@ -49,11 +51,12 @@ properties:
power-domains:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- power-domains
@ -66,6 +69,7 @@ allOf:
compatible:
contains:
enum:
- renesas,r8a78000-rtc
- renesas,r9a09g077-rtc
- renesas,r9a09g087-rtc
then:
@ -75,6 +79,24 @@ allOf:
clock-names:
minItems: 2
- if:
properties:
compatible:
contains:
const: renesas,r8a78000-rtc
then:
properties:
interrupts: false
interrupt-names: false
required:
- resets
else:
properties:
resets: false
required:
- interrupts
- interrupt-names
unevaluatedProperties: false
examples:
@ -91,5 +113,4 @@ examples:
clocks = <&sysctrl R9A06G032_HCLK_RTC>;
clock-names = "hclk";
power-domains = <&sysctrl>;
start-year = <2000>;
};

View File

@ -0,0 +1,58 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/ricoh,r2223x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ricoh R2223x Real-Time Clock
maintainers:
- Heiko Schocher <hs@nabladev.com>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
const: ricoh,r2223x
reg:
maxItems: 1
interrupts:
maxItems: 1
"#clock-cells":
const: 0
ricoh,eco-mode:
type: boolean
description:
Put the RTC into eco mode, which lowers its current consumption while
running from the backup supply. Set this on boards where the RTC is
expected to keep time on a small backup cell.
start-year: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@32 {
compatible = "ricoh,r2223x";
reg = <0x32>;
interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
#clock-cells = <0>;
ricoh,eco-mode;
};
};

View File

@ -51,6 +51,7 @@ properties:
if trickle charger should be enabled.
trickle-voltage-millivolt:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Selected voltage for trickle charger. Should be given
if trickle charger should be enabled and the trickle voltage is different

View File

@ -0,0 +1,118 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/sii,s35390a.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: S-35390A 2-wire real-time clock
maintainers:
- Markus Probst <markus.probst@posteo.de>
description:
The S-35390A is a CMOS 2-wire real-time clock IC which operates with the
very low current consumption in the wide range of operation voltage.
allOf:
- $ref: rtc.yaml#
properties:
compatible:
const: sii,s35390a
reg:
maxItems: 1
interrupts:
minItems: 1
maxItems: 2
description: Supports up to 2 interrupt lines via the INT1 and INT2 pins.
interrupt-names:
minItems: 1
maxItems: 2
items:
enum:
- int1
- int2
wakeup-parent: true
wakeup-source: true
"#clock-cells":
const: 1
patternProperties:
"^pins":
type: object
additionalProperties: false
patternProperties:
"-pins$":
$ref: /schemas/pinctrl/pinmux-node.yaml#
additionalProperties: false
properties:
pins:
minItems: 1
items:
enum:
- int1
- int2
function:
description: |
Pin function:
- ignore: Preserve the previous state.
- disable: Disable pin output.
- wakeup: Output wakes up the system.
- clock: Output clock pulse.
- pmin1: Minute periodical output with 50% duty.
- pmin2: Minute periodical output L for 7.81 ms.
Can only be used with pin int1.
enum:
- ignore
- disable
- wakeup
- clock
- pmin1
- pmin2
required:
- pins
- function
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@30 {
compatible = "sii,s35390a";
reg = <0x30>;
pinctrl-0 = <&rtc_pins_default>;
pinctrl-names = "default";
interrupt-names = "int1";
interrupts = <23>;
rtc_pins_default: pins {
int1-pins {
pins = "int1";
function = "wakeup";
};
int2-pins {
pins = "int2";
function = "disable";
};
};
};
};

View File

@ -81,8 +81,6 @@ properties:
- ricoh,rv5c386
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
- ricoh,rv5c387a
# 2-wire CMOS real-time clock
- sii,s35390a
# ST SPEAr Real-time Clock
- st,spear600-rtc
# VIA/Wondermedia VT8500 Real-time Clock

View File

@ -24,6 +24,7 @@
static struct platform_device *rpi_hwmon;
static struct platform_device *rpi_clk;
static struct platform_device *rpi_rtc;
struct rpi_firmware {
struct mbox_client cl;
@ -231,6 +232,26 @@ static void rpi_register_clk_driver(struct device *dev)
-1, NULL, 0);
}
static void rpi_register_rtc_driver(struct device *dev)
{
struct platform_device *pdev;
/*
* Check if our model of Raspberry Pi board is from the 5th gen
* as the RTC is only present on that model.
*/
if (!of_machine_is_compatible("brcm,bcm2712"))
return;
pdev = platform_device_register_data(dev, "raspberrypi-rtc",
-1, NULL, 0);
if (IS_ERR(pdev))
return;
rpi_rtc = pdev;
}
unsigned int rpi_firmware_clk_get_max_rate(struct rpi_firmware *fw, unsigned int id)
{
struct rpi_firmware_clk_rate_request msg =
@ -305,6 +326,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
rpi_firmware_print_firmware_revision(fw);
rpi_register_hwmon_driver(dev, fw);
rpi_register_clk_driver(dev);
rpi_register_rtc_driver(dev);
return 0;
}
@ -327,6 +349,8 @@ static void rpi_firmware_remove(struct platform_device *pdev)
rpi_hwmon = NULL;
platform_device_unregister(rpi_clk);
rpi_clk = NULL;
platform_device_unregister(rpi_rtc);
rpi_rtc = NULL;
rpi_firmware_put(fw);
}

View File

@ -14,6 +14,7 @@
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@ -649,7 +650,6 @@ static int amd_pmc_wa_irq1(struct amd_pmc_dev *pdev)
static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
{
struct rtc_device *rtc_device;
time64_t then, now, duration;
struct rtc_wkalrm alarm;
struct rtc_time tm;
@ -665,7 +665,8 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
if (pdev->major < 64 || (pdev->major == 64 && pdev->minor < 53))
return 0;
rtc_device = rtc_class_open("rtc0");
struct rtc_device *rtc_device __free(rtc_class_close) =
rtc_class_open("rtc0");
if (!rtc_device)
return 0;
rc = rtc_read_next_alarm(rtc_device, &alarm);

View File

@ -30,6 +30,27 @@ config RTC_HCTOSYS
the value read from a specified RTC device. This is useful to avoid
unnecessary fsck runs at boot time, and to network better.
config RTC_HCTOSYS_TIME32_LIMIT
bool "Reject RTC dates after the 2038 cutoff"
depends on RTC_HCTOSYS && COMPAT_32BIT_TIME && !64BIT
default y
help
Reject RTC dates after 03:14:07 UTC on 19 January 2038 when
initializing the system clock in order to work around broken
RTC implementations that produce nondeterministic timestamps
without a working backup battery.
A rejected date leaves system time unchanged, normally near
the Unix epoch, and the RTC's hctosys sysfs attribute reads
0. Userspace must supply the time if no other source has
initialized it.
Say Y here if the kernel may have to run old time32 userspace on
hardware that can produce unpredictable RTC timestamps. If the
kernel is intended to only run time64 compatible userspace and
continue working past 2038, you must pick N here in order to
have a working RTC_HCTOSYS functionality.
config RTC_HCTOSYS_DEVICE
string "RTC used to set the system time"
depends on RTC_HCTOSYS
@ -212,17 +233,6 @@ config RTC_DRV_ABEOZ9
This driver can also be built as a module. If so, the module
will be called rtc-ab-e0z9.
config RTC_DRV_ABX80X
tristate "Abracon ABx80x"
select WATCHDOG_CORE if WATCHDOG
help
If you say yes here you get support for Abracon AB080X and AB180X
families of ultra-low-power battery- and capacitor-backed real-time
clock chips.
This driver can also be built as a module. If so, the module
will be called rtc-abx80x.
config RTC_DRV_AC100
tristate "X-Powers AC100"
depends on MFD_AC100
@ -668,7 +678,9 @@ config RTC_DRV_RC5T619
config RTC_DRV_S35390A
tristate "Seiko Instruments S-35390A"
select PINCTRL
select BITREVERSE
select GENERIC_PINCONF
help
If you say yes here you will get support for the Seiko
Instruments S-35390A.
@ -954,6 +966,20 @@ config RTC_I2C_AND_SPI
comment "SPI and I2C RTC drivers"
config RTC_DRV_ABX80X
tristate "Abracon ABx80x"
depends on RTC_I2C_AND_SPI
select WATCHDOG_CORE if WATCHDOG
select REGMAP_I2C if I2C
select REGMAP_SPI if SPI_MASTER
help
If you say yes here you get support for Abracon AB080X, AB180X,
AB081X and AB181X families of ultra-low-power battery- and
capacitor-backed real-time clock chips.
This driver can also be built as a module. If so, the module
will be called rtc-abx80x.
config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232/DS3234"
depends on RTC_I2C_AND_SPI
@ -1999,6 +2025,18 @@ config RTC_DRV_R7301
This driver can also be built as a module. If so, the module
will be called rtc-r7301.
config RTC_DRV_RPI
tristate "Raspberry Pi RTC"
depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
depends on ARCH_BCM2835 || COMPILE_TEST
default ARCH_BCM2835
help
If you say yes here you get support for the RTC found on
Raspberry Pi 5th gen devices.
This driver can also be built as a module. If so, the module
will be called rtc-raspberrypi.
config RTC_DRV_STM32
tristate "STM32 RTC"
select REGMAP_MMIO

View File

@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RPI) += rtc-raspberrypi.o
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o

View File

@ -72,12 +72,14 @@ static void rtc_hctosys(struct rtc_device *rtc)
tv64.tv_sec = rtc_tm_to_time64(&tm);
#if BITS_PER_LONG == 32
if (tv64.tv_sec > INT_MAX) {
if (IS_ENABLED(CONFIG_RTC_HCTOSYS_TIME32_LIMIT) &&
tv64.tv_sec > INT_MAX) {
dev_warn(rtc->dev.parent,
"hctosys: rejecting %ptR UTC due to CONFIG_RTC_HCTOSYS_TIME32_LIMIT=y\n",
&tm);
err = -ERANGE;
goto err_read;
}
#endif
err = do_settimeofday64(&tv64);

File diff suppressed because it is too large Load Diff

View File

@ -516,12 +516,12 @@ static irqreturn_t ac100_rtc_irq(int irq, void *data)
unsigned int val = 0;
int ret;
rtc_lock(chip->rtc);
guard(rtc_ops)(chip->rtc);
/* read status */
ret = regmap_read(regmap, AC100_ALM_INT_STA, &val);
if (ret)
goto out;
return IRQ_HANDLED;
if (val & AC100_ALM_INT_ENABLE) {
/* signal rtc framework */
@ -530,16 +530,14 @@ static irqreturn_t ac100_rtc_irq(int irq, void *data)
/* clear status */
ret = regmap_write(regmap, AC100_ALM_INT_STA, val);
if (ret)
goto out;
return IRQ_HANDLED;
/* disable interrupt */
ret = ac100_rtc_alarm_irq_enable(chip->dev, 0);
if (ret)
goto out;
return IRQ_HANDLED;
}
out:
rtc_unlock(chip->rtc);
return IRQ_HANDLED;
}

View File

@ -116,15 +116,13 @@ static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id)
u32 isr;
unsigned long events = 0;
rtc_lock(priv->rtc);
guard(rtc_ops)(priv->rtc);
isr = ioread32(priv->iobase + HW_CIIR);
if (!isr) {
rtc_unlock(priv->rtc);
return IRQ_NONE;
}
iowrite32(0, priv->iobase + HW_CIIR);
rtc_unlock(priv->rtc);
events |= RTC_AF | RTC_IRQF;

View File

@ -147,7 +147,7 @@ static void atcrtc_alarm_clear(struct work_struct *work)
container_of(work, struct atcrtc_dev, rtc_work);
int ret;
rtc_lock(rtc->rtc_dev);
guard(rtc_ops)(rtc->rtc_dev);
if (!rtc->alarm_en) {
ret = atcrtc_check_write_done(rtc);
@ -159,7 +159,6 @@ static void atcrtc_alarm_clear(struct work_struct *work)
regmap_update_bits(rtc->regmap, RTC_CR,
ALARM_WAKEUP | ALARM_INT, 0);
}
rtc_unlock(rtc->rtc_dev);
}
static int atcrtc_read_time(struct device *dev, struct rtc_time *tm)

View File

@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
@ -328,6 +329,10 @@ static int bd70528_probe(struct platform_device *pdev)
device_set_wakeup_capable(&pdev->dev, true);
device_wakeup_enable(&pdev->dev);
ret = devm_pm_set_wake_irq(&pdev->dev, irq);
if (ret)
return ret;
rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc)) {
dev_err(&pdev->dev, "RTC device creation failed\n");

View File

@ -210,7 +210,7 @@ static ssize_t bq32k_sysfs_show_tricklecharge_bypass(struct device *dev,
if (error)
return error;
return sprintf(buf, "%d\n", (reg & BQ32K_TCFE) ? 1 : 0);
return sysfs_emit(buf, "%d\n", (reg & BQ32K_TCFE) ? 1 : 0);
}
static ssize_t bq32k_sysfs_store_tricklecharge_bypass(struct device *dev,

View File

@ -57,7 +57,28 @@
*/
static bool use_acpi_alarm;
module_param(use_acpi_alarm, bool, 0444);
static bool use_acpi_alarm_explicit;
static int set_use_acpi_alarm(const char *val, const struct kernel_param *kp)
{
int ret;
ret = param_set_bool(val, kp);
if (!ret)
use_acpi_alarm_explicit = true;
return ret;
}
static const struct kernel_param_ops use_acpi_alarm_ops = {
.flags = KERNEL_PARAM_OPS_FL_NOARG,
.set = set_use_acpi_alarm,
.get = param_get_bool,
};
param_check_bool(use_acpi_alarm, &use_acpi_alarm);
module_param_cb(use_acpi_alarm, &use_acpi_alarm_ops, &use_acpi_alarm, 0444);
__MODULE_PARM_TYPE(use_acpi_alarm, "bool");
static inline int cmos_use_acpi_alarm(void)
{
@ -758,7 +779,9 @@ static u32 rtc_handler(void *context)
unsigned char rtc_intr;
unsigned long flags;
/* Quiesce this event before rtc->irqwork can arm the next one. */
acpi_clear_event(ACPI_EVENT_RTC);
acpi_disable_event(ACPI_EVENT_RTC, 0);
/*
* Always update rtc irq when ACPI is used as RTC Alarm.
* Or else, ACPI SCI is enabled during suspend/resume only,
@ -781,8 +804,6 @@ static u32 rtc_handler(void *context)
}
pm_wakeup_hard_event(dev);
acpi_clear_event(ACPI_EVENT_RTC);
acpi_disable_event(ACPI_EVENT_RTC, 0);
return ACPI_INTERRUPT_HANDLED;
}
@ -822,6 +843,9 @@ static void rtc_wake_off(struct device *dev)
#ifdef CONFIG_X86
static void use_acpi_alarm_quirks(void)
{
if (use_acpi_alarm_explicit)
return;
if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC)
return;

View File

@ -440,7 +440,7 @@ static void ds1305_work(struct work_struct *work)
int status;
/* lock to protect ds1305->ctrl */
rtc_lock(ds1305->rtc);
guard(rtc_ops)(ds1305->rtc);
/* Disable the IRQ, and clear its status ... for now, we "know"
* that if more than one alarm is active, they're in sync.
@ -458,8 +458,6 @@ static void ds1305_work(struct work_struct *work)
if (status < 0)
dev_dbg(&spi->dev, "clear irq --> %d\n", status);
rtc_unlock(ds1305->rtc);
if (!test_bit(FLAG_EXITING, &ds1305->flags))
enable_irq(spi->irq);

View File

@ -579,28 +579,27 @@ static irqreturn_t rx8130_irq(int irq, void *dev_id)
u8 ctl[3];
int ret;
rtc_lock(ds1307->rtc);
guard(rtc_ops)(ds1307->rtc);
/* Read control registers. */
ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl,
sizeof(ctl));
if (ret < 0)
goto out;
return IRQ_HANDLED;
if (!(ctl[1] & RX8130_REG_FLAG_AF))
goto out;
return IRQ_HANDLED;
ctl[1] &= ~RX8130_REG_FLAG_AF;
ctl[2] &= ~RX8130_REG_CONTROL0_AIE;
ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl,
sizeof(ctl));
if (ret < 0)
goto out;
return IRQ_HANDLED;
rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
out:
rtc_unlock(ds1307->rtc);
return IRQ_HANDLED;
}
@ -1381,7 +1380,7 @@ static ssize_t ds3231_hwmon_show_temp(struct device *dev,
if (ret)
return ret;
return sprintf(buf, "%d\n", temp);
return sysfs_emit(buf, "%d\n", temp);
}
static SENSOR_DEVICE_ATTR(temp1_input, 0444, ds3231_hwmon_show_temp,
NULL, 0);
@ -1891,7 +1890,6 @@ static int ds1307_probe(struct i2c_client *client)
if (!ds1307)
return -ENOMEM;
dev_set_drvdata(&client->dev, ds1307);
ds1307->dev = &client->dev;
ds1307->name = client->name;

View File

@ -94,9 +94,9 @@ static ssize_t ds1343_show_glitchfilter(struct device *dev,
glitch_filt_status = !!(data & DS1343_EGFIL);
if (glitch_filt_status)
return sprintf(buf, "enabled\n");
return sysfs_emit(buf, "enabled\n");
else
return sprintf(buf, "disabled\n");
return sysfs_emit(buf, "disabled\n");
}
static ssize_t ds1343_store_glitchfilter(struct device *dev,
@ -180,7 +180,7 @@ static ssize_t ds1343_show_tricklecharger(struct device *dev,
}
}
return sprintf(buf, "%s %s\n", diodes, resistors);
return sysfs_emit(buf, "%s %s\n", diodes, resistors);
}
static DEVICE_ATTR(trickle_charger, 0444, ds1343_show_tricklecharger, NULL);
@ -312,11 +312,11 @@ static irqreturn_t ds1343_thread(int irq, void *dev_id)
unsigned int stat;
int res = 0;
rtc_lock(priv->rtc);
guard(rtc_ops)(priv->rtc);
res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
if (res)
goto out;
return IRQ_HANDLED;
if (stat & DS1343_IRQF0) {
stat &= ~DS1343_IRQF0;
@ -328,8 +328,6 @@ static irqreturn_t ds1343_thread(int irq, void *dev_id)
DS1343_A0IE, 0);
}
out:
rtc_unlock(priv->rtc);
return IRQ_HANDLED;
}

View File

@ -666,7 +666,7 @@ ds1685_rtc_irq_handler(int irq, void *dev_id)
if (unlikely(!rtc))
return IRQ_HANDLED;
rtc_lock(rtc->dev);
guard(rtc_ops)(rtc->dev);
/* Ctrlb holds the interrupt-enable bits and ctrlc the flag bits. */
ctrlb = rtc->read(rtc, RTC_CTRL_B);
@ -711,7 +711,6 @@ ds1685_rtc_irq_handler(int irq, void *dev_id)
}
}
rtc_update_irq(rtc->dev, num_irqs, events);
rtc_unlock(rtc->dev);
return events ? IRQ_HANDLED : IRQ_NONE;
}
@ -989,8 +988,8 @@ ds1685_rtc_sysfs_battery_show(struct device *dev,
ctrld = rtc->read(rtc, RTC_CTRL_D);
return sprintf(buf, "%s\n",
(ctrld & RTC_CTRL_D_VRT) ? "ok" : "not ok or N/A");
return sysfs_emit(buf, "%s\n",
(ctrld & RTC_CTRL_D_VRT) ? "ok" : "not ok or N/A");
}
static DEVICE_ATTR(battery, S_IRUGO, ds1685_rtc_sysfs_battery_show, NULL);
@ -1011,8 +1010,8 @@ ds1685_rtc_sysfs_auxbatt_show(struct device *dev,
ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
ds1685_rtc_switch_to_bank0(rtc);
return sprintf(buf, "%s\n",
(ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "not ok or N/A");
return sysfs_emit(buf, "%s\n",
(ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "not ok or N/A");
}
static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_rtc_sysfs_auxbatt_show, NULL);
@ -1033,7 +1032,7 @@ ds1685_rtc_sysfs_serial_show(struct device *dev,
ds1685_rtc_get_ssn(rtc, ssn);
ds1685_rtc_switch_to_bank0(rtc);
return sprintf(buf, "%8phC\n", ssn);
return sysfs_emit(buf, "%8phC\n", ssn);
}
static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL);
@ -1367,7 +1366,7 @@ module_platform_driver(ds1685_rtc_driver);
void __noreturn
ds1685_rtc_poweroff(struct platform_device *pdev)
{
u8 ctrla, ctrl4a, ctrl4b;
u8 ctrla, ctrlb, ctrl4a, ctrl4b;
struct ds1685_priv *rtc;
/* Check for valid RTC data, else, spin forever. */
@ -1394,6 +1393,8 @@ ds1685_rtc_poweroff(struct platform_device *pdev)
ctrla &= ~(RTC_CTRL_A_DV2);
rtc->write(rtc, RTC_CTRL_A, ctrla);
ctrlb = rtc->read(rtc, RTC_CTRL_B);
/*
* Read Control 4A and check the status of the auxillary
* battery. This must be present and working (VRT2 = 1)
@ -1408,25 +1409,35 @@ ds1685_rtc_poweroff(struct platform_device *pdev)
/*
* The auxillary battery is present and working.
* Enable extended functions (ABE=1), enable
* wake-up (WIE=1), and enable kickstart (KSE=1)
* in Control 4B.
* Enable extended functions (ABE=1) and kickstart
* (KSE=1) in Control 4B. Enable wake-up (WIE=1) only
* if an alarm is set, else stale alarm registers
* can power the system back on.
*/
ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
ctrl4b |= (RTC_CTRL_4B_ABE | RTC_CTRL_4B_WIE |
RTC_CTRL_4B_KSE);
ctrl4b |= (RTC_CTRL_4B_ABE | RTC_CTRL_4B_KSE);
if (ctrlb & RTC_CTRL_B_AIE)
ctrl4b |= RTC_CTRL_4B_WIE;
else
ctrl4b &= ~(RTC_CTRL_4B_WIE);
rtc->write(rtc, RTC_EXT_CTRL_4B, ctrl4b);
}
/* Set PAB to 1 in Control 4A to power the system down. */
/*
* Set PAB to 1 in Control 4A to power the system down. PAB
* is cleared again while KF and KSE, or WF and WIE, are set,
* so keep clearing the flags and setting PAB until power is
* gone. We do not switch back to bank0.
*/
dev_warn(&pdev->dev, "Powerdown.\n");
msleep(20);
rtc->write(rtc, RTC_EXT_CTRL_4A,
(ctrl4a | RTC_CTRL_4A_PAB));
/* Spin ... we do not switch back to bank0. */
while(1);
unreachable();
mdelay(20);
while (1) {
ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
rtc->write(rtc, RTC_EXT_CTRL_4A,
(ctrl4a & ~RTC_CTRL_4A_RWK_MASK) |
RTC_CTRL_4A_PAB);
mdelay(100);
}
}
}
EXPORT_SYMBOL_GPL(ds1685_rtc_poweroff);

View File

@ -389,45 +389,39 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
int ret;
int stat, control;
rtc_lock(ds3232->rtc);
guard(rtc_ops)(ds3232->rtc);
ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret)
goto unlock;
return IRQ_HANDLED;
if (stat & DS3232_REG_SR_A1F) {
ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret) {
dev_warn(ds3232->dev,
"Read Control Register error %d\n", ret);
} else {
/* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE);
ret = regmap_write(ds3232->regmap, DS3232_REG_CR,
control);
if (ret) {
dev_warn(ds3232->dev,
"Write Control Register error %d\n",
ret);
goto unlock;
}
/* clear the alarm pend flag */
stat &= ~DS3232_REG_SR_A1F;
ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
if (ret) {
dev_warn(ds3232->dev,
"Write Status Register error %d\n",
ret);
goto unlock;
}
rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
return IRQ_HANDLED;
}
/* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE);
ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
if (ret) {
dev_warn(ds3232->dev,
"Write Control Register error %d\n", ret);
return IRQ_HANDLED;
}
}
unlock:
rtc_unlock(ds3232->rtc);
/* clear the alarm pend flag */
stat &= ~DS3232_REG_SR_A1F;
ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
if (ret) {
dev_warn(ds3232->dev,
"Write Status Register error %d\n", ret);
return IRQ_HANDLED;
}
rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
}
return IRQ_HANDLED;
}

View File

@ -93,7 +93,7 @@ static ssize_t comp_preload_show(struct device *dev,
ep93xx_rtc_get_swcomp(dev->parent, &preload, NULL);
return sprintf(buf, "%d\n", preload);
return sysfs_emit(buf, "%d\n", preload);
}
static DEVICE_ATTR_RO(comp_preload);
@ -104,7 +104,7 @@ static ssize_t comp_delete_show(struct device *dev,
ep93xx_rtc_get_swcomp(dev->parent, NULL, &delete);
return sprintf(buf, "%d\n", delete);
return sysfs_emit(buf, "%d\n", delete);
}
static DEVICE_ATTR_RO(comp_delete);

View File

@ -72,7 +72,7 @@ static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD);
time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
time = offset + (timeu64_t)days * 86400 + hour * 3600 + min * 60 + sec;
rtc_time64_to_tm(time, tm);
@ -92,7 +92,7 @@ static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);
offset = time - ((timeu64_t)day * 86400 + hour * 3600 + min * 60 + sec);
writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD);
writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR);
@ -119,51 +119,33 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
rtc->pclk = devm_clk_get(dev, "PCLK");
if (IS_ERR(rtc->pclk)) {
rtc->pclk = devm_clk_get_enabled(dev, "PCLK");
if (IS_ERR_OR_NULL(rtc->pclk)) {
dev_err(dev, "could not get PCLK\n");
} else {
ret = clk_prepare_enable(rtc->pclk);
if (ret) {
dev_err(dev, "failed to enable PCLK\n");
return ret;
}
return PTR_ERR_OR_ZERO(rtc->pclk);
}
rtc->extclk = devm_clk_get(dev, "EXTCLK");
if (IS_ERR(rtc->extclk)) {
rtc->extclk = devm_clk_get_enabled(dev, "EXTCLK");
if (IS_ERR_OR_NULL(rtc->extclk)) {
dev_err(dev, "could not get EXTCLK\n");
} else {
ret = clk_prepare_enable(rtc->extclk);
if (ret) {
dev_err(dev, "failed to enable EXTCLK\n");
goto err_disable_pclk;
}
return PTR_ERR_OR_ZERO(rtc->extclk);
}
rtc->rtc_irq = platform_get_irq(pdev, 0);
if (rtc->rtc_irq < 0) {
ret = rtc->rtc_irq;
goto err_disable_extclk;
}
if (rtc->rtc_irq < 0)
return rtc->rtc_irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
goto err_disable_extclk;
}
if (!res)
return -ENODEV;
rtc->rtc_base = devm_ioremap(dev, res->start,
resource_size(res));
if (!rtc->rtc_base) {
ret = -ENOMEM;
goto err_disable_extclk;
}
if (!rtc->rtc_base)
return -ENOMEM;
rtc_dev = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc_dev)) {
ret = PTR_ERR(rtc_dev);
goto err_disable_extclk;
}
if (IS_ERR(rtc_dev))
return PTR_ERR(rtc_dev);
rtc_dev->ops = &ftrtc010_rtc_ops;
@ -178,25 +160,13 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
IRQF_SHARED, pdev->name, dev);
if (unlikely(ret))
goto err_disable_extclk;
return ret;
return devm_rtc_register_device(rtc_dev);
ret = devm_rtc_register_device(rtc_dev);
if (ret)
return ret;
err_disable_extclk:
clk_disable_unprepare(rtc->extclk);
err_disable_pclk:
clk_disable_unprepare(rtc->pclk);
return ret;
}
static void ftrtc010_rtc_remove(struct platform_device *pdev)
{
struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev);
if (!IS_ERR(rtc->extclk))
clk_disable_unprepare(rtc->extclk);
if (!IS_ERR(rtc->pclk))
clk_disable_unprepare(rtc->pclk);
return 0;
}
static const struct of_device_id ftrtc010_rtc_dt_match[] = {
@ -212,7 +182,6 @@ static struct platform_driver ftrtc010_rtc_driver = {
.of_match_table = ftrtc010_rtc_dt_match,
},
.probe = ftrtc010_rtc_probe,
.remove = ftrtc010_rtc_remove,
};
module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);

View File

@ -417,7 +417,7 @@ static irqreturn_t hym8563_irq(int irq, void *dev_id)
struct i2c_client *client = hym8563->client;
int data, ret;
rtc_lock(hym8563->rtc);
guard(rtc_ops)(hym8563->rtc);
/* Clear the alarm flag */
@ -425,7 +425,7 @@ static irqreturn_t hym8563_irq(int irq, void *dev_id)
if (data < 0) {
dev_err(&client->dev, "%s: error reading i2c data %d\n",
__func__, data);
goto out;
return IRQ_HANDLED;
}
data &= ~HYM8563_CTL2_AF;
@ -436,8 +436,6 @@ static irqreturn_t hym8563_irq(int irq, void *dev_id)
__func__, ret);
}
out:
rtc_unlock(hym8563->rtc);
return IRQ_HANDLED;
}

View File

@ -615,8 +615,8 @@ static ssize_t timestamp0_show(struct device *dev,
if (sr)
return sr;
return sprintf(buf, "%llu\n",
(unsigned long long)rtc_tm_to_time64(&tm));
return sysfs_emit(buf, "%llu\n",
(unsigned long long)rtc_tm_to_time64(&tm));
};
static DEVICE_ATTR_RW(timestamp0);
@ -709,7 +709,7 @@ isl1208_sysfs_show_atrim(struct device *dev,
if (atr < 0)
return atr;
return sprintf(buf, "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25);
return sysfs_emit(buf, "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25);
}
static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL);
@ -722,7 +722,7 @@ isl1208_sysfs_show_dtrim(struct device *dev,
if (dtr < 0)
return dtr;
return sprintf(buf, "%d ppm\n", dtr - 100);
return sysfs_emit(buf, "%d ppm\n", dtr - 100);
}
static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
@ -735,7 +735,7 @@ isl1208_sysfs_show_usr(struct device *dev,
if (usr < 0)
return usr;
return sprintf(buf, "0x%.4x\n", usr);
return sysfs_emit(buf, "0x%.4x\n", usr);
}
static ssize_t

View File

@ -162,19 +162,15 @@ static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
unsigned long events = 0;
int flags, flags_afe;
rtc_lock(m41t80->rtc);
guard(rtc_ops)(m41t80->rtc);
flags_afe = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (flags_afe < 0) {
rtc_unlock(m41t80->rtc);
if (flags_afe < 0)
return IRQ_NONE;
}
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
if (flags <= 0) {
rtc_unlock(m41t80->rtc);
if (flags <= 0)
return IRQ_NONE;
}
if (flags & M41T80_FLAGS_AF) {
flags &= ~M41T80_FLAGS_AF;
@ -189,8 +185,6 @@ static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
flags_afe);
}
rtc_unlock(m41t80->rtc);
return IRQ_HANDLED;
}

View File

@ -352,7 +352,7 @@ static irqreturn_t mcp795_irq(int irq, void *data)
struct rtc_device *rtc = spi_get_drvdata(spi);
int ret;
rtc_lock(rtc);
guard(rtc_ops)(rtc);
/* Disable alarm.
* There is no need to clear ALM0IF (Alarm 0 Interrupt Flag) bit,
@ -364,7 +364,6 @@ static irqreturn_t mcp795_irq(int irq, void *data)
"Failed to disable alarm in IRQ (ret=%d)\n", ret);
rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
rtc_unlock(rtc);
return IRQ_HANDLED;
}

View File

@ -131,8 +131,8 @@ static int mpfs_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->enabled = mode & MODE_WAKE_EN;
time = (u64)readl(rtcdev->base + ALARM_LOWER_REG) << 32;
time |= (readl(rtcdev->base + ALARM_UPPER_REG) & ALARM_UPPER_MASK);
time = readl(rtcdev->base + ALARM_LOWER_REG);
time |= ((u64)readl(rtcdev->base + ALARM_UPPER_REG) & ALARM_UPPER_MASK) << 32;
rtc_time64_to_tm(time, &alrm->time);
return 0;

View File

@ -4,6 +4,8 @@
* Author: Tianping.Fang <tianping.fang@mediatek.com>
*/
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/mfd/mt6397/core.h>
@ -243,10 +245,91 @@ static const struct rtc_class_ops mtk_rtc_ops = {
.set_alarm = mtk_rtc_set_alarm,
};
/*
* The spare byte of each of these registers, in the order a board addresses
* them as RTC_NEW_SPARE0 to RTC_NEW_SPARE3.
*/
static const u32 mtk_rtc_spare_reg[] = {
RTC_AL_HOU, RTC_AL_DOM, RTC_AL_DOW, RTC_AL_MTH,
};
static int mtk_rtc_nvram_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct mt6397_rtc *rtc = priv;
u8 *buf = val;
u32 data;
int ret = 0;
if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) ||
bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset)
return -EINVAL;
mutex_lock(&rtc->lock);
while (bytes--) {
ret = regmap_read(rtc->regmap,
rtc->addr_base + mtk_rtc_spare_reg[offset++],
&data);
if (ret)
break;
*buf++ = FIELD_GET(RTC_SPARE_MASK, data);
}
mutex_unlock(&rtc->lock);
return ret;
}
static int mtk_rtc_nvram_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
struct mt6397_rtc *rtc = priv;
u8 *buf = val;
int ret = 0;
if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) ||
bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset)
return -EINVAL;
mutex_lock(&rtc->lock);
while (bytes--) {
ret = regmap_update_bits(rtc->regmap,
rtc->addr_base + mtk_rtc_spare_reg[offset++],
RTC_SPARE_MASK,
FIELD_PREP(RTC_SPARE_MASK, *buf++));
if (ret)
goto out;
}
/*
* None of it reaches the always-on domain until the write trigger,
* which commits every pending alarm register at once -- so this runs
* under the same lock the alarm paths take, rather than landing in
* the middle of one of them.
*/
ret = mtk_rtc_write_trigger(rtc);
out:
mutex_unlock(&rtc->lock);
return ret;
}
static int mtk_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
struct nvmem_config nvmem_cfg = {
.name = "mt6397_rtc_spare",
.word_size = 1,
.stride = 1,
.size = ARRAY_SIZE(mtk_rtc_spare_reg),
.type = NVMEM_TYPE_BATTERY_BACKED,
.reg_read = mtk_rtc_nvram_read,
.reg_write = mtk_rtc_nvram_write,
};
struct mt6397_rtc *rtc;
int ret;
@ -293,7 +376,13 @@ static int mtk_rtc_probe(struct platform_device *pdev)
rtc->rtc_dev->start_secs = mktime64(1968, 1, 2, 0, 0, 0);
rtc->rtc_dev->set_start_time = true;
return devm_rtc_register_device(rtc->rtc_dev);
ret = devm_rtc_register_device(rtc->rtc_dev);
if (ret)
return ret;
nvmem_cfg.priv = rtc;
return devm_rtc_nvmem_register(rtc->rtc_dev, &nvmem_cfg);
}
#ifdef CONFIG_PM_SLEEP

View File

@ -4,6 +4,7 @@
#include <linux/bcd.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
@ -23,6 +24,7 @@
#define NCT3018Y_REG_CTRL 0x0A /* timer control */
#define NCT3018Y_REG_ST 0x0B /* status */
#define NCT3018Y_REG_CLKO 0x0C /* clock out */
#define NCT3018Y_REG_INTR_CTRL 0x12 /* intrusion control */
#define NCT3018Y_REG_PART 0x21 /* part info */
#define NCT3018Y_BIT_AF BIT(7)
@ -34,6 +36,7 @@
#define NCT3018Y_BIT_OFIE BIT(2)
#define NCT3018Y_BIT_CIE BIT(1)
#define NCT3018Y_BIT_TWO BIT(0)
#define NCT3018Y_BIT_INTRUSION BIT(1) /* in NCT3018Y_REG_INTR_CTRL */
#define NCT3018Y_REG_BAT_MASK 0x07
#define NCT3018Y_REG_CLKO_F_MASK 0x03 /* frequenc mask */
@ -491,6 +494,95 @@ static const struct rtc_class_ops nct3018y_rtc_ops = {
.ioctl = nct3018y_ioctl,
};
#if IS_REACHABLE(CONFIG_HWMON)
static umode_t nct3018y_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
if (type == hwmon_intrusion && attr == hwmon_intrusion_alarm)
return 0644;
return 0;
}
static int nct3018y_hwmon_read(struct device *dev,
enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct nct3018y *nct3018y = dev_get_drvdata(dev);
int flags;
flags = i2c_smbus_read_byte_data(nct3018y->client,
NCT3018Y_REG_INTR_CTRL);
if (flags < 0)
return flags;
*val = !!(flags & NCT3018Y_BIT_INTRUSION);
return 0;
}
static int nct3018y_hwmon_write(struct device *dev,
enum hwmon_sensor_types type, u32 attr,
int channel, long val)
{
struct nct3018y *nct3018y = dev_get_drvdata(dev);
int flags;
/* The alarm latches until it is cleared, and only clearing is a
* meaningful thing to ask for.
*/
if (val)
return -EINVAL;
flags = i2c_smbus_read_byte_data(nct3018y->client,
NCT3018Y_REG_INTR_CTRL);
if (flags < 0)
return flags;
return i2c_smbus_write_byte_data(nct3018y->client,
NCT3018Y_REG_INTR_CTRL,
flags & ~NCT3018Y_BIT_INTRUSION);
}
static const struct hwmon_channel_info * const nct3018y_hwmon_info[] = {
HWMON_CHANNEL_INFO(intrusion, HWMON_INTRUSION_ALARM),
NULL
};
static const struct hwmon_ops nct3018y_hwmon_ops = {
.is_visible = nct3018y_hwmon_is_visible,
.read = nct3018y_hwmon_read,
.write = nct3018y_hwmon_write,
};
static const struct hwmon_chip_info nct3018y_hwmon_chip_info = {
.ops = &nct3018y_hwmon_ops,
.info = nct3018y_hwmon_info,
};
static void nct3018y_hwmon_register(struct nct3018y *nct3018y)
{
struct device *dev;
dev = devm_hwmon_device_register_with_info(&nct3018y->client->dev,
"nct3018y", nct3018y,
&nct3018y_hwmon_chip_info,
NULL);
if (IS_ERR(dev))
dev_warn(&nct3018y->client->dev,
"unable to register hwmon device %ld\n", PTR_ERR(dev));
}
#else
static void nct3018y_hwmon_register(struct nct3018y *nct3018y)
{
}
#endif /* IS_REACHABLE(CONFIG_HWMON) */
static int nct3018y_probe(struct i2c_client *client)
{
struct nct3018y *nct3018y;
@ -568,6 +660,8 @@ static int nct3018y_probe(struct i2c_client *client)
nct3018y_clkout_register_clk(nct3018y);
#endif
nct3018y_hwmon_register(nct3018y);
return devm_rtc_register_device(nct3018y->rtc);
}

View File

@ -210,20 +210,16 @@ static irqreturn_t nct6694_irq(int irq, void *dev_id)
};
int ret;
rtc_lock(data->rtc);
guard(rtc_ops)(data->rtc);
sts->irq_en = NCT6694_RTC_IRQ_EN;
sts->irq_pend = NCT6694_RTC_IRQ_STS;
ret = nct6694_write_msg(data->nct6694, &cmd_hd, sts);
if (ret) {
rtc_unlock(data->rtc);
if (ret)
return IRQ_NONE;
}
rtc_update_irq(data->rtc, 1, RTC_IRQF | RTC_AF);
rtc_unlock(data->rtc);
return IRQ_HANDLED;
}

View File

@ -358,11 +358,8 @@ static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data)
if (ret < 0)
return IRQ_NONE;
if (ret & NVVRS_INT_SRC1_RTC_MASK) {
rtc_lock(info->rtc);
if (ret & NVVRS_INT_SRC1_RTC_MASK)
rtc_update_irq(info->rtc, 1, RTC_IRQF | RTC_AF);
rtc_unlock(info->rtc);
}
/* Clear all interrupts */
if (nvvrs_pseq_irq_clear(info) < 0)

View File

@ -408,7 +408,7 @@ static struct omap_rtc *omap_rtc_power_off_rtc;
* generates pmic_pwr_enable control, which can be used to control an external
* PMIC.
*/
int omap_rtc_power_off_program(struct device *dev)
int omap_rtc_power_off_program(void)
{
struct omap_rtc *rtc = omap_rtc_power_off_rtc;
struct rtc_time tm;
@ -481,10 +481,9 @@ EXPORT_SYMBOL(omap_rtc_power_off_program);
*/
static void omap_rtc_power_off(void)
{
struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc;
u32 val;
omap_rtc_power_off_program(rtc->dev.parent);
omap_rtc_power_off_program();
/* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */
omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc);

View File

@ -310,7 +310,8 @@ static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
unsigned int val = 0;
int ret = IRQ_NONE;
rtc_lock(pcf2123->rtc);
guard(rtc_ops)(pcf2123->rtc);
regmap_read(pcf2123->map, PCF2123_REG_CTRL2, &val);
/* Alarm? */
@ -323,8 +324,6 @@ static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
rtc_update_irq(pcf2123->rtc, 1, RTC_IRQF | RTC_AF);
}
rtc_unlock(pcf2123->rtc);
return ret;
}

View File

@ -972,7 +972,7 @@ static ssize_t timestamp_show(struct device *dev,
if (ret)
return ret;
}
return sprintf(buf, "%llu\n", (unsigned long long)ts);
return sysfs_emit(buf, "%llu\n", (unsigned long long)ts);
}
static ssize_t timestamp0_show(struct device *dev,

View File

@ -44,6 +44,7 @@
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_CTRL2_AF BIT(6)
#define PCF85063_CTRL2_AIE BIT(7)
#define PCF85063_CTRL2_TF BIT(3)
#define PCF85063_REG_OFFSET 0x02
#define PCF85063_OFFSET_SIGN_BIT 6 /* 2's complement sign bit */
@ -63,6 +64,14 @@
#define PCF85063_REG_ALM_S 0x0b
#define PCF85063_AEN BIT(7)
#define PCF85063_REG_TIMER_VALUE 0x10
#define PCF85063_REG_TIMER_MODE 0x11
#define PCF85063_TIMER_MODE_TI_TP BIT(0)
#define PCF85063_TIMER_MODE_TIE BIT(1)
#define PCF85063_TIMER_MODE_TE BIT(2)
#define PCF85063_TIMER_MODE_TCF_MASK GENMASK(4, 3)
#define PCF85063_TIMER_MODE_TCF_1HZ (2 << 3)
struct pcf85063_config {
struct regmap_config regmap;
unsigned has_alarms:1;
@ -188,20 +197,75 @@ static int pcf85063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return 0;
}
/*
* The chip has no dedicated 1 Hz update interrupt. Drive the countdown timer
* at 1 Hz to emulate it, so the RTC core can offload UIE to the hardware
* instead of polling. A free-running timer is left untouched to preserve its
* phase across the per-second re-arming done by the core.
*/
static int pcf85063_set_timer_1hz(struct pcf85063 *pcf85063, bool enable)
{
unsigned int mask = PCF85063_TIMER_MODE_TCF_MASK |
PCF85063_TIMER_MODE_TIE |
PCF85063_TIMER_MODE_TI_TP |
PCF85063_TIMER_MODE_TE;
unsigned int mode = 0;
unsigned int cur;
int ret;
if (enable)
mode = PCF85063_TIMER_MODE_TCF_1HZ | PCF85063_TIMER_MODE_TIE |
PCF85063_TIMER_MODE_TI_TP | PCF85063_TIMER_MODE_TE;
ret = regmap_read(pcf85063->regmap, PCF85063_REG_TIMER_MODE, &cur);
if (ret)
return ret;
if ((cur & mask) == mode)
return 0;
/* Stop the counter before changing its reload value. */
ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_TIMER_MODE,
PCF85063_TIMER_MODE_TE, 0);
if (ret)
return ret;
if (enable) {
ret = regmap_write(pcf85063->regmap, PCF85063_REG_TIMER_VALUE, 1);
if (ret)
return ret;
/* Clear TF but preserve AF */
ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
PCF85063_CTRL2_TF | PCF85063_CTRL2_AF, PCF85063_CTRL2_AF);
if (ret)
return ret;
}
return regmap_update_bits(pcf85063->regmap, PCF85063_REG_TIMER_MODE,
mask, mode);
}
static int pcf85063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
u8 buf[5];
int ret;
ret = pcf85063_set_timer_1hz(pcf85063, pcf85063->rtc->uie_rtctimer.enabled);
if (ret)
return ret;
buf[0] = bin2bcd(alrm->time.tm_sec);
buf[1] = bin2bcd(alrm->time.tm_min);
buf[2] = bin2bcd(alrm->time.tm_hour);
buf[3] = bin2bcd(alrm->time.tm_mday);
buf[4] = PCF85063_AEN; /* Do not match on week day */
/* Preserve TF */
ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF, 0);
PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
PCF85063_CTRL2_TF);
if (ret)
return ret;
@ -211,23 +275,33 @@ static int pcf85063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return ret;
return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
alrm->enabled ? PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF : PCF85063_CTRL2_AF);
PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
pcf85063->rtc->aie_timer.enabled ?
PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF :
PCF85063_CTRL2_AF | PCF85063_CTRL2_TF);
}
static int pcf85063_rtc_alarm_irq_enable(struct device *dev,
unsigned int enabled)
{
struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
int ret;
ret = pcf85063_set_timer_1hz(pcf85063, pcf85063->rtc->uie_rtctimer.enabled);
if (ret)
return ret;
return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
PCF85063_CTRL2_AIE,
enabled ? PCF85063_CTRL2_AIE : 0);
PCF85063_CTRL2_AIE | PCF85063_CTRL2_TF,
pcf85063->rtc->aie_timer.enabled ?
PCF85063_CTRL2_AIE | PCF85063_CTRL2_TF : PCF85063_CTRL2_TF);
}
static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id)
{
struct pcf85063 *pcf85063 = dev_id;
unsigned long events = RTC_IRQF;
irqreturn_t ret = IRQ_NONE;
unsigned int val;
int err;
@ -236,14 +310,33 @@ static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id)
return IRQ_NONE;
if (val & PCF85063_CTRL2_AF) {
rtc_update_irq(pcf85063->rtc, 1, RTC_IRQF | RTC_AF);
regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
0);
return IRQ_HANDLED;
events |= RTC_AF;
val &= ~PCF85063_CTRL2_AF;
ret = IRQ_HANDLED;
} else {
/* Preserve AF if it comes after the above regmap_read() */
val |= PCF85063_CTRL2_AF;
}
return IRQ_NONE;
if (val & PCF85063_CTRL2_TF) {
events |= RTC_UF;
val &= ~PCF85063_CTRL2_TF;
ret = IRQ_HANDLED;
} else {
/*
* While not documented, TF demonstrates the same
* write-1-to-preserve semantics as AF in real HW
*/
val |= PCF85063_CTRL2_TF;
}
if (ret == IRQ_HANDLED) {
regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
PCF85063_CTRL2_AF | PCF85063_CTRL2_TF, val);
rtc_update_irq(pcf85063->rtc, 1, events);
}
return ret;
}
static int pcf85063_read_offset(struct device *dev, long *offset)
@ -432,7 +525,8 @@ static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] == rate)
return regmap_update_bits(pcf85063->regmap,
PCF85063_REG_CTRL2,
PCF85063_REG_CLKO_F_MASK, i);
PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
i | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF);
return -EINVAL;
}
@ -461,7 +555,8 @@ static int pcf85063_clkout_control(struct clk_hw *hw, bool enable)
}
return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
PCF85063_REG_CLKO_F_MASK, buf);
PCF85063_REG_CLKO_F_MASK | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF,
buf | PCF85063_CTRL2_AF | PCF85063_CTRL2_TF);
}
static int pcf85063_clkout_prepare(struct clk_hw *hw)
@ -495,12 +590,13 @@ static const struct clk_ops pcf85063_clkout_ops = {
.set_rate = pcf85063_clkout_set_rate,
};
static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
static int pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
{
struct clk *clk;
struct device *dev = pcf85063->rtc->dev.parent;
struct clk_init_data init = {};
struct device_node *node = pcf85063->rtc->dev.parent->of_node;
struct device_node *node = dev->of_node;
struct device_node *fixed_clock;
int ret;
fixed_clock = of_get_child_by_name(node, "clock");
if (fixed_clock) {
@ -510,7 +606,7 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
* registered automatically when being referenced.
*/
of_node_put(fixed_clock);
return NULL;
return 0;
}
init.name = "pcf85063-clkout";
@ -524,12 +620,12 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
of_property_read_string(node, "clock-output-names", &init.name);
/* register the clock */
clk = devm_clk_register(&pcf85063->rtc->dev, &pcf85063->clkout_hw);
ret = devm_clk_hw_register(dev, &pcf85063->clkout_hw);
if (ret)
return ret;
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
return clk;
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
&pcf85063->clkout_hw);
}
#endif
@ -607,6 +703,7 @@ static int pcf85063_probe(struct device *dev, struct regmap *regmap, int irq,
dev_warn(&pcf85063->rtc->dev,
"unable to request IRQ, alarms disabled\n");
} else {
set_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features);
set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
device_init_wakeup(dev, true);
err = dev_pm_set_wake_irq(dev, irq);

View File

@ -479,7 +479,8 @@ static int pcf8563_probe(struct i2c_client *client)
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -ENODEV;
pcf8563 = devm_kzalloc(&client->dev, sizeof(struct pcf8563),
@ -531,7 +532,7 @@ static int pcf8563_probe(struct i2c_client *client)
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8563_irq,
IRQF_SHARED | IRQF_ONESHOT | irqflags,
pcf8563_driver.driver.name, client);
pcf8563_driver.driver.name, pcf8563);
if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n",
client->irq);

View File

@ -0,0 +1,278 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/**
* rtc-raspberrypi.c
*
* RTC driver using firmware mailbox
* Supports battery backed RTC and wake alarms
*
* Based on rtc-meson-vrtc by Neil Armstrong
*
* Copyright (c) 2023, Raspberry Pi Ltd.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/of.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
#define RTC_TIME 0
#define RTC_ALARM 1
#define RTC_ALARM_PENDING 2
#define RTC_ALARM_ENABLE 3
#define RTC_BBAT_CHG_VOLTS 4
#define RTC_BBAT_CHG_VOLTS_MIN 5
#define RTC_BBAT_CHG_VOLTS_MAX 6
#define RTC_BBAT_VOLTS 7
struct rpi_rtc_data {
struct rtc_device *rtc;
struct rpi_firmware *fw;
u32 bbat_vchg_millivolts;
u32 bbat_vchg_min_millivolts;
u32 bbat_vchg_max_millivolts;
};
struct rpi_rtc_reg {
__le32 reg;
__le32 val;
} __packed;
static int rpi_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_TIME)
};
int err;
err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
&data, sizeof(data));
rtc_time64_to_tm(le32_to_cpu(data.val), tm);
return err;
}
static int rpi_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_TIME),
.val = cpu_to_le32(rtc_tm_to_time64(tm))
};
return rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
&data, sizeof(data));
}
static int rpi_rtc_alarm_irq_is_enabled(struct device *dev, unsigned char *enabled)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_ALARM_ENABLE)
};
int err;
err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
&data, sizeof(data));
*enabled = le32_to_cpu(data.val) & 0x1;
return err;
}
static int rpi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_ALARM_ENABLE),
.val = cpu_to_le32(enabled)
};
return rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
&data, sizeof(data));
}
static int rpi_rtc_alarm_clear_pending(struct device *dev)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_ALARM_PENDING),
.val = cpu_to_le32(1)
};
return rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
&data, sizeof(data));
}
static int rpi_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_ALARM)
};
int err;
err = rpi_rtc_alarm_irq_is_enabled(dev, &alarm->enabled);
if (!err)
err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
&data, sizeof(data));
rtc_time64_to_tm(le32_to_cpu(data.val), &alarm->time);
return err;
}
static int rpi_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_ALARM),
.val = cpu_to_le32(rtc_tm_to_time64(&alarm->time))
};
int err;
err = rpi_rtc_alarm_clear_pending(dev);
if (!err)
err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
&data, sizeof(data));
if (!err)
err = rpi_rtc_alarm_irq_enable(dev, alarm->enabled);
return err;
}
static const struct rtc_class_ops rpi_rtc_ops = {
.read_time = rpi_rtc_read_time,
.set_time = rpi_rtc_set_time,
.read_alarm = rpi_rtc_read_alarm,
.set_alarm = rpi_rtc_set_alarm,
.alarm_irq_enable = rpi_rtc_alarm_irq_enable,
};
static void rpi_rtc_set_limits(struct device *dev)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS_MIN)
};
int err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
&data, sizeof(data));
if (!err)
rtc->bbat_vchg_min_millivolts = le32_to_cpu(data.val) / 1000U;
else
dev_warn(dev, "failed to get minimum trickle charge voltage\n");
data.reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS_MAX);
data.val = cpu_to_le32(0);
err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_GET_RTC_REG,
&data, sizeof(data));
if (!err)
rtc->bbat_vchg_max_millivolts = le32_to_cpu(data.val) / 1000U;
else
dev_warn(dev, "failed to get maximum trickle charge voltage\n");
}
static void rpi_rtc_set_charge_voltage(struct device *dev)
{
struct rpi_rtc_data *rtc = dev_get_drvdata(dev);
struct rpi_rtc_reg data = {
.reg = cpu_to_le32(RTC_BBAT_CHG_VOLTS),
.val = cpu_to_le32(rtc->bbat_vchg_millivolts * 1000U)
};
int err;
if (rtc->bbat_vchg_millivolts != 0 &&
(rtc->bbat_vchg_millivolts < rtc->bbat_vchg_min_millivolts ||
rtc->bbat_vchg_millivolts > rtc->bbat_vchg_max_millivolts)) {
dev_warn(dev, "trickle charge voltage %umV is outside of the supported range (%umV - %umV)\n",
rtc->bbat_vchg_millivolts,
rtc->bbat_vchg_min_millivolts,
rtc->bbat_vchg_max_millivolts);
return;
}
err = rpi_firmware_property(rtc->fw, RPI_FIRMWARE_SET_RTC_REG,
&data, sizeof(data));
if (err)
dev_err(dev, "failed to set trickle charge voltage to %umV: %d\n",
rtc->bbat_vchg_millivolts, err);
else if (rtc->bbat_vchg_millivolts)
dev_info(dev, "trickle charging enabled at %umV\n",
rtc->bbat_vchg_millivolts);
}
static int rpi_rtc_probe(struct platform_device *pdev)
{
struct rpi_rtc_data *rtc;
struct device *dev = &pdev->dev;
struct rpi_firmware *firmware;
int ret;
// Get the firmware device from the parent device
firmware = devm_rpi_firmware_get(dev, dev->parent->of_node);
if (!firmware)
return -EPROBE_DEFER;
rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->fw = firmware;
ret = devm_device_init_wakeup(dev);
if (ret)
return ret;
platform_set_drvdata(pdev, rtc);
rtc->rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc->rtc))
return PTR_ERR(rtc->rtc);
rtc->rtc->range_max = U32_MAX; /* 2106-02-07 */
set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->rtc->features);
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc->features);
rtc->rtc->ops = &rpi_rtc_ops;
rpi_rtc_alarm_clear_pending(dev);
/*
* The trickle-voltage property lives on the parent firmware node
* because we deliberately do not create a DT child node just to
* instantiate this driver (see DT maintainer guidance).
* The firmware driver registers us as a platform device at runtime.
*/
rtc->bbat_vchg_millivolts = 0;
of_property_read_u32(dev->parent->of_node, "trickle-voltage-millivolt",
&rtc->bbat_vchg_millivolts);
rpi_rtc_set_limits(dev);
rpi_rtc_set_charge_voltage(dev);
return devm_rtc_register_device(rtc->rtc);
}
static const struct platform_device_id raspberrypi_rtc_id[] = {
{ "raspberrypi-rtc" },
{ }
};
MODULE_DEVICE_TABLE(platform, raspberrypi_rtc_id);
static struct platform_driver rpi_rtc_driver = {
.driver = {
.name = "raspberrypi-rtc",
},
.id_table = raspberrypi_rtc_id,
.probe = rpi_rtc_probe
};
module_platform_driver(rpi_rtc_driver);
MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.com>");
MODULE_AUTHOR("Sander Speetjens <sander.speetjens@gmail.com>");
MODULE_DESCRIPTION("Raspberry Pi RTC driver");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -52,6 +52,7 @@
#define RS5C_REG_CTRL2 15
# define RS5C372_CTRL2_24 (1 << 5)
# define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2x2x */
# define R2223x_CTRL2_ECO (1 << 7) /* only if R2223x */
# define R2x2x_CTRL2_VDET (1 << 6) /* only if R2x2x */
# define R2x2x_CTRL2_XSTP (1 << 5) /* only if R2x2x */
# define R2x2x_CTRL2_PON (1 << 4) /* only if R2x2x */
@ -68,6 +69,7 @@ enum rtc_type {
rtc_undef = 0,
rtc_r2025sd,
rtc_r2221tl,
rtc_r2223x,
rtc_rs5c372a,
rtc_rs5c372b,
rtc_rv5c386,
@ -77,6 +79,7 @@ enum rtc_type {
static const struct i2c_device_id rs5c372_id[] = {
{ .name = "r2025sd", .driver_data = rtc_r2025sd },
{ .name = "r2221tl", .driver_data = rtc_r2221tl },
{ .name = "r2223x", .driver_data = rtc_r2223x },
{ .name = "rs5c372a", .driver_data = rtc_rs5c372a },
{ .name = "rs5c372b", .driver_data = rtc_rs5c372b },
{ .name = "rv5c386", .driver_data = rtc_rv5c386 },
@ -94,6 +97,10 @@ static const __maybe_unused struct of_device_id rs5c372_of_match[] = {
.compatible = "ricoh,r2221tl",
.data = (void *)rtc_r2221tl
},
{
.compatible = "ricoh,r2223x",
.data = (void *)rtc_r2223x
},
{
.compatible = "ricoh,rs5c372a",
.data = (void *)rtc_rs5c372a
@ -221,8 +228,10 @@ static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
case rtc_r2223x:
if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
(rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) {
((rs5c->type == rtc_r2221tl || rs5c->type == rtc_r2223x) &&
(ctrl2 & R2x2x_CTRL2_XSTP))) {
dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
return -EINVAL;
}
@ -292,6 +301,7 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
case rtc_r2223x:
ctrl2 &= ~(R2x2x_CTRL2_VDET | R2x2x_CTRL2_PON);
if (rs5c->type == rtc_r2025sd)
ctrl2 |= R2x2x_CTRL2_XSTP;
@ -511,8 +521,10 @@ static int rs5c372_ioctl(struct device *dev, unsigned int cmd, unsigned long arg
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
case rtc_r2223x:
if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
(rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) {
((rs5c->type == rtc_r2221tl || rs5c->type == rtc_r2223x) &&
(ctrl2 & R2x2x_CTRL2_XSTP))) {
flags |= RTC_VL_DATA_INVALID;
}
if (ctrl2 & R2x2x_CTRL2_VDET)
@ -527,7 +539,8 @@ static int rs5c372_ioctl(struct device *dev, unsigned int cmd, unsigned long arg
return put_user(flags, (unsigned int __user *)arg);
case RTC_VL_CLR:
/* clear VDET bit */
if (rs5c->type == rtc_r2025sd || rs5c->type == rtc_r2221tl) {
if (rs5c->type == rtc_r2025sd || rs5c->type == rtc_r2221tl ||
rs5c->type == rtc_r2223x) {
ctrl2 &= ~R2x2x_CTRL2_VDET;
if (i2c_smbus_write_byte_data(rs5c->client, addr, ctrl2) < 0) {
dev_dbg(&rs5c->client->dev, "%s: write error in line %i\n",
@ -554,6 +567,7 @@ static int rs5c372_read_offset(struct device *dev, long *offset)
switch (rs5c->type) {
case rtc_r2221tl:
case rtc_r2223x:
ppb_per_step = val & R2221TL_TRIM_DEV ? 1017 : 3051;
break;
case rtc_rs5c372a:
@ -600,6 +614,7 @@ static int rs5c372_set_offset(struct device *dev, long offset)
}
break;
case rtc_r2221tl:
case rtc_r2223x:
/*
* Check if it is possible to use high resolution mode (DEV=1).
* In this mode, the minimum resolution is 2 / (32768 * 20 * 3),
@ -684,7 +699,7 @@ static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
if (err)
return err;
return sprintf(buf, "%d\n", trim);
return sysfs_emit(buf, "%d\n", trim);
}
static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL);
@ -697,7 +712,7 @@ static ssize_t rs5c372_sysfs_show_osc(struct device *dev,
if (err)
return err;
return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000);
return sysfs_emit(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000);
}
static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL);
@ -750,6 +765,7 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
return ret;
break;
case rtc_r2221tl:
case rtc_r2223x:
if (!(buf[1] & R2x2x_CTRL2_XSTP))
return ret;
break;
@ -768,6 +784,7 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
break;
case rtc_r2025sd:
case rtc_r2221tl:
case rtc_r2223x:
case rtc_rv5c386:
case rtc_rv5c387a:
buf[0] |= RV5C387_CTRL1_24;
@ -791,6 +808,24 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
return 0;
}
static int rs5c372_set_eco_mode(struct rs5c372 *rs5c372, bool eco)
{
struct i2c_client *client = rs5c372->client;
int ctrl2;
ctrl2 = i2c_smbus_read_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2));
if (ctrl2 < 0)
return ctrl2;
if (eco)
ctrl2 |= R2223x_CTRL2_ECO;
else
ctrl2 &= ~R2223x_CTRL2_ECO;
return i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C_REG_CTRL2),
ctrl2);
}
static int rs5c372_probe(struct i2c_client *client)
{
int err = 0;
@ -847,6 +882,7 @@ static int rs5c372_probe(struct i2c_client *client)
break;
case rtc_r2025sd:
case rtc_r2221tl:
case rtc_r2223x:
case rtc_rv5c386:
case rtc_rv5c387a:
if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
@ -876,6 +912,7 @@ static int rs5c372_probe(struct i2c_client *client)
({ char *s; switch (rs5c372->type) {
case rtc_r2025sd: s = "r2025sd"; break;
case rtc_r2221tl: s = "r2221tl"; break;
case rtc_r2223x: s = "r2223x"; break;
case rtc_rs5c372a: s = "rs5c372a"; break;
case rtc_rs5c372b: s = "rs5c372b"; break;
case rtc_rv5c386: s = "rv5c386"; break;
@ -885,6 +922,15 @@ static int rs5c372_probe(struct i2c_client *client)
rs5c372->time24 ? "24hr" : "am/pm"
);
if (rs5c372->type == rtc_r2223x) {
bool eco = device_property_read_bool(&client->dev,
"ricoh,eco-mode");
err = rs5c372_set_eco_mode(rs5c372, eco);
if (err < 0)
goto exit;
}
/* REVISIT use client->irq to register alarm irq ... */
rs5c372->rtc = devm_rtc_device_register(&client->dev,
rs5c372_driver.driver.name,

View File

@ -147,8 +147,8 @@ static ssize_t timestamp0_show(struct device *dev,
if (ret)
return ret;
return sprintf(buf, "%llu\n",
(unsigned long long)rtc_tm_to_time64(&tm));
return sysfs_emit(buf, "%llu\n",
(unsigned long long)rtc_tm_to_time64(&tm));
};
static DEVICE_ATTR_RW(timestamp0);
@ -164,7 +164,7 @@ static ssize_t timestamp0_count_show(struct device *dev,
if (ret)
return ret;
return sprintf(buf, "%u\n", count);
return sysfs_emit(buf, "%u\n", count);
};
static DEVICE_ATTR_RO(timestamp0_count);

View File

@ -270,19 +270,17 @@ static irqreturn_t rv3029_handle_irq(int irq, void *dev_id)
unsigned long events = 0;
int ret;
rtc_lock(rv3029->rtc);
guard(rtc_ops)(rv3029->rtc);
ret = regmap_read(rv3029->regmap, RV3029_IRQ_CTRL, &controls);
if (ret) {
dev_warn(dev, "Read IRQ Control Register error %d\n", ret);
rtc_unlock(rv3029->rtc);
return IRQ_NONE;
}
ret = regmap_read(rv3029->regmap, RV3029_IRQ_FLAGS, &flags);
if (ret) {
dev_warn(dev, "Read IRQ Flags Register error %d\n", ret);
rtc_unlock(rv3029->rtc);
return IRQ_NONE;
}
@ -297,7 +295,6 @@ static irqreturn_t rv3029_handle_irq(int irq, void *dev_id)
regmap_write(rv3029->regmap, RV3029_IRQ_FLAGS, flags);
regmap_write(rv3029->regmap, RV3029_IRQ_CTRL, controls);
}
rtc_unlock(rv3029->rtc);
return IRQ_HANDLED;
}
@ -604,7 +601,7 @@ static ssize_t rv3029_hwmon_show_temp(struct device *dev,
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", temp_mC);
return sysfs_emit(buf, "%d\n", temp_mC);
}
static ssize_t rv3029_hwmon_set_update_interval(struct device *dev,
@ -657,7 +654,7 @@ static ssize_t rv3029_hwmon_show_update_interval(struct device *dev,
interval_ms = 0;
}
return sprintf(buf, "%d\n", interval_ms);
return sysfs_emit(buf, "%d\n", interval_ms);
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, rv3029_hwmon_show_temp,

View File

@ -73,11 +73,10 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
struct rx8010_data *rx8010 = i2c_get_clientdata(client);
int flagreg, err;
rtc_lock(rx8010->rtc);
guard(rtc_ops)(rx8010->rtc);
err = regmap_read(rx8010->regs, RX8010_FLAG, &flagreg);
if (err) {
rtc_unlock(rx8010->rtc);
return IRQ_NONE;
}
@ -100,7 +99,6 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
}
err = regmap_write(rx8010->regs, RX8010_FLAG, flagreg);
rtc_unlock(rx8010->rtc);
return err ? IRQ_NONE : IRQ_HANDLED;
}

View File

@ -180,10 +180,11 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
struct rx8025_data *rx8025 = i2c_get_clientdata(client);
int status, xstp;
rtc_lock(rx8025->rtc);
guard(rtc_ops)(rx8025->rtc);
status = rx8025_read_reg(client, RX8025_REG_CTRL2);
if (status < 0)
goto out;
return IRQ_HANDLED;
xstp = rx8025_is_osc_stopped(rx8025->model, status);
if (xstp)
@ -201,13 +202,10 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
status &= RX8025_BIT_CTRL2_DAFG;
if (rx8025_write_reg(client, RX8025_REG_CTRL1,
rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE))
goto out;
return IRQ_HANDLED;
rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF);
}
out:
rtc_unlock(rx8025->rtc);
return IRQ_HANDLED;
}
@ -488,7 +486,7 @@ static ssize_t rx8025_sysfs_show_clock_adjust(struct device *dev,
if (err)
return err;
return sprintf(buf, "%ld\n", -adj);
return sysfs_emit(buf, "%ld\n", -adj);
}
static ssize_t rx8025_sysfs_store_clock_adjust(struct device *dev,

View File

@ -68,6 +68,7 @@
struct rzn1_rtc_data {
bool has_subu;
bool broken_irqs;
};
struct rzn1_rtc {
@ -396,6 +397,11 @@ static const struct rtc_class_ops rzn1_rtc_ops_scmp = {
.alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
};
static const struct rtc_class_ops rzn1_rtc_ops_scmp_no_alarm = {
.read_time = rzn1_rtc_read_time,
.set_time = rzn1_rtc_set_time,
};
static void rzn1_rtc_disable_hardware(void *data)
{
struct device *dev = data;
@ -431,10 +437,6 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
if (IS_ERR(rtc->base))
return dev_err_probe(dev, PTR_ERR(rtc->base), "Missing reg\n");
irq = platform_get_irq_byname(pdev, "alarm");
if (irq < 0)
return irq;
rtc->rtcdev = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc->rtcdev))
return PTR_ERR(rtc->rtcdev);
@ -503,25 +505,40 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
spin_lock_init(&rtc->ctl1_access_lock);
ret = devm_request_irq(dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc);
if (ret)
return dev_err_probe(dev, ret, "RTC alarm interrupt not available\n");
irq = platform_get_irq_byname_optional(pdev, "pps");
if (irq == -EPROBE_DEFER)
return irq;
if (irq >= 0)
ret = devm_request_irq(dev, irq, rzn1_rtc_1s_irq, 0, "RZN1 RTC 1s", rtc);
if (irq < 0 || ret) {
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
if (data->broken_irqs) {
/* All known broken irqs are on SCMP only variants */
rtc->rtcdev->ops = &rzn1_rtc_ops_scmp_no_alarm;
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
dev_warn(dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n");
} else {
irq = platform_get_irq_byname(pdev, "alarm");
if (irq < 0)
return irq;
ret = devm_request_irq(dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc);
if (ret)
return dev_err_probe(dev, ret, "RTC alarm interrupt not available\n");
irq = platform_get_irq_byname_optional(pdev, "pps");
if (irq == -EPROBE_DEFER)
return irq;
if (irq >= 0)
ret = devm_request_irq(dev, irq, rzn1_rtc_1s_irq, 0, "RZN1 RTC 1s", rtc);
if (irq < 0 || ret) {
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
dev_warn(dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n");
}
}
return devm_rtc_register_device(rtc->rtcdev);
}
static const struct rzn1_rtc_data rzn1_rtc_r8a78000_data = {
.has_subu = false,
.broken_irqs = true,
};
static const struct rzn1_rtc_data rzn1_rtc_rzt2h_data = {
.has_subu = false,
};
@ -531,6 +548,7 @@ static const struct rzn1_rtc_data rzn1_rtc_rzn1_data = {
};
static const struct of_device_id rzn1_rtc_of_match[] = {
{ .compatible = "renesas,r8a78000-rtc", .data = &rzn1_rtc_r8a78000_data },
{ .compatible = "renesas,r9a09g077-rtc", .data = &rzn1_rtc_rzt2h_data },
{ .compatible = "renesas,rzn1-rtc", .data = &rzn1_rtc_rzn1_data },
{ /* sentinel */ }

View File

@ -5,6 +5,7 @@
* Copyright (c) 2007 Byron Bradley
*/
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/i2c.h>
@ -12,11 +13,17 @@
#include <linux/bcd.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf-generic.h>
#define DRIVER_NAME "rtc-s35390a"
#define S35390A_CMD_STATUS1 0
#define S35390A_CMD_STATUS2 1
#define S35390A_CMD_TIME1 2
#define S35390A_CMD_TIME2 3
#define S35390A_CMD_INT1_REG1 4
#define S35390A_CMD_INT2_REG1 5
#define S35390A_CMD_FREE_REG 7
@ -36,19 +43,38 @@
#define S35390A_FLAG_POC BIT(0)
#define S35390A_FLAG_BLD BIT(1)
#define S35390A_FLAG_INT2 BIT(2)
#define S35390A_FLAG_INT1 BIT(3)
#define S35390A_FLAG_24H BIT(6)
#define S35390A_FLAG_RESET BIT(7)
/* flag for STATUS2 */
#define S35390A_FLAG_TEST BIT(0)
#define S35390A_INT_MODE_NOINTR 0x00
/* INT2 pin output mode */
#define S35390A_INT2_MODE_MASK 0x0E
#define S35390A_INT2_MODE_NOINTR 0x00
#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 */
#define S35390A_INT2_MODE_PMIN1 (BIT(3) | BIT(2)) /* INT2FE | INT2ME */
/* INT1 pin output mode */
#define S35390A_INT1_MODE_MASK 0xF0
#define S35390A_INT1_MODE_ALARM BIT(5) /* INT1AE */
#define S35390A_INT1_MODE_PMIN_EDG BIT(6) /* INT1ME */
#define S35390A_INT1_MODE_FREQ BIT(7) /* INT1FE */
#define S35390A_INT1_MODE_PMIN1 (BIT(7) | BIT(6)) /* INT1FE | INT1ME */
#define S35390A_INT1_MODE_PMIN2 (BIT(7) | BIT(6) | BIT(5)) /* INT1FE | INT1ME | INT1AE */
#define S35390A_INT1_MODE_32768KHZ BIT(4) /* 32kE */
#define S35390A_FUNC_IGNORE 0x00
#define S35390A_FUNC_DISABLE 0x01
#define S35390A_FUNC_WAKEUP 0x02
#define S35390A_FUNC_CLOCK 0x03
#define S35390A_FUNC_PMIN1 0x04
#define S35390A_FUNC_PMIN2 0x05
static const struct i2c_device_id s35390a_id[] = {
{ .name = "s35390a" },
@ -64,7 +90,10 @@ MODULE_DEVICE_TABLE(of, s35390a_of_match);
struct s35390a {
struct i2c_client *client[8];
int twentyfourhour;
struct rtc_device *rtc;
struct mutex pinfunction_lock; /* lock preventing concurrent access of pin function */
int pinfunction[2];
};
static int s35390a_set_reg(struct s35390a *s35390a, int reg, u8 *buf, int len)
@ -102,9 +131,8 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, u8 *buf, int len)
return 0;
}
static int s35390a_init(struct s35390a *s35390a)
static int s35390a_init(struct s35390a *s35390a, u8 *sts)
{
u8 buf;
int ret;
unsigned initcount = 0;
@ -117,17 +145,17 @@ static int s35390a_init(struct s35390a *s35390a)
* The 24H bit is kept over reset, so set it already here.
*/
initialize:
buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
*sts = S35390A_FLAG_RESET | S35390A_FLAG_24H;
ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, sts, 1);
if (ret < 0)
return ret;
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, sts, 1);
if (ret < 0)
return ret;
if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
if (*sts & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
/* Try up to five times to reset the chip */
if (initcount < 5) {
++initcount;
@ -167,23 +195,9 @@ static int s35390a_read_status(struct s35390a *s35390a, char *status1)
return 0;
}
static int s35390a_disable_test_mode(struct s35390a *s35390a)
static char s35390a_hr2reg(int hour, bool twentyfourhour)
{
u8 buf[1];
if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0)
return -EIO;
if (!(buf[0] & S35390A_FLAG_TEST))
return 0;
buf[0] &= ~S35390A_FLAG_TEST;
return s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf));
}
static char s35390a_hr2reg(struct s35390a *s35390a, int hour)
{
if (s35390a->twentyfourhour)
if (twentyfourhour)
return bin2bcd(hour);
if (hour < 12)
@ -192,11 +206,11 @@ static char s35390a_hr2reg(struct s35390a *s35390a, int hour)
return 0x40 | bin2bcd(hour - 12);
}
static int s35390a_reg2hr(struct s35390a *s35390a, char reg)
static int s35390a_reg2hr(char reg, bool twentyfourhour)
{
unsigned hour;
if (s35390a->twentyfourhour)
if (twentyfourhour)
return bcd2bin(reg & 0x3f);
hour = bcd2bin(reg & 0x3f);
@ -210,7 +224,7 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
int i;
int i, err;
u8 buf[7], status;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, "
@ -218,14 +232,18 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm)
tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year,
tm->tm_wday);
if (s35390a_read_status(s35390a, &status) == 1)
s35390a_init(s35390a);
err = s35390a_read_status(s35390a, &status);
if (err == 1)
err = s35390a_init(s35390a, &status);
if (err < 0)
return err;
buf[S35390A_BYTE_YEAR] = bin2bcd(tm->tm_year - 100);
buf[S35390A_BYTE_MONTH] = bin2bcd(tm->tm_mon + 1);
buf[S35390A_BYTE_DAY] = bin2bcd(tm->tm_mday);
buf[S35390A_BYTE_WDAY] = bin2bcd(tm->tm_wday);
buf[S35390A_BYTE_HOURS] = s35390a_hr2reg(s35390a, tm->tm_hour);
buf[S35390A_BYTE_HOURS] = s35390a_hr2reg(tm->tm_hour, status & S35390A_FLAG_24H);
buf[S35390A_BYTE_MINS] = bin2bcd(tm->tm_min);
buf[S35390A_BYTE_SECS] = bin2bcd(tm->tm_sec);
@ -243,8 +261,11 @@ static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
u8 buf[7], status;
int i, err;
if (s35390a_read_status(s35390a, &status) == 1)
err = s35390a_read_status(s35390a, &status);
if (err == 1)
return -EINVAL;
if (err < 0)
return err;
err = s35390a_get_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf));
if (err < 0)
@ -256,7 +277,7 @@ static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_sec = bcd2bin(buf[S35390A_BYTE_SECS]);
tm->tm_min = bcd2bin(buf[S35390A_BYTE_MINS]);
tm->tm_hour = s35390a_reg2hr(s35390a, buf[S35390A_BYTE_HOURS]);
tm->tm_hour = s35390a_reg2hr(buf[S35390A_BYTE_HOURS], status & S35390A_FLAG_24H);
tm->tm_wday = bcd2bin(buf[S35390A_BYTE_WDAY]);
tm->tm_mday = bcd2bin(buf[S35390A_BYTE_DAY]);
tm->tm_mon = bcd2bin(buf[S35390A_BYTE_MONTH]) - 1;
@ -270,11 +291,44 @@ static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
return 0;
}
static int s35390a_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct s35390a *s35390a = dev_get_drvdata(dev);
u8 sts;
int err;
guard(mutex)(&s35390a->pinfunction_lock);
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
return err;
if (enabled) {
if (s35390a->pinfunction[0] == S35390A_FUNC_WAKEUP)
sts = (sts & ~S35390A_INT1_MODE_MASK) | S35390A_INT1_MODE_ALARM;
if (s35390a->pinfunction[1] == S35390A_FUNC_WAKEUP)
sts = (sts & ~S35390A_INT2_MODE_MASK) | S35390A_INT2_MODE_ALARM;
} else {
if (s35390a->pinfunction[0] == S35390A_FUNC_WAKEUP)
sts = (sts & ~S35390A_INT1_MODE_MASK) | S35390A_INT_MODE_NOINTR;
if (s35390a->pinfunction[1] == S35390A_FUNC_WAKEUP)
sts = (sts & ~S35390A_INT2_MODE_MASK) | S35390A_INT_MODE_NOINTR;
}
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
return err;
return 0;
}
static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
u8 buf[3], sts = 0;
u8 buf[3], status1, status2 = 0;
int err, i;
dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\
@ -282,23 +336,25 @@ 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);
guard(mutex)(&s35390a->pinfunction_lock);
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &status2, sizeof(status2));
if (err < 0)
return err;
/* disable interrupt (which deasserts the irq line) */
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (s35390a->pinfunction[0] == S35390A_FUNC_WAKEUP)
status2 = (status2 & ~S35390A_INT1_MODE_MASK) | S35390A_INT_MODE_NOINTR;
if (s35390a->pinfunction[1] == S35390A_FUNC_WAKEUP)
status2 = (status2 & ~S35390A_INT2_MODE_MASK) | S35390A_INT_MODE_NOINTR;
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &status2, sizeof(status2));
if (err < 0)
return err;
/* clear pending interrupt (in STATUS1 only), if any */
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts));
if (err < 0)
return err;
if (alm->enabled)
sts = S35390A_INT2_MODE_ALARM;
else
sts = S35390A_INT2_MODE_NOINTR;
/* set interrupt mode*/
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &status1, sizeof(status1));
if (err < 0)
return err;
@ -307,8 +363,8 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
else
buf[S35390A_ALRM_BYTE_WDAY] = 0;
buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
alm->time.tm_hour) | 0x80;
buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(alm->time.tm_hour,
status1 & S35390A_FLAG_24H) | 0x80;
buf[S35390A_ALRM_BYTE_MINS] = bin2bcd(alm->time.tm_min) | 0x80;
if (alm->time.tm_hour >= 12)
@ -317,35 +373,71 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
for (i = 0; i < 3; ++i)
buf[i] = bitrev8(buf[i]);
err = s35390a_set_reg(s35390a, S35390A_CMD_INT2_REG1, buf,
sizeof(buf));
if (alm->enabled) {
/* set interrupt mode */
if (s35390a->pinfunction[0] == S35390A_FUNC_WAKEUP)
status2 = (status2 & ~S35390A_INT1_MODE_MASK) | S35390A_INT1_MODE_ALARM;
return err;
if (s35390a->pinfunction[1] == S35390A_FUNC_WAKEUP)
status2 = (status2 & ~S35390A_INT2_MODE_MASK) | S35390A_INT2_MODE_ALARM;
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &status2, sizeof(status2));
if (err < 0)
return err;
}
if (s35390a->pinfunction[0] == S35390A_FUNC_WAKEUP) {
err = s35390a_set_reg(s35390a, S35390A_CMD_INT1_REG1, buf, sizeof(buf));
if (err < 0)
return err;
}
if (s35390a->pinfunction[1] == S35390A_FUNC_WAKEUP) {
err = s35390a_set_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
if (err < 0)
return err;
}
return 0;
}
static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
u8 buf[3], sts;
int i, err;
u8 buf[3], status1, status2;
int i, err, reg;
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
guard(mutex)(&s35390a->pinfunction_lock);
err = s35390a_read_status(s35390a, &status1);
if (err == 1)
return -EINVAL;
if (err < 0)
return err;
if ((sts & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &status2, sizeof(status2));
if (err < 0)
return err;
if (s35390a->pinfunction[1] == S35390A_FUNC_WAKEUP &&
(status2 & S35390A_INT2_MODE_MASK) == S35390A_INT2_MODE_ALARM) {
reg = S35390A_CMD_INT2_REG1;
} else if (s35390a->pinfunction[0] == S35390A_FUNC_WAKEUP &&
(status2 & S35390A_INT1_MODE_MASK) == S35390A_INT1_MODE_ALARM) {
reg = S35390A_CMD_INT1_REG1;
} else {
/*
* When the alarm isn't enabled, the register to configure
* the alarm time isn't accessible.
*/
alm->enabled = 0;
return 0;
} else {
alm->enabled = 1;
}
err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
alm->enabled = 1;
err = s35390a_get_reg(s35390a, reg, buf, sizeof(buf));
if (err < 0)
return err;
@ -354,7 +446,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
buf[i] = bitrev8(buf[i]);
/*
* B0 of the three matching registers is an enable flag. Iff it is set
* B0 of the three matching registers is an enable flag. If it is set
* the configured value is used for matching.
*/
if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
@ -363,8 +455,8 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
alm->time.tm_hour =
s35390a_reg2hr(s35390a,
buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
s35390a_reg2hr(buf[S35390A_ALRM_BYTE_HOURS] & ~0x80,
status1 & S35390A_FLAG_24H);
if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
@ -398,7 +490,7 @@ static int s35390a_rtc_ioctl(struct device *dev, unsigned int cmd,
break;
case RTC_VL_CLR:
/* update flag and clear register */
err = s35390a_init(s35390a);
err = s35390a_init(s35390a, &sts);
if (err < 0)
return err;
break;
@ -410,11 +502,12 @@ static int s35390a_rtc_ioctl(struct device *dev, unsigned int cmd,
}
static const struct rtc_class_ops s35390a_rtc_ops = {
.read_time = s35390a_rtc_read_time,
.set_time = s35390a_rtc_set_time,
.set_alarm = s35390a_rtc_set_alarm,
.read_alarm = s35390a_rtc_read_alarm,
.ioctl = s35390a_rtc_ioctl,
.read_time = s35390a_rtc_read_time,
.set_time = s35390a_rtc_set_time,
.set_alarm = s35390a_rtc_set_alarm,
.read_alarm = s35390a_rtc_read_alarm,
.alarm_irq_enable = s35390a_rtc_alarm_irq_enable,
.ioctl = s35390a_rtc_ioctl,
};
static int s35390a_nvmem_read(void *priv, unsigned int offset, void *val,
@ -434,13 +527,168 @@ static int s35390a_nvmem_write(void *priv, unsigned int offset, void *val,
return s35390a_set_reg(s35390a, S35390A_CMD_FREE_REG, val, bytes);
}
static const struct pinctrl_pin_desc s35390a_pins_desc[] = {
PINCTRL_PIN(0, "int1"),
PINCTRL_PIN(1, "int2"),
};
static const unsigned int int1_pins[] = { 0 };
static const unsigned int int2_pins[] = { 1 };
static const struct pingroup s35390a_pin_groups[] = {
PINCTRL_PINGROUP("int1_grp", int1_pins, ARRAY_SIZE(int1_pins)),
PINCTRL_PINGROUP("int2_grp", int2_pins, ARRAY_SIZE(int2_pins)),
};
static int s35390a_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(s35390a_pin_groups);
}
static const char *s35390a_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int group)
{
return s35390a_pin_groups[group].name;
}
static int s35390a_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
const unsigned int **pins, unsigned int *npins)
{
*pins = s35390a_pin_groups[selector].pins;
*npins = s35390a_pin_groups[selector].npins;
return 0;
}
static const char * const all_groups[] = { "int1_grp", "int2_grp" };
static const char * const int1_groups[] = { "int1_grp" };
static const struct pinfunction s35390a_functions[] = {
[S35390A_FUNC_IGNORE] = PINCTRL_PINFUNCTION("ignore", all_groups, ARRAY_SIZE(all_groups)),
[S35390A_FUNC_DISABLE] = PINCTRL_PINFUNCTION("disable", all_groups, ARRAY_SIZE(all_groups)),
[S35390A_FUNC_WAKEUP] = PINCTRL_PINFUNCTION("wakeup", all_groups, ARRAY_SIZE(all_groups)),
[S35390A_FUNC_CLOCK] = PINCTRL_PINFUNCTION("clock", all_groups, ARRAY_SIZE(all_groups)),
[S35390A_FUNC_PMIN1] = PINCTRL_PINFUNCTION("pmin1", all_groups, ARRAY_SIZE(all_groups)),
[S35390A_FUNC_PMIN2] = PINCTRL_PINFUNCTION("pmin2", int1_groups, ARRAY_SIZE(int1_groups)),
};
static int s35390a_pinctrl_get_functions_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(s35390a_functions);
}
static const char *s35390a_pinctrl_get_function_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
return s35390a_functions[selector].name;
}
static int s35390a_pinctrl_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector,
const char * const **groups,
unsigned int * const ngroups)
{
*groups = s35390a_functions[selector].groups;
*ngroups = s35390a_functions[selector].ngroups;
return 0;
}
static int s35390a_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
unsigned int group)
{
int err;
u8 status2, flag, mask;
struct s35390a *s35390a = pinctrl_dev_get_drvdata(pctldev);
mask = group == 0 ? S35390A_INT1_MODE_MASK : S35390A_INT2_MODE_MASK;
guard(mutex)(&s35390a->pinfunction_lock);
dev_dbg(&s35390a->client[0]->dev, "%s: function=%d group=%d\n",
__func__, function, group);
if (function == s35390a->pinfunction[group])
return 0;
if (function != S35390A_FUNC_IGNORE) {
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &status2, 1);
if (err < 0) {
dev_err(&s35390a->client[0]->dev, "error reading status\n");
return err;
}
switch (function) {
case S35390A_FUNC_DISABLE:
case S35390A_FUNC_CLOCK: /* not implemented */
status2 = (status2 & ~mask) | S35390A_INT_MODE_NOINTR;
break;
case S35390A_FUNC_WAKEUP:
flag = group == 0 ? S35390A_INT1_MODE_ALARM : S35390A_INT2_MODE_ALARM;
if ((status2 & mask) != flag)
status2 = (status2 & ~mask) | S35390A_INT_MODE_NOINTR;
break;
case S35390A_FUNC_PMIN1:
flag = group == 0 ? S35390A_INT1_MODE_PMIN1 : S35390A_INT2_MODE_PMIN1;
status2 = (status2 & ~mask) | flag;
break;
/* INT1 only modes */
case S35390A_FUNC_PMIN2:
if (group == 1)
return -EINVAL;
status2 = (status2 & ~mask) | S35390A_INT1_MODE_PMIN2;
break;
}
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &status2, 1);
if (err < 0) {
dev_err(&s35390a->client[0]->dev, "error setting interrupts\n");
return err;
}
}
s35390a->pinfunction[group] = function;
return 0;
}
static const struct pinctrl_ops s35390a_pinctrl_ops = {
.get_groups_count = s35390a_pinctrl_get_groups_count,
.get_group_name = s35390a_pinctrl_get_group_name,
.get_group_pins = s35390a_pinctrl_get_group_pins,
#if IS_ENABLED(CONFIG_OF)
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
.dt_free_map = pinconf_generic_dt_free_map
#endif
};
static const struct pinmux_ops s35390a_pinmux_ops = {
.get_functions_count = s35390a_pinctrl_get_functions_count,
.get_function_name = s35390a_pinctrl_get_function_name,
.get_function_groups = s35390a_pinctrl_get_function_groups,
.set_mux = s35390a_pinctrl_set_mux,
.strict = true,
};
static struct pinctrl_desc s35390a_pinctrl_desc = {
.name = DRIVER_NAME,
.pins = s35390a_pins_desc,
.npins = ARRAY_SIZE(s35390a_pins_desc),
.pctlops = &s35390a_pinctrl_ops,
.pmxops = &s35390a_pinmux_ops,
.owner = THIS_MODULE,
};
static int s35390a_probe(struct i2c_client *client)
{
int err, err_read;
int err;
unsigned int i;
struct s35390a *s35390a;
struct rtc_device *rtc;
u8 buf, status1;
struct pinctrl_dev *pctl;
u8 status1, status2;
bool irq = false;
struct device *dev = &client->dev;
struct nvmem_config nvmem_cfg = {
.name = "s35390a_nvram",
@ -451,6 +699,7 @@ static int s35390a_probe(struct i2c_client *client)
.reg_read = s35390a_nvmem_read,
.reg_write = s35390a_nvmem_write,
};
int fallback[ARRAY_SIZE(s35390a_pin_groups)];
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
@ -459,7 +708,11 @@ static int s35390a_probe(struct i2c_client *client)
if (!s35390a)
return -ENOMEM;
mutex_init(&s35390a->pinfunction_lock);
memset(s35390a->pinfunction, -1, sizeof(s35390a->pinfunction));
s35390a->client[0] = client;
i2c_set_clientdata(client, s35390a);
/* This chip uses multiple addresses, use dummy devices for them */
@ -474,39 +727,35 @@ static int s35390a_probe(struct i2c_client *client)
}
}
err = s35390a_read_status(s35390a, &status1);
if (err < 0) {
dev_err(dev, "error resetting chip\n");
return err;
}
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &status2, sizeof(status2));
if (err < 0)
return dev_err_probe(dev, err, "disabling alarm and test mode failed\n");
if (status1 & S35390A_FLAG_INT1) {
status2 = (status2 & ~S35390A_INT1_MODE_MASK) | S35390A_INT_MODE_NOINTR;
irq = true;
}
if (status1 & S35390A_FLAG_INT2) {
status2 = (status2 & ~S35390A_INT2_MODE_MASK) | S35390A_INT_MODE_NOINTR;
irq = true;
}
status2 &= ~S35390A_FLAG_TEST;
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &status2, sizeof(status2));
if (err < 0)
return dev_err_probe(dev, err, "disabling alarm and test mode failed\n");
rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
err_read = s35390a_read_status(s35390a, &status1);
if (err_read < 0) {
dev_err(dev, "error resetting chip\n");
return err_read;
}
if (status1 & S35390A_FLAG_24H)
s35390a->twentyfourhour = 1;
else
s35390a->twentyfourhour = 0;
if (status1 & S35390A_FLAG_INT2) {
/* disable alarm (and maybe test mode) */
buf = 0;
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
if (err < 0) {
dev_err(dev, "error disabling alarm");
return err;
}
} else {
err = s35390a_disable_test_mode(s35390a);
if (err < 0) {
dev_err(dev, "error disabling test mode\n");
return err;
}
}
device_set_wakeup_capable(dev, 1);
rtc->ops = &s35390a_rtc_ops;
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->range_max = RTC_TIMESTAMP_END_2099;
@ -514,9 +763,43 @@ static int s35390a_probe(struct i2c_client *client)
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features);
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
if (status1 & S35390A_FLAG_INT2)
s35390a->rtc = rtc;
device_set_wakeup_capable(dev, 1);
if (irq)
rtc_update_irq(rtc, 1, RTC_AF);
err = devm_pinctrl_register_and_init(dev, &s35390a_pinctrl_desc, s35390a, &pctl);
if (err)
return dev_err_probe(dev, err, "pinctrl register failed\n");
err = pinctrl_enable(pctl);
if (err)
return dev_err_probe(dev, err, "pinctrl enable failed\n");
/* If no pinmux function is defined in DT, fallback to previous behaviour */
if (dmi_match(DMI_SYS_VENDOR, "Synology Inc.")) {
/*
* Synology uses interrupt signal 1 for wakeup. Since pinctrl cannot be
* configured on ACPI, we check against the dmi sys vendor.
*/
fallback[0] = S35390A_FUNC_WAKEUP;
fallback[1] = S35390A_FUNC_DISABLE;
} else {
fallback[0] = S35390A_FUNC_IGNORE;
fallback[1] = S35390A_FUNC_WAKEUP;
}
for (i = 0; i < ARRAY_SIZE(s35390a_pin_groups); i++) {
if (s35390a->pinfunction[i] == -1) {
err = s35390a_pinctrl_set_mux(pctl, fallback[i], i);
if (err)
return err;
}
}
nvmem_cfg.priv = s35390a;
err = devm_rtc_nvmem_register(rtc, &nvmem_cfg);
if (err)
@ -527,7 +810,7 @@ static int s35390a_probe(struct i2c_client *client)
static struct i2c_driver s35390a_driver = {
.driver = {
.name = "rtc-s35390a",
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(s35390a_of_match),
},
.probe = s35390a_probe,

View File

@ -465,7 +465,7 @@ static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
const struct stm32_rtc_events *evts = &rtc->data->events;
unsigned int status, cr;
rtc_lock(rtc->rtc_dev);
guard(rtc_ops)(rtc->rtc_dev);
status = readl_relaxed(rtc->base + regs->sr);
cr = readl_relaxed(rtc->base + regs->cr);
@ -482,8 +482,6 @@ static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
stm32_rtc_clear_event_flags(rtc, evts->alra);
}
rtc_unlock(rtc->rtc_dev);
return IRQ_HANDLED;
}

View File

@ -231,6 +231,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
const char *iosc_name = "rtc-int-osc";
const char *clkout_name = "osc32k-out";
const char *parents[2];
struct resource res;
u32 reg;
rtc = kzalloc_obj(*rtc);
@ -267,9 +268,6 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
}
writel(reg, rtc->base + SUN6I_LOSC_CTRL);
/* Yes, I know, this is ugly. */
sun6i_rtc = rtc;
of_property_read_string_index(node, "clock-output-names", 2,
&iosc_name);
@ -280,7 +278,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
300000000);
if (IS_ERR(rtc->int_osc)) {
pr_crit("Couldn't register the internal oscillator\n");
goto err;
goto err_unmap;
}
parents[0] = clk_hw_get_name(rtc->int_osc);
@ -309,7 +307,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
&rtc->lock);
if (IS_ERR(rtc->ext_losc)) {
pr_crit("Couldn't register the LOSC external gate\n");
goto err_register;
goto err_losc;
}
clk_data->num = 3;
@ -317,12 +315,22 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
clk_data->hws[2] = rtc->int_osc;
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
/* Yes, I know, this is ugly. */
sun6i_rtc = rtc;
return;
err_losc:
clk_unregister(rtc->losc);
err_register:
clk_hw_unregister_fixed_rate(rtc->int_osc);
err_unmap:
iounmap(rtc->base);
of_address_to_resource(node, 0, &res);
release_mem_region(res.start, resource_size(&res));
err:
kfree(clk_data);
kfree(rtc);
}
static const struct sun6i_rtc_clk_data sun6i_a31_rtc_data = {
@ -350,6 +358,10 @@ static void __init sun8i_a23_rtc_clk_init(struct device_node *node)
CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc",
sun8i_a23_rtc_clk_init);
/* The B288 RTC clocks are the same as the A23's */
CLK_OF_DECLARE_DRIVER(sun8i_b288_rtc_clk, "allwinner,sun8i-b288-rtc",
sun8i_a23_rtc_clk_init);
static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = {
.rc_osc_rate = 16000000,
.fixed_prescaler = 32,
@ -859,6 +871,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
static const struct of_device_id sun6i_rtc_dt_ids[] = {
{ .compatible = "allwinner,sun6i-a31-rtc" },
{ .compatible = "allwinner,sun8i-a23-rtc" },
{ .compatible = "allwinner,sun8i-b288-rtc" },
{ .compatible = "allwinner,sun8i-h3-rtc" },
{ .compatible = "allwinner,sun8i-r40-rtc" },
{ .compatible = "allwinner,sun8i-v3-rtc" },

View File

@ -575,7 +575,7 @@ static ssize_t x1205_sysfs_show_atrim(struct device *dev,
if (err)
return err;
return sprintf(buf, "%d.%02d pF\n", atrim / 1000, atrim % 1000);
return sysfs_emit(buf, "%d.%02d pF\n", atrim / 1000, atrim % 1000);
}
static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
@ -588,7 +588,7 @@ static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
if (err)
return err;
return sprintf(buf, "%d ppm\n", dtrim);
return sysfs_emit(buf, "%d ppm\n", dtrim);
}
static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);

View File

@ -174,7 +174,7 @@ static struct wkup_m3_wakeup_src rtc_wake_src(void)
static int am33xx_rtc_only_idle(unsigned long wfi_flags)
{
omap_rtc_power_off_program(&omap_rtc->dev);
omap_rtc_power_off_program();
am33xx_do_wfi_sram(wfi_flags);
return 0;
}

View File

@ -49,6 +49,13 @@
#define RTC_AL_SEC 0x0018
/* The high byte of four of the alarms is spare, always-on storage */
#define RTC_AL_HOU 0x001c
#define RTC_AL_DOM 0x001e
#define RTC_AL_DOW 0x0020
#define RTC_AL_MTH 0x0022
#define RTC_SPARE_MASK GENMASK(15, 8)
#define RTC_AL_SEC_MASK 0x003f
#define RTC_AL_MIN_MASK 0x003f
#define RTC_AL_HOU_MASK 0x001f

View File

@ -13,6 +13,7 @@
#define _LINUX_RTC_H_
#include <linux/cleanup.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/nvmem-provider.h>
@ -167,6 +168,9 @@ struct rtc_device {
#define rtc_lock(d) mutex_lock(&d->ops_lock)
#define rtc_unlock(d) mutex_unlock(&d->ops_lock)
DEFINE_GUARD(rtc_ops, struct rtc_device *, mutex_lock(&_T->ops_lock),
mutex_unlock(&_T->ops_lock))
/* useful timestamps */
#define RTC_TIMESTAMP_BEGIN_0000 -62167219200ULL /* 0000-01-01 00:00:00 */
#define RTC_TIMESTAMP_BEGIN_1900 -2208988800LL /* 1900-01-01 00:00:00 */
@ -201,6 +205,7 @@ extern void rtc_update_irq(struct rtc_device *rtc,
extern struct rtc_device *rtc_class_open(const char *name);
extern void rtc_class_close(struct rtc_device *rtc);
DEFINE_FREE(rtc_class_close, struct rtc_device *, if (_T) rtc_class_close(_T));
extern int rtc_irq_set_state(struct rtc_device *rtc, int enabled);
extern int rtc_irq_set_freq(struct rtc_device *rtc, int freq);

View File

@ -3,5 +3,5 @@
#ifndef _LINUX_RTCOMAP_H_
#define _LINUX_RTCOMAP_H_
int omap_rtc_power_off_program(struct device *dev);
int omap_rtc_power_off_program(void);
#endif /* _LINUX_RTCOMAP_H_ */

View File

@ -75,6 +75,7 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048,
RPI_FIRMWARE_GET_RTC_REG = 0x00030087,
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
@ -92,6 +93,7 @@ enum rpi_firmware_property_tag {
RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066,
RPI_FIRMWARE_SET_RTC_REG = 0x00038087,
/* Dispmanx TAGS */
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,

View File

@ -49,7 +49,7 @@ TEST_F(rtc, date_read) {
struct rtc_time rtc_tm;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
/* Read the RTC time/date */
@ -116,9 +116,10 @@ TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
long iter_count = 0;
struct rtc_time rtc_tm;
time_t start_rtc_read, prev_rtc_read;
struct timespec prev_mono, cur_mono;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
@ -126,25 +127,31 @@ TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
ASSERT_NE(-1, rc);
clock_gettime(CLOCK_MONOTONIC, &prev_mono);
start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
prev_rtc_read = start_rtc_read;
do {
time_t rtc_read;
time_t delta_s = 0;
rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
ASSERT_NE(-1, rc);
clock_gettime(CLOCK_MONOTONIC, &cur_mono);
rtc_read = rtc_time_to_timestamp(&rtc_tm);
delta_s = cur_mono.tv_sec - prev_mono.tv_sec;
/* Time should not go backwards */
ASSERT_LE(prev_rtc_read, rtc_read);
/* Time should not increase more then 1s at a time */
ASSERT_GE(prev_rtc_read + 1, rtc_read);
/* Time should not increase more then elapsed time + 1s */
ASSERT_GE(prev_rtc_read + delta_s + 1, rtc_read);
/* Sleep 11ms to avoid killing / overheating the RTC */
nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
prev_rtc_read = rtc_read;
prev_mono = cur_mono;
iter_count++;
} while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
@ -156,15 +163,14 @@ TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
unsigned long data;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
/* Turn on update interrupts */
rc = ioctl(self->fd, RTC_UIE_ON, 0);
if (rc == -1) {
ASSERT_EQ(EINVAL, errno);
TH_LOG("skip update IRQs not supported.");
return;
SKIP(return, "update IRQs are not supported.");
}
for (i = 0; i < NUM_UIE; i++) {
@ -185,15 +191,14 @@ TEST_F(rtc, uie_select) {
unsigned long data;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
/* Turn on update interrupts */
rc = ioctl(self->fd, RTC_UIE_ON, 0);
if (rc == -1) {
ASSERT_EQ(EINVAL, errno);
TH_LOG("skip update IRQs not supported.");
return;
SKIP(return, "update IRQs are not supported.");
}
for (i = 0; i < NUM_UIE; i++) {
@ -229,14 +234,14 @@ TEST_F(rtc, alarm_alm_set) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 1);
if (alarm_state == RTC_ALARM_DISABLED)
SKIP(return, "Skipping test since alarms are not supported.");
SKIP(return, "alarms are not supported.");
if (alarm_state == RTC_ALARM_RES_MINUTE)
SKIP(return, "Skipping test since alarms has only minute granularity.");
SKIP(return, "alarms has only minute granularity.");
rc = ioctl(self->fd, RTC_RD_TIME, &tm);
ASSERT_NE(-1, rc);
@ -252,8 +257,7 @@ TEST_F(rtc, alarm_alm_set) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
TH_LOG("skip alarms are not supported.");
return;
SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_ALM_READ, &tm);
@ -299,14 +303,14 @@ TEST_F(rtc, alarm_wkalm_set) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 1);
if (alarm_state == RTC_ALARM_DISABLED)
SKIP(return, "Skipping test since alarms are not supported.");
SKIP(return, "alarms are not supported.");
if (alarm_state == RTC_ALARM_RES_MINUTE)
SKIP(return, "Skipping test since alarms has only minute granularity.");
SKIP(return, "alarms has only minute granularity.");
rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
ASSERT_NE(-1, rc);
@ -324,8 +328,7 @@ TEST_F(rtc, alarm_wkalm_set) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
TH_LOG("skip alarms are not supported.");
return;
SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
@ -363,12 +366,12 @@ TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 0);
if (alarm_state == RTC_ALARM_DISABLED)
SKIP(return, "Skipping test since alarms are not supported.");
SKIP(return, "alarms are not supported.");
rc = ioctl(self->fd, RTC_RD_TIME, &tm);
ASSERT_NE(-1, rc);
@ -384,8 +387,7 @@ TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
TH_LOG("skip alarms are not supported.");
return;
SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_ALM_READ, &tm);
@ -431,12 +433,12 @@ TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
enum rtc_alarm_state alarm_state = RTC_ALARM_UNKNOWN;
if (self->fd == -1 && errno == ENOENT)
SKIP(return, "Skipping test since %s does not exist", rtc_file);
SKIP(return, "%s does not exist", rtc_file);
ASSERT_NE(-1, self->fd);
alarm_state = get_rtc_alarm_state(self->fd, 0);
if (alarm_state == RTC_ALARM_DISABLED)
SKIP(return, "Skipping test since alarms are not supported.");
SKIP(return, "alarms are not supported.");
rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
ASSERT_NE(-1, rc);
@ -454,8 +456,7 @@ TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
*/
ASSERT_EQ(RTC_ALARM_UNKNOWN, alarm_state);
ASSERT_EQ(EINVAL, errno);
TH_LOG("skip alarms are not supported.");
return;
SKIP(return, "alarms are not supported.");
}
rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
@ -502,8 +503,7 @@ int main(int argc, char **argv)
if (access(rtc_file, R_OK) == 0)
ret = test_harness_run(argc, argv);
else
ksft_exit_skip("[SKIP]: Cannot access rtc file %s - Exiting\n",
rtc_file);
ksft_exit_skip("Cannot access rtc file %s - Exiting\n", rtc_file);
return ret;
}