mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
RTC for 6.2
Removed driver: - davinci Drivers: - convert i2c drivers to .probe_new - fix spelling mistakes and duplicated words in comments - cmos: rework wake setup and ACPI event handling - cros-ec: Limit RTC alarm range to fix alarmtimer - ds1347: fix century register handling - efi: wakeup support - isl12022: temperature sensor support - pcf85063: fix read_alarm and clkout - pcf8523: use stop bit to detect invalid time - pcf8563: use RTC_FEATURE_ALARM - snvs: be more flexible on LPSRT reads - many static checker fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmOeZV4ACgkQY6TcMGxw OjLUeRAAhOXdMW/J00D25lwFbPazXypF8v92j/TfjQiL23GMWgsiuH+etEl/eoHe XoAD2pGLdrd4Py2f5vRAYwW/dLVWRZ8nQHNSsur9BwgyyrZHEMti4zx3pm+ceT/k d1E/pagC5013SBXDgsJY6N3PyNxIrptY2ONip3dxQifKhYJ4SsiG0SVha/LkLJUt HvF0tvQd3+Iu+VM59fwOs5vFp11mJCALoFrlF0G4WyRWrl5ekIuVgVhMbmEPUmTL vuLZm2Z2a210jDckuOdpiD5z2KzGAHrS7HMdWSAMow0QeAZEv4gQT+HgPghaxhWk MIWlaJK32+D93wwGfQpyiC6yR+sT+YlSnSnLeA6g23RKE4uN7niiFKPgoa03zSQo /UBrgmzKwS2g8vxzKETUB7KMvkMaX4+jmxtdDzdct+hxSAJvOZPlNlm7AvH2M7ai /OtjdBSKlIYHLjQMbFTHI/iml2ESch7Q5HoPV+ZUhkvhE+9TWEaGU6BVfFMl9ODv 92T+wxZMQNBbXNArgfpybW1q0L+jQgsh985hHegNGVh4qDLuHdo27oDymbLt27vj ABT3w38MsM9YYl7gRj8/lz0am0EVoK2fVk9B1Ixt9w9yKKSNpWpIdGQg0dmjsB9Z gYCtwOomJxhvZp5zeyGACfpxj/JvtJTsDTPSSXptnrZdDFnt2Jo= =DGOn -----END PGP SIGNATURE----- Merge tag 'rtc-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "Most of the changes are a rework of the cmos driver by Rafael and fixes for issues found using static checkers. The removal of a driver leads to a reduction of the number of LOC of the subsystem. Removed driver: - davinci Updates: - convert i2c drivers to .probe_new - fix spelling mistakes and duplicated words in comments - cmos: rework wake setup and ACPI event handling - cros-ec: Limit RTC alarm range to fix alarmtimer - ds1347: fix century register handling - efi: wakeup support - isl12022: temperature sensor support - pcf85063: fix read_alarm and clkout - pcf8523: use stop bit to detect invalid time - pcf8563: use RTC_FEATURE_ALARM - snvs: be more flexible on LPSRT reads - many static checker fixes" * tag 'rtc-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (48 commits) rtc: ds1742: use devm_platform_get_and_ioremap_resource() rtc: mxc_v2: Add missing clk_disable_unprepare() rtc: rs5c313: correct some spelling mistakes rtc: at91rm9200: Fix syntax errors in comments rtc: remove duplicated words in comments rtc: rv3028: Use IRQ flags obtained from device tree if available rtc: ds1307: use sysfs_emit() to instead of scnprintf() rtc: isl12026: drop obsolete dependency on COMPILE_TEST dt-bindings: rtc: m41t80: Convert text schema to YAML one rtc: pcf85063: fix pcf85063_clkout_control rtc: rx6110: fix warning with !OF rtc: rk808: reduce 'struct rk808' usage rtc: msc313: Fix function prototype mismatch in msc313_rtc_probe() dt-bindings: rtc: convert rtc-meson.txt to dt-schema rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe() rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe() rtc: pcf85063: Fix reading alarm rtc: pcf8523: fix for stop bit rtc: efi: Add wakeup support rtc: pcf8563: clear RTC_FEATURE_ALARM if no irq ...
This commit is contained in:
commit
acd04af6e4
@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/amlogic,meson6-rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic Meson6, Meson8, Meson8b and Meson8m2 RTC
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||
- Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: rtc.yaml#
|
||||
- $ref: /schemas/nvmem/nvmem.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- amlogic,meson6-rtc
|
||||
- amlogic,meson8-rtc
|
||||
- amlogic,meson8b-rtc
|
||||
- amlogic,meson8m2-rtc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
rtc: rtc@740 {
|
||||
compatible = "amlogic,meson6-rtc";
|
||||
reg = <0x740 0x14>;
|
||||
interrupts = <GIC_SPI 72 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&rtc32k_xtal>;
|
||||
vdd-supply = <&rtc_vdd>;
|
||||
resets = <&reset_rtc>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
mac@0 {
|
||||
reg = <0 6>;
|
||||
};
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
Haoyu Microelectronics HYM8563 Real Time Clock
|
||||
|
||||
The HYM8563 provides basic rtc and alarm functionality
|
||||
as well as a clock output of up to 32kHz.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be: "haoyu,hym8563"
|
||||
- reg: i2c address
|
||||
- #clock-cells: the value should be 0
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock binding
|
||||
- interrupts: rtc alarm/event interrupt
|
||||
|
||||
Example:
|
||||
|
||||
hym8563: hym8563@51 {
|
||||
compatible = "haoyu,hym8563";
|
||||
reg = <0x51>;
|
||||
|
||||
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
device {
|
||||
...
|
||||
clocks = <&hym8563>;
|
||||
...
|
||||
};
|
56
Documentation/devicetree/bindings/rtc/haoyu,hym8563.yaml
Normal file
56
Documentation/devicetree/bindings/rtc/haoyu,hym8563.yaml
Normal file
@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/haoyu,hym8563.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Haoyu Microelectronics HYM8563 RTC
|
||||
|
||||
maintainers:
|
||||
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: haoyu,hym8563
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clock-output-names:
|
||||
description: From common clock binding to override the default output clock name.
|
||||
maxItems: 1
|
||||
|
||||
wakeup-source:
|
||||
description: Enables wake up of host system on alarm.
|
||||
|
||||
allOf:
|
||||
- $ref: rtc.yaml
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#clock-cells"
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rtc@51 {
|
||||
compatible = "haoyu,hym8563";
|
||||
reg = <0x51>;
|
||||
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
@ -11,12 +11,16 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,pm8058-rtc
|
||||
- qcom,pm8921-rtc
|
||||
- qcom,pm8941-rtc
|
||||
- qcom,pm8018-rtc
|
||||
- qcom,pmk8350-rtc
|
||||
oneOf:
|
||||
- enum:
|
||||
- qcom,pm8058-rtc
|
||||
- qcom,pm8921-rtc
|
||||
- qcom,pm8941-rtc
|
||||
- qcom,pmk8350-rtc
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,pm8018-rtc
|
||||
- const: qcom,pm8921-rtc
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
|
@ -1,39 +0,0 @@
|
||||
ST M41T80 family of RTC and compatible
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of:
|
||||
"st,m41t62",
|
||||
"st,m41t65",
|
||||
"st,m41t80",
|
||||
"st,m41t81",
|
||||
"st,m41t81s",
|
||||
"st,m41t82",
|
||||
"st,m41t83",
|
||||
"st,m41t84",
|
||||
"st,m41t85",
|
||||
"st,m41t87",
|
||||
"microcrystal,rv4162",
|
||||
- reg: I2C bus address of the device
|
||||
|
||||
Optional properties:
|
||||
- interrupts: rtc alarm interrupt.
|
||||
- clock-output-names: From common clock binding to override the default output
|
||||
clock name
|
||||
- wakeup-source: Enables wake up of host system on alarm
|
||||
|
||||
Optional child node:
|
||||
- clock: Provide this if the square wave pin is used as boot-enabled fixed clock.
|
||||
|
||||
Example:
|
||||
rtc@68 {
|
||||
compatible = "st,m41t80";
|
||||
reg = <0x68>;
|
||||
interrupt-parent = <&UIC0>;
|
||||
interrupts = <0x9 0x8>;
|
||||
|
||||
clock {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
@ -1,35 +0,0 @@
|
||||
* Amlogic Meson6, Meson8, Meson8b and Meson8m2 RTC
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following describing the hardware:
|
||||
* "amlogic,meson6-rtc"
|
||||
* "amlogic,meson8-rtc"
|
||||
* "amlogic,meson8b-rtc"
|
||||
* "amlogic,meson8m2-rtc"
|
||||
|
||||
- reg: physical register space for the controller's memory mapped registers.
|
||||
- interrupts: the interrupt line of the RTC block.
|
||||
- clocks: reference to the external 32.768kHz crystal oscillator.
|
||||
- vdd-supply: reference to the power supply of the RTC block.
|
||||
- resets: reset controller reference to allow reset of the controller
|
||||
|
||||
Optional properties for the battery-backed non-volatile memory:
|
||||
- #address-cells: should be 1 to address the battery-backed non-volatile memory
|
||||
- #size-cells: should be 1 to reference the battery-backed non-volatile memory
|
||||
|
||||
Optional child nodes:
|
||||
- see ../nvmem/nvmem.txt
|
||||
|
||||
Example:
|
||||
|
||||
rtc: rtc@740 {
|
||||
compatible = "amlogic,meson6-rtc";
|
||||
reg = <0x740 0x14>;
|
||||
interrupts = <GIC_SPI 72 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&rtc32k_xtal>;
|
||||
vdd-supply = <&rtc_vdd>;
|
||||
resets = <&reset RESET_RTC>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
};
|
73
Documentation/devicetree/bindings/rtc/st,m41t80.yaml
Normal file
73
Documentation/devicetree/bindings/rtc/st,m41t80.yaml
Normal file
@ -0,0 +1,73 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/st,m41t80.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ST M41T80 family of RTC and compatible
|
||||
|
||||
maintainers:
|
||||
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- st,m41t62
|
||||
- st,m41t65
|
||||
- st,m41t80
|
||||
- st,m41t81
|
||||
- st,m41t81s
|
||||
- st,m41t82
|
||||
- st,m41t83
|
||||
- st,m41t84
|
||||
- st,m41t85
|
||||
- st,m41t87
|
||||
- microcrystal,rv4162
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
description: From common clock binding to override the default output clock name.
|
||||
|
||||
clock:
|
||||
type: object
|
||||
$ref: /schemas/clock/fixed-clock.yaml#
|
||||
properties:
|
||||
clock-frequency:
|
||||
const: 32768
|
||||
|
||||
allOf:
|
||||
- $ref: rtc.yaml
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
rtc@68 {
|
||||
compatible = "st,m41t80";
|
||||
reg = <0x68>;
|
||||
interrupt-parent = <&UIC0>;
|
||||
interrupts = <0x9 0x8>;
|
||||
|
||||
clock {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
};
|
@ -433,7 +433,7 @@ config RTC_DRV_ISL12022
|
||||
|
||||
config RTC_DRV_ISL12026
|
||||
tristate "Intersil ISL12026"
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
If you say yes here you get support for the
|
||||
Intersil ISL12026 RTC chip.
|
||||
@ -1351,16 +1351,6 @@ config RTC_DRV_ASM9260
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-asm9260.
|
||||
|
||||
config RTC_DRV_DAVINCI
|
||||
tristate "TI DaVinci RTC"
|
||||
depends on ARCH_DAVINCI_DM365 || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for the RTC on the
|
||||
DaVinci platforms (DM365).
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-davinci.
|
||||
|
||||
config RTC_DRV_DIGICOLOR
|
||||
tristate "Conexant Digicolor RTC"
|
||||
depends on ARCH_DIGICOLOR || COMPILE_TEST
|
||||
|
@ -44,7 +44,6 @@ obj-$(CONFIG_RTC_DRV_CROS_EC) += rtc-cros-ec.o
|
||||
obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
|
||||
obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
|
||||
obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
|
||||
obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
|
||||
obj-$(CONFIG_RTC_DRV_DIGICOLOR) += rtc-digicolor.o
|
||||
obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
|
||||
|
@ -374,11 +374,11 @@ struct rtc_device *devm_rtc_allocate_device(struct device *dev)
|
||||
|
||||
rtc->id = id;
|
||||
rtc->dev.parent = dev;
|
||||
err = dev_set_name(&rtc->dev, "rtc%d", id);
|
||||
err = devm_add_action_or_reset(dev, devm_rtc_release_device, rtc);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = devm_add_action_or_reset(dev, devm_rtc_release_device, rtc);
|
||||
err = dev_set_name(&rtc->dev, "rtc%d", id);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
|
@ -256,7 +256,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
*
|
||||
* This could all instead be done in the lower level driver,
|
||||
* but since more than one lower level RTC implementation needs it,
|
||||
* then it's probably best best to do it here instead of there..
|
||||
* then it's probably best to do it here instead of there..
|
||||
*/
|
||||
|
||||
/* Get the "before" timestamp */
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/rtc.h>
|
||||
@ -673,13 +674,28 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int abx80x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static const struct i2c_device_id abx80x_id[] = {
|
||||
{ "abx80x", ABX80X },
|
||||
{ "ab0801", AB0801 },
|
||||
{ "ab0803", AB0803 },
|
||||
{ "ab0804", AB0804 },
|
||||
{ "ab0805", AB0805 },
|
||||
{ "ab1801", AB1801 },
|
||||
{ "ab1803", AB1803 },
|
||||
{ "ab1804", AB1804 },
|
||||
{ "ab1805", AB1805 },
|
||||
{ "rv1805", RV1805 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, abx80x_id);
|
||||
|
||||
static int abx80x_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device_node *np = client->dev.of_node;
|
||||
struct abx80x_priv *priv;
|
||||
int i, data, err, trickle_cfg = -EINVAL;
|
||||
char buf[7];
|
||||
const struct i2c_device_id *id = i2c_match_id(abx80x_id, client);
|
||||
unsigned int part = id->driver_data;
|
||||
unsigned int partnumber;
|
||||
unsigned int majrev, minrev;
|
||||
@ -847,21 +863,6 @@ static int abx80x_probe(struct i2c_client *client,
|
||||
return devm_rtc_register_device(priv->rtc);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id abx80x_id[] = {
|
||||
{ "abx80x", ABX80X },
|
||||
{ "ab0801", AB0801 },
|
||||
{ "ab0803", AB0803 },
|
||||
{ "ab0804", AB0804 },
|
||||
{ "ab0805", AB0805 },
|
||||
{ "ab1801", AB1801 },
|
||||
{ "ab1803", AB1803 },
|
||||
{ "ab1804", AB1804 },
|
||||
{ "ab1805", AB1805 },
|
||||
{ "rv1805", RV1805 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, abx80x_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id abx80x_of_match[] = {
|
||||
{
|
||||
@ -914,7 +915,7 @@ static struct i2c_driver abx80x_driver = {
|
||||
.name = "rtc-abx80x",
|
||||
.of_match_table = of_match_ptr(abx80x_of_match),
|
||||
},
|
||||
.probe = abx80x_probe,
|
||||
.probe_new = abx80x_probe,
|
||||
.id_table = abx80x_id,
|
||||
};
|
||||
|
||||
|
@ -130,7 +130,7 @@ static void at91_rtc_write_idr(u32 mask)
|
||||
*
|
||||
* Note that there is still a possibility that the mask is updated
|
||||
* before interrupts have actually been disabled in hardware. The only
|
||||
* way to be certain would be to poll the IMR-register, which is is
|
||||
* way to be certain would be to poll the IMR-register, which is
|
||||
* the very register we are trying to emulate. The register read back
|
||||
* is a reasonable heuristic.
|
||||
*/
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
|
@ -744,6 +744,168 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
#include <linux/acpi.h>
|
||||
|
||||
static u32 rtc_handler(void *context)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
unsigned char rtc_control = 0;
|
||||
unsigned char rtc_intr;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
/*
|
||||
* Always update rtc irq when ACPI is used as RTC Alarm.
|
||||
* Or else, ACPI SCI is enabled during suspend/resume only,
|
||||
* update rtc irq in that case.
|
||||
*/
|
||||
if (cmos_use_acpi_alarm())
|
||||
cmos_interrupt(0, (void *)cmos->rtc);
|
||||
else {
|
||||
/* Fix me: can we use cmos_interrupt() here as well? */
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
if (cmos_rtc.suspend_ctrl)
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
if (rtc_control & RTC_AIE) {
|
||||
cmos_rtc.suspend_ctrl &= ~RTC_AIE;
|
||||
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
||||
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
|
||||
rtc_update_irq(cmos->rtc, 1, rtc_intr);
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
}
|
||||
|
||||
pm_wakeup_hard_event(dev);
|
||||
acpi_clear_event(ACPI_EVENT_RTC);
|
||||
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
||||
return ACPI_INTERRUPT_HANDLED;
|
||||
}
|
||||
|
||||
static void acpi_rtc_event_setup(struct device *dev)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, dev);
|
||||
/*
|
||||
* After the RTC handler is installed, the Fixed_RTC event should
|
||||
* be disabled. Only when the RTC alarm is set will it be enabled.
|
||||
*/
|
||||
acpi_clear_event(ACPI_EVENT_RTC);
|
||||
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
||||
}
|
||||
|
||||
static void acpi_rtc_event_cleanup(void)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
acpi_remove_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler);
|
||||
}
|
||||
|
||||
static void rtc_wake_on(struct device *dev)
|
||||
{
|
||||
acpi_clear_event(ACPI_EVENT_RTC);
|
||||
acpi_enable_event(ACPI_EVENT_RTC, 0);
|
||||
}
|
||||
|
||||
static void rtc_wake_off(struct device *dev)
|
||||
{
|
||||
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/* Enable use_acpi_alarm mode for Intel platforms no earlier than 2015 */
|
||||
static void use_acpi_alarm_quirks(void)
|
||||
{
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
|
||||
return;
|
||||
|
||||
if (!is_hpet_enabled())
|
||||
return;
|
||||
|
||||
if (dmi_get_bios_year() < 2015)
|
||||
return;
|
||||
|
||||
use_acpi_alarm = true;
|
||||
}
|
||||
#else
|
||||
static inline void use_acpi_alarm_quirks(void) { }
|
||||
#endif
|
||||
|
||||
static void acpi_cmos_wake_setup(struct device *dev)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
use_acpi_alarm_quirks();
|
||||
|
||||
cmos_rtc.wake_on = rtc_wake_on;
|
||||
cmos_rtc.wake_off = rtc_wake_off;
|
||||
|
||||
/* ACPI tables bug workaround. */
|
||||
if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
|
||||
dev_dbg(dev, "bogus FADT month_alarm (%d)\n",
|
||||
acpi_gbl_FADT.month_alarm);
|
||||
acpi_gbl_FADT.month_alarm = 0;
|
||||
}
|
||||
|
||||
cmos_rtc.day_alrm = acpi_gbl_FADT.day_alarm;
|
||||
cmos_rtc.mon_alrm = acpi_gbl_FADT.month_alarm;
|
||||
cmos_rtc.century = acpi_gbl_FADT.century;
|
||||
|
||||
if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
|
||||
dev_info(dev, "RTC can wake from S4\n");
|
||||
|
||||
/* RTC always wakes from S1/S2/S3, and often S4/STD */
|
||||
device_init_wakeup(dev, 1);
|
||||
}
|
||||
|
||||
static void cmos_check_acpi_rtc_status(struct device *dev,
|
||||
unsigned char *rtc_control)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
acpi_event_status rtc_status;
|
||||
acpi_status status;
|
||||
|
||||
if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC)
|
||||
return;
|
||||
|
||||
status = acpi_get_event_status(ACPI_EVENT_RTC, &rtc_status);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "Could not get RTC status\n");
|
||||
} else if (rtc_status & ACPI_EVENT_FLAG_SET) {
|
||||
unsigned char mask;
|
||||
*rtc_control &= ~RTC_AIE;
|
||||
CMOS_WRITE(*rtc_control, RTC_CONTROL);
|
||||
mask = CMOS_READ(RTC_INTR_FLAGS);
|
||||
rtc_update_irq(cmos->rtc, 1, mask);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !CONFIG_ACPI */
|
||||
|
||||
static inline void acpi_rtc_event_setup(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void acpi_rtc_event_cleanup(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void acpi_cmos_wake_setup(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void cmos_check_acpi_rtc_status(struct device *dev,
|
||||
unsigned char *rtc_control)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
#define INITSECTION
|
||||
|
||||
@ -827,19 +989,27 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
if (info->address_space)
|
||||
address_space = info->address_space;
|
||||
|
||||
if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
|
||||
cmos_rtc.day_alrm = info->rtc_day_alarm;
|
||||
if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
|
||||
cmos_rtc.mon_alrm = info->rtc_mon_alarm;
|
||||
if (info->rtc_century && info->rtc_century < 128)
|
||||
cmos_rtc.century = info->rtc_century;
|
||||
cmos_rtc.day_alrm = info->rtc_day_alarm;
|
||||
cmos_rtc.mon_alrm = info->rtc_mon_alarm;
|
||||
cmos_rtc.century = info->rtc_century;
|
||||
|
||||
if (info->wake_on && info->wake_off) {
|
||||
cmos_rtc.wake_on = info->wake_on;
|
||||
cmos_rtc.wake_off = info->wake_off;
|
||||
}
|
||||
} else {
|
||||
acpi_cmos_wake_setup(dev);
|
||||
}
|
||||
|
||||
if (cmos_rtc.day_alrm >= 128)
|
||||
cmos_rtc.day_alrm = 0;
|
||||
|
||||
if (cmos_rtc.mon_alrm >= 128)
|
||||
cmos_rtc.mon_alrm = 0;
|
||||
|
||||
if (cmos_rtc.century >= 128)
|
||||
cmos_rtc.century = 0;
|
||||
|
||||
cmos_rtc.dev = dev;
|
||||
dev_set_drvdata(dev, &cmos_rtc);
|
||||
|
||||
@ -928,6 +1098,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
nvmem_cfg.size = address_space - NVRAM_OFFSET;
|
||||
devm_rtc_nvmem_register(cmos_rtc.rtc, &nvmem_cfg);
|
||||
|
||||
/*
|
||||
* Everything has gone well so far, so by default register a handler for
|
||||
* the ACPI RTC fixed event.
|
||||
*/
|
||||
if (!info)
|
||||
acpi_rtc_event_setup(dev);
|
||||
|
||||
dev_info(dev, "%s%s, %d bytes nvram%s\n",
|
||||
!is_valid_irq(rtc_irq) ? "no alarms" :
|
||||
cmos_rtc.mon_alrm ? "alarms up to one year" :
|
||||
@ -973,6 +1150,9 @@ static void cmos_do_remove(struct device *dev)
|
||||
hpet_unregister_irq_handler(cmos_interrupt);
|
||||
}
|
||||
|
||||
if (!dev_get_platdata(dev))
|
||||
acpi_rtc_event_cleanup();
|
||||
|
||||
cmos->rtc = NULL;
|
||||
|
||||
ports = cmos->iomem;
|
||||
@ -1122,9 +1302,6 @@ static void cmos_check_wkalrm(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void cmos_check_acpi_rtc_status(struct device *dev,
|
||||
unsigned char *rtc_control);
|
||||
|
||||
static int __maybe_unused cmos_resume(struct device *dev)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
@ -1191,175 +1368,13 @@ static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
|
||||
* predate even PNPBIOS should set up platform_bus devices.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
#include <linux/acpi.h>
|
||||
|
||||
static u32 rtc_handler(void *context)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
unsigned char rtc_control = 0;
|
||||
unsigned char rtc_intr;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
/*
|
||||
* Always update rtc irq when ACPI is used as RTC Alarm.
|
||||
* Or else, ACPI SCI is enabled during suspend/resume only,
|
||||
* update rtc irq in that case.
|
||||
*/
|
||||
if (cmos_use_acpi_alarm())
|
||||
cmos_interrupt(0, (void *)cmos->rtc);
|
||||
else {
|
||||
/* Fix me: can we use cmos_interrupt() here as well? */
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
if (cmos_rtc.suspend_ctrl)
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
if (rtc_control & RTC_AIE) {
|
||||
cmos_rtc.suspend_ctrl &= ~RTC_AIE;
|
||||
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
||||
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
|
||||
rtc_update_irq(cmos->rtc, 1, rtc_intr);
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
}
|
||||
|
||||
pm_wakeup_hard_event(dev);
|
||||
acpi_clear_event(ACPI_EVENT_RTC);
|
||||
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
||||
return ACPI_INTERRUPT_HANDLED;
|
||||
}
|
||||
|
||||
static inline void rtc_wake_setup(struct device *dev)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, dev);
|
||||
/*
|
||||
* After the RTC handler is installed, the Fixed_RTC event should
|
||||
* be disabled. Only when the RTC alarm is set will it be enabled.
|
||||
*/
|
||||
acpi_clear_event(ACPI_EVENT_RTC);
|
||||
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
||||
}
|
||||
|
||||
static void rtc_wake_on(struct device *dev)
|
||||
{
|
||||
acpi_clear_event(ACPI_EVENT_RTC);
|
||||
acpi_enable_event(ACPI_EVENT_RTC, 0);
|
||||
}
|
||||
|
||||
static void rtc_wake_off(struct device *dev)
|
||||
{
|
||||
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/* Enable use_acpi_alarm mode for Intel platforms no earlier than 2015 */
|
||||
static void use_acpi_alarm_quirks(void)
|
||||
{
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
|
||||
return;
|
||||
|
||||
if (!is_hpet_enabled())
|
||||
return;
|
||||
|
||||
if (dmi_get_bios_year() < 2015)
|
||||
return;
|
||||
|
||||
use_acpi_alarm = true;
|
||||
}
|
||||
#else
|
||||
static inline void use_acpi_alarm_quirks(void) { }
|
||||
#endif
|
||||
|
||||
/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
|
||||
* its device node and pass extra config data. This helps its driver use
|
||||
* capabilities that the now-obsolete mc146818 didn't have, and informs it
|
||||
* that this board's RTC is wakeup-capable (per ACPI spec).
|
||||
*/
|
||||
static struct cmos_rtc_board_info acpi_rtc_info;
|
||||
|
||||
static void cmos_wake_setup(struct device *dev)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
use_acpi_alarm_quirks();
|
||||
|
||||
acpi_rtc_info.wake_on = rtc_wake_on;
|
||||
acpi_rtc_info.wake_off = rtc_wake_off;
|
||||
|
||||
/* workaround bug in some ACPI tables */
|
||||
if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
|
||||
dev_dbg(dev, "bogus FADT month_alarm (%d)\n",
|
||||
acpi_gbl_FADT.month_alarm);
|
||||
acpi_gbl_FADT.month_alarm = 0;
|
||||
}
|
||||
|
||||
acpi_rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
|
||||
acpi_rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
|
||||
acpi_rtc_info.rtc_century = acpi_gbl_FADT.century;
|
||||
|
||||
/* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */
|
||||
if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
|
||||
dev_info(dev, "RTC can wake from S4\n");
|
||||
|
||||
dev->platform_data = &acpi_rtc_info;
|
||||
|
||||
/* RTC always wakes from S1/S2/S3, and often S4/STD */
|
||||
device_init_wakeup(dev, 1);
|
||||
}
|
||||
|
||||
static void cmos_check_acpi_rtc_status(struct device *dev,
|
||||
unsigned char *rtc_control)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
acpi_event_status rtc_status;
|
||||
acpi_status status;
|
||||
|
||||
if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC)
|
||||
return;
|
||||
|
||||
status = acpi_get_event_status(ACPI_EVENT_RTC, &rtc_status);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "Could not get RTC status\n");
|
||||
} else if (rtc_status & ACPI_EVENT_FLAG_SET) {
|
||||
unsigned char mask;
|
||||
*rtc_control &= ~RTC_AIE;
|
||||
CMOS_WRITE(*rtc_control, RTC_CONTROL);
|
||||
mask = CMOS_READ(RTC_INTR_FLAGS);
|
||||
rtc_update_irq(cmos->rtc, 1, mask);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void cmos_wake_setup(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static void cmos_check_acpi_rtc_status(struct device *dev,
|
||||
unsigned char *rtc_control)
|
||||
{
|
||||
}
|
||||
|
||||
static void rtc_wake_setup(struct device *dev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
|
||||
#include <linux/pnp.h>
|
||||
|
||||
static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
||||
{
|
||||
int irq, ret;
|
||||
|
||||
cmos_wake_setup(&pnp->dev);
|
||||
int irq;
|
||||
|
||||
if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) {
|
||||
irq = 0;
|
||||
@ -1375,13 +1390,7 @@ static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
||||
irq = pnp_irq(pnp, 0);
|
||||
}
|
||||
|
||||
ret = cmos_do_probe(&pnp->dev, pnp_get_resource(pnp, IORESOURCE_IO, 0), irq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtc_wake_setup(&pnp->dev);
|
||||
|
||||
return 0;
|
||||
return cmos_do_probe(&pnp->dev, pnp_get_resource(pnp, IORESOURCE_IO, 0), irq);
|
||||
}
|
||||
|
||||
static void cmos_pnp_remove(struct pnp_dev *pnp)
|
||||
@ -1465,10 +1474,9 @@ static inline void cmos_of_init(struct platform_device *pdev) {}
|
||||
static int __init cmos_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *resource;
|
||||
int irq, ret;
|
||||
int irq;
|
||||
|
||||
cmos_of_init(pdev);
|
||||
cmos_wake_setup(&pdev->dev);
|
||||
|
||||
if (RTC_IOMAPPED)
|
||||
resource = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
@ -1478,13 +1486,7 @@ static int __init cmos_platform_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
irq = -1;
|
||||
|
||||
ret = cmos_do_probe(&pdev->dev, resource, irq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtc_wake_setup(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
return cmos_do_probe(&pdev->dev, resource, irq);
|
||||
}
|
||||
|
||||
static int cmos_platform_remove(struct platform_device *pdev)
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#define DRV_NAME "cros-ec-rtc"
|
||||
|
||||
#define SECS_PER_DAY (24 * 60 * 60)
|
||||
|
||||
/**
|
||||
* struct cros_ec_rtc - Driver data for EC RTC
|
||||
*
|
||||
@ -43,13 +45,8 @@ static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command,
|
||||
msg.msg.insize = sizeof(msg.data);
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
|
||||
if (ret < 0) {
|
||||
dev_err(cros_ec->dev,
|
||||
"error getting %s from EC: %d\n",
|
||||
command == EC_CMD_RTC_GET_VALUE ? "time" : "alarm",
|
||||
ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*response = msg.data.time;
|
||||
|
||||
@ -59,7 +56,7 @@ static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command,
|
||||
static int cros_ec_rtc_set(struct cros_ec_device *cros_ec, u32 command,
|
||||
u32 param)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_response_rtc data;
|
||||
@ -71,13 +68,8 @@ static int cros_ec_rtc_set(struct cros_ec_device *cros_ec, u32 command,
|
||||
msg.data.time = param;
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg);
|
||||
if (ret < 0) {
|
||||
dev_err(cros_ec->dev, "error setting %s on EC: %d\n",
|
||||
command == EC_CMD_RTC_SET_VALUE ? "time" : "alarm",
|
||||
ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -190,8 +182,21 @@ static int cros_ec_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "error setting alarm: %d\n", ret);
|
||||
return ret;
|
||||
if (ret == -EINVAL && alarm_offset >= SECS_PER_DAY) {
|
||||
/*
|
||||
* RTC chips on some older Chromebooks can only handle
|
||||
* alarms up to 24h in the future. Try to set an alarm
|
||||
* below that limit to avoid suspend failures.
|
||||
*/
|
||||
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM,
|
||||
SECS_PER_DAY - 1);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "error setting alarm in %u seconds: %d\n",
|
||||
alarm_offset, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1,512 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* DaVinci Power Management and Real Time Clock Driver for TI platforms
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments, Inc
|
||||
*
|
||||
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* The DaVinci RTC is a simple RTC with the following
|
||||
* Sec: 0 - 59 : BCD count
|
||||
* Min: 0 - 59 : BCD count
|
||||
* Hour: 0 - 23 : BCD count
|
||||
* Day: 0 - 0x7FFF(32767) : Binary count ( Over 89 years )
|
||||
*/
|
||||
|
||||
/* PRTC interface registers */
|
||||
#define DAVINCI_PRTCIF_PID 0x00
|
||||
#define PRTCIF_CTLR 0x04
|
||||
#define PRTCIF_LDATA 0x08
|
||||
#define PRTCIF_UDATA 0x0C
|
||||
#define PRTCIF_INTEN 0x10
|
||||
#define PRTCIF_INTFLG 0x14
|
||||
|
||||
/* PRTCIF_CTLR bit fields */
|
||||
#define PRTCIF_CTLR_BUSY BIT(31)
|
||||
#define PRTCIF_CTLR_SIZE BIT(25)
|
||||
#define PRTCIF_CTLR_DIR BIT(24)
|
||||
#define PRTCIF_CTLR_BENU_MSB BIT(23)
|
||||
#define PRTCIF_CTLR_BENU_3RD_BYTE BIT(22)
|
||||
#define PRTCIF_CTLR_BENU_2ND_BYTE BIT(21)
|
||||
#define PRTCIF_CTLR_BENU_LSB BIT(20)
|
||||
#define PRTCIF_CTLR_BENU_MASK (0x00F00000)
|
||||
#define PRTCIF_CTLR_BENL_MSB BIT(19)
|
||||
#define PRTCIF_CTLR_BENL_3RD_BYTE BIT(18)
|
||||
#define PRTCIF_CTLR_BENL_2ND_BYTE BIT(17)
|
||||
#define PRTCIF_CTLR_BENL_LSB BIT(16)
|
||||
#define PRTCIF_CTLR_BENL_MASK (0x000F0000)
|
||||
|
||||
/* PRTCIF_INTEN bit fields */
|
||||
#define PRTCIF_INTEN_RTCSS BIT(1)
|
||||
#define PRTCIF_INTEN_RTCIF BIT(0)
|
||||
#define PRTCIF_INTEN_MASK (PRTCIF_INTEN_RTCSS \
|
||||
| PRTCIF_INTEN_RTCIF)
|
||||
|
||||
/* PRTCIF_INTFLG bit fields */
|
||||
#define PRTCIF_INTFLG_RTCSS BIT(1)
|
||||
#define PRTCIF_INTFLG_RTCIF BIT(0)
|
||||
#define PRTCIF_INTFLG_MASK (PRTCIF_INTFLG_RTCSS \
|
||||
| PRTCIF_INTFLG_RTCIF)
|
||||
|
||||
/* PRTC subsystem registers */
|
||||
#define PRTCSS_RTC_INTC_EXTENA1 (0x0C)
|
||||
#define PRTCSS_RTC_CTRL (0x10)
|
||||
#define PRTCSS_RTC_WDT (0x11)
|
||||
#define PRTCSS_RTC_TMR0 (0x12)
|
||||
#define PRTCSS_RTC_TMR1 (0x13)
|
||||
#define PRTCSS_RTC_CCTRL (0x14)
|
||||
#define PRTCSS_RTC_SEC (0x15)
|
||||
#define PRTCSS_RTC_MIN (0x16)
|
||||
#define PRTCSS_RTC_HOUR (0x17)
|
||||
#define PRTCSS_RTC_DAY0 (0x18)
|
||||
#define PRTCSS_RTC_DAY1 (0x19)
|
||||
#define PRTCSS_RTC_AMIN (0x1A)
|
||||
#define PRTCSS_RTC_AHOUR (0x1B)
|
||||
#define PRTCSS_RTC_ADAY0 (0x1C)
|
||||
#define PRTCSS_RTC_ADAY1 (0x1D)
|
||||
#define PRTCSS_RTC_CLKC_CNT (0x20)
|
||||
|
||||
/* PRTCSS_RTC_INTC_EXTENA1 */
|
||||
#define PRTCSS_RTC_INTC_EXTENA1_MASK (0x07)
|
||||
|
||||
/* PRTCSS_RTC_CTRL bit fields */
|
||||
#define PRTCSS_RTC_CTRL_WDTBUS BIT(7)
|
||||
#define PRTCSS_RTC_CTRL_WEN BIT(6)
|
||||
#define PRTCSS_RTC_CTRL_WDRT BIT(5)
|
||||
#define PRTCSS_RTC_CTRL_WDTFLG BIT(4)
|
||||
#define PRTCSS_RTC_CTRL_TE BIT(3)
|
||||
#define PRTCSS_RTC_CTRL_TIEN BIT(2)
|
||||
#define PRTCSS_RTC_CTRL_TMRFLG BIT(1)
|
||||
#define PRTCSS_RTC_CTRL_TMMD BIT(0)
|
||||
|
||||
/* PRTCSS_RTC_CCTRL bit fields */
|
||||
#define PRTCSS_RTC_CCTRL_CALBUSY BIT(7)
|
||||
#define PRTCSS_RTC_CCTRL_DAEN BIT(5)
|
||||
#define PRTCSS_RTC_CCTRL_HAEN BIT(4)
|
||||
#define PRTCSS_RTC_CCTRL_MAEN BIT(3)
|
||||
#define PRTCSS_RTC_CCTRL_ALMFLG BIT(2)
|
||||
#define PRTCSS_RTC_CCTRL_AIEN BIT(1)
|
||||
#define PRTCSS_RTC_CCTRL_CAEN BIT(0)
|
||||
|
||||
static DEFINE_SPINLOCK(davinci_rtc_lock);
|
||||
|
||||
struct davinci_rtc {
|
||||
struct rtc_device *rtc;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static inline void rtcif_write(struct davinci_rtc *davinci_rtc,
|
||||
u32 val, u32 addr)
|
||||
{
|
||||
writel(val, davinci_rtc->base + addr);
|
||||
}
|
||||
|
||||
static inline u32 rtcif_read(struct davinci_rtc *davinci_rtc, u32 addr)
|
||||
{
|
||||
return readl(davinci_rtc->base + addr);
|
||||
}
|
||||
|
||||
static inline void rtcif_wait(struct davinci_rtc *davinci_rtc)
|
||||
{
|
||||
while (rtcif_read(davinci_rtc, PRTCIF_CTLR) & PRTCIF_CTLR_BUSY)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static inline void rtcss_write(struct davinci_rtc *davinci_rtc,
|
||||
unsigned long val, u8 addr)
|
||||
{
|
||||
rtcif_wait(davinci_rtc);
|
||||
|
||||
rtcif_write(davinci_rtc, PRTCIF_CTLR_BENL_LSB | addr, PRTCIF_CTLR);
|
||||
rtcif_write(davinci_rtc, val, PRTCIF_LDATA);
|
||||
|
||||
rtcif_wait(davinci_rtc);
|
||||
}
|
||||
|
||||
static inline u8 rtcss_read(struct davinci_rtc *davinci_rtc, u8 addr)
|
||||
{
|
||||
rtcif_wait(davinci_rtc);
|
||||
|
||||
rtcif_write(davinci_rtc, PRTCIF_CTLR_DIR | PRTCIF_CTLR_BENL_LSB | addr,
|
||||
PRTCIF_CTLR);
|
||||
|
||||
rtcif_wait(davinci_rtc);
|
||||
|
||||
return rtcif_read(davinci_rtc, PRTCIF_LDATA);
|
||||
}
|
||||
|
||||
static inline void davinci_rtcss_calendar_wait(struct davinci_rtc *davinci_rtc)
|
||||
{
|
||||
while (rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) &
|
||||
PRTCSS_RTC_CCTRL_CALBUSY)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static irqreturn_t davinci_rtc_interrupt(int irq, void *class_dev)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = class_dev;
|
||||
unsigned long events = 0;
|
||||
u32 irq_flg;
|
||||
u8 alm_irq, tmr_irq;
|
||||
u8 rtc_ctrl, rtc_cctrl;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
irq_flg = rtcif_read(davinci_rtc, PRTCIF_INTFLG) &
|
||||
PRTCIF_INTFLG_RTCSS;
|
||||
|
||||
alm_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) &
|
||||
PRTCSS_RTC_CCTRL_ALMFLG;
|
||||
|
||||
tmr_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL) &
|
||||
PRTCSS_RTC_CTRL_TMRFLG;
|
||||
|
||||
if (irq_flg) {
|
||||
if (alm_irq) {
|
||||
events |= RTC_IRQF | RTC_AF;
|
||||
rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL);
|
||||
rtc_cctrl |= PRTCSS_RTC_CCTRL_ALMFLG;
|
||||
rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL);
|
||||
} else if (tmr_irq) {
|
||||
events |= RTC_IRQF | RTC_PF;
|
||||
rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL);
|
||||
rtc_ctrl |= PRTCSS_RTC_CTRL_TMRFLG;
|
||||
rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
|
||||
}
|
||||
|
||||
rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS,
|
||||
PRTCIF_INTFLG);
|
||||
rtc_update_irq(davinci_rtc->rtc, 1, events);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
davinci_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
|
||||
u8 rtc_ctrl;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL);
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_WIE_ON:
|
||||
rtc_ctrl |= PRTCSS_RTC_CTRL_WEN | PRTCSS_RTC_CTRL_WDTFLG;
|
||||
break;
|
||||
case RTC_WIE_OFF:
|
||||
rtc_ctrl &= ~PRTCSS_RTC_CTRL_WEN;
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
|
||||
|
||||
spin_unlock_irqrestore(&davinci_rtc_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void convertfromdays(u16 days, struct rtc_time *tm)
|
||||
{
|
||||
int tmp_days, year, mon;
|
||||
|
||||
for (year = 2000;; year++) {
|
||||
tmp_days = rtc_year_days(1, 12, year);
|
||||
if (days >= tmp_days)
|
||||
days -= tmp_days;
|
||||
else {
|
||||
for (mon = 0;; mon++) {
|
||||
tmp_days = rtc_month_days(mon, year);
|
||||
if (days >= tmp_days) {
|
||||
days -= tmp_days;
|
||||
} else {
|
||||
tm->tm_year = year - 1900;
|
||||
tm->tm_mon = mon;
|
||||
tm->tm_mday = days + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void convert2days(u16 *days, struct rtc_time *tm)
|
||||
{
|
||||
int i;
|
||||
*days = 0;
|
||||
|
||||
for (i = 2000; i < 1900 + tm->tm_year; i++)
|
||||
*days += rtc_year_days(1, 12, i);
|
||||
|
||||
*days += rtc_year_days(tm->tm_mday, tm->tm_mon, 1900 + tm->tm_year);
|
||||
}
|
||||
|
||||
static int davinci_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
|
||||
u16 days = 0;
|
||||
u8 day0, day1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
tm->tm_sec = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_SEC));
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
tm->tm_min = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_MIN));
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
tm->tm_hour = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_HOUR));
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
day0 = rtcss_read(davinci_rtc, PRTCSS_RTC_DAY0);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
day1 = rtcss_read(davinci_rtc, PRTCSS_RTC_DAY1);
|
||||
|
||||
spin_unlock_irqrestore(&davinci_rtc_lock, flags);
|
||||
|
||||
days |= day1;
|
||||
days <<= 8;
|
||||
days |= day0;
|
||||
|
||||
convertfromdays(days, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
|
||||
u16 days;
|
||||
u8 rtc_cctrl;
|
||||
unsigned long flags;
|
||||
|
||||
convert2days(&days, tm);
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, bin2bcd(tm->tm_sec), PRTCSS_RTC_SEC);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, bin2bcd(tm->tm_min), PRTCSS_RTC_MIN);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, bin2bcd(tm->tm_hour), PRTCSS_RTC_HOUR);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_DAY0);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_DAY1);
|
||||
|
||||
rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL);
|
||||
rtc_cctrl |= PRTCSS_RTC_CCTRL_CAEN;
|
||||
rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL);
|
||||
|
||||
spin_unlock_irqrestore(&davinci_rtc_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enabled)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
u8 rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL);
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
if (enabled)
|
||||
rtc_cctrl |= PRTCSS_RTC_CCTRL_DAEN |
|
||||
PRTCSS_RTC_CCTRL_HAEN |
|
||||
PRTCSS_RTC_CCTRL_MAEN |
|
||||
PRTCSS_RTC_CCTRL_ALMFLG |
|
||||
PRTCSS_RTC_CCTRL_AIEN;
|
||||
else
|
||||
rtc_cctrl &= ~PRTCSS_RTC_CCTRL_AIEN;
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL);
|
||||
|
||||
spin_unlock_irqrestore(&davinci_rtc_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
|
||||
u16 days = 0;
|
||||
u8 day0, day1;
|
||||
unsigned long flags;
|
||||
|
||||
alm->time.tm_sec = 0;
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
alm->time.tm_min = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_AMIN));
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
alm->time.tm_hour = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_AHOUR));
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
day0 = rtcss_read(davinci_rtc, PRTCSS_RTC_ADAY0);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
day1 = rtcss_read(davinci_rtc, PRTCSS_RTC_ADAY1);
|
||||
|
||||
spin_unlock_irqrestore(&davinci_rtc_lock, flags);
|
||||
days |= day1;
|
||||
days <<= 8;
|
||||
days |= day0;
|
||||
|
||||
convertfromdays(days, &alm->time);
|
||||
|
||||
alm->pending = !!(rtcss_read(davinci_rtc,
|
||||
PRTCSS_RTC_CCTRL) &
|
||||
PRTCSS_RTC_CCTRL_AIEN);
|
||||
alm->enabled = alm->pending && device_may_wakeup(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
u16 days;
|
||||
|
||||
convert2days(&days, &alm->time);
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_min), PRTCSS_RTC_AMIN);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_hour), PRTCSS_RTC_AHOUR);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_ADAY0);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_ADAY1);
|
||||
|
||||
spin_unlock_irqrestore(&davinci_rtc_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops davinci_rtc_ops = {
|
||||
.ioctl = davinci_rtc_ioctl,
|
||||
.read_time = davinci_rtc_read_time,
|
||||
.set_time = davinci_rtc_set_time,
|
||||
.alarm_irq_enable = davinci_rtc_alarm_irq_enable,
|
||||
.read_alarm = davinci_rtc_read_alarm,
|
||||
.set_alarm = davinci_rtc_set_alarm,
|
||||
};
|
||||
|
||||
static int __init davinci_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct davinci_rtc *davinci_rtc;
|
||||
int ret = 0;
|
||||
|
||||
davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL);
|
||||
if (!davinci_rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
davinci_rtc->irq = platform_get_irq(pdev, 0);
|
||||
if (davinci_rtc->irq < 0)
|
||||
return davinci_rtc->irq;
|
||||
|
||||
davinci_rtc->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(davinci_rtc->base))
|
||||
return PTR_ERR(davinci_rtc->base);
|
||||
|
||||
platform_set_drvdata(pdev, davinci_rtc);
|
||||
|
||||
davinci_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(davinci_rtc->rtc))
|
||||
return PTR_ERR(davinci_rtc->rtc);
|
||||
|
||||
davinci_rtc->rtc->ops = &davinci_rtc_ops;
|
||||
davinci_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
davinci_rtc->rtc->range_max = RTC_TIMESTAMP_BEGIN_2000 + (1 << 16) * 86400ULL - 1;
|
||||
|
||||
rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
|
||||
rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
|
||||
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_INTC_EXTENA1);
|
||||
|
||||
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL);
|
||||
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
|
||||
|
||||
ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt,
|
||||
0, "davinci_rtc", davinci_rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to register davinci RTC interrupt\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
rtcif_write(davinci_rtc, PRTCIF_INTEN_RTCSS, PRTCIF_INTEN);
|
||||
rtcss_write(davinci_rtc, PRTCSS_RTC_INTC_EXTENA1_MASK,
|
||||
PRTCSS_RTC_INTC_EXTENA1);
|
||||
|
||||
rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
return devm_rtc_register_device(davinci_rtc->rtc);
|
||||
}
|
||||
|
||||
static int __exit davinci_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_rtc *davinci_rtc = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver davinci_rtc_driver = {
|
||||
.remove = __exit_p(davinci_rtc_remove),
|
||||
.driver = {
|
||||
.name = "rtc_davinci",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(davinci_rtc_driver, davinci_rtc_probe);
|
||||
|
||||
MODULE_AUTHOR("Miguel Aguilar <miguel.aguilar@ridgerun.com>");
|
||||
MODULE_DESCRIPTION("Texas Instruments DaVinci PRTC Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -185,11 +185,6 @@ static int ds1302_probe(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ds1302_remove(struct spi_device *spi)
|
||||
{
|
||||
spi_set_drvdata(spi, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ds1302_dt_ids[] = {
|
||||
{ .compatible = "maxim,ds1302", },
|
||||
@ -208,7 +203,6 @@ static struct spi_driver ds1302_driver = {
|
||||
.driver.name = "rtc-ds1302",
|
||||
.driver.of_match_table = of_match_ptr(ds1302_dt_ids),
|
||||
.probe = ds1302_probe,
|
||||
.remove = ds1302_remove,
|
||||
.id_table = ds1302_spi_ids,
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
@ -1218,8 +1219,7 @@ static ssize_t frequency_test_show(struct device *dev,
|
||||
|
||||
regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, (ctrl_reg & M41TXX_BIT_FT) ? "on\n" :
|
||||
"off\n");
|
||||
return sysfs_emit(buf, (ctrl_reg & M41TXX_BIT_FT) ? "on\n" : "off\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(frequency_test);
|
||||
|
@ -112,7 +112,7 @@ static int ds1347_set_time(struct device *dev, struct rtc_time *dt)
|
||||
return err;
|
||||
|
||||
century = (dt->tm_year / 100) + 19;
|
||||
err = regmap_write(map, DS1347_CENTURY_REG, century);
|
||||
err = regmap_write(map, DS1347_CENTURY_REG, bin2bcd(century));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -158,8 +158,7 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(ioaddr))
|
||||
return PTR_ERR(ioaddr);
|
||||
|
||||
|
@ -271,6 +271,8 @@ static int __init efi_rtc_probe(struct platform_device *dev)
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
|
||||
set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features);
|
||||
|
||||
device_init_wakeup(&dev->dev, true);
|
||||
|
||||
return devm_rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
|
@ -327,12 +327,7 @@ static struct platform_driver ftm_rtc_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ftm_alarm_init(void)
|
||||
{
|
||||
return platform_driver_register(&ftm_rtc_driver);
|
||||
}
|
||||
|
||||
device_initcall(ftm_alarm_init);
|
||||
module_platform_driver(ftm_rtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("NXP/Freescale FlexTimer alarm driver");
|
||||
MODULE_AUTHOR("Biwen Li <biwen.li@nxp.com>");
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/hwmon.h>
|
||||
|
||||
/* ISL register offsets */
|
||||
#define ISL12022_REG_SC 0x00
|
||||
@ -30,6 +31,9 @@
|
||||
#define ISL12022_REG_SR 0x07
|
||||
#define ISL12022_REG_INT 0x08
|
||||
|
||||
#define ISL12022_REG_BETA 0x0d
|
||||
#define ISL12022_REG_TEMP_L 0x28
|
||||
|
||||
/* ISL register bits */
|
||||
#define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */
|
||||
|
||||
@ -38,6 +42,7 @@
|
||||
|
||||
#define ISL12022_INT_WRTC (1 << 6)
|
||||
|
||||
#define ISL12022_BETA_TSE (1 << 7)
|
||||
|
||||
static struct i2c_driver isl12022_driver;
|
||||
|
||||
@ -46,6 +51,93 @@ struct isl12022 {
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static umode_t isl12022_hwmon_is_visible(const void *data,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
if (type == hwmon_temp && attr == hwmon_temp_input)
|
||||
return 0444;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A user-initiated temperature conversion is not started by this function,
|
||||
* so the temperature is updated once every ~60 seconds.
|
||||
*/
|
||||
static int isl12022_hwmon_read_temp(struct device *dev, long *mC)
|
||||
{
|
||||
struct isl12022 *isl12022 = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = isl12022->regmap;
|
||||
u8 temp_buf[2];
|
||||
int temp, ret;
|
||||
|
||||
ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L,
|
||||
temp_buf, sizeof(temp_buf));
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* Temperature is represented as a 10-bit number, unit half-Kelvins.
|
||||
*/
|
||||
temp = (temp_buf[1] << 8) | temp_buf[0];
|
||||
temp *= 500;
|
||||
temp -= 273000;
|
||||
|
||||
*mC = temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isl12022_hwmon_read(struct device *dev,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
if (type == hwmon_temp && attr == hwmon_temp_input)
|
||||
return isl12022_hwmon_read_temp(dev, val);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *isl12022_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops isl12022_hwmon_ops = {
|
||||
.is_visible = isl12022_hwmon_is_visible,
|
||||
.read = isl12022_hwmon_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info isl12022_hwmon_chip_info = {
|
||||
.ops = &isl12022_hwmon_ops,
|
||||
.info = isl12022_hwmon_info,
|
||||
};
|
||||
|
||||
static void isl12022_hwmon_register(struct device *dev)
|
||||
{
|
||||
struct isl12022 *isl12022;
|
||||
struct device *hwmon;
|
||||
int ret;
|
||||
|
||||
if (!IS_REACHABLE(CONFIG_HWMON))
|
||||
return;
|
||||
|
||||
isl12022 = dev_get_drvdata(dev);
|
||||
|
||||
ret = regmap_update_bits(isl12022->regmap, ISL12022_REG_BETA,
|
||||
ISL12022_BETA_TSE, ISL12022_BETA_TSE);
|
||||
if (ret) {
|
||||
dev_warn(dev, "unable to enable temperature sensor\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", isl12022,
|
||||
&isl12022_hwmon_chip_info,
|
||||
NULL);
|
||||
if (IS_ERR(hwmon))
|
||||
dev_warn(dev, "unable to register hwmon device: %pe\n", hwmon);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the routines that deal directly with the isl12022 hardware, we use
|
||||
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
|
||||
@ -160,6 +252,8 @@ static int isl12022_probe(struct i2c_client *client)
|
||||
return PTR_ERR(isl12022->regmap);
|
||||
}
|
||||
|
||||
isl12022_hwmon_register(&client->dev);
|
||||
|
||||
isl12022->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(isl12022->rtc))
|
||||
return PTR_ERR(isl12022->rtc);
|
||||
|
@ -797,7 +797,7 @@ static int isl1208_setup_irq(struct i2c_client *client, int irq)
|
||||
}
|
||||
|
||||
static int
|
||||
isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
isl1208_probe(struct i2c_client *client)
|
||||
{
|
||||
int rc = 0;
|
||||
struct isl1208_state *isl1208;
|
||||
@ -821,6 +821,8 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
if (!isl1208->config)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
const struct i2c_device_id *id = i2c_match_id(isl1208_id, client);
|
||||
|
||||
if (id->driver_data >= ISL_LAST_ID)
|
||||
return -ENODEV;
|
||||
isl1208->config = &isl1208_configs[id->driver_data];
|
||||
@ -906,7 +908,7 @@ static struct i2c_driver isl1208_driver = {
|
||||
.name = "rtc-isl1208",
|
||||
.of_match_table = of_match_ptr(isl1208_of_match),
|
||||
},
|
||||
.probe = isl1208_probe,
|
||||
.probe_new = isl1208_probe,
|
||||
.id_table = isl1208_id,
|
||||
};
|
||||
|
||||
|
@ -692,7 +692,7 @@ static void wdt_disable(void)
|
||||
* @ppos: pointer to the position to write. No seeks allowed
|
||||
*
|
||||
* A write to a watchdog device is defined as a keepalive signal. Any
|
||||
* write of data will do, as we we don't define content meaning.
|
||||
* write of data will do, as we don't define content meaning.
|
||||
*/
|
||||
static ssize_t wdt_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@ -876,8 +876,7 @@ static struct notifier_block wdt_notifier = {
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
static int m41t80_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int m41t80_probe(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
int rc = 0;
|
||||
@ -897,11 +896,13 @@ static int m41t80_probe(struct i2c_client *client,
|
||||
return -ENOMEM;
|
||||
|
||||
m41t80_data->client = client;
|
||||
if (client->dev.of_node)
|
||||
if (client->dev.of_node) {
|
||||
m41t80_data->features = (unsigned long)
|
||||
of_device_get_match_data(&client->dev);
|
||||
else
|
||||
} else {
|
||||
const struct i2c_device_id *id = i2c_match_id(m41t80_id, client);
|
||||
m41t80_data->features = id->driver_data;
|
||||
}
|
||||
i2c_set_clientdata(client, m41t80_data);
|
||||
|
||||
m41t80_data->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
@ -1007,7 +1008,7 @@ static struct i2c_driver m41t80_driver = {
|
||||
.of_match_table = of_match_ptr(m41t80_of_match),
|
||||
.pm = &m41t80_pm,
|
||||
},
|
||||
.probe = m41t80_probe,
|
||||
.probe_new = m41t80_probe,
|
||||
.remove = m41t80_remove,
|
||||
.id_table = m41t80_id,
|
||||
};
|
||||
|
@ -212,22 +212,12 @@ static int msc313_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(dev, NULL);
|
||||
clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "No input reference clock\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable the reference clock, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
writew(rate & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_L);
|
||||
writew((rate >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_H);
|
||||
|
@ -336,8 +336,10 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(pdata->rtc))
|
||||
if (IS_ERR(pdata->rtc)) {
|
||||
clk_disable_unprepare(pdata->clk);
|
||||
return PTR_ERR(pdata->rtc);
|
||||
}
|
||||
|
||||
pdata->rtc->ops = &mxc_rtc_ops;
|
||||
pdata->rtc->range_max = U32_MAX;
|
||||
|
@ -452,8 +452,7 @@ static const struct rtc_class_ops nct3018y_rtc_ops = {
|
||||
.ioctl = nct3018y_ioctl,
|
||||
};
|
||||
|
||||
static int nct3018y_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int nct3018y_probe(struct i2c_client *client)
|
||||
{
|
||||
struct nct3018y *nct3018y;
|
||||
int err, flags;
|
||||
@ -541,7 +540,7 @@ static struct i2c_driver nct3018y_driver = {
|
||||
.name = "rtc-nct3018y",
|
||||
.of_match_table = of_match_ptr(nct3018y_of_match),
|
||||
},
|
||||
.probe = nct3018y_probe,
|
||||
.probe_new = nct3018y_probe,
|
||||
.id_table = nct3018y_id,
|
||||
};
|
||||
|
||||
|
@ -885,9 +885,17 @@ static const struct regmap_bus pcf2127_i2c_regmap = {
|
||||
|
||||
static struct i2c_driver pcf2127_i2c_driver;
|
||||
|
||||
static int pcf2127_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static const struct i2c_device_id pcf2127_i2c_id[] = {
|
||||
{ "pcf2127", 1 },
|
||||
{ "pcf2129", 0 },
|
||||
{ "pca2129", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);
|
||||
|
||||
static int pcf2127_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct i2c_device_id *id = i2c_match_id(pcf2127_i2c_id, client);
|
||||
struct regmap *regmap;
|
||||
static const struct regmap_config config = {
|
||||
.reg_bits = 8,
|
||||
@ -910,20 +918,12 @@ static int pcf2127_i2c_probe(struct i2c_client *client,
|
||||
pcf2127_i2c_driver.driver.name, id->driver_data);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id pcf2127_i2c_id[] = {
|
||||
{ "pcf2127", 1 },
|
||||
{ "pcf2129", 0 },
|
||||
{ "pca2129", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);
|
||||
|
||||
static struct i2c_driver pcf2127_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-pcf2127-i2c",
|
||||
.of_match_table = of_match_ptr(pcf2127_of_match),
|
||||
},
|
||||
.probe = pcf2127_i2c_probe,
|
||||
.probe_new = pcf2127_i2c_probe,
|
||||
.id_table = pcf2127_i2c_id,
|
||||
};
|
||||
|
||||
|
@ -169,10 +169,10 @@ static int pcf85063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
alrm->time.tm_sec = bcd2bin(buf[0]);
|
||||
alrm->time.tm_min = bcd2bin(buf[1]);
|
||||
alrm->time.tm_hour = bcd2bin(buf[2]);
|
||||
alrm->time.tm_mday = bcd2bin(buf[3]);
|
||||
alrm->time.tm_sec = bcd2bin(buf[0] & 0x7f);
|
||||
alrm->time.tm_min = bcd2bin(buf[1] & 0x7f);
|
||||
alrm->time.tm_hour = bcd2bin(buf[2] & 0x3f);
|
||||
alrm->time.tm_mday = bcd2bin(buf[3] & 0x3f);
|
||||
|
||||
ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &val);
|
||||
if (ret)
|
||||
@ -424,7 +424,7 @@ static int pcf85063_clkout_control(struct clk_hw *hw, bool enable)
|
||||
unsigned int buf;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(pcf85063->regmap, PCF85063_REG_OFFSET, &buf);
|
||||
ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
buf &= PCF85063_REG_CLKO_F_MASK;
|
||||
|
@ -99,24 +99,24 @@ static irqreturn_t pcf8523_irq(int irq, void *dev_id)
|
||||
static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pcf8523 *pcf8523 = dev_get_drvdata(dev);
|
||||
u8 regs[7];
|
||||
u8 regs[10];
|
||||
int err;
|
||||
|
||||
err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_SECONDS, regs,
|
||||
err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_CONTROL1, regs,
|
||||
sizeof(regs));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (regs[0] & PCF8523_SECONDS_OS)
|
||||
if ((regs[0] & PCF8523_CONTROL1_STOP) || (regs[3] & PCF8523_SECONDS_OS))
|
||||
return -EINVAL;
|
||||
|
||||
tm->tm_sec = bcd2bin(regs[0] & 0x7f);
|
||||
tm->tm_min = bcd2bin(regs[1] & 0x7f);
|
||||
tm->tm_hour = bcd2bin(regs[2] & 0x3f);
|
||||
tm->tm_mday = bcd2bin(regs[3] & 0x3f);
|
||||
tm->tm_wday = regs[4] & 0x7;
|
||||
tm->tm_mon = bcd2bin(regs[5] & 0x1f) - 1;
|
||||
tm->tm_year = bcd2bin(regs[6]) + 100;
|
||||
tm->tm_sec = bcd2bin(regs[3] & 0x7f);
|
||||
tm->tm_min = bcd2bin(regs[4] & 0x7f);
|
||||
tm->tm_hour = bcd2bin(regs[5] & 0x3f);
|
||||
tm->tm_mday = bcd2bin(regs[6] & 0x3f);
|
||||
tm->tm_wday = regs[7] & 0x7;
|
||||
tm->tm_mon = bcd2bin(regs[8] & 0x1f) - 1;
|
||||
tm->tm_year = bcd2bin(regs[9]) + 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -567,6 +567,8 @@ static int pcf8563_probe(struct i2c_client *client)
|
||||
client->irq);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
clear_bit(RTC_FEATURE_ALARM, pcf8563->rtc->features);
|
||||
}
|
||||
|
||||
err = devm_rtc_register_device(pcf8563->rtc);
|
||||
|
@ -324,16 +324,16 @@ static int pic32_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&pdata->alarm_lock);
|
||||
|
||||
pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(pdata->rtc))
|
||||
return PTR_ERR(pdata->rtc);
|
||||
|
||||
clk_prepare_enable(pdata->clk);
|
||||
|
||||
pic32_rtc_enable(pdata, 1);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(pdata->rtc))
|
||||
return PTR_ERR(pdata->rtc);
|
||||
|
||||
pdata->rtc->ops = &pic32_rtcops;
|
||||
pdata->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
pdata->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
@ -461,7 +461,6 @@ static const struct pm8xxx_rtc_regs pmk8350_regs = {
|
||||
*/
|
||||
static const struct of_device_id pm8xxx_id_table[] = {
|
||||
{ .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs },
|
||||
{ .compatible = "qcom,pm8018-rtc", .data = &pm8921_regs },
|
||||
{ .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs },
|
||||
{ .compatible = "qcom,pm8941-rtc", .data = &pm8941_regs },
|
||||
{ .compatible = "qcom,pmk8350-rtc", .data = &pmk8350_regs },
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/mfd/rk808.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
/* RTC_CTRL_REG bitfields */
|
||||
#define BIT_RTC_CTRL_REG_STOP_RTC_M BIT(0)
|
||||
@ -51,7 +50,7 @@ struct rk_rtc_compat_reg {
|
||||
};
|
||||
|
||||
struct rk808_rtc {
|
||||
struct rk808 *rk808;
|
||||
struct regmap *regmap;
|
||||
struct rtc_device *rtc;
|
||||
struct rk_rtc_compat_reg *creg;
|
||||
int irq;
|
||||
@ -97,12 +96,11 @@ static void gregorian_to_rockchip(struct rtc_time *tm)
|
||||
static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
u8 rtc_data[NUM_TIME_REGS];
|
||||
int ret;
|
||||
|
||||
/* Force an update of the shadowed registers right now */
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_RTC_GET_TIME,
|
||||
BIT_RTC_CTRL_REG_RTC_GET_TIME);
|
||||
if (ret) {
|
||||
@ -116,7 +114,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
* 32khz. If we clear the GET_TIME bit here, the time of i2c transfer
|
||||
* certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency.
|
||||
*/
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_RTC_GET_TIME,
|
||||
0);
|
||||
if (ret) {
|
||||
@ -124,7 +122,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(rk808->regmap, rk808_rtc->creg->seconds_reg,
|
||||
ret = regmap_bulk_read(rk808_rtc->regmap, rk808_rtc->creg->seconds_reg,
|
||||
rtc_data, NUM_TIME_REGS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret);
|
||||
@ -148,7 +146,6 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
u8 rtc_data[NUM_TIME_REGS];
|
||||
int ret;
|
||||
|
||||
@ -163,7 +160,7 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
rtc_data[6] = bin2bcd(tm->tm_wday);
|
||||
|
||||
/* Stop RTC while updating the RTC registers */
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M);
|
||||
if (ret) {
|
||||
@ -171,14 +168,14 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_write(rk808->regmap, rk808_rtc->creg->seconds_reg,
|
||||
ret = regmap_bulk_write(rk808_rtc->regmap, rk808_rtc->creg->seconds_reg,
|
||||
rtc_data, NUM_TIME_REGS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to bull write rtc_data: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/* Start RTC again */
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to update RTC control: %d\n", ret);
|
||||
@ -191,12 +188,11 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
u8 alrm_data[NUM_ALARM_REGS];
|
||||
uint32_t int_reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(rk808->regmap,
|
||||
ret = regmap_bulk_read(rk808_rtc->regmap,
|
||||
rk808_rtc->creg->alarm_seconds_reg,
|
||||
alrm_data, NUM_ALARM_REGS);
|
||||
if (ret) {
|
||||
@ -212,7 +208,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
|
||||
rockchip_to_gregorian(&alrm->time);
|
||||
|
||||
ret = regmap_read(rk808->regmap, rk808_rtc->creg->int_reg, &int_reg);
|
||||
ret = regmap_read(rk808_rtc->regmap, rk808_rtc->creg->int_reg, &int_reg);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read RTC INT REG: %d\n", ret);
|
||||
return ret;
|
||||
@ -228,10 +224,9 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc)
|
||||
{
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg,
|
||||
ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->int_reg,
|
||||
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, 0);
|
||||
|
||||
return ret;
|
||||
@ -239,10 +234,9 @@ static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc)
|
||||
|
||||
static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc)
|
||||
{
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg,
|
||||
ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->int_reg,
|
||||
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M,
|
||||
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
|
||||
|
||||
@ -252,7 +246,6 @@ static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc)
|
||||
static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
u8 alrm_data[NUM_ALARM_REGS];
|
||||
int ret;
|
||||
|
||||
@ -272,7 +265,7 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1);
|
||||
alrm_data[5] = bin2bcd(alrm->time.tm_year - 100);
|
||||
|
||||
ret = regmap_bulk_write(rk808->regmap,
|
||||
ret = regmap_bulk_write(rk808_rtc->regmap,
|
||||
rk808_rtc->creg->alarm_seconds_reg,
|
||||
alrm_data, NUM_ALARM_REGS);
|
||||
if (ret) {
|
||||
@ -313,20 +306,18 @@ static int rk808_rtc_alarm_irq_enable(struct device *dev,
|
||||
static irqreturn_t rk808_alarm_irq(int irq, void *data)
|
||||
{
|
||||
struct rk808_rtc *rk808_rtc = data;
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
struct i2c_client *client = rk808->i2c;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg,
|
||||
ret = regmap_write(rk808_rtc->regmap, rk808_rtc->creg->status_reg,
|
||||
RTC_STATUS_MASK);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
dev_err(&rk808_rtc->rtc->dev,
|
||||
"%s:Failed to update RTC status: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc_update_irq(rk808_rtc->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
dev_dbg(&client->dev,
|
||||
dev_dbg(&rk808_rtc->rtc->dev,
|
||||
"%s:irq=%d\n", __func__, irq);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -404,10 +395,12 @@ static int rk808_rtc_probe(struct platform_device *pdev)
|
||||
break;
|
||||
}
|
||||
platform_set_drvdata(pdev, rk808_rtc);
|
||||
rk808_rtc->rk808 = rk808;
|
||||
rk808_rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!rk808_rtc->regmap)
|
||||
return -ENODEV;
|
||||
|
||||
/* start rtc running by default, and use shadowed timer. */
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M |
|
||||
BIT_RTC_CTRL_REG_RTC_READSEL_M,
|
||||
BIT_RTC_CTRL_REG_RTC_READSEL_M);
|
||||
@ -417,7 +410,7 @@ static int rk808_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg,
|
||||
ret = regmap_write(rk808_rtc->regmap, rk808_rtc->creg->status_reg,
|
||||
RTC_STATUS_MASK);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Ricoh RS5C313 RTC device/driver
|
||||
* Copyright (C) 2007 Nobuhiro Iwamatsu
|
||||
*
|
||||
* 2005-09-19 modifed by kogiidena
|
||||
* 2005-09-19 modified by kogiidena
|
||||
*
|
||||
* Based on the old drivers/char/rs5c313_rtc.c by:
|
||||
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
|
||||
@ -36,7 +36,7 @@
|
||||
* 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init
|
||||
* 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
|
||||
* CONFIG_HPET_EMULATE_RTC
|
||||
* 1.13 Nobuhiro Iwamatsu: Updata driver.
|
||||
* 1.13 Nobuhiro Iwamatsu: Update driver.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -280,7 +280,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
while (1) {
|
||||
RS5C313_CEENABLE; /* CE:H */
|
||||
|
||||
/* Initiatlize control reg. 24 hour */
|
||||
/* Initialize control reg. 24 hour */
|
||||
rs5c313_write_cntreg(0x04);
|
||||
|
||||
if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
|
||||
|
@ -150,7 +150,7 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
|
||||
* least 80219 chips; this works around that bug.
|
||||
*
|
||||
* The third method on the other hand doesn't work for the SMBus-only
|
||||
* configurations, so we use the the first method there, stripping off
|
||||
* configurations, so we use the first method there, stripping off
|
||||
* the extra register in the process.
|
||||
*/
|
||||
if (rs5c->smbus) {
|
||||
@ -791,8 +791,7 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rs5c372_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int rs5c372_probe(struct i2c_client *client)
|
||||
{
|
||||
int err = 0;
|
||||
int smbus_mode = 0;
|
||||
@ -826,11 +825,13 @@ static int rs5c372_probe(struct i2c_client *client,
|
||||
|
||||
rs5c372->client = client;
|
||||
i2c_set_clientdata(client, rs5c372);
|
||||
if (client->dev.of_node)
|
||||
if (client->dev.of_node) {
|
||||
rs5c372->type = (enum rtc_type)
|
||||
of_device_get_match_data(&client->dev);
|
||||
else
|
||||
} else {
|
||||
const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client);
|
||||
rs5c372->type = id->driver_data;
|
||||
}
|
||||
|
||||
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
|
||||
rs5c372->regs = &rs5c372->buf[1];
|
||||
@ -920,7 +921,7 @@ static struct i2c_driver rs5c372_driver = {
|
||||
.name = "rtc-rs5c372",
|
||||
.of_match_table = of_match_ptr(rs5c372_of_match),
|
||||
},
|
||||
.probe = rs5c372_probe,
|
||||
.probe_new = rs5c372_probe,
|
||||
.remove = rs5c372_remove,
|
||||
.id_table = rs5c372_id,
|
||||
};
|
||||
|
@ -902,9 +902,20 @@ static int rv3028_probe(struct i2c_client *client)
|
||||
return PTR_ERR(rv3028->rtc);
|
||||
|
||||
if (client->irq > 0) {
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* If flags = 0, devm_request_threaded_irq() will use IRQ flags
|
||||
* obtained from device tree.
|
||||
*/
|
||||
if (dev_fwnode(&client->dev))
|
||||
flags = 0;
|
||||
else
|
||||
flags = IRQF_TRIGGER_LOW;
|
||||
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, rv3028_handle_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
flags | IRQF_ONESHOT,
|
||||
"rv3028", rv3028);
|
||||
if (ret) {
|
||||
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Register map */
|
||||
|
@ -576,8 +576,16 @@ static int rv8803_regs_configure(struct rv8803_data *rv8803)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv8803_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static const struct i2c_device_id rv8803_id[] = {
|
||||
{ "rv8803", rv_8803 },
|
||||
{ "rv8804", rx_8804 },
|
||||
{ "rx8803", rx_8803 },
|
||||
{ "rx8900", rx_8900 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rv8803_id);
|
||||
|
||||
static int rv8803_probe(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct rv8803_data *rv8803;
|
||||
@ -605,11 +613,14 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
|
||||
mutex_init(&rv8803->flags_lock);
|
||||
rv8803->client = client;
|
||||
if (client->dev.of_node)
|
||||
if (client->dev.of_node) {
|
||||
rv8803->type = (enum rv8803_type)
|
||||
of_device_get_match_data(&client->dev);
|
||||
else
|
||||
} else {
|
||||
const struct i2c_device_id *id = i2c_match_id(rv8803_id, client);
|
||||
|
||||
rv8803->type = id->driver_data;
|
||||
}
|
||||
i2c_set_clientdata(client, rv8803);
|
||||
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
@ -666,15 +677,6 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id rv8803_id[] = {
|
||||
{ "rv8803", rv_8803 },
|
||||
{ "rv8804", rx_8804 },
|
||||
{ "rx8803", rx_8803 },
|
||||
{ "rx8900", rx_8900 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rv8803_id);
|
||||
|
||||
static const __maybe_unused struct of_device_id rv8803_of_match[] = {
|
||||
{
|
||||
.compatible = "microcrystal,rv8803",
|
||||
@ -701,7 +703,7 @@ static struct i2c_driver rv8803_driver = {
|
||||
.name = "rtc-rv8803",
|
||||
.of_match_table = of_match_ptr(rv8803_of_match),
|
||||
},
|
||||
.probe = rv8803_probe,
|
||||
.probe_new = rv8803_probe,
|
||||
.id_table = rv8803_id,
|
||||
};
|
||||
module_i2c_driver(rv8803_driver);
|
||||
|
@ -376,7 +376,7 @@ static const struct spi_device_id rx6110_spi_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, rx6110_spi_id);
|
||||
|
||||
static const struct of_device_id rx6110_spi_of_match[] = {
|
||||
static const __maybe_unused struct of_device_id rx6110_spi_of_match[] = {
|
||||
{ .compatible = "epson,rx6110" },
|
||||
{ },
|
||||
};
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
@ -519,9 +520,9 @@ static const struct attribute_group rx8025_attr_group = {
|
||||
.attrs = rx8025_attrs,
|
||||
};
|
||||
|
||||
static int rx8025_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int rx8025_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct i2c_device_id *id = i2c_match_id(rx8025_id, client);
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct rx8025_data *rx8025;
|
||||
int err = 0;
|
||||
@ -580,7 +581,7 @@ static struct i2c_driver rx8025_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-rx8025",
|
||||
},
|
||||
.probe = rx8025_probe,
|
||||
.probe_new = rx8025_probe,
|
||||
.id_table = rx8025_id,
|
||||
};
|
||||
|
||||
|
@ -355,7 +355,9 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
|
||||
set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
|
||||
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
|
||||
|
||||
devm_pm_runtime_enable(&pdev->dev);
|
||||
ret = devm_pm_runtime_enable(&pdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = pm_runtime_resume_and_get(&pdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -211,7 +211,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, err;
|
||||
int i;
|
||||
char buf[7], status;
|
||||
|
||||
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, "
|
||||
@ -234,9 +234,7 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
for (i = 0; i < 7; ++i)
|
||||
buf[i] = bitrev8(buf[i]);
|
||||
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf));
|
||||
|
||||
return err;
|
||||
return s35390a_set_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
@ -429,14 +429,9 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(info->base);
|
||||
|
||||
info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
|
||||
if (IS_ERR(info->rtc_clk)) {
|
||||
ret = PTR_ERR(info->rtc_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to find rtc clock\n");
|
||||
else
|
||||
dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(info->rtc_clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_clk),
|
||||
"failed to find rtc clock\n");
|
||||
ret = clk_prepare_enable(info->rtc_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -32,6 +32,14 @@
|
||||
#define SNVS_LPPGDR_INIT 0x41736166
|
||||
#define CNTR_TO_SECS_SH 15
|
||||
|
||||
/* The maximum RTC clock cycles that are allowed to pass between two
|
||||
* consecutive clock counter register reads. If the values are corrupted a
|
||||
* bigger difference is expected. The RTC frequency is 32kHz. With 320 cycles
|
||||
* we end at 10ms which should be enough for most cases. If it once takes
|
||||
* longer than expected we do a retry.
|
||||
*/
|
||||
#define MAX_RTC_READ_DIFF_CYCLES 320
|
||||
|
||||
struct snvs_rtc_data {
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
@ -56,6 +64,7 @@ static u64 rtc_read_lpsrt(struct snvs_rtc_data *data)
|
||||
static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
|
||||
{
|
||||
u64 read1, read2;
|
||||
s64 diff;
|
||||
unsigned int timeout = 100;
|
||||
|
||||
/* As expected, the registers might update between the read of the LSB
|
||||
@ -66,7 +75,8 @@ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
|
||||
do {
|
||||
read2 = read1;
|
||||
read1 = rtc_read_lpsrt(data);
|
||||
} while (read1 != read2 && --timeout);
|
||||
diff = read1 - read2;
|
||||
} while (((diff < 0) || (diff > MAX_RTC_READ_DIFF_CYCLES)) && --timeout);
|
||||
if (!timeout)
|
||||
dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
|
||||
|
||||
@ -78,13 +88,15 @@ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
|
||||
static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb)
|
||||
{
|
||||
u32 count1, count2;
|
||||
s32 diff;
|
||||
unsigned int timeout = 100;
|
||||
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
|
||||
do {
|
||||
count2 = count1;
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
|
||||
} while (count1 != count2 && --timeout);
|
||||
diff = count1 - count2;
|
||||
} while (((diff < 0) || (diff > MAX_RTC_READ_DIFF_CYCLES)) && --timeout);
|
||||
if (!timeout) {
|
||||
dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
|
||||
return -ETIMEDOUT;
|
||||
|
@ -238,6 +238,7 @@ static int st_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
rtc->clkrate = clk_get_rate(rtc->clk);
|
||||
if (!rtc->clkrate) {
|
||||
clk_disable_unprepare(rtc->clk);
|
||||
dev_err(&pdev->dev, "Unable to fetch clock rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*/
|
||||
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user