RTC for 4.3
Core: - use is_visible() to control sysfs attributes - switch wakealarm attribute to DEVICE_ATTR_RW - make rtc_does_wakealarm() return boolean - properly manage lifetime of dev and cdev in rtc device - remove unnecessary device_get() in rtc_device_unregister - fix double free in rtc_register_device() error path New drivers: - NXP LPC24xx - Xilinx Zynq MP - Dialog DA9062 Subsystem wide cleanups: - fix drivers that consider 0 as a valid IRQ in client->irq - Drop (un)likely before IS_ERR(_OR_NULL) - drop the remaining owner assignment for i2c_driver and platform_driver - module autoload fixes Drivers: - 88pm80x: add device tree support - abx80x: fix RTC write bit - ab8500: Add a sentinel to ab85xx_rtc_ids[] - armada38x: Align RTC set time procedure with the official errata - as3722: correct month value - at91sam9: cleanups - at91rm9200: get and use slow clock and cleanups - bq32k: remove redundant check - cmos: century support, proper fix for the spurious wakeup - ds1307: cleanups and wakeup irq support - ds1374: Remove unused variable - ds1685: Use module_platform_driver - ds3232: fix WARNING trace in resume function - gemini: fix ptr_ret.cocci warnings - mt6397: implement suspend/resume - omap: support internal and external clock enabling - opal: Enable alarms only when opal supports tpo - pcf2127: use OFS flag to detect unreliable date and warn the user - pl031: fix typo for author email - rx8025: huge cleanup and fixes - sa1100/pxa: share common code - s5m: fix to update ctrl register - s3c: fix clocks and wakeup, cleanup - sirfsoc: use regmap - nvram_read()/nvram_write() functions for cmos, ds1305, ds1307, ds1343, ds1511, ds1553, ds1742, m48t59, rp5c01, stk17ta8, tx4939 - use rtc_valid_tm() error code when reading date/time instead of 0 for isl12022, pcf2123, pcf2127 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJV7ARpAAoJEKbNnwlvZCyzo40P/09fca3C9HBEI5hgJO7PmQX8 +3wkacMjEi58yMTzWoDCFh2H1Vvajm1d6bJ6H//5/3h/KPKrjIsCTFlMfuv8gfbe xFoeXPMdiojjPxFjbjnpM+0GD9SKTIjwpP4d8HgoUDwGRJ6dxaTOVuJXRmVGcmas e4Ih6hDy2YBiRXLzLHSvSNcTJDGznwMvEEg1AfqUjAtNm4BUzhUnvq0CYlSdwMzy xK6w0LmOr67l2QpjiQNCvIn04OWdDQ35f0GcRHYEY66cZPkvPp3OCC/UbeChU6uK He/v1n+QdBTbkKYeYmNnBSr42KPTLONNaOFXf79PpAz/WtiYxLxJDbf8DYW9gGQj mC3rMNWXf4rEFHkHYH4KvbvxplYd6/pCByMFJa76pKtcE2FG7pVAQZgLaLGemct4 q0MW73n7yBR1wDlTHqqKu1pAnz1CW3Eui96mDJJptG3CtNqe9a8G48Yzy5OuYAcI wxBWCbxeT2z+EuePOBGlQvPreyqyTjHXL87NqMEDrzFrdQd02rn90xqIPlCbcr/P qyRwIrDGFyV8PX9I4ewrtt9WfgttayHgZ4juaSi9F479oT6006z6vArrTg2Q/saA b0X+hG8oLGSZuSobASjjCtjTE+jYhr+4hzGuHJw0ky0CzLQOqf1APMKDwLN4m5Pz Ex+JKalozL+LElGMCS3q =cKuu -----END PGP SIGNATURE----- Merge tag 'rtc-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "Core: - use is_visible() to control sysfs attributes - switch wakealarm attribute to DEVICE_ATTR_RW - make rtc_does_wakealarm() return boolean - properly manage lifetime of dev and cdev in rtc device - remove unnecessary device_get() in rtc_device_unregister - fix double free in rtc_register_device() error path New drivers: - NXP LPC24xx - Xilinx Zynq MP - Dialog DA9062 Subsystem wide cleanups: - fix drivers that consider 0 as a valid IRQ in client->irq - Drop (un)likely before IS_ERR(_OR_NULL) - drop the remaining owner assignment for i2c_driver and platform_driver - module autoload fixes Drivers: - 88pm80x: add device tree support - abx80x: fix RTC write bit - ab8500: Add a sentinel to ab85xx_rtc_ids[] - armada38x: Align RTC set time procedure with the official errata - as3722: correct month value - at91sam9: cleanups - at91rm9200: get and use slow clock and cleanups - bq32k: remove redundant check - cmos: century support, proper fix for the spurious wakeup - ds1307: cleanups and wakeup irq support - ds1374: Remove unused variable - ds1685: Use module_platform_driver - ds3232: fix WARNING trace in resume function - gemini: fix ptr_ret.cocci warnings - mt6397: implement suspend/resume - omap: support internal and external clock enabling - opal: Enable alarms only when opal supports tpo - pcf2127: use OFS flag to detect unreliable date and warn the user - pl031: fix typo for author email - rx8025: huge cleanup and fixes - sa1100/pxa: share common code - s5m: fix to update ctrl register - s3c: fix clocks and wakeup, cleanup - sirfsoc: use regmap - nvram_read()/nvram_write() functions for cmos, ds1305, ds1307, ds1343, ds1511, ds1553, ds1742, m48t59, rp5c01, stk17ta8, tx4939 - use rtc_valid_tm() error code when reading date/time instead of 0 for isl12022, pcf2123, pcf2127" * tag 'rtc-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (90 commits) rtc: abx80x: fix RTC write bit rtc: ab8500: Add a sentinel to ab85xx_rtc_ids[] rtc: ds1374: Remove unused variable rtc: Fix module autoload for OF platform drivers rtc: Fix module autoload for rtc-{ab8500,max8997,s5m} drivers rtc: omap: Add external clock enabling support rtc: omap: Add internal clock enabling support ARM: dts: AM437x: Add the internal and external clock nodes for rtc rtc: s5m: fix to update ctrl register rtc: add xilinx zynqmp rtc driver devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc rtc: as3722: correct month value ARM: config: Switch PXA27x platforms to use PXA RTC driver ARM: mmp: remove unused RTC register definitions ARM: sa1100: remove unused RTC register definitions rtc: sa1100/pxa: convert to run-time register mapping ARM: pxa: add memory resource to SA1100 RTC device rtc: pxa: convert to use shared sa1100 functions rtc: sa1100: prepare to share sa1100_rtc_ops rtc: ds3232: fix WARNING trace in resume function ...
This commit is contained in:
Коммит
c19176154b
|
@ -0,0 +1,21 @@
|
|||
NXP LPC1788 real-time clock
|
||||
|
||||
The LPC1788 RTC provides calendar and clock functionality
|
||||
together with periodic tick and alarm interrupt support.
|
||||
|
||||
Required properties:
|
||||
- compatible : must contain "nxp,lpc1788-rtc"
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
- interrupts : A single interrupt specifier.
|
||||
- clocks : Must contain clock specifiers for rtc and register clock
|
||||
- clock-names : Must contain "rtc" and "reg"
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
|
||||
Example:
|
||||
rtc: rtc@40046000 {
|
||||
compatible = "nxp,lpc1788-rtc";
|
||||
reg = <0x40046000 0x1000>;
|
||||
interrupts = <47>;
|
||||
clocks = <&creg_clk 0>, <&ccu1 CLK_CPU_BUS>;
|
||||
clock-names = "rtc", "reg";
|
||||
};
|
|
@ -16,6 +16,8 @@ Required properties:
|
|||
Optional properties:
|
||||
- system-power-controller: whether the rtc is controlling the system power
|
||||
through pmic_power_en
|
||||
- clocks: Any internal or external clocks feeding in to rtc
|
||||
- clock-names: Corresponding names of the clocks
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -26,4 +28,6 @@ rtc@1c23000 {
|
|||
19>;
|
||||
interrupt-parent = <&intc>;
|
||||
system-power-controller;
|
||||
clocks = <&clk_32k_rtc>, <&clk_32768_ck>;
|
||||
clock-names = "ext-clk", "int-clk";
|
||||
};
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
* Xilinx Zynq Ultrascale+ MPSoC Real Time Clock
|
||||
|
||||
RTC controller for the Xilinx Zynq MPSoC Real Time Clock
|
||||
Separate IRQ lines for seconds and alarm
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "xlnx,zynqmp-rtc"
|
||||
- reg: Physical base address of the controller and length
|
||||
of memory mapped region.
|
||||
- interrupts: IRQ lines for the RTC.
|
||||
- interrupt-names: interrupt line names eg. "sec" "alarm"
|
||||
|
||||
Optional:
|
||||
- calibration: calibration value for 1 sec period which will
|
||||
be programmed directly to calibration register
|
||||
|
||||
Example:
|
||||
rtc: rtc@ffa60000 {
|
||||
compatible = "xlnx,zynqmp-rtc";
|
||||
reg = <0x0 0xffa60000 0x100>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 26 4>, <0 27 4>;
|
||||
interrupt-names = "alarm", "sec";
|
||||
calibration = <0x198233>;
|
||||
};
|
|
@ -358,6 +358,8 @@
|
|||
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH
|
||||
GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ti,hwmods = "rtc";
|
||||
clocks = <&clk_32768_ck>;
|
||||
clock-names = "int-clk";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -112,6 +112,13 @@
|
|||
clock-frequency = <12000000>;
|
||||
};
|
||||
|
||||
/* fixed 32k external oscillator clock */
|
||||
clk_32k_rtc: clk_32k_rtc {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
|
||||
sound0: sound@0 {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,name = "AM437x-GP-EVM";
|
||||
|
@ -941,3 +948,9 @@
|
|||
tx-num-evt = <32>;
|
||||
rx-num-evt = <32>;
|
||||
};
|
||||
|
||||
&rtc {
|
||||
clocks = <&clk_32k_rtc>, <&clk_32768_ck>;
|
||||
clock-names = "ext-clk", "int-clk";
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -110,6 +110,13 @@
|
|||
gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
/* fixed 32k external oscillator clock */
|
||||
clk_32k_rtc: clk_32k_rtc {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
};
|
||||
|
||||
&am43xx_pinmux {
|
||||
|
@ -394,6 +401,8 @@
|
|||
};
|
||||
|
||||
&rtc {
|
||||
clocks = <&clk_32k_rtc>, <&clk_32768_ck>;
|
||||
clock-names = "ext-clk", "int-clk";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,13 @@
|
|||
display0 = &lcd0;
|
||||
};
|
||||
|
||||
/* fixed 32k external oscillator clock */
|
||||
clk_32k_rtc: clk_32k_rtc {
|
||||
#clock-cells = <0>;
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <32768>;
|
||||
};
|
||||
|
||||
backlight {
|
||||
compatible = "pwm-backlight";
|
||||
pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>;
|
||||
|
@ -697,6 +704,8 @@
|
|||
};
|
||||
|
||||
&rtc {
|
||||
clocks = <&clk_32k_rtc>, <&clk_32768_ck>;
|
||||
clock-names = "ext-clk", "int-clk";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ CONFIG_LEDS_TRIGGERS=y
|
|||
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_V3020=y
|
||||
CONFIG_RTC_DRV_SA1100=y
|
||||
CONFIG_RTC_DRV_PXA=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=y
|
||||
CONFIG_INOTIFY=y
|
||||
|
|
|
@ -157,7 +157,7 @@ CONFIG_LEDS_TRIGGERS=y
|
|||
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_V3020=y
|
||||
CONFIG_RTC_DRV_SA1100=y
|
||||
CONFIG_RTC_DRV_PXA=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=y
|
||||
CONFIG_INOTIFY=y
|
||||
|
|
|
@ -150,7 +150,7 @@ CONFIG_LEDS_TRIGGERS=y
|
|||
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DEBUG=y
|
||||
CONFIG_RTC_DRV_SA1100=y
|
||||
CONFIG_RTC_DRV_PXA=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_INOTIFY=y
|
||||
CONFIG_MSDOS_FS=m
|
||||
|
|
|
@ -67,7 +67,7 @@ CONFIG_MMC=y
|
|||
CONFIG_MMC_DEBUG=y
|
||||
CONFIG_MMC_PXA=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_SA1100=y
|
||||
CONFIG_RTC_DRV_PXA=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=y
|
||||
# CONFIG_DNOTIFY is not set
|
||||
|
|
|
@ -82,7 +82,7 @@ CONFIG_MMC=y
|
|||
CONFIG_MMC_PXA=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_PCF8563=m
|
||||
CONFIG_RTC_DRV_SA1100=m
|
||||
CONFIG_RTC_DRV_PXA=m
|
||||
CONFIG_EXT2_FS=m
|
||||
CONFIG_EXT3_FS=m
|
||||
# CONFIG_DNOTIFY is not set
|
||||
|
|
|
@ -177,7 +177,7 @@ CONFIG_NEW_LEDS=y
|
|||
CONFIG_RTC_CLASS=y
|
||||
# CONFIG_RTC_HCTOSYS is not set
|
||||
CONFIG_RTC_DRV_PCF8583=m
|
||||
CONFIG_RTC_DRV_SA1100=y
|
||||
CONFIG_RTC_DRV_PXA=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT2_FS_XATTR=y
|
||||
CONFIG_EXT2_FS_POSIX_ACL=y
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef __ASM_MACH_REGS_RTC_H
|
||||
#define __ASM_MACH_REGS_RTC_H
|
||||
|
||||
#include <mach/addr-map.h>
|
||||
|
||||
#define RTC_VIRT_BASE (APB_VIRT_BASE + 0x10000)
|
||||
#define RTC_REG(x) (*((volatile u32 __iomem *)(RTC_VIRT_BASE + (x))))
|
||||
|
||||
/*
|
||||
* Real Time Clock
|
||||
*/
|
||||
|
||||
#define RCNR RTC_REG(0x00) /* RTC Count Register */
|
||||
#define RTAR RTC_REG(0x04) /* RTC Alarm Register */
|
||||
#define RTSR RTC_REG(0x08) /* RTC Status Register */
|
||||
#define RTTR RTC_REG(0x0C) /* RTC Timer Trim Register */
|
||||
|
||||
#define RTSR_HZE (1 << 3) /* HZ interrupt enable */
|
||||
#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */
|
||||
#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */
|
||||
#define RTSR_AL (1 << 0) /* RTC alarm detected */
|
||||
|
||||
#endif /* __ASM_MACH_REGS_RTC_H */
|
|
@ -440,25 +440,11 @@ struct platform_device pxa_device_rtc = {
|
|||
.resource = pxa_rtc_resources,
|
||||
};
|
||||
|
||||
static struct resource sa1100_rtc_resources[] = {
|
||||
{
|
||||
.start = IRQ_RTC1Hz,
|
||||
.end = IRQ_RTC1Hz,
|
||||
.name = "rtc 1Hz",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
.start = IRQ_RTCAlrm,
|
||||
.end = IRQ_RTCAlrm,
|
||||
.name = "rtc alarm",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device sa1100_device_rtc = {
|
||||
.name = "sa1100-rtc",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(sa1100_rtc_resources),
|
||||
.resource = sa1100_rtc_resources,
|
||||
.num_resources = ARRAY_SIZE(pxa_rtc_resources),
|
||||
.resource = pxa_rtc_resources,
|
||||
};
|
||||
|
||||
static struct resource pxa_ac97_resources[] = {
|
||||
|
|
|
@ -282,7 +282,6 @@ static struct platform_device *devices[] __initdata = {
|
|||
&pxa_device_asoc_ssp2,
|
||||
&pxa_device_asoc_ssp3,
|
||||
&pxa_device_asoc_platform,
|
||||
&sa1100_device_rtc,
|
||||
&pxa_device_rtc,
|
||||
&pxa27x_device_ssp1,
|
||||
&pxa27x_device_ssp2,
|
||||
|
|
|
@ -394,7 +394,6 @@ static struct platform_device *devices[] __initdata = {
|
|||
&pxa_device_asoc_ssp3,
|
||||
&pxa_device_asoc_ssp4,
|
||||
&pxa_device_asoc_platform,
|
||||
&sa1100_device_rtc,
|
||||
&pxa_device_rtc,
|
||||
&pxa3xx_device_ssp1,
|
||||
&pxa3xx_device_ssp2,
|
||||
|
|
|
@ -857,40 +857,6 @@
|
|||
#define OIER_E3 OIER_E (3) /* match interrupt Enable 3 */
|
||||
|
||||
|
||||
/*
|
||||
* Real-Time Clock (RTC) control registers
|
||||
*
|
||||
* Registers
|
||||
* RTAR Real-Time Clock (RTC) Alarm Register (read/write).
|
||||
* RCNR Real-Time Clock (RTC) CouNt Register (read/write).
|
||||
* RTTR Real-Time Clock (RTC) Trim Register (read/write).
|
||||
* RTSR Real-Time Clock (RTC) Status Register (read/write).
|
||||
*
|
||||
* Clocks
|
||||
* frtx, Trtx Frequency, period of the real-time clock crystal
|
||||
* (32.768 kHz nominal).
|
||||
* frtc, Trtc Frequency, period of the real-time clock counter
|
||||
* (1 Hz nominal).
|
||||
*/
|
||||
|
||||
#define RTAR __REG(0x90010000) /* RTC Alarm Reg. */
|
||||
#define RCNR __REG(0x90010004) /* RTC CouNt Reg. */
|
||||
#define RTTR __REG(0x90010008) /* RTC Trim Reg. */
|
||||
#define RTSR __REG(0x90010010) /* RTC Status Reg. */
|
||||
|
||||
#define RTTR_C Fld (16, 0) /* clock divider Count - 1 */
|
||||
#define RTTR_D Fld (10, 16) /* trim Delete count */
|
||||
/* frtc = (1023*(C + 1) - D)*frtx/ */
|
||||
/* (1023*(C + 1)^2) */
|
||||
/* Trtc = (1023*(C + 1)^2)*Trtx/ */
|
||||
/* (1023*(C + 1) - D) */
|
||||
|
||||
#define RTSR_AL 0x00000001 /* ALarm detected */
|
||||
#define RTSR_HZ 0x00000002 /* 1 Hz clock detected */
|
||||
#define RTSR_ALE 0x00000004 /* ALarm interrupt Enable */
|
||||
#define RTSR_HZE 0x00000008 /* 1 Hz clock interrupt Enable */
|
||||
|
||||
|
||||
/*
|
||||
* Power Manager (PM) control registers
|
||||
*
|
||||
|
|
|
@ -945,11 +945,11 @@ config RTC_DRV_DA9055
|
|||
will be called rtc-da9055
|
||||
|
||||
config RTC_DRV_DA9063
|
||||
tristate "Dialog Semiconductor DA9063 RTC"
|
||||
depends on MFD_DA9063
|
||||
tristate "Dialog Semiconductor DA9063/DA9062 RTC"
|
||||
depends on MFD_DA9063 || MFD_DA9062
|
||||
help
|
||||
If you say yes here you will get support for the RTC subsystem
|
||||
of the Dialog Semiconductor DA9063.
|
||||
for the Dialog Semiconductor PMIC chips DA9063 and DA9062.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called "rtc-da9063".
|
||||
|
@ -1116,6 +1116,13 @@ config RTC_DRV_OPAL
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-opal.
|
||||
|
||||
config RTC_DRV_ZYNQMP
|
||||
tristate "Xilinx Zynq Ultrascale+ MPSoC RTC"
|
||||
depends on OF
|
||||
help
|
||||
If you say yes here you get support for the RTC controller found on
|
||||
Xilinx Zynq Ultrascale+ MPSoC.
|
||||
|
||||
comment "on-CPU RTC drivers"
|
||||
|
||||
config RTC_DRV_DAVINCI
|
||||
|
@ -1306,11 +1313,13 @@ config RTC_DRV_GENERIC
|
|||
just say Y.
|
||||
|
||||
config RTC_DRV_PXA
|
||||
tristate "PXA27x/PXA3xx"
|
||||
depends on ARCH_PXA
|
||||
help
|
||||
If you say Y here you will get access to the real time clock
|
||||
built into your PXA27x or PXA3xx CPU.
|
||||
tristate "PXA27x/PXA3xx"
|
||||
depends on ARCH_PXA
|
||||
select RTC_DRV_SA1100
|
||||
help
|
||||
If you say Y here you will get access to the real time clock
|
||||
built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs
|
||||
consisting of an SA1100 compatible RTC and the extended PXA RTC.
|
||||
|
||||
This RTC driver uses PXA RTC registers available since pxa27x
|
||||
series (RDxR, RYxR) instead of legacy RCNR, RTAR.
|
||||
|
@ -1456,6 +1465,18 @@ config RTC_DRV_JZ4740
|
|||
This driver can also be buillt as a module. If so, the module
|
||||
will be called rtc-jz4740.
|
||||
|
||||
config RTC_DRV_LPC24XX
|
||||
tristate "NXP RTC for LPC178x/18xx/408x/43xx"
|
||||
depends on ARCH_LPC18XX || COMPILE_TEST
|
||||
depends on OF && HAS_IOMEM
|
||||
help
|
||||
This enables support for the NXP RTC found which can be found on
|
||||
NXP LPC178x/18xx/408x/43xx devices.
|
||||
|
||||
If you have one of the devices above enable this driver to use
|
||||
the hardware RTC. This driver can also be buillt as a module. If
|
||||
so, the module will be called rtc-lpc24xx.
|
||||
|
||||
config RTC_DRV_LPC32XX
|
||||
depends on ARCH_LPC32XX
|
||||
tristate "NXP LPC32XX RTC"
|
||||
|
|
|
@ -74,6 +74,7 @@ obj-$(CONFIG_RTC_DRV_ISL12057) += rtc-isl12057.o
|
|||
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
|
||||
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
|
||||
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
|
||||
obj-$(CONFIG_RTC_DRV_LPC24XX) += rtc-lpc24xx.o
|
||||
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
|
||||
obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
|
||||
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
|
||||
|
@ -158,3 +159,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
|
|||
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
|
||||
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
|
||||
obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
|
||||
obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o
|
||||
|
|
|
@ -202,6 +202,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
|||
rtc->max_user_freq = 64;
|
||||
rtc->dev.parent = dev;
|
||||
rtc->dev.class = rtc_class;
|
||||
rtc->dev.groups = rtc_get_dev_attribute_groups();
|
||||
rtc->dev.release = rtc_device_release;
|
||||
|
||||
mutex_init(&rtc->ops_lock);
|
||||
|
@ -234,12 +235,12 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
|||
|
||||
err = device_register(&rtc->dev);
|
||||
if (err) {
|
||||
/* This will free both memory and the ID */
|
||||
put_device(&rtc->dev);
|
||||
goto exit_kfree;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rtc_dev_add_device(rtc);
|
||||
rtc_sysfs_add_device(rtc);
|
||||
rtc_proc_add_device(rtc);
|
||||
|
||||
dev_info(dev, "rtc core: registered %s as %s\n",
|
||||
|
@ -247,9 +248,6 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
|||
|
||||
return rtc;
|
||||
|
||||
exit_kfree:
|
||||
kfree(rtc);
|
||||
|
||||
exit_ida:
|
||||
ida_simple_remove(&rtc_ida, id);
|
||||
|
||||
|
@ -268,19 +266,17 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
|
|||
*/
|
||||
void rtc_device_unregister(struct rtc_device *rtc)
|
||||
{
|
||||
if (get_device(&rtc->dev) != NULL) {
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
/* remove innards of this RTC, then disable it, before
|
||||
* letting any rtc_class_open() users access it again
|
||||
*/
|
||||
rtc_sysfs_del_device(rtc);
|
||||
rtc_dev_del_device(rtc);
|
||||
rtc_proc_del_device(rtc);
|
||||
device_unregister(&rtc->dev);
|
||||
rtc->ops = NULL;
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
put_device(&rtc->dev);
|
||||
}
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
/*
|
||||
* Remove innards of this RTC, then disable it, before
|
||||
* letting any rtc_class_open() users access it again
|
||||
*/
|
||||
rtc_dev_del_device(rtc);
|
||||
rtc_proc_del_device(rtc);
|
||||
device_del(&rtc->dev);
|
||||
rtc->ops = NULL;
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
put_device(&rtc->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_device_unregister);
|
||||
|
||||
|
@ -363,7 +359,6 @@ static int __init rtc_init(void)
|
|||
}
|
||||
rtc_class->pm = RTC_CLASS_DEV_PM_OPS;
|
||||
rtc_dev_init();
|
||||
rtc_sysfs_init(rtc_class);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -564,7 +564,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
|
|||
void rtc_update_irq(struct rtc_device *rtc,
|
||||
unsigned long num, unsigned long events)
|
||||
{
|
||||
if (unlikely(IS_ERR_OR_NULL(rtc)))
|
||||
if (IS_ERR_OR_NULL(rtc))
|
||||
return;
|
||||
|
||||
pm_stay_awake(rtc->dev.parent);
|
||||
|
|
|
@ -251,17 +251,26 @@ static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume);
|
|||
static int pm80x_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm80x_platform_data *pm80x_pdata =
|
||||
dev_get_platdata(pdev->dev.parent);
|
||||
struct pm80x_rtc_pdata *pdata = NULL;
|
||||
struct pm80x_rtc_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct pm80x_rtc_info *info;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct rtc_time tm;
|
||||
unsigned long ticks = 0;
|
||||
int ret;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
if (pdata == NULL)
|
||||
dev_warn(&pdev->dev, "No platform data!\n");
|
||||
if (!pdata && !node) {
|
||||
dev_err(&pdev->dev,
|
||||
"pm80x-rtc requires platform data or of_node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata) {
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
info =
|
||||
devm_kzalloc(&pdev->dev, sizeof(struct pm80x_rtc_info), GFP_KERNEL);
|
||||
|
@ -327,11 +336,8 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
|
|||
regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO,
|
||||
PM800_RTC1_USE_XO);
|
||||
|
||||
if (pm80x_pdata) {
|
||||
pdata = pm80x_pdata->rtc;
|
||||
if (pdata)
|
||||
info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup;
|
||||
}
|
||||
/* remember whether this power up is caused by PMIC RTC or not */
|
||||
info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup;
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
|
|
|
@ -1009,6 +1009,7 @@ static const struct of_device_id abb5zes3_dt_match[] = {
|
|||
{ .compatible = "abracon,abb5zes3" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, abb5zes3_dt_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id abb5zes3_id[] = {
|
||||
|
@ -1020,7 +1021,6 @@ MODULE_DEVICE_TABLE(i2c, abb5zes3_id);
|
|||
static struct i2c_driver abb5zes3_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &abb5zes3_rtc_pm_ops,
|
||||
.of_match_table = of_match_ptr(abb5zes3_dt_match),
|
||||
},
|
||||
|
|
|
@ -445,7 +445,9 @@ static const struct rtc_class_ops ab8540_rtc_ops = {
|
|||
static const struct platform_device_id ab85xx_rtc_ids[] = {
|
||||
{ "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, },
|
||||
{ "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids);
|
||||
|
||||
static int ab8500_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#define ABX8XX_REG_WD 0x07
|
||||
|
||||
#define ABX8XX_REG_CTRL1 0x10
|
||||
#define ABX8XX_CTRL_WRITE BIT(1)
|
||||
#define ABX8XX_CTRL_WRITE BIT(0)
|
||||
#define ABX8XX_CTRL_12_24 BIT(6)
|
||||
|
||||
#define ABX8XX_REG_CFG_KEY 0x1f
|
||||
|
|
|
@ -40,13 +40,6 @@ struct armada38x_rtc {
|
|||
void __iomem *regs;
|
||||
void __iomem *regs_soc;
|
||||
spinlock_t lock;
|
||||
/*
|
||||
* While setting the time, the RTC TIME register should not be
|
||||
* accessed. Setting the RTC time involves sleeping during
|
||||
* 100ms, so a mutex instead of a spinlock is used to protect
|
||||
* it
|
||||
*/
|
||||
struct mutex mutex_time;
|
||||
int irq;
|
||||
};
|
||||
|
||||
|
@ -64,9 +57,9 @@ static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
|
|||
static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned long time, time_check;
|
||||
unsigned long time, time_check, flags;
|
||||
|
||||
mutex_lock(&rtc->mutex_time);
|
||||
spin_lock_irqsave(&rtc->lock, flags);
|
||||
time = readl(rtc->regs + RTC_TIME);
|
||||
/*
|
||||
* WA for failing time set attempts. As stated in HW ERRATA if
|
||||
|
@ -77,7 +70,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
if ((time_check - time) > 1)
|
||||
time_check = readl(rtc->regs + RTC_TIME);
|
||||
|
||||
mutex_unlock(&rtc->mutex_time);
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
rtc_time_to_tm(time_check, tm);
|
||||
|
||||
|
@ -88,23 +81,23 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
{
|
||||
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
unsigned long time;
|
||||
unsigned long time, flags;
|
||||
|
||||
ret = rtc_tm_to_time(tm, &time);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
/*
|
||||
* Setting the RTC time not always succeeds. According to the
|
||||
* errata we need to first write on the status register and
|
||||
* then wait for 100ms before writing to the time register to be
|
||||
* sure that the data will be taken into account.
|
||||
* According to errata FE-3124064, Write to RTC TIME register
|
||||
* may fail. As a workaround, after writing to RTC TIME
|
||||
* register, issue a dummy write of 0x0 twice to RTC Status
|
||||
* register.
|
||||
*/
|
||||
mutex_lock(&rtc->mutex_time);
|
||||
rtc_delayed_write(0, rtc, RTC_STATUS);
|
||||
msleep(100);
|
||||
spin_lock_irqsave(&rtc->lock, flags);
|
||||
rtc_delayed_write(time, rtc, RTC_TIME);
|
||||
mutex_unlock(&rtc->mutex_time);
|
||||
rtc_delayed_write(0, rtc, RTC_STATUS);
|
||||
rtc_delayed_write(0, rtc, RTC_STATUS);
|
||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -229,7 +222,6 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&rtc->lock);
|
||||
mutex_init(&rtc->mutex_time);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
|
||||
rtc->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
@ -303,6 +295,7 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = {
|
|||
{ .compatible = "marvell,armada-380-rtc", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
|
||||
#endif
|
||||
|
||||
static struct platform_driver armada38x_rtc_driver = {
|
||||
|
|
|
@ -45,7 +45,7 @@ static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm)
|
|||
rbuff[1] = bin2bcd(tm->tm_min);
|
||||
rbuff[2] = bin2bcd(tm->tm_hour);
|
||||
rbuff[3] = bin2bcd(tm->tm_mday);
|
||||
rbuff[4] = bin2bcd(tm->tm_mon);
|
||||
rbuff[4] = bin2bcd(tm->tm_mon + 1);
|
||||
rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900));
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm)
|
|||
tm->tm_min = bcd2bin(rbuff[1] & 0x7F);
|
||||
tm->tm_hour = bcd2bin(rbuff[2] & 0x3F);
|
||||
tm->tm_mday = bcd2bin(rbuff[3] & 0x3F);
|
||||
tm->tm_mon = bcd2bin(rbuff[4] & 0x1F);
|
||||
tm->tm_mon = bcd2bin(rbuff[4] & 0x1F) - 1;
|
||||
tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -18,20 +18,21 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "rtc-at91rm9200.h"
|
||||
|
@ -59,6 +60,7 @@ static bool suspended;
|
|||
static DEFINE_SPINLOCK(suspended_lock);
|
||||
static unsigned long cached_events;
|
||||
static u32 at91_rtc_imr;
|
||||
static struct clk *sclk;
|
||||
|
||||
static void at91_rtc_write_ier(u32 mask)
|
||||
{
|
||||
|
@ -407,6 +409,16 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sclk))
|
||||
return PTR_ERR(sclk);
|
||||
|
||||
ret = clk_prepare_enable(sclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not enable slow clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
at91_rtc_write(AT91_RTC_CR, 0);
|
||||
at91_rtc_write(AT91_RTC_MR, 0); /* 24 hour mode */
|
||||
|
||||
|
@ -420,7 +432,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
|||
"at91_rtc", pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
|
||||
return ret;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* cpu init code should really have flagged this device as
|
||||
|
@ -431,8 +443,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&at91_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
if (IS_ERR(rtc)) {
|
||||
ret = PTR_ERR(rtc);
|
||||
goto err_clk;
|
||||
}
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
/* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy
|
||||
|
@ -442,6 +456,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(sclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -454,6 +473,8 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
|
|||
AT91_RTC_SECEV | AT91_RTC_TIMEV |
|
||||
AT91_RTC_CALEV);
|
||||
|
||||
clk_disable_unprepare(sclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,20 +11,20 @@
|
|||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_data/atmel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
/*
|
||||
* This driver uses two configurable hardware resources that live in the
|
||||
|
@ -425,18 +425,19 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(rtc->sclk))
|
||||
return PTR_ERR(rtc->sclk);
|
||||
|
||||
sclk_rate = clk_get_rate(rtc->sclk);
|
||||
if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) {
|
||||
dev_err(&pdev->dev, "Invalid slow clock rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rtc->sclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not enable slow clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
sclk_rate = clk_get_rate(rtc->sclk);
|
||||
if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) {
|
||||
dev_err(&pdev->dev, "Invalid slow clock rate\n");
|
||||
ret = -EINVAL;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
mr = rtt_readl(rtc, MR);
|
||||
|
||||
/* unless RTT is counting at 1 Hz, re-initialize it */
|
||||
|
@ -451,8 +452,10 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&at91_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtcdev))
|
||||
return PTR_ERR(rtc->rtcdev);
|
||||
if (IS_ERR(rtc->rtcdev)) {
|
||||
ret = PTR_ERR(rtc->rtcdev);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* register irq handler after we know what name we'll use */
|
||||
ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
|
||||
|
@ -460,7 +463,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
|||
dev_name(&rtc->rtcdev->dev), rtc);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
|
||||
return ret;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* NOTE: sam9260 rev A silicon has a ROM bug which resets the
|
||||
|
@ -474,6 +477,11 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
|||
dev_name(&rtc->rtcdev->dev));
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(rtc->sclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -487,8 +495,7 @@ static int at91_rtc_remove(struct platform_device *pdev)
|
|||
/* disable all interrupts */
|
||||
rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
|
||||
|
||||
if (!IS_ERR(rtc->sclk))
|
||||
clk_disable_unprepare(rtc->sclk);
|
||||
clk_disable_unprepare(rtc->sclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -361,7 +361,7 @@ static int bfin_rtc_probe(struct platform_device *pdev)
|
|||
/* Register our RTC with the RTC framework */
|
||||
rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops,
|
||||
THIS_MODULE);
|
||||
if (unlikely(IS_ERR(rtc->rtc_dev)))
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
/* Grab the IRQ and init the hardware */
|
||||
|
|
|
@ -212,7 +212,7 @@ static int bq32k_probe(struct i2c_client *client,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
if (client && client->dev.of_node)
|
||||
if (client->dev.of_node)
|
||||
trickle_charger_of_init(dev, client->dev.of_node);
|
||||
|
||||
rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name,
|
||||
|
@ -234,7 +234,6 @@ MODULE_DEVICE_TABLE(i2c, bq32k_id);
|
|||
static struct i2c_driver bq32k_driver = {
|
||||
.driver = {
|
||||
.name = "bq32k",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = bq32k_probe,
|
||||
.id_table = bq32k_id,
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
|
||||
#include <asm-generic/rtc.h>
|
||||
|
@ -51,6 +50,7 @@ struct cmos_rtc {
|
|||
struct device *dev;
|
||||
int irq;
|
||||
struct resource *iomem;
|
||||
time64_t alarm_expires;
|
||||
|
||||
void (*wake_on)(struct device *);
|
||||
void (*wake_off)(struct device *);
|
||||
|
@ -377,53 +377,11 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
cmos->alarm_expires = rtc_tm_to_time64(&t->time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes.
|
||||
*/
|
||||
static bool alarm_disable_quirk;
|
||||
|
||||
static int __init set_alarm_disable_quirk(const struct dmi_system_id *id)
|
||||
{
|
||||
alarm_disable_quirk = true;
|
||||
pr_info("BIOS has alarm-disable quirk - RTC alarms disabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id rtc_quirks[] __initconst = {
|
||||
/* https://bugzilla.novell.com/show_bug.cgi?id=805740 */
|
||||
{
|
||||
.callback = set_alarm_disable_quirk,
|
||||
.ident = "IBM Truman",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "4852570"),
|
||||
},
|
||||
},
|
||||
/* https://bugzilla.novell.com/show_bug.cgi?id=812592 */
|
||||
{
|
||||
.callback = set_alarm_disable_quirk,
|
||||
.ident = "Gigabyte GA-990XA-UD3",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR,
|
||||
"Gigabyte Technology Co., Ltd."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"),
|
||||
},
|
||||
},
|
||||
/* http://permalink.gmane.org/gmane.linux.kernel/1604474 */
|
||||
{
|
||||
.callback = set_alarm_disable_quirk,
|
||||
.ident = "Toshiba Satellite L300",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
|
@ -432,9 +390,6 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
if (!is_valid_irq(cmos->irq))
|
||||
return -EINVAL;
|
||||
|
||||
if (alarm_disable_quirk)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
|
||||
if (enabled)
|
||||
|
@ -512,13 +467,6 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
{
|
||||
int retval;
|
||||
|
||||
if (unlikely(off >= attr->size))
|
||||
return 0;
|
||||
if (unlikely(off < 0))
|
||||
return -EINVAL;
|
||||
if ((off + count) > attr->size)
|
||||
count = attr->size - off;
|
||||
|
||||
off += NVRAM_OFFSET;
|
||||
spin_lock_irq(&rtc_lock);
|
||||
for (retval = 0; count; count--, off++, retval++) {
|
||||
|
@ -543,12 +491,6 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
int retval;
|
||||
|
||||
cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
|
||||
if (unlikely(off >= attr->size))
|
||||
return -EFBIG;
|
||||
if (unlikely(off < 0))
|
||||
return -EINVAL;
|
||||
if ((off + count) > attr->size)
|
||||
count = attr->size - off;
|
||||
|
||||
/* NOTE: on at least PCs and Ataris, the boot firmware uses a
|
||||
* checksum on part of the NVRAM data. That's currently ignored
|
||||
|
@ -860,6 +802,51 @@ static void __exit cmos_do_remove(struct device *dev)
|
|||
cmos->dev = NULL;
|
||||
}
|
||||
|
||||
static int cmos_aie_poweroff(struct device *dev)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
struct rtc_time now;
|
||||
time64_t t_now;
|
||||
int retval = 0;
|
||||
unsigned char rtc_control;
|
||||
|
||||
if (!cmos->alarm_expires)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
/* We only care about the situation where AIE is disabled. */
|
||||
if (rtc_control & RTC_AIE)
|
||||
return -EBUSY;
|
||||
|
||||
cmos_read_time(dev, &now);
|
||||
t_now = rtc_tm_to_time64(&now);
|
||||
|
||||
/*
|
||||
* When enabling "RTC wake-up" in BIOS setup, the machine reboots
|
||||
* automatically right after shutdown on some buggy boxes.
|
||||
* This automatic rebooting issue won't happen when the alarm
|
||||
* time is larger than now+1 seconds.
|
||||
*
|
||||
* If the alarm time is equal to now+1 seconds, the issue can be
|
||||
* prevented by cancelling the alarm.
|
||||
*/
|
||||
if (cmos->alarm_expires == t_now + 1) {
|
||||
struct rtc_wkalrm alarm;
|
||||
|
||||
/* Cancel the AIE timer by configuring the past time. */
|
||||
rtc_time64_to_tm(t_now - 1, &alarm.time);
|
||||
alarm.enabled = 0;
|
||||
retval = cmos_set_alarm(dev, &alarm);
|
||||
} else if (cmos->alarm_expires > t_now + 1) {
|
||||
retval = -EBUSY;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int cmos_suspend(struct device *dev)
|
||||
|
@ -1094,8 +1081,12 @@ static void cmos_pnp_shutdown(struct pnp_dev *pnp)
|
|||
struct device *dev = &pnp->dev;
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
|
||||
if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
|
||||
return;
|
||||
if (system_state == SYSTEM_POWER_OFF) {
|
||||
int retval = cmos_poweroff(dev);
|
||||
|
||||
if (cmos_aie_poweroff(dev) < 0 && !retval)
|
||||
return;
|
||||
}
|
||||
|
||||
cmos_do_shutdown(cmos->irq);
|
||||
}
|
||||
|
@ -1200,8 +1191,12 @@ static void cmos_platform_shutdown(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
|
||||
if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
|
||||
return;
|
||||
if (system_state == SYSTEM_POWER_OFF) {
|
||||
int retval = cmos_poweroff(dev);
|
||||
|
||||
if (cmos_aie_poweroff(dev) < 0 && !retval)
|
||||
return;
|
||||
}
|
||||
|
||||
cmos_do_shutdown(cmos->irq);
|
||||
}
|
||||
|
@ -1243,8 +1238,6 @@ static int __init cmos_init(void)
|
|||
platform_driver_registered = true;
|
||||
}
|
||||
|
||||
dmi_check_system(rtc_quirks);
|
||||
|
||||
if (retval == 0)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -263,6 +263,7 @@ static const struct of_device_id coh901331_dt_match[] = {
|
|||
{ .compatible = "stericsson,coh901331" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, coh901331_dt_match);
|
||||
|
||||
static struct platform_driver coh901331_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -48,23 +48,10 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc)
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_RTC_INTF_SYSFS
|
||||
|
||||
extern void __init rtc_sysfs_init(struct class *);
|
||||
extern void rtc_sysfs_add_device(struct rtc_device *rtc);
|
||||
extern void rtc_sysfs_del_device(struct rtc_device *rtc);
|
||||
|
||||
const struct attribute_group **rtc_get_dev_attribute_groups(void);
|
||||
#else
|
||||
|
||||
static inline void rtc_sysfs_init(struct class *rtc)
|
||||
static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void rtc_sysfs_add_device(struct rtc_device *rtc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rtc_sysfs_del_device(struct rtc_device *rtc)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,15 +12,18 @@
|
|||
* Library General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/mfd/da9062/registers.h>
|
||||
#include <linux/mfd/da9063/registers.h>
|
||||
#include <linux/mfd/da9063/core.h>
|
||||
|
||||
|
@ -29,99 +32,231 @@
|
|||
#define YEARS_FROM_DA9063(year) ((year) + 100)
|
||||
#define MONTHS_FROM_DA9063(month) ((month) - 1)
|
||||
|
||||
#define RTC_ALARM_DATA_LEN (DA9063_AD_REG_ALARM_Y - DA9063_AD_REG_ALARM_MI + 1)
|
||||
|
||||
#define RTC_DATA_LEN (DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1)
|
||||
#define RTC_SEC 0
|
||||
#define RTC_MIN 1
|
||||
#define RTC_HOUR 2
|
||||
#define RTC_DAY 3
|
||||
#define RTC_MONTH 4
|
||||
#define RTC_YEAR 5
|
||||
|
||||
struct da9063_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
struct da9063 *hw;
|
||||
struct rtc_time alarm_time;
|
||||
bool rtc_sync;
|
||||
int alarm_year;
|
||||
int alarm_start;
|
||||
int alarm_len;
|
||||
int data_start;
|
||||
enum {
|
||||
RTC_SEC = 0,
|
||||
RTC_MIN = 1,
|
||||
RTC_HOUR = 2,
|
||||
RTC_DAY = 3,
|
||||
RTC_MONTH = 4,
|
||||
RTC_YEAR = 5,
|
||||
RTC_DATA_LEN
|
||||
};
|
||||
|
||||
static void da9063_data_to_tm(u8 *data, struct rtc_time *tm)
|
||||
struct da9063_compatible_rtc_regmap {
|
||||
/* REGS */
|
||||
int rtc_enable_reg;
|
||||
int rtc_enable_32k_crystal_reg;
|
||||
int rtc_alarm_secs_reg;
|
||||
int rtc_alarm_year_reg;
|
||||
int rtc_count_secs_reg;
|
||||
int rtc_count_year_reg;
|
||||
int rtc_event_reg;
|
||||
/* MASKS */
|
||||
int rtc_enable_mask;
|
||||
int rtc_crystal_mask;
|
||||
int rtc_event_alarm_mask;
|
||||
int rtc_alarm_on_mask;
|
||||
int rtc_alarm_status_mask;
|
||||
int rtc_tick_on_mask;
|
||||
int rtc_ready_to_read_mask;
|
||||
int rtc_count_sec_mask;
|
||||
int rtc_count_min_mask;
|
||||
int rtc_count_hour_mask;
|
||||
int rtc_count_day_mask;
|
||||
int rtc_count_month_mask;
|
||||
int rtc_count_year_mask;
|
||||
/* ALARM CONFIG */
|
||||
int rtc_data_start;
|
||||
int rtc_alarm_len;
|
||||
};
|
||||
|
||||
struct da9063_compatible_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
struct rtc_time alarm_time;
|
||||
struct regmap *regmap;
|
||||
const struct da9063_compatible_rtc_regmap *config;
|
||||
bool rtc_sync;
|
||||
};
|
||||
|
||||
static const struct da9063_compatible_rtc_regmap da9063_ad_regs = {
|
||||
/* REGS */
|
||||
.rtc_enable_reg = DA9063_REG_CONTROL_E,
|
||||
.rtc_alarm_secs_reg = DA9063_AD_REG_ALARM_MI,
|
||||
.rtc_alarm_year_reg = DA9063_AD_REG_ALARM_Y,
|
||||
.rtc_count_secs_reg = DA9063_REG_COUNT_S,
|
||||
.rtc_count_year_reg = DA9063_REG_COUNT_Y,
|
||||
.rtc_event_reg = DA9063_REG_EVENT_A,
|
||||
/* MASKS */
|
||||
.rtc_enable_mask = DA9063_RTC_EN,
|
||||
.rtc_crystal_mask = DA9063_CRYSTAL,
|
||||
.rtc_enable_32k_crystal_reg = DA9063_REG_EN_32K,
|
||||
.rtc_event_alarm_mask = DA9063_E_ALARM,
|
||||
.rtc_alarm_on_mask = DA9063_ALARM_ON,
|
||||
.rtc_alarm_status_mask = DA9063_ALARM_STATUS_ALARM |
|
||||
DA9063_ALARM_STATUS_TICK,
|
||||
.rtc_tick_on_mask = DA9063_TICK_ON,
|
||||
.rtc_ready_to_read_mask = DA9063_RTC_READ,
|
||||
.rtc_count_sec_mask = DA9063_COUNT_SEC_MASK,
|
||||
.rtc_count_min_mask = DA9063_COUNT_MIN_MASK,
|
||||
.rtc_count_hour_mask = DA9063_COUNT_HOUR_MASK,
|
||||
.rtc_count_day_mask = DA9063_COUNT_DAY_MASK,
|
||||
.rtc_count_month_mask = DA9063_COUNT_MONTH_MASK,
|
||||
.rtc_count_year_mask = DA9063_COUNT_YEAR_MASK,
|
||||
/* ALARM CONFIG */
|
||||
.rtc_data_start = RTC_MIN,
|
||||
.rtc_alarm_len = RTC_DATA_LEN - 1,
|
||||
};
|
||||
|
||||
static const struct da9063_compatible_rtc_regmap da9063_bb_regs = {
|
||||
/* REGS */
|
||||
.rtc_enable_reg = DA9063_REG_CONTROL_E,
|
||||
.rtc_alarm_secs_reg = DA9063_BB_REG_ALARM_S,
|
||||
.rtc_alarm_year_reg = DA9063_BB_REG_ALARM_Y,
|
||||
.rtc_count_secs_reg = DA9063_REG_COUNT_S,
|
||||
.rtc_count_year_reg = DA9063_REG_COUNT_Y,
|
||||
.rtc_event_reg = DA9063_REG_EVENT_A,
|
||||
/* MASKS */
|
||||
.rtc_enable_mask = DA9063_RTC_EN,
|
||||
.rtc_crystal_mask = DA9063_CRYSTAL,
|
||||
.rtc_enable_32k_crystal_reg = DA9063_REG_EN_32K,
|
||||
.rtc_event_alarm_mask = DA9063_E_ALARM,
|
||||
.rtc_alarm_on_mask = DA9063_ALARM_ON,
|
||||
.rtc_alarm_status_mask = DA9063_ALARM_STATUS_ALARM |
|
||||
DA9063_ALARM_STATUS_TICK,
|
||||
.rtc_tick_on_mask = DA9063_TICK_ON,
|
||||
.rtc_ready_to_read_mask = DA9063_RTC_READ,
|
||||
.rtc_count_sec_mask = DA9063_COUNT_SEC_MASK,
|
||||
.rtc_count_min_mask = DA9063_COUNT_MIN_MASK,
|
||||
.rtc_count_hour_mask = DA9063_COUNT_HOUR_MASK,
|
||||
.rtc_count_day_mask = DA9063_COUNT_DAY_MASK,
|
||||
.rtc_count_month_mask = DA9063_COUNT_MONTH_MASK,
|
||||
.rtc_count_year_mask = DA9063_COUNT_YEAR_MASK,
|
||||
/* ALARM CONFIG */
|
||||
.rtc_data_start = RTC_SEC,
|
||||
.rtc_alarm_len = RTC_DATA_LEN,
|
||||
};
|
||||
|
||||
static const struct da9063_compatible_rtc_regmap da9062_aa_regs = {
|
||||
/* REGS */
|
||||
.rtc_enable_reg = DA9062AA_CONTROL_E,
|
||||
.rtc_alarm_secs_reg = DA9062AA_ALARM_S,
|
||||
.rtc_alarm_year_reg = DA9062AA_ALARM_Y,
|
||||
.rtc_count_secs_reg = DA9062AA_COUNT_S,
|
||||
.rtc_count_year_reg = DA9062AA_COUNT_Y,
|
||||
.rtc_event_reg = DA9062AA_EVENT_A,
|
||||
/* MASKS */
|
||||
.rtc_enable_mask = DA9062AA_RTC_EN_MASK,
|
||||
.rtc_crystal_mask = DA9062AA_CRYSTAL_MASK,
|
||||
.rtc_enable_32k_crystal_reg = DA9062AA_EN_32K,
|
||||
.rtc_event_alarm_mask = DA9062AA_M_ALARM_MASK,
|
||||
.rtc_alarm_on_mask = DA9062AA_ALARM_ON_MASK,
|
||||
.rtc_alarm_status_mask = (0x02 << 6),
|
||||
.rtc_tick_on_mask = DA9062AA_TICK_ON_MASK,
|
||||
.rtc_ready_to_read_mask = DA9062AA_RTC_READ_MASK,
|
||||
.rtc_count_sec_mask = DA9062AA_COUNT_SEC_MASK,
|
||||
.rtc_count_min_mask = DA9062AA_COUNT_MIN_MASK,
|
||||
.rtc_count_hour_mask = DA9062AA_COUNT_HOUR_MASK,
|
||||
.rtc_count_day_mask = DA9062AA_COUNT_DAY_MASK,
|
||||
.rtc_count_month_mask = DA9062AA_COUNT_MONTH_MASK,
|
||||
.rtc_count_year_mask = DA9062AA_COUNT_YEAR_MASK,
|
||||
/* ALARM CONFIG */
|
||||
.rtc_data_start = RTC_SEC,
|
||||
.rtc_alarm_len = RTC_DATA_LEN,
|
||||
};
|
||||
|
||||
static const struct of_device_id da9063_compatible_reg_id_table[] = {
|
||||
{ .compatible = "dlg,da9063-rtc", .data = &da9063_bb_regs },
|
||||
{ .compatible = "dlg,da9062-rtc", .data = &da9062_aa_regs },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
|
||||
|
||||
static void da9063_data_to_tm(u8 *data, struct rtc_time *tm,
|
||||
struct da9063_compatible_rtc *rtc)
|
||||
{
|
||||
tm->tm_sec = data[RTC_SEC] & DA9063_COUNT_SEC_MASK;
|
||||
tm->tm_min = data[RTC_MIN] & DA9063_COUNT_MIN_MASK;
|
||||
tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK;
|
||||
tm->tm_mday = data[RTC_DAY] & DA9063_COUNT_DAY_MASK;
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
|
||||
tm->tm_sec = data[RTC_SEC] & config->rtc_count_sec_mask;
|
||||
tm->tm_min = data[RTC_MIN] & config->rtc_count_min_mask;
|
||||
tm->tm_hour = data[RTC_HOUR] & config->rtc_count_hour_mask;
|
||||
tm->tm_mday = data[RTC_DAY] & config->rtc_count_day_mask;
|
||||
tm->tm_mon = MONTHS_FROM_DA9063(data[RTC_MONTH] &
|
||||
DA9063_COUNT_MONTH_MASK);
|
||||
config->rtc_count_month_mask);
|
||||
tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] &
|
||||
DA9063_COUNT_YEAR_MASK);
|
||||
config->rtc_count_year_mask);
|
||||
}
|
||||
|
||||
static void da9063_tm_to_data(struct rtc_time *tm, u8 *data)
|
||||
static void da9063_tm_to_data(struct rtc_time *tm, u8 *data,
|
||||
struct da9063_compatible_rtc *rtc)
|
||||
{
|
||||
data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK;
|
||||
data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK;
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
|
||||
data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK;
|
||||
data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK;
|
||||
data[RTC_SEC] &= ~config->rtc_count_sec_mask;
|
||||
data[RTC_SEC] |= tm->tm_sec & config->rtc_count_sec_mask;
|
||||
|
||||
data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK;
|
||||
data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK;
|
||||
data[RTC_MIN] &= ~config->rtc_count_min_mask;
|
||||
data[RTC_MIN] |= tm->tm_min & config->rtc_count_min_mask;
|
||||
|
||||
data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK;
|
||||
data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK;
|
||||
data[RTC_HOUR] &= ~config->rtc_count_hour_mask;
|
||||
data[RTC_HOUR] |= tm->tm_hour & config->rtc_count_hour_mask;
|
||||
|
||||
data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK;
|
||||
data[RTC_DAY] &= ~config->rtc_count_day_mask;
|
||||
data[RTC_DAY] |= tm->tm_mday & config->rtc_count_day_mask;
|
||||
|
||||
data[RTC_MONTH] &= ~config->rtc_count_month_mask;
|
||||
data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) &
|
||||
DA9063_COUNT_MONTH_MASK;
|
||||
config->rtc_count_month_mask;
|
||||
|
||||
data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK;
|
||||
data[RTC_YEAR] &= ~config->rtc_count_year_mask;
|
||||
data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) &
|
||||
DA9063_COUNT_YEAR_MASK;
|
||||
config->rtc_count_year_mask;
|
||||
}
|
||||
|
||||
static int da9063_rtc_stop_alarm(struct device *dev)
|
||||
{
|
||||
struct da9063_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
|
||||
return regmap_update_bits(rtc->hw->regmap, rtc->alarm_year,
|
||||
DA9063_ALARM_ON, 0);
|
||||
return regmap_update_bits(rtc->regmap,
|
||||
config->rtc_alarm_year_reg,
|
||||
config->rtc_alarm_on_mask,
|
||||
0);
|
||||
}
|
||||
|
||||
static int da9063_rtc_start_alarm(struct device *dev)
|
||||
{
|
||||
struct da9063_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
|
||||
return regmap_update_bits(rtc->hw->regmap, rtc->alarm_year,
|
||||
DA9063_ALARM_ON, DA9063_ALARM_ON);
|
||||
return regmap_update_bits(rtc->regmap,
|
||||
config->rtc_alarm_year_reg,
|
||||
config->rtc_alarm_on_mask,
|
||||
config->rtc_alarm_on_mask);
|
||||
}
|
||||
|
||||
static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct da9063_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
unsigned long tm_secs;
|
||||
unsigned long al_secs;
|
||||
u8 data[RTC_DATA_LEN];
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S,
|
||||
ret = regmap_bulk_read(rtc->regmap,
|
||||
config->rtc_count_secs_reg,
|
||||
data, RTC_DATA_LEN);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read RTC time data: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(data[RTC_SEC] & DA9063_RTC_READ)) {
|
||||
if (!(data[RTC_SEC] & config->rtc_ready_to_read_mask)) {
|
||||
dev_dbg(dev, "RTC not yet ready to be read by the host\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
da9063_data_to_tm(data, tm);
|
||||
da9063_data_to_tm(data, tm, rtc);
|
||||
|
||||
rtc_tm_to_time(tm, &tm_secs);
|
||||
rtc_tm_to_time(&rtc->alarm_time, &al_secs);
|
||||
|
@ -137,12 +272,14 @@ static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
|
||||
static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct da9063_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
u8 data[RTC_DATA_LEN];
|
||||
int ret;
|
||||
|
||||
da9063_tm_to_data(tm, data);
|
||||
ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S,
|
||||
da9063_tm_to_data(tm, data, rtc);
|
||||
ret = regmap_bulk_write(rtc->regmap,
|
||||
config->rtc_count_secs_reg,
|
||||
data, RTC_DATA_LEN);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to set RTC time data: %d\n", ret);
|
||||
|
@ -152,26 +289,31 @@ static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
|
||||
static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct da9063_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
u8 data[RTC_DATA_LEN];
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
data[RTC_SEC] = 0;
|
||||
ret = regmap_bulk_read(rtc->hw->regmap, rtc->alarm_start,
|
||||
&data[rtc->data_start], rtc->alarm_len);
|
||||
ret = regmap_bulk_read(rtc->regmap,
|
||||
config->rtc_alarm_secs_reg,
|
||||
&data[config->rtc_data_start],
|
||||
config->rtc_alarm_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
da9063_data_to_tm(data, &alrm->time);
|
||||
da9063_data_to_tm(data, &alrm->time, rtc);
|
||||
|
||||
alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON);
|
||||
alrm->enabled = !!(data[RTC_YEAR] & config->rtc_alarm_on_mask);
|
||||
|
||||
ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val);
|
||||
ret = regmap_read(rtc->regmap,
|
||||
config->rtc_event_reg,
|
||||
&val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (val & (DA9063_E_ALARM))
|
||||
if (val & config->rtc_event_alarm_mask)
|
||||
alrm->pending = 1;
|
||||
else
|
||||
alrm->pending = 0;
|
||||
|
@ -181,11 +323,12 @@ static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
|
||||
static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct da9063_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
u8 data[RTC_DATA_LEN];
|
||||
int ret;
|
||||
|
||||
da9063_tm_to_data(&alrm->time, data);
|
||||
da9063_tm_to_data(&alrm->time, data, rtc);
|
||||
|
||||
ret = da9063_rtc_stop_alarm(dev);
|
||||
if (ret < 0) {
|
||||
|
@ -193,14 +336,16 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_write(rtc->hw->regmap, rtc->alarm_start,
|
||||
&data[rtc->data_start], rtc->alarm_len);
|
||||
ret = regmap_bulk_write(rtc->regmap,
|
||||
config->rtc_alarm_secs_reg,
|
||||
&data[config->rtc_data_start],
|
||||
config->rtc_alarm_len);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to write alarm: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
da9063_data_to_tm(data, &rtc->alarm_time);
|
||||
da9063_data_to_tm(data, &rtc->alarm_time, rtc);
|
||||
|
||||
if (alrm->enabled) {
|
||||
ret = da9063_rtc_start_alarm(dev);
|
||||
|
@ -213,7 +358,8 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
static int da9063_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enabled)
|
||||
{
|
||||
if (enabled)
|
||||
return da9063_rtc_start_alarm(dev);
|
||||
|
@ -223,10 +369,13 @@ static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
|
||||
static irqreturn_t da9063_alarm_event(int irq, void *data)
|
||||
{
|
||||
struct da9063_rtc *rtc = data;
|
||||
struct da9063_compatible_rtc *rtc = data;
|
||||
const struct da9063_compatible_rtc_regmap *config = rtc->config;
|
||||
|
||||
regmap_update_bits(rtc->hw->regmap, rtc->alarm_year,
|
||||
DA9063_ALARM_ON, 0);
|
||||
regmap_update_bits(rtc->regmap,
|
||||
config->rtc_alarm_year_reg,
|
||||
config->rtc_alarm_on_mask,
|
||||
0);
|
||||
|
||||
rtc->rtc_sync = true;
|
||||
rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
|
||||
|
@ -244,72 +393,92 @@ static const struct rtc_class_ops da9063_rtc_ops = {
|
|||
|
||||
static int da9063_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct da9063_rtc *rtc;
|
||||
struct da9063_compatible_rtc *rtc;
|
||||
const struct da9063_compatible_rtc_regmap *config;
|
||||
const struct of_device_id *match;
|
||||
int irq_alarm;
|
||||
u8 data[RTC_DATA_LEN];
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E,
|
||||
DA9063_RTC_EN, DA9063_RTC_EN);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to enable RTC\n");
|
||||
goto err;
|
||||
}
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENXIO;
|
||||
|
||||
ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K,
|
||||
DA9063_CRYSTAL, DA9063_CRYSTAL);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n");
|
||||
goto err;
|
||||
}
|
||||
match = of_match_node(da9063_compatible_reg_id_table,
|
||||
pdev->dev.of_node);
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
if (da9063->variant_code == PMIC_DA9063_AD) {
|
||||
rtc->alarm_year = DA9063_AD_REG_ALARM_Y;
|
||||
rtc->alarm_start = DA9063_AD_REG_ALARM_MI;
|
||||
rtc->alarm_len = RTC_ALARM_DATA_LEN;
|
||||
rtc->data_start = RTC_MIN;
|
||||
} else {
|
||||
rtc->alarm_year = DA9063_BB_REG_ALARM_Y;
|
||||
rtc->alarm_start = DA9063_BB_REG_ALARM_S;
|
||||
rtc->alarm_len = RTC_DATA_LEN;
|
||||
rtc->data_start = RTC_SEC;
|
||||
rtc->config = match->data;
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "dlg,da9063-rtc")) {
|
||||
struct da9063 *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
if (chip->variant_code == PMIC_DA9063_AD)
|
||||
rtc->config = &da9063_ad_regs;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(da9063->regmap, rtc->alarm_start,
|
||||
DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM,
|
||||
0);
|
||||
rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!rtc->regmap) {
|
||||
dev_warn(&pdev->dev, "Parent regmap unavailable.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
config = rtc->config;
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
config->rtc_enable_reg,
|
||||
config->rtc_enable_mask,
|
||||
config->rtc_enable_mask);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to enable RTC\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
config->rtc_enable_32k_crystal_reg,
|
||||
config->rtc_crystal_mask,
|
||||
config->rtc_crystal_mask);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
config->rtc_alarm_secs_reg,
|
||||
config->rtc_alarm_status_mask,
|
||||
0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(da9063->regmap, rtc->alarm_start,
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
config->rtc_alarm_secs_reg,
|
||||
DA9063_ALARM_STATUS_ALARM,
|
||||
DA9063_ALARM_STATUS_ALARM);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(da9063->regmap, rtc->alarm_year,
|
||||
DA9063_TICK_ON, 0);
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
config->rtc_alarm_year_reg,
|
||||
config->rtc_tick_on_mask,
|
||||
0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to disable TICKs\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
data[RTC_SEC] = 0;
|
||||
ret = regmap_bulk_read(da9063->regmap, rtc->alarm_start,
|
||||
&data[rtc->data_start], rtc->alarm_len);
|
||||
ret = regmap_bulk_read(rtc->regmap,
|
||||
config->rtc_alarm_secs_reg,
|
||||
&data[config->rtc_data_start],
|
||||
config->rtc_alarm_len);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
@ -322,18 +491,16 @@ static int da9063_rtc_probe(struct platform_device *pdev)
|
|||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
|
||||
irq_alarm, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc->hw = da9063;
|
||||
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
|
||||
&da9063_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
da9063_data_to_tm(data, &rtc->alarm_time);
|
||||
da9063_data_to_tm(data, &rtc->alarm_time, rtc);
|
||||
rtc->rtc_sync = false;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -341,6 +508,7 @@ static struct platform_driver da9063_rtc_driver = {
|
|||
.probe = da9063_rtc_probe,
|
||||
.driver = {
|
||||
.name = DA9063_DRVNAME_RTC,
|
||||
.of_match_table = da9063_compatible_reg_id_table,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -477,6 +477,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
|
|||
|
||||
cdev_init(&rtc->char_dev, &rtc_dev_fops);
|
||||
rtc->char_dev.owner = rtc->owner;
|
||||
rtc->char_dev.kobj.parent = &rtc->dev.kobj;
|
||||
}
|
||||
|
||||
void rtc_dev_add_device(struct rtc_device *rtc)
|
||||
|
|
|
@ -538,15 +538,6 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
|
||||
spi = container_of(kobj, struct spi_device, dev.kobj);
|
||||
|
||||
if (unlikely(off >= DS1305_NVRAM_LEN))
|
||||
return 0;
|
||||
if (count >= DS1305_NVRAM_LEN)
|
||||
count = DS1305_NVRAM_LEN;
|
||||
if ((off + count) > DS1305_NVRAM_LEN)
|
||||
count = DS1305_NVRAM_LEN - off;
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
addr = DS1305_NVRAM + off;
|
||||
msg_init(&m, x, &addr, count, NULL, buf);
|
||||
|
||||
|
@ -569,15 +560,6 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
|
||||
spi = container_of(kobj, struct spi_device, dev.kobj);
|
||||
|
||||
if (unlikely(off >= DS1305_NVRAM_LEN))
|
||||
return -EFBIG;
|
||||
if (count >= DS1305_NVRAM_LEN)
|
||||
count = DS1305_NVRAM_LEN;
|
||||
if ((off + count) > DS1305_NVRAM_LEN)
|
||||
count = DS1305_NVRAM_LEN - off;
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
addr = (DS1305_WRITE | DS1305_NVRAM) + off;
|
||||
msg_init(&m, x, &addr, count, buf, NULL);
|
||||
|
||||
|
|
|
@ -11,14 +11,17 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/rtc/ds1307.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
/*
|
||||
* We can't determine type by probing, but if we expect pre-Linux code
|
||||
|
@ -114,7 +117,7 @@ struct ds1307 {
|
|||
#define HAS_ALARM 1 /* bit 1 == irq claimed */
|
||||
struct i2c_client *client;
|
||||
struct rtc_device *rtc;
|
||||
struct work_struct work;
|
||||
int wakeirq;
|
||||
s32 (*read_block_data)(const struct i2c_client *client, u8 command,
|
||||
u8 length, u8 *values);
|
||||
s32 (*write_block_data)(const struct i2c_client *client, u8 command,
|
||||
|
@ -311,27 +314,17 @@ static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
|
|||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The IRQ logic includes a "real" handler running in IRQ context just
|
||||
* long enough to schedule this workqueue entry. We need a task context
|
||||
* to talk to the RTC, since I2C I/O calls require that; and disable the
|
||||
* IRQ until we clear its status on the chip, so that this handler can
|
||||
* work with any type of triggering (not just falling edge).
|
||||
*
|
||||
* The ds1337 and ds1339 both have two alarms, but we only use the first
|
||||
* one (with a "seconds" field). For ds1337 we expect nINTA is our alarm
|
||||
* signal; ds1339 chips have only one alarm signal.
|
||||
*/
|
||||
static void ds1307_work(struct work_struct *work)
|
||||
static irqreturn_t ds1307_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct ds1307 *ds1307;
|
||||
struct i2c_client *client;
|
||||
struct mutex *lock;
|
||||
struct i2c_client *client = dev_id;
|
||||
struct ds1307 *ds1307 = i2c_get_clientdata(client);
|
||||
struct mutex *lock = &ds1307->rtc->ops_lock;
|
||||
int stat, control;
|
||||
|
||||
ds1307 = container_of(work, struct ds1307, work);
|
||||
client = ds1307->client;
|
||||
lock = &ds1307->rtc->ops_lock;
|
||||
|
||||
mutex_lock(lock);
|
||||
stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
|
||||
if (stat < 0)
|
||||
|
@ -352,18 +345,8 @@ static void ds1307_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
out:
|
||||
if (test_bit(HAS_ALARM, &ds1307->flags))
|
||||
enable_irq(client->irq);
|
||||
mutex_unlock(lock);
|
||||
}
|
||||
|
||||
static irqreturn_t ds1307_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct i2c_client *client = dev_id;
|
||||
struct ds1307 *ds1307 = i2c_get_clientdata(client);
|
||||
|
||||
disable_irq_nosync(irq);
|
||||
schedule_work(&ds1307->work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -634,13 +617,14 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
|
|||
MCP794XX_BIT_ALMX_C1 | \
|
||||
MCP794XX_BIT_ALMX_C2)
|
||||
|
||||
static void mcp794xx_work(struct work_struct *work)
|
||||
static irqreturn_t mcp794xx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct ds1307 *ds1307 = container_of(work, struct ds1307, work);
|
||||
struct i2c_client *client = ds1307->client;
|
||||
struct i2c_client *client = dev_id;
|
||||
struct ds1307 *ds1307 = i2c_get_clientdata(client);
|
||||
struct mutex *lock = &ds1307->rtc->ops_lock;
|
||||
int reg, ret;
|
||||
|
||||
mutex_lock(&ds1307->rtc->ops_lock);
|
||||
mutex_lock(lock);
|
||||
|
||||
/* Check and clear alarm 0 interrupt flag. */
|
||||
reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL);
|
||||
|
@ -665,9 +649,9 @@ static void mcp794xx_work(struct work_struct *work)
|
|||
rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
|
||||
|
||||
out:
|
||||
if (test_bit(HAS_ALARM, &ds1307->flags))
|
||||
enable_irq(client->irq);
|
||||
mutex_unlock(&ds1307->rtc->ops_lock);
|
||||
mutex_unlock(lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
|
@ -798,13 +782,6 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
client = kobj_to_i2c_client(kobj);
|
||||
ds1307 = i2c_get_clientdata(client);
|
||||
|
||||
if (unlikely(off >= ds1307->nvram->size))
|
||||
return 0;
|
||||
if ((off + count) > ds1307->nvram->size)
|
||||
count = ds1307->nvram->size - off;
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
|
||||
count, buf);
|
||||
if (result < 0)
|
||||
|
@ -824,13 +801,6 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
client = kobj_to_i2c_client(kobj);
|
||||
ds1307 = i2c_get_clientdata(client);
|
||||
|
||||
if (unlikely(off >= ds1307->nvram->size))
|
||||
return -EFBIG;
|
||||
if ((off + count) > ds1307->nvram->size)
|
||||
count = ds1307->nvram->size - off;
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
|
||||
count, buf);
|
||||
if (result < 0) {
|
||||
|
@ -896,6 +866,8 @@ static int ds1307_probe(struct i2c_client *client,
|
|||
bool want_irq = false;
|
||||
unsigned char *buf;
|
||||
struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
irq_handler_t irq_handler = ds1307_irq;
|
||||
|
||||
static const int bbsqi_bitpos[] = {
|
||||
[ds_1337] = 0,
|
||||
[ds_1339] = DS1339_BIT_BBSQI,
|
||||
|
@ -962,8 +934,6 @@ static int ds1307_probe(struct i2c_client *client,
|
|||
* running on Vbackup (BBSQI/BBSQW)
|
||||
*/
|
||||
if (ds1307->client->irq > 0 && chip->alarm) {
|
||||
INIT_WORK(&ds1307->work, ds1307_work);
|
||||
|
||||
ds1307->regs[0] |= DS1337_BIT_INTCN
|
||||
| bbsqi_bitpos[ds1307->type];
|
||||
ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
|
||||
|
@ -1053,7 +1023,7 @@ static int ds1307_probe(struct i2c_client *client,
|
|||
case mcp794xx:
|
||||
rtc_ops = &mcp794xx_rtc_ops;
|
||||
if (ds1307->client->irq > 0 && chip->alarm) {
|
||||
INIT_WORK(&ds1307->work, mcp794xx_work);
|
||||
irq_handler = mcp794xx_irq;
|
||||
want_irq = true;
|
||||
}
|
||||
break;
|
||||
|
@ -1176,18 +1146,43 @@ read_rtc:
|
|||
}
|
||||
|
||||
if (want_irq) {
|
||||
err = request_irq(client->irq, ds1307_irq, IRQF_SHARED,
|
||||
ds1307->rtc->name, client);
|
||||
struct device_node *node = client->dev.of_node;
|
||||
|
||||
err = devm_request_threaded_irq(&client->dev,
|
||||
client->irq, NULL, irq_handler,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
ds1307->rtc->name, client);
|
||||
if (err) {
|
||||
client->irq = 0;
|
||||
dev_err(&client->dev, "unable to request IRQ!\n");
|
||||
} else {
|
||||
goto no_irq;
|
||||
}
|
||||
|
||||
set_bit(HAS_ALARM, &ds1307->flags);
|
||||
dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
|
||||
set_bit(HAS_ALARM, &ds1307->flags);
|
||||
dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
|
||||
|
||||
/* Currently supported by OF code only! */
|
||||
if (!node)
|
||||
goto no_irq;
|
||||
|
||||
err = of_irq_get(node, 1);
|
||||
if (err <= 0) {
|
||||
if (err == -EPROBE_DEFER)
|
||||
goto exit;
|
||||
goto no_irq;
|
||||
}
|
||||
ds1307->wakeirq = err;
|
||||
|
||||
err = dev_pm_set_dedicated_wake_irq(&client->dev,
|
||||
ds1307->wakeirq);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "unable to setup wakeIRQ %d!\n",
|
||||
err);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
no_irq:
|
||||
if (chip->nvram_size) {
|
||||
|
||||
ds1307->nvram = devm_kzalloc(&client->dev,
|
||||
|
@ -1231,10 +1226,8 @@ static int ds1307_remove(struct i2c_client *client)
|
|||
{
|
||||
struct ds1307 *ds1307 = i2c_get_clientdata(client);
|
||||
|
||||
if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
|
||||
free_irq(client->irq, client);
|
||||
cancel_work_sync(&ds1307->work);
|
||||
}
|
||||
if (ds1307->wakeirq)
|
||||
dev_pm_clear_wake_irq(&client->dev);
|
||||
|
||||
if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
|
||||
sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
|
||||
|
@ -1245,7 +1238,6 @@ static int ds1307_remove(struct i2c_client *client)
|
|||
static struct i2c_driver ds1307_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-ds1307",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ds1307_probe,
|
||||
.remove = ds1307_remove,
|
||||
|
|
|
@ -162,12 +162,6 @@ static ssize_t ds1343_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct ds1343_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
if ((count + off) > DS1343_NVRAM_LEN)
|
||||
count = DS1343_NVRAM_LEN - off;
|
||||
|
||||
address = DS1343_NVRAM + off;
|
||||
|
||||
ret = regmap_bulk_write(priv->map, address, buf, count);
|
||||
|
@ -187,12 +181,6 @@ static ssize_t ds1343_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct ds1343_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
if ((count + off) > DS1343_NVRAM_LEN)
|
||||
count = DS1343_NVRAM_LEN - off;
|
||||
|
||||
address = DS1343_NVRAM + off;
|
||||
|
||||
ret = regmap_bulk_read(priv->map, address, buf, count);
|
||||
|
|
|
@ -664,8 +664,6 @@ static int ds1374_remove(struct i2c_client *client)
|
|||
{
|
||||
struct ds1374 *ds1374 = i2c_get_clientdata(client);
|
||||
#ifdef CONFIG_RTC_DRV_DS1374_WDT
|
||||
int res;
|
||||
|
||||
misc_deregister(&ds1374_miscdev);
|
||||
ds1374_miscdev.parent = NULL;
|
||||
unregister_reboot_notifier(&ds1374_wdt_notifier);
|
||||
|
@ -688,7 +686,7 @@ static int ds1374_suspend(struct device *dev)
|
|||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (client->irq >= 0 && device_may_wakeup(&client->dev))
|
||||
if (client->irq > 0 && device_may_wakeup(&client->dev))
|
||||
enable_irq_wake(client->irq);
|
||||
return 0;
|
||||
}
|
||||
|
@ -697,7 +695,7 @@ static int ds1374_resume(struct device *dev)
|
|||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (client->irq >= 0 && device_may_wakeup(&client->dev))
|
||||
if (client->irq > 0 && device_may_wakeup(&client->dev))
|
||||
disable_irq_wake(client->irq);
|
||||
return 0;
|
||||
}
|
||||
|
@ -708,7 +706,6 @@ static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume);
|
|||
static struct i2c_driver ds1374_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-ds1374",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &ds1374_pm,
|
||||
},
|
||||
.probe = ds1374_probe,
|
||||
|
|
|
@ -64,7 +64,7 @@ enum ds1511reg {
|
|||
#define DS1511_KIE 0x04
|
||||
#define DS1511_WDE 0x02
|
||||
#define DS1511_WDS 0x01
|
||||
#define DS1511_RAM_MAX 0xff
|
||||
#define DS1511_RAM_MAX 0x100
|
||||
|
||||
#define RTC_CMD DS1511_CONTROL_B
|
||||
#define RTC_CMD1 DS1511_CONTROL_A
|
||||
|
@ -159,7 +159,7 @@ ds1511_wdog_set(unsigned long deciseconds)
|
|||
/*
|
||||
* set wdog enable and wdog 'steering' bit to issue a reset
|
||||
*/
|
||||
rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
|
||||
rtc_write(rtc_read(RTC_CMD) | DS1511_WDE | DS1511_WDS, RTC_CMD);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -407,26 +407,10 @@ ds1511_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
{
|
||||
ssize_t count;
|
||||
|
||||
/*
|
||||
* if count is more than one, turn on "burst" mode
|
||||
* turn it off when you're done
|
||||
*/
|
||||
if (size > 1)
|
||||
rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
|
||||
|
||||
if (pos > DS1511_RAM_MAX)
|
||||
pos = DS1511_RAM_MAX;
|
||||
|
||||
if (size + pos > DS1511_RAM_MAX + 1)
|
||||
size = DS1511_RAM_MAX - pos + 1;
|
||||
|
||||
rtc_write(pos, DS1511_RAMADDR_LSB);
|
||||
for (count = 0; size > 0; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
*buf++ = rtc_read(DS1511_RAMDATA);
|
||||
|
||||
if (count > 1)
|
||||
rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -437,26 +421,10 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
{
|
||||
ssize_t count;
|
||||
|
||||
/*
|
||||
* if count is more than one, turn on "burst" mode
|
||||
* turn it off when you're done
|
||||
*/
|
||||
if (size > 1)
|
||||
rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
|
||||
|
||||
if (pos > DS1511_RAM_MAX)
|
||||
pos = DS1511_RAM_MAX;
|
||||
|
||||
if (size + pos > DS1511_RAM_MAX + 1)
|
||||
size = DS1511_RAM_MAX - pos + 1;
|
||||
|
||||
rtc_write(pos, DS1511_RAMADDR_LSB);
|
||||
for (count = 0; size > 0; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
rtc_write(*buf++, DS1511_RAMDATA);
|
||||
|
||||
if (count > 1)
|
||||
rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -490,7 +458,7 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
|
|||
/*
|
||||
* turn on the clock and the crystal, etc.
|
||||
*/
|
||||
rtc_write(0, RTC_CMD);
|
||||
rtc_write(DS1511_BME, RTC_CMD);
|
||||
rtc_write(0, RTC_CMD1);
|
||||
/*
|
||||
* clear the wdog counter
|
||||
|
|
|
@ -245,7 +245,7 @@ static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
ssize_t count;
|
||||
|
||||
for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
*buf++ = readb(ioaddr + pos++);
|
||||
return count;
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ static ssize_t ds1553_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
ssize_t count;
|
||||
|
||||
for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
writeb(*buf++, ioaddr + pos++);
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -2145,27 +2145,7 @@ static struct platform_driver ds1685_rtc_driver = {
|
|||
.probe = ds1685_rtc_probe,
|
||||
.remove = ds1685_rtc_remove,
|
||||
};
|
||||
|
||||
/**
|
||||
* ds1685_rtc_init - rtc module init.
|
||||
*/
|
||||
static int __init
|
||||
ds1685_rtc_init(void)
|
||||
{
|
||||
return platform_driver_register(&ds1685_rtc_driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* ds1685_rtc_exit - rtc module exit.
|
||||
*/
|
||||
static void __exit
|
||||
ds1685_rtc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ds1685_rtc_driver);
|
||||
}
|
||||
|
||||
module_init(ds1685_rtc_init);
|
||||
module_exit(ds1685_rtc_exit);
|
||||
module_platform_driver(ds1685_rtc_driver);
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ static ssize_t ds1742_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
void __iomem *ioaddr = pdata->ioaddr_nvram;
|
||||
ssize_t count;
|
||||
|
||||
for (count = 0; size > 0 && pos < pdata->size_nvram; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
*buf++ = readb(ioaddr + pos++);
|
||||
return count;
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
void __iomem *ioaddr = pdata->ioaddr_nvram;
|
||||
ssize_t count;
|
||||
|
||||
for (count = 0; size > 0 && pos < pdata->size_nvram; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
writeb(*buf++, ioaddr + pos++);
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -443,7 +443,7 @@ static int ds3232_remove(struct i2c_client *client)
|
|||
{
|
||||
struct ds3232 *ds3232 = i2c_get_clientdata(client);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
if (client->irq > 0) {
|
||||
mutex_lock(&ds3232->mutex);
|
||||
ds3232->exiting = 1;
|
||||
mutex_unlock(&ds3232->mutex);
|
||||
|
@ -463,7 +463,10 @@ static int ds3232_suspend(struct device *dev)
|
|||
|
||||
if (device_can_wakeup(dev)) {
|
||||
ds3232->suspended = true;
|
||||
irq_set_irq_wake(client->irq, 1);
|
||||
if (irq_set_irq_wake(client->irq, 1)) {
|
||||
dev_warn_once(dev, "Cannot set wakeup source\n");
|
||||
ds3232->suspended = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -500,7 +503,6 @@ MODULE_DEVICE_TABLE(i2c, ds3232_id);
|
|||
static struct i2c_driver ds3232_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-ds3232",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &ds3232_pm_ops,
|
||||
},
|
||||
.probe = ds3232_probe,
|
||||
|
|
|
@ -523,7 +523,6 @@ exit_free:
|
|||
static struct i2c_driver fm3130_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-fm3130",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = fm3130_probe,
|
||||
.id_table = fm3130_id,
|
||||
|
|
|
@ -148,10 +148,7 @@ static int gemini_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
rtc->rtc_dev = rtc_device_register(pdev->name, dev,
|
||||
&gemini_rtc_ops, THIS_MODULE);
|
||||
if (likely(IS_ERR(rtc->rtc_dev)))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(rtc->rtc_dev);
|
||||
}
|
||||
|
||||
static int gemini_rtc_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -599,7 +599,6 @@ MODULE_DEVICE_TABLE(of, hym8563_dt_idtable);
|
|||
static struct i2c_driver hym8563_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-hym8563",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &hym8563_pm_ops,
|
||||
.of_match_table = hym8563_dt_idtable,
|
||||
},
|
||||
|
|
|
@ -151,12 +151,7 @@ static int isl12022_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
|
||||
/* The clock can give out invalid datetime, but we cannot return
|
||||
* -EINVAL otherwise hwclock will refuse to set the time on bootup. */
|
||||
if (rtc_valid_tm(tm) < 0)
|
||||
dev_err(&client->dev, "retrieved date and time is invalid.\n");
|
||||
|
||||
return 0;
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
|
@ -279,6 +274,7 @@ static const struct of_device_id isl12022_dt_match[] = {
|
|||
{ .compatible = "isil,isl12022" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, isl12022_dt_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id isl12022_id[] = {
|
||||
|
|
|
@ -648,6 +648,7 @@ static const struct of_device_id isl12057_dt_match[] = {
|
|||
{ .compatible = "isil,isl12057" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, isl12057_dt_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id isl12057_id[] = {
|
||||
|
@ -659,7 +660,6 @@ MODULE_DEVICE_TABLE(i2c, isl12057_id);
|
|||
static struct i2c_driver isl12057_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &isl12057_rtc_pm_ops,
|
||||
.of_match_table = of_match_ptr(isl12057_dt_match),
|
||||
},
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* RTC driver for NXP LPC178x/18xx/43xx Real-Time Clock (RTC)
|
||||
*
|
||||
* Copyright (C) 2011 NXP Semiconductors
|
||||
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/* LPC24xx RTC register offsets and bits */
|
||||
#define LPC24XX_ILR 0x00
|
||||
#define LPC24XX_RTCCIF BIT(0)
|
||||
#define LPC24XX_RTCALF BIT(1)
|
||||
#define LPC24XX_CTC 0x04
|
||||
#define LPC24XX_CCR 0x08
|
||||
#define LPC24XX_CLKEN BIT(0)
|
||||
#define LPC178X_CCALEN BIT(4)
|
||||
#define LPC24XX_CIIR 0x0c
|
||||
#define LPC24XX_AMR 0x10
|
||||
#define LPC24XX_ALARM_DISABLE 0xff
|
||||
#define LPC24XX_CTIME0 0x14
|
||||
#define LPC24XX_CTIME1 0x18
|
||||
#define LPC24XX_CTIME2 0x1c
|
||||
#define LPC24XX_SEC 0x20
|
||||
#define LPC24XX_MIN 0x24
|
||||
#define LPC24XX_HOUR 0x28
|
||||
#define LPC24XX_DOM 0x2c
|
||||
#define LPC24XX_DOW 0x30
|
||||
#define LPC24XX_DOY 0x34
|
||||
#define LPC24XX_MONTH 0x38
|
||||
#define LPC24XX_YEAR 0x3c
|
||||
#define LPC24XX_ALSEC 0x60
|
||||
#define LPC24XX_ALMIN 0x64
|
||||
#define LPC24XX_ALHOUR 0x68
|
||||
#define LPC24XX_ALDOM 0x6c
|
||||
#define LPC24XX_ALDOW 0x70
|
||||
#define LPC24XX_ALDOY 0x74
|
||||
#define LPC24XX_ALMON 0x78
|
||||
#define LPC24XX_ALYEAR 0x7c
|
||||
|
||||
/* Macros to read fields in consolidated time (CT) registers */
|
||||
#define CT0_SECS(x) (((x) >> 0) & 0x3f)
|
||||
#define CT0_MINS(x) (((x) >> 8) & 0x3f)
|
||||
#define CT0_HOURS(x) (((x) >> 16) & 0x1f)
|
||||
#define CT0_DOW(x) (((x) >> 24) & 0x07)
|
||||
#define CT1_DOM(x) (((x) >> 0) & 0x1f)
|
||||
#define CT1_MONTH(x) (((x) >> 8) & 0x0f)
|
||||
#define CT1_YEAR(x) (((x) >> 16) & 0xfff)
|
||||
#define CT2_DOY(x) (((x) >> 0) & 0xfff)
|
||||
|
||||
#define rtc_readl(dev, reg) readl((dev)->rtc_base + (reg))
|
||||
#define rtc_writel(dev, reg, val) writel((val), (dev)->rtc_base + (reg))
|
||||
|
||||
struct lpc24xx_rtc {
|
||||
void __iomem *rtc_base;
|
||||
struct rtc_device *rtc;
|
||||
struct clk *clk_rtc;
|
||||
struct clk *clk_reg;
|
||||
};
|
||||
|
||||
static int lpc24xx_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
/* Disable RTC during update */
|
||||
rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN);
|
||||
|
||||
rtc_writel(rtc, LPC24XX_SEC, tm->tm_sec);
|
||||
rtc_writel(rtc, LPC24XX_MIN, tm->tm_min);
|
||||
rtc_writel(rtc, LPC24XX_HOUR, tm->tm_hour);
|
||||
rtc_writel(rtc, LPC24XX_DOW, tm->tm_wday);
|
||||
rtc_writel(rtc, LPC24XX_DOM, tm->tm_mday);
|
||||
rtc_writel(rtc, LPC24XX_DOY, tm->tm_yday);
|
||||
rtc_writel(rtc, LPC24XX_MONTH, tm->tm_mon);
|
||||
rtc_writel(rtc, LPC24XX_YEAR, tm->tm_year);
|
||||
|
||||
rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc24xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
u32 ct0, ct1, ct2;
|
||||
|
||||
ct0 = rtc_readl(rtc, LPC24XX_CTIME0);
|
||||
ct1 = rtc_readl(rtc, LPC24XX_CTIME1);
|
||||
ct2 = rtc_readl(rtc, LPC24XX_CTIME2);
|
||||
|
||||
tm->tm_sec = CT0_SECS(ct0);
|
||||
tm->tm_min = CT0_MINS(ct0);
|
||||
tm->tm_hour = CT0_HOURS(ct0);
|
||||
tm->tm_wday = CT0_DOW(ct0);
|
||||
tm->tm_mon = CT1_MONTH(ct1);
|
||||
tm->tm_mday = CT1_DOM(ct1);
|
||||
tm->tm_year = CT1_YEAR(ct1);
|
||||
tm->tm_yday = CT2_DOY(ct2);
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int lpc24xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &wkalrm->time;
|
||||
|
||||
tm->tm_sec = rtc_readl(rtc, LPC24XX_ALSEC);
|
||||
tm->tm_min = rtc_readl(rtc, LPC24XX_ALMIN);
|
||||
tm->tm_hour = rtc_readl(rtc, LPC24XX_ALHOUR);
|
||||
tm->tm_mday = rtc_readl(rtc, LPC24XX_ALDOM);
|
||||
tm->tm_wday = rtc_readl(rtc, LPC24XX_ALDOW);
|
||||
tm->tm_yday = rtc_readl(rtc, LPC24XX_ALDOY);
|
||||
tm->tm_mon = rtc_readl(rtc, LPC24XX_ALMON);
|
||||
tm->tm_year = rtc_readl(rtc, LPC24XX_ALYEAR);
|
||||
|
||||
wkalrm->enabled = rtc_readl(rtc, LPC24XX_AMR) == 0;
|
||||
wkalrm->pending = !!(rtc_readl(rtc, LPC24XX_ILR) & LPC24XX_RTCCIF);
|
||||
|
||||
return rtc_valid_tm(&wkalrm->time);
|
||||
}
|
||||
|
||||
static int lpc24xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &wkalrm->time;
|
||||
|
||||
/* Disable alarm irq during update */
|
||||
rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
|
||||
|
||||
rtc_writel(rtc, LPC24XX_ALSEC, tm->tm_sec);
|
||||
rtc_writel(rtc, LPC24XX_ALMIN, tm->tm_min);
|
||||
rtc_writel(rtc, LPC24XX_ALHOUR, tm->tm_hour);
|
||||
rtc_writel(rtc, LPC24XX_ALDOM, tm->tm_mday);
|
||||
rtc_writel(rtc, LPC24XX_ALDOW, tm->tm_wday);
|
||||
rtc_writel(rtc, LPC24XX_ALDOY, tm->tm_yday);
|
||||
rtc_writel(rtc, LPC24XX_ALMON, tm->tm_mon);
|
||||
rtc_writel(rtc, LPC24XX_ALYEAR, tm->tm_year);
|
||||
|
||||
if (wkalrm->enabled)
|
||||
rtc_writel(rtc, LPC24XX_AMR, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc24xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (enable)
|
||||
rtc_writel(rtc, LPC24XX_AMR, 0);
|
||||
else
|
||||
rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t lpc24xx_rtc_interrupt(int irq, void *data)
|
||||
{
|
||||
unsigned long events = RTC_IRQF;
|
||||
struct lpc24xx_rtc *rtc = data;
|
||||
u32 rtc_iir;
|
||||
|
||||
/* Check interrupt cause */
|
||||
rtc_iir = rtc_readl(rtc, LPC24XX_ILR);
|
||||
if (rtc_iir & LPC24XX_RTCALF) {
|
||||
events |= RTC_AF;
|
||||
rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
|
||||
}
|
||||
|
||||
/* Clear interrupt status and report event */
|
||||
rtc_writel(rtc, LPC24XX_ILR, rtc_iir);
|
||||
rtc_update_irq(rtc->rtc, 1, events);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops lpc24xx_rtc_ops = {
|
||||
.read_time = lpc24xx_rtc_read_time,
|
||||
.set_time = lpc24xx_rtc_set_time,
|
||||
.read_alarm = lpc24xx_rtc_read_alarm,
|
||||
.set_alarm = lpc24xx_rtc_set_alarm,
|
||||
.alarm_irq_enable = lpc24xx_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int lpc24xx_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc24xx_rtc *rtc;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(rtc->rtc_base))
|
||||
return PTR_ERR(rtc->rtc_base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_warn(&pdev->dev, "can't get interrupt resource\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
rtc->clk_rtc = devm_clk_get(&pdev->dev, "rtc");
|
||||
if (IS_ERR(rtc->clk_rtc)) {
|
||||
dev_err(&pdev->dev, "error getting rtc clock\n");
|
||||
return PTR_ERR(rtc->clk_rtc);
|
||||
}
|
||||
|
||||
rtc->clk_reg = devm_clk_get(&pdev->dev, "reg");
|
||||
if (IS_ERR(rtc->clk_reg)) {
|
||||
dev_err(&pdev->dev, "error getting reg clock\n");
|
||||
return PTR_ERR(rtc->clk_reg);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rtc->clk_rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable rtc clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rtc->clk_reg);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable reg clock\n");
|
||||
goto disable_rtc_clk;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
/* Clear any pending interrupts */
|
||||
rtc_writel(rtc, LPC24XX_ILR, LPC24XX_RTCCIF | LPC24XX_RTCALF);
|
||||
|
||||
/* Enable RTC count */
|
||||
rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, lpc24xx_rtc_interrupt, 0,
|
||||
pdev->name, rtc);
|
||||
if (ret < 0) {
|
||||
dev_warn(&pdev->dev, "can't request interrupt\n");
|
||||
goto disable_clks;
|
||||
}
|
||||
|
||||
rtc->rtc = devm_rtc_device_register(&pdev->dev, "lpc24xx-rtc",
|
||||
&lpc24xx_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
dev_err(&pdev->dev, "can't register rtc device\n");
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
goto disable_clks;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clks:
|
||||
clk_disable_unprepare(rtc->clk_reg);
|
||||
disable_rtc_clk:
|
||||
clk_disable_unprepare(rtc->clk_rtc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpc24xx_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc24xx_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
/* Ensure all interrupt sources are masked */
|
||||
rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
|
||||
rtc_writel(rtc, LPC24XX_CIIR, 0);
|
||||
|
||||
rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN);
|
||||
|
||||
clk_disable_unprepare(rtc->clk_rtc);
|
||||
clk_disable_unprepare(rtc->clk_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc24xx_rtc_match[] = {
|
||||
{ .compatible = "nxp,lpc1788-rtc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match);
|
||||
|
||||
static struct platform_driver lpc24xx_rtc_driver = {
|
||||
.probe = lpc24xx_rtc_probe,
|
||||
.remove = lpc24xx_rtc_remove,
|
||||
.driver = {
|
||||
.name = "lpc24xx-rtc",
|
||||
.of_match_table = lpc24xx_rtc_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpc24xx_rtc_driver);
|
||||
|
||||
MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com>");
|
||||
MODULE_DESCRIPTION("RTC driver for the LPC178x/18xx/408x/43xx SoCs");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -345,11 +345,12 @@ static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
ssize_t cnt = 0;
|
||||
unsigned long flags;
|
||||
|
||||
for (; size > 0 && pos < pdata->offset; cnt++, size--) {
|
||||
spin_lock_irqsave(&m48t59->lock, flags);
|
||||
spin_lock_irqsave(&m48t59->lock, flags);
|
||||
|
||||
for (; cnt < size; cnt++)
|
||||
*buf++ = M48T59_READ(cnt);
|
||||
spin_unlock_irqrestore(&m48t59->lock, flags);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&m48t59->lock, flags);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
@ -365,11 +366,12 @@ static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
ssize_t cnt = 0;
|
||||
unsigned long flags;
|
||||
|
||||
for (; size > 0 && pos < pdata->offset; cnt++, size--) {
|
||||
spin_lock_irqsave(&m48t59->lock, flags);
|
||||
spin_lock_irqsave(&m48t59->lock, flags);
|
||||
|
||||
for (; cnt < size; cnt++)
|
||||
M48T59_WRITE(*buf++, cnt);
|
||||
spin_unlock_irqrestore(&m48t59->lock, flags);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&m48t59->lock, flags);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
|
|
@ -521,6 +521,7 @@ static const struct platform_device_id rtc_id[] = {
|
|||
{ "max8997-rtc", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, rtc_id);
|
||||
|
||||
static struct platform_driver max8997_rtc_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -312,6 +312,7 @@ static const struct of_device_id moxart_rtc_match[] = {
|
|||
{ .compatible = "moxa,moxart-rtc" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, moxart_rtc_match);
|
||||
|
||||
static struct platform_driver moxart_rtc_driver = {
|
||||
.probe = moxart_rtc_probe,
|
||||
|
|
|
@ -406,6 +406,7 @@ static const struct of_device_id mpc5121_rtc_match[] = {
|
|||
{ .compatible = "fsl,mpc5200-rtc", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mpc5121_rtc_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver mpc5121_rtc_driver = {
|
||||
|
|
|
@ -373,15 +373,42 @@ static int mtk_rtc_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mt6397_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(rtc->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt6397_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(rtc->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_rtc_suspend,
|
||||
mt6397_rtc_resume);
|
||||
|
||||
static const struct of_device_id mt6397_rtc_of_match[] = {
|
||||
{ .compatible = "mediatek,mt6397-rtc", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt6397_rtc_of_match);
|
||||
|
||||
static struct platform_driver mtk_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "mt6397-rtc",
|
||||
.of_match_table = mt6397_rtc_of_match,
|
||||
.pm = &mt6397_pm_ops,
|
||||
},
|
||||
.probe = mtk_rtc_probe,
|
||||
.remove = mtk_rtc_remove,
|
||||
|
|
|
@ -324,6 +324,7 @@ static const struct of_device_id rtc_mv_of_match_table[] = {
|
|||
{ .compatible = "marvell,orion-rtc", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table);
|
||||
#endif
|
||||
|
||||
static struct platform_driver mv_rtc_driver = {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
/*
|
||||
* The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
|
||||
|
@ -107,6 +108,7 @@
|
|||
|
||||
/* OMAP_RTC_OSC_REG bit fields: */
|
||||
#define OMAP_RTC_OSC_32KCLK_EN BIT(6)
|
||||
#define OMAP_RTC_OSC_SEL_32KCLK_SRC BIT(3)
|
||||
|
||||
/* OMAP_RTC_IRQWAKEEN bit fields: */
|
||||
#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1)
|
||||
|
@ -132,10 +134,12 @@ struct omap_rtc_device_type {
|
|||
struct omap_rtc {
|
||||
struct rtc_device *rtc;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
int irq_alarm;
|
||||
int irq_timer;
|
||||
u8 interrupts_reg;
|
||||
bool is_pmic_controller;
|
||||
bool has_ext_clk;
|
||||
const struct omap_rtc_device_type *type;
|
||||
};
|
||||
|
||||
|
@ -553,6 +557,15 @@ static int omap_rtc_probe(struct platform_device *pdev)
|
|||
if (rtc->irq_alarm <= 0)
|
||||
return -ENOENT;
|
||||
|
||||
rtc->clk = devm_clk_get(&pdev->dev, "ext-clk");
|
||||
if (!IS_ERR(rtc->clk))
|
||||
rtc->has_ext_clk = true;
|
||||
else
|
||||
rtc->clk = devm_clk_get(&pdev->dev, "int-clk");
|
||||
|
||||
if (!IS_ERR(rtc->clk))
|
||||
clk_prepare_enable(rtc->clk);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rtc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(rtc->base))
|
||||
|
@ -627,6 +640,16 @@ static int omap_rtc_probe(struct platform_device *pdev)
|
|||
if (reg != new_ctrl)
|
||||
rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl);
|
||||
|
||||
/*
|
||||
* If we have the external clock then switch to it so we can keep
|
||||
* ticking across suspend.
|
||||
*/
|
||||
if (rtc->has_ext_clk) {
|
||||
reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
|
||||
rtc_write(rtc, OMAP_RTC_OSC_REG,
|
||||
reg | OMAP_RTC_OSC_SEL_32KCLK_SRC);
|
||||
}
|
||||
|
||||
rtc->type->lock(rtc);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
@ -672,6 +695,7 @@ err:
|
|||
static int __exit omap_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_rtc *rtc = platform_get_drvdata(pdev);
|
||||
u8 reg;
|
||||
|
||||
if (pm_power_off == omap_rtc_power_off &&
|
||||
omap_rtc_power_off_rtc == rtc) {
|
||||
|
@ -681,10 +705,19 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
|
|||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
if (!IS_ERR(rtc->clk))
|
||||
clk_disable_unprepare(rtc->clk);
|
||||
|
||||
rtc->type->unlock(rtc);
|
||||
/* leave rtc running, but disable irqs */
|
||||
rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
|
||||
|
||||
if (rtc->has_ext_clk) {
|
||||
reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
|
||||
reg &= ~OMAP_RTC_OSC_SEL_32KCLK_SRC;
|
||||
rtc_write(rtc, OMAP_RTC_OSC_REG, reg);
|
||||
}
|
||||
|
||||
rtc->type->lock(rtc);
|
||||
|
||||
/* Disable the clock/module */
|
||||
|
|
|
@ -190,11 +190,9 @@ exit:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops opal_rtc_ops = {
|
||||
static struct rtc_class_ops opal_rtc_ops = {
|
||||
.read_time = opal_get_rtc_time,
|
||||
.set_time = opal_set_rtc_time,
|
||||
.read_alarm = opal_get_tpo_time,
|
||||
.set_alarm = opal_set_tpo_time,
|
||||
};
|
||||
|
||||
static int opal_rtc_probe(struct platform_device *pdev)
|
||||
|
@ -202,8 +200,11 @@ static int opal_rtc_probe(struct platform_device *pdev)
|
|||
struct rtc_device *rtc;
|
||||
|
||||
if (pdev->dev.of_node && of_get_property(pdev->dev.of_node, "has-tpo",
|
||||
NULL))
|
||||
NULL)) {
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
opal_rtc_ops.read_alarm = opal_get_tpo_time;
|
||||
opal_rtc_ops.set_alarm = opal_set_tpo_time;
|
||||
}
|
||||
|
||||
rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops,
|
||||
THIS_MODULE);
|
||||
|
@ -236,7 +237,6 @@ static struct platform_driver opal_rtc_driver = {
|
|||
.id_table = opal_rtc_driver_ids,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = opal_rtc_match,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -165,13 +165,7 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
|
||||
/* the clock can give out invalid datetime, but we cannot return
|
||||
* -EINVAL otherwise hwclock will refuse to set the time on bootup.
|
||||
*/
|
||||
if (rtc_valid_tm(tm) < 0)
|
||||
dev_err(dev, "retrieved date/time is not valid.\n");
|
||||
|
||||
return 0;
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
|
|
@ -33,11 +33,14 @@
|
|||
#define PCF2127_REG_MO (0x08)
|
||||
#define PCF2127_REG_YR (0x09)
|
||||
|
||||
#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */
|
||||
|
||||
static struct i2c_driver pcf2127_driver;
|
||||
|
||||
struct pcf2127 {
|
||||
struct rtc_device *rtc;
|
||||
int voltage_low; /* indicates if a low_voltage was detected */
|
||||
int oscillator_failed; /* OSF was detected and date is unreliable */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -59,7 +62,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
if (buf[PCF2127_REG_CTRL3] & 0x04) {
|
||||
pcf2127->voltage_low = 1;
|
||||
dev_info(&client->dev,
|
||||
"low voltage detected, date/time is not reliable.\n");
|
||||
"low voltage detected, check/replace RTC battery.\n");
|
||||
}
|
||||
|
||||
if (buf[PCF2127_REG_SC] & PCF2127_OSF) {
|
||||
/*
|
||||
* no need clear the flag here,
|
||||
* it will be cleared once the new date is saved
|
||||
*/
|
||||
pcf2127->oscillator_failed = 1;
|
||||
dev_warn(&client->dev,
|
||||
"oscillator stop detected, date/time is not reliable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
|
@ -88,17 +102,12 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
|
||||
/* the clock can give out invalid datetime, but we cannot return
|
||||
* -EINVAL otherwise hwclock will refuse to set the time on bootup.
|
||||
*/
|
||||
if (rtc_valid_tm(tm) < 0)
|
||||
dev_err(&client->dev, "retrieved date/time is not valid.\n");
|
||||
|
||||
return 0;
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
{
|
||||
struct pcf2127 *pcf2127 = i2c_get_clientdata(client);
|
||||
unsigned char buf[8];
|
||||
int i = 0, err;
|
||||
|
||||
|
@ -112,7 +121,7 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
buf[i++] = PCF2127_REG_SC;
|
||||
|
||||
/* hours, minutes and seconds */
|
||||
buf[i++] = bin2bcd(tm->tm_sec);
|
||||
buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */
|
||||
buf[i++] = bin2bcd(tm->tm_min);
|
||||
buf[i++] = bin2bcd(tm->tm_hour);
|
||||
buf[i++] = bin2bcd(tm->tm_mday);
|
||||
|
@ -132,6 +141,9 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
/* clear OSF flag in client data */
|
||||
pcf2127->oscillator_failed = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -144,7 +156,9 @@ static int pcf2127_rtc_ioctl(struct device *dev,
|
|||
switch (cmd) {
|
||||
case RTC_VL_READ:
|
||||
if (pcf2127->voltage_low)
|
||||
dev_info(dev, "low voltage detected, date/time is not reliable.\n");
|
||||
dev_info(dev, "low voltage detected, check/replace battery\n");
|
||||
if (pcf2127->oscillator_failed)
|
||||
dev_info(dev, "oscillator stop detected, date/time is not reliable\n");
|
||||
|
||||
if (copy_to_user((void __user *)arg, &pcf2127->voltage_low,
|
||||
sizeof(int)))
|
||||
|
@ -217,7 +231,6 @@ MODULE_DEVICE_TABLE(of, pcf2127_of_match);
|
|||
static struct i2c_driver pcf2127_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-pcf2127",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(pcf2127_of_match),
|
||||
},
|
||||
.probe = pcf2127_probe,
|
||||
|
|
|
@ -189,7 +189,6 @@ MODULE_DEVICE_TABLE(of, pcf85063_of_match);
|
|||
static struct i2c_driver pcf85063_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-pcf85063",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(pcf85063_of_match),
|
||||
},
|
||||
.probe = pcf85063_probe,
|
||||
|
|
|
@ -334,7 +334,6 @@ MODULE_DEVICE_TABLE(of, pcf8523_of_match);
|
|||
static struct i2c_driver pcf8523_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(pcf8523_of_match),
|
||||
},
|
||||
.probe = pcf8523_probe,
|
||||
|
|
|
@ -483,7 +483,6 @@ MODULE_DEVICE_TABLE(of, pcf8563_of_match);
|
|||
static struct i2c_driver pcf8563_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-pcf8563",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(pcf8563_of_match),
|
||||
},
|
||||
.probe = pcf8563_probe,
|
||||
|
|
|
@ -309,7 +309,6 @@ MODULE_DEVICE_TABLE(i2c, pcf8583_id);
|
|||
static struct i2c_driver pcf8583_driver = {
|
||||
.driver = {
|
||||
.name = "pcf8583",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = pcf8583_probe,
|
||||
.id_table = pcf8583_id,
|
||||
|
|
|
@ -476,6 +476,6 @@ static struct amba_driver pl031_driver = {
|
|||
|
||||
module_amba_driver(pl031_driver);
|
||||
|
||||
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
|
||||
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
|
||||
MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include "rtc-sa1100.h"
|
||||
|
||||
#define RTC_DEF_DIVIDER (32768 - 1)
|
||||
#define RTC_DEF_TRIM 0
|
||||
#define MAXFREQ_PERIODIC 1000
|
||||
|
@ -86,10 +88,9 @@
|
|||
__raw_writel((value), (pxa_rtc)->base + (reg))
|
||||
|
||||
struct pxa_rtc {
|
||||
struct sa1100_rtc sa1100_rtc;
|
||||
struct resource *ress;
|
||||
void __iomem *base;
|
||||
int irq_1Hz;
|
||||
int irq_Alrm;
|
||||
struct rtc_device *rtc;
|
||||
spinlock_t lock; /* Protects this structure */
|
||||
};
|
||||
|
@ -184,25 +185,25 @@ static int pxa_rtc_open(struct device *dev)
|
|||
struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, 0,
|
||||
ret = request_irq(pxa_rtc->sa1100_rtc.irq_1hz, pxa_rtc_irq, 0,
|
||||
"rtc 1Hz", dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_1Hz,
|
||||
ret);
|
||||
dev_err(dev, "can't get irq %i, err %d\n",
|
||||
pxa_rtc->sa1100_rtc.irq_1hz, ret);
|
||||
goto err_irq_1Hz;
|
||||
}
|
||||
ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, 0,
|
||||
ret = request_irq(pxa_rtc->sa1100_rtc.irq_alarm, pxa_rtc_irq, 0,
|
||||
"rtc Alrm", dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_Alrm,
|
||||
ret);
|
||||
dev_err(dev, "can't get irq %i, err %d\n",
|
||||
pxa_rtc->sa1100_rtc.irq_alarm, ret);
|
||||
goto err_irq_Alrm;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq_Alrm:
|
||||
free_irq(pxa_rtc->irq_1Hz, dev);
|
||||
free_irq(pxa_rtc->sa1100_rtc.irq_1hz, dev);
|
||||
err_irq_1Hz:
|
||||
return ret;
|
||||
}
|
||||
|
@ -215,8 +216,8 @@ static void pxa_rtc_release(struct device *dev)
|
|||
rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE);
|
||||
spin_unlock_irq(&pxa_rtc->lock);
|
||||
|
||||
free_irq(pxa_rtc->irq_Alrm, dev);
|
||||
free_irq(pxa_rtc->irq_1Hz, dev);
|
||||
free_irq(pxa_rtc->sa1100_rtc.irq_1hz, dev);
|
||||
free_irq(pxa_rtc->sa1100_rtc.irq_alarm, dev);
|
||||
}
|
||||
|
||||
static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
@ -320,12 +321,13 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pxa_rtc *pxa_rtc;
|
||||
struct sa1100_rtc *sa1100_rtc;
|
||||
int ret;
|
||||
u32 rttr;
|
||||
|
||||
pxa_rtc = devm_kzalloc(dev, sizeof(*pxa_rtc), GFP_KERNEL);
|
||||
if (!pxa_rtc)
|
||||
return -ENOMEM;
|
||||
sa1100_rtc = &pxa_rtc->sa1100_rtc;
|
||||
|
||||
spin_lock_init(&pxa_rtc->lock);
|
||||
platform_set_drvdata(pdev, pxa_rtc);
|
||||
|
@ -336,13 +338,13 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0);
|
||||
if (pxa_rtc->irq_1Hz < 0) {
|
||||
sa1100_rtc->irq_1hz = platform_get_irq(pdev, 0);
|
||||
if (sa1100_rtc->irq_1hz < 0) {
|
||||
dev_err(dev, "No 1Hz IRQ resource defined\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
pxa_rtc->irq_Alrm = platform_get_irq(pdev, 1);
|
||||
if (pxa_rtc->irq_Alrm < 0) {
|
||||
sa1100_rtc->irq_alarm = platform_get_irq(pdev, 1);
|
||||
if (sa1100_rtc->irq_alarm < 0) {
|
||||
dev_err(dev, "No alarm IRQ resource defined\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
@ -354,15 +356,14 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the clock divider is uninitialized then reset it to the
|
||||
* default value to get the 1Hz clock.
|
||||
*/
|
||||
if (rtc_readl(pxa_rtc, RTTR) == 0) {
|
||||
rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
|
||||
rtc_writel(pxa_rtc, RTTR, rttr);
|
||||
dev_warn(dev, "warning: initializing default clock"
|
||||
" divider/trim value\n");
|
||||
sa1100_rtc->rcnr = pxa_rtc->base + 0x0;
|
||||
sa1100_rtc->rtsr = pxa_rtc->base + 0x8;
|
||||
sa1100_rtc->rtar = pxa_rtc->base + 0x4;
|
||||
sa1100_rtc->rttr = pxa_rtc->base + 0xc;
|
||||
ret = sa1100_rtc_init(pdev, sa1100_rtc);
|
||||
if (!ret) {
|
||||
dev_err(dev, "Unable to init SA1100 RTC sub-device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE);
|
||||
|
@ -402,7 +403,7 @@ static int pxa_rtc_suspend(struct device *dev)
|
|||
struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(pxa_rtc->irq_Alrm);
|
||||
enable_irq_wake(pxa_rtc->sa1100_rtc.irq_alarm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -411,7 +412,7 @@ static int pxa_rtc_resume(struct device *dev)
|
|||
struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(pxa_rtc->irq_Alrm);
|
||||
disable_irq_wake(pxa_rtc->sa1100_rtc.irq_alarm);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -170,7 +170,7 @@ static ssize_t rp5c01_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
|
||||
spin_lock_irq(&priv->lock);
|
||||
|
||||
for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) {
|
||||
for (count = 0; count < size; count++) {
|
||||
u8 data;
|
||||
|
||||
rp5c01_write(priv,
|
||||
|
@ -200,7 +200,7 @@ static ssize_t rp5c01_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
|
||||
spin_lock_irq(&priv->lock);
|
||||
|
||||
for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) {
|
||||
for (count = 0; count < size; count++) {
|
||||
u8 data = *buf++;
|
||||
|
||||
rp5c01_write(priv,
|
||||
|
|
|
@ -18,13 +18,11 @@
|
|||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/* Register definitions */
|
||||
|
@ -48,17 +46,17 @@
|
|||
#define RX8025_BIT_CTRL1_CT (7 << 0)
|
||||
/* 1 Hz periodic level irq */
|
||||
#define RX8025_BIT_CTRL1_CT_1HZ 4
|
||||
#define RX8025_BIT_CTRL1_TEST (1 << 3)
|
||||
#define RX8025_BIT_CTRL1_1224 (1 << 5)
|
||||
#define RX8025_BIT_CTRL1_DALE (1 << 6)
|
||||
#define RX8025_BIT_CTRL1_WALE (1 << 7)
|
||||
#define RX8025_BIT_CTRL1_TEST BIT(3)
|
||||
#define RX8025_BIT_CTRL1_1224 BIT(5)
|
||||
#define RX8025_BIT_CTRL1_DALE BIT(6)
|
||||
#define RX8025_BIT_CTRL1_WALE BIT(7)
|
||||
|
||||
#define RX8025_BIT_CTRL2_DAFG (1 << 0)
|
||||
#define RX8025_BIT_CTRL2_WAFG (1 << 1)
|
||||
#define RX8025_BIT_CTRL2_CTFG (1 << 2)
|
||||
#define RX8025_BIT_CTRL2_PON (1 << 4)
|
||||
#define RX8025_BIT_CTRL2_XST (1 << 5)
|
||||
#define RX8025_BIT_CTRL2_VDET (1 << 6)
|
||||
#define RX8025_BIT_CTRL2_DAFG BIT(0)
|
||||
#define RX8025_BIT_CTRL2_WAFG BIT(1)
|
||||
#define RX8025_BIT_CTRL2_CTFG BIT(2)
|
||||
#define RX8025_BIT_CTRL2_PON BIT(4)
|
||||
#define RX8025_BIT_CTRL2_XST BIT(5)
|
||||
#define RX8025_BIT_CTRL2_VDET BIT(6)
|
||||
|
||||
/* Clock precision adjustment */
|
||||
#define RX8025_ADJ_RESOLUTION 3050 /* in ppb */
|
||||
|
@ -74,84 +72,84 @@ MODULE_DEVICE_TABLE(i2c, rx8025_id);
|
|||
struct rx8025_data {
|
||||
struct i2c_client *client;
|
||||
struct rtc_device *rtc;
|
||||
struct work_struct work;
|
||||
u8 ctrl1;
|
||||
unsigned exiting:1;
|
||||
};
|
||||
|
||||
static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value)
|
||||
static s32 rx8025_read_reg(const struct i2c_client *client, u8 number)
|
||||
{
|
||||
int ret = i2c_smbus_read_byte_data(client, (number << 4) | 0x08);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Unable to read register #%d\n", number);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*value = ret;
|
||||
return 0;
|
||||
return i2c_smbus_read_byte_data(client, number << 4);
|
||||
}
|
||||
|
||||
static int rx8025_read_regs(struct i2c_client *client,
|
||||
int number, u8 length, u8 *values)
|
||||
static int rx8025_read_regs(const struct i2c_client *client,
|
||||
u8 number, u8 length, u8 *values)
|
||||
{
|
||||
int ret = i2c_smbus_read_i2c_block_data(client, (number << 4) | 0x08,
|
||||
length, values);
|
||||
|
||||
if (ret != length) {
|
||||
dev_err(&client->dev, "Unable to read registers #%d..#%d\n",
|
||||
number, number + length - 1);
|
||||
int ret = i2c_smbus_read_i2c_block_data(client, number << 4, length,
|
||||
values);
|
||||
if (ret != length)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 rx8025_write_reg(const struct i2c_client *client, u8 number,
|
||||
u8 value)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, number << 4, value);
|
||||
}
|
||||
|
||||
static s32 rx8025_write_regs(const struct i2c_client *client,
|
||||
u8 number, u8 length, const u8 *values)
|
||||
{
|
||||
return i2c_smbus_write_i2c_block_data(client, number << 4,
|
||||
length, values);
|
||||
}
|
||||
|
||||
static int rx8025_check_validity(struct device *dev)
|
||||
{
|
||||
struct rx8025_data *rx8025 = dev_get_drvdata(dev);
|
||||
int ctrl2;
|
||||
|
||||
ctrl2 = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2);
|
||||
if (ctrl2 < 0)
|
||||
return ctrl2;
|
||||
|
||||
if (ctrl2 & RX8025_BIT_CTRL2_VDET)
|
||||
dev_warn(dev, "power voltage drop detected\n");
|
||||
|
||||
if (ctrl2 & RX8025_BIT_CTRL2_PON) {
|
||||
dev_warn(dev, "power-on reset detected, date is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(ctrl2 & RX8025_BIT_CTRL2_XST)) {
|
||||
dev_warn(dev, "crystal stopped, date is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx8025_write_reg(struct i2c_client *client, int number, u8 value)
|
||||
static int rx8025_reset_validity(struct i2c_client *client)
|
||||
{
|
||||
int ret = i2c_smbus_write_byte_data(client, number << 4, value);
|
||||
int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2);
|
||||
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Unable to write register #%d\n",
|
||||
number);
|
||||
if (ctrl2 < 0)
|
||||
return ctrl2;
|
||||
|
||||
return ret;
|
||||
ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET);
|
||||
|
||||
return rx8025_write_reg(client, RX8025_REG_CTRL2,
|
||||
ctrl2 | RX8025_BIT_CTRL2_XST);
|
||||
}
|
||||
|
||||
static int rx8025_write_regs(struct i2c_client *client,
|
||||
int number, u8 length, u8 *values)
|
||||
{
|
||||
int ret = i2c_smbus_write_i2c_block_data(client, (number << 4) | 0x08,
|
||||
length, values);
|
||||
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Unable to write registers #%d..#%d\n",
|
||||
number, number + length - 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t rx8025_irq(int irq, void *dev_id)
|
||||
static irqreturn_t rx8025_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct i2c_client *client = dev_id;
|
||||
struct rx8025_data *rx8025 = i2c_get_clientdata(client);
|
||||
int status;
|
||||
|
||||
disable_irq_nosync(irq);
|
||||
schedule_work(&rx8025->work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rx8025_work(struct work_struct *work)
|
||||
{
|
||||
struct rx8025_data *rx8025 = container_of(work, struct rx8025_data,
|
||||
work);
|
||||
struct i2c_client *client = rx8025->client;
|
||||
struct mutex *lock = &rx8025->rtc->ops_lock;
|
||||
u8 status;
|
||||
|
||||
mutex_lock(lock);
|
||||
|
||||
if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status))
|
||||
status = rx8025_read_reg(client, RX8025_REG_CTRL2);
|
||||
if (status < 0)
|
||||
goto out;
|
||||
|
||||
if (!(status & RX8025_BIT_CTRL2_XST))
|
||||
|
@ -161,9 +159,7 @@ static void rx8025_work(struct work_struct *work)
|
|||
if (status & RX8025_BIT_CTRL2_CTFG) {
|
||||
/* periodic */
|
||||
status &= ~RX8025_BIT_CTRL2_CTFG;
|
||||
local_irq_disable();
|
||||
rtc_update_irq(rx8025->rtc, 1, RTC_PF | RTC_IRQF);
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
if (status & RX8025_BIT_CTRL2_DAFG) {
|
||||
|
@ -172,20 +168,11 @@ static void rx8025_work(struct work_struct *work)
|
|||
if (rx8025_write_reg(client, RX8025_REG_CTRL1,
|
||||
rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE))
|
||||
goto out;
|
||||
local_irq_disable();
|
||||
rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF);
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
/* acknowledge IRQ */
|
||||
rx8025_write_reg(client, RX8025_REG_CTRL2,
|
||||
status | RX8025_BIT_CTRL2_XST);
|
||||
|
||||
out:
|
||||
if (!rx8025->exiting)
|
||||
enable_irq(client->irq);
|
||||
|
||||
mutex_unlock(lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rx8025_get_time(struct device *dev, struct rtc_time *dt)
|
||||
|
@ -194,6 +181,10 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt)
|
|||
u8 date[7];
|
||||
int err;
|
||||
|
||||
err = rx8025_check_validity(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -213,10 +204,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt)
|
|||
|
||||
dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f);
|
||||
dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1;
|
||||
dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]);
|
||||
|
||||
if (dt->tm_year < 70)
|
||||
dt->tm_year += 100;
|
||||
dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100;
|
||||
|
||||
dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
|
||||
dt->tm_sec, dt->tm_min, dt->tm_hour,
|
||||
|
@ -229,12 +217,10 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt)
|
|||
{
|
||||
struct rx8025_data *rx8025 = dev_get_drvdata(dev);
|
||||
u8 date[7];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* BUG: The HW assumes every year that is a multiple of 4 to be a leap
|
||||
* year. Next time this is wrong is 2100, which will not be a leap
|
||||
* year.
|
||||
*/
|
||||
if ((dt->tm_year < 100) || (dt->tm_year > 199))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Here the read-only bits are written as "0". I'm not sure if that
|
||||
|
@ -251,17 +237,21 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt)
|
|||
date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday);
|
||||
date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday);
|
||||
date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1);
|
||||
date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year % 100);
|
||||
date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100);
|
||||
|
||||
dev_dbg(dev,
|
||||
"%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
__func__,
|
||||
date[0], date[1], date[2], date[3], date[4], date[5], date[6]);
|
||||
|
||||
return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date);
|
||||
ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return rx8025_reset_validity(rx8025->client);
|
||||
}
|
||||
|
||||
static int rx8025_init_client(struct i2c_client *client, int *need_reset)
|
||||
static int rx8025_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct rx8025_data *rx8025 = i2c_get_clientdata(client);
|
||||
u8 ctrl[2], ctrl2;
|
||||
|
@ -275,38 +265,18 @@ static int rx8025_init_client(struct i2c_client *client, int *need_reset)
|
|||
/* Keep test bit zero ! */
|
||||
rx8025->ctrl1 = ctrl[0] & ~RX8025_BIT_CTRL1_TEST;
|
||||
|
||||
if (ctrl[1] & RX8025_BIT_CTRL2_PON) {
|
||||
dev_warn(&client->dev, "power-on reset was detected, "
|
||||
"you may have to readjust the clock\n");
|
||||
*need_reset = 1;
|
||||
}
|
||||
|
||||
if (ctrl[1] & RX8025_BIT_CTRL2_VDET) {
|
||||
dev_warn(&client->dev, "a power voltage drop was detected, "
|
||||
"you may have to readjust the clock\n");
|
||||
*need_reset = 1;
|
||||
}
|
||||
|
||||
if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) {
|
||||
dev_warn(&client->dev, "Oscillation stop was detected,"
|
||||
"you may have to readjust the clock\n");
|
||||
*need_reset = 1;
|
||||
}
|
||||
|
||||
if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) {
|
||||
dev_warn(&client->dev, "Alarm was detected\n");
|
||||
need_clear = 1;
|
||||
}
|
||||
|
||||
if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG))
|
||||
if (ctrl[1] & RX8025_BIT_CTRL2_CTFG)
|
||||
need_clear = 1;
|
||||
|
||||
if (*need_reset || need_clear) {
|
||||
ctrl2 = ctrl[0];
|
||||
ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET |
|
||||
RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG |
|
||||
if (need_clear) {
|
||||
ctrl2 = ctrl[1];
|
||||
ctrl2 &= ~(RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG |
|
||||
RX8025_BIT_CTRL2_DAFG);
|
||||
ctrl2 |= RX8025_BIT_CTRL2_XST;
|
||||
|
||||
err = rx8025_write_reg(client, RX8025_REG_CTRL2, ctrl2);
|
||||
}
|
||||
|
@ -319,8 +289,8 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
{
|
||||
struct rx8025_data *rx8025 = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = rx8025->client;
|
||||
u8 ctrl2, ald[2];
|
||||
int err;
|
||||
u8 ald[2];
|
||||
int ctrl2, err;
|
||||
|
||||
if (client->irq <= 0)
|
||||
return -EINVAL;
|
||||
|
@ -329,9 +299,9 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = rx8025_read_reg(client, RX8025_REG_CTRL2, &ctrl2);
|
||||
if (err)
|
||||
return err;
|
||||
ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2);
|
||||
if (ctrl2 < 0)
|
||||
return ctrl2;
|
||||
|
||||
dev_dbg(dev, "%s: read alarm 0x%02x 0x%02x ctrl2 %02x\n",
|
||||
__func__, ald[0], ald[1], ctrl2);
|
||||
|
@ -452,12 +422,11 @@ static struct rtc_class_ops rx8025_rtc_ops = {
|
|||
static int rx8025_get_clock_adjust(struct device *dev, int *adj)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 digoff;
|
||||
int err;
|
||||
int digoff;
|
||||
|
||||
err = rx8025_read_reg(client, RX8025_REG_DIGOFF, &digoff);
|
||||
if (err)
|
||||
return err;
|
||||
digoff = rx8025_read_reg(client, RX8025_REG_DIGOFF);
|
||||
if (digoff < 0)
|
||||
return digoff;
|
||||
|
||||
*adj = digoff >= 64 ? digoff - 128 : digoff;
|
||||
if (*adj > 0)
|
||||
|
@ -539,88 +508,53 @@ static int rx8025_probe(struct i2c_client *client,
|
|||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct rx8025_data *rx8025;
|
||||
int err, need_reset = 0;
|
||||
int err = 0;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
||||
| I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
dev_err(&adapter->dev,
|
||||
"doesn't support required functionality\n");
|
||||
err = -EIO;
|
||||
goto errout;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);
|
||||
if (!rx8025) {
|
||||
err = -ENOMEM;
|
||||
goto errout;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rx8025->client = client;
|
||||
i2c_set_clientdata(client, rx8025);
|
||||
INIT_WORK(&rx8025->work, rx8025_work);
|
||||
|
||||
err = rx8025_init_client(client, &need_reset);
|
||||
err = rx8025_init_client(client);
|
||||
if (err)
|
||||
goto errout;
|
||||
|
||||
if (need_reset) {
|
||||
struct rtc_time tm;
|
||||
dev_info(&client->dev,
|
||||
"bad conditions detected, resetting date\n");
|
||||
rtc_time_to_tm(0, &tm); /* 1970/1/1 */
|
||||
rx8025_set_time(&client->dev, &tm);
|
||||
}
|
||||
return err;
|
||||
|
||||
rx8025->rtc = devm_rtc_device_register(&client->dev, client->name,
|
||||
&rx8025_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rx8025->rtc)) {
|
||||
err = PTR_ERR(rx8025->rtc);
|
||||
dev_err(&client->dev, "unable to register the class device\n");
|
||||
goto errout;
|
||||
return PTR_ERR(rx8025->rtc);
|
||||
}
|
||||
|
||||
if (client->irq > 0) {
|
||||
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
|
||||
err = request_irq(client->irq, rx8025_irq,
|
||||
0, "rx8025", client);
|
||||
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
||||
rx8025_handle_irq, 0, "rx8025",
|
||||
client);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "unable to request IRQ\n");
|
||||
goto errout;
|
||||
dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
|
||||
client->irq = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rx8025->rtc->irq_freq = 1;
|
||||
rx8025->rtc->max_user_freq = 1;
|
||||
|
||||
err = rx8025_sysfs_register(&client->dev);
|
||||
if (err)
|
||||
goto errout_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
errout_irq:
|
||||
if (client->irq > 0)
|
||||
free_irq(client->irq, client);
|
||||
|
||||
errout:
|
||||
dev_err(&adapter->dev, "probing for rx8025 failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rx8025_remove(struct i2c_client *client)
|
||||
{
|
||||
struct rx8025_data *rx8025 = i2c_get_clientdata(client);
|
||||
struct mutex *lock = &rx8025->rtc->ops_lock;
|
||||
|
||||
if (client->irq > 0) {
|
||||
mutex_lock(lock);
|
||||
rx8025->exiting = 1;
|
||||
mutex_unlock(lock);
|
||||
|
||||
free_irq(client->irq, client);
|
||||
cancel_work_sync(&rx8025->work);
|
||||
}
|
||||
|
||||
rx8025_sysfs_unregister(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -628,7 +562,6 @@ static int rx8025_remove(struct i2c_client *client)
|
|||
static struct i2c_driver rx8025_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-rx8025",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = rx8025_probe,
|
||||
.remove = rx8025_remove,
|
||||
|
|
|
@ -315,7 +315,6 @@ MODULE_DEVICE_TABLE(i2c, rx8581_id);
|
|||
static struct i2c_driver rx8581_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-rx8581",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = rx8581_probe,
|
||||
.id_table = rx8581_id,
|
||||
|
|
|
@ -39,6 +39,7 @@ struct s3c_rtc {
|
|||
void __iomem *base;
|
||||
struct clk *rtc_clk;
|
||||
struct clk *rtc_src_clk;
|
||||
bool clk_disabled;
|
||||
|
||||
struct s3c_rtc_data *data;
|
||||
|
||||
|
@ -71,9 +72,12 @@ static void s3c_rtc_enable_clk(struct s3c_rtc *info)
|
|||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
|
||||
clk_enable(info->rtc_clk);
|
||||
if (info->data->needs_src_clk)
|
||||
clk_enable(info->rtc_src_clk);
|
||||
if (info->clk_disabled) {
|
||||
clk_enable(info->rtc_clk);
|
||||
if (info->data->needs_src_clk)
|
||||
clk_enable(info->rtc_src_clk);
|
||||
info->clk_disabled = false;
|
||||
}
|
||||
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
|
||||
}
|
||||
|
||||
|
@ -82,9 +86,12 @@ static void s3c_rtc_disable_clk(struct s3c_rtc *info)
|
|||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
|
||||
if (info->data->needs_src_clk)
|
||||
clk_disable(info->rtc_src_clk);
|
||||
clk_disable(info->rtc_clk);
|
||||
if (!info->clk_disabled) {
|
||||
if (info->data->needs_src_clk)
|
||||
clk_disable(info->rtc_src_clk);
|
||||
clk_disable(info->rtc_clk);
|
||||
info->clk_disabled = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
|
||||
}
|
||||
|
||||
|
@ -128,6 +135,11 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
|
|||
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
if (enabled)
|
||||
s3c_rtc_enable_clk(info);
|
||||
else
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -410,8 +422,9 @@ static int s3c_rtc_remove(struct platform_device *pdev)
|
|||
|
||||
s3c_rtc_setaie(info->dev, 0);
|
||||
|
||||
if (info->data->needs_src_clk)
|
||||
clk_unprepare(info->rtc_src_clk);
|
||||
clk_unprepare(info->rtc_clk);
|
||||
info->rtc_clk = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -482,6 +495,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(info->rtc_src_clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to find rtc source clock\n");
|
||||
clk_disable_unprepare(info->rtc_clk);
|
||||
return PTR_ERR(info->rtc_src_clk);
|
||||
}
|
||||
clk_prepare_enable(info->rtc_src_clk);
|
||||
|
|
|
@ -635,6 +635,16 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
|
|||
case S2MPS13X:
|
||||
data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
|
||||
ret = regmap_write(info->regmap, info->regs->ctrl, data[0]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Should set WUDR & (RUDR or AUDR) bits to high after writing
|
||||
* RTC_CTRL register like writing Alarm registers. We can't find
|
||||
* the description from datasheet but vendor code does that
|
||||
* really.
|
||||
*/
|
||||
ret = s5m8767_rtc_set_alarm_reg(info);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -797,6 +807,7 @@ static const struct platform_device_id s5m_rtc_id[] = {
|
|||
{ "s2mps14-rtc", S2MPS14X },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, s5m_rtc_id);
|
||||
|
||||
static struct platform_driver s5m_rtc_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -35,24 +35,17 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/irqs.h>
|
||||
#define RTSR_HZE BIT(3) /* HZ interrupt enable */
|
||||
#define RTSR_ALE BIT(2) /* RTC alarm interrupt enable */
|
||||
#define RTSR_HZ BIT(1) /* HZ rising-edge detected */
|
||||
#define RTSR_AL BIT(0) /* RTC alarm detected */
|
||||
|
||||
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
|
||||
#include <mach/regs-rtc.h>
|
||||
#endif
|
||||
#include "rtc-sa1100.h"
|
||||
|
||||
#define RTC_DEF_DIVIDER (32768 - 1)
|
||||
#define RTC_DEF_TRIM 0
|
||||
#define RTC_FREQ 1024
|
||||
|
||||
struct sa1100_rtc {
|
||||
spinlock_t lock;
|
||||
int irq_1hz;
|
||||
int irq_alarm;
|
||||
struct rtc_device *rtc;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
|
@ -63,16 +56,16 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
|
|||
|
||||
spin_lock(&info->lock);
|
||||
|
||||
rtsr = RTSR;
|
||||
rtsr = readl_relaxed(info->rtsr);
|
||||
/* clear interrupt sources */
|
||||
RTSR = 0;
|
||||
writel_relaxed(0, info->rtsr);
|
||||
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
||||
* See also the comments in sa1100_rtc_probe(). */
|
||||
if (rtsr & (RTSR_ALE | RTSR_HZE)) {
|
||||
/* This is the original code, before there was the if test
|
||||
* above. This code does not clear interrupts that were not
|
||||
* enabled. */
|
||||
RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
|
||||
writel_relaxed((RTSR_AL | RTSR_HZ) & (rtsr >> 2), info->rtsr);
|
||||
} else {
|
||||
/* For some reason, it is possible to enter this routine
|
||||
* without interruptions enabled, it has been tested with
|
||||
|
@ -81,13 +74,13 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
|
|||
* This situation leads to an infinite "loop" of interrupt
|
||||
* routine calling and as a result the processor seems to
|
||||
* lock on its first call to open(). */
|
||||
RTSR = RTSR_AL | RTSR_HZ;
|
||||
writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr);
|
||||
}
|
||||
|
||||
/* clear alarm interrupt if it has occurred */
|
||||
if (rtsr & RTSR_AL)
|
||||
rtsr &= ~RTSR_ALE;
|
||||
RTSR = rtsr & (RTSR_ALE | RTSR_HZE);
|
||||
writel_relaxed(rtsr & (RTSR_ALE | RTSR_HZE), info->rtsr);
|
||||
|
||||
/* update irq data & counter */
|
||||
if (rtsr & RTSR_AL)
|
||||
|
@ -135,7 +128,7 @@ static void sa1100_rtc_release(struct device *dev)
|
|||
struct sa1100_rtc *info = dev_get_drvdata(dev);
|
||||
|
||||
spin_lock_irq(&info->lock);
|
||||
RTSR = 0;
|
||||
writel_relaxed(0, info->rtsr);
|
||||
spin_unlock_irq(&info->lock);
|
||||
|
||||
free_irq(info->irq_alarm, dev);
|
||||
|
@ -144,39 +137,46 @@ static void sa1100_rtc_release(struct device *dev)
|
|||
|
||||
static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
u32 rtsr;
|
||||
struct sa1100_rtc *info = dev_get_drvdata(dev);
|
||||
|
||||
spin_lock_irq(&info->lock);
|
||||
rtsr = readl_relaxed(info->rtsr);
|
||||
if (enabled)
|
||||
RTSR |= RTSR_ALE;
|
||||
rtsr |= RTSR_ALE;
|
||||
else
|
||||
RTSR &= ~RTSR_ALE;
|
||||
rtsr &= ~RTSR_ALE;
|
||||
writel_relaxed(rtsr, info->rtsr);
|
||||
spin_unlock_irq(&info->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
rtc_time_to_tm(RCNR, tm);
|
||||
struct sa1100_rtc *info = dev_get_drvdata(dev);
|
||||
|
||||
rtc_time_to_tm(readl_relaxed(info->rcnr), tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct sa1100_rtc *info = dev_get_drvdata(dev);
|
||||
unsigned long time;
|
||||
int ret;
|
||||
|
||||
ret = rtc_tm_to_time(tm, &time);
|
||||
if (ret == 0)
|
||||
RCNR = time;
|
||||
writel_relaxed(time, info->rcnr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
u32 rtsr;
|
||||
struct sa1100_rtc *info = dev_get_drvdata(dev);
|
||||
|
||||
rtsr = RTSR;
|
||||
rtsr = readl_relaxed(info->rtsr);
|
||||
alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
|
||||
alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
|
||||
return 0;
|
||||
|
@ -192,12 +192,13 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
ret = rtc_tm_to_time(&alrm->time, &time);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
|
||||
RTAR = time;
|
||||
writel_relaxed(readl_relaxed(info->rtsr) &
|
||||
(RTSR_HZE | RTSR_ALE | RTSR_AL), info->rtsr);
|
||||
writel_relaxed(time, info->rtar);
|
||||
if (alrm->enabled)
|
||||
RTSR |= RTSR_ALE;
|
||||
writel_relaxed(readl_relaxed(info->rtsr) | RTSR_ALE, info->rtsr);
|
||||
else
|
||||
RTSR &= ~RTSR_ALE;
|
||||
writel_relaxed(readl_relaxed(info->rtsr) & ~RTSR_ALE, info->rtsr);
|
||||
out:
|
||||
spin_unlock_irq(&info->lock);
|
||||
|
||||
|
@ -206,8 +207,10 @@ out:
|
|||
|
||||
static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR);
|
||||
seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR);
|
||||
struct sa1100_rtc *info = dev_get_drvdata(dev);
|
||||
|
||||
seq_printf(seq, "trim/divider\t\t: 0x%08x\n", readl_relaxed(info->rttr));
|
||||
seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", readl_relaxed(info->rtsr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -223,29 +226,18 @@ static const struct rtc_class_ops sa1100_rtc_ops = {
|
|||
.alarm_irq_enable = sa1100_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int sa1100_rtc_probe(struct platform_device *pdev)
|
||||
int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
struct sa1100_rtc *info;
|
||||
int irq_1hz, irq_alarm, ret = 0;
|
||||
int ret;
|
||||
|
||||
irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz");
|
||||
irq_alarm = platform_get_irq_byname(pdev, "rtc alarm");
|
||||
if (irq_1hz < 0 || irq_alarm < 0)
|
||||
return -ENODEV;
|
||||
spin_lock_init(&info->lock);
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(info->clk)) {
|
||||
dev_err(&pdev->dev, "failed to find rtc clock source\n");
|
||||
return PTR_ERR(info->clk);
|
||||
}
|
||||
info->irq_1hz = irq_1hz;
|
||||
info->irq_alarm = irq_alarm;
|
||||
spin_lock_init(&info->lock);
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret)
|
||||
|
@ -257,22 +249,19 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
|||
* If the clock divider is uninitialized then reset it to the
|
||||
* default value to get the 1Hz clock.
|
||||
*/
|
||||
if (RTTR == 0) {
|
||||
RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
|
||||
if (readl_relaxed(info->rttr) == 0) {
|
||||
writel_relaxed(RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16), info->rttr);
|
||||
dev_warn(&pdev->dev, "warning: "
|
||||
"initializing default clock divider/trim value\n");
|
||||
/* The current RTC value probably doesn't make sense either */
|
||||
RCNR = 0;
|
||||
writel_relaxed(0, info->rcnr);
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops,
|
||||
THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rtc)) {
|
||||
ret = PTR_ERR(rtc);
|
||||
goto err_dev;
|
||||
clk_disable_unprepare(info->clk);
|
||||
return PTR_ERR(rtc);
|
||||
}
|
||||
info->rtc = rtc;
|
||||
|
||||
|
@ -298,12 +287,52 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
|||
*
|
||||
* Notice that clearing bit 1 and 0 is accomplished by writting ONES to
|
||||
* the corresponding bits in RTSR. */
|
||||
RTSR = RTSR_AL | RTSR_HZ;
|
||||
writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr);
|
||||
|
||||
return 0;
|
||||
err_dev:
|
||||
clk_disable_unprepare(info->clk);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sa1100_rtc_init);
|
||||
|
||||
static int sa1100_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sa1100_rtc *info;
|
||||
struct resource *iores;
|
||||
void __iomem *base;
|
||||
int irq_1hz, irq_alarm;
|
||||
|
||||
irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz");
|
||||
irq_alarm = platform_get_irq_byname(pdev, "rtc alarm");
|
||||
if (irq_1hz < 0 || irq_alarm < 0)
|
||||
return -ENODEV;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->irq_1hz = irq_1hz;
|
||||
info->irq_alarm = irq_alarm;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, iores);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_SA1100) ||
|
||||
of_device_is_compatible(pdev->dev.of_node, "mrvl,sa1100-rtc")) {
|
||||
info->rcnr = base + 0x04;
|
||||
info->rtsr = base + 0x10;
|
||||
info->rtar = base + 0x00;
|
||||
info->rttr = base + 0x08;
|
||||
} else {
|
||||
info->rcnr = base + 0x0;
|
||||
info->rtsr = base + 0x8;
|
||||
info->rtar = base + 0x4;
|
||||
info->rttr = base + 0xc;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return sa1100_rtc_init(pdev, info);
|
||||
}
|
||||
|
||||
static int sa1100_rtc_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __RTC_SA1100_H__
|
||||
#define __RTC_SA1100_H__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
struct clk;
|
||||
struct platform_device;
|
||||
|
||||
struct sa1100_rtc {
|
||||
spinlock_t lock;
|
||||
void __iomem *rcnr;
|
||||
void __iomem *rtar;
|
||||
void __iomem *rtsr;
|
||||
void __iomem *rttr;
|
||||
int irq_1hz;
|
||||
int irq_alarm;
|
||||
struct rtc_device *rtc;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info);
|
||||
|
||||
#endif
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc/sirfsoc_rtciobrg.h>
|
||||
|
||||
|
||||
|
@ -48,12 +49,27 @@ struct sirfsoc_rtc_drv {
|
|||
/* Overflow for every 8 years extra time */
|
||||
u32 overflow_rtc;
|
||||
spinlock_t lock;
|
||||
struct regmap *regmap;
|
||||
#ifdef CONFIG_PM
|
||||
u32 saved_counter;
|
||||
u32 saved_overflow_rtc;
|
||||
#endif
|
||||
};
|
||||
|
||||
static u32 sirfsoc_rtc_readl(struct sirfsoc_rtc_drv *rtcdrv, u32 offset)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
regmap_read(rtcdrv->regmap, rtcdrv->rtc_base + offset, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void sirfsoc_rtc_writel(struct sirfsoc_rtc_drv *rtcdrv,
|
||||
u32 offset, u32 val)
|
||||
{
|
||||
regmap_write(rtcdrv->regmap, rtcdrv->rtc_base + offset, val);
|
||||
}
|
||||
|
||||
static int sirfsoc_rtc_read_alarm(struct device *dev,
|
||||
struct rtc_wkalrm *alrm)
|
||||
{
|
||||
|
@ -64,9 +80,9 @@ static int sirfsoc_rtc_read_alarm(struct device *dev,
|
|||
|
||||
spin_lock_irq(&rtcdrv->lock);
|
||||
|
||||
rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
|
||||
rtc_count = sirfsoc_rtc_readl(rtcdrv, RTC_CN);
|
||||
|
||||
rtc_alarm = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_ALARM0);
|
||||
rtc_alarm = sirfsoc_rtc_readl(rtcdrv, RTC_ALARM0);
|
||||
memset(alrm, 0, sizeof(struct rtc_wkalrm));
|
||||
|
||||
/*
|
||||
|
@ -82,8 +98,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev,
|
|||
rtc_time_to_tm(rtcdrv->overflow_rtc
|
||||
<< (BITS_PER_LONG - RTC_SHIFT)
|
||||
| rtc_alarm >> RTC_SHIFT, &(alrm->time));
|
||||
if (sirfsoc_rtc_iobrg_readl(
|
||||
rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E)
|
||||
if (sirfsoc_rtc_readl(rtcdrv, RTC_STATUS) & SIRFSOC_RTC_AL0E)
|
||||
alrm->enabled = 1;
|
||||
|
||||
spin_unlock_irq(&rtcdrv->lock);
|
||||
|
@ -103,8 +118,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
|
|||
|
||||
spin_lock_irq(&rtcdrv->lock);
|
||||
|
||||
rtc_status_reg = sirfsoc_rtc_iobrg_readl(
|
||||
rtcdrv->rtc_base + RTC_STATUS);
|
||||
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS);
|
||||
if (rtc_status_reg & SIRFSOC_RTC_AL0E) {
|
||||
/*
|
||||
* An ongoing alarm in progress - ingore it and not
|
||||
|
@ -113,8 +127,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
|
|||
dev_info(dev, "An old alarm was set, will be replaced by a new one\n");
|
||||
}
|
||||
|
||||
sirfsoc_rtc_iobrg_writel(
|
||||
rtc_alarm << RTC_SHIFT, rtcdrv->rtc_base + RTC_ALARM0);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, rtc_alarm << RTC_SHIFT);
|
||||
rtc_status_reg &= ~0x07; /* mask out the lower status bits */
|
||||
/*
|
||||
* This bit RTC_AL sets it as a wake-up source for Sleep Mode
|
||||
|
@ -123,8 +136,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
|
|||
rtc_status_reg |= SIRFSOC_RTC_AL0;
|
||||
/* enable the RTC alarm interrupt */
|
||||
rtc_status_reg |= SIRFSOC_RTC_AL0E;
|
||||
sirfsoc_rtc_iobrg_writel(
|
||||
rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg);
|
||||
|
||||
spin_unlock_irq(&rtcdrv->lock);
|
||||
} else {
|
||||
|
@ -135,8 +147,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
|
|||
*/
|
||||
spin_lock_irq(&rtcdrv->lock);
|
||||
|
||||
rtc_status_reg = sirfsoc_rtc_iobrg_readl(
|
||||
rtcdrv->rtc_base + RTC_STATUS);
|
||||
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS);
|
||||
if (rtc_status_reg & SIRFSOC_RTC_AL0E) {
|
||||
/* clear the RTC status register's alarm bit */
|
||||
rtc_status_reg &= ~0x07;
|
||||
|
@ -145,8 +156,8 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
|
|||
/* Clear the Alarm enable bit */
|
||||
rtc_status_reg &= ~(SIRFSOC_RTC_AL0E);
|
||||
|
||||
sirfsoc_rtc_iobrg_writel(rtc_status_reg,
|
||||
rtcdrv->rtc_base + RTC_STATUS);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS,
|
||||
rtc_status_reg);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&rtcdrv->lock);
|
||||
|
@ -167,9 +178,9 @@ static int sirfsoc_rtc_read_time(struct device *dev,
|
|||
* fail, read several times to make sure get stable value.
|
||||
*/
|
||||
do {
|
||||
tmp_rtc = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
|
||||
tmp_rtc = sirfsoc_rtc_readl(rtcdrv, RTC_CN);
|
||||
cpu_relax();
|
||||
} while (tmp_rtc != sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN));
|
||||
} while (tmp_rtc != sirfsoc_rtc_readl(rtcdrv, RTC_CN));
|
||||
|
||||
rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) |
|
||||
tmp_rtc >> RTC_SHIFT, tm);
|
||||
|
@ -187,10 +198,8 @@ static int sirfsoc_rtc_set_time(struct device *dev,
|
|||
|
||||
rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT);
|
||||
|
||||
sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
|
||||
rtcdrv->rtc_base + RTC_SW_VALUE);
|
||||
sirfsoc_rtc_iobrg_writel(
|
||||
rtc_time << RTC_SHIFT, rtcdrv->rtc_base + RTC_CN);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_CN, rtc_time << RTC_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -222,14 +231,13 @@ static int sirfsoc_rtc_alarm_irq_enable(struct device *dev,
|
|||
|
||||
spin_lock_irq(&rtcdrv->lock);
|
||||
|
||||
rtc_status_reg = sirfsoc_rtc_iobrg_readl(
|
||||
rtcdrv->rtc_base + RTC_STATUS);
|
||||
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS);
|
||||
if (enabled)
|
||||
rtc_status_reg |= SIRFSOC_RTC_AL0E;
|
||||
else
|
||||
rtc_status_reg &= ~SIRFSOC_RTC_AL0E;
|
||||
|
||||
sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg);
|
||||
|
||||
spin_unlock_irq(&rtcdrv->lock);
|
||||
|
||||
|
@ -254,7 +262,7 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
|
|||
|
||||
spin_lock(&rtcdrv->lock);
|
||||
|
||||
rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS);
|
||||
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS);
|
||||
/* this bit will be set ONLY if an alarm was active
|
||||
* and it expired NOW
|
||||
* So this is being used as an ASSERT
|
||||
|
@ -270,7 +278,8 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
|
|||
/* Clear the Alarm enable bit */
|
||||
rtc_status_reg &= ~(SIRFSOC_RTC_AL0E);
|
||||
}
|
||||
sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
|
||||
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg);
|
||||
|
||||
spin_unlock(&rtcdrv->lock);
|
||||
|
||||
|
@ -287,6 +296,13 @@ static const struct of_device_id sirfsoc_rtc_of_match[] = {
|
|||
{ .compatible = "sirf,prima2-sysrtc"},
|
||||
{},
|
||||
};
|
||||
|
||||
const struct regmap_config sysrtc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_rtc_of_match);
|
||||
|
||||
static int sirfsoc_rtc_probe(struct platform_device *pdev)
|
||||
|
@ -314,27 +330,35 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
|
|||
/* Register rtc alarm as a wakeup source */
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
rtcdrv->regmap = devm_regmap_init_iobg(&pdev->dev,
|
||||
&sysrtc_regmap_config);
|
||||
if (IS_ERR(rtcdrv->regmap)) {
|
||||
err = PTR_ERR(rtcdrv->regmap);
|
||||
dev_err(&pdev->dev, "Failed to allocate register map: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set SYS_RTC counter in RTC_HZ HZ Units
|
||||
* We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1
|
||||
* If 16HZ, therefore RTC_DIV = 1023;
|
||||
*/
|
||||
rtc_div = ((32768 / RTC_HZ) / 2) - 1;
|
||||
sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div);
|
||||
|
||||
/* 0x3 -> RTC_CLK */
|
||||
sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK,
|
||||
rtcdrv->rtc_base + RTC_CLOCK_SWITCH);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK);
|
||||
|
||||
/* reset SYS RTC ALARM0 */
|
||||
sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0);
|
||||
|
||||
/* reset SYS RTC ALARM1 */
|
||||
sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0);
|
||||
|
||||
/* Restore RTC Overflow From Register After Command Reboot */
|
||||
rtcdrv->overflow_rtc =
|
||||
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
|
||||
sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE);
|
||||
|
||||
rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&sirfsoc_rtc_ops, THIS_MODULE);
|
||||
|
@ -372,10 +396,10 @@ static int sirfsoc_rtc_suspend(struct device *dev)
|
|||
{
|
||||
struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
|
||||
rtcdrv->overflow_rtc =
|
||||
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
|
||||
sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE);
|
||||
|
||||
rtcdrv->saved_counter =
|
||||
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
|
||||
sirfsoc_rtc_readl(rtcdrv, RTC_CN);
|
||||
rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
|
||||
if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq))
|
||||
rtcdrv->irq_wake = 1;
|
||||
|
@ -392,12 +416,10 @@ static int sirfsoc_rtc_resume(struct device *dev)
|
|||
* if resume from snapshot and the rtc power is lost,
|
||||
* restroe the rtc settings
|
||||
*/
|
||||
if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl(
|
||||
rtcdrv->rtc_base + RTC_CLOCK_SWITCH)) {
|
||||
if (SIRFSOC_RTC_CLK != sirfsoc_rtc_readl(rtcdrv, RTC_CLOCK_SWITCH)) {
|
||||
u32 rtc_div;
|
||||
/* 0x3 -> RTC_CLK */
|
||||
sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK,
|
||||
rtcdrv->rtc_base + RTC_CLOCK_SWITCH);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK);
|
||||
/*
|
||||
* Set SYS_RTC counter in RTC_HZ HZ Units
|
||||
* We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1
|
||||
|
@ -405,13 +427,13 @@ static int sirfsoc_rtc_resume(struct device *dev)
|
|||
*/
|
||||
rtc_div = ((32768 / RTC_HZ) / 2) - 1;
|
||||
|
||||
sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div);
|
||||
|
||||
/* reset SYS RTC ALARM0 */
|
||||
sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0);
|
||||
|
||||
/* reset SYS RTC ALARM1 */
|
||||
sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0);
|
||||
}
|
||||
rtcdrv->overflow_rtc = rtcdrv->saved_overflow_rtc;
|
||||
|
||||
|
@ -419,15 +441,14 @@ static int sirfsoc_rtc_resume(struct device *dev)
|
|||
* if current counter is small than previous,
|
||||
* it means overflow in sleep
|
||||
*/
|
||||
tmp = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
|
||||
tmp = sirfsoc_rtc_readl(rtcdrv, RTC_CN);
|
||||
if (tmp <= rtcdrv->saved_counter)
|
||||
rtcdrv->overflow_rtc++;
|
||||
/*
|
||||
*PWRC Value Be Changed When Suspend, Restore Overflow
|
||||
* In Memory To Register
|
||||
*/
|
||||
sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
|
||||
rtcdrv->rtc_base + RTC_SW_VALUE);
|
||||
sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc);
|
||||
|
||||
if (device_may_wakeup(dev) && rtcdrv->irq_wake) {
|
||||
disable_irq_wake(rtcdrv->irq);
|
||||
|
|
|
@ -254,7 +254,7 @@ static ssize_t stk17ta8_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
ssize_t count;
|
||||
|
||||
for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
*buf++ = readb(ioaddr + pos++);
|
||||
return count;
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ static ssize_t stk17ta8_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
ssize_t count;
|
||||
|
||||
for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
|
||||
for (count = 0; count < size; count++)
|
||||
writeb(*buf++, ioaddr + pos++);
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -122,20 +122,8 @@ hctosys_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
}
|
||||
static DEVICE_ATTR_RO(hctosys);
|
||||
|
||||
static struct attribute *rtc_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_date.attr,
|
||||
&dev_attr_time.attr,
|
||||
&dev_attr_since_epoch.attr,
|
||||
&dev_attr_max_user_freq.attr,
|
||||
&dev_attr_hctosys.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(rtc);
|
||||
|
||||
static ssize_t
|
||||
rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ssize_t retval;
|
||||
unsigned long alarm;
|
||||
|
@ -159,7 +147,7 @@ rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
|
||||
wakealarm_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t n)
|
||||
{
|
||||
ssize_t retval;
|
||||
|
@ -221,45 +209,57 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
|
|||
retval = rtc_set_alarm(rtc, &alm);
|
||||
return (retval < 0) ? retval : n;
|
||||
}
|
||||
static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
|
||||
rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
|
||||
static DEVICE_ATTR_RW(wakealarm);
|
||||
|
||||
static struct attribute *rtc_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_date.attr,
|
||||
&dev_attr_time.attr,
|
||||
&dev_attr_since_epoch.attr,
|
||||
&dev_attr_max_user_freq.attr,
|
||||
&dev_attr_hctosys.attr,
|
||||
&dev_attr_wakealarm.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* The reason to trigger an alarm with no process watching it (via sysfs)
|
||||
* is its side effect: waking from a system state like suspend-to-RAM or
|
||||
* suspend-to-disk. So: no attribute unless that side effect is possible.
|
||||
* (Userspace may disable that mechanism later.)
|
||||
*/
|
||||
static inline int rtc_does_wakealarm(struct rtc_device *rtc)
|
||||
static bool rtc_does_wakealarm(struct rtc_device *rtc)
|
||||
{
|
||||
if (!device_can_wakeup(rtc->dev.parent))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
return rtc->ops->set_alarm != NULL;
|
||||
}
|
||||
|
||||
|
||||
void rtc_sysfs_add_device(struct rtc_device *rtc)
|
||||
static umode_t rtc_attr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct rtc_device *rtc = to_rtc_device(dev);
|
||||
umode_t mode = attr->mode;
|
||||
|
||||
/* not all RTCs support both alarms and wakeup */
|
||||
if (!rtc_does_wakealarm(rtc))
|
||||
return;
|
||||
if (attr == &dev_attr_wakealarm.attr)
|
||||
if (!rtc_does_wakealarm(rtc))
|
||||
mode = 0;
|
||||
|
||||
err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
|
||||
if (err)
|
||||
dev_err(rtc->dev.parent,
|
||||
"failed to create alarm attribute, %d\n", err);
|
||||
return mode;
|
||||
}
|
||||
|
||||
void rtc_sysfs_del_device(struct rtc_device *rtc)
|
||||
{
|
||||
/* REVISIT did we add it successfully? */
|
||||
if (rtc_does_wakealarm(rtc))
|
||||
device_remove_file(&rtc->dev, &dev_attr_wakealarm);
|
||||
}
|
||||
static struct attribute_group rtc_attr_group = {
|
||||
.is_visible = rtc_attr_is_visible,
|
||||
.attrs = rtc_attrs,
|
||||
};
|
||||
|
||||
void __init rtc_sysfs_init(struct class *rtc_class)
|
||||
static const struct attribute_group *rtc_attr_groups[] = {
|
||||
&rtc_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct attribute_group **rtc_get_dev_attribute_groups(void)
|
||||
{
|
||||
rtc_class->dev_groups = rtc_groups;
|
||||
return rtc_attr_groups;
|
||||
}
|
||||
|
|
|
@ -199,8 +199,7 @@ static ssize_t tx4939_rtc_nvram_read(struct file *filp, struct kobject *kobj,
|
|||
ssize_t count;
|
||||
|
||||
spin_lock_irq(&pdata->lock);
|
||||
for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;
|
||||
count++, size--) {
|
||||
for (count = 0; count < size; count++) {
|
||||
__raw_writel(pos++, &rtcreg->adr);
|
||||
*buf++ = __raw_readl(&rtcreg->dat);
|
||||
}
|
||||
|
@ -218,8 +217,7 @@ static ssize_t tx4939_rtc_nvram_write(struct file *filp, struct kobject *kobj,
|
|||
ssize_t count;
|
||||
|
||||
spin_lock_irq(&pdata->lock);
|
||||
for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;
|
||||
count++, size--) {
|
||||
for (count = 0; count < size; count++) {
|
||||
__raw_writel(pos++, &rtcreg->adr);
|
||||
__raw_writel(*buf++, &rtcreg->dat);
|
||||
}
|
||||
|
|
|
@ -271,6 +271,7 @@ static const struct of_device_id wmt_dt_ids[] = {
|
|||
{ .compatible = "via,vt8500-rtc", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wmt_dt_ids);
|
||||
|
||||
static struct platform_driver vt8500_rtc_driver = {
|
||||
.probe = vt8500_rtc_probe,
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Xilinx Zynq Ultrascale+ MPSoC Real Time Clock Driver
|
||||
*
|
||||
* Copyright (C) 2015 Xilinx, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/* RTC Registers */
|
||||
#define RTC_SET_TM_WR 0x00
|
||||
#define RTC_SET_TM_RD 0x04
|
||||
#define RTC_CALIB_WR 0x08
|
||||
#define RTC_CALIB_RD 0x0C
|
||||
#define RTC_CUR_TM 0x10
|
||||
#define RTC_CUR_TICK 0x14
|
||||
#define RTC_ALRM 0x18
|
||||
#define RTC_INT_STS 0x20
|
||||
#define RTC_INT_MASK 0x24
|
||||
#define RTC_INT_EN 0x28
|
||||
#define RTC_INT_DIS 0x2C
|
||||
#define RTC_CTRL 0x40
|
||||
|
||||
#define RTC_FR_EN BIT(20)
|
||||
#define RTC_FR_DATSHIFT 16
|
||||
#define RTC_TICK_MASK 0xFFFF
|
||||
#define RTC_INT_SEC BIT(0)
|
||||
#define RTC_INT_ALRM BIT(1)
|
||||
#define RTC_OSC_EN BIT(24)
|
||||
|
||||
#define RTC_CALIB_DEF 0x198233
|
||||
#define RTC_CALIB_MASK 0x1FFFFF
|
||||
#define RTC_SEC_MAX_VAL 0xFFFFFFFF
|
||||
|
||||
struct xlnx_rtc_dev {
|
||||
struct rtc_device *rtc;
|
||||
void __iomem *reg_base;
|
||||
int alarm_irq;
|
||||
int sec_irq;
|
||||
};
|
||||
|
||||
static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
unsigned long new_time;
|
||||
|
||||
new_time = rtc_tm_to_time64(tm);
|
||||
|
||||
if (new_time > RTC_SEC_MAX_VAL)
|
||||
return -EINVAL;
|
||||
|
||||
writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
|
||||
rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm);
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int xlnx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
|
||||
rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_ALRM), &alrm->time);
|
||||
alrm->enabled = readl(xrtcdev->reg_base + RTC_INT_MASK) & RTC_INT_ALRM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_rtc_alarm_irq_enable(struct device *dev, u32 enabled)
|
||||
{
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
|
||||
if (enabled)
|
||||
writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN);
|
||||
else
|
||||
writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
unsigned long alarm_time;
|
||||
|
||||
alarm_time = rtc_tm_to_time64(&alrm->time);
|
||||
|
||||
if (alarm_time > RTC_SEC_MAX_VAL)
|
||||
return -EINVAL;
|
||||
|
||||
writel((u32)alarm_time, (xrtcdev->reg_base + RTC_ALRM));
|
||||
|
||||
xlnx_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev, u32 calibval)
|
||||
{
|
||||
/*
|
||||
* Based on crystal freq of 33.330 KHz
|
||||
* set the seconds counter and enable, set fractions counter
|
||||
* to default value suggested as per design spec
|
||||
* to correct RTC delay in frequency over period of time.
|
||||
*/
|
||||
calibval &= RTC_CALIB_MASK;
|
||||
writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops xlnx_rtc_ops = {
|
||||
.set_time = xlnx_rtc_set_time,
|
||||
.read_time = xlnx_rtc_read_time,
|
||||
.read_alarm = xlnx_rtc_read_alarm,
|
||||
.set_alarm = xlnx_rtc_set_alarm,
|
||||
.alarm_irq_enable = xlnx_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
|
||||
{
|
||||
struct xlnx_rtc_dev *xrtcdev = (struct xlnx_rtc_dev *)id;
|
||||
unsigned int status;
|
||||
|
||||
status = readl(xrtcdev->reg_base + RTC_INT_STS);
|
||||
/* Check if interrupt asserted */
|
||||
if (!(status & (RTC_INT_SEC | RTC_INT_ALRM)))
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(status, xrtcdev->reg_base + RTC_INT_STS);
|
||||
|
||||
if (status & RTC_INT_SEC)
|
||||
rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_UF);
|
||||
if (status & RTC_INT_ALRM)
|
||||
rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int xlnx_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct xlnx_rtc_dev *xrtcdev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
unsigned int calibvalue;
|
||||
|
||||
xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
|
||||
if (!xrtcdev)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, xrtcdev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
xrtcdev->reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(xrtcdev->reg_base))
|
||||
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");
|
||||
return xrtcdev->alarm_irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, xrtcdev->alarm_irq,
|
||||
xlnx_rtc_interrupt, 0,
|
||||
dev_name(&pdev->dev), xrtcdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request irq failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
xrtcdev->sec_irq = platform_get_irq_byname(pdev, "sec");
|
||||
if (xrtcdev->sec_irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource\n");
|
||||
return xrtcdev->sec_irq;
|
||||
}
|
||||
ret = devm_request_irq(&pdev->dev, xrtcdev->sec_irq,
|
||||
xlnx_rtc_interrupt, 0,
|
||||
dev_name(&pdev->dev), xrtcdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request irq failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "calibration",
|
||||
&calibvalue);
|
||||
if (ret)
|
||||
calibvalue = RTC_CALIB_DEF;
|
||||
|
||||
xlnx_init_rtc(xrtcdev, calibvalue);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
xrtcdev->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&xlnx_rtc_ops, THIS_MODULE);
|
||||
return PTR_ERR_OR_ZERO(xrtcdev->rtc);
|
||||
}
|
||||
|
||||
static int xlnx_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
xlnx_rtc_alarm_irq_enable(&pdev->dev, 0);
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused xlnx_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
enable_irq_wake(xrtcdev->alarm_irq);
|
||||
else
|
||||
xlnx_rtc_alarm_irq_enable(dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused xlnx_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
disable_irq_wake(xrtcdev->alarm_irq);
|
||||
else
|
||||
xlnx_rtc_alarm_irq_enable(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(xlnx_rtc_pm_ops, xlnx_rtc_suspend, xlnx_rtc_resume);
|
||||
|
||||
static const struct of_device_id xlnx_rtc_of_match[] = {
|
||||
{.compatible = "xlnx,zynqmp-rtc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match);
|
||||
|
||||
static struct platform_driver xlnx_rtc_driver = {
|
||||
.probe = xlnx_rtc_probe,
|
||||
.remove = xlnx_rtc_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.pm = &xlnx_rtc_pm_ops,
|
||||
.of_match_table = xlnx_rtc_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(xlnx_rtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Xilinx Zynq MPSoC RTC driver");
|
||||
MODULE_AUTHOR("Xilinx Inc.");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -16,6 +16,9 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/delay.h>
|
||||
#ifdef CONFIG_ACPI
|
||||
#include <linux/acpi.h>
|
||||
#endif
|
||||
|
||||
#define RTC_PIE 0x40 /* periodic interrupt enable */
|
||||
#define RTC_AIE 0x20 /* alarm interrupt enable */
|
||||
|
@ -46,6 +49,7 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
|
|||
{
|
||||
unsigned char ctrl;
|
||||
unsigned long flags;
|
||||
unsigned char century = 0;
|
||||
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
unsigned int real_year;
|
||||
|
@ -78,6 +82,11 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
|
|||
time->tm_year = CMOS_READ(RTC_YEAR);
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
real_year = CMOS_READ(RTC_DEC_YEAR);
|
||||
#endif
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
|
||||
acpi_gbl_FADT.century)
|
||||
century = CMOS_READ(acpi_gbl_FADT.century);
|
||||
#endif
|
||||
ctrl = CMOS_READ(RTC_CONTROL);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
@ -90,12 +99,16 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
|
|||
time->tm_mday = bcd2bin(time->tm_mday);
|
||||
time->tm_mon = bcd2bin(time->tm_mon);
|
||||
time->tm_year = bcd2bin(time->tm_year);
|
||||
century = bcd2bin(century);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
time->tm_year += real_year - 72;
|
||||
#endif
|
||||
|
||||
if (century)
|
||||
time->tm_year += (century - 19) * 100;
|
||||
|
||||
/*
|
||||
* Account for differences between how the RTC uses the values
|
||||
* and how they are defined in a struct rtc_time;
|
||||
|
@ -122,6 +135,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
|
|||
#ifdef CONFIG_MACH_DECSTATION
|
||||
unsigned int real_yrs, leap_yr;
|
||||
#endif
|
||||
unsigned char century = 0;
|
||||
|
||||
yrs = time->tm_year;
|
||||
mon = time->tm_mon + 1; /* tm_mon starts at zero */
|
||||
|
@ -150,6 +164,15 @@ static inline int __set_rtc_time(struct rtc_time *time)
|
|||
yrs = 73;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
|
||||
acpi_gbl_FADT.century) {
|
||||
century = (yrs + 1900) / 100;
|
||||
yrs %= 100;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* These limits and adjustments are independent of
|
||||
* whether the chip is in binary mode or not.
|
||||
*/
|
||||
|
@ -169,6 +192,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
|
|||
day = bin2bcd(day);
|
||||
mon = bin2bcd(mon);
|
||||
yrs = bin2bcd(yrs);
|
||||
century = bin2bcd(century);
|
||||
}
|
||||
|
||||
save_control = CMOS_READ(RTC_CONTROL);
|
||||
|
@ -185,6 +209,11 @@ static inline int __set_rtc_time(struct rtc_time *time)
|
|||
CMOS_WRITE(hrs, RTC_HOURS);
|
||||
CMOS_WRITE(min, RTC_MINUTES);
|
||||
CMOS_WRITE(sec, RTC_SECONDS);
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
|
||||
acpi_gbl_FADT.century)
|
||||
CMOS_WRITE(century, acpi_gbl_FADT.century);
|
||||
#endif
|
||||
|
||||
CMOS_WRITE(save_control, RTC_CONTROL);
|
||||
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
|
||||
|
|
Загрузка…
Ссылка в новой задаче