RTC for 5.4
Subsystem: - add debug message when registration fails New drivers: - Amlogic Virtual Wake - Freescale FlexTimer Module alarm Drivers: - remove superfluous error messages - convert to i2c_new_dummy_device and devm_i2c_new_dummy_device - Remove dev_err() usage after platform_get_irq() - Set RTC range for: pcf2123, pcf8563, snvs. - pcf2127: tamper detection and watchdog support - pcf85363: fix regmap issue - sun6i: H6 support - remove w90x900/nuc900 driver -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEycoQi/giopmpPgB12wIijOdRNOUFAl2HVakACgkQ2wIijOdR NOVdJA/+PeTgZT393YT6PeuDda10CqtycZoEQNjP9P0wO9SKPNKVjvejS+H6U2+f BaiiGUnOjJ6tgODjfW9OXFTmtly+J7gNxKy2D+Hybzb9AjV36+sQPeiNBQ3EV8EO vlJc38ZUwtFVNQWOoH9Ffwqjian9YsJZRJL5F8T6PiBp6YIDlrs0fmzx0Yaesx66 aSS12DncpEnW+Kt3fknm7C1isCp0A9S4j/60enqqb3aRnN4wdp1XFWIAccToCNY8 c/Eqq0A38BBp+/1xrWaftOGJ6POkLDfQskQJJjV6QI8jC29DJIVZsRlChDVuYYmF K+XJG6SeVvJEP+Be7agWfcE8yXoUR5KqV3zsj3jyHRI4PUc77cpAt3ugXkGuGlmy jVotXJmwvvqEODYAyrY91SK7wSqEF3T+FFoUMcyVRvWJ7+8FAyrMfS9HYgpVET+S rVVrL2+SIGYYY4Hjt8lzmK2RMW6R35iEHqt7lUpiASaoPwvkXQBs3m+dlgy66UAB bjoBRmTpqq9rBUrs1FnJ4Kl9R6WuuSKSEjqhxhR4RqsSeTcZUTZFmWBHVZm//BRg 8iCqpv1ObnttQLhitfX7mc63lp/n7zUsAKH/rroF/ltNxbMydwiBlqJE7APPiDEp mJLIapPbBnaq7YuGmt+ulpQxeEltVbINGNbwZwLF2lGf3FlIQu0= =v1mB -----END PGP SIGNATURE----- Merge tag 'rtc-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "Two new drivers and the new pcf2127 feature make the bulk of the additions. The rest are the usual fixes and new features. Subsystem: - add debug message when registration fails New drivers: - Amlogic Virtual Wake - Freescale FlexTimer Module alarm Drivers: - remove superfluous error messages - convert to i2c_new_dummy_device and devm_i2c_new_dummy_device - Remove dev_err() usage after platform_get_irq() - Set RTC range for: pcf2123, pcf8563, snvs. - pcf2127: tamper detection and watchdog support - pcf85363: fix regmap issue - sun6i: H6 support - remove w90x900/nuc900 driver" * tag 'rtc-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (51 commits) rtc: meson: mark PM functions as __maybe_unused rtc: sc27xx: Remove clearing SPRD_RTC_POWEROFF_ALM_FLAG flag dt-bindings: rtc: ds1307: add rx8130 compatible rtc: sun6i: Allow using as wakeup source from suspend rtc: pcf8563: let the core handle range offsetting rtc: pcf8563: remove useless indirection rtc: pcf8563: convert to devm_rtc_allocate_device rtc: pcf8563: add Microcrystal RV8564 compatible rtc: pcf8563: add Epson RTC8564 compatible rtc: s35390a: convert to devm_i2c_new_dummy_device() rtc: max77686: convert to devm_i2c_new_dummy_device() rtc: pcf85363/pcf85263: fix regmap error in set_time rtc: snvs: switch to rtc_time64_to_tm/rtc_tm_to_time64 rtc: snvs: set range rtc: snvs: fix possible race condition rtc: pcf2127: bugfix: watchdog build dependency rtc: pcf2127: add tamper detection support rtc: pcf2127: add watchdog feature support rtc: pcf2127: bugfix: read rtc disables watchdog rtc: pcf2127: cleanup register and bit defines ...
This commit is contained in:
commit
9dbd83f665
|
@ -25,6 +25,7 @@ properties:
|
|||
- items:
|
||||
- const: allwinner,sun50i-a64-rtc
|
||||
- const: allwinner,sun8i-h3-rtc
|
||||
- const: allwinner,sun50i-h6-rtc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -92,6 +93,18 @@ allOf:
|
|||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun50i-h6-rtc
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-output-names:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
NXP PCF2123 SPI Real Time Clock
|
||||
|
||||
Required properties:
|
||||
- compatible: should be: "nxp,rtc-pcf2123"
|
||||
- compatible: should be: "nxp,pcf2123"
|
||||
or "microcrystal,rv2123"
|
||||
- reg: should be the SPI slave chipselect address
|
||||
|
||||
|
@ -11,7 +11,7 @@ Optional properties:
|
|||
Example:
|
||||
|
||||
pcf2123: rtc@3 {
|
||||
compatible = "nxp,rtc-pcf2123"
|
||||
compatible = "nxp,pcf2123"
|
||||
reg = <3>
|
||||
spi-cs-high;
|
||||
};
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
Philips PCF8563/Epson RTC8564 Real Time Clock
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "nxp,pcf8563".
|
||||
- compatible: Should contain "nxp,pcf8563",
|
||||
"epson,rtc8564" or
|
||||
"microcrystal,rv8564"
|
||||
- reg: I2C address for chip.
|
||||
|
||||
Optional property:
|
||||
|
|
|
@ -19,6 +19,7 @@ Required properties:
|
|||
"pericom,pt7c4338",
|
||||
"epson,rx8025",
|
||||
"isil,isl12057"
|
||||
"epson,rx8130"
|
||||
- reg: I2C bus address of the device
|
||||
|
||||
Optional properties:
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
Freescale FlexTimer Module (FTM) Alarm
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "fsl,<chip>-ftm-alarm", the
|
||||
supported chips include
|
||||
"fsl,ls1012a-ftm-alarm"
|
||||
"fsl,ls1021a-ftm-alarm"
|
||||
"fsl,ls1028a-ftm-alarm"
|
||||
"fsl,ls1043a-ftm-alarm"
|
||||
"fsl,ls1046a-ftm-alarm"
|
||||
"fsl,ls1088a-ftm-alarm"
|
||||
"fsl,ls208xa-ftm-alarm"
|
||||
"fsl,lx2160a-ftm-alarm"
|
||||
- reg : Specifies base physical address and size of the register sets for the
|
||||
FlexTimer Module.
|
||||
- interrupts : Should be the FlexTimer Module interrupt.
|
||||
- fsl,rcpm-wakeup property and rcpm node : Please refer
|
||||
Documentation/devicetree/bindings/soc/fsl/rcpm.txt
|
||||
|
||||
Optional properties:
|
||||
- big-endian: If the host controller is big-endian mode, specify this property.
|
||||
The default endian mode is little-endian.
|
||||
|
||||
Example:
|
||||
rcpm: rcpm@1e34040 {
|
||||
compatible = "fsl,ls1088a-rcpm", "fsl,qoriq-rcpm-2.1+";
|
||||
reg = <0x0 0x1e34040 0x0 0x18>;
|
||||
#fsl,rcpm-wakeup-cells = <6>;
|
||||
};
|
||||
|
||||
ftm_alarm0: timer@2800000 {
|
||||
compatible = "fsl,ls1088a-ftm-alarm";
|
||||
reg = <0x0 0x2800000 0x0 0x10000>;
|
||||
fsl,rcpm-wakeup = <&rcpm 0x0 0x0 0x0 0x0 0x4000 0x0>;
|
||||
interrupts = <0 44 4>;
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
* Amlogic Virtual RTC (VRTC)
|
||||
|
||||
This is a Linux interface to an RTC managed by firmware, hence it's
|
||||
virtual from a Linux perspective. The interface is 1 register where
|
||||
an alarm time (in seconds) is to be written.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "amlogic,meson-vrtc"
|
||||
- reg: physical address for the alarm register
|
||||
|
||||
The alarm register is a simple scratch register shared between the
|
||||
application processors (AP) and the secure co-processor (SCP.) When
|
||||
the AP suspends, the SCP will use the value of this register to
|
||||
program an always-on timer before going sleep. When the timer expires,
|
||||
the SCP will wake up and will then wake the AP.
|
||||
|
||||
Example:
|
||||
|
||||
vrtc: rtc@0a8 {
|
||||
compatible = "amlogic,meson-vrtc";
|
||||
reg = <0x0 0x000a8 0x0 0x4>;
|
||||
};
|
|
@ -52,8 +52,6 @@ properties:
|
|||
- nxp,pcf2127
|
||||
# Real-time clock
|
||||
- nxp,pcf2129
|
||||
# Real-time clock/calendar
|
||||
- nxp,pcf8563
|
||||
# Real-time Clock Module
|
||||
- pericom,pt7c4338
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
|
|
|
@ -1466,6 +1466,7 @@ F: arch/arm64/boot/dts/amlogic/
|
|||
F: drivers/pinctrl/meson/
|
||||
F: drivers/mmc/host/meson*
|
||||
F: drivers/soc/amlogic/
|
||||
F: drivers/rtc/rtc-meson*
|
||||
N: meson
|
||||
|
||||
ARM/Amlogic Meson SoC Sound Drivers
|
||||
|
|
|
@ -373,6 +373,17 @@ config RTC_DRV_MAX77686
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-max77686.
|
||||
|
||||
config RTC_DRV_MESON_VRTC
|
||||
tristate "Amlogic Meson Virtual RTC"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default m if ARCH_MESON
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
Virtual RTC of Amlogic SoCs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-meson-vrtc.
|
||||
|
||||
config RTC_DRV_RK808
|
||||
tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC"
|
||||
depends on MFD_RK808
|
||||
|
@ -500,6 +511,7 @@ config RTC_DRV_M41T80_WDT
|
|||
watchdog timer in the ST M41T60 and M41T80 RTC chips series.
|
||||
config RTC_DRV_BD70528
|
||||
tristate "ROHM BD70528 PMIC RTC"
|
||||
depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
|
||||
help
|
||||
If you say Y here you will get support for the RTC
|
||||
on ROHM BD70528 Power Management IC.
|
||||
|
@ -874,9 +886,15 @@ config RTC_DRV_DS3232_HWMON
|
|||
config RTC_DRV_PCF2127
|
||||
tristate "NXP PCF2127"
|
||||
depends on RTC_I2C_AND_SPI
|
||||
select WATCHDOG_CORE if WATCHDOG
|
||||
help
|
||||
If you say yes here you get support for the NXP PCF2127/29 RTC
|
||||
chips.
|
||||
chips with integrated quartz crystal for industrial applications.
|
||||
Both chips also have watchdog timer and tamper switch detection
|
||||
features.
|
||||
|
||||
PCF2127 has an additional feature of 512 bytes battery backed
|
||||
memory that's accessible using nvmem interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-pcf2127.
|
||||
|
@ -1247,13 +1265,6 @@ config RTC_DRV_AB8500
|
|||
Select this to enable the ST-Ericsson AB8500 power management IC RTC
|
||||
support. This chip contains a battery- and capacitor-backed RTC.
|
||||
|
||||
config RTC_DRV_NUC900
|
||||
tristate "NUC910/NUC920 RTC driver"
|
||||
depends on ARCH_W90X900 || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for the RTC subsystem of the
|
||||
NUC910/NUC920 used in embedded systems.
|
||||
|
||||
config RTC_DRV_OPAL
|
||||
tristate "IBM OPAL RTC driver"
|
||||
depends on PPC_POWERNV
|
||||
|
@ -1323,6 +1334,21 @@ config RTC_DRV_IMXDI
|
|||
This driver can also be built as a module, if so, the module
|
||||
will be called "rtc-imxdi".
|
||||
|
||||
config RTC_DRV_FSL_FTM_ALARM
|
||||
tristate "Freescale FlexTimer alarm timer"
|
||||
depends on ARCH_LAYERSCAPE || SOC_LS1021A
|
||||
select FSL_RCPM
|
||||
default y
|
||||
help
|
||||
For the FlexTimer in LS1012A, LS1021A, LS1028A, LS1043A, LS1046A,
|
||||
LS1088A, LS208xA, we can use FTM as the wakeup source.
|
||||
|
||||
Say y here to enable FTM alarm support. The FTM alarm provides
|
||||
alarm functions for wakeup system from deep sleep.
|
||||
|
||||
This driver can also be built as a module, if so, the module
|
||||
will be called "rtc-fsl-ftm-alarm".
|
||||
|
||||
config RTC_DRV_MESON
|
||||
tristate "Amlogic Meson RTC"
|
||||
depends on (ARM && ARCH_MESON) || COMPILE_TEST
|
||||
|
|
|
@ -73,6 +73,7 @@ obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
|
|||
obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
|
||||
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
|
||||
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
|
||||
obj-$(CONFIG_RTC_DRV_FSL_FTM_ALARM) += rtc-fsl-ftm-alarm.o
|
||||
obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o
|
||||
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
|
||||
obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o
|
||||
|
@ -102,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
|
|||
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
|
||||
obj-$(CONFIG_RTC_DRV_MESON_VRTC)+= rtc-meson-vrtc.o
|
||||
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
|
||||
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
|
||||
obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o
|
||||
|
@ -113,7 +115,6 @@ obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
|
|||
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
|
||||
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
|
||||
obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o
|
||||
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
|
||||
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
|
||||
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
|
||||
obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
|
||||
|
|
|
@ -346,8 +346,10 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
|
|||
struct rtc_wkalrm alrm;
|
||||
int err;
|
||||
|
||||
if (!rtc->ops)
|
||||
if (!rtc->ops) {
|
||||
dev_dbg(&rtc->dev, "no ops set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rtc->owner = owner;
|
||||
rtc_device_get_offset(rtc);
|
||||
|
|
|
@ -264,7 +264,6 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
info->irq = platform_get_irq(pdev, 0);
|
||||
if (info->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource!\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -296,10 +295,9 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
|
|||
info->rtc_dev->range_max = U32_MAX;
|
||||
|
||||
ret = rtc_register_device(info->rtc_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||
if (ret)
|
||||
goto out_rtc;
|
||||
}
|
||||
|
||||
/*
|
||||
* enable internal XO instead of internal 3.25MHz clock since it can
|
||||
* free running in PMIC power-down state.
|
||||
|
|
|
@ -328,10 +328,8 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
|
|||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->irq = platform_get_irq(pdev, 0);
|
||||
if (info->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource!\n");
|
||||
if (info->irq < 0)
|
||||
return info->irq;
|
||||
}
|
||||
|
||||
info->chip = chip;
|
||||
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
|
||||
|
|
|
@ -390,35 +390,31 @@ static int abeoz9_probe(struct i2c_client *client,
|
|||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -ENODEV;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &abeoz9_rtc_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
ret = PTR_ERR(regmap);
|
||||
dev_err(dev, "regmap allocation failed: %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->regmap = regmap;
|
||||
dev_set_drvdata(dev, data);
|
||||
|
||||
ret = abeoz9_rtc_setup(dev, client->dev.of_node);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
data->rtc = devm_rtc_allocate_device(dev);
|
||||
ret = PTR_ERR_OR_ZERO(data->rtc);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
data->rtc->ops = &rtc_ops;
|
||||
data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
|
@ -426,14 +422,10 @@ static int abeoz9_probe(struct i2c_client *client,
|
|||
|
||||
ret = rtc_register_device(data->rtc);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
abeoz9_hwmon_register(dev, data);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dev_err(dev, "unable to register RTC device (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
|
|
@ -578,10 +578,8 @@ static int ac100_rtc_probe(struct platform_device *pdev)
|
|||
chip->regmap = ac100->regmap;
|
||||
|
||||
chip->irq = platform_get_irq(pdev, 0);
|
||||
if (chip->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource\n");
|
||||
if (chip->irq < 0)
|
||||
return chip->irq;
|
||||
}
|
||||
|
||||
chip->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(chip->rtc))
|
||||
|
@ -612,15 +610,7 @@ static int ac100_rtc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rtc_register_device(chip->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "RTC enabled\n");
|
||||
|
||||
return 0;
|
||||
return rtc_register_device(chip->rtc);
|
||||
}
|
||||
|
||||
static int ac100_rtc_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -502,7 +502,6 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct armada38x_rtc *rtc;
|
||||
const struct of_device_id *match;
|
||||
int ret;
|
||||
|
||||
match = of_match_device(armada38x_rtc_of_match_table, &pdev->dev);
|
||||
if (!match)
|
||||
|
@ -530,11 +529,8 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(rtc->regs_soc);
|
||||
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (rtc->irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq\n");
|
||||
if (rtc->irq < 0)
|
||||
return rtc->irq;
|
||||
}
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
|
@ -564,11 +560,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
rtc->rtc_dev->range_max = U32_MAX;
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
return rtc_register_device(rtc->rtc_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -257,10 +257,8 @@ static int asm9260_rtc_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
irq_alarm = platform_get_irq(pdev, 0);
|
||||
if (irq_alarm < 0) {
|
||||
dev_err(dev, "No alarm IRQ resource defined\n");
|
||||
if (irq_alarm < 0)
|
||||
return irq_alarm;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->iobase = devm_ioremap_resource(dev, res);
|
||||
|
|
|
@ -86,7 +86,6 @@ static int aspeed_rtc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct aspeed_rtc *rtc;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
|
@ -107,11 +106,7 @@ static int aspeed_rtc_probe(struct platform_device *pdev)
|
|||
rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return rtc_register_device(rtc->rtc_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_rtc_match[] = {
|
||||
|
|
|
@ -378,10 +378,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource defined\n");
|
||||
if (irq < 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
at91_rtc_regs = devm_ioremap(&pdev->dev, regs->start,
|
||||
resource_size(regs));
|
||||
|
|
|
@ -342,10 +342,8 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
|||
struct of_phandle_args args;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get interrupt resource\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
|
|
|
@ -416,11 +416,8 @@ static int bd70528_probe(struct platform_device *pdev)
|
|||
bd_rtc->dev = &pdev->dev;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm");
|
||||
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get irq\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, bd_rtc);
|
||||
|
||||
|
@ -479,11 +476,7 @@ static int bd70528_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = rtc_register_device(rtc);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Registering RTC failed\n");
|
||||
|
||||
return ret;
|
||||
return rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static struct platform_driver bd70528_rtc = {
|
||||
|
|
|
@ -255,10 +255,8 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
|
|||
timer->rtc->range_max = U32_MAX;
|
||||
|
||||
ret = rtc_register_device(timer->rtc);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to register device\n");
|
||||
if (ret)
|
||||
goto err_notifier;
|
||||
}
|
||||
|
||||
dev_info(dev, "registered, with irq %d\n", timer->irq);
|
||||
|
||||
|
|
|
@ -289,12 +289,8 @@ static int cdns_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
crtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(crtc->rtc_dev)) {
|
||||
ret = PTR_ERR(crtc->rtc_dev);
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to allocate the RTC device, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(crtc->rtc_dev))
|
||||
return PTR_ERR(crtc->rtc_dev);
|
||||
|
||||
platform_set_drvdata(pdev, crtc);
|
||||
|
||||
|
@ -343,11 +339,8 @@ static int cdns_rtc_probe(struct platform_device *pdev)
|
|||
writel(CDNS_RTC_KRTCR_KRTC, crtc->regs + CDNS_RTC_KRTCR);
|
||||
|
||||
ret = rtc_register_device(crtc->rtc_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register the RTC device, %d\n", ret);
|
||||
if (ret)
|
||||
goto err_disable_wakeup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -477,10 +477,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
davinci_rtc->irq = platform_get_irq(pdev, 0);
|
||||
if (davinci_rtc->irq < 0) {
|
||||
dev_err(dev, "no RTC irq\n");
|
||||
if (davinci_rtc->irq < 0)
|
||||
return davinci_rtc->irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
davinci_rtc->base = devm_ioremap_resource(dev, res);
|
||||
|
|
|
@ -690,19 +690,16 @@ static int ds1305_probe(struct spi_device *spi)
|
|||
|
||||
/* register RTC ... from here on, ds1305->ctrl needs locking */
|
||||
ds1305->rtc = devm_rtc_allocate_device(&spi->dev);
|
||||
if (IS_ERR(ds1305->rtc)) {
|
||||
if (IS_ERR(ds1305->rtc))
|
||||
return PTR_ERR(ds1305->rtc);
|
||||
}
|
||||
|
||||
ds1305->rtc->ops = &ds1305_ops;
|
||||
|
||||
ds1305_nvmem_cfg.priv = ds1305;
|
||||
ds1305->rtc->nvram_old_abi = true;
|
||||
status = rtc_register_device(ds1305->rtc);
|
||||
if (status) {
|
||||
dev_dbg(&spi->dev, "register rtc --> %d\n", status);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
rtc_nvmem_register(ds1305->rtc, &ds1305_nvmem_cfg);
|
||||
|
||||
|
|
|
@ -128,9 +128,6 @@ static int ds1672_probe(struct i2c_client *client,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
i2c_set_clientdata(client, rtc);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,337 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Freescale FlexTimer Module (FTM) alarm device driver.
|
||||
*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
* Copyright 2019 NXP
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fsl/ftm.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT)
|
||||
|
||||
/*
|
||||
* Select Fixed frequency clock (32KHz) as clock source
|
||||
* of FlexTimer Module
|
||||
*/
|
||||
#define FTM_SC_CLKS_FIXED_FREQ 0x02
|
||||
#define FIXED_FREQ_CLK 32000
|
||||
|
||||
/* Select 128 (2^7) as divider factor */
|
||||
#define MAX_FREQ_DIV (1 << FTM_SC_PS_MASK)
|
||||
|
||||
/* Maximum counter value in FlexTimer's CNT registers */
|
||||
#define MAX_COUNT_VAL 0xffff
|
||||
|
||||
struct ftm_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *base;
|
||||
bool big_endian;
|
||||
u32 alarm_freq;
|
||||
};
|
||||
|
||||
static inline u32 rtc_readl(struct ftm_rtc *dev, u32 reg)
|
||||
{
|
||||
if (dev->big_endian)
|
||||
return ioread32be(dev->base + reg);
|
||||
else
|
||||
return ioread32(dev->base + reg);
|
||||
}
|
||||
|
||||
static inline void rtc_writel(struct ftm_rtc *dev, u32 reg, u32 val)
|
||||
{
|
||||
if (dev->big_endian)
|
||||
iowrite32be(val, dev->base + reg);
|
||||
else
|
||||
iowrite32(val, dev->base + reg);
|
||||
}
|
||||
|
||||
static inline void ftm_counter_enable(struct ftm_rtc *rtc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* select and enable counter clock source */
|
||||
val = rtc_readl(rtc, FTM_SC);
|
||||
val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
|
||||
val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ));
|
||||
rtc_writel(rtc, FTM_SC, val);
|
||||
}
|
||||
|
||||
static inline void ftm_counter_disable(struct ftm_rtc *rtc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* disable counter clock source */
|
||||
val = rtc_readl(rtc, FTM_SC);
|
||||
val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
|
||||
rtc_writel(rtc, FTM_SC, val);
|
||||
}
|
||||
|
||||
static inline void ftm_irq_acknowledge(struct ftm_rtc *rtc)
|
||||
{
|
||||
unsigned int timeout = 100;
|
||||
|
||||
/*
|
||||
*Fix errata A-007728 for flextimer
|
||||
* If the FTM counter reaches the FTM_MOD value between
|
||||
* the reading of the TOF bit and the writing of 0 to
|
||||
* the TOF bit, the process of clearing the TOF bit
|
||||
* does not work as expected when FTMx_CONF[NUMTOF] != 0
|
||||
* and the current TOF count is less than FTMx_CONF[NUMTOF].
|
||||
* If the above condition is met, the TOF bit remains set.
|
||||
* If the TOF interrupt is enabled (FTMx_SC[TOIE] = 1),the
|
||||
* TOF interrupt also remains asserted.
|
||||
*
|
||||
* Above is the errata discription
|
||||
*
|
||||
* In one word: software clearing TOF bit not works when
|
||||
* FTMx_CONF[NUMTOF] was seted as nonzero and FTM counter
|
||||
* reaches the FTM_MOD value.
|
||||
*
|
||||
* The workaround is clearing TOF bit until it works
|
||||
* (FTM counter doesn't always reache the FTM_MOD anyway),
|
||||
* which may cost some cycles.
|
||||
*/
|
||||
while ((FTM_SC_TOF & rtc_readl(rtc, FTM_SC)) && timeout--)
|
||||
rtc_writel(rtc, FTM_SC, rtc_readl(rtc, FTM_SC) & (~FTM_SC_TOF));
|
||||
}
|
||||
|
||||
static inline void ftm_irq_enable(struct ftm_rtc *rtc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = rtc_readl(rtc, FTM_SC);
|
||||
val |= FTM_SC_TOIE;
|
||||
rtc_writel(rtc, FTM_SC, val);
|
||||
}
|
||||
|
||||
static inline void ftm_irq_disable(struct ftm_rtc *rtc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = rtc_readl(rtc, FTM_SC);
|
||||
val &= ~FTM_SC_TOIE;
|
||||
rtc_writel(rtc, FTM_SC, val);
|
||||
}
|
||||
|
||||
static inline void ftm_reset_counter(struct ftm_rtc *rtc)
|
||||
{
|
||||
/*
|
||||
* The CNT register contains the FTM counter value.
|
||||
* Reset clears the CNT register. Writing any value to COUNT
|
||||
* updates the counter with its initial value, CNTIN.
|
||||
*/
|
||||
rtc_writel(rtc, FTM_CNT, 0x00);
|
||||
}
|
||||
|
||||
static void ftm_clean_alarm(struct ftm_rtc *rtc)
|
||||
{
|
||||
ftm_counter_disable(rtc);
|
||||
|
||||
rtc_writel(rtc, FTM_CNTIN, 0x00);
|
||||
rtc_writel(rtc, FTM_MOD, ~0U);
|
||||
|
||||
ftm_reset_counter(rtc);
|
||||
}
|
||||
|
||||
static irqreturn_t ftm_rtc_alarm_interrupt(int irq, void *dev)
|
||||
{
|
||||
struct ftm_rtc *rtc = dev;
|
||||
|
||||
ftm_irq_acknowledge(rtc);
|
||||
ftm_irq_disable(rtc);
|
||||
ftm_clean_alarm(rtc);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ftm_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enabled)
|
||||
{
|
||||
struct ftm_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (enabled)
|
||||
ftm_irq_enable(rtc);
|
||||
else
|
||||
ftm_irq_disable(rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* The function is not really getting time from the RTC
|
||||
* since FlexTimer is not a RTC device, but we need to
|
||||
* get time to setup alarm, so we are using system time
|
||||
* for now.
|
||||
*/
|
||||
static int ftm_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct timespec64 ts64;
|
||||
|
||||
ktime_get_real_ts64(&ts64);
|
||||
rtc_time_to_tm(ts64.tv_sec, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Select fixed frequency clock (32KHz) as clock source;
|
||||
* 2. Select 128 (2^7) as divider factor;
|
||||
* So clock is 250 Hz (32KHz/128).
|
||||
*
|
||||
* 3. FlexTimer's CNT register is a 32bit register,
|
||||
* but the register's 16 bit as counter value,it's other 16 bit
|
||||
* is reserved.So minimum counter value is 0x0,maximum counter
|
||||
* value is 0xffff.
|
||||
* So max alarm value is 262 (65536 / 250) seconds
|
||||
*/
|
||||
static int ftm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct rtc_time tm;
|
||||
unsigned long now, alm_time, cycle;
|
||||
struct ftm_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
ftm_rtc_read_time(dev, &tm);
|
||||
rtc_tm_to_time(&tm, &now);
|
||||
rtc_tm_to_time(&alm->time, &alm_time);
|
||||
|
||||
ftm_clean_alarm(rtc);
|
||||
cycle = (alm_time - now) * rtc->alarm_freq;
|
||||
if (cycle > MAX_COUNT_VAL) {
|
||||
pr_err("Out of alarm range {0~262} seconds.\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
ftm_irq_disable(rtc);
|
||||
|
||||
/*
|
||||
* The counter increments until the value of MOD is reached,
|
||||
* at which point the counter is reloaded with the value of CNTIN.
|
||||
* The TOF (the overflow flag) bit is set when the FTM counter
|
||||
* changes from MOD to CNTIN. So we should using the cycle - 1.
|
||||
*/
|
||||
rtc_writel(rtc, FTM_MOD, cycle - 1);
|
||||
|
||||
ftm_counter_enable(rtc);
|
||||
ftm_irq_enable(rtc);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops ftm_rtc_ops = {
|
||||
.read_time = ftm_rtc_read_time,
|
||||
.read_alarm = ftm_rtc_read_alarm,
|
||||
.set_alarm = ftm_rtc_set_alarm,
|
||||
.alarm_irq_enable = ftm_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int ftm_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *r;
|
||||
int irq;
|
||||
int ret;
|
||||
struct ftm_rtc *rtc;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (unlikely(!rtc)) {
|
||||
dev_err(&pdev->dev, "cannot alloc memory for rtc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
dev_err(&pdev->dev, "cannot get resource for rtc\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rtc->base = devm_ioremap_resource(&pdev->dev, r);
|
||||
if (IS_ERR(rtc->base)) {
|
||||
dev_err(&pdev->dev, "cannot ioremap resource for rtc\n");
|
||||
return PTR_ERR(rtc->base);
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (irq <= 0) {
|
||||
dev_err(&pdev->dev, "unable to get IRQ from DT, %d\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, ftm_rtc_alarm_interrupt,
|
||||
IRQF_NO_SUSPEND, dev_name(&pdev->dev), rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to request irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc->big_endian = of_property_read_bool(np, "big-endian");
|
||||
rtc->alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV;
|
||||
rtc->rtc_dev->ops = &ftm_rtc_ops;
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't register rtc device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ftm_rtc_match[] = {
|
||||
{ .compatible = "fsl,ls1012a-ftm-alarm", },
|
||||
{ .compatible = "fsl,ls1021a-ftm-alarm", },
|
||||
{ .compatible = "fsl,ls1028a-ftm-alarm", },
|
||||
{ .compatible = "fsl,ls1043a-ftm-alarm", },
|
||||
{ .compatible = "fsl,ls1046a-ftm-alarm", },
|
||||
{ .compatible = "fsl,ls1088a-ftm-alarm", },
|
||||
{ .compatible = "fsl,ls208xa-ftm-alarm", },
|
||||
{ .compatible = "fsl,lx2160a-ftm-alarm", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver ftm_rtc_driver = {
|
||||
.probe = ftm_rtc_probe,
|
||||
.driver = {
|
||||
.name = "ftm-alarm",
|
||||
.of_match_table = ftm_rtc_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ftm_alarm_init(void)
|
||||
{
|
||||
return platform_driver_register(&ftm_rtc_driver);
|
||||
}
|
||||
|
||||
device_initcall(ftm_alarm_init);
|
||||
|
||||
MODULE_DESCRIPTION("NXP/Freescale FlexTimer alarm driver");
|
||||
MODULE_AUTHOR("Biwen Li <biwen.li@nxp.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -167,10 +167,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev)
|
|||
imx_sc_rtc->range_max = U32_MAX;
|
||||
|
||||
ret = rtc_register_device(imx_sc_rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier);
|
||||
|
||||
|
|
|
@ -740,7 +740,6 @@ static void dryice_work(struct work_struct *work)
|
|||
*/
|
||||
static int __init dryice_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct imxdi_dev *imxdi;
|
||||
int norm_irq, sec_irq;
|
||||
int rc;
|
||||
|
@ -751,8 +750,7 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
imxdi->pdev = pdev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
imxdi->ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
imxdi->ioaddr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(imxdi->ioaddr))
|
||||
return PTR_ERR(imxdi->ioaddr);
|
||||
|
||||
|
|
|
@ -454,9 +454,9 @@ static int isl12026_probe_new(struct i2c_client *client)
|
|||
|
||||
isl12026_force_power_modes(client);
|
||||
|
||||
priv->nvm_client = i2c_new_dummy(client->adapter, ISL12026_EEPROM_ADDR);
|
||||
if (!priv->nvm_client)
|
||||
return -ENOMEM;
|
||||
priv->nvm_client = i2c_new_dummy_device(client->adapter, ISL12026_EEPROM_ADDR);
|
||||
if (IS_ERR(priv->nvm_client))
|
||||
return PTR_ERR(priv->nvm_client);
|
||||
|
||||
priv->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
ret = PTR_ERR_OR_ZERO(priv->rtc);
|
||||
|
|
|
@ -323,10 +323,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
|
|||
rtc->type = id->driver_data;
|
||||
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
if (rtc->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get platform irq\n");
|
||||
if (rtc->irq < 0)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rtc->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
|
@ -362,10 +360,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
|
|||
rtc->rtc->range_max = U32_MAX;
|
||||
|
||||
ret = rtc_register_device(rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, rtc->irq, jz4740_rtc_irq, 0,
|
||||
pdev->name, rtc);
|
||||
|
|
|
@ -673,11 +673,8 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
|
|||
struct platform_device *pdev = to_platform_device(info->dev);
|
||||
|
||||
info->rtc_irq = platform_get_irq(pdev, 0);
|
||||
if (info->rtc_irq < 0) {
|
||||
dev_err(info->dev, "Failed to get rtc interrupts: %d\n",
|
||||
info->rtc_irq);
|
||||
if (info->rtc_irq < 0)
|
||||
return info->rtc_irq;
|
||||
}
|
||||
} else {
|
||||
info->rtc_irq = parent_i2c->irq;
|
||||
}
|
||||
|
@ -693,11 +690,11 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
|
|||
goto add_rtc_irq;
|
||||
}
|
||||
|
||||
info->rtc = i2c_new_dummy(parent_i2c->adapter,
|
||||
info->drv_data->rtc_i2c_addr);
|
||||
if (!info->rtc) {
|
||||
info->rtc = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter,
|
||||
info->drv_data->rtc_i2c_addr);
|
||||
if (IS_ERR(info->rtc)) {
|
||||
dev_err(info->dev, "Failed to allocate I2C device for RTC\n");
|
||||
return -ENODEV;
|
||||
return PTR_ERR(info->rtc);
|
||||
}
|
||||
|
||||
info->rtc_regmap = devm_regmap_init_i2c(info->rtc,
|
||||
|
@ -705,7 +702,7 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info)
|
|||
if (IS_ERR(info->rtc_regmap)) {
|
||||
ret = PTR_ERR(info->rtc_regmap);
|
||||
dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret);
|
||||
goto err_unregister_i2c;
|
||||
return ret;
|
||||
}
|
||||
|
||||
add_rtc_irq:
|
||||
|
@ -715,15 +712,10 @@ add_rtc_irq:
|
|||
&info->rtc_irq_data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret);
|
||||
goto err_unregister_i2c;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_i2c:
|
||||
if (info->rtc)
|
||||
i2c_unregister_device(info->rtc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_probe(struct platform_device *pdev)
|
||||
|
@ -786,8 +778,6 @@ static int max77686_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
err_rtc:
|
||||
regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data);
|
||||
if (info->rtc)
|
||||
i2c_unregister_device(info->rtc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -798,8 +788,6 @@ static int max77686_rtc_remove(struct platform_device *pdev)
|
|||
|
||||
free_irq(info->virq, info);
|
||||
regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data);
|
||||
if (info->rtc)
|
||||
i2c_unregister_device(info->rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/time64.h>
|
||||
|
||||
struct meson_vrtc_data {
|
||||
void __iomem *io_alarm;
|
||||
struct rtc_device *rtc;
|
||||
unsigned long alarm_time;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static int meson_vrtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct timespec64 time;
|
||||
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
ktime_get_raw_ts64(&time);
|
||||
rtc_time64_to_tm(time.tv_sec, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_vrtc_set_wakeup_time(struct meson_vrtc_data *vrtc,
|
||||
unsigned long time)
|
||||
{
|
||||
writel_relaxed(time, vrtc->io_alarm);
|
||||
}
|
||||
|
||||
static int meson_vrtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct meson_vrtc_data *vrtc = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "%s: alarm->enabled=%d\n", __func__, alarm->enabled);
|
||||
if (alarm->enabled)
|
||||
vrtc->alarm_time = rtc_tm_to_time64(&alarm->time);
|
||||
else
|
||||
vrtc->alarm_time = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_vrtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct meson_vrtc_data *vrtc = dev_get_drvdata(dev);
|
||||
|
||||
vrtc->enabled = enabled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops meson_vrtc_ops = {
|
||||
.read_time = meson_vrtc_read_time,
|
||||
.set_alarm = meson_vrtc_set_alarm,
|
||||
.alarm_irq_enable = meson_vrtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int meson_vrtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_vrtc_data *vrtc;
|
||||
int ret;
|
||||
|
||||
vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL);
|
||||
if (!vrtc)
|
||||
return -ENOMEM;
|
||||
|
||||
vrtc->io_alarm = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(vrtc->io_alarm))
|
||||
return PTR_ERR(vrtc->io_alarm);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
platform_set_drvdata(pdev, vrtc);
|
||||
|
||||
vrtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(vrtc->rtc))
|
||||
return PTR_ERR(vrtc->rtc);
|
||||
|
||||
vrtc->rtc->ops = &meson_vrtc_ops;
|
||||
ret = rtc_register_device(vrtc->rtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused meson_vrtc_suspend(struct device *dev)
|
||||
{
|
||||
struct meson_vrtc_data *vrtc = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
if (vrtc->alarm_time) {
|
||||
unsigned long local_time;
|
||||
long alarm_secs;
|
||||
struct timespec64 time;
|
||||
|
||||
ktime_get_raw_ts64(&time);
|
||||
local_time = time.tv_sec;
|
||||
|
||||
dev_dbg(dev, "alarm_time = %lus, local_time=%lus\n",
|
||||
vrtc->alarm_time, local_time);
|
||||
alarm_secs = vrtc->alarm_time - local_time;
|
||||
if (alarm_secs > 0) {
|
||||
meson_vrtc_set_wakeup_time(vrtc, alarm_secs);
|
||||
dev_dbg(dev, "system will wakeup in %lds.\n",
|
||||
alarm_secs);
|
||||
} else {
|
||||
dev_err(dev, "alarm time already passed: %lds.\n",
|
||||
alarm_secs);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused meson_vrtc_resume(struct device *dev)
|
||||
{
|
||||
struct meson_vrtc_data *vrtc = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
|
||||
vrtc->alarm_time = 0;
|
||||
meson_vrtc_set_wakeup_time(vrtc, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(meson_vrtc_pm_ops,
|
||||
meson_vrtc_suspend, meson_vrtc_resume);
|
||||
|
||||
static const struct of_device_id meson_vrtc_dt_match[] = {
|
||||
{ .compatible = "amlogic,meson-vrtc"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_vrtc_dt_match);
|
||||
|
||||
static struct platform_driver meson_vrtc_driver = {
|
||||
.probe = meson_vrtc_probe,
|
||||
.driver = {
|
||||
.name = "meson-vrtc",
|
||||
.of_match_table = meson_vrtc_dt_match,
|
||||
.pm = &meson_vrtc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(meson_vrtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic Virtual Wakeup RTC Timer driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -343,10 +343,8 @@ static int mtk_rtc_probe(struct platform_device *pdev)
|
|||
rtc->rtc_dev->ops = &mtk_rtc_ops;
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register rtc device failed\n");
|
||||
if (ret)
|
||||
goto out_free_irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -329,7 +329,6 @@ static int mtk_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
hw->irq = platform_get_irq(pdev, 0);
|
||||
if (hw->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource\n");
|
||||
ret = hw->irq;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -184,8 +184,9 @@ static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
|
|||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irq(&pdata->rtc->irq_lock);
|
||||
spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
|
||||
reg = readw(ioaddr + RTC_RTCIENR);
|
||||
|
||||
if (enabled)
|
||||
|
@ -194,7 +195,7 @@ static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
|
|||
reg &= ~bit;
|
||||
|
||||
writew(reg, ioaddr + RTC_RTCIENR);
|
||||
spin_unlock_irq(&pdata->rtc->irq_lock);
|
||||
spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
|
||||
}
|
||||
|
||||
/* This function is the RTC interrupt service routine. */
|
||||
|
|
|
@ -279,7 +279,6 @@ static int mxc_rtc_wait_for_flag(void __iomem *ioaddr, int flag)
|
|||
static int mxc_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mxc_rtc_data *pdata;
|
||||
struct resource *res;
|
||||
void __iomem *ioaddr;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -287,8 +286,7 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
|||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
pdata->ioaddr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pdata->ioaddr))
|
||||
return PTR_ERR(pdata->ioaddr);
|
||||
|
||||
|
|
|
@ -1,271 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2008-2009 Nuvoton technology corporation.
|
||||
*
|
||||
* Wan ZongShun <mcuos.com@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
/* RTC Control Registers */
|
||||
#define REG_RTC_INIR 0x00
|
||||
#define REG_RTC_AER 0x04
|
||||
#define REG_RTC_FCR 0x08
|
||||
#define REG_RTC_TLR 0x0C
|
||||
#define REG_RTC_CLR 0x10
|
||||
#define REG_RTC_TSSR 0x14
|
||||
#define REG_RTC_DWR 0x18
|
||||
#define REG_RTC_TAR 0x1C
|
||||
#define REG_RTC_CAR 0x20
|
||||
#define REG_RTC_LIR 0x24
|
||||
#define REG_RTC_RIER 0x28
|
||||
#define REG_RTC_RIIR 0x2C
|
||||
#define REG_RTC_TTR 0x30
|
||||
|
||||
#define RTCSET 0x01
|
||||
#define AERRWENB 0x10000
|
||||
#define INIRRESET 0xa5eb1357
|
||||
#define AERPOWERON 0xA965
|
||||
#define AERPOWEROFF 0x0000
|
||||
#define LEAPYEAR 0x0001
|
||||
#define TICKENB 0x80
|
||||
#define TICKINTENB 0x0002
|
||||
#define ALARMINTENB 0x0001
|
||||
#define MODE24 0x0001
|
||||
|
||||
struct nuc900_rtc {
|
||||
int irq_num;
|
||||
void __iomem *rtc_reg;
|
||||
struct rtc_device *rtcdev;
|
||||
};
|
||||
|
||||
struct nuc900_bcd_time {
|
||||
int bcd_sec;
|
||||
int bcd_min;
|
||||
int bcd_hour;
|
||||
int bcd_mday;
|
||||
int bcd_mon;
|
||||
int bcd_year;
|
||||
};
|
||||
|
||||
static irqreturn_t nuc900_rtc_interrupt(int irq, void *_rtc)
|
||||
{
|
||||
struct nuc900_rtc *rtc = _rtc;
|
||||
unsigned long events = 0, rtc_irq;
|
||||
|
||||
rtc_irq = __raw_readl(rtc->rtc_reg + REG_RTC_RIIR);
|
||||
|
||||
if (rtc_irq & ALARMINTENB) {
|
||||
rtc_irq &= ~ALARMINTENB;
|
||||
__raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR);
|
||||
events |= RTC_AF | RTC_IRQF;
|
||||
}
|
||||
|
||||
if (rtc_irq & TICKINTENB) {
|
||||
rtc_irq &= ~TICKINTENB;
|
||||
__raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR);
|
||||
events |= RTC_UF | RTC_IRQF;
|
||||
}
|
||||
|
||||
rtc_update_irq(rtc->rtcdev, 1, events);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc)
|
||||
{
|
||||
unsigned int timeout = 0x1000;
|
||||
__raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR);
|
||||
|
||||
mdelay(10);
|
||||
|
||||
__raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER);
|
||||
|
||||
while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB)
|
||||
&& --timeout)
|
||||
mdelay(1);
|
||||
|
||||
if (!timeout)
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void nuc900_rtc_bcd2bin(unsigned int timereg,
|
||||
unsigned int calreg, struct rtc_time *tm)
|
||||
{
|
||||
tm->tm_mday = bcd2bin(calreg >> 0);
|
||||
tm->tm_mon = bcd2bin(calreg >> 8);
|
||||
tm->tm_year = bcd2bin(calreg >> 16) + 100;
|
||||
|
||||
tm->tm_sec = bcd2bin(timereg >> 0);
|
||||
tm->tm_min = bcd2bin(timereg >> 8);
|
||||
tm->tm_hour = bcd2bin(timereg >> 16);
|
||||
}
|
||||
|
||||
static void nuc900_rtc_bin2bcd(struct device *dev, struct rtc_time *settm,
|
||||
struct nuc900_bcd_time *gettm)
|
||||
{
|
||||
gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0;
|
||||
gettm->bcd_mon = bin2bcd(settm->tm_mon) << 8;
|
||||
|
||||
if (settm->tm_year < 100) {
|
||||
dev_warn(dev, "The year will be between 1970-1999, right?\n");
|
||||
gettm->bcd_year = bin2bcd(settm->tm_year) << 16;
|
||||
} else {
|
||||
gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16;
|
||||
}
|
||||
|
||||
gettm->bcd_sec = bin2bcd(settm->tm_sec) << 0;
|
||||
gettm->bcd_min = bin2bcd(settm->tm_min) << 8;
|
||||
gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16;
|
||||
}
|
||||
|
||||
static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct nuc900_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (enabled)
|
||||
__raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)|
|
||||
(ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER);
|
||||
else
|
||||
__raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)&
|
||||
(~ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nuc900_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct nuc900_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int timeval, clrval;
|
||||
|
||||
timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR);
|
||||
clrval = __raw_readl(rtc->rtc_reg + REG_RTC_CLR);
|
||||
|
||||
nuc900_rtc_bcd2bin(timeval, clrval, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct nuc900_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct nuc900_bcd_time gettm;
|
||||
unsigned long val;
|
||||
int *err;
|
||||
|
||||
nuc900_rtc_bin2bcd(dev, tm, &gettm);
|
||||
|
||||
err = check_rtc_access_enable(rtc);
|
||||
if (IS_ERR(err))
|
||||
return PTR_ERR(err);
|
||||
|
||||
val = gettm.bcd_mday | gettm.bcd_mon | gettm.bcd_year;
|
||||
__raw_writel(val, rtc->rtc_reg + REG_RTC_CLR);
|
||||
|
||||
val = gettm.bcd_sec | gettm.bcd_min | gettm.bcd_hour;
|
||||
__raw_writel(val, rtc->rtc_reg + REG_RTC_TLR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nuc900_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct nuc900_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int timeval, carval;
|
||||
|
||||
timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR);
|
||||
carval = __raw_readl(rtc->rtc_reg + REG_RTC_CAR);
|
||||
|
||||
nuc900_rtc_bcd2bin(timeval, carval, &alrm->time);
|
||||
|
||||
return rtc_valid_tm(&alrm->time);
|
||||
}
|
||||
|
||||
static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct nuc900_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct nuc900_bcd_time tm;
|
||||
unsigned long val;
|
||||
int *err;
|
||||
|
||||
nuc900_rtc_bin2bcd(dev, &alrm->time, &tm);
|
||||
|
||||
err = check_rtc_access_enable(rtc);
|
||||
if (IS_ERR(err))
|
||||
return PTR_ERR(err);
|
||||
|
||||
val = tm.bcd_mday | tm.bcd_mon | tm.bcd_year;
|
||||
__raw_writel(val, rtc->rtc_reg + REG_RTC_CAR);
|
||||
|
||||
val = tm.bcd_sec | tm.bcd_min | tm.bcd_hour;
|
||||
__raw_writel(val, rtc->rtc_reg + REG_RTC_TAR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops nuc900_rtc_ops = {
|
||||
.read_time = nuc900_rtc_read_time,
|
||||
.set_time = nuc900_rtc_set_time,
|
||||
.read_alarm = nuc900_rtc_read_alarm,
|
||||
.set_alarm = nuc900_rtc_set_alarm,
|
||||
.alarm_irq_enable = nuc900_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int __init nuc900_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct nuc900_rtc *nuc900_rtc;
|
||||
|
||||
nuc900_rtc = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_rtc),
|
||||
GFP_KERNEL);
|
||||
if (!nuc900_rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(nuc900_rtc->rtc_reg))
|
||||
return PTR_ERR(nuc900_rtc->rtc_reg);
|
||||
|
||||
platform_set_drvdata(pdev, nuc900_rtc);
|
||||
|
||||
nuc900_rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&nuc900_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(nuc900_rtc->rtcdev)) {
|
||||
dev_err(&pdev->dev, "rtc device register failed\n");
|
||||
return PTR_ERR(nuc900_rtc->rtcdev);
|
||||
}
|
||||
|
||||
__raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24,
|
||||
nuc900_rtc->rtc_reg + REG_RTC_TSSR);
|
||||
|
||||
nuc900_rtc->irq_num = platform_get_irq(pdev, 0);
|
||||
if (devm_request_irq(&pdev->dev, nuc900_rtc->irq_num,
|
||||
nuc900_rtc_interrupt, 0, "nuc900rtc", nuc900_rtc)) {
|
||||
dev_err(&pdev->dev, "NUC900 RTC request irq failed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver nuc900_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "nuc900-rtc",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(nuc900_rtc_driver, nuc900_rtc_probe);
|
||||
|
||||
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
|
||||
MODULE_DESCRIPTION("nuc910/nuc920 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:nuc900-rtc");
|
|
@ -82,7 +82,7 @@
|
|||
#define OSC_HAS_STOPPED BIT(7) /* Clock has been stopped */
|
||||
|
||||
/* PCF2123_REG_ALRM_XX BITS */
|
||||
#define ALRM_ENABLE BIT(7) /* MN, HR, DM, or DW alarm enable */
|
||||
#define ALRM_DISABLE BIT(7) /* MN, HR, DM, or DW alarm matching */
|
||||
|
||||
/* PCF2123_REG_TMR_CLKOUT BITS */
|
||||
#define CD_TMR_4096KHZ (0) /* 4096 KHz countdown timer */
|
||||
|
@ -104,7 +104,7 @@
|
|||
|
||||
static struct spi_driver pcf2123_driver;
|
||||
|
||||
struct pcf2123_plat_data {
|
||||
struct pcf2123_data {
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *map;
|
||||
};
|
||||
|
@ -119,11 +119,11 @@ static const struct regmap_config pcf2123_regmap_config = {
|
|||
|
||||
static int pcf2123_read_offset(struct device *dev, long *offset)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
int ret, val;
|
||||
unsigned int reg;
|
||||
|
||||
ret = regmap_read(pdata->map, PCF2123_REG_OFFSET, ®);
|
||||
ret = regmap_read(pcf2123->map, PCF2123_REG_OFFSET, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -149,7 +149,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset)
|
|||
*/
|
||||
static int pcf2123_set_offset(struct device *dev, long offset)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
s8 reg;
|
||||
|
||||
if (offset > OFFSET_STEP * 127)
|
||||
|
@ -169,16 +169,16 @@ static int pcf2123_set_offset(struct device *dev, long offset)
|
|||
reg |= OFFSET_COARSE;
|
||||
}
|
||||
|
||||
return regmap_write(pdata->map, PCF2123_REG_OFFSET, (unsigned int)reg);
|
||||
return regmap_write(pcf2123->map, PCF2123_REG_OFFSET, (unsigned int)reg);
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
u8 rxbuf[7];
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(pdata->map, PCF2123_REG_SC, rxbuf,
|
||||
ret = regmap_bulk_read(pcf2123->map, PCF2123_REG_SC, rxbuf,
|
||||
sizeof(rxbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -194,9 +194,7 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
tm->tm_mday = bcd2bin(rxbuf[3] & 0x3F);
|
||||
tm->tm_wday = rxbuf[4] & 0x07;
|
||||
tm->tm_mon = bcd2bin(rxbuf[5] & 0x1F) - 1; /* rtc mn 1-12 */
|
||||
tm->tm_year = bcd2bin(rxbuf[6]);
|
||||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100; /* assume we are in 1970...2069 */
|
||||
tm->tm_year = bcd2bin(rxbuf[6]) + 100;
|
||||
|
||||
dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
|
||||
|
||||
|
@ -205,14 +203,14 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
|
||||
static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
u8 txbuf[7];
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm);
|
||||
|
||||
/* Stop the counter first */
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -223,29 +221,37 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
txbuf[3] = bin2bcd(tm->tm_mday & 0x3F);
|
||||
txbuf[4] = tm->tm_wday & 0x07;
|
||||
txbuf[5] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
|
||||
txbuf[6] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
|
||||
txbuf[6] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
ret = regmap_bulk_write(pdata->map, PCF2123_REG_SC, txbuf,
|
||||
ret = regmap_bulk_write(pcf2123->map, PCF2123_REG_SC, txbuf,
|
||||
sizeof(txbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Start the counter */
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_alarm_irq_enable(struct device *dev, unsigned int en)
|
||||
{
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
|
||||
return regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AIE,
|
||||
en ? CTRL2_AIE : 0);
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
u8 rxbuf[4];
|
||||
int ret;
|
||||
unsigned int val = 0;
|
||||
|
||||
ret = regmap_bulk_read(pdata->map, PCF2123_REG_ALRM_MN, rxbuf,
|
||||
ret = regmap_bulk_read(pcf2123->map, PCF2123_REG_ALRM_MN, rxbuf,
|
||||
sizeof(rxbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -257,7 +263,7 @@ static int pcf2123_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
|
||||
dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
|
||||
|
||||
ret = regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
|
||||
ret = regmap_read(pcf2123->map, PCF2123_REG_CTRL2, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -268,19 +274,19 @@ static int pcf2123_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
|
||||
static int pcf2123_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
u8 txbuf[4];
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time);
|
||||
|
||||
/* Ensure alarm flag is clear */
|
||||
ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
|
||||
/* Disable alarm interrupt */
|
||||
ret = regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AIE, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable alarm interrupt */
|
||||
ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AIE, 0);
|
||||
/* Ensure alarm flag is clear */
|
||||
ret = regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -288,42 +294,34 @@ static int pcf2123_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
txbuf[0] = bin2bcd(alm->time.tm_min & 0x7F);
|
||||
txbuf[1] = bin2bcd(alm->time.tm_hour & 0x3F);
|
||||
txbuf[2] = bin2bcd(alm->time.tm_mday & 0x3F);
|
||||
txbuf[3] = bin2bcd(alm->time.tm_wday & 0x07);
|
||||
txbuf[3] = ALRM_DISABLE;
|
||||
|
||||
ret = regmap_bulk_write(pdata->map, PCF2123_REG_ALRM_MN, txbuf,
|
||||
ret = regmap_bulk_write(pcf2123->map, PCF2123_REG_ALRM_MN, txbuf,
|
||||
sizeof(txbuf));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable alarm interrupt */
|
||||
if (alm->enabled) {
|
||||
ret = regmap_update_bits(pdata->map, PCF2123_REG_CTRL2,
|
||||
CTRL2_AIE, CTRL2_AIE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return pcf2123_rtc_alarm_irq_enable(dev, alm->enabled);
|
||||
}
|
||||
|
||||
static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct mutex *lock = &pdata->rtc->ops_lock;
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
struct mutex *lock = &pcf2123->rtc->ops_lock;
|
||||
unsigned int val = 0;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
mutex_lock(lock);
|
||||
regmap_read(pdata->map, PCF2123_REG_CTRL2, &val);
|
||||
regmap_read(pcf2123->map, PCF2123_REG_CTRL2, &val);
|
||||
|
||||
/* Alarm? */
|
||||
if (val & CTRL2_AF) {
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* Clear alarm flag */
|
||||
regmap_update_bits(pdata->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
|
||||
regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AF, 0);
|
||||
|
||||
rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
rtc_update_irq(pcf2123->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
}
|
||||
|
||||
mutex_unlock(lock);
|
||||
|
@ -333,23 +331,23 @@ static irqreturn_t pcf2123_rtc_irq(int irq, void *dev)
|
|||
|
||||
static int pcf2123_reset(struct device *dev)
|
||||
{
|
||||
struct pcf2123_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct pcf2123_data *pcf2123 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
unsigned int val = 0;
|
||||
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
|
||||
ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Stop the counter */
|
||||
dev_dbg(dev, "stopping RTC\n");
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_STOP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* See if the counter was actually stopped */
|
||||
dev_dbg(dev, "checking for presence of RTC\n");
|
||||
ret = regmap_read(pdata->map, PCF2123_REG_CTRL1, &val);
|
||||
ret = regmap_read(pcf2123->map, PCF2123_REG_CTRL1, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -358,7 +356,7 @@ static int pcf2123_reset(struct device *dev)
|
|||
return -ENODEV;
|
||||
|
||||
/* Start the counter */
|
||||
ret = regmap_write(pdata->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_CLEAR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -372,26 +370,27 @@ static const struct rtc_class_ops pcf2123_rtc_ops = {
|
|||
.set_offset = pcf2123_set_offset,
|
||||
.read_alarm = pcf2123_rtc_read_alarm,
|
||||
.set_alarm = pcf2123_rtc_set_alarm,
|
||||
.alarm_irq_enable = pcf2123_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int pcf2123_probe(struct spi_device *spi)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
struct rtc_time tm;
|
||||
struct pcf2123_plat_data *pdata;
|
||||
struct pcf2123_data *pcf2123;
|
||||
int ret = 0;
|
||||
|
||||
pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
|
||||
pcf2123 = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
if (!pcf2123)
|
||||
return -ENOMEM;
|
||||
spi->dev.platform_data = pdata;
|
||||
|
||||
pdata->map = devm_regmap_init_spi(spi, &pcf2123_regmap_config);
|
||||
dev_set_drvdata(&spi->dev, pcf2123);
|
||||
|
||||
if (IS_ERR(pdata->map)) {
|
||||
pcf2123->map = devm_regmap_init_spi(spi, &pcf2123_regmap_config);
|
||||
if (IS_ERR(pcf2123->map)) {
|
||||
dev_err(&spi->dev, "regmap init failed.\n");
|
||||
goto kfree_exit;
|
||||
return PTR_ERR(pcf2123->map);
|
||||
}
|
||||
|
||||
ret = pcf2123_rtc_read_time(&spi->dev, &tm);
|
||||
|
@ -399,7 +398,7 @@ static int pcf2123_probe(struct spi_device *spi)
|
|||
ret = pcf2123_reset(&spi->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "chip not found\n");
|
||||
goto kfree_exit;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -407,16 +406,11 @@ static int pcf2123_probe(struct spi_device *spi)
|
|||
(spi->max_speed_hz + 500) / 1000);
|
||||
|
||||
/* Finalize the initialization */
|
||||
rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name,
|
||||
&pcf2123_rtc_ops, THIS_MODULE);
|
||||
rtc = devm_rtc_allocate_device(&spi->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
if (IS_ERR(rtc)) {
|
||||
dev_err(&spi->dev, "failed to register.\n");
|
||||
ret = PTR_ERR(rtc);
|
||||
goto kfree_exit;
|
||||
}
|
||||
|
||||
pdata->rtc = rtc;
|
||||
pcf2123->rtc = rtc;
|
||||
|
||||
/* Register alarm irq */
|
||||
if (spi->irq > 0) {
|
||||
|
@ -434,19 +428,25 @@ static int pcf2123_probe(struct spi_device *spi)
|
|||
* support to this driver to generate interrupts more than once
|
||||
* per minute.
|
||||
*/
|
||||
pdata->rtc->uie_unsupported = 1;
|
||||
rtc->uie_unsupported = 1;
|
||||
rtc->ops = &pcf2123_rtc_ops;
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->set_start_time = true;
|
||||
|
||||
ret = rtc_register_device(rtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
kfree_exit:
|
||||
spi->dev.platform_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pcf2123_dt_ids[] = {
|
||||
{ .compatible = "nxp,rtc-pcf2123", },
|
||||
{ .compatible = "nxp,pcf2123", },
|
||||
{ .compatible = "microcrystal,rv2123", },
|
||||
/* Deprecated, do not use */
|
||||
{ .compatible = "nxp,rtc-pcf2123", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcf2123_dt_ids);
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
*
|
||||
* Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
|
||||
*
|
||||
* Watchdog and tamper functions
|
||||
* Author: Bruno Thomsen <bruno.thomsen@gmail.com>
|
||||
*
|
||||
* based on the other drivers in this same directory.
|
||||
*
|
||||
* Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf
|
||||
|
@ -18,30 +21,67 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */
|
||||
#define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */
|
||||
/* Control register 1 */
|
||||
#define PCF2127_REG_CTRL1 0x00
|
||||
#define PCF2127_BIT_CTRL1_TSF1 BIT(4)
|
||||
/* Control register 2 */
|
||||
#define PCF2127_REG_CTRL2 0x01
|
||||
#define PCF2127_BIT_CTRL2_TSIE BIT(2)
|
||||
#define PCF2127_BIT_CTRL2_TSF2 BIT(5)
|
||||
/* Control register 3 */
|
||||
#define PCF2127_REG_CTRL3 0x02
|
||||
#define PCF2127_BIT_CTRL3_BLIE BIT(0)
|
||||
#define PCF2127_BIT_CTRL3_BIE BIT(1)
|
||||
#define PCF2127_BIT_CTRL3_BLF BIT(2)
|
||||
#define PCF2127_BIT_CTRL3_BF BIT(3)
|
||||
#define PCF2127_BIT_CTRL3_BTSE BIT(4)
|
||||
/* Time and date registers */
|
||||
#define PCF2127_REG_SC 0x03
|
||||
#define PCF2127_BIT_SC_OSF BIT(7)
|
||||
#define PCF2127_REG_MN 0x04
|
||||
#define PCF2127_REG_HR 0x05
|
||||
#define PCF2127_REG_DM 0x06
|
||||
#define PCF2127_REG_DW 0x07
|
||||
#define PCF2127_REG_MO 0x08
|
||||
#define PCF2127_REG_YR 0x09
|
||||
/* Watchdog registers */
|
||||
#define PCF2127_REG_WD_CTL 0x10
|
||||
#define PCF2127_BIT_WD_CTL_TF0 BIT(0)
|
||||
#define PCF2127_BIT_WD_CTL_TF1 BIT(1)
|
||||
#define PCF2127_BIT_WD_CTL_CD0 BIT(6)
|
||||
#define PCF2127_BIT_WD_CTL_CD1 BIT(7)
|
||||
#define PCF2127_REG_WD_VAL 0x11
|
||||
/* Tamper timestamp registers */
|
||||
#define PCF2127_REG_TS_CTRL 0x12
|
||||
#define PCF2127_BIT_TS_CTRL_TSOFF BIT(6)
|
||||
#define PCF2127_BIT_TS_CTRL_TSM BIT(7)
|
||||
#define PCF2127_REG_TS_SC 0x13
|
||||
#define PCF2127_REG_TS_MN 0x14
|
||||
#define PCF2127_REG_TS_HR 0x15
|
||||
#define PCF2127_REG_TS_DM 0x16
|
||||
#define PCF2127_REG_TS_MO 0x17
|
||||
#define PCF2127_REG_TS_YR 0x18
|
||||
/*
|
||||
* RAM registers
|
||||
* PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is
|
||||
* battery backed and can survive a power outage.
|
||||
* PCF2129 doesn't have this feature.
|
||||
*/
|
||||
#define PCF2127_REG_RAM_ADDR_MSB 0x1A
|
||||
#define PCF2127_REG_RAM_WRT_CMD 0x1C
|
||||
#define PCF2127_REG_RAM_RD_CMD 0x1D
|
||||
|
||||
#define PCF2127_REG_CTRL3 (0x02) /* Control Register 3 */
|
||||
#define PCF2127_REG_CTRL3_BLF BIT(2)
|
||||
|
||||
#define PCF2127_REG_SC (0x03) /* datetime */
|
||||
#define PCF2127_REG_MN (0x04)
|
||||
#define PCF2127_REG_HR (0x05)
|
||||
#define PCF2127_REG_DM (0x06)
|
||||
#define PCF2127_REG_DW (0x07)
|
||||
#define PCF2127_REG_MO (0x08)
|
||||
#define PCF2127_REG_YR (0x09)
|
||||
|
||||
/* the pcf2127 has 512 bytes nvmem, pcf2129 doesn't */
|
||||
#define PCF2127_REG_RAM_addr_MSB 0x1a
|
||||
#define PCF2127_REG_RAM_wrt_cmd 0x1c
|
||||
#define PCF2127_REG_RAM_rd_cmd 0x1d
|
||||
|
||||
#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */
|
||||
/* Watchdog timer value constants */
|
||||
#define PCF2127_WD_VAL_STOP 0
|
||||
#define PCF2127_WD_VAL_MIN 2
|
||||
#define PCF2127_WD_VAL_MAX 255
|
||||
#define PCF2127_WD_VAL_DEFAULT 60
|
||||
|
||||
struct pcf2127 {
|
||||
struct rtc_device *rtc;
|
||||
struct watchdog_device wdd;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
|
@ -54,30 +94,25 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
|
||||
unsigned char buf[10];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= PCF2127_REG_CTRL3; i++) {
|
||||
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1 + i,
|
||||
(unsigned int *)(buf + i));
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: read error\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC,
|
||||
(buf + PCF2127_REG_SC),
|
||||
ARRAY_SIZE(buf) - PCF2127_REG_SC);
|
||||
/*
|
||||
* Avoid reading CTRL2 register as it causes WD_VAL register
|
||||
* value to reset to 0 which means watchdog is stopped.
|
||||
*/
|
||||
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3,
|
||||
(buf + PCF2127_REG_CTRL3),
|
||||
ARRAY_SIZE(buf) - PCF2127_REG_CTRL3);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: read error\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF)
|
||||
if (buf[PCF2127_REG_CTRL3] & PCF2127_BIT_CTRL3_BLF)
|
||||
dev_info(dev,
|
||||
"low voltage detected, check/replace RTC battery.\n");
|
||||
|
||||
if (buf[PCF2127_REG_SC] & PCF2127_OSF) {
|
||||
/* Clock integrity is not guaranteed when OSF flag is set. */
|
||||
if (buf[PCF2127_REG_SC] & PCF2127_BIT_SC_OSF) {
|
||||
/*
|
||||
* no need clear the flag here,
|
||||
* it will be cleared once the new date is saved
|
||||
|
@ -88,14 +123,12 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
}
|
||||
|
||||
dev_dbg(dev,
|
||||
"%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, "
|
||||
"sec=%02x, min=%02x, hr=%02x, "
|
||||
"%s: raw data is cr3=%02x, sec=%02x, min=%02x, hr=%02x, "
|
||||
"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
|
||||
__func__,
|
||||
buf[0], buf[1], buf[2],
|
||||
buf[3], buf[4], buf[5],
|
||||
buf[6], buf[7], buf[8], buf[9]);
|
||||
|
||||
__func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC],
|
||||
buf[PCF2127_REG_MN], buf[PCF2127_REG_HR],
|
||||
buf[PCF2127_REG_DM], buf[PCF2127_REG_DW],
|
||||
buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]);
|
||||
|
||||
tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F);
|
||||
tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F);
|
||||
|
@ -166,7 +199,7 @@ static int pcf2127_rtc_ioctl(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
touser = touser & PCF2127_REG_CTRL3_BLF ? 1 : 0;
|
||||
touser = touser & PCF2127_BIT_CTRL3_BLF ? 1 : 0;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &touser, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
@ -192,12 +225,12 @@ static int pcf2127_nvmem_read(void *priv, unsigned int offset,
|
|||
int ret;
|
||||
unsigned char offsetbuf[] = { offset >> 8, offset };
|
||||
|
||||
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB,
|
||||
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_ADDR_MSB,
|
||||
offsetbuf, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_rd_cmd,
|
||||
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_RD_CMD,
|
||||
val, bytes);
|
||||
|
||||
return ret ?: bytes;
|
||||
|
@ -210,17 +243,176 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset,
|
|||
int ret;
|
||||
unsigned char offsetbuf[] = { offset >> 8, offset };
|
||||
|
||||
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB,
|
||||
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_ADDR_MSB,
|
||||
offsetbuf, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_wrt_cmd,
|
||||
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_WRT_CMD,
|
||||
val, bytes);
|
||||
|
||||
return ret ?: bytes;
|
||||
}
|
||||
|
||||
/* watchdog driver */
|
||||
|
||||
static int pcf2127_wdt_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd);
|
||||
|
||||
return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, wdd->timeout);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart watchdog timer if feature is active.
|
||||
*
|
||||
* Note: Reading CTRL2 register causes watchdog to stop which is unfortunate,
|
||||
* since register also contain control/status flags for other features.
|
||||
* Always call this function after reading CTRL2 register.
|
||||
*/
|
||||
static int pcf2127_wdt_active_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (watchdog_active(wdd)) {
|
||||
ret = pcf2127_wdt_ping(wdd);
|
||||
if (ret)
|
||||
dev_err(wdd->parent,
|
||||
"%s: watchdog restart failed, ret=%d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pcf2127_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
return pcf2127_wdt_ping(wdd);
|
||||
}
|
||||
|
||||
static int pcf2127_wdt_stop(struct watchdog_device *wdd)
|
||||
{
|
||||
struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd);
|
||||
|
||||
return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL,
|
||||
PCF2127_WD_VAL_STOP);
|
||||
}
|
||||
|
||||
static int pcf2127_wdt_set_timeout(struct watchdog_device *wdd,
|
||||
unsigned int new_timeout)
|
||||
{
|
||||
dev_dbg(wdd->parent, "new watchdog timeout: %is (old: %is)\n",
|
||||
new_timeout, wdd->timeout);
|
||||
|
||||
wdd->timeout = new_timeout;
|
||||
|
||||
return pcf2127_wdt_active_ping(wdd);
|
||||
}
|
||||
|
||||
static const struct watchdog_info pcf2127_wdt_info = {
|
||||
.identity = "NXP PCF2127/PCF2129 Watchdog",
|
||||
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
|
||||
};
|
||||
|
||||
static const struct watchdog_ops pcf2127_watchdog_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = pcf2127_wdt_start,
|
||||
.stop = pcf2127_wdt_stop,
|
||||
.ping = pcf2127_wdt_ping,
|
||||
.set_timeout = pcf2127_wdt_set_timeout,
|
||||
};
|
||||
|
||||
/* sysfs interface */
|
||||
|
||||
static ssize_t timestamp0_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
|
||||
PCF2127_BIT_CTRL1_TSF1, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
|
||||
PCF2127_BIT_CTRL2_TSF2, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
static ssize_t timestamp0_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
|
||||
struct rtc_time tm;
|
||||
int ret;
|
||||
unsigned char data[25];
|
||||
|
||||
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data,
|
||||
sizeof(data));
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(dev,
|
||||
"%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, "
|
||||
"ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
|
||||
__func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2],
|
||||
data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC],
|
||||
data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR],
|
||||
data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO],
|
||||
data[PCF2127_REG_TS_YR]);
|
||||
|
||||
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(data[PCF2127_REG_CTRL1] & PCF2127_BIT_CTRL1_TSF1) &&
|
||||
!(data[PCF2127_REG_CTRL2] & PCF2127_BIT_CTRL2_TSF2))
|
||||
return 0;
|
||||
|
||||
tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F);
|
||||
tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F);
|
||||
tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F);
|
||||
tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F);
|
||||
/* TS_MO register (month) value range: 1-12 */
|
||||
tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1;
|
||||
tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]);
|
||||
if (tm.tm_year < 70)
|
||||
tm.tm_year += 100; /* assume we are in 1970...2069 */
|
||||
|
||||
ret = rtc_valid_tm(&tm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%llu\n",
|
||||
(unsigned long long)rtc_tm_to_time64(&tm));
|
||||
};
|
||||
|
||||
static DEVICE_ATTR_RW(timestamp0);
|
||||
|
||||
static struct attribute *pcf2127_attrs[] = {
|
||||
&dev_attr_timestamp0.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group pcf2127_attr_group = {
|
||||
.attrs = pcf2127_attrs,
|
||||
};
|
||||
|
||||
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
||||
const char *name, bool has_nvmem)
|
||||
{
|
||||
|
@ -237,11 +429,22 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
|||
|
||||
dev_set_drvdata(dev, pcf2127);
|
||||
|
||||
pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops,
|
||||
THIS_MODULE);
|
||||
pcf2127->rtc = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(pcf2127->rtc))
|
||||
return PTR_ERR(pcf2127->rtc);
|
||||
|
||||
pcf2127->rtc->ops = &pcf2127_rtc_ops;
|
||||
|
||||
pcf2127->wdd.parent = dev;
|
||||
pcf2127->wdd.info = &pcf2127_wdt_info;
|
||||
pcf2127->wdd.ops = &pcf2127_watchdog_ops;
|
||||
pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN;
|
||||
pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX;
|
||||
pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT;
|
||||
pcf2127->wdd.min_hw_heartbeat_ms = 500;
|
||||
|
||||
watchdog_set_drvdata(&pcf2127->wdd, pcf2127);
|
||||
|
||||
if (has_nvmem) {
|
||||
struct nvmem_config nvmem_cfg = {
|
||||
.priv = pcf2127,
|
||||
|
@ -253,7 +456,84 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
|||
ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
/*
|
||||
* Watchdog timer enabled and reset pin /RST activated when timed out.
|
||||
* Select 1Hz clock source for watchdog timer.
|
||||
* Timer is not started until WD_VAL is loaded with a valid value.
|
||||
* Note: Countdown timer disabled and not available.
|
||||
*/
|
||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL,
|
||||
PCF2127_BIT_WD_CTL_CD1 |
|
||||
PCF2127_BIT_WD_CTL_CD0 |
|
||||
PCF2127_BIT_WD_CTL_TF1 |
|
||||
PCF2127_BIT_WD_CTL_TF0,
|
||||
PCF2127_BIT_WD_CTL_CD1 |
|
||||
PCF2127_BIT_WD_CTL_CD0 |
|
||||
PCF2127_BIT_WD_CTL_TF1);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
ret = devm_watchdog_register_device(dev, &pcf2127->wdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif /* CONFIG_WATCHDOG */
|
||||
|
||||
/*
|
||||
* Disable battery low/switch-over timestamp and interrupts.
|
||||
* Clear battery interrupt flags which can block new trigger events.
|
||||
* Note: This is the default chip behaviour but added to ensure
|
||||
* correct tamper timestamp and interrupt function.
|
||||
*/
|
||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL3,
|
||||
PCF2127_BIT_CTRL3_BTSE |
|
||||
PCF2127_BIT_CTRL3_BF |
|
||||
PCF2127_BIT_CTRL3_BIE |
|
||||
PCF2127_BIT_CTRL3_BLIE, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: interrupt config (ctrl3) failed\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable timestamp function and store timestamp of first trigger
|
||||
* event until TSF1 and TFS2 interrupt flags are cleared.
|
||||
*/
|
||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL,
|
||||
PCF2127_BIT_TS_CTRL_TSOFF |
|
||||
PCF2127_BIT_TS_CTRL_TSM,
|
||||
PCF2127_BIT_TS_CTRL_TSM);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable interrupt generation when TSF1 or TSF2 timestamp flags
|
||||
* are set. Interrupt signal is an open-drain output and can be
|
||||
* left floating if unused.
|
||||
*/
|
||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
|
||||
PCF2127_BIT_CTRL2_TSIE,
|
||||
PCF2127_BIT_CTRL2_TSIE);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: tamper detection config (ctrl2) failed\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: tamper sysfs registering failed\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return rtc_register_device(pcf2127->rtc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
|
|
@ -166,7 +166,12 @@ static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
buf[DT_YEARS] = bin2bcd(tm->tm_year % 100);
|
||||
|
||||
ret = regmap_bulk_write(pcf85363->regmap, CTRL_STOP_EN,
|
||||
tmp, sizeof(tmp));
|
||||
tmp, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_write(pcf85363->regmap, DT_100THS,
|
||||
buf, sizeof(tmp) - 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -196,8 +196,9 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id)
|
|||
* In the routines that deal directly with the pcf8563 hardware, we use
|
||||
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
|
||||
*/
|
||||
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
|
||||
unsigned char buf[9];
|
||||
int err;
|
||||
|
@ -228,9 +229,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
|
||||
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
|
||||
tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
|
||||
tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
|
||||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100; /* assume we are in 1970...2069 */
|
||||
tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]) + 100;
|
||||
/* detect the polarity heuristically. see note above. */
|
||||
pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
|
||||
(tm->tm_year >= 100) : (tm->tm_year < 100);
|
||||
|
@ -244,8 +243,9 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
|
||||
unsigned char buf[9];
|
||||
|
||||
|
@ -266,7 +266,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
|
||||
|
||||
/* year and century */
|
||||
buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
|
||||
buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year - 100);
|
||||
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
|
||||
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
|
||||
|
||||
|
@ -299,8 +299,8 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
|
|||
* because of the cached voltage_low value but do it
|
||||
* anyway for consistency.
|
||||
*/
|
||||
if (pcf8563_get_datetime(to_i2c_client(dev), &tm))
|
||||
pcf8563_set_datetime(to_i2c_client(dev), &tm);
|
||||
if (pcf8563_rtc_read_time(dev, &tm))
|
||||
pcf8563_rtc_set_time(dev, &tm);
|
||||
|
||||
/* Clear the cached value. */
|
||||
pcf8563->voltage_low = 0;
|
||||
|
@ -314,16 +314,6 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
|
|||
#define pcf8563_rtc_ioctl NULL
|
||||
#endif
|
||||
|
||||
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return pcf8563_get_datetime(to_i2c_client(dev), tm);
|
||||
}
|
||||
|
||||
static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return pcf8563_set_datetime(to_i2c_client(dev), tm);
|
||||
}
|
||||
|
||||
static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
@ -591,13 +581,17 @@ static int pcf8563_probe(struct i2c_client *client,
|
|||
return err;
|
||||
}
|
||||
|
||||
pcf8563->rtc = devm_rtc_device_register(&client->dev,
|
||||
pcf8563_driver.driver.name,
|
||||
&pcf8563_rtc_ops, THIS_MODULE);
|
||||
|
||||
pcf8563->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(pcf8563->rtc))
|
||||
return PTR_ERR(pcf8563->rtc);
|
||||
|
||||
pcf8563->rtc->ops = &pcf8563_rtc_ops;
|
||||
/* the pcf8563 alarm only supports a minute accuracy */
|
||||
pcf8563->rtc->uie_unsupported = 1;
|
||||
pcf8563->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
pcf8563->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
pcf8563->rtc->set_start_time = true;
|
||||
|
||||
if (client->irq > 0) {
|
||||
err = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, pcf8563_irq,
|
||||
|
@ -608,17 +602,17 @@ static int pcf8563_probe(struct i2c_client *client,
|
|||
client->irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err = rtc_register_device(pcf8563->rtc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
/* register clk in common clk framework */
|
||||
pcf8563_clkout_register_clk(pcf8563);
|
||||
#endif
|
||||
|
||||
/* the pcf8563 alarm only supports a minute accuracy */
|
||||
pcf8563->rtc->uie_unsupported = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -632,6 +626,8 @@ MODULE_DEVICE_TABLE(i2c, pcf8563_id);
|
|||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pcf8563_of_match[] = {
|
||||
{ .compatible = "nxp,pcf8563" },
|
||||
{ .compatible = "epson,rtc8564" },
|
||||
{ .compatible = "microcrystal,rv8564" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pcf8563_of_match);
|
||||
|
|
|
@ -308,10 +308,8 @@ static int pic32_rtc_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
pdata->alarm_irq = platform_get_irq(pdev, 0);
|
||||
if (pdata->alarm_irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq for alarm\n");
|
||||
if (pdata->alarm_irq < 0)
|
||||
return pdata->alarm_irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pdata->reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
|
|
@ -468,10 +468,8 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
|
||||
if (rtc_dd->rtc_alarm_irq < 0) {
|
||||
dev_err(&pdev->dev, "Alarm IRQ resource absent!\n");
|
||||
if (rtc_dd->rtc_alarm_irq < 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
|
||||
"allow-set-time");
|
||||
|
|
|
@ -186,16 +186,12 @@ static int puv3_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
/* find the IRQs */
|
||||
puv3_rtc_tickno = platform_get_irq(pdev, 1);
|
||||
if (puv3_rtc_tickno < 0) {
|
||||
dev_err(&pdev->dev, "no irq for rtc tick\n");
|
||||
if (puv3_rtc_tickno < 0)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
puv3_rtc_alarmno = platform_get_irq(pdev, 0);
|
||||
if (puv3_rtc_alarmno < 0) {
|
||||
dev_err(&pdev->dev, "no irq for alarm\n");
|
||||
if (puv3_rtc_alarmno < 0)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "PKUnity_rtc: tick irq %d, alarm irq %d\n",
|
||||
puv3_rtc_tickno, puv3_rtc_alarmno);
|
||||
|
@ -239,10 +235,8 @@ static int puv3_rtc_probe(struct platform_device *pdev)
|
|||
/* register RTC and exit */
|
||||
rtc->ops = &puv3_rtcops;
|
||||
ret = rtc_register_device(rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "cannot attach rtc\n");
|
||||
if (ret)
|
||||
goto err_nortc;
|
||||
}
|
||||
|
||||
/* platform setup code should have handled this; sigh */
|
||||
if (!device_can_wakeup(&pdev->dev))
|
||||
|
|
|
@ -324,15 +324,11 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
sa1100_rtc->irq_1hz = platform_get_irq(pdev, 0);
|
||||
if (sa1100_rtc->irq_1hz < 0) {
|
||||
dev_err(dev, "No 1Hz IRQ resource defined\n");
|
||||
if (sa1100_rtc->irq_1hz < 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
sa1100_rtc->irq_alarm = platform_get_irq(pdev, 1);
|
||||
if (sa1100_rtc->irq_alarm < 0) {
|
||||
dev_err(dev, "No alarm IRQ resource defined\n");
|
||||
if (sa1100_rtc->irq_alarm < 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
pxa_rtc->base = devm_ioremap(dev, pxa_rtc->ress->start,
|
||||
resource_size(pxa_rtc->ress));
|
||||
|
|
|
@ -434,12 +434,8 @@ static int rk808_rtc_probe(struct platform_device *pdev)
|
|||
rk808_rtc->rtc->ops = &rk808_rtc_ops;
|
||||
|
||||
rk808_rtc->irq = platform_get_irq(pdev, 0);
|
||||
if (rk808_rtc->irq < 0) {
|
||||
if (rk808_rtc->irq != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Wake up is not possible as irq = %d\n",
|
||||
rk808_rtc->irq);
|
||||
if (rk808_rtc->irq < 0)
|
||||
return rk808_rtc->irq;
|
||||
}
|
||||
|
||||
/* request alarm irq of rk808 */
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rk808_rtc->irq, NULL,
|
||||
|
|
|
@ -639,9 +639,8 @@ static int rv3028_probe(struct i2c_client *client)
|
|||
dev_warn(&client->dev, "An alarm may have been missed.\n");
|
||||
|
||||
rv3028->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rv3028->rtc)) {
|
||||
if (IS_ERR(rv3028->rtc))
|
||||
return PTR_ERR(rv3028->rtc);
|
||||
}
|
||||
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
|
|
|
@ -278,13 +278,13 @@ static int rv3029_eeprom_read(struct device *dev, u8 reg,
|
|||
static int rv3029_eeprom_write(struct device *dev, u8 reg,
|
||||
u8 const buf[], size_t len)
|
||||
{
|
||||
int ret;
|
||||
int ret, err;
|
||||
size_t i;
|
||||
u8 tmp;
|
||||
|
||||
ret = rv3029_eeprom_enter(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
err = rv3029_eeprom_enter(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < len; i++, reg++) {
|
||||
ret = rv3029_read_regs(dev, reg, &tmp, 1);
|
||||
|
@ -300,11 +300,11 @@ static int rv3029_eeprom_write(struct device *dev, u8 reg,
|
|||
break;
|
||||
}
|
||||
|
||||
ret = rv3029_eeprom_exit(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
err = rv3029_eeprom_exit(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv3029_eeprom_update_bits(struct device *dev,
|
||||
|
|
|
@ -564,9 +564,8 @@ static int rv8803_probe(struct i2c_client *client,
|
|||
dev_warn(&client->dev, "An alarm maybe have been missed.\n");
|
||||
|
||||
rv8803->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rv8803->rtc)) {
|
||||
if (IS_ERR(rv8803->rtc))
|
||||
return PTR_ERR(rv8803->rtc);
|
||||
}
|
||||
|
||||
if (client->irq > 0) {
|
||||
err = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
|
|
|
@ -434,37 +434,32 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
char buf, status1;
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
err = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return -ENODEV;
|
||||
|
||||
s35390a = devm_kzalloc(dev, sizeof(struct s35390a), GFP_KERNEL);
|
||||
if (!s35390a) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
if (!s35390a)
|
||||
return -ENOMEM;
|
||||
|
||||
s35390a->client[0] = client;
|
||||
i2c_set_clientdata(client, s35390a);
|
||||
|
||||
/* This chip uses multiple addresses, use dummy devices for them */
|
||||
for (i = 1; i < 8; ++i) {
|
||||
s35390a->client[i] = i2c_new_dummy(client->adapter,
|
||||
client->addr + i);
|
||||
if (!s35390a->client[i]) {
|
||||
s35390a->client[i] = devm_i2c_new_dummy_device(dev,
|
||||
client->adapter,
|
||||
client->addr + i);
|
||||
if (IS_ERR(s35390a->client[i])) {
|
||||
dev_err(dev, "Address %02x unavailable\n",
|
||||
client->addr + i);
|
||||
err = -EBUSY;
|
||||
goto exit_dummy;
|
||||
return PTR_ERR(s35390a->client[i]);
|
||||
}
|
||||
}
|
||||
|
||||
err_read = s35390a_read_status(s35390a, &status1);
|
||||
if (err_read < 0) {
|
||||
err = err_read;
|
||||
dev_err(dev, "error resetting chip\n");
|
||||
goto exit_dummy;
|
||||
return err_read;
|
||||
}
|
||||
|
||||
if (status1 & S35390A_FLAG_24H)
|
||||
|
@ -478,13 +473,13 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "error disabling alarm");
|
||||
goto exit_dummy;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
err = s35390a_disable_test_mode(s35390a);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "error disabling test mode\n");
|
||||
goto exit_dummy;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,10 +488,8 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
s35390a->rtc = devm_rtc_device_register(dev, s35390a_driver.driver.name,
|
||||
&s35390a_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(s35390a->rtc)) {
|
||||
err = PTR_ERR(s35390a->rtc);
|
||||
goto exit_dummy;
|
||||
}
|
||||
if (IS_ERR(s35390a->rtc))
|
||||
return PTR_ERR(s35390a->rtc);
|
||||
|
||||
/* supports per-minute alarms only, therefore set uie_unsupported */
|
||||
s35390a->rtc->uie_unsupported = 1;
|
||||
|
@ -505,26 +498,6 @@ static int s35390a_probe(struct i2c_client *client,
|
|||
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_dummy:
|
||||
for (i = 1; i < 8; ++i)
|
||||
if (s35390a->client[i])
|
||||
i2c_unregister_device(s35390a->client[i]);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int s35390a_remove(struct i2c_client *client)
|
||||
{
|
||||
unsigned int i;
|
||||
struct s35390a *s35390a = i2c_get_clientdata(client);
|
||||
|
||||
for (i = 1; i < 8; ++i)
|
||||
if (s35390a->client[i])
|
||||
i2c_unregister_device(s35390a->client[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver s35390a_driver = {
|
||||
|
@ -533,7 +506,6 @@ static struct i2c_driver s35390a_driver = {
|
|||
.of_match_table = of_match_ptr(s35390a_of_match),
|
||||
},
|
||||
.probe = s35390a_probe,
|
||||
.remove = s35390a_remove,
|
||||
.id_table = s35390a_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -453,10 +453,8 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
/* find the IRQs */
|
||||
info->irq_tick = platform_get_irq(pdev, 1);
|
||||
if (info->irq_tick < 0) {
|
||||
dev_err(&pdev->dev, "no irq for rtc tick\n");
|
||||
if (info->irq_tick < 0)
|
||||
return info->irq_tick;
|
||||
}
|
||||
|
||||
info->dev = &pdev->dev;
|
||||
info->data = of_device_get_match_data(&pdev->dev);
|
||||
|
@ -470,10 +468,8 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, info);
|
||||
|
||||
info->irq_alarm = platform_get_irq(pdev, 0);
|
||||
if (info->irq_alarm < 0) {
|
||||
dev_err(&pdev->dev, "no irq for alarm\n");
|
||||
if (info->irq_alarm < 0)
|
||||
return info->irq_alarm;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
|
||||
info->irq_tick, info->irq_alarm);
|
||||
|
|
|
@ -760,10 +760,10 @@ static int s5m_rtc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR);
|
||||
if (!info->i2c) {
|
||||
info->i2c = i2c_new_dummy_device(s5m87xx->i2c->adapter, RTC_I2C_ADDR);
|
||||
if (IS_ERR(info->i2c)) {
|
||||
dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n");
|
||||
return -ENODEV;
|
||||
return PTR_ERR(info->i2c);
|
||||
}
|
||||
|
||||
info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg);
|
||||
|
|
|
@ -138,7 +138,7 @@ static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= ~(SPRD_RTC_ALMLOCK_MASK | SPRD_RTC_POWEROFF_ALM_FLAG);
|
||||
val &= ~SPRD_RTC_ALMLOCK_MASK;
|
||||
if (lock)
|
||||
val |= SPRD_RTC_ALM_LOCK;
|
||||
else
|
||||
|
@ -614,10 +614,8 @@ static int sprd_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
if (rtc->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get RTC irq number\n");
|
||||
if (rtc->irq < 0)
|
||||
return rtc->irq;
|
||||
}
|
||||
|
||||
rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc))
|
||||
|
@ -656,7 +654,6 @@ static int sprd_rtc_probe(struct platform_device *pdev)
|
|||
rtc->rtc->range_max = 5662310399LL;
|
||||
ret = rtc_register_device(rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register rtc device\n");
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -193,10 +193,8 @@ static int sd3078_probe(struct i2c_client *client,
|
|||
sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
ret = rtc_register_device(sd3078->rtc);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to register rtc device\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sd3078_enable_reg_write(sd3078);
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
unsigned long time = rtc_read_lp_counter(data);
|
||||
|
||||
rtc_time_to_tm(time, tm);
|
||||
rtc_time64_to_tm(time, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -159,11 +159,9 @@ static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
unsigned long time;
|
||||
unsigned long time = rtc_tm_to_time64(tm);
|
||||
int ret;
|
||||
|
||||
rtc_tm_to_time(tm, &time);
|
||||
|
||||
/* Disable RTC first */
|
||||
ret = snvs_rtc_enable(data, false);
|
||||
if (ret)
|
||||
|
@ -185,7 +183,7 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
u32 lptar, lpsr;
|
||||
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPTAR, &lptar);
|
||||
rtc_time_to_tm(lptar, &alrm->time);
|
||||
rtc_time64_to_tm(lptar, &alrm->time);
|
||||
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr);
|
||||
alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0;
|
||||
|
@ -207,12 +205,9 @@ static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
|||
static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
struct rtc_time *alrm_tm = &alrm->time;
|
||||
unsigned long time;
|
||||
unsigned long time = rtc_tm_to_time64(&alrm->time);
|
||||
int ret;
|
||||
|
||||
rtc_tm_to_time(alrm_tm, &time);
|
||||
|
||||
regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0);
|
||||
ret = rtc_write_sync_lp(data);
|
||||
if (ret)
|
||||
|
@ -279,6 +274,10 @@ static int snvs_rtc_probe(struct platform_device *pdev)
|
|||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(data->rtc))
|
||||
return PTR_ERR(data->rtc);
|
||||
|
||||
data->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap");
|
||||
|
||||
if (IS_ERR(data->regmap)) {
|
||||
|
@ -343,10 +342,10 @@ static int snvs_rtc_probe(struct platform_device *pdev)
|
|||
goto error_rtc_device_register;
|
||||
}
|
||||
|
||||
data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&snvs_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(data->rtc)) {
|
||||
ret = PTR_ERR(data->rtc);
|
||||
data->rtc->ops = &snvs_rtc_ops;
|
||||
data->rtc->range_max = U32_MAX;
|
||||
ret = rtc_register_device(data->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
|
||||
goto error_rtc_device_register;
|
||||
}
|
||||
|
|
|
@ -358,10 +358,8 @@ static int spear_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
/* alarm irqs */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no update irq?\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
status = devm_request_irq(&pdev->dev, irq, spear_rtc_irq, 0, pdev->name,
|
||||
config);
|
||||
|
|
|
@ -776,7 +776,6 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
rtc->irq_alarm = platform_get_irq(pdev, 0);
|
||||
if (rtc->irq_alarm <= 0) {
|
||||
dev_err(&pdev->dev, "no alarm irq\n");
|
||||
ret = rtc->irq_alarm;
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,11 @@
|
|||
/* Control register */
|
||||
#define SUN6I_LOSC_CTRL 0x0000
|
||||
#define SUN6I_LOSC_CTRL_KEY (0x16aa << 16)
|
||||
#define SUN6I_LOSC_CTRL_AUTO_SWT_BYPASS BIT(15)
|
||||
#define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9)
|
||||
#define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8)
|
||||
#define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7)
|
||||
#define SUN6I_LOSC_CTRL_EXT_LOSC_EN BIT(4)
|
||||
#define SUN6I_LOSC_CTRL_EXT_OSC BIT(0)
|
||||
#define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7)
|
||||
|
||||
|
@ -128,6 +130,8 @@ struct sun6i_rtc_clk_data {
|
|||
unsigned int has_prescaler : 1;
|
||||
unsigned int has_out_clk : 1;
|
||||
unsigned int export_iosc : 1;
|
||||
unsigned int has_losc_en : 1;
|
||||
unsigned int has_auto_swt : 1;
|
||||
};
|
||||
|
||||
struct sun6i_rtc_dev {
|
||||
|
@ -190,6 +194,10 @@ static int sun6i_rtc_osc_set_parent(struct clk_hw *hw, u8 index)
|
|||
val &= ~SUN6I_LOSC_CTRL_EXT_OSC;
|
||||
val |= SUN6I_LOSC_CTRL_KEY;
|
||||
val |= index ? SUN6I_LOSC_CTRL_EXT_OSC : 0;
|
||||
if (rtc->data->has_losc_en) {
|
||||
val &= ~SUN6I_LOSC_CTRL_EXT_LOSC_EN;
|
||||
val |= index ? SUN6I_LOSC_CTRL_EXT_LOSC_EN : 0;
|
||||
}
|
||||
writel(val, rtc->base + SUN6I_LOSC_CTRL);
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
|
@ -215,6 +223,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];
|
||||
u32 reg;
|
||||
|
||||
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
|
@ -235,9 +244,18 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
|
|||
goto err;
|
||||
}
|
||||
|
||||
reg = SUN6I_LOSC_CTRL_KEY;
|
||||
if (rtc->data->has_auto_swt) {
|
||||
/* Bypass auto-switch to int osc, on ext losc failure */
|
||||
reg |= SUN6I_LOSC_CTRL_AUTO_SWT_BYPASS;
|
||||
writel(reg, rtc->base + SUN6I_LOSC_CTRL);
|
||||
}
|
||||
|
||||
/* Switch to the external, more precise, oscillator */
|
||||
writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
|
||||
rtc->base + SUN6I_LOSC_CTRL);
|
||||
reg |= SUN6I_LOSC_CTRL_EXT_OSC;
|
||||
if (rtc->data->has_losc_en)
|
||||
reg |= SUN6I_LOSC_CTRL_EXT_LOSC_EN;
|
||||
writel(reg, rtc->base + SUN6I_LOSC_CTRL);
|
||||
|
||||
/* Yes, I know, this is ugly. */
|
||||
sun6i_rtc = rtc;
|
||||
|
@ -345,6 +363,23 @@ CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc",
|
|||
CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc",
|
||||
sun8i_h3_rtc_clk_init);
|
||||
|
||||
static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = {
|
||||
.rc_osc_rate = 16000000,
|
||||
.fixed_prescaler = 32,
|
||||
.has_prescaler = 1,
|
||||
.has_out_clk = 1,
|
||||
.export_iosc = 1,
|
||||
.has_losc_en = 1,
|
||||
.has_auto_swt = 1,
|
||||
};
|
||||
|
||||
static void __init sun50i_h6_rtc_clk_init(struct device_node *node)
|
||||
{
|
||||
sun6i_rtc_clk_init(node, &sun50i_h6_rtc_data);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(sun50i_h6_rtc_clk, "allwinner,sun50i-h6-rtc",
|
||||
sun50i_h6_rtc_clk_init);
|
||||
|
||||
static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = {
|
||||
.rc_osc_rate = 32000,
|
||||
.has_out_clk = 1,
|
||||
|
@ -598,6 +633,33 @@ static const struct rtc_class_ops sun6i_rtc_ops = {
|
|||
.alarm_irq_enable = sun6i_rtc_alarm_irq_enable
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* Enable IRQ wake on suspend, to wake up from RTC. */
|
||||
static int sun6i_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(chip->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Disable IRQ wake on resume. */
|
||||
static int sun6i_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(chip->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(sun6i_rtc_pm_ops,
|
||||
sun6i_rtc_suspend, sun6i_rtc_resume);
|
||||
|
||||
static int sun6i_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sun6i_rtc_dev *chip = sun6i_rtc;
|
||||
|
@ -610,10 +672,8 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
|
|||
chip->dev = &pdev->dev;
|
||||
|
||||
chip->irq = platform_get_irq(pdev, 0);
|
||||
if (chip->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource\n");
|
||||
if (chip->irq < 0)
|
||||
return chip->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq,
|
||||
0, dev_name(&pdev->dev), chip);
|
||||
|
@ -650,6 +710,8 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
clk_prepare_enable(chip->losc);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
chip->rtc = devm_rtc_device_register(&pdev->dev, "rtc-sun6i",
|
||||
&sun6i_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(chip->rtc)) {
|
||||
|
@ -675,6 +737,7 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = {
|
|||
{ .compatible = "allwinner,sun8i-r40-rtc" },
|
||||
{ .compatible = "allwinner,sun8i-v3-rtc" },
|
||||
{ .compatible = "allwinner,sun50i-h5-rtc" },
|
||||
{ .compatible = "allwinner,sun50i-h6-rtc" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
|
||||
|
@ -684,6 +747,7 @@ static struct platform_driver sun6i_rtc_driver = {
|
|||
.driver = {
|
||||
.name = "sun6i-rtc",
|
||||
.of_match_table = sun6i_rtc_dt_ids,
|
||||
.pm = &sun6i_rtc_pm_ops,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(sun6i_rtc_driver);
|
||||
|
|
|
@ -442,10 +442,8 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(chip->base);
|
||||
|
||||
chip->irq = platform_get_irq(pdev, 0);
|
||||
if (chip->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource\n");
|
||||
if (chip->irq < 0)
|
||||
return chip->irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, chip->irq, sunxi_rtc_alarmirq,
|
||||
0, dev_name(&pdev->dev), chip);
|
||||
if (ret) {
|
||||
|
@ -474,15 +472,7 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
chip->rtc->ops = &sunxi_rtc_ops;
|
||||
|
||||
ret = rtc_register_device(chip->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "RTC enabled\n");
|
||||
|
||||
return 0;
|
||||
return rtc_register_device(chip->rtc);
|
||||
}
|
||||
|
||||
static struct platform_driver sunxi_rtc_driver = {
|
||||
|
|
|
@ -290,10 +290,8 @@ static int tegra_rtc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(info->base);
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "failed to get platform IRQ: %d\n", ret);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
info->irq = ret;
|
||||
|
||||
|
@ -334,10 +332,8 @@ static int tegra_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ret = rtc_register_device(info->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register device: %d\n", ret);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
|
||||
|
||||
|
|
|
@ -259,7 +259,6 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
|
|||
rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
dev_err(&pdev->dev, "RTC allocate device: ret %d\n", ret);
|
||||
goto fail_rtc_register;
|
||||
}
|
||||
|
||||
|
@ -280,10 +279,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
|
|||
disable_irq(rtc->irq);
|
||||
|
||||
ret = rtc_register_device(rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "RTC device register: ret %d\n", ret);
|
||||
if (ret)
|
||||
goto fail_rtc_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -425,13 +425,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
|
|||
tps_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
tps_rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
ret = rtc_register_device(tps_rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rtc_register_device(tps_rtc->rtc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -212,10 +212,8 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, vt8500_rtc);
|
||||
|
||||
vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);
|
||||
if (vt8500_rtc->irq_alarm < 0) {
|
||||
dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
|
||||
if (vt8500_rtc->irq_alarm < 0)
|
||||
return vt8500_rtc->irq_alarm;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
vt8500_rtc->regbase = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
|
|
@ -157,10 +157,8 @@ static int xgene_rtc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(pdata->rtc);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0,
|
||||
dev_name(&pdev->dev), pdata);
|
||||
if (ret) {
|
||||
|
|
|
@ -218,10 +218,8 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(xrtcdev->reg_base);
|
||||
|
||||
xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm");
|
||||
if (xrtcdev->alarm_irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource\n");
|
||||
if (xrtcdev->alarm_irq < 0)
|
||||
return xrtcdev->alarm_irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, xrtcdev->alarm_irq,
|
||||
xlnx_rtc_interrupt, 0,
|
||||
dev_name(&pdev->dev), xrtcdev);
|
||||
|
@ -231,10 +229,8 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
xrtcdev->sec_irq = platform_get_irq_byname(pdev, "sec");
|
||||
if (xrtcdev->sec_irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource\n");
|
||||
if (xrtcdev->sec_irq < 0)
|
||||
return xrtcdev->sec_irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, xrtcdev->sec_irq,
|
||||
xlnx_rtc_interrupt, 0,
|
||||
dev_name(&pdev->dev), xrtcdev);
|
||||
|
|
Loading…
Reference in New Issue