RTC for 4.2
Core: - Coding style and whitespace fixes (interface, Makefile and Kconfig) - New rtc_tm_sub() helper - New CONFIG_RTC_SYSTOHC_DEVICE option - Removed rtc_set_mmss() New drivers: - Mediatek MT6397 - Cortina Gemini Drivers: - Year 2106 fixes for isl1208, pcf8563 and sunxi - update author email for at32ap700x and efi - ds1307: alarm fix - efi: use correct EFI 'epoch' - hym8563: make irq optional - imxdi: cleanups and better handling of the security/tamper monitoring - snvs: fix wakealarm - Compilation fixes or warning removal for gemini, mt6397, palmas, pfc8563 - Trivial cleanups for ab8500, ds1216, ds1286, ds1672, ep93xx, hid-sensor-time, max6900, max8998, max77686, max77802, mc13xxx, mv, mxc, s3c, spear, v3020 - Kconfig fixes for stmp3xxx and xgene -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJVi7VHAAoJEKbNnwlvZCyzv+YP/1sMAsrusvx3cUEmhJurNk5H +vPUdogbr8df9voLkHqTaK1B5+LrL5EXYu+y/6VOwaLIiYv7P9k/eOeZ44fraidc H7xnDQ7cOGzE5LpjPg8+o56rh3rGDF1UdZBwbFTgfv4gmZi+GAf+2MEUam+dVVtF K9+7Xu77A6EgW+h2uHix8GVtflHdRk/Vxjxl0uOR9BM9O883N5dYYZ7sjenfG65D dctAEo+U1xUCw3GCIQ63DvD0joThQk7IB9xJmK/lE5nIv4tbGp5PV8VSNkjKxbFz 1wa9SR1dhBdjbJ6ZeHh8N5EJ0d5MrssW1blsb7/06MHTu0KYgCndU5EEDOE2pVqD GJooYa6RsNqz/KElJ7/0z4T+DJxW7BWaZYRIwv4jpuA4/Y74O5FDw0ULOqxhB8zd kVgfWb0feNQikaZio8gOyzIBkw3CBZBu+f6HMJGaeYWSzTNsDLgA8ee7mUawMP31 ljOxOuPMiTGUbAczK9URo/acZYWNyCOQdm85FxCuwCuPe48m7CyTU6wWBX0Vwj5q y3sHH5stcykCesneNj+IJ8v/knqo9d6M43CbCbwBeo0DJskuXF6jjQ9QLBNZP9U0 7qQa7isL3j3J7T5EouJIBQH2yy4SFiffVOZOPbJ8l+iRUPZUMdOEs2VkQs8BKIZ+ znu/Ov941h8/HbyI6rcl =mugF -----END PGP SIGNATURE----- Merge tag 'rtc-v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "Core: - Coding style and whitespace fixes (interface, Makefile and Kconfig) - New rtc_tm_sub() helper - New CONFIG_RTC_SYSTOHC_DEVICE option - Removed rtc_set_mmss() New drivers: - Mediatek MT6397 - Cortina Gemini Drivers: - Year 2106 fixes for isl1208, pcf8563 and sunxi - update author email for at32ap700x and efi - ds1307: alarm fix - efi: use correct EFI 'epoch' - hym8563: make irq optional - imxdi: cleanups and better handling of the security/tamper monitoring - snvs: fix wakealarm - Compilation fixes or warning removal for gemini, mt6397, palmas, pfc8563 - Trivial cleanups for ab8500, ds1216, ds1286, ds1672, ep93xx, hid-sensor-time, max6900, max8998, max77686, max77802, mc13xxx, mv, mxc, s3c, spear, v3020 - Kconfig fixes for stmp3xxx and xgene" * tag 'rtc-v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (48 commits) rtc: remove useless I2C dependencies rtc: whitespace fixes rtc: Properly sort Makefile MAINTAINERS: Add RTC subsystem repository rtc: pfc8563: fix uninitialized variable warning rtc: ds1307: Enable the mcp794xx alarm after programming time rtc: hym8563: make the irq optional rtc: gemini: fix cocci warnings rtc: mv: correct 24 hour error message rtc: mv: use BIT() rtc: efi: use correct EFI 'epoch' rtc: interface: Remove rtc_set_mmss() sparc: time: Replace update_persistent_clock() with CONFIG_RTC_SYSTOHC rtc: NTP: Add CONFIG_RTC_SYSTOHC_DEVICE for NTP synchronization rtc: sunxi: Replace deprecated rtc_tm_to_time() rtc: isl1208: Replace deprecated rtc_tm_to_time() rtc: Introduce rtc_tm_sub() helper function rtc: pcf8563: Replace deprecated rtc_time_to_tm() and rtc_tm_to_time() rtc: palmas: Initialise bb_charging flag before using it rtc: simplify use of devm_ioremap_resource ...
This commit is contained in:
commit
c13c810063
|
@ -6,11 +6,11 @@ as well as a clock output of up to 32kHz.
|
|||
Required properties:
|
||||
- compatible: should be: "haoyu,hym8563"
|
||||
- reg: i2c address
|
||||
- interrupts: rtc alarm/event interrupt
|
||||
- #clock-cells: the value should be 0
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock binding
|
||||
- interrupts: rtc alarm/event interrupt
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -984,6 +984,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
|||
T: git git://github.com/ulli-kroll/linux.git
|
||||
S: Maintained
|
||||
F: arch/arm/mach-gemini/
|
||||
F: drivers/rtc/rtc-gemini.c
|
||||
|
||||
ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
|
||||
M: Barry Song <baohua@kernel.org>
|
||||
|
@ -1243,6 +1244,13 @@ W: http://www.digriz.org.uk/ts78xx/kernel
|
|||
S: Maintained
|
||||
F: arch/arm/mach-orion5x/ts78xx-*
|
||||
|
||||
ARM/Mediatek RTC DRIVER
|
||||
M: Eddie Huang <eddie.huang@mediatek.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/rtc/rtc-mt6397.c
|
||||
|
||||
ARM/Mediatek SoC support
|
||||
M: Matthias Brugger <matthias.bgg@gmail.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
|
@ -8380,6 +8388,7 @@ M: Alessandro Zummo <a.zummo@towertech.it>
|
|||
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
L: rtc-linux@googlegroups.com
|
||||
Q: http://patchwork.ozlabs.org/project/rtc-linux/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
|
||||
S: Maintained
|
||||
F: Documentation/rtc.txt
|
||||
F: drivers/rtc/
|
||||
|
|
|
@ -25,6 +25,7 @@ config SPARC
|
|||
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
|
||||
select RTC_CLASS
|
||||
select RTC_DRV_M48T59
|
||||
select RTC_SYSTOHC
|
||||
select HAVE_DMA_ATTRS
|
||||
select HAVE_DMA_API_DEBUG
|
||||
select HAVE_ARCH_JUMP_LABEL if SPARC64
|
||||
|
@ -35,7 +36,6 @@ config SPARC
|
|||
select HAVE_BPF_JIT
|
||||
select HAVE_DEBUG_BUGVERBOSE
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_CMOS_UPDATE
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_STRNCPY_FROM_USER
|
||||
select GENERIC_STRNLEN_USER
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/rtc/m48t59.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/clocksource.h>
|
||||
|
@ -65,8 +64,6 @@ DEFINE_PER_CPU(struct clock_event_device, sparc32_clockevent);
|
|||
DEFINE_SPINLOCK(rtc_lock);
|
||||
EXPORT_SYMBOL(rtc_lock);
|
||||
|
||||
static int set_rtc_mmss(unsigned long);
|
||||
|
||||
unsigned long profile_pc(struct pt_regs *regs)
|
||||
{
|
||||
extern char __copy_user_begin[], __copy_user_end[];
|
||||
|
@ -87,11 +84,6 @@ EXPORT_SYMBOL(profile_pc);
|
|||
|
||||
volatile u32 __iomem *master_l10_counter;
|
||||
|
||||
int update_persistent_clock(struct timespec now)
|
||||
{
|
||||
return set_rtc_mmss(now.tv_sec);
|
||||
}
|
||||
|
||||
irqreturn_t notrace timer_interrupt(int dummy, void *dev_id)
|
||||
{
|
||||
if (timer_cs_enabled) {
|
||||
|
@ -362,16 +354,3 @@ void __init time_init(void)
|
|||
sbus_time_init();
|
||||
}
|
||||
|
||||
|
||||
static int set_rtc_mmss(unsigned long secs)
|
||||
{
|
||||
struct rtc_device *rtc = rtc_class_open("rtc0");
|
||||
int err = -1;
|
||||
|
||||
if (rtc) {
|
||||
err = rtc_set_mmss(rtc, secs);
|
||||
rtc_class_close(rtc);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/rtc/m48t59.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/clockchips.h>
|
||||
|
@ -394,19 +393,6 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = {
|
|||
|
||||
static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
|
||||
|
||||
int update_persistent_clock(struct timespec now)
|
||||
{
|
||||
struct rtc_device *rtc = rtc_class_open("rtc0");
|
||||
int err = -1;
|
||||
|
||||
if (rtc) {
|
||||
err = rtc_set_mmss(rtc, now.tv_sec);
|
||||
rtc_class_close(rtc);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
unsigned long cmos_regs;
|
||||
EXPORT_SYMBOL(cmos_regs);
|
||||
|
||||
|
|
|
@ -21,9 +21,27 @@
|
|||
#include <linux/mfd/mt6397/core.h>
|
||||
#include <linux/mfd/mt6397/registers.h>
|
||||
|
||||
#define MT6397_RTC_BASE 0xe000
|
||||
#define MT6397_RTC_SIZE 0x3e
|
||||
|
||||
static const struct resource mt6397_rtc_resources[] = {
|
||||
{
|
||||
.start = MT6397_RTC_BASE,
|
||||
.end = MT6397_RTC_BASE + MT6397_RTC_SIZE,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = MT6397_IRQ_RTC,
|
||||
.end = MT6397_IRQ_RTC,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell mt6397_devs[] = {
|
||||
{
|
||||
.name = "mt6397-rtc",
|
||||
.num_resources = ARRAY_SIZE(mt6397_rtc_resources),
|
||||
.resources = mt6397_rtc_resources,
|
||||
.of_compatible = "mediatek,mt6397-rtc",
|
||||
}, {
|
||||
.name = "mt6397-regulator",
|
||||
|
|
|
@ -12,7 +12,7 @@ menuconfig RTC_CLASS
|
|||
select RTC_LIB
|
||||
help
|
||||
Generic RTC class support. If you say yes here, you will
|
||||
be allowed to plug one or more RTCs to your system. You will
|
||||
be allowed to plug one or more RTCs to your system. You will
|
||||
probably want to enable one or more of the interfaces below.
|
||||
|
||||
if RTC_CLASS
|
||||
|
@ -25,17 +25,9 @@ config RTC_HCTOSYS
|
|||
the value read from a specified RTC device. This is useful to avoid
|
||||
unnecessary fsck runs at boot time, and to network better.
|
||||
|
||||
config RTC_SYSTOHC
|
||||
bool "Set the RTC time based on NTP synchronization"
|
||||
default y
|
||||
help
|
||||
If you say yes here, the system time (wall clock) will be stored
|
||||
in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
|
||||
minutes if userspace reports synchronized NTP status.
|
||||
|
||||
config RTC_HCTOSYS_DEVICE
|
||||
string "RTC used to set the system time"
|
||||
depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y
|
||||
depends on RTC_HCTOSYS
|
||||
default "rtc0"
|
||||
help
|
||||
The RTC device that will be used to (re)initialize the system
|
||||
|
@ -56,6 +48,25 @@ config RTC_HCTOSYS_DEVICE
|
|||
sleep states. Do not specify an RTC here unless it stays powered
|
||||
during all this system's supported sleep states.
|
||||
|
||||
config RTC_SYSTOHC
|
||||
bool "Set the RTC time based on NTP synchronization"
|
||||
default y
|
||||
help
|
||||
If you say yes here, the system time (wall clock) will be stored
|
||||
in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
|
||||
minutes if userspace reports synchronized NTP status.
|
||||
|
||||
config RTC_SYSTOHC_DEVICE
|
||||
string "RTC used to synchronize NTP adjustment"
|
||||
depends on RTC_SYSTOHC
|
||||
default RTC_HCTOSYS_DEVICE if RTC_HCTOSYS
|
||||
default "rtc0"
|
||||
help
|
||||
The RTC device used for NTP synchronization. The main difference
|
||||
between RTC_HCTOSYS_DEVICE and RTC_SYSTOHC_DEVICE is that this
|
||||
one can sleep when setting time, because it runs in the workqueue
|
||||
context.
|
||||
|
||||
config RTC_DEBUG
|
||||
bool "RTC debug support"
|
||||
help
|
||||
|
@ -135,7 +146,7 @@ if I2C
|
|||
|
||||
config RTC_DRV_88PM860X
|
||||
tristate "Marvell 88PM860x"
|
||||
depends on I2C && MFD_88PM860X
|
||||
depends on MFD_88PM860X
|
||||
help
|
||||
If you say yes here you get support for RTC function in Marvell
|
||||
88PM860x chips.
|
||||
|
@ -145,7 +156,7 @@ config RTC_DRV_88PM860X
|
|||
|
||||
config RTC_DRV_88PM80X
|
||||
tristate "Marvell 88PM80x"
|
||||
depends on I2C && MFD_88PM800
|
||||
depends on MFD_88PM800
|
||||
help
|
||||
If you say yes here you get support for RTC function in Marvell
|
||||
88PM80x chips.
|
||||
|
@ -154,10 +165,9 @@ config RTC_DRV_88PM80X
|
|||
will be called rtc-88pm80x.
|
||||
|
||||
config RTC_DRV_ABB5ZES3
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
|
||||
help
|
||||
select REGMAP_I2C
|
||||
tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
|
||||
help
|
||||
If you say yes here you get support for the Abracon
|
||||
AB-RTCMC-32.768kHz-B5ZE-S3 I2C RTC chip.
|
||||
|
||||
|
@ -204,7 +214,6 @@ config RTC_DRV_DS1307
|
|||
|
||||
config RTC_DRV_DS1374
|
||||
tristate "Dallas/Maxim DS1374"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Dallas Semiconductor
|
||||
DS1374 real-time clock chips. If an interrupt is associated
|
||||
|
@ -232,7 +241,6 @@ config RTC_DRV_DS1672
|
|||
|
||||
config RTC_DRV_DS3232
|
||||
tristate "Dallas/Maxim DS3232"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Dallas Semiconductor
|
||||
DS3232 real-time clock chips. If an interrupt is associated
|
||||
|
@ -243,7 +251,7 @@ config RTC_DRV_DS3232
|
|||
|
||||
config RTC_DRV_HYM8563
|
||||
tristate "Haoyu Microelectronics HYM8563"
|
||||
depends on I2C && OF
|
||||
depends on OF
|
||||
help
|
||||
Say Y to enable support for the HYM8563 I2C RTC chip. Apart
|
||||
from the usual rtc functions it provides a clock output of
|
||||
|
@ -365,10 +373,9 @@ config RTC_DRV_ISL12022
|
|||
will be called rtc-isl12022.
|
||||
|
||||
config RTC_DRV_ISL12057
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
tristate "Intersil ISL12057"
|
||||
help
|
||||
select REGMAP_I2C
|
||||
tristate "Intersil ISL12057"
|
||||
help
|
||||
If you say yes here you get support for the Intersil ISL12057
|
||||
I2C RTC chip.
|
||||
|
||||
|
@ -603,13 +610,13 @@ comment "SPI RTC drivers"
|
|||
if SPI_MASTER
|
||||
|
||||
config RTC_DRV_M41T93
|
||||
tristate "ST M41T93"
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
ST M41T93 SPI RTC chip.
|
||||
tristate "ST M41T93"
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
ST M41T93 SPI RTC chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-m41t93.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-m41t93.
|
||||
|
||||
config RTC_DRV_M41T94
|
||||
tristate "ST M41T94"
|
||||
|
@ -1200,7 +1207,7 @@ config RTC_DRV_SH
|
|||
Say Y here to enable support for the on-chip RTC found in
|
||||
most SuperH processors.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rtc-sh.
|
||||
|
||||
config RTC_DRV_VR41XX
|
||||
|
@ -1299,14 +1306,14 @@ 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
|
||||
help
|
||||
If you say Y here you will get access to the real time clock
|
||||
built into your PXA27x or PXA3xx CPU.
|
||||
|
||||
This RTC driver uses PXA RTC registers available since pxa27x
|
||||
series (RDxR, RYxR) instead of legacy RCNR, RTAR.
|
||||
This RTC driver uses PXA RTC registers available since pxa27x
|
||||
series (RDxR, RYxR) instead of legacy RCNR, RTAR.
|
||||
|
||||
config RTC_DRV_VT8500
|
||||
tristate "VIA/WonderMedia 85xx SoC RTC"
|
||||
|
@ -1372,6 +1379,17 @@ config RTC_DRV_ARMADA38X
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called armada38x-rtc.
|
||||
|
||||
config RTC_DRV_GEMINI
|
||||
tristate "Gemini SoC RTC"
|
||||
depends on ARCH_GEMINI || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
If you say Y here you will get support for the
|
||||
RTC found on Gemini SoC's.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-gemini.
|
||||
|
||||
config RTC_DRV_PS3
|
||||
tristate "PS3 RTC"
|
||||
depends on PPC_PS3
|
||||
|
@ -1396,6 +1414,7 @@ config RTC_DRV_COH901331
|
|||
config RTC_DRV_STMP
|
||||
tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC"
|
||||
depends on ARCH_MXS
|
||||
select STMP_DEVICE
|
||||
help
|
||||
If you say yes here you will get support for the onboard
|
||||
STMP3xxx/i.MX23/i.MX28 RTC.
|
||||
|
@ -1541,9 +1560,20 @@ config RTC_DRV_MOXART
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-moxart
|
||||
|
||||
config RTC_DRV_MT6397
|
||||
tristate "Mediatek Real Time Clock driver"
|
||||
depends on MFD_MT6397 || COMPILE_TEST
|
||||
help
|
||||
This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
|
||||
MT6397 PMIC. You should enable MT6397 PMIC MFD before select
|
||||
Mediatek(R) RTC driver.
|
||||
|
||||
If you want to use Mediatek(R) RTC interface, select Y or M here.
|
||||
|
||||
config RTC_DRV_XGENE
|
||||
tristate "APM X-Gene RTC"
|
||||
depends on HAS_IOMEM
|
||||
depends on ARCH_XGENE || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for the APM X-Gene SoC real time
|
||||
clock.
|
||||
|
|
|
@ -14,14 +14,14 @@ ifdef CONFIG_RTC_DRV_EFI
|
|||
rtc-core-y += rtc-efi-platform.o
|
||||
endif
|
||||
|
||||
rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
|
||||
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
|
||||
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
|
||||
rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
|
||||
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
|
||||
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
|
||||
|
||||
# Keep the list ordered.
|
||||
|
||||
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
|
||||
obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
|
||||
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
|
||||
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
|
||||
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
|
||||
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
|
||||
|
@ -43,7 +43,6 @@ obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
|
|||
obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
|
||||
obj-$(CONFIG_RTC_DRV_DIGICOLOR) += rtc-digicolor.o
|
||||
obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
|
||||
obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
|
||||
|
@ -58,20 +57,21 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
|
|||
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1685_FAMILY) += rtc-ds1685.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
|
||||
obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
|
||||
obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
|
||||
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
|
||||
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
|
||||
obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
|
||||
obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
|
||||
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
|
||||
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
|
||||
obj-$(CONFIG_RTC_DRV_GEMINI) += rtc-gemini.o
|
||||
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
|
||||
obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
|
||||
obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o
|
||||
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
|
||||
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_LPC32XX) += rtc-lpc32xx.o
|
||||
|
@ -82,32 +82,35 @@ obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
|
|||
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
|
||||
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
|
||||
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
|
||||
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX77802) += rtc-max77802.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX77802) += rtc-max77802.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
|
||||
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
|
||||
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
|
||||
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
|
||||
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
|
||||
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
|
||||
obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
|
||||
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
|
||||
obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o
|
||||
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
|
||||
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
|
||||
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
|
||||
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
|
||||
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
|
||||
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
|
||||
obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
|
||||
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
|
||||
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
|
||||
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
|
||||
obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
|
||||
|
@ -130,21 +133,23 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
|
|||
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
|
||||
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
|
||||
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
|
||||
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
|
||||
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
|
||||
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
|
||||
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
|
||||
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
|
||||
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
|
||||
obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
|
||||
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
|
||||
obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o
|
||||
obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o
|
||||
obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
|
||||
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
|
||||
obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
|
||||
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.o
|
||||
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
|
||||
obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
|
||||
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
|
||||
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
|
||||
|
@ -153,6 +158,3 @@ 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_SIRFSOC) += rtc-sirfsoc.o
|
||||
obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
|
||||
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
|
||||
|
|
|
@ -91,51 +91,6 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_set_time);
|
||||
|
||||
int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!rtc->ops)
|
||||
err = -ENODEV;
|
||||
else if (rtc->ops->set_mmss64)
|
||||
err = rtc->ops->set_mmss64(rtc->dev.parent, secs);
|
||||
else if (rtc->ops->set_mmss)
|
||||
err = rtc->ops->set_mmss(rtc->dev.parent, secs);
|
||||
else if (rtc->ops->read_time && rtc->ops->set_time) {
|
||||
struct rtc_time new, old;
|
||||
|
||||
err = rtc->ops->read_time(rtc->dev.parent, &old);
|
||||
if (err == 0) {
|
||||
rtc_time64_to_tm(secs, &new);
|
||||
|
||||
/*
|
||||
* avoid writing when we're going to change the day of
|
||||
* the month. We will retry in the next minute. This
|
||||
* basically means that if the RTC must not drift
|
||||
* by more than 1 minute in 11 minutes.
|
||||
*/
|
||||
if (!((old.tm_hour == 23 && old.tm_min == 59) ||
|
||||
(new.tm_hour == 23 && new.tm_min == 59)))
|
||||
err = rtc->ops->set_time(rtc->dev.parent,
|
||||
&new);
|
||||
}
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
pm_stay_awake(rtc->dev.parent);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
/* A timer might have just expired */
|
||||
schedule_work(&rtc->irqwork);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_set_mmss);
|
||||
|
||||
static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int err;
|
||||
|
@ -976,14 +931,12 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
|
|||
*
|
||||
* Kernel interface to cancel an rtc_timer
|
||||
*/
|
||||
int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
{
|
||||
int ret = 0;
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
if (timer->enabled)
|
||||
rtc_timer_remove(rtc, timer);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -442,7 +442,7 @@ static const struct rtc_class_ops ab8540_rtc_ops = {
|
|||
.alarm_irq_enable = ab8500_rtc_irq_enable,
|
||||
};
|
||||
|
||||
static struct platform_device_id ab85xx_rtc_ids[] = {
|
||||
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, },
|
||||
};
|
||||
|
|
|
@ -282,6 +282,6 @@ static struct platform_driver at32_rtc_driver = {
|
|||
|
||||
module_platform_driver_probe(at32_rtc_driver, at32_rtc_probe);
|
||||
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
|
||||
MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -144,15 +144,13 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev)
|
|||
struct ds1216_priv *priv;
|
||||
u8 dummy[8];
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->ioaddr))
|
||||
return PTR_ERR(priv->ioaddr);
|
||||
|
|
|
@ -332,13 +332,11 @@ static int ds1286_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct ds1286_priv *priv;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct ds1286_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->rtcregs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->rtcregs))
|
||||
return PTR_ERR(priv->rtcregs);
|
||||
|
|
|
@ -742,17 +742,17 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
regs[6] &= ~MCP794XX_BIT_ALMX_IF;
|
||||
/* Set alarm match: second, minute, hour, day, date, month. */
|
||||
regs[6] |= MCP794XX_MSK_ALMX_MATCH;
|
||||
|
||||
if (t->enabled)
|
||||
regs[0] |= MCP794XX_BIT_ALM0_EN;
|
||||
else
|
||||
regs[0] &= ~MCP794XX_BIT_ALM0_EN;
|
||||
/* Disable interrupt. We will not enable until completely programmed */
|
||||
regs[0] &= ~MCP794XX_BIT_ALM0_EN;
|
||||
|
||||
ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
if (!t->enabled)
|
||||
return 0;
|
||||
regs[0] |= MCP794XX_BIT_ALM0_EN;
|
||||
return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, regs[0]);
|
||||
}
|
||||
|
||||
static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
|
|
@ -198,6 +198,7 @@ static struct i2c_device_id ds1672_id[] = {
|
|||
{ "ds1672", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ds1672_id);
|
||||
|
||||
static struct i2c_driver ds1672_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Author: dann frazier <dannf@hp.com>
|
||||
* Author: dann frazier <dannf@dannf.org>
|
||||
* Based on efirtc.c by Stephane Eranian
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -24,10 +24,6 @@
|
|||
#include <linux/efi.h>
|
||||
|
||||
#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
|
||||
/*
|
||||
* EFI Epoch is 1/1/1998
|
||||
*/
|
||||
#define EFI_RTC_EPOCH 1998
|
||||
|
||||
/*
|
||||
* returns day of the year [0-365]
|
||||
|
@ -38,31 +34,24 @@ compute_yday(efi_time_t *eft)
|
|||
/* efi_time_t.month is in the [1-12] so, we need -1 */
|
||||
return rtc_year_days(eft->day, eft->month - 1, eft->year);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns day of the week [0-6] 0=Sunday
|
||||
*
|
||||
* Don't try to provide a year that's before 1998, please !
|
||||
*/
|
||||
static int
|
||||
compute_wday(efi_time_t *eft)
|
||||
compute_wday(efi_time_t *eft, int yday)
|
||||
{
|
||||
int y;
|
||||
int ndays = 0;
|
||||
|
||||
if (eft->year < EFI_RTC_EPOCH) {
|
||||
pr_err("EFI year < " __stringify(EFI_RTC_EPOCH) ", invalid date\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (y = EFI_RTC_EPOCH; y < eft->year; y++)
|
||||
ndays += 365 + (is_leap_year(y) ? 1 : 0);
|
||||
|
||||
ndays += compute_yday(eft);
|
||||
int ndays = eft->year * (365 % 7)
|
||||
+ (eft->year - 1) / 4
|
||||
- (eft->year - 1) / 100
|
||||
+ (eft->year - 1) / 400
|
||||
+ yday;
|
||||
|
||||
/*
|
||||
* 4=1/1/1998 was a Thursday
|
||||
* 1/1/0000 may or may not have been a Sunday (if it ever existed at
|
||||
* all) but assuming it was makes this calculation work correctly.
|
||||
*/
|
||||
return (ndays + 4) % 7;
|
||||
return ndays % 7;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -103,16 +92,16 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
|
|||
if (!eft->month || eft->month > 12)
|
||||
return false;
|
||||
wtime->tm_mon = eft->month - 1;
|
||||
wtime->tm_year = eft->year - 1900;
|
||||
|
||||
/* day of the week [0-6], Sunday=0 */
|
||||
wtime->tm_wday = compute_wday(eft);
|
||||
if (wtime->tm_wday < 0)
|
||||
if (eft->year < 1900 || eft->year > 9999)
|
||||
return false;
|
||||
wtime->tm_year = eft->year - 1900;
|
||||
|
||||
/* day in the year [1-365]*/
|
||||
wtime->tm_yday = compute_yday(eft);
|
||||
|
||||
/* day of the week [0-6], Sunday=0 */
|
||||
wtime->tm_wday = compute_wday(eft, wtime->tm_yday);
|
||||
|
||||
switch (eft->daylight & EFI_ISDST) {
|
||||
case EFI_ISDST:
|
||||
|
@ -233,7 +222,7 @@ static struct platform_driver efi_rtc_driver = {
|
|||
module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
|
||||
|
||||
MODULE_ALIAS("platform:rtc-efi");
|
||||
MODULE_AUTHOR("dann frazier <dannf@hp.com>");
|
||||
MODULE_AUTHOR("dann frazier <dannf@dannf.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("EFI RTC driver");
|
||||
MODULE_ALIAS("platform:rtc-efi");
|
||||
|
|
|
@ -45,7 +45,7 @@ static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
|
|||
struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
|
||||
unsigned long comp;
|
||||
|
||||
comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
|
||||
comp = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
|
||||
|
||||
if (preload)
|
||||
*preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
|
||||
|
@ -63,7 +63,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
|
||||
unsigned long time;
|
||||
|
||||
time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
|
||||
time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
|
||||
|
||||
rtc_time_to_tm(time, tm);
|
||||
return 0;
|
||||
|
@ -73,7 +73,7 @@ static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
|
|||
{
|
||||
struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
|
||||
|
||||
__raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
|
||||
writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Gemini OnChip RTC
|
||||
*
|
||||
* Copyright (C) 2009 Janos Laube <janos.dev@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.
|
||||
*
|
||||
* This program is distributed in the hope that 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.
|
||||
*
|
||||
* Original code for older kernel 2.6.15 are from Stormlinksemi
|
||||
* first update from Janos Laube for > 2.6.29 kernels
|
||||
*
|
||||
* checkpatch fixes and usage of rtc-lib code
|
||||
* Hans Ulli Kroll <ulli.kroll@googlemail.com>
|
||||
*/
|
||||
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_NAME "rtc-gemini"
|
||||
#define DRV_VERSION "0.2"
|
||||
|
||||
MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>");
|
||||
MODULE_DESCRIPTION("RTC driver for Gemini SoC");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
||||
struct gemini_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *rtc_base;
|
||||
int rtc_irq;
|
||||
};
|
||||
|
||||
enum gemini_rtc_offsets {
|
||||
GEMINI_RTC_SECOND = 0x00,
|
||||
GEMINI_RTC_MINUTE = 0x04,
|
||||
GEMINI_RTC_HOUR = 0x08,
|
||||
GEMINI_RTC_DAYS = 0x0C,
|
||||
GEMINI_RTC_ALARM_SECOND = 0x10,
|
||||
GEMINI_RTC_ALARM_MINUTE = 0x14,
|
||||
GEMINI_RTC_ALARM_HOUR = 0x18,
|
||||
GEMINI_RTC_RECORD = 0x1C,
|
||||
GEMINI_RTC_CR = 0x20
|
||||
};
|
||||
|
||||
static irqreturn_t gemini_rtc_interrupt(int irq, void *dev)
|
||||
{
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks like the RTC in the Gemini SoC is (totaly) broken
|
||||
* We can't read/write directly the time from RTC registers.
|
||||
* We must do some "offset" calculation to get the real time
|
||||
*
|
||||
* This FIX works pretty fine and Stormlinksemi aka Cortina-Networks does
|
||||
* the same thing, without the rtc-lib.c calls.
|
||||
*/
|
||||
|
||||
static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct gemini_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
unsigned int days, hour, min, sec;
|
||||
unsigned long offset, time;
|
||||
|
||||
sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
|
||||
min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
|
||||
hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
|
||||
days = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
|
||||
offset = readl(rtc->rtc_base + GEMINI_RTC_RECORD);
|
||||
|
||||
time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
|
||||
|
||||
rtc_time_to_tm(time, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct gemini_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int sec, min, hour, day;
|
||||
unsigned long offset, time;
|
||||
|
||||
if (tm->tm_year >= 2148) /* EPOCH Year + 179 */
|
||||
return -EINVAL;
|
||||
|
||||
rtc_tm_to_time(tm, &time);
|
||||
|
||||
sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
|
||||
min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
|
||||
hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
|
||||
day = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
|
||||
|
||||
offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);
|
||||
|
||||
writel(offset, rtc->rtc_base + GEMINI_RTC_RECORD);
|
||||
writel(0x01, rtc->rtc_base + GEMINI_RTC_CR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rtc_class_ops gemini_rtc_ops = {
|
||||
.read_time = gemini_rtc_read_time,
|
||||
.set_time = gemini_rtc_set_time,
|
||||
};
|
||||
|
||||
static int gemini_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gemini_rtc *rtc;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (unlikely(!rtc))
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
rtc->rtc_irq = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
rtc->rtc_base = devm_ioremap(dev, res->start,
|
||||
resource_size(res));
|
||||
|
||||
ret = devm_request_irq(dev, rtc->rtc_irq, gemini_rtc_interrupt,
|
||||
IRQF_SHARED, pdev->name, dev);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int gemini_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gemini_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
rtc_device_unregister(rtc->rtc_dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gemini_rtc_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
.probe = gemini_rtc_probe,
|
||||
.remove = gemini_rtc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver_probe(gemini_rtc_driver, gemini_rtc_probe);
|
|
@ -318,7 +318,7 @@ static int hid_time_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id hid_time_ids[] = {
|
||||
static const struct platform_device_id hid_time_ids[] = {
|
||||
{
|
||||
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
|
||||
.name = "HID-SENSOR-2000a0",
|
||||
|
|
|
@ -548,14 +548,16 @@ static int hym8563_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, hym8563_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
client->name, hym8563);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "irq %d request failed, %d\n",
|
||||
client->irq, ret);
|
||||
return ret;
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, hym8563_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
client->name, hym8563);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "irq %d request failed, %d\n",
|
||||
client->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* check state of calendar information */
|
||||
|
|
|
@ -129,6 +129,324 @@ struct imxdi_dev {
|
|||
struct work_struct work;
|
||||
};
|
||||
|
||||
/* Some background:
|
||||
*
|
||||
* The DryIce unit is a complex security/tamper monitor device. To be able do
|
||||
* its job in a useful manner it runs a bigger statemachine to bring it into
|
||||
* security/tamper failure state and once again to bring it out of this state.
|
||||
*
|
||||
* This unit can be in one of three states:
|
||||
*
|
||||
* - "NON-VALID STATE"
|
||||
* always after the battery power was removed
|
||||
* - "FAILURE STATE"
|
||||
* if one of the enabled security events has happened
|
||||
* - "VALID STATE"
|
||||
* if the unit works as expected
|
||||
*
|
||||
* Everything stops when the unit enters the failure state including the RTC
|
||||
* counter (to be able to detect the time the security event happened).
|
||||
*
|
||||
* The following events (when enabled) let the DryIce unit enter the failure
|
||||
* state:
|
||||
*
|
||||
* - wire-mesh-tamper detect
|
||||
* - external tamper B detect
|
||||
* - external tamper A detect
|
||||
* - temperature tamper detect
|
||||
* - clock tamper detect
|
||||
* - voltage tamper detect
|
||||
* - RTC counter overflow
|
||||
* - monotonic counter overflow
|
||||
* - external boot
|
||||
*
|
||||
* If we find the DryIce unit in "FAILURE STATE" and the TDCHL cleared, we
|
||||
* can only detect this state. In this case the unit is completely locked and
|
||||
* must force a second "SYSTEM POR" to bring the DryIce into the
|
||||
* "NON-VALID STATE" + "FAILURE STATE" where a recovery is possible.
|
||||
* If the TDCHL is set in the "FAILURE STATE" we are out of luck. In this case
|
||||
* a battery power cycle is required.
|
||||
*
|
||||
* In the "NON-VALID STATE" + "FAILURE STATE" we can clear the "FAILURE STATE"
|
||||
* and recover the DryIce unit. By clearing the "NON-VALID STATE" as the last
|
||||
* task, we bring back this unit into life.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Do a write into the unit without interrupt support.
|
||||
* We do not need to check the WEF here, because the only reason this kind of
|
||||
* write error can happen is if we write to the unit twice within the 122 us
|
||||
* interval. This cannot happen, since we are using this function only while
|
||||
* setting up the unit.
|
||||
*/
|
||||
static void di_write_busy_wait(const struct imxdi_dev *imxdi, u32 val,
|
||||
unsigned reg)
|
||||
{
|
||||
/* do the register write */
|
||||
writel(val, imxdi->ioaddr + reg);
|
||||
|
||||
/*
|
||||
* now it takes four 32,768 kHz clock cycles to take
|
||||
* the change into effect = 122 us
|
||||
*/
|
||||
usleep_range(130, 200);
|
||||
}
|
||||
|
||||
static void di_report_tamper_info(struct imxdi_dev *imxdi, u32 dsr)
|
||||
{
|
||||
u32 dtcr;
|
||||
|
||||
dtcr = readl(imxdi->ioaddr + DTCR);
|
||||
|
||||
dev_emerg(&imxdi->pdev->dev, "DryIce tamper event detected\n");
|
||||
/* the following flags force a transition into the "FAILURE STATE" */
|
||||
if (dsr & DSR_VTD)
|
||||
dev_emerg(&imxdi->pdev->dev, "%sVoltage Tamper Event\n",
|
||||
dtcr & DTCR_VTE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_CTD)
|
||||
dev_emerg(&imxdi->pdev->dev, "%s32768 Hz Clock Tamper Event\n",
|
||||
dtcr & DTCR_CTE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_TTD)
|
||||
dev_emerg(&imxdi->pdev->dev, "%sTemperature Tamper Event\n",
|
||||
dtcr & DTCR_TTE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_SAD)
|
||||
dev_emerg(&imxdi->pdev->dev,
|
||||
"%sSecure Controller Alarm Event\n",
|
||||
dtcr & DTCR_SAIE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_EBD)
|
||||
dev_emerg(&imxdi->pdev->dev, "%sExternal Boot Tamper Event\n",
|
||||
dtcr & DTCR_EBE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_ETAD)
|
||||
dev_emerg(&imxdi->pdev->dev, "%sExternal Tamper A Event\n",
|
||||
dtcr & DTCR_ETAE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_ETBD)
|
||||
dev_emerg(&imxdi->pdev->dev, "%sExternal Tamper B Event\n",
|
||||
dtcr & DTCR_ETBE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_WTD)
|
||||
dev_emerg(&imxdi->pdev->dev, "%sWire-mesh Tamper Event\n",
|
||||
dtcr & DTCR_WTE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_MCO)
|
||||
dev_emerg(&imxdi->pdev->dev,
|
||||
"%sMonotonic-counter Overflow Event\n",
|
||||
dtcr & DTCR_MOE ? "" : "Spurious ");
|
||||
|
||||
if (dsr & DSR_TCO)
|
||||
dev_emerg(&imxdi->pdev->dev, "%sTimer-counter Overflow Event\n",
|
||||
dtcr & DTCR_TOE ? "" : "Spurious ");
|
||||
}
|
||||
|
||||
static void di_what_is_to_be_done(struct imxdi_dev *imxdi,
|
||||
const char *power_supply)
|
||||
{
|
||||
dev_emerg(&imxdi->pdev->dev, "Please cycle the %s power supply in order to get the DryIce/RTC unit working again\n",
|
||||
power_supply);
|
||||
}
|
||||
|
||||
static int di_handle_failure_state(struct imxdi_dev *imxdi, u32 dsr)
|
||||
{
|
||||
u32 dcr;
|
||||
|
||||
dev_dbg(&imxdi->pdev->dev, "DSR register reports: %08X\n", dsr);
|
||||
|
||||
/* report the cause */
|
||||
di_report_tamper_info(imxdi, dsr);
|
||||
|
||||
dcr = readl(imxdi->ioaddr + DCR);
|
||||
|
||||
if (dcr & DCR_FSHL) {
|
||||
/* we are out of luck */
|
||||
di_what_is_to_be_done(imxdi, "battery");
|
||||
return -ENODEV;
|
||||
}
|
||||
/*
|
||||
* with the next SYSTEM POR we will transit from the "FAILURE STATE"
|
||||
* into the "NON-VALID STATE" + "FAILURE STATE"
|
||||
*/
|
||||
di_what_is_to_be_done(imxdi, "main");
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int di_handle_valid_state(struct imxdi_dev *imxdi, u32 dsr)
|
||||
{
|
||||
/* initialize alarm */
|
||||
di_write_busy_wait(imxdi, DCAMR_UNSET, DCAMR);
|
||||
di_write_busy_wait(imxdi, 0, DCALR);
|
||||
|
||||
/* clear alarm flag */
|
||||
if (dsr & DSR_CAF)
|
||||
di_write_busy_wait(imxdi, DSR_CAF, DSR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int di_handle_invalid_state(struct imxdi_dev *imxdi, u32 dsr)
|
||||
{
|
||||
u32 dcr, sec;
|
||||
|
||||
/*
|
||||
* lets disable all sources which can force the DryIce unit into
|
||||
* the "FAILURE STATE" for now
|
||||
*/
|
||||
di_write_busy_wait(imxdi, 0x00000000, DTCR);
|
||||
/* and lets protect them at runtime from any change */
|
||||
di_write_busy_wait(imxdi, DCR_TDCSL, DCR);
|
||||
|
||||
sec = readl(imxdi->ioaddr + DTCMR);
|
||||
if (sec != 0)
|
||||
dev_warn(&imxdi->pdev->dev,
|
||||
"The security violation has happend at %u seconds\n",
|
||||
sec);
|
||||
/*
|
||||
* the timer cannot be set/modified if
|
||||
* - the TCHL or TCSL bit is set in DCR
|
||||
*/
|
||||
dcr = readl(imxdi->ioaddr + DCR);
|
||||
if (!(dcr & DCR_TCE)) {
|
||||
if (dcr & DCR_TCHL) {
|
||||
/* we are out of luck */
|
||||
di_what_is_to_be_done(imxdi, "battery");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (dcr & DCR_TCSL) {
|
||||
di_what_is_to_be_done(imxdi, "main");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* - the timer counter stops/is stopped if
|
||||
* - its overflow flag is set (TCO in DSR)
|
||||
* -> clear overflow bit to make it count again
|
||||
* - NVF is set in DSR
|
||||
* -> clear non-valid bit to make it count again
|
||||
* - its TCE (DCR) is cleared
|
||||
* -> set TCE to make it count
|
||||
* - it was never set before
|
||||
* -> write a time into it (required again if the NVF was set)
|
||||
*/
|
||||
/* state handled */
|
||||
di_write_busy_wait(imxdi, DSR_NVF, DSR);
|
||||
/* clear overflow flag */
|
||||
di_write_busy_wait(imxdi, DSR_TCO, DSR);
|
||||
/* enable the counter */
|
||||
di_write_busy_wait(imxdi, dcr | DCR_TCE, DCR);
|
||||
/* set and trigger it to make it count */
|
||||
di_write_busy_wait(imxdi, sec, DTCMR);
|
||||
|
||||
/* now prepare for the valid state */
|
||||
return di_handle_valid_state(imxdi, __raw_readl(imxdi->ioaddr + DSR));
|
||||
}
|
||||
|
||||
static int di_handle_invalid_and_failure_state(struct imxdi_dev *imxdi, u32 dsr)
|
||||
{
|
||||
u32 dcr;
|
||||
|
||||
/*
|
||||
* now we must first remove the tamper sources in order to get the
|
||||
* device out of the "FAILURE STATE"
|
||||
* To disable any of the following sources we need to modify the DTCR
|
||||
*/
|
||||
if (dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD | DSR_EBD | DSR_SAD |
|
||||
DSR_TTD | DSR_CTD | DSR_VTD | DSR_MCO | DSR_TCO)) {
|
||||
dcr = __raw_readl(imxdi->ioaddr + DCR);
|
||||
if (dcr & DCR_TDCHL) {
|
||||
/*
|
||||
* the tamper register is locked. We cannot disable the
|
||||
* tamper detection. The TDCHL can only be reset by a
|
||||
* DRYICE POR, but we cannot force a DRYICE POR in
|
||||
* softwere because we are still in "FAILURE STATE".
|
||||
* We need a DRYICE POR via battery power cycling....
|
||||
*/
|
||||
/*
|
||||
* out of luck!
|
||||
* we cannot disable them without a DRYICE POR
|
||||
*/
|
||||
di_what_is_to_be_done(imxdi, "battery");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (dcr & DCR_TDCSL) {
|
||||
/* a soft lock can be removed by a SYSTEM POR */
|
||||
di_what_is_to_be_done(imxdi, "main");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable all sources */
|
||||
di_write_busy_wait(imxdi, 0x00000000, DTCR);
|
||||
|
||||
/* clear the status bits now */
|
||||
di_write_busy_wait(imxdi, dsr & (DSR_WTD | DSR_ETBD | DSR_ETAD |
|
||||
DSR_EBD | DSR_SAD | DSR_TTD | DSR_CTD | DSR_VTD |
|
||||
DSR_MCO | DSR_TCO), DSR);
|
||||
|
||||
dsr = readl(imxdi->ioaddr + DSR);
|
||||
if ((dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF |
|
||||
DSR_WCF | DSR_WEF)) != 0)
|
||||
dev_warn(&imxdi->pdev->dev,
|
||||
"There are still some sources of pain in DSR: %08x!\n",
|
||||
dsr & ~(DSR_NVF | DSR_SVF | DSR_WBF | DSR_WNF |
|
||||
DSR_WCF | DSR_WEF));
|
||||
|
||||
/*
|
||||
* now we are trying to clear the "Security-violation flag" to
|
||||
* get the DryIce out of this state
|
||||
*/
|
||||
di_write_busy_wait(imxdi, DSR_SVF, DSR);
|
||||
|
||||
/* success? */
|
||||
dsr = readl(imxdi->ioaddr + DSR);
|
||||
if (dsr & DSR_SVF) {
|
||||
dev_crit(&imxdi->pdev->dev,
|
||||
"Cannot clear the security violation flag. We are ending up in an endless loop!\n");
|
||||
/* last resort */
|
||||
di_what_is_to_be_done(imxdi, "battery");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* now we have left the "FAILURE STATE" and ending up in the
|
||||
* "NON-VALID STATE" time to recover everything
|
||||
*/
|
||||
return di_handle_invalid_state(imxdi, dsr);
|
||||
}
|
||||
|
||||
static int di_handle_state(struct imxdi_dev *imxdi)
|
||||
{
|
||||
int rc;
|
||||
u32 dsr;
|
||||
|
||||
dsr = readl(imxdi->ioaddr + DSR);
|
||||
|
||||
switch (dsr & (DSR_NVF | DSR_SVF)) {
|
||||
case DSR_NVF:
|
||||
dev_warn(&imxdi->pdev->dev, "Invalid stated unit detected\n");
|
||||
rc = di_handle_invalid_state(imxdi, dsr);
|
||||
break;
|
||||
case DSR_SVF:
|
||||
dev_warn(&imxdi->pdev->dev, "Failure stated unit detected\n");
|
||||
rc = di_handle_failure_state(imxdi, dsr);
|
||||
break;
|
||||
case DSR_NVF | DSR_SVF:
|
||||
dev_warn(&imxdi->pdev->dev,
|
||||
"Failure+Invalid stated unit detected\n");
|
||||
rc = di_handle_invalid_and_failure_state(imxdi, dsr);
|
||||
break;
|
||||
default:
|
||||
dev_notice(&imxdi->pdev->dev, "Unlocked unit detected\n");
|
||||
rc = di_handle_valid_state(imxdi, dsr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* enable a dryice interrupt
|
||||
*/
|
||||
|
@ -137,8 +455,8 @@ static void di_int_enable(struct imxdi_dev *imxdi, u32 intr)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&imxdi->irq_lock, flags);
|
||||
__raw_writel(__raw_readl(imxdi->ioaddr + DIER) | intr,
|
||||
imxdi->ioaddr + DIER);
|
||||
writel(readl(imxdi->ioaddr + DIER) | intr,
|
||||
imxdi->ioaddr + DIER);
|
||||
spin_unlock_irqrestore(&imxdi->irq_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -150,8 +468,8 @@ static void di_int_disable(struct imxdi_dev *imxdi, u32 intr)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&imxdi->irq_lock, flags);
|
||||
__raw_writel(__raw_readl(imxdi->ioaddr + DIER) & ~intr,
|
||||
imxdi->ioaddr + DIER);
|
||||
writel(readl(imxdi->ioaddr + DIER) & ~intr,
|
||||
imxdi->ioaddr + DIER);
|
||||
spin_unlock_irqrestore(&imxdi->irq_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -169,11 +487,11 @@ static void clear_write_error(struct imxdi_dev *imxdi)
|
|||
dev_warn(&imxdi->pdev->dev, "WARNING: Register write error!\n");
|
||||
|
||||
/* clear the write error flag */
|
||||
__raw_writel(DSR_WEF, imxdi->ioaddr + DSR);
|
||||
writel(DSR_WEF, imxdi->ioaddr + DSR);
|
||||
|
||||
/* wait for it to take effect */
|
||||
for (cnt = 0; cnt < 1000; cnt++) {
|
||||
if ((__raw_readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0)
|
||||
if ((readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0)
|
||||
return;
|
||||
udelay(10);
|
||||
}
|
||||
|
@ -201,7 +519,7 @@ static int di_write_wait(struct imxdi_dev *imxdi, u32 val, int reg)
|
|||
imxdi->dsr = 0;
|
||||
|
||||
/* do the register write */
|
||||
__raw_writel(val, imxdi->ioaddr + reg);
|
||||
writel(val, imxdi->ioaddr + reg);
|
||||
|
||||
/* wait for the write to finish */
|
||||
ret = wait_event_interruptible_timeout(imxdi->write_wait,
|
||||
|
@ -235,7 +553,7 @@ static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
struct imxdi_dev *imxdi = dev_get_drvdata(dev);
|
||||
unsigned long now;
|
||||
|
||||
now = __raw_readl(imxdi->ioaddr + DTCMR);
|
||||
now = readl(imxdi->ioaddr + DTCMR);
|
||||
rtc_time_to_tm(now, tm);
|
||||
|
||||
return 0;
|
||||
|
@ -248,14 +566,35 @@ static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
static int dryice_rtc_set_mmss(struct device *dev, unsigned long secs)
|
||||
{
|
||||
struct imxdi_dev *imxdi = dev_get_drvdata(dev);
|
||||
u32 dcr, dsr;
|
||||
int rc;
|
||||
|
||||
dcr = readl(imxdi->ioaddr + DCR);
|
||||
dsr = readl(imxdi->ioaddr + DSR);
|
||||
|
||||
if (!(dcr & DCR_TCE) || (dsr & DSR_SVF)) {
|
||||
if (dcr & DCR_TCHL) {
|
||||
/* we are even more out of luck */
|
||||
di_what_is_to_be_done(imxdi, "battery");
|
||||
return -EPERM;
|
||||
}
|
||||
if ((dcr & DCR_TCSL) || (dsr & DSR_SVF)) {
|
||||
/* we are out of luck for now */
|
||||
di_what_is_to_be_done(imxdi, "main");
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
/* zero the fractional part first */
|
||||
rc = di_write_wait(imxdi, 0, DTCLR);
|
||||
if (rc == 0)
|
||||
rc = di_write_wait(imxdi, secs, DTCMR);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
return rc;
|
||||
rc = di_write_wait(imxdi, secs, DTCMR);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
return di_write_wait(imxdi, readl(imxdi->ioaddr + DCR) | DCR_TCE, DCR);
|
||||
}
|
||||
|
||||
static int dryice_rtc_alarm_irq_enable(struct device *dev,
|
||||
|
@ -280,17 +619,17 @@ static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
struct imxdi_dev *imxdi = dev_get_drvdata(dev);
|
||||
u32 dcamr;
|
||||
|
||||
dcamr = __raw_readl(imxdi->ioaddr + DCAMR);
|
||||
dcamr = readl(imxdi->ioaddr + DCAMR);
|
||||
rtc_time_to_tm(dcamr, &alarm->time);
|
||||
|
||||
/* alarm is enabled if the interrupt is enabled */
|
||||
alarm->enabled = (__raw_readl(imxdi->ioaddr + DIER) & DIER_CAIE) != 0;
|
||||
alarm->enabled = (readl(imxdi->ioaddr + DIER) & DIER_CAIE) != 0;
|
||||
|
||||
/* don't allow the DSR read to mess up DSR_WCF */
|
||||
mutex_lock(&imxdi->write_mutex);
|
||||
|
||||
/* alarm is pending if the alarm flag is set */
|
||||
alarm->pending = (__raw_readl(imxdi->ioaddr + DSR) & DSR_CAF) != 0;
|
||||
alarm->pending = (readl(imxdi->ioaddr + DSR) & DSR_CAF) != 0;
|
||||
|
||||
mutex_unlock(&imxdi->write_mutex);
|
||||
|
||||
|
@ -312,7 +651,7 @@ static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
return rc;
|
||||
|
||||
/* don't allow setting alarm in the past */
|
||||
now = __raw_readl(imxdi->ioaddr + DTCMR);
|
||||
now = readl(imxdi->ioaddr + DTCMR);
|
||||
if (alarm_time < now)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -346,7 +685,26 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
|
|||
u32 dsr, dier;
|
||||
irqreturn_t rc = IRQ_NONE;
|
||||
|
||||
dier = __raw_readl(imxdi->ioaddr + DIER);
|
||||
dier = readl(imxdi->ioaddr + DIER);
|
||||
dsr = readl(imxdi->ioaddr + DSR);
|
||||
|
||||
/* handle the security violation event */
|
||||
if (dier & DIER_SVIE) {
|
||||
if (dsr & DSR_SVF) {
|
||||
/*
|
||||
* Disable the interrupt when this kind of event has
|
||||
* happened.
|
||||
* There cannot be more than one event of this type,
|
||||
* because it needs a complex state change
|
||||
* including a main power cycle to get again out of
|
||||
* this state.
|
||||
*/
|
||||
di_int_disable(imxdi, DIER_SVIE);
|
||||
/* report the violation */
|
||||
di_report_tamper_info(imxdi, dsr);
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle write complete and write error cases */
|
||||
if (dier & DIER_WCIE) {
|
||||
|
@ -357,7 +715,6 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
|
|||
return rc;
|
||||
|
||||
/* DSR_WCF clears itself on DSR read */
|
||||
dsr = __raw_readl(imxdi->ioaddr + DSR);
|
||||
if (dsr & (DSR_WCF | DSR_WEF)) {
|
||||
/* mask the interrupt */
|
||||
di_int_disable(imxdi, DIER_WCIE);
|
||||
|
@ -373,7 +730,6 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
|
|||
/* handle the alarm case */
|
||||
if (dier & DIER_CAIE) {
|
||||
/* DSR_WCF clears itself on DSR read */
|
||||
dsr = __raw_readl(imxdi->ioaddr + DSR);
|
||||
if (dsr & DSR_CAF) {
|
||||
/* mask the interrupt */
|
||||
di_int_disable(imxdi, DIER_CAIE);
|
||||
|
@ -446,7 +802,11 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
|
|||
*/
|
||||
|
||||
/* mask all interrupts */
|
||||
__raw_writel(0, imxdi->ioaddr + DIER);
|
||||
writel(0, imxdi->ioaddr + DIER);
|
||||
|
||||
rc = di_handle_state(imxdi);
|
||||
if (rc != 0)
|
||||
goto err;
|
||||
|
||||
rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq,
|
||||
IRQF_SHARED, pdev->name, imxdi);
|
||||
|
@ -455,44 +815,6 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* put dryice into valid state */
|
||||
if (__raw_readl(imxdi->ioaddr + DSR) & DSR_NVF) {
|
||||
rc = di_write_wait(imxdi, DSR_NVF | DSR_SVF, DSR);
|
||||
if (rc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* initialize alarm */
|
||||
rc = di_write_wait(imxdi, DCAMR_UNSET, DCAMR);
|
||||
if (rc)
|
||||
goto err;
|
||||
rc = di_write_wait(imxdi, 0, DCALR);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
/* clear alarm flag */
|
||||
if (__raw_readl(imxdi->ioaddr + DSR) & DSR_CAF) {
|
||||
rc = di_write_wait(imxdi, DSR_CAF, DSR);
|
||||
if (rc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* the timer won't count if it has never been written to */
|
||||
if (__raw_readl(imxdi->ioaddr + DTCMR) == 0) {
|
||||
rc = di_write_wait(imxdi, 0, DTCMR);
|
||||
if (rc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* start keeping time */
|
||||
if (!(__raw_readl(imxdi->ioaddr + DCR) & DCR_TCE)) {
|
||||
rc = di_write_wait(imxdi,
|
||||
__raw_readl(imxdi->ioaddr + DCR) | DCR_TCE,
|
||||
DCR);
|
||||
if (rc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, imxdi);
|
||||
imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&dryice_rtc_ops, THIS_MODULE);
|
||||
|
@ -516,7 +838,7 @@ static int __exit dryice_rtc_remove(struct platform_device *pdev)
|
|||
flush_work(&imxdi->work);
|
||||
|
||||
/* mask all interrupts */
|
||||
__raw_writel(0, imxdi->ioaddr + DIER);
|
||||
writel(0, imxdi->ioaddr + DIER);
|
||||
|
||||
clk_disable_unprepare(imxdi->clk);
|
||||
|
||||
|
|
|
@ -370,22 +370,15 @@ isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
|
|||
struct rtc_time *alarm_tm = &alarm->time;
|
||||
u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
|
||||
const int offs = ISL1208_REG_SCA;
|
||||
unsigned long rtc_secs, alarm_secs;
|
||||
struct rtc_time rtc_tm;
|
||||
int err, enable;
|
||||
|
||||
err = isl1208_i2c_read_time(client, &rtc_tm);
|
||||
if (err)
|
||||
return err;
|
||||
err = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (err)
|
||||
return err;
|
||||
err = rtc_tm_to_time(alarm_tm, &alarm_secs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* If the alarm time is before the current time disable the alarm */
|
||||
if (!alarm->enabled || alarm_secs <= rtc_secs)
|
||||
if (!alarm->enabled || rtc_tm_sub(alarm_tm, &rtc_tm) <= 0)
|
||||
enable = 0x00;
|
||||
else
|
||||
enable = 0x80;
|
||||
|
|
|
@ -234,6 +234,7 @@ static struct i2c_device_id max6900_id[] = {
|
|||
{ "max6900", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max6900_id);
|
||||
|
||||
static struct i2c_driver max6900_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -511,6 +511,7 @@ static const struct platform_device_id rtc_id[] = {
|
|||
{ "max77686-rtc", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, rtc_id);
|
||||
|
||||
static struct platform_driver max77686_rtc_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -484,6 +484,7 @@ static const struct platform_device_id rtc_id[] = {
|
|||
{ "max77802-rtc", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, rtc_id);
|
||||
|
||||
static struct platform_driver max77802_rtc_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -309,6 +309,7 @@ static const struct platform_device_id max8998_rtc_id[] = {
|
|||
{ "lp3974-rtc", TYPE_LP3974 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max8998_rtc_id);
|
||||
|
||||
static struct platform_driver max8998_rtc_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -216,7 +216,7 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
|||
|
||||
s1970 = rtc_tm_to_time64(&alarm->time);
|
||||
|
||||
dev_dbg(dev, "%s: o%2.s %lld\n", __func__, alarm->enabled ? "n" : "ff",
|
||||
dev_dbg(dev, "%s: %s %lld\n", __func__, alarm->enabled ? "on" : "off",
|
||||
(long long)s1970);
|
||||
|
||||
ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled,
|
||||
|
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 MediaTek Inc.
|
||||
* Author: Tianping.Fang <tianping.fang@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that 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.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/mt6397/core.h>
|
||||
|
||||
#define RTC_BBPU 0x0000
|
||||
#define RTC_BBPU_CBUSY BIT(6)
|
||||
|
||||
#define RTC_WRTGR 0x003c
|
||||
|
||||
#define RTC_IRQ_STA 0x0002
|
||||
#define RTC_IRQ_STA_AL BIT(0)
|
||||
#define RTC_IRQ_STA_LP BIT(3)
|
||||
|
||||
#define RTC_IRQ_EN 0x0004
|
||||
#define RTC_IRQ_EN_AL BIT(0)
|
||||
#define RTC_IRQ_EN_ONESHOT BIT(2)
|
||||
#define RTC_IRQ_EN_LP BIT(3)
|
||||
#define RTC_IRQ_EN_ONESHOT_AL (RTC_IRQ_EN_ONESHOT | RTC_IRQ_EN_AL)
|
||||
|
||||
#define RTC_AL_MASK 0x0008
|
||||
#define RTC_AL_MASK_DOW BIT(4)
|
||||
|
||||
#define RTC_TC_SEC 0x000a
|
||||
/* Min, Hour, Dom... register offset to RTC_TC_SEC */
|
||||
#define RTC_OFFSET_SEC 0
|
||||
#define RTC_OFFSET_MIN 1
|
||||
#define RTC_OFFSET_HOUR 2
|
||||
#define RTC_OFFSET_DOM 3
|
||||
#define RTC_OFFSET_DOW 4
|
||||
#define RTC_OFFSET_MTH 5
|
||||
#define RTC_OFFSET_YEAR 6
|
||||
#define RTC_OFFSET_COUNT 7
|
||||
|
||||
#define RTC_AL_SEC 0x0018
|
||||
|
||||
#define RTC_PDN2 0x002e
|
||||
#define RTC_PDN2_PWRON_ALARM BIT(4)
|
||||
|
||||
#define RTC_MIN_YEAR 1968
|
||||
#define RTC_BASE_YEAR 1900
|
||||
#define RTC_NUM_YEARS 128
|
||||
#define RTC_MIN_YEAR_OFFSET (RTC_MIN_YEAR - RTC_BASE_YEAR)
|
||||
|
||||
struct mt6397_rtc {
|
||||
struct device *dev;
|
||||
struct rtc_device *rtc_dev;
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
int irq;
|
||||
u32 addr_base;
|
||||
};
|
||||
|
||||
static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc)
|
||||
{
|
||||
unsigned long timeout = jiffies + HZ;
|
||||
int ret;
|
||||
u32 data;
|
||||
|
||||
ret = regmap_write(rtc->regmap, rtc->addr_base + RTC_WRTGR, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
while (1) {
|
||||
ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_BBPU,
|
||||
&data);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (!(data & RTC_BBPU_CBUSY))
|
||||
break;
|
||||
if (time_after(jiffies, timeout)) {
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t mtk_rtc_irq_handler_thread(int irq, void *data)
|
||||
{
|
||||
struct mt6397_rtc *rtc = data;
|
||||
u32 irqsta, irqen;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_IRQ_STA, &irqsta);
|
||||
if ((ret >= 0) && (irqsta & RTC_IRQ_STA_AL)) {
|
||||
rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
|
||||
irqen = irqsta & ~RTC_IRQ_EN_AL;
|
||||
mutex_lock(&rtc->lock);
|
||||
if (regmap_write(rtc->regmap, rtc->addr_base + RTC_IRQ_EN,
|
||||
irqen) < 0)
|
||||
mtk_rtc_write_trigger(rtc);
|
||||
mutex_unlock(&rtc->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int __mtk_rtc_read_time(struct mt6397_rtc *rtc,
|
||||
struct rtc_time *tm, int *sec)
|
||||
{
|
||||
int ret;
|
||||
u16 data[RTC_OFFSET_COUNT];
|
||||
|
||||
mutex_lock(&rtc->lock);
|
||||
ret = regmap_bulk_read(rtc->regmap, rtc->addr_base + RTC_TC_SEC,
|
||||
data, RTC_OFFSET_COUNT);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
tm->tm_sec = data[RTC_OFFSET_SEC];
|
||||
tm->tm_min = data[RTC_OFFSET_MIN];
|
||||
tm->tm_hour = data[RTC_OFFSET_HOUR];
|
||||
tm->tm_mday = data[RTC_OFFSET_DOM];
|
||||
tm->tm_mon = data[RTC_OFFSET_MTH];
|
||||
tm->tm_year = data[RTC_OFFSET_YEAR];
|
||||
|
||||
ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_TC_SEC, sec);
|
||||
exit:
|
||||
mutex_unlock(&rtc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
time64_t time;
|
||||
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
|
||||
int days, sec, ret;
|
||||
|
||||
do {
|
||||
ret = __mtk_rtc_read_time(rtc, tm, &sec);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
} while (sec < tm->tm_sec);
|
||||
|
||||
/* HW register use 7 bits to store year data, minus
|
||||
* RTC_MIN_YEAR_OFFSET before write year data to register, and plus
|
||||
* RTC_MIN_YEAR_OFFSET back after read year from register
|
||||
*/
|
||||
tm->tm_year += RTC_MIN_YEAR_OFFSET;
|
||||
|
||||
/* HW register start mon from one, but tm_mon start from zero. */
|
||||
tm->tm_mon--;
|
||||
time = rtc_tm_to_time64(tm);
|
||||
|
||||
/* rtc_tm_to_time64 covert Gregorian date to seconds since
|
||||
* 01-01-1970 00:00:00, and this date is Thursday.
|
||||
*/
|
||||
days = div_s64(time, 86400);
|
||||
tm->tm_wday = (days + 4) % 7;
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
u16 data[RTC_OFFSET_COUNT];
|
||||
|
||||
tm->tm_year -= RTC_MIN_YEAR_OFFSET;
|
||||
tm->tm_mon++;
|
||||
|
||||
data[RTC_OFFSET_SEC] = tm->tm_sec;
|
||||
data[RTC_OFFSET_MIN] = tm->tm_min;
|
||||
data[RTC_OFFSET_HOUR] = tm->tm_hour;
|
||||
data[RTC_OFFSET_DOM] = tm->tm_mday;
|
||||
data[RTC_OFFSET_MTH] = tm->tm_mon;
|
||||
data[RTC_OFFSET_YEAR] = tm->tm_year;
|
||||
|
||||
mutex_lock(&rtc->lock);
|
||||
ret = regmap_bulk_write(rtc->regmap, rtc->addr_base + RTC_TC_SEC,
|
||||
data, RTC_OFFSET_COUNT);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
/* Time register write to hardware after call trigger function */
|
||||
ret = mtk_rtc_write_trigger(rtc);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&rtc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct rtc_time *tm = &alm->time;
|
||||
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
|
||||
u32 irqen, pdn2;
|
||||
int ret;
|
||||
u16 data[RTC_OFFSET_COUNT];
|
||||
|
||||
mutex_lock(&rtc->lock);
|
||||
ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_IRQ_EN, &irqen);
|
||||
if (ret < 0)
|
||||
goto err_exit;
|
||||
ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_PDN2, &pdn2);
|
||||
if (ret < 0)
|
||||
goto err_exit;
|
||||
|
||||
ret = regmap_bulk_read(rtc->regmap, rtc->addr_base + RTC_AL_SEC,
|
||||
data, RTC_OFFSET_COUNT);
|
||||
if (ret < 0)
|
||||
goto err_exit;
|
||||
|
||||
alm->enabled = !!(irqen & RTC_IRQ_EN_AL);
|
||||
alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM);
|
||||
mutex_unlock(&rtc->lock);
|
||||
|
||||
tm->tm_sec = data[RTC_OFFSET_SEC];
|
||||
tm->tm_min = data[RTC_OFFSET_MIN];
|
||||
tm->tm_hour = data[RTC_OFFSET_HOUR];
|
||||
tm->tm_mday = data[RTC_OFFSET_DOM];
|
||||
tm->tm_mon = data[RTC_OFFSET_MTH];
|
||||
tm->tm_year = data[RTC_OFFSET_YEAR];
|
||||
|
||||
tm->tm_year += RTC_MIN_YEAR_OFFSET;
|
||||
tm->tm_mon--;
|
||||
|
||||
return 0;
|
||||
err_exit:
|
||||
mutex_unlock(&rtc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
{
|
||||
struct rtc_time *tm = &alm->time;
|
||||
struct mt6397_rtc *rtc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
u16 data[RTC_OFFSET_COUNT];
|
||||
|
||||
tm->tm_year -= RTC_MIN_YEAR_OFFSET;
|
||||
tm->tm_mon++;
|
||||
|
||||
data[RTC_OFFSET_SEC] = tm->tm_sec;
|
||||
data[RTC_OFFSET_MIN] = tm->tm_min;
|
||||
data[RTC_OFFSET_HOUR] = tm->tm_hour;
|
||||
data[RTC_OFFSET_DOM] = tm->tm_mday;
|
||||
data[RTC_OFFSET_MTH] = tm->tm_mon;
|
||||
data[RTC_OFFSET_YEAR] = tm->tm_year;
|
||||
|
||||
mutex_lock(&rtc->lock);
|
||||
if (alm->enabled) {
|
||||
ret = regmap_bulk_write(rtc->regmap,
|
||||
rtc->addr_base + RTC_AL_SEC,
|
||||
data, RTC_OFFSET_COUNT);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
ret = regmap_write(rtc->regmap, rtc->addr_base + RTC_AL_MASK,
|
||||
RTC_AL_MASK_DOW);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
rtc->addr_base + RTC_IRQ_EN,
|
||||
RTC_IRQ_EN_ONESHOT_AL,
|
||||
RTC_IRQ_EN_ONESHOT_AL);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
} else {
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
rtc->addr_base + RTC_IRQ_EN,
|
||||
RTC_IRQ_EN_ONESHOT_AL, 0);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* All alarm time register write to hardware after calling
|
||||
* mtk_rtc_write_trigger. This can avoid race condition if alarm
|
||||
* occur happen during writing alarm time register.
|
||||
*/
|
||||
ret = mtk_rtc_write_trigger(rtc);
|
||||
exit:
|
||||
mutex_unlock(&rtc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct rtc_class_ops mtk_rtc_ops = {
|
||||
.read_time = mtk_rtc_read_time,
|
||||
.set_time = mtk_rtc_set_time,
|
||||
.read_alarm = mtk_rtc_read_alarm,
|
||||
.set_alarm = mtk_rtc_set_alarm,
|
||||
};
|
||||
|
||||
static int mtk_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct mt6397_rtc *rtc;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(struct mt6397_rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rtc->addr_base = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
rtc->irq = irq_create_mapping(mt6397_chip->irq_domain, res->start);
|
||||
if (rtc->irq <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
rtc->regmap = mt6397_chip->regmap;
|
||||
rtc->dev = &pdev->dev;
|
||||
mutex_init(&rtc->lock);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
ret = request_threaded_irq(rtc->irq, NULL,
|
||||
mtk_rtc_irq_handler_thread,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
|
||||
"mt6397-rtc", rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
|
||||
rtc->irq, ret);
|
||||
goto out_dispose_irq;
|
||||
}
|
||||
|
||||
rtc->rtc_dev = rtc_device_register("mt6397-rtc", &pdev->dev,
|
||||
&mtk_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc_dev)) {
|
||||
dev_err(&pdev->dev, "register rtc device failed\n");
|
||||
ret = PTR_ERR(rtc->rtc_dev);
|
||||
goto out_free_irq;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_irq:
|
||||
free_irq(rtc->irq, rtc->rtc_dev);
|
||||
out_dispose_irq:
|
||||
irq_dispose_mapping(rtc->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mt6397_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
rtc_device_unregister(rtc->rtc_dev);
|
||||
free_irq(rtc->irq, rtc->rtc_dev);
|
||||
irq_dispose_mapping(rtc->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mt6397_rtc_of_match[] = {
|
||||
{ .compatible = "mediatek,mt6397-rtc", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver mtk_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "mt6397-rtc",
|
||||
.of_match_table = mt6397_rtc_of_match,
|
||||
},
|
||||
.probe = mtk_rtc_probe,
|
||||
.remove = mtk_rtc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(mtk_rtc_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Tianping Fang <tianping.fang@mediatek.com>");
|
||||
MODULE_DESCRIPTION("RTC Driver for MediaTek MT6397 PMIC");
|
||||
MODULE_ALIAS("platform:mt6397-rtc");
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -24,7 +25,7 @@
|
|||
#define RTC_MINUTES_OFFS 8
|
||||
#define RTC_HOURS_OFFS 16
|
||||
#define RTC_WDAY_OFFS 24
|
||||
#define RTC_HOURS_12H_MODE (1 << 22) /* 12 hours mode */
|
||||
#define RTC_HOURS_12H_MODE BIT(22) /* 12 hour mode */
|
||||
|
||||
#define RTC_DATE_REG_OFFS 4
|
||||
#define RTC_MDAY_OFFS 0
|
||||
|
@ -33,7 +34,7 @@
|
|||
|
||||
#define RTC_ALARM_TIME_REG_OFFS 8
|
||||
#define RTC_ALARM_DATE_REG_OFFS 0xc
|
||||
#define RTC_ALARM_VALID (1 << 7)
|
||||
#define RTC_ALARM_VALID BIT(7)
|
||||
|
||||
#define RTC_ALARM_INTERRUPT_MASK_REG_OFFS 0x10
|
||||
#define RTC_ALARM_INTERRUPT_CASUE_REG_OFFS 0x14
|
||||
|
@ -77,7 +78,7 @@ static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
|||
|
||||
second = rtc_time & 0x7f;
|
||||
minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f;
|
||||
hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */
|
||||
hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hour mode */
|
||||
wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7;
|
||||
|
||||
day = rtc_date & 0x3f;
|
||||
|
@ -108,7 +109,7 @@ static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|||
|
||||
second = rtc_time & 0x7f;
|
||||
minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f;
|
||||
hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */
|
||||
hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hour mode */
|
||||
wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7;
|
||||
|
||||
day = rtc_date & 0x3f;
|
||||
|
@ -239,10 +240,10 @@ static int __init mv_rtc_probe(struct platform_device *pdev)
|
|||
if (!IS_ERR(pdata->clk))
|
||||
clk_prepare_enable(pdata->clk);
|
||||
|
||||
/* make sure the 24 hours mode is enabled */
|
||||
/* make sure the 24 hour mode is enabled */
|
||||
rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
|
||||
if (rtc_time & RTC_HOURS_12H_MODE) {
|
||||
dev_err(&pdev->dev, "24 Hours mode not supported.\n");
|
||||
dev_err(&pdev->dev, "12 Hour mode is enabled but not supported.\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ struct rtc_plat_data {
|
|||
enum imx_rtc_type devtype;
|
||||
};
|
||||
|
||||
static struct platform_device_id imx_rtc_devtype[] = {
|
||||
static const struct platform_device_id imx_rtc_devtype[] = {
|
||||
{
|
||||
.name = "imx1-rtc",
|
||||
.driver_data = IMX1_RTC,
|
||||
|
|
|
@ -239,7 +239,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
|
|||
struct palmas_rtc *palmas_rtc = NULL;
|
||||
int ret;
|
||||
bool enable_bb_charging = false;
|
||||
bool high_bb_charging;
|
||||
bool high_bb_charging = false;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
enable_bb_charging = of_property_read_bool(pdev->dev.of_node,
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define DRV_VERSION "0.4.3"
|
||||
#define DRV_VERSION "0.4.4"
|
||||
|
||||
#define PCF8563_REG_ST1 0x00 /* status */
|
||||
#define PCF8563_REG_ST2 0x01
|
||||
|
@ -202,8 +202,9 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
|
||||
if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
|
||||
pcf8563->voltage_low = 1;
|
||||
dev_info(&client->dev,
|
||||
dev_err(&client->dev,
|
||||
"low voltage detected, date/time is not reliable.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
|
@ -234,12 +235,6 @@ static int pcf8563_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;
|
||||
}
|
||||
|
||||
|
@ -363,13 +358,13 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
unsigned char buf[4];
|
||||
int err;
|
||||
unsigned long alarm_time;
|
||||
|
||||
/* The alarm has no seconds, round up to nearest minute */
|
||||
if (tm->time.tm_sec) {
|
||||
rtc_tm_to_time(&tm->time, &alarm_time);
|
||||
alarm_time += 60-tm->time.tm_sec;
|
||||
rtc_time_to_tm(alarm_time, &tm->time);
|
||||
time64_t alarm_time = rtc_tm_to_time64(&tm->time);
|
||||
|
||||
alarm_time += 60 - tm->time.tm_sec;
|
||||
rtc_time64_to_tm(alarm_time, &tm->time);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d "
|
||||
|
@ -437,7 +432,7 @@ static int pcf8563_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
|
||||
if (err < 0) {
|
||||
if (err) {
|
||||
dev_err(&client->dev, "%s: read error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -772,18 +772,6 @@ static struct s3c_rtc_data const s3c6410_rtc_data = {
|
|||
.disable = s3c6410_rtc_disable,
|
||||
};
|
||||
|
||||
static struct s3c_rtc_data const exynos3250_rtc_data = {
|
||||
.max_user_freq = 32768,
|
||||
.needs_src_clk = true,
|
||||
.irq_handler = s3c6410_rtc_irq,
|
||||
.set_freq = s3c6410_rtc_setfreq,
|
||||
.enable_tick = s3c6410_rtc_enable_tick,
|
||||
.save_tick_cnt = s3c6410_rtc_save_tick_cnt,
|
||||
.restore_tick_cnt = s3c6410_rtc_restore_tick_cnt,
|
||||
.enable = s3c24xx_rtc_enable,
|
||||
.disable = s3c6410_rtc_disable,
|
||||
};
|
||||
|
||||
static const struct of_device_id s3c_rtc_dt_match[] = {
|
||||
{
|
||||
.compatible = "samsung,s3c2410-rtc",
|
||||
|
@ -799,7 +787,7 @@ static const struct of_device_id s3c_rtc_dt_match[] = {
|
|||
.data = (void *)&s3c6410_rtc_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos3250-rtc",
|
||||
.data = (void *)&exynos3250_rtc_data,
|
||||
.data = (void *)&s3c6410_rtc_data,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
|
|
@ -322,6 +322,13 @@ static int snvs_rtc_suspend(struct device *dev)
|
|||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(data->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snvs_rtc_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (data->clk)
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
|
@ -331,23 +338,28 @@ static int snvs_rtc_suspend(struct device *dev)
|
|||
static int snvs_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(data->irq);
|
||||
return disable_irq_wake(data->irq);
|
||||
|
||||
if (data->clk) {
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snvs_rtc_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (data->clk)
|
||||
return clk_prepare_enable(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops snvs_rtc_pm_ops = {
|
||||
.suspend_noirq = snvs_rtc_suspend,
|
||||
.resume_noirq = snvs_rtc_resume,
|
||||
.suspend = snvs_rtc_suspend,
|
||||
.suspend_noirq = snvs_rtc_suspend_noirq,
|
||||
.resume = snvs_rtc_resume,
|
||||
.resume_noirq = snvs_rtc_resume_noirq,
|
||||
};
|
||||
|
||||
#define SNVS_RTC_PM_OPS (&snvs_rtc_pm_ops)
|
||||
|
|
|
@ -358,12 +358,6 @@ static int spear_rtc_probe(struct platform_device *pdev)
|
|||
int status = 0;
|
||||
int irq;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no resource defined\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
|
||||
if (!config)
|
||||
return -ENOMEM;
|
||||
|
@ -383,6 +377,7 @@ static int spear_rtc_probe(struct platform_device *pdev)
|
|||
return status;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
config->ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(config->ioaddr))
|
||||
return PTR_ERR(config->ioaddr);
|
||||
|
|
|
@ -269,14 +269,13 @@ static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||
struct sunxi_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
struct rtc_time *alrm_tm = &wkalrm->time;
|
||||
struct rtc_time tm_now;
|
||||
u32 alrm = 0;
|
||||
unsigned long time_now = 0;
|
||||
unsigned long time_set = 0;
|
||||
unsigned long time_gap = 0;
|
||||
unsigned long time_gap_day = 0;
|
||||
unsigned long time_gap_hour = 0;
|
||||
unsigned long time_gap_min = 0;
|
||||
int ret = 0;
|
||||
u32 alrm;
|
||||
time64_t diff;
|
||||
unsigned long time_gap;
|
||||
unsigned long time_gap_day;
|
||||
unsigned long time_gap_hour;
|
||||
unsigned long time_gap_min;
|
||||
int ret;
|
||||
|
||||
ret = sunxi_rtc_gettime(dev, &tm_now);
|
||||
if (ret < 0) {
|
||||
|
@ -284,14 +283,18 @@ static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
rtc_tm_to_time(alrm_tm, &time_set);
|
||||
rtc_tm_to_time(&tm_now, &time_now);
|
||||
if (time_set <= time_now) {
|
||||
diff = rtc_tm_sub(alrm_tm, &tm_now);
|
||||
if (diff <= 0) {
|
||||
dev_err(dev, "Date to set in the past\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
time_gap = time_set - time_now;
|
||||
if (diff > 255 * SEC_IN_DAY) {
|
||||
dev_err(dev, "Day must be in the range 0 - 255\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
time_gap = diff;
|
||||
time_gap_day = time_gap / SEC_IN_DAY;
|
||||
time_gap -= time_gap_day * SEC_IN_DAY;
|
||||
time_gap_hour = time_gap / SEC_IN_HOUR;
|
||||
|
@ -299,11 +302,6 @@ static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
|||
time_gap_min = time_gap / SEC_IN_MIN;
|
||||
time_gap -= time_gap_min * SEC_IN_MIN;
|
||||
|
||||
if (time_gap_day > 255) {
|
||||
dev_err(dev, "Day must be in the range 0 - 255\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sunxi_rtc_setaie(0, chip);
|
||||
writel(0, chip->base + SUNXI_ALRM_DHMS);
|
||||
usleep_range(100, 300);
|
||||
|
|
|
@ -49,18 +49,13 @@ struct v3020_chip_ops {
|
|||
#define V3020_RD 2
|
||||
#define V3020_IO 3
|
||||
|
||||
struct v3020_gpio {
|
||||
const char *name;
|
||||
unsigned int gpio;
|
||||
};
|
||||
|
||||
struct v3020 {
|
||||
/* MMIO access */
|
||||
void __iomem *ioaddress;
|
||||
int leftshift;
|
||||
|
||||
/* GPIO access */
|
||||
struct v3020_gpio *gpio;
|
||||
struct gpio *gpio;
|
||||
|
||||
struct v3020_chip_ops *ops;
|
||||
|
||||
|
@ -107,48 +102,34 @@ static struct v3020_chip_ops v3020_mmio_ops = {
|
|||
.write_bit = v3020_mmio_write_bit,
|
||||
};
|
||||
|
||||
static struct v3020_gpio v3020_gpio[] = {
|
||||
{ "RTC CS", 0 },
|
||||
{ "RTC WR", 0 },
|
||||
{ "RTC RD", 0 },
|
||||
{ "RTC IO", 0 },
|
||||
static struct gpio v3020_gpio[] = {
|
||||
{ 0, GPIOF_OUT_INIT_HIGH, "RTC CS"},
|
||||
{ 0, GPIOF_OUT_INIT_HIGH, "RTC WR"},
|
||||
{ 0, GPIOF_OUT_INIT_HIGH, "RTC RD"},
|
||||
{ 0, GPIOF_OUT_INIT_HIGH, "RTC IO"},
|
||||
};
|
||||
|
||||
static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev,
|
||||
struct v3020_platform_data *pdata)
|
||||
{
|
||||
int i, err;
|
||||
int err;
|
||||
|
||||
v3020_gpio[V3020_CS].gpio = pdata->gpio_cs;
|
||||
v3020_gpio[V3020_WR].gpio = pdata->gpio_wr;
|
||||
v3020_gpio[V3020_RD].gpio = pdata->gpio_rd;
|
||||
v3020_gpio[V3020_IO].gpio = pdata->gpio_io;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) {
|
||||
err = gpio_request(v3020_gpio[i].gpio, v3020_gpio[i].name);
|
||||
if (err)
|
||||
goto err_request;
|
||||
err = gpio_request_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
|
||||
|
||||
gpio_direction_output(v3020_gpio[i].gpio, 1);
|
||||
}
|
||||
|
||||
chip->gpio = v3020_gpio;
|
||||
|
||||
return 0;
|
||||
|
||||
err_request:
|
||||
while (--i >= 0)
|
||||
gpio_free(v3020_gpio[i].gpio);
|
||||
if (!err)
|
||||
chip->gpio = v3020_gpio;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void v3020_gpio_unmap(struct v3020 *chip)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++)
|
||||
gpio_free(v3020_gpio[i].gpio);
|
||||
gpio_free_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
|
||||
}
|
||||
|
||||
static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit)
|
||||
|
|
|
@ -31,7 +31,7 @@ int rtc_set_ntp_time(struct timespec64 now)
|
|||
else
|
||||
rtc_time64_to_tm(now.tv_sec + 1, &tm);
|
||||
|
||||
rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
|
||||
rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
|
||||
if (rtc) {
|
||||
/* rtc_hctosys exclusively uses UTC, so we call set_time here,
|
||||
* not set_mmss. */
|
||||
|
|
|
@ -24,6 +24,14 @@ extern void rtc_time64_to_tm(time64_t time, struct rtc_time *tm);
|
|||
ktime_t rtc_tm_to_ktime(struct rtc_time tm);
|
||||
struct rtc_time rtc_ktime_to_tm(ktime_t kt);
|
||||
|
||||
/*
|
||||
* rtc_tm_sub - Return the difference in seconds.
|
||||
*/
|
||||
static inline time64_t rtc_tm_sub(struct rtc_time *lhs, struct rtc_time *rhs)
|
||||
{
|
||||
return rtc_tm_to_time64(lhs) - rtc_tm_to_time64(rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Use rtc_time64_to_tm().
|
||||
*/
|
||||
|
@ -101,8 +109,7 @@ struct rtc_timer {
|
|||
/* flags */
|
||||
#define RTC_DEV_BUSY 0
|
||||
|
||||
struct rtc_device
|
||||
{
|
||||
struct rtc_device {
|
||||
struct device dev;
|
||||
struct module *owner;
|
||||
|
||||
|
@ -161,7 +168,6 @@ extern void devm_rtc_device_unregister(struct device *dev,
|
|||
|
||||
extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
|
||||
extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
|
||||
extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs);
|
||||
extern int rtc_set_ntp_time(struct timespec64 now);
|
||||
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
|
||||
extern int rtc_read_alarm(struct rtc_device *rtc,
|
||||
|
@ -198,10 +204,10 @@ int rtc_register(rtc_task_t *task);
|
|||
int rtc_unregister(rtc_task_t *task);
|
||||
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
|
||||
|
||||
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data);
|
||||
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
|
||||
ktime_t expires, ktime_t period);
|
||||
int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer);
|
||||
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data);
|
||||
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
|
||||
ktime_t expires, ktime_t period);
|
||||
void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer);
|
||||
void rtc_timer_do_work(struct work_struct *work);
|
||||
|
||||
static inline bool is_leap_year(unsigned int year)
|
||||
|
|
Loading…
Reference in New Issue