Commit c13c8100 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 24867481 3783055e
...@@ -6,11 +6,11 @@ as well as a clock output of up to 32kHz. ...@@ -6,11 +6,11 @@ as well as a clock output of up to 32kHz.
Required properties: Required properties:
- compatible: should be: "haoyu,hym8563" - compatible: should be: "haoyu,hym8563"
- reg: i2c address - reg: i2c address
- interrupts: rtc alarm/event interrupt
- #clock-cells: the value should be 0 - #clock-cells: the value should be 0
Optional properties: Optional properties:
- clock-output-names: From common clock binding - clock-output-names: From common clock binding
- interrupts: rtc alarm/event interrupt
Example: Example:
......
...@@ -984,6 +984,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ...@@ -984,6 +984,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
T: git git://github.com/ulli-kroll/linux.git T: git git://github.com/ulli-kroll/linux.git
S: Maintained S: Maintained
F: arch/arm/mach-gemini/ F: arch/arm/mach-gemini/
F: drivers/rtc/rtc-gemini.c
ARM/CSR SIRFPRIMA2 MACHINE SUPPORT ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
M: Barry Song <baohua@kernel.org> M: Barry Song <baohua@kernel.org>
...@@ -1243,6 +1244,13 @@ W: http://www.digriz.org.uk/ts78xx/kernel ...@@ -1243,6 +1244,13 @@ W: http://www.digriz.org.uk/ts78xx/kernel
S: Maintained S: Maintained
F: arch/arm/mach-orion5x/ts78xx-* 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 ARM/Mediatek SoC support
M: Matthias Brugger <matthias.bgg@gmail.com> M: Matthias Brugger <matthias.bgg@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
...@@ -8380,6 +8388,7 @@ M: Alessandro Zummo <a.zummo@towertech.it> ...@@ -8380,6 +8388,7 @@ M: Alessandro Zummo <a.zummo@towertech.it>
M: Alexandre Belloni <alexandre.belloni@free-electrons.com> M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
L: rtc-linux@googlegroups.com L: rtc-linux@googlegroups.com
Q: http://patchwork.ozlabs.org/project/rtc-linux/list/ 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 S: Maintained
F: Documentation/rtc.txt F: Documentation/rtc.txt
F: drivers/rtc/ F: drivers/rtc/
......
...@@ -25,6 +25,7 @@ config SPARC ...@@ -25,6 +25,7 @@ config SPARC
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select RTC_CLASS select RTC_CLASS
select RTC_DRV_M48T59 select RTC_DRV_M48T59
select RTC_SYSTOHC
select HAVE_DMA_ATTRS select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG select HAVE_DMA_API_DEBUG
select HAVE_ARCH_JUMP_LABEL if SPARC64 select HAVE_ARCH_JUMP_LABEL if SPARC64
...@@ -35,7 +36,6 @@ config SPARC ...@@ -35,7 +36,6 @@ config SPARC
select HAVE_BPF_JIT select HAVE_BPF_JIT
select HAVE_DEBUG_BUGVERBOSE select HAVE_DEBUG_BUGVERBOSE
select GENERIC_SMP_IDLE_THREAD select GENERIC_SMP_IDLE_THREAD
select GENERIC_CMOS_UPDATE
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/rtc.h>
#include <linux/rtc/m48t59.h> #include <linux/rtc/m48t59.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
...@@ -65,8 +64,6 @@ DEFINE_PER_CPU(struct clock_event_device, sparc32_clockevent); ...@@ -65,8 +64,6 @@ DEFINE_PER_CPU(struct clock_event_device, sparc32_clockevent);
DEFINE_SPINLOCK(rtc_lock); DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL(rtc_lock);
static int set_rtc_mmss(unsigned long);
unsigned long profile_pc(struct pt_regs *regs) unsigned long profile_pc(struct pt_regs *regs)
{ {
extern char __copy_user_begin[], __copy_user_end[]; extern char __copy_user_begin[], __copy_user_end[];
...@@ -87,11 +84,6 @@ EXPORT_SYMBOL(profile_pc); ...@@ -87,11 +84,6 @@ EXPORT_SYMBOL(profile_pc);
volatile u32 __iomem *master_l10_counter; 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) irqreturn_t notrace timer_interrupt(int dummy, void *dev_id)
{ {
if (timer_cs_enabled) { if (timer_cs_enabled) {
...@@ -362,16 +354,3 @@ void __init time_init(void) ...@@ -362,16 +354,3 @@ void __init time_init(void)
sbus_time_init(); 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 @@ ...@@ -28,7 +28,6 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/rtc.h>
#include <linux/rtc/m48t59.h> #include <linux/rtc/m48t59.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
...@@ -394,19 +393,6 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = { ...@@ -394,19 +393,6 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = {
static unsigned long timer_ticks_per_nsec_quotient __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; unsigned long cmos_regs;
EXPORT_SYMBOL(cmos_regs); EXPORT_SYMBOL(cmos_regs);
......
...@@ -21,9 +21,27 @@ ...@@ -21,9 +21,27 @@
#include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6397/registers.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[] = { static const struct mfd_cell mt6397_devs[] = {
{ {
.name = "mt6397-rtc", .name = "mt6397-rtc",
.num_resources = ARRAY_SIZE(mt6397_rtc_resources),
.resources = mt6397_rtc_resources,
.of_compatible = "mediatek,mt6397-rtc", .of_compatible = "mediatek,mt6397-rtc",
}, { }, {
.name = "mt6397-regulator", .name = "mt6397-regulator",
......
...@@ -25,17 +25,9 @@ config RTC_HCTOSYS ...@@ -25,17 +25,9 @@ config RTC_HCTOSYS
the value read from a specified RTC device. This is useful to avoid the value read from a specified RTC device. This is useful to avoid
unnecessary fsck runs at boot time, and to network better. 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 config RTC_HCTOSYS_DEVICE
string "RTC used to set the system time" string "RTC used to set the system time"
depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y depends on RTC_HCTOSYS
default "rtc0" default "rtc0"
help help
The RTC device that will be used to (re)initialize the system The RTC device that will be used to (re)initialize the system
...@@ -56,6 +48,25 @@ config RTC_HCTOSYS_DEVICE ...@@ -56,6 +48,25 @@ config RTC_HCTOSYS_DEVICE
sleep states. Do not specify an RTC here unless it stays powered sleep states. Do not specify an RTC here unless it stays powered
during all this system's supported sleep states. 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 config RTC_DEBUG
bool "RTC debug support" bool "RTC debug support"
help help
...@@ -135,7 +146,7 @@ if I2C ...@@ -135,7 +146,7 @@ if I2C
config RTC_DRV_88PM860X config RTC_DRV_88PM860X
tristate "Marvell 88PM860x" tristate "Marvell 88PM860x"
depends on I2C && MFD_88PM860X depends on MFD_88PM860X
help help
If you say yes here you get support for RTC function in Marvell If you say yes here you get support for RTC function in Marvell
88PM860x chips. 88PM860x chips.
...@@ -145,7 +156,7 @@ config RTC_DRV_88PM860X ...@@ -145,7 +156,7 @@ config RTC_DRV_88PM860X
config RTC_DRV_88PM80X config RTC_DRV_88PM80X
tristate "Marvell 88PM80x" tristate "Marvell 88PM80x"
depends on I2C && MFD_88PM800 depends on MFD_88PM800
help help
If you say yes here you get support for RTC function in Marvell If you say yes here you get support for RTC function in Marvell
88PM80x chips. 88PM80x chips.
...@@ -154,7 +165,6 @@ config RTC_DRV_88PM80X ...@@ -154,7 +165,6 @@ config RTC_DRV_88PM80X
will be called rtc-88pm80x. will be called rtc-88pm80x.
config RTC_DRV_ABB5ZES3 config RTC_DRV_ABB5ZES3
depends on I2C
select REGMAP_I2C select REGMAP_I2C
tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3" tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
help help
...@@ -204,7 +214,6 @@ config RTC_DRV_DS1307 ...@@ -204,7 +214,6 @@ config RTC_DRV_DS1307
config RTC_DRV_DS1374 config RTC_DRV_DS1374
tristate "Dallas/Maxim DS1374" tristate "Dallas/Maxim DS1374"
depends on I2C
help help
If you say yes here you get support for Dallas Semiconductor If you say yes here you get support for Dallas Semiconductor
DS1374 real-time clock chips. If an interrupt is associated DS1374 real-time clock chips. If an interrupt is associated
...@@ -232,7 +241,6 @@ config RTC_DRV_DS1672 ...@@ -232,7 +241,6 @@ config RTC_DRV_DS1672
config RTC_DRV_DS3232 config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232" tristate "Dallas/Maxim DS3232"
depends on I2C
help help
If you say yes here you get support for Dallas Semiconductor If you say yes here you get support for Dallas Semiconductor
DS3232 real-time clock chips. If an interrupt is associated DS3232 real-time clock chips. If an interrupt is associated
...@@ -243,7 +251,7 @@ config RTC_DRV_DS3232 ...@@ -243,7 +251,7 @@ config RTC_DRV_DS3232
config RTC_DRV_HYM8563 config RTC_DRV_HYM8563
tristate "Haoyu Microelectronics HYM8563" tristate "Haoyu Microelectronics HYM8563"
depends on I2C && OF depends on OF
help help
Say Y to enable support for the HYM8563 I2C RTC chip. Apart Say Y to enable support for the HYM8563 I2C RTC chip. Apart
from the usual rtc functions it provides a clock output of from the usual rtc functions it provides a clock output of
...@@ -365,7 +373,6 @@ config RTC_DRV_ISL12022 ...@@ -365,7 +373,6 @@ config RTC_DRV_ISL12022
will be called rtc-isl12022. will be called rtc-isl12022.
config RTC_DRV_ISL12057 config RTC_DRV_ISL12057
depends on I2C
select REGMAP_I2C select REGMAP_I2C
tristate "Intersil ISL12057" tristate "Intersil ISL12057"
help help
...@@ -1372,6 +1379,17 @@ config RTC_DRV_ARMADA38X ...@@ -1372,6 +1379,17 @@ config RTC_DRV_ARMADA38X
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called armada38x-rtc. 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 config RTC_DRV_PS3
tristate "PS3 RTC" tristate "PS3 RTC"
depends on PPC_PS3 depends on PPC_PS3
...@@ -1396,6 +1414,7 @@ config RTC_DRV_COH901331 ...@@ -1396,6 +1414,7 @@ config RTC_DRV_COH901331
config RTC_DRV_STMP config RTC_DRV_STMP
tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC"
depends on ARCH_MXS depends on ARCH_MXS
select STMP_DEVICE
help help
If you say yes here you will get support for the onboard If you say yes here you will get support for the onboard
STMP3xxx/i.MX23/i.MX28 RTC. STMP3xxx/i.MX23/i.MX28 RTC.
...@@ -1541,9 +1560,20 @@ config RTC_DRV_MOXART ...@@ -1541,9 +1560,20 @@ config RTC_DRV_MOXART
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-moxart 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 config RTC_DRV_XGENE
tristate "APM X-Gene RTC" tristate "APM X-Gene RTC"
depends on HAS_IOMEM depends on HAS_IOMEM
depends on ARCH_XGENE || COMPILE_TEST
help help
If you say yes here you get support for the APM X-Gene SoC real time If you say yes here you get support for the APM X-Gene SoC real time
clock. clock.
......
...@@ -20,8 +20,8 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o ...@@ -20,8 +20,8 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
# Keep the list ordered. # Keep the list ordered.
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.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_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
...@@ -43,7 +43,6 @@ obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.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_DAVINCI) += rtc-davinci.o
obj-$(CONFIG_RTC_DRV_DIGICOLOR) += rtc-digicolor.o obj-$(CONFIG_RTC_DRV_DIGICOLOR) += rtc-digicolor.o
obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.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_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
...@@ -65,13 +64,14 @@ obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o ...@@ -65,13 +64,14 @@ obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.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_GENERIC) += rtc-generic.o
obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.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_HYM8563) += rtc-hym8563.o
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.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_ISL12022) += rtc-isl12022.o
obj-$(CONFIG_RTC_DRV_ISL12057) += rtc-isl12057.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_JZ4740) += rtc-jz4740.o
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
...@@ -82,32 +82,35 @@ obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.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_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.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_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_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.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_MC13XXX) += rtc-mc13xxx.o
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.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_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_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.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_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.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_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_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.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_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_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
...@@ -130,21 +133,23 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.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_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.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_SNVS) += rtc-snvs.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.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_SUN4V) += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o
obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o
obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.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_TPS6586X) += rtc-tps6586x.o
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.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_TX4939) += rtc-tx4939.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
...@@ -153,6 +158,3 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.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_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.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) ...@@ -91,51 +91,6 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
} }
EXPORT_SYMBOL_GPL(rtc_set_time); 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) static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{ {
int err; int err;
...@@ -976,14 +931,12 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, ...@@ -976,14 +931,12 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
* *
* Kernel interface to cancel an rtc_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); mutex_lock(&rtc->ops_lock);
if (timer->enabled) if (timer->enabled)
rtc_timer_remove(rtc, timer); rtc_timer_remove(rtc, timer);
mutex_unlock(&rtc->ops_lock); mutex_unlock(&rtc->ops_lock);
return ret;
} }
...@@ -442,7 +442,7 @@ static const struct rtc_class_ops ab8540_rtc_ops = { ...@@ -442,7 +442,7 @@ static const struct rtc_class_ops ab8540_rtc_ops = {
.alarm_irq_enable = ab8500_rtc_irq_enable, .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, }, { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, },
{ "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, }, { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, },
}; };
......
...@@ -282,6 +282,6 @@ static struct platform_driver at32_rtc_driver = { ...@@ -282,6 +282,6 @@ static struct platform_driver at32_rtc_driver = {
module_platform_driver_probe(at32_rtc_driver, at32_rtc_probe); 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_DESCRIPTION("Real time clock for AVR32 AT32AP700x");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -144,15 +144,13 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev) ...@@ -144,15 +144,13 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev)
struct ds1216_priv *priv; struct ds1216_priv *priv;
u8 dummy[8]; u8 dummy[8];
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->ioaddr = devm_ioremap_resource(&pdev->dev, res); priv->ioaddr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->ioaddr)) if (IS_ERR(priv->ioaddr))
return PTR_ERR(priv->ioaddr); return PTR_ERR(priv->ioaddr);
......
...@@ -332,13 +332,11 @@ static int ds1286_probe(struct platform_device *pdev) ...@@ -332,13 +332,11 @@ static int ds1286_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
struct ds1286_priv *priv; 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); priv = devm_kzalloc(&pdev->dev, sizeof(struct ds1286_priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->rtcregs = devm_ioremap_resource(&pdev->dev, res); priv->rtcregs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->rtcregs)) if (IS_ERR(priv->rtcregs))
return PTR_ERR(priv->rtcregs); return PTR_ERR(priv->rtcregs);
......
...@@ -742,17 +742,17 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -742,17 +742,17 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
regs[6] &= ~MCP794XX_BIT_ALMX_IF; regs[6] &= ~MCP794XX_BIT_ALMX_IF;
/* Set alarm match: second, minute, hour, day, date, month. */ /* Set alarm match: second, minute, hour, day, date, month. */
regs[6] |= MCP794XX_MSK_ALMX_MATCH; regs[6] |= MCP794XX_MSK_ALMX_MATCH;
/* Disable interrupt. We will not enable until completely programmed */
if (t->enabled)
regs[0] |= MCP794XX_BIT_ALM0_EN;
else
regs[0] &= ~MCP794XX_BIT_ALM0_EN; regs[0] &= ~MCP794XX_BIT_ALM0_EN;
ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs); ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!t->enabled)
return 0; 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) static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
......
...@@ -198,6 +198,7 @@ static struct i2c_device_id ds1672_id[] = { ...@@ -198,6 +198,7 @@ static struct i2c_device_id ds1672_id[] = {
{ "ds1672", 0 }, { "ds1672", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, ds1672_id);
static struct i2c_driver ds1672_driver = { static struct i2c_driver ds1672_driver = {
.driver = { .driver = {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P. * 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 * Based on efirtc.c by Stephane Eranian
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
...@@ -24,10 +24,6 @@ ...@@ -24,10 +24,6 @@
#include <linux/efi.h> #include <linux/efi.h>
#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) #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] * returns day of the year [0-365]
...@@ -38,31 +34,24 @@ compute_yday(efi_time_t *eft) ...@@ -38,31 +34,24 @@ compute_yday(efi_time_t *eft)
/* efi_time_t.month is in the [1-12] so, we need -1 */ /* efi_time_t.month is in the [1-12] so, we need -1 */
return rtc_year_days(eft->day, eft->month - 1, eft->year); return rtc_year_days(eft->day, eft->month - 1, eft->year);
} }
/* /*
* returns day of the week [0-6] 0=Sunday * returns day of the week [0-6] 0=Sunday
*
* Don't try to provide a year that's before 1998, please !
*/ */
static int static int
compute_wday(efi_time_t *eft) compute_wday(efi_time_t *eft, int yday)
{ {
int y; int ndays = eft->year * (365 % 7)
int ndays = 0; + (eft->year - 1) / 4
- (eft->year - 1) / 100
if (eft->year < EFI_RTC_EPOCH) { + (eft->year - 1) / 400
pr_err("EFI year < " __stringify(EFI_RTC_EPOCH) ", invalid date\n"); + yday;
return -1;
}
for (y = EFI_RTC_EPOCH; y < eft->year; y++)
ndays += 365 + (is_leap_year(y) ? 1 : 0);
ndays += compute_yday(eft);
/* /*
* 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 static void
...@@ -103,16 +92,16 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) ...@@ -103,16 +92,16 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
if (!eft->month || eft->month > 12) if (!eft->month || eft->month > 12)
return false; return false;
wtime->tm_mon = eft->month - 1; wtime->tm_mon = eft->month - 1;
wtime->tm_year = eft->year - 1900;
/* day of the week [0-6], Sunday=0 */ if (eft->year < 1900 || eft->year > 9999)
wtime->tm_wday = compute_wday(eft);
if (wtime->tm_wday < 0)
return false; return false;
wtime->tm_year = eft->year - 1900;
/* day in the year [1-365]*/ /* day in the year [1-365]*/
wtime->tm_yday = compute_yday(eft); 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) { switch (eft->daylight & EFI_ISDST) {
case EFI_ISDST: case EFI_ISDST:
...@@ -233,7 +222,7 @@ static struct platform_driver efi_rtc_driver = { ...@@ -233,7 +222,7 @@ static struct platform_driver efi_rtc_driver = {
module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe); module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
MODULE_ALIAS("platform:rtc-efi"); MODULE_ALIAS("platform:rtc-efi");
MODULE_AUTHOR("dann frazier <dannf@hp.com>"); MODULE_AUTHOR("dann frazier <dannf@dannf.org>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EFI RTC driver"); MODULE_DESCRIPTION("EFI RTC driver");
MODULE_ALIAS("platform:rtc-efi"); MODULE_ALIAS("platform:rtc-efi");
...@@ -45,7 +45,7 @@ static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, ...@@ -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); struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
unsigned long comp; unsigned long comp;
comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP); comp = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
if (preload) if (preload)
*preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK) *preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
...@@ -63,7 +63,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -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); struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
unsigned long time; 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); rtc_time_to_tm(time, tm);
return 0; return 0;
...@@ -73,7 +73,7 @@ static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) ...@@ -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); 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; return 0;
} }
......
/*
* 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) ...@@ -318,7 +318,7 @@ static int hid_time_remove(struct platform_device *pdev)
return 0; 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 */ /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-2000a0", .name = "HID-SENSOR-2000a0",
......
...@@ -548,6 +548,7 @@ static int hym8563_probe(struct i2c_client *client, ...@@ -548,6 +548,7 @@ static int hym8563_probe(struct i2c_client *client,
return ret; return ret;
} }
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq, ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, hym8563_irq, NULL, hym8563_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
...@@ -557,6 +558,7 @@ static int hym8563_probe(struct i2c_client *client, ...@@ -557,6 +558,7 @@ static int hym8563_probe(struct i2c_client *client,
client->irq, ret); client->irq, ret);
return ret; return ret;
} }
}
/* check state of calendar information */ /* check state of calendar information */
ret = i2c_smbus_read_byte_data(client, HYM8563_SEC); ret = i2c_smbus_read_byte_data(client, HYM8563_SEC);
......
...@@ -129,6 +129,324 @@ struct imxdi_dev { ...@@ -129,6 +129,324 @@ struct imxdi_dev {
struct work_struct work; 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 * enable a dryice interrupt
*/ */
...@@ -137,7 +455,7 @@ static void di_int_enable(struct imxdi_dev *imxdi, u32 intr) ...@@ -137,7 +455,7 @@ static void di_int_enable(struct imxdi_dev *imxdi, u32 intr)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&imxdi->irq_lock, flags); spin_lock_irqsave(&imxdi->irq_lock, flags);
__raw_writel(__raw_readl(imxdi->ioaddr + DIER) | intr, writel(readl(imxdi->ioaddr + DIER) | intr,
imxdi->ioaddr + DIER); imxdi->ioaddr + DIER);
spin_unlock_irqrestore(&imxdi->irq_lock, flags); spin_unlock_irqrestore(&imxdi->irq_lock, flags);
} }
...@@ -150,7 +468,7 @@ static void di_int_disable(struct imxdi_dev *imxdi, u32 intr) ...@@ -150,7 +468,7 @@ static void di_int_disable(struct imxdi_dev *imxdi, u32 intr)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&imxdi->irq_lock, flags); spin_lock_irqsave(&imxdi->irq_lock, flags);
__raw_writel(__raw_readl(imxdi->ioaddr + DIER) & ~intr, writel(readl(imxdi->ioaddr + DIER) & ~intr,
imxdi->ioaddr + DIER); imxdi->ioaddr + DIER);
spin_unlock_irqrestore(&imxdi->irq_lock, flags); spin_unlock_irqrestore(&imxdi->irq_lock, flags);
} }
...@@ -169,11 +487,11 @@ static void clear_write_error(struct imxdi_dev *imxdi) ...@@ -169,11 +487,11 @@ static void clear_write_error(struct imxdi_dev *imxdi)
dev_warn(&imxdi->pdev->dev, "WARNING: Register write error!\n"); dev_warn(&imxdi->pdev->dev, "WARNING: Register write error!\n");
/* clear the write error flag */ /* clear the write error flag */
__raw_writel(DSR_WEF, imxdi->ioaddr + DSR); writel(DSR_WEF, imxdi->ioaddr + DSR);
/* wait for it to take effect */ /* wait for it to take effect */
for (cnt = 0; cnt < 1000; cnt++) { for (cnt = 0; cnt < 1000; cnt++) {
if ((__raw_readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0) if ((readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0)
return; return;
udelay(10); udelay(10);
} }
...@@ -201,7 +519,7 @@ static int di_write_wait(struct imxdi_dev *imxdi, u32 val, int reg) ...@@ -201,7 +519,7 @@ static int di_write_wait(struct imxdi_dev *imxdi, u32 val, int reg)
imxdi->dsr = 0; imxdi->dsr = 0;
/* do the register write */ /* do the register write */
__raw_writel(val, imxdi->ioaddr + reg); writel(val, imxdi->ioaddr + reg);
/* wait for the write to finish */ /* wait for the write to finish */
ret = wait_event_interruptible_timeout(imxdi->write_wait, 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) ...@@ -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); struct imxdi_dev *imxdi = dev_get_drvdata(dev);
unsigned long now; unsigned long now;
now = __raw_readl(imxdi->ioaddr + DTCMR); now = readl(imxdi->ioaddr + DTCMR);
rtc_time_to_tm(now, tm); rtc_time_to_tm(now, tm);
return 0; return 0;
...@@ -248,14 +566,35 @@ static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -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) static int dryice_rtc_set_mmss(struct device *dev, unsigned long secs)
{ {
struct imxdi_dev *imxdi = dev_get_drvdata(dev); struct imxdi_dev *imxdi = dev_get_drvdata(dev);
u32 dcr, dsr;
int rc; 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 */ /* zero the fractional part first */
rc = di_write_wait(imxdi, 0, DTCLR); rc = di_write_wait(imxdi, 0, DTCLR);
if (rc == 0) if (rc != 0)
rc = di_write_wait(imxdi, secs, DTCMR); return rc;
rc = di_write_wait(imxdi, secs, DTCMR);
if (rc != 0)
return rc; return rc;
return di_write_wait(imxdi, readl(imxdi->ioaddr + DCR) | DCR_TCE, DCR);
} }
static int dryice_rtc_alarm_irq_enable(struct device *dev, 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) ...@@ -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); struct imxdi_dev *imxdi = dev_get_drvdata(dev);
u32 dcamr; u32 dcamr;
dcamr = __raw_readl(imxdi->ioaddr + DCAMR); dcamr = readl(imxdi->ioaddr + DCAMR);
rtc_time_to_tm(dcamr, &alarm->time); rtc_time_to_tm(dcamr, &alarm->time);
/* alarm is enabled if the interrupt is enabled */ /* 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 */ /* don't allow the DSR read to mess up DSR_WCF */
mutex_lock(&imxdi->write_mutex); mutex_lock(&imxdi->write_mutex);
/* alarm is pending if the alarm flag is set */ /* 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); mutex_unlock(&imxdi->write_mutex);
...@@ -312,7 +651,7 @@ static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ...@@ -312,7 +651,7 @@ static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
return rc; return rc;
/* don't allow setting alarm in the past */ /* don't allow setting alarm in the past */
now = __raw_readl(imxdi->ioaddr + DTCMR); now = readl(imxdi->ioaddr + DTCMR);
if (alarm_time < now) if (alarm_time < now)
return -EINVAL; return -EINVAL;
...@@ -346,7 +685,26 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id) ...@@ -346,7 +685,26 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
u32 dsr, dier; u32 dsr, dier;
irqreturn_t rc = IRQ_NONE; 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 */ /* handle write complete and write error cases */
if (dier & DIER_WCIE) { if (dier & DIER_WCIE) {
...@@ -357,7 +715,6 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id) ...@@ -357,7 +715,6 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
return rc; return rc;
/* DSR_WCF clears itself on DSR read */ /* DSR_WCF clears itself on DSR read */
dsr = __raw_readl(imxdi->ioaddr + DSR);
if (dsr & (DSR_WCF | DSR_WEF)) { if (dsr & (DSR_WCF | DSR_WEF)) {
/* mask the interrupt */ /* mask the interrupt */
di_int_disable(imxdi, DIER_WCIE); di_int_disable(imxdi, DIER_WCIE);
...@@ -373,7 +730,6 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id) ...@@ -373,7 +730,6 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
/* handle the alarm case */ /* handle the alarm case */
if (dier & DIER_CAIE) { if (dier & DIER_CAIE) {
/* DSR_WCF clears itself on DSR read */ /* DSR_WCF clears itself on DSR read */
dsr = __raw_readl(imxdi->ioaddr + DSR);
if (dsr & DSR_CAF) { if (dsr & DSR_CAF) {
/* mask the interrupt */ /* mask the interrupt */
di_int_disable(imxdi, DIER_CAIE); di_int_disable(imxdi, DIER_CAIE);
...@@ -446,7 +802,11 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) ...@@ -446,7 +802,11 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
*/ */
/* mask all interrupts */ /* 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, rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq,
IRQF_SHARED, pdev->name, imxdi); IRQF_SHARED, pdev->name, imxdi);
...@@ -455,44 +815,6 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) ...@@ -455,44 +815,6 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
goto err; 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); platform_set_drvdata(pdev, imxdi);
imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&dryice_rtc_ops, THIS_MODULE); &dryice_rtc_ops, THIS_MODULE);
...@@ -516,7 +838,7 @@ static int __exit dryice_rtc_remove(struct platform_device *pdev) ...@@ -516,7 +838,7 @@ static int __exit dryice_rtc_remove(struct platform_device *pdev)
flush_work(&imxdi->work); flush_work(&imxdi->work);
/* mask all interrupts */ /* mask all interrupts */
__raw_writel(0, imxdi->ioaddr + DIER); writel(0, imxdi->ioaddr + DIER);
clk_disable_unprepare(imxdi->clk); clk_disable_unprepare(imxdi->clk);
......
...@@ -370,22 +370,15 @@ isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) ...@@ -370,22 +370,15 @@ isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
struct rtc_time *alarm_tm = &alarm->time; struct rtc_time *alarm_tm = &alarm->time;
u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
const int offs = ISL1208_REG_SCA; const int offs = ISL1208_REG_SCA;
unsigned long rtc_secs, alarm_secs;
struct rtc_time rtc_tm; struct rtc_time rtc_tm;
int err, enable; int err, enable;
err = isl1208_i2c_read_time(client, &rtc_tm); 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) if (err)
return err; return err;
/* If the alarm time is before the current time disable the alarm */ /* 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; enable = 0x00;
else else
enable = 0x80; enable = 0x80;
......
...@@ -234,6 +234,7 @@ static struct i2c_device_id max6900_id[] = { ...@@ -234,6 +234,7 @@ static struct i2c_device_id max6900_id[] = {
{ "max6900", 0 }, { "max6900", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, max6900_id);
static struct i2c_driver max6900_driver = { static struct i2c_driver max6900_driver = {
.driver = { .driver = {
......
...@@ -511,6 +511,7 @@ static const struct platform_device_id rtc_id[] = { ...@@ -511,6 +511,7 @@ static const struct platform_device_id rtc_id[] = {
{ "max77686-rtc", 0 }, { "max77686-rtc", 0 },
{}, {},
}; };
MODULE_DEVICE_TABLE(platform, rtc_id);
static struct platform_driver max77686_rtc_driver = { static struct platform_driver max77686_rtc_driver = {
.driver = { .driver = {
......
...@@ -484,6 +484,7 @@ static const struct platform_device_id rtc_id[] = { ...@@ -484,6 +484,7 @@ static const struct platform_device_id rtc_id[] = {
{ "max77802-rtc", 0 }, { "max77802-rtc", 0 },
{}, {},
}; };
MODULE_DEVICE_TABLE(platform, rtc_id);
static struct platform_driver max77802_rtc_driver = { static struct platform_driver max77802_rtc_driver = {
.driver = { .driver = {
......
...@@ -309,6 +309,7 @@ static const struct platform_device_id max8998_rtc_id[] = { ...@@ -309,6 +309,7 @@ static const struct platform_device_id max8998_rtc_id[] = {
{ "lp3974-rtc", TYPE_LP3974 }, { "lp3974-rtc", TYPE_LP3974 },
{ } { }
}; };
MODULE_DEVICE_TABLE(platform, max8998_rtc_id);
static struct platform_driver max8998_rtc_driver = { static struct platform_driver max8998_rtc_driver = {
.driver = { .driver = {
......
...@@ -216,7 +216,7 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ...@@ -216,7 +216,7 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
s1970 = rtc_tm_to_time64(&alarm->time); 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); (long long)s1970);
ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled, ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled,
......
/*
* 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 @@ ...@@ -10,6 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/bitops.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -24,7 +25,7 @@ ...@@ -24,7 +25,7 @@
#define RTC_MINUTES_OFFS 8 #define RTC_MINUTES_OFFS 8
#define RTC_HOURS_OFFS 16 #define RTC_HOURS_OFFS 16
#define RTC_WDAY_OFFS 24 #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_DATE_REG_OFFS 4
#define RTC_MDAY_OFFS 0 #define RTC_MDAY_OFFS 0
...@@ -33,7 +34,7 @@ ...@@ -33,7 +34,7 @@
#define RTC_ALARM_TIME_REG_OFFS 8 #define RTC_ALARM_TIME_REG_OFFS 8
#define RTC_ALARM_DATE_REG_OFFS 0xc #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_MASK_REG_OFFS 0x10
#define RTC_ALARM_INTERRUPT_CASUE_REG_OFFS 0x14 #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) ...@@ -77,7 +78,7 @@ static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm)
second = rtc_time & 0x7f; second = rtc_time & 0x7f;
minute = (rtc_time >> RTC_MINUTES_OFFS) & 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; wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7;
day = rtc_date & 0x3f; day = rtc_date & 0x3f;
...@@ -108,7 +109,7 @@ static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) ...@@ -108,7 +109,7 @@ static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
second = rtc_time & 0x7f; second = rtc_time & 0x7f;
minute = (rtc_time >> RTC_MINUTES_OFFS) & 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; wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7;
day = rtc_date & 0x3f; day = rtc_date & 0x3f;
...@@ -239,10 +240,10 @@ static int __init mv_rtc_probe(struct platform_device *pdev) ...@@ -239,10 +240,10 @@ static int __init mv_rtc_probe(struct platform_device *pdev)
if (!IS_ERR(pdata->clk)) if (!IS_ERR(pdata->clk))
clk_prepare_enable(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); rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
if (rtc_time & RTC_HOURS_12H_MODE) { 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; ret = -EINVAL;
goto out; goto out;
} }
......
...@@ -84,7 +84,7 @@ struct rtc_plat_data { ...@@ -84,7 +84,7 @@ struct rtc_plat_data {
enum imx_rtc_type devtype; 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", .name = "imx1-rtc",
.driver_data = IMX1_RTC, .driver_data = IMX1_RTC,
......
...@@ -239,7 +239,7 @@ static int palmas_rtc_probe(struct platform_device *pdev) ...@@ -239,7 +239,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
struct palmas_rtc *palmas_rtc = NULL; struct palmas_rtc *palmas_rtc = NULL;
int ret; int ret;
bool enable_bb_charging = false; bool enable_bb_charging = false;
bool high_bb_charging; bool high_bb_charging = false;
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
enable_bb_charging = of_property_read_bool(pdev->dev.of_node, enable_bb_charging = of_property_read_bool(pdev->dev.of_node,
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/err.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_ST1 0x00 /* status */
#define PCF8563_REG_ST2 0x01 #define PCF8563_REG_ST2 0x01
...@@ -202,8 +202,9 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -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) { if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
pcf8563->voltage_low = 1; pcf8563->voltage_low = 1;
dev_info(&client->dev, dev_err(&client->dev,
"low voltage detected, date/time is not reliable.\n"); "low voltage detected, date/time is not reliable.\n");
return -EINVAL;
} }
dev_dbg(&client->dev, dev_dbg(&client->dev,
...@@ -234,12 +235,6 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -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_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 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 0;
} }
...@@ -363,13 +358,13 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) ...@@ -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); struct i2c_client *client = to_i2c_client(dev);
unsigned char buf[4]; unsigned char buf[4];
int err; int err;
unsigned long alarm_time;
/* The alarm has no seconds, round up to nearest minute */ /* The alarm has no seconds, round up to nearest minute */
if (tm->time.tm_sec) { if (tm->time.tm_sec) {
rtc_tm_to_time(&tm->time, &alarm_time); time64_t alarm_time = rtc_tm_to_time64(&tm->time);
alarm_time += 60-tm->time.tm_sec;
rtc_time_to_tm(alarm_time, &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 " dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d "
...@@ -437,7 +432,7 @@ static int pcf8563_probe(struct i2c_client *client, ...@@ -437,7 +432,7 @@ static int pcf8563_probe(struct i2c_client *client,
} }
err = pcf8563_get_alarm_mode(client, NULL, &alm_pending); err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
if (err < 0) { if (err) {
dev_err(&client->dev, "%s: read error\n", __func__); dev_err(&client->dev, "%s: read error\n", __func__);
return err; return err;
} }
......
...@@ -772,18 +772,6 @@ static struct s3c_rtc_data const s3c6410_rtc_data = { ...@@ -772,18 +772,6 @@ static struct s3c_rtc_data const s3c6410_rtc_data = {
.disable = s3c6410_rtc_disable, .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[] = { static const struct of_device_id s3c_rtc_dt_match[] = {
{ {
.compatible = "samsung,s3c2410-rtc", .compatible = "samsung,s3c2410-rtc",
...@@ -799,7 +787,7 @@ static const struct of_device_id s3c_rtc_dt_match[] = { ...@@ -799,7 +787,7 @@ static const struct of_device_id s3c_rtc_dt_match[] = {
.data = (void *)&s3c6410_rtc_data, .data = (void *)&s3c6410_rtc_data,
}, { }, {
.compatible = "samsung,exynos3250-rtc", .compatible = "samsung,exynos3250-rtc",
.data = (void *)&exynos3250_rtc_data, .data = (void *)&s3c6410_rtc_data,
}, },
{ /* sentinel */ }, { /* sentinel */ },
}; };
......
...@@ -322,6 +322,13 @@ static int snvs_rtc_suspend(struct device *dev) ...@@ -322,6 +322,13 @@ static int snvs_rtc_suspend(struct device *dev)
if (device_may_wakeup(dev)) if (device_may_wakeup(dev))
enable_irq_wake(data->irq); 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) if (data->clk)
clk_disable_unprepare(data->clk); clk_disable_unprepare(data->clk);
...@@ -331,23 +338,28 @@ static int snvs_rtc_suspend(struct device *dev) ...@@ -331,23 +338,28 @@ static int snvs_rtc_suspend(struct device *dev)
static int snvs_rtc_resume(struct device *dev) static int snvs_rtc_resume(struct device *dev)
{ {
struct snvs_rtc_data *data = dev_get_drvdata(dev); struct snvs_rtc_data *data = dev_get_drvdata(dev);
int ret;
if (device_may_wakeup(dev)) if (device_may_wakeup(dev))
disable_irq_wake(data->irq); return disable_irq_wake(data->irq);
if (data->clk) { return 0;
ret = clk_prepare_enable(data->clk); }
if (ret)
return ret; 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; return 0;
} }
static const struct dev_pm_ops snvs_rtc_pm_ops = { static const struct dev_pm_ops snvs_rtc_pm_ops = {
.suspend_noirq = snvs_rtc_suspend, .suspend = snvs_rtc_suspend,
.resume_noirq = snvs_rtc_resume, .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) #define SNVS_RTC_PM_OPS (&snvs_rtc_pm_ops)
......
...@@ -358,12 +358,6 @@ static int spear_rtc_probe(struct platform_device *pdev) ...@@ -358,12 +358,6 @@ static int spear_rtc_probe(struct platform_device *pdev)
int status = 0; int status = 0;
int irq; 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); config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
if (!config) if (!config)
return -ENOMEM; return -ENOMEM;
...@@ -383,6 +377,7 @@ static int spear_rtc_probe(struct platform_device *pdev) ...@@ -383,6 +377,7 @@ static int spear_rtc_probe(struct platform_device *pdev)
return status; return status;
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
config->ioaddr = devm_ioremap_resource(&pdev->dev, res); config->ioaddr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(config->ioaddr)) if (IS_ERR(config->ioaddr))
return PTR_ERR(config->ioaddr); return PTR_ERR(config->ioaddr);
......
...@@ -269,14 +269,13 @@ static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) ...@@ -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 sunxi_rtc_dev *chip = dev_get_drvdata(dev);
struct rtc_time *alrm_tm = &wkalrm->time; struct rtc_time *alrm_tm = &wkalrm->time;
struct rtc_time tm_now; struct rtc_time tm_now;
u32 alrm = 0; u32 alrm;
unsigned long time_now = 0; time64_t diff;
unsigned long time_set = 0; unsigned long time_gap;
unsigned long time_gap = 0; unsigned long time_gap_day;
unsigned long time_gap_day = 0; unsigned long time_gap_hour;
unsigned long time_gap_hour = 0; unsigned long time_gap_min;
unsigned long time_gap_min = 0; int ret;
int ret = 0;
ret = sunxi_rtc_gettime(dev, &tm_now); ret = sunxi_rtc_gettime(dev, &tm_now);
if (ret < 0) { if (ret < 0) {
...@@ -284,14 +283,18 @@ static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) ...@@ -284,14 +283,18 @@ static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
return -EINVAL; return -EINVAL;
} }
rtc_tm_to_time(alrm_tm, &time_set); diff = rtc_tm_sub(alrm_tm, &tm_now);
rtc_tm_to_time(&tm_now, &time_now); if (diff <= 0) {
if (time_set <= time_now) {
dev_err(dev, "Date to set in the past\n"); dev_err(dev, "Date to set in the past\n");
return -EINVAL; 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_day = time_gap / SEC_IN_DAY;
time_gap -= time_gap_day * SEC_IN_DAY; time_gap -= time_gap_day * SEC_IN_DAY;
time_gap_hour = time_gap / SEC_IN_HOUR; time_gap_hour = time_gap / SEC_IN_HOUR;
...@@ -299,11 +302,6 @@ static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) ...@@ -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_min = time_gap / SEC_IN_MIN;
time_gap -= time_gap_min * 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); sunxi_rtc_setaie(0, chip);
writel(0, chip->base + SUNXI_ALRM_DHMS); writel(0, chip->base + SUNXI_ALRM_DHMS);
usleep_range(100, 300); usleep_range(100, 300);
......
...@@ -49,18 +49,13 @@ struct v3020_chip_ops { ...@@ -49,18 +49,13 @@ struct v3020_chip_ops {
#define V3020_RD 2 #define V3020_RD 2
#define V3020_IO 3 #define V3020_IO 3
struct v3020_gpio {
const char *name;
unsigned int gpio;
};
struct v3020 { struct v3020 {
/* MMIO access */ /* MMIO access */
void __iomem *ioaddress; void __iomem *ioaddress;
int leftshift; int leftshift;
/* GPIO access */ /* GPIO access */
struct v3020_gpio *gpio; struct gpio *gpio;
struct v3020_chip_ops *ops; struct v3020_chip_ops *ops;
...@@ -107,48 +102,34 @@ static struct v3020_chip_ops v3020_mmio_ops = { ...@@ -107,48 +102,34 @@ static struct v3020_chip_ops v3020_mmio_ops = {
.write_bit = v3020_mmio_write_bit, .write_bit = v3020_mmio_write_bit,
}; };
static struct v3020_gpio v3020_gpio[] = { static struct gpio v3020_gpio[] = {
{ "RTC CS", 0 }, { 0, GPIOF_OUT_INIT_HIGH, "RTC CS"},
{ "RTC WR", 0 }, { 0, GPIOF_OUT_INIT_HIGH, "RTC WR"},
{ "RTC RD", 0 }, { 0, GPIOF_OUT_INIT_HIGH, "RTC RD"},
{ "RTC IO", 0 }, { 0, GPIOF_OUT_INIT_HIGH, "RTC IO"},
}; };
static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev, static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev,
struct v3020_platform_data *pdata) struct v3020_platform_data *pdata)
{ {
int i, err; int err;
v3020_gpio[V3020_CS].gpio = pdata->gpio_cs; v3020_gpio[V3020_CS].gpio = pdata->gpio_cs;
v3020_gpio[V3020_WR].gpio = pdata->gpio_wr; v3020_gpio[V3020_WR].gpio = pdata->gpio_wr;
v3020_gpio[V3020_RD].gpio = pdata->gpio_rd; v3020_gpio[V3020_RD].gpio = pdata->gpio_rd;
v3020_gpio[V3020_IO].gpio = pdata->gpio_io; v3020_gpio[V3020_IO].gpio = pdata->gpio_io;
for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) { err = gpio_request_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
err = gpio_request(v3020_gpio[i].gpio, v3020_gpio[i].name);
if (err)
goto err_request;
gpio_direction_output(v3020_gpio[i].gpio, 1);
}
if (!err)
chip->gpio = v3020_gpio; chip->gpio = v3020_gpio;
return 0;
err_request:
while (--i >= 0)
gpio_free(v3020_gpio[i].gpio);
return err; return err;
} }
static void v3020_gpio_unmap(struct v3020 *chip) static void v3020_gpio_unmap(struct v3020 *chip)
{ {
int i; gpio_free_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++)
gpio_free(v3020_gpio[i].gpio);
} }
static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit) static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit)
......
...@@ -31,7 +31,7 @@ int rtc_set_ntp_time(struct timespec64 now) ...@@ -31,7 +31,7 @@ int rtc_set_ntp_time(struct timespec64 now)
else else
rtc_time64_to_tm(now.tv_sec + 1, &tm); 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) { if (rtc) {
/* rtc_hctosys exclusively uses UTC, so we call set_time here, /* rtc_hctosys exclusively uses UTC, so we call set_time here,
* not set_mmss. */ * not set_mmss. */
......
...@@ -24,6 +24,14 @@ extern void rtc_time64_to_tm(time64_t time, struct rtc_time *tm); ...@@ -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); ktime_t rtc_tm_to_ktime(struct rtc_time tm);
struct rtc_time rtc_ktime_to_tm(ktime_t kt); 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(). * Deprecated. Use rtc_time64_to_tm().
*/ */
...@@ -101,8 +109,7 @@ struct rtc_timer { ...@@ -101,8 +109,7 @@ struct rtc_timer {
/* flags */ /* flags */
#define RTC_DEV_BUSY 0 #define RTC_DEV_BUSY 0
struct rtc_device struct rtc_device {
{
struct device dev; struct device dev;
struct module *owner; struct module *owner;
...@@ -161,7 +168,6 @@ extern void devm_rtc_device_unregister(struct device *dev, ...@@ -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_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_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); extern int rtc_set_ntp_time(struct timespec64 now);
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
extern int rtc_read_alarm(struct rtc_device *rtc, extern int rtc_read_alarm(struct rtc_device *rtc,
...@@ -198,10 +204,10 @@ int rtc_register(rtc_task_t *task); ...@@ -198,10 +204,10 @@ int rtc_register(rtc_task_t *task);
int rtc_unregister(rtc_task_t *task); int rtc_unregister(rtc_task_t *task);
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); 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); 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, int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
ktime_t expires, ktime_t period); ktime_t expires, ktime_t period);
int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer); void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer);
void rtc_timer_do_work(struct work_struct *work); void rtc_timer_do_work(struct work_struct *work);
static inline bool is_leap_year(unsigned int year) static inline bool is_leap_year(unsigned int year)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment