aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig49
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c30
-rw-r--r--drivers/rtc/interface.c21
-rw-r--r--drivers/rtc/rtc-88pm80x.c1
-rw-r--r--drivers/rtc/rtc-88pm860x.c1
-rw-r--r--drivers/rtc/rtc-ab3100.c1
-rw-r--r--drivers/rtc/rtc-ab8500.c3
-rw-r--r--drivers/rtc/rtc-at32ap700x.c1
-rw-r--r--drivers/rtc/rtc-at91rm9200.c1
-rw-r--r--drivers/rtc/rtc-at91sam9.c139
-rw-r--r--drivers/rtc/rtc-au1xxx.c1
-rw-r--r--drivers/rtc/rtc-bfin.c1
-rw-r--r--drivers/rtc/rtc-bq4802.c1
-rw-r--r--drivers/rtc/rtc-coh901331.c1
-rw-r--r--drivers/rtc/rtc-da9052.c1
-rw-r--r--drivers/rtc/rtc-da9055.c1
-rw-r--r--drivers/rtc/rtc-da9063.c1
-rw-r--r--drivers/rtc/rtc-davinci.c1
-rw-r--r--drivers/rtc/rtc-dm355evm.c1
-rw-r--r--drivers/rtc/rtc-ds1216.c1
-rw-r--r--drivers/rtc/rtc-ds1286.c1
-rw-r--r--drivers/rtc/rtc-ds1302.c1
-rw-r--r--drivers/rtc/rtc-ds1307.c127
-rw-r--r--drivers/rtc/rtc-ds1374.c285
-rw-r--r--drivers/rtc/rtc-ds1511.c1
-rw-r--r--drivers/rtc/rtc-ds1553.c1
-rw-r--r--drivers/rtc/rtc-ds1742.c1
-rw-r--r--drivers/rtc/rtc-ds2404.c1
-rw-r--r--drivers/rtc/rtc-efi.c1
-rw-r--r--drivers/rtc/rtc-ep93xx.c1
-rw-r--r--drivers/rtc/rtc-generic.c1
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c1
-rw-r--r--drivers/rtc/rtc-imxdi.c1
-rw-r--r--drivers/rtc/rtc-isl12057.c83
-rw-r--r--drivers/rtc/rtc-jz4740.c1
-rw-r--r--drivers/rtc/rtc-lib.c38
-rw-r--r--drivers/rtc/rtc-lp8788.c1
-rw-r--r--drivers/rtc/rtc-lpc32xx.c1
-rw-r--r--drivers/rtc/rtc-ls1x.c1
-rw-r--r--drivers/rtc/rtc-m48t35.c1
-rw-r--r--drivers/rtc/rtc-m48t59.c1
-rw-r--r--drivers/rtc/rtc-m48t86.c1
-rw-r--r--drivers/rtc/rtc-max77686.c1
-rw-r--r--drivers/rtc/rtc-max77802.c1
-rw-r--r--drivers/rtc/rtc-max8907.c1
-rw-r--r--drivers/rtc/rtc-max8925.c1
-rw-r--r--drivers/rtc/rtc-max8997.c1
-rw-r--r--drivers/rtc/rtc-max8998.c1
-rw-r--r--drivers/rtc/rtc-mc13xxx.c1
-rw-r--r--drivers/rtc/rtc-moxart.c1
-rw-r--r--drivers/rtc/rtc-mpc5121.c1
-rw-r--r--drivers/rtc/rtc-msm6242.c1
-rw-r--r--drivers/rtc/rtc-mv.c1
-rw-r--r--drivers/rtc/rtc-mxc.c1
-rw-r--r--drivers/rtc/rtc-nuc900.c1
-rw-r--r--drivers/rtc/rtc-omap.c548
-rw-r--r--drivers/rtc/rtc-opal.c261
-rw-r--r--drivers/rtc/rtc-palmas.c1
-rw-r--r--drivers/rtc/rtc-pcap.c1
-rw-r--r--drivers/rtc/rtc-pcf8563.c55
-rw-r--r--drivers/rtc/rtc-pm8xxx.c1
-rw-r--r--drivers/rtc/rtc-ps3.c1
-rw-r--r--drivers/rtc/rtc-puv3.c1
-rw-r--r--drivers/rtc/rtc-rc5t583.c1
-rw-r--r--drivers/rtc/rtc-rp5c01.c1
-rw-r--r--drivers/rtc/rtc-rs5c313.c1
-rw-r--r--drivers/rtc/rtc-s3c.c1
-rw-r--r--drivers/rtc/rtc-s5m.c1
-rw-r--r--drivers/rtc/rtc-sh.c1
-rw-r--r--drivers/rtc/rtc-sirfsoc.c67
-rw-r--r--drivers/rtc/rtc-snvs.c51
-rw-r--r--drivers/rtc/rtc-starfire.c1
-rw-r--r--drivers/rtc/rtc-stk17ta8.c1
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c1
-rw-r--r--drivers/rtc/rtc-sun4v.c1
-rw-r--r--drivers/rtc/rtc-sunxi.c1
-rw-r--r--drivers/rtc/rtc-tegra.c1
-rw-r--r--drivers/rtc/rtc-test.c1
-rw-r--r--drivers/rtc/rtc-tile.c1
-rw-r--r--drivers/rtc/rtc-tps6586x.c1
-rw-r--r--drivers/rtc/rtc-tps65910.c1
-rw-r--r--drivers/rtc/rtc-tps80031.c1
-rw-r--r--drivers/rtc/rtc-twl.c1
-rw-r--r--drivers/rtc/rtc-tx4939.c1
-rw-r--r--drivers/rtc/rtc-v3020.c1
-rw-r--r--drivers/rtc/rtc-vr41xx.c1
-rw-r--r--drivers/rtc/rtc-vt8500.c1
-rw-r--r--drivers/rtc/rtc-xgene.c1
89 files changed, 1366 insertions, 466 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 6dd12ddbabc6..f15cddfeb897 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -192,6 +192,14 @@ config RTC_DRV_DS1374
This driver can also be built as a module. If so, the module
will be called rtc-ds1374.
+config RTC_DRV_DS1374_WDT
+ bool "Dallas/Maxim DS1374 watchdog timer"
+ depends on RTC_DRV_DS1374
+ help
+ If you say Y here you will get support for the
+ watchdog timer in the Dallas Semiconductor DS1374
+ real-time clock chips.
+
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
help
@@ -979,6 +987,17 @@ config RTC_DRV_NUC900
If you say yes here you get support for the RTC subsystem of the
NUC910/NUC920 used in embedded systems.
+config RTC_DRV_OPAL
+ tristate "IBM OPAL RTC driver"
+ depends on PPC_POWERNV
+ default y
+ help
+ If you say yes here you get support for the PowerNV platform RTC
+ driver based on OPAL interfaces.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-opal.
+
comment "on-CPU RTC drivers"
config RTC_DRV_DAVINCI
@@ -1109,36 +1128,42 @@ config RTC_DRV_AT91RM9200
this is powered by the backup power supply.
config RTC_DRV_AT91SAM9
- tristate "AT91SAM9x/AT91CAP9 RTT as RTC"
- depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
+ tristate "AT91SAM9 RTT as RTC"
+ depends on ARCH_AT91
+ select MFD_SYSCON
help
- RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT
- (Real Time Timer). These timers are powered by the backup power
- supply (such as a small coin cell battery), but do not need to
- be used as RTCs.
-
- (On AT91SAM9rl and AT91SAM9G45 chips you probably want to use the
- dedicated RTC module and leave the RTT available for other uses.)
+ Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which
+ can be used as an RTC thanks to the backup power supply (e.g. a
+ small coin cell battery) which keeps this block and the GPBR
+ (General Purpose Backup Registers) block powered when the device
+ is shutdown.
+ Some AT91SAM9 SoCs provide a real RTC block, on those ones you'd
+ probably want to use the real RTC block instead of the "RTT as an
+ RTC" driver.
config RTC_DRV_AT91SAM9_RTT
int
range 0 1
default 0
- prompt "RTT module Number" if ARCH_AT91SAM9263
depends on RTC_DRV_AT91SAM9
help
+ This option is only relevant for legacy board support and
+ won't be used when booting a DT board.
+
More than one RTT module is available. You can choose which
one will be used as an RTC. The default of zero is normally
OK to use, though some systems use that for non-RTC purposes.
config RTC_DRV_AT91SAM9_GPBR
int
- range 0 3 if !ARCH_AT91SAM9263
- range 0 15 if ARCH_AT91SAM9263
+ range 0 3
default 0
prompt "Backup Register Number"
depends on RTC_DRV_AT91SAM9
help
+ This option is only relevant for legacy board support and
+ won't be used when booting a DT board.
+
The RTC driver needs to use one of the General Purpose Backup
Registers (GPBRs) as well as the RTT. You can choose which one
will be used. The default of zero is normally OK to use, but
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index b188323c096a..c8ef3e1e6ccd 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.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_PALMAS) += rtc-palmas.o
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 38e26be705be..472a5adc4642 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -45,14 +45,14 @@ int rtc_hctosys_ret = -ENODEV;
* system's wall clock; restore it on resume().
*/
-static struct timespec old_rtc, old_system, old_delta;
+static struct timespec64 old_rtc, old_system, old_delta;
static int rtc_suspend(struct device *dev)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- struct timespec delta, delta_delta;
+ struct timespec64 delta, delta_delta;
int err;
if (has_persistent_clock())
@@ -68,8 +68,8 @@ static int rtc_suspend(struct device *dev)
return 0;
}
- getnstimeofday(&old_system);
- rtc_tm_to_time(&tm, &old_rtc.tv_sec);
+ getnstimeofday64(&old_system);
+ old_rtc.tv_sec = rtc_tm_to_time64(&tm);
/*
@@ -78,8 +78,8 @@ static int rtc_suspend(struct device *dev)
* try to compensate so the difference in system time
* and rtc time stays close to constant.
*/
- delta = timespec_sub(old_system, old_rtc);
- delta_delta = timespec_sub(delta, old_delta);
+ delta = timespec64_sub(old_system, old_rtc);
+ delta_delta = timespec64_sub(delta, old_delta);
if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
/*
* if delta_delta is too large, assume time correction
@@ -88,7 +88,7 @@ static int rtc_suspend(struct device *dev)
old_delta = delta;
} else {
/* Otherwise try to adjust old_system to compensate */
- old_system = timespec_sub(old_system, delta_delta);
+ old_system = timespec64_sub(old_system, delta_delta);
}
return 0;
@@ -98,8 +98,8 @@ static int rtc_resume(struct device *dev)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- struct timespec new_system, new_rtc;
- struct timespec sleep_time;
+ struct timespec64 new_system, new_rtc;
+ struct timespec64 sleep_time;
int err;
if (has_persistent_clock())
@@ -110,7 +110,7 @@ static int rtc_resume(struct device *dev)
return 0;
/* snapshot the current rtc and system time at resume */
- getnstimeofday(&new_system);
+ getnstimeofday64(&new_system);
err = rtc_read_time(rtc, &tm);
if (err < 0) {
pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev));
@@ -121,7 +121,7 @@ static int rtc_resume(struct device *dev)
pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev));
return 0;
}
- rtc_tm_to_time(&tm, &new_rtc.tv_sec);
+ new_rtc.tv_sec = rtc_tm_to_time64(&tm);
new_rtc.tv_nsec = 0;
if (new_rtc.tv_sec < old_rtc.tv_sec) {
@@ -130,7 +130,7 @@ static int rtc_resume(struct device *dev)
}
/* calculate the RTC time delta (sleep time)*/
- sleep_time = timespec_sub(new_rtc, old_rtc);
+ sleep_time = timespec64_sub(new_rtc, old_rtc);
/*
* Since these RTC suspend/resume handlers are not called
@@ -139,11 +139,11 @@ static int rtc_resume(struct device *dev)
* so subtract kernel run-time between rtc_suspend to rtc_resume
* to keep things accurate.
*/
- sleep_time = timespec_sub(sleep_time,
- timespec_sub(new_system, old_system));
+ sleep_time = timespec64_sub(sleep_time,
+ timespec64_sub(new_system, old_system));
if (sleep_time.tv_sec >= 0)
- timekeeping_inject_sleeptime(&sleep_time);
+ timekeeping_inject_sleeptime64(&sleep_time);
rtc_hctosys_ret = 0;
return 0;
}
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 5b2717f5dafa..45bfc28ee3aa 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -30,6 +30,14 @@ static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
else {
memset(tm, 0, sizeof(struct rtc_time));
err = rtc->ops->read_time(rtc->dev.parent, tm);
+ if (err < 0) {
+ dev_err(&rtc->dev, "read_time: fail to read\n");
+ return err;
+ }
+
+ err = rtc_valid_tm(tm);
+ if (err < 0)
+ dev_err(&rtc->dev, "read_time: rtc_time isn't valid\n");
}
return err;
}
@@ -891,11 +899,24 @@ again:
if (next) {
struct rtc_wkalrm alarm;
int err;
+ int retry = 3;
+
alarm.time = rtc_ktime_to_tm(next->expires);
alarm.enabled = 1;
+reprogram:
err = __rtc_set_alarm(rtc, &alarm);
if (err == -ETIME)
goto again;
+ else if (err) {
+ if (retry-- > 0)
+ goto reprogram;
+
+ timer = container_of(next, struct rtc_timer, node);
+ timerqueue_del(&rtc->timerqueue, &timer->node);
+ timer->enabled = 0;
+ dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err);
+ goto again;
+ }
} else
rtc_alarm_disable(rtc);
diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c
index 0916089c7c3e..7df0579d9852 100644
--- a/drivers/rtc/rtc-88pm80x.c
+++ b/drivers/rtc/rtc-88pm80x.c
@@ -352,7 +352,6 @@ static int pm80x_rtc_remove(struct platform_device *pdev)
static struct platform_driver pm80x_rtc_driver = {
.driver = {
.name = "88pm80x-rtc",
- .owner = THIS_MODULE,
.pm = &pm80x_rtc_pm_ops,
},
.probe = pm80x_rtc_probe,
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index 0c6add1a38dc..19e53b3b8e00 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -448,7 +448,6 @@ static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resum
static struct platform_driver pm860x_rtc_driver = {
.driver = {
.name = "88pm860x-rtc",
- .owner = THIS_MODULE,
.pm = &pm860x_rtc_pm_ops,
},
.probe = pm860x_rtc_probe,
diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c
index ff435343ba9f..1d0340fdb820 100644
--- a/drivers/rtc/rtc-ab3100.c
+++ b/drivers/rtc/rtc-ab3100.c
@@ -243,7 +243,6 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
static struct platform_driver ab3100_rtc_driver = {
.driver = {
.name = "ab3100-rtc",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index 727e2f5d14d9..6856f0a3a3d5 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -504,6 +504,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
return err;
}
+ rtc->uie_unsupported = 1;
+
return 0;
}
@@ -517,7 +519,6 @@ static int ab8500_rtc_remove(struct platform_device *pdev)
static struct platform_driver ab8500_rtc_driver = {
.driver = {
.name = "ab8500-rtc",
- .owner = THIS_MODULE,
},
.probe = ab8500_rtc_probe,
.remove = ab8500_rtc_remove,
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index aee3387fb099..d618d6c7ef93 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -277,7 +277,6 @@ static struct platform_driver at32_rtc_driver = {
.remove = __exit_p(at32_rtc_remove),
.driver = {
.name = "at32ap700x_rtc",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 44fe83ee9bee..70a5d94cc766 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -491,7 +491,6 @@ static struct platform_driver at91_rtc_driver = {
.shutdown = at91_rtc_shutdown,
.driver = {
.name = "at91_rtc",
- .owner = THIS_MODULE,
.pm = &at91_rtc_pm_ops,
.of_match_table = of_match_ptr(at91_rtc_dt_ids),
},
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 596374304532..6b9aaf1afc72 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -21,10 +21,9 @@
#include <linux/slab.h>
#include <linux/platform_data/atmel.h>
#include <linux/io.h>
-
-#include <mach/at91_rtt.h>
-#include <mach/cpu.h>
-#include <mach/hardware.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
/*
* This driver uses two configurable hardware resources that live in the
@@ -47,6 +46,22 @@
* registers available, likewise usable for more than "RTC" support.
*/
+#define AT91_RTT_MR 0x00 /* Real-time Mode Register */
+#define AT91_RTT_RTPRES (0xffff << 0) /* Real-time Timer Prescaler Value */
+#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */
+#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */
+#define AT91_RTT_RTTRST (1 << 18) /* Real Time Timer Restart */
+
+#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */
+#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */
+
+#define AT91_RTT_VR 0x08 /* Real-time Value Register */
+#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */
+
+#define AT91_RTT_SR 0x0c /* Real-time Status Register */
+#define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */
+#define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */
+
/*
* We store ALARM_DISABLED in ALMV to record that no alarm is set.
* It's also the reset value for that field.
@@ -58,19 +73,30 @@ struct sam9_rtc {
void __iomem *rtt;
struct rtc_device *rtcdev;
u32 imr;
- void __iomem *gpbr;
+ struct regmap *gpbr;
+ unsigned int gpbr_offset;
int irq;
+ struct clk *sclk;
};
#define rtt_readl(rtc, field) \
- __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
+ readl((rtc)->rtt + AT91_RTT_ ## field)
#define rtt_writel(rtc, field, val) \
- __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+ writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+
+static inline unsigned int gpbr_readl(struct sam9_rtc *rtc)
+{
+ unsigned int val;
+
+ regmap_read(rtc->gpbr, rtc->gpbr_offset, &val);
-#define gpbr_readl(rtc) \
- __raw_readl((rtc)->gpbr)
-#define gpbr_writel(rtc, val) \
- __raw_writel((val), (rtc)->gpbr)
+ return val;
+}
+
+static inline void gpbr_writel(struct sam9_rtc *rtc, unsigned int val)
+{
+ regmap_write(rtc->gpbr, rtc->gpbr_offset, val);
+}
/*
* Read current time and date in RTC
@@ -287,22 +313,22 @@ static const struct rtc_class_ops at91_rtc_ops = {
.alarm_irq_enable = at91_rtc_alarm_irq_enable,
};
+static struct regmap_config gpbr_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
/*
* Initialize and install RTC driver
*/
static int at91_rtc_probe(struct platform_device *pdev)
{
- struct resource *r, *r_gpbr;
+ struct resource *r;
struct sam9_rtc *rtc;
int ret, irq;
u32 mr;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!r || !r_gpbr) {
- dev_err(&pdev->dev, "need 2 ressources\n");
- return -ENODEV;
- }
+ unsigned int sclk_rate;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -321,24 +347,66 @@ static int at91_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, rtc);
- rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (!rtc->rtt) {
- dev_err(&pdev->dev, "failed to map registers, aborting.\n");
- return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rtc->rtt = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(rtc->rtt))
+ return PTR_ERR(rtc->rtt);
+
+ if (!pdev->dev.of_node) {
+ /*
+ * TODO: Remove this code chunk when removing non DT board
+ * support. Remember to remove the gpbr_regmap_config
+ * variable too.
+ */
+ void __iomem *gpbr;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ gpbr = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(gpbr))
+ return PTR_ERR(gpbr);
+
+ rtc->gpbr = regmap_init_mmio(NULL, gpbr,
+ &gpbr_regmap_config);
+ } else {
+ struct of_phandle_args args;
+
+ ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
+ "atmel,rtt-rtc-time-reg", 1, 0,
+ &args);
+ if (ret)
+ return ret;
+
+ rtc->gpbr = syscon_node_to_regmap(args.np);
+ rtc->gpbr_offset = args.args[0];
}
- rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start,
- resource_size(r_gpbr));
- if (!rtc->gpbr) {
- dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
+ if (IS_ERR(rtc->gpbr)) {
+ dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
return -ENOMEM;
}
+ rtc->sclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rtc->sclk))
+ return PTR_ERR(rtc->sclk);
+
+ sclk_rate = clk_get_rate(rtc->sclk);
+ if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) {
+ dev_err(&pdev->dev, "Invalid slow clock rate\n");
+ return -EINVAL;
+ }
+
+ ret = clk_prepare_enable(rtc->sclk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not enable slow clock\n");
+ return ret;
+ }
+
mr = rtt_readl(rtc, MR);
/* unless RTT is counting at 1 Hz, re-initialize it */
- if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
- mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
+ if ((mr & AT91_RTT_RTPRES) != sclk_rate) {
+ mr = AT91_RTT_RTTRST | (sclk_rate & AT91_RTT_RTPRES);
gpbr_writel(rtc, 0);
}
@@ -383,6 +451,9 @@ static int at91_rtc_remove(struct platform_device *pdev)
/* disable all interrupts */
rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+ if (!IS_ERR(rtc->sclk))
+ clk_disable_unprepare(rtc->sclk);
+
return 0;
}
@@ -440,14 +511,22 @@ static int at91_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
+#ifdef CONFIG_OF
+static const struct of_device_id at91_rtc_dt_ids[] = {
+ { .compatible = "atmel,at91sam9260-rtt" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
+#endif
+
static struct platform_driver at91_rtc_driver = {
.probe = at91_rtc_probe,
.remove = at91_rtc_remove,
.shutdown = at91_rtc_shutdown,
.driver = {
.name = "rtc-at91sam9",
- .owner = THIS_MODULE,
.pm = &at91_rtc_pm_ops,
+ .of_match_table = of_match_ptr(at91_rtc_dt_ids),
},
};
diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c
index fd25e2374d4e..84d6e026784d 100644
--- a/drivers/rtc/rtc-au1xxx.c
+++ b/drivers/rtc/rtc-au1xxx.c
@@ -117,7 +117,6 @@ out_err:
static struct platform_driver au1xrtc_driver = {
.driver = {
.name = "rtc-au1xxx",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index fe4bdb06a55a..3d44b11721ea 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -434,7 +434,6 @@ static SIMPLE_DEV_PM_OPS(bfin_rtc_pm_ops, bfin_rtc_suspend, bfin_rtc_resume);
static struct platform_driver bfin_rtc_driver = {
.driver = {
.name = "rtc-bfin",
- .owner = THIS_MODULE,
.pm = &bfin_rtc_pm_ops,
},
.probe = bfin_rtc_probe,
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
index fc0ff87aa5df..bd170cb3361c 100644
--- a/drivers/rtc/rtc-bq4802.c
+++ b/drivers/rtc/rtc-bq4802.c
@@ -192,7 +192,6 @@ MODULE_ALIAS("platform:rtc-bq4802");
static struct platform_driver bq4802_driver = {
.driver = {
.name = "rtc-bq4802",
- .owner = THIS_MODULE,
},
.probe = bq4802_probe,
};
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index 869cae273799..56343b2fbc68 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -267,7 +267,6 @@ static const struct of_device_id coh901331_dt_match[] = {
static struct platform_driver coh901331_driver = {
.driver = {
.name = "rtc-coh901331",
- .owner = THIS_MODULE,
.pm = &coh901331_pm_ops,
.of_match_table = coh901331_dt_match,
},
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
index e5c9486cf452..613c43b7e9ae 100644
--- a/drivers/rtc/rtc-da9052.c
+++ b/drivers/rtc/rtc-da9052.c
@@ -265,7 +265,6 @@ static struct platform_driver da9052_rtc_driver = {
.probe = da9052_rtc_probe,
.driver = {
.name = "da9052-rtc",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c
index a825491331c8..7ec0872d5e3b 100644
--- a/drivers/rtc/rtc-da9055.c
+++ b/drivers/rtc/rtc-da9055.c
@@ -391,7 +391,6 @@ static struct platform_driver da9055_rtc_driver = {
.probe = da9055_rtc_probe,
.driver = {
.name = "da9055-rtc",
- .owner = THIS_MODULE,
.pm = &da9055_rtc_pm_ops,
},
};
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
index 731ed1a97f59..7ffc5707f8b9 100644
--- a/drivers/rtc/rtc-da9063.c
+++ b/drivers/rtc/rtc-da9063.c
@@ -341,7 +341,6 @@ static struct platform_driver da9063_rtc_driver = {
.probe = da9063_rtc_probe,
.driver = {
.name = DA9063_DRVNAME_RTC,
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
index c0a3b59f65a2..c84f46168a52 100644
--- a/drivers/rtc/rtc-davinci.c
+++ b/drivers/rtc/rtc-davinci.c
@@ -550,7 +550,6 @@ static struct platform_driver davinci_rtc_driver = {
.remove = __exit_p(davinci_rtc_remove),
.driver = {
.name = "rtc_davinci",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c
index 1aca08394c47..94067f8eeb10 100644
--- a/drivers/rtc/rtc-dm355evm.c
+++ b/drivers/rtc/rtc-dm355evm.c
@@ -146,7 +146,6 @@ static int dm355evm_rtc_probe(struct platform_device *pdev)
static struct platform_driver rtc_dm355evm_driver = {
.probe = dm355evm_rtc_probe,
.driver = {
- .owner = THIS_MODULE,
.name = "rtc-dm355evm",
},
};
diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c
index 9c04fd2bc209..d16f550897b8 100644
--- a/drivers/rtc/rtc-ds1216.c
+++ b/drivers/rtc/rtc-ds1216.c
@@ -170,7 +170,6 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev)
static struct platform_driver ds1216_rtc_platform_driver = {
.driver = {
.name = "rtc-ds1216",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c
index 50e109b78252..2fe537f4e2bd 100644
--- a/drivers/rtc/rtc-ds1286.c
+++ b/drivers/rtc/rtc-ds1286.c
@@ -356,7 +356,6 @@ static int ds1286_probe(struct platform_device *pdev)
static struct platform_driver ds1286_platform_driver = {
.driver = {
.name = "rtc-ds1286",
- .owner = THIS_MODULE,
},
.probe = ds1286_probe,
};
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 07e8d79b4a09..6bef7a5233c4 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -244,7 +244,6 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
static struct platform_driver ds1302_platform_driver = {
.driver = {
.name = DRV_NAME,
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index bb43cf703efc..4ffabb322a9a 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -35,7 +35,7 @@ enum ds_type {
ds_1388,
ds_3231,
m41t00,
- mcp7941x,
+ mcp794xx,
rx_8025,
last_ds_type /* always last */
/* rs5c372 too? different address... */
@@ -46,7 +46,7 @@ enum ds_type {
#define DS1307_REG_SECS 0x00 /* 00-59 */
# define DS1307_BIT_CH 0x80
# define DS1340_BIT_nEOSC 0x80
-# define MCP7941X_BIT_ST 0x80
+# define MCP794XX_BIT_ST 0x80
#define DS1307_REG_MIN 0x01 /* 00-59 */
#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
# define DS1307_BIT_12HR 0x40 /* in REG_HOUR */
@@ -54,7 +54,7 @@ enum ds_type {
# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
#define DS1307_REG_WDAY 0x03 /* 01-07 */
-# define MCP7941X_BIT_VBATEN 0x08
+# define MCP794XX_BIT_VBATEN 0x08
#define DS1307_REG_MDAY 0x04 /* 01-31 */
#define DS1307_REG_MONTH 0x05 /* 01-12 */
# define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */
@@ -159,7 +159,7 @@ static struct chip_desc chips[last_ds_type] = {
[ds_3231] = {
.alarm = 1,
},
- [mcp7941x] = {
+ [mcp794xx] = {
.alarm = 1,
/* this is battery backed SRAM */
.nvram_offset = 0x20,
@@ -176,7 +176,8 @@ static const struct i2c_device_id ds1307_id[] = {
{ "ds1340", ds_1340 },
{ "ds3231", ds_3231 },
{ "m41t00", m41t00 },
- { "mcp7941x", mcp7941x },
+ { "mcp7940x", mcp794xx },
+ { "mcp7941x", mcp794xx },
{ "pt7c4338", ds_1307 },
{ "rx8025", rx_8025 },
{ }
@@ -439,14 +440,14 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
| DS1340_BIT_CENTURY;
break;
- case mcp7941x:
+ case mcp794xx:
/*
* these bits were cleared when preparing the date/time
* values and need to be set again before writing the
* buffer out to the device.
*/
- buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
- buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
+ buf[DS1307_REG_SECS] |= MCP794XX_BIT_ST;
+ buf[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
break;
default:
break;
@@ -614,26 +615,26 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
/*----------------------------------------------------------------------*/
/*
- * Alarm support for mcp7941x devices.
+ * Alarm support for mcp794xx devices.
*/
-#define MCP7941X_REG_CONTROL 0x07
-# define MCP7941X_BIT_ALM0_EN 0x10
-# define MCP7941X_BIT_ALM1_EN 0x20
-#define MCP7941X_REG_ALARM0_BASE 0x0a
-#define MCP7941X_REG_ALARM0_CTRL 0x0d
-#define MCP7941X_REG_ALARM1_BASE 0x11
-#define MCP7941X_REG_ALARM1_CTRL 0x14
-# define MCP7941X_BIT_ALMX_IF (1 << 3)
-# define MCP7941X_BIT_ALMX_C0 (1 << 4)
-# define MCP7941X_BIT_ALMX_C1 (1 << 5)
-# define MCP7941X_BIT_ALMX_C2 (1 << 6)
-# define MCP7941X_BIT_ALMX_POL (1 << 7)
-# define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \
- MCP7941X_BIT_ALMX_C1 | \
- MCP7941X_BIT_ALMX_C2)
-
-static void mcp7941x_work(struct work_struct *work)
+#define MCP794XX_REG_CONTROL 0x07
+# define MCP794XX_BIT_ALM0_EN 0x10
+# define MCP794XX_BIT_ALM1_EN 0x20
+#define MCP794XX_REG_ALARM0_BASE 0x0a
+#define MCP794XX_REG_ALARM0_CTRL 0x0d
+#define MCP794XX_REG_ALARM1_BASE 0x11
+#define MCP794XX_REG_ALARM1_CTRL 0x14
+# define MCP794XX_BIT_ALMX_IF (1 << 3)
+# define MCP794XX_BIT_ALMX_C0 (1 << 4)
+# define MCP794XX_BIT_ALMX_C1 (1 << 5)
+# define MCP794XX_BIT_ALMX_C2 (1 << 6)
+# define MCP794XX_BIT_ALMX_POL (1 << 7)
+# define MCP794XX_MSK_ALMX_MATCH (MCP794XX_BIT_ALMX_C0 | \
+ MCP794XX_BIT_ALMX_C1 | \
+ MCP794XX_BIT_ALMX_C2)
+
+static void mcp794xx_work(struct work_struct *work)
{
struct ds1307 *ds1307 = container_of(work, struct ds1307, work);
struct i2c_client *client = ds1307->client;
@@ -642,22 +643,22 @@ static void mcp7941x_work(struct work_struct *work)
mutex_lock(&ds1307->rtc->ops_lock);
/* Check and clear alarm 0 interrupt flag. */
- reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL);
+ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL);
if (reg < 0)
goto out;
- if (!(reg & MCP7941X_BIT_ALMX_IF))
+ if (!(reg & MCP794XX_BIT_ALMX_IF))
goto out;
- reg &= ~MCP7941X_BIT_ALMX_IF;
- ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg);
+ reg &= ~MCP794XX_BIT_ALMX_IF;
+ ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_ALARM0_CTRL, reg);
if (ret < 0)
goto out;
/* Disable alarm 0. */
- reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
if (reg < 0)
goto out;
- reg &= ~MCP7941X_BIT_ALM0_EN;
- ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+ reg &= ~MCP794XX_BIT_ALM0_EN;
+ ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
if (ret < 0)
goto out;
@@ -669,7 +670,7 @@ out:
mutex_unlock(&ds1307->rtc->ops_lock);
}
-static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -680,11 +681,11 @@ static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
return -EINVAL;
/* Read control and alarm 0 registers. */
- ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
if (ret < 0)
return ret;
- t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN);
+ t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN);
/* Report alarm 0 time assuming 24-hour and day-of-month modes. */
t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f);
@@ -701,14 +702,14 @@ static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
"enabled=%d polarity=%d irq=%d match=%d\n", __func__,
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
- !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL),
- !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF),
- (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4);
+ !!(ds1307->regs[6] & MCP794XX_BIT_ALMX_POL),
+ !!(ds1307->regs[6] & MCP794XX_BIT_ALMX_IF),
+ (ds1307->regs[6] & MCP794XX_MSK_ALMX_MATCH) >> 4);
return 0;
}
-static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -725,7 +726,7 @@ static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
t->enabled, t->pending);
/* Read control and alarm 0 registers. */
- ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
if (ret < 0)
return ret;
@@ -738,23 +739,23 @@ static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
regs[8] = bin2bcd(t->time.tm_mon) + 1;
/* Clear the alarm 0 interrupt flag. */
- regs[6] &= ~MCP7941X_BIT_ALMX_IF;
+ regs[6] &= ~MCP794XX_BIT_ALMX_IF;
/* Set alarm match: second, minute, hour, day, date, month. */
- regs[6] |= MCP7941X_MSK_ALMX_MATCH;
+ regs[6] |= MCP794XX_MSK_ALMX_MATCH;
if (t->enabled)
- regs[0] |= MCP7941X_BIT_ALM0_EN;
+ regs[0] |= MCP794XX_BIT_ALM0_EN;
else
- regs[0] &= ~MCP7941X_BIT_ALM0_EN;
+ regs[0] &= ~MCP794XX_BIT_ALM0_EN;
- ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
if (ret < 0)
return ret;
return 0;
}
-static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -763,24 +764,24 @@ static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
- reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
if (reg < 0)
return reg;
if (enabled)
- reg |= MCP7941X_BIT_ALM0_EN;
+ reg |= MCP794XX_BIT_ALM0_EN;
else
- reg &= ~MCP7941X_BIT_ALM0_EN;
+ reg &= ~MCP794XX_BIT_ALM0_EN;
- return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+ return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
}
-static const struct rtc_class_ops mcp7941x_rtc_ops = {
+static const struct rtc_class_ops mcp794xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
- .read_alarm = mcp7941x_read_alarm,
- .set_alarm = mcp7941x_set_alarm,
- .alarm_irq_enable = mcp7941x_alarm_irq_enable,
+ .read_alarm = mcp794xx_read_alarm,
+ .set_alarm = mcp794xx_set_alarm,
+ .alarm_irq_enable = mcp794xx_alarm_irq_enable,
};
/*----------------------------------------------------------------------*/
@@ -1049,10 +1050,10 @@ static int ds1307_probe(struct i2c_client *client,
case ds_1388:
ds1307->offset = 1; /* Seconds starts at 1 */
break;
- case mcp7941x:
- rtc_ops = &mcp7941x_rtc_ops;
+ case mcp794xx:
+ rtc_ops = &mcp794xx_rtc_ops;
if (ds1307->client->irq > 0 && chip->alarm) {
- INIT_WORK(&ds1307->work, mcp7941x_work);
+ INIT_WORK(&ds1307->work, mcp794xx_work);
want_irq = true;
}
break;
@@ -1117,18 +1118,18 @@ read_rtc:
dev_warn(&client->dev, "SET TIME!\n");
}
break;
- case mcp7941x:
+ case mcp794xx:
/* make sure that the backup battery is enabled */
- if (!(ds1307->regs[DS1307_REG_WDAY] & MCP7941X_BIT_VBATEN)) {
+ if (!(ds1307->regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
i2c_smbus_write_byte_data(client, DS1307_REG_WDAY,
ds1307->regs[DS1307_REG_WDAY]
- | MCP7941X_BIT_VBATEN);
+ | MCP794XX_BIT_VBATEN);
}
/* clock halted? turn it on, so clock can tick. */
- if (!(tmp & MCP7941X_BIT_ST)) {
+ if (!(tmp & MCP794XX_BIT_ST)) {
i2c_smbus_write_byte_data(client, DS1307_REG_SECS,
- MCP7941X_BIT_ST);
+ MCP794XX_BIT_ST);
dev_warn(&client->dev, "SET TIME!\n");
goto read_rtc;
}
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 9e6e14fb53d7..8605fde394b2 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -4,6 +4,7 @@
* Based on code by Randy Vinson <rvinson@mvista.com>,
* which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>.
*
+ * Copyright (C) 2014 Rose Technology
* Copyright (C) 2006-2007 Freescale Semiconductor
*
* 2005 (c) MontaVista Software, Inc. This file is licensed under
@@ -26,6 +27,13 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/pm.h>
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/miscdevice.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+#endif
#define DS1374_REG_TOD0 0x00 /* Time of Day */
#define DS1374_REG_TOD1 0x01
@@ -49,6 +57,14 @@ static const struct i2c_device_id ds1374_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ds1374_id);
+#ifdef CONFIG_OF
+static const struct of_device_id ds1374_of_match[] = {
+ { .compatible = "dallas,ds1374" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ds1374_of_match);
+#endif
+
struct ds1374 {
struct i2c_client *client;
struct rtc_device *rtc;
@@ -162,6 +178,7 @@ static int ds1374_set_time(struct device *dev, struct rtc_time *time)
return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4);
}
+#ifndef CONFIG_RTC_DRV_DS1374_WDT
/* The ds1374 has a decrementer for an alarm, rather than a comparator.
* If the time of day is changed, then the alarm will need to be
* reset.
@@ -263,6 +280,7 @@ out:
mutex_unlock(&ds1374->mutex);
return ret;
}
+#endif
static irqreturn_t ds1374_irq(int irq, void *dev_id)
{
@@ -307,6 +325,7 @@ unlock:
mutex_unlock(&ds1374->mutex);
}
+#ifndef CONFIG_RTC_DRV_DS1374_WDT
static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -331,15 +350,260 @@ out:
mutex_unlock(&ds1374->mutex);
return ret;
}
+#endif
static const struct rtc_class_ops ds1374_rtc_ops = {
.read_time = ds1374_read_time,
.set_time = ds1374_set_time,
+#ifndef CONFIG_RTC_DRV_DS1374_WDT
.read_alarm = ds1374_read_alarm,
.set_alarm = ds1374_set_alarm,
.alarm_irq_enable = ds1374_alarm_irq_enable,
+#endif
+};
+
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+/*
+ *****************************************************************************
+ *
+ * Watchdog Driver
+ *
+ *****************************************************************************
+ */
+static struct i2c_client *save_client;
+/* Default margin */
+#define WD_TIMO 131762
+
+#define DRV_NAME "DS1374 Watchdog"
+
+static int wdt_margin = WD_TIMO;
+static unsigned long wdt_is_open;
+module_param(wdt_margin, int, 0);
+MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 32s)");
+
+static const struct watchdog_info ds1374_wdt_info = {
+ .identity = "DS1374 WTD",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
};
+static int ds1374_wdt_settimeout(unsigned int timeout)
+{
+ int ret = -ENOIOCTLCMD;
+ int cr;
+
+ ret = cr = i2c_smbus_read_byte_data(save_client, DS1374_REG_CR);
+ if (ret < 0)
+ goto out;
+
+ /* Disable any existing watchdog/alarm before setting the new one */
+ cr &= ~DS1374_REG_CR_WACE;
+
+ ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
+ if (ret < 0)
+ goto out;
+
+ /* Set new watchdog time */
+ ret = ds1374_write_rtc(save_client, timeout, DS1374_REG_WDALM0, 3);
+ if (ret) {
+ pr_info("rtc-ds1374 - couldn't set new watchdog time\n");
+ goto out;
+ }
+
+ /* Enable watchdog timer */
+ cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_WDALM;
+ cr &= ~DS1374_REG_CR_AIE;
+
+ ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
+ if (ret < 0)
+ goto out;
+
+ return 0;
+out:
+ return ret;
+}
+
+
+/*
+ * Reload the watchdog timer. (ie, pat the watchdog)
+ */
+static void ds1374_wdt_ping(void)
+{
+ u32 val;
+ int ret = 0;
+
+ ret = ds1374_read_rtc(save_client, &val, DS1374_REG_WDALM0, 3);
+ if (ret)
+ pr_info("WD TICK FAIL!!!!!!!!!! %i\n", ret);
+}
+
+static void ds1374_wdt_disable(void)
+{
+ int ret = -ENOIOCTLCMD;
+ int cr;
+
+ cr = i2c_smbus_read_byte_data(save_client, DS1374_REG_CR);
+ /* Disable watchdog timer */
+ cr &= ~DS1374_REG_CR_WACE;
+
+ ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int ds1374_wdt_open(struct inode *inode, struct file *file)
+{
+ struct ds1374 *ds1374 = i2c_get_clientdata(save_client);
+
+ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+ mutex_lock(&ds1374->mutex);
+ if (test_and_set_bit(0, &wdt_is_open)) {
+ mutex_unlock(&ds1374->mutex);
+ return -EBUSY;
+ }
+ /*
+ * Activate
+ */
+ wdt_is_open = 1;
+ mutex_unlock(&ds1374->mutex);
+ return nonseekable_open(inode, file);
+ }
+ return -ENODEV;
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int ds1374_wdt_release(struct inode *inode, struct file *file)
+{
+ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR)
+ clear_bit(0, &wdt_is_open);
+
+ return 0;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t ds1374_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ ds1374_wdt_ping();
+ return 1;
+ }
+ return 0;
+}
+
+static ssize_t ds1374_wdt_read(struct file *file, char __user *data,
+ size_t len, loff_t *ppos)
+{
+ return 0;
+}
+
+/*
+ * Handle commands from user-space.
+ */
+static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int new_margin, options;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info __user *)arg,
+ &ds1374_wdt_info, sizeof(ds1374_wdt_info)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, (int __user *)arg);
+ case WDIOC_KEEPALIVE:
+ ds1374_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int __user *)arg))
+ return -EFAULT;
+
+ if (new_margin < 1 || new_margin > 16777216)
+ return -EINVAL;
+
+ wdt_margin = new_margin;
+ ds1374_wdt_settimeout(new_margin);
+ ds1374_wdt_ping();
+ /* fallthrough */
+ case WDIOC_GETTIMEOUT:
+ return put_user(wdt_margin, (int __user *)arg);
+ case WDIOC_SETOPTIONS:
+ if (copy_from_user(&options, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ pr_info("rtc-ds1374: disable watchdog\n");
+ ds1374_wdt_disable();
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ pr_info("rtc-ds1374: enable watchdog\n");
+ ds1374_wdt_settimeout(wdt_margin);
+ ds1374_wdt_ping();
+ }
+
+ return -EINVAL;
+ }
+ return -ENOTTY;
+}
+
+static long ds1374_wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+ struct ds1374 *ds1374 = i2c_get_clientdata(save_client);
+
+ mutex_lock(&ds1374->mutex);
+ ret = ds1374_wdt_ioctl(file, cmd, arg);
+ mutex_unlock(&ds1374->mutex);
+
+ return ret;
+}
+
+static int ds1374_wdt_notify_sys(struct notifier_block *this,
+ unsigned long code, void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ /* Disable Watchdog */
+ ds1374_wdt_disable();
+ return NOTIFY_DONE;
+}
+
+static const struct file_operations ds1374_wdt_fops = {
+ .owner = THIS_MODULE,
+ .read = ds1374_wdt_read,
+ .unlocked_ioctl = ds1374_wdt_unlocked_ioctl,
+ .write = ds1374_wdt_write,
+ .open = ds1374_wdt_open,
+ .release = ds1374_wdt_release,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice ds1374_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &ds1374_wdt_fops,
+};
+
+static struct notifier_block ds1374_wdt_notifier = {
+ .notifier_call = ds1374_wdt_notify_sys,
+};
+
+#endif /*CONFIG_RTC_DRV_DS1374_WDT*/
+/*
+ *****************************************************************************
+ *
+ * Driver Interface
+ *
+ *****************************************************************************
+ */
static int ds1374_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -378,12 +642,33 @@ static int ds1374_probe(struct i2c_client *client,
return PTR_ERR(ds1374->rtc);
}
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+ save_client = client;
+ ret = misc_register(&ds1374_miscdev);
+ if (ret)
+ return ret;
+ ret = register_reboot_notifier(&ds1374_wdt_notifier);
+ if (ret) {
+ misc_deregister(&ds1374_miscdev);
+ return ret;
+ }
+ ds1374_wdt_settimeout(131072);
+#endif
+
return 0;
}
static int ds1374_remove(struct i2c_client *client)
{
struct ds1374 *ds1374 = i2c_get_clientdata(client);
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+ int res;
+
+ res = misc_deregister(&ds1374_miscdev);
+ if (!res)
+ ds1374_miscdev.parent = NULL;
+ unregister_reboot_notifier(&ds1374_wdt_notifier);
+#endif
if (client->irq > 0) {
mutex_lock(&ds1374->mutex);
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index b13d1399b81a..7415c2b4d6e8 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -561,7 +561,6 @@ static struct platform_driver ds1511_rtc_driver = {
.remove = ds1511_rtc_remove,
.driver = {
.name = "ds1511",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index ab56893aac73..a24e091bcb41 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -351,7 +351,6 @@ static struct platform_driver ds1553_rtc_driver = {
.remove = ds1553_rtc_remove,
.driver = {
.name = "rtc-ds1553",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 9822715db8ba..0f8d8ace1515 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -230,7 +230,6 @@ static struct platform_driver ds1742_rtc_driver = {
.remove = ds1742_rtc_remove,
.driver = {
.name = "rtc-ds1742",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(ds1742_rtc_of_match),
},
};
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
index fc209dc4e245..7885edd3d507 100644
--- a/drivers/rtc/rtc-ds2404.c
+++ b/drivers/rtc/rtc-ds2404.c
@@ -274,7 +274,6 @@ static struct platform_driver rtc_device_driver = {
.remove = rtc_remove,
.driver = {
.name = "ds2404",
- .owner = THIS_MODULE,
},
};
module_platform_driver(rtc_device_driver);
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index 53b589dc34eb..b37b0c80bd5a 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -226,7 +226,6 @@ static int __init efi_rtc_probe(struct platform_device *dev)
static struct platform_driver efi_rtc_driver = {
.driver = {
.name = "rtc-efi",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 5e4f5dc40ba5..de325d68c7e4 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -174,7 +174,6 @@ static int ep93xx_rtc_remove(struct platform_device *pdev)
static struct platform_driver ep93xx_rtc_driver = {
.driver = {
.name = "ep93xx-rtc",
- .owner = THIS_MODULE,
},
.probe = ep93xx_rtc_probe,
.remove = ep93xx_rtc_remove,
diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c
index 9b6725ebbfb2..e782ebd719b2 100644
--- a/drivers/rtc/rtc-generic.c
+++ b/drivers/rtc/rtc-generic.c
@@ -51,7 +51,6 @@ static int __init generic_rtc_probe(struct platform_device *dev)
static struct platform_driver generic_rtc_driver = {
.driver = {
.name = "rtc-generic",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c
index 965a9da70867..ae7c2ba440cf 100644
--- a/drivers/rtc/rtc-hid-sensor-time.c
+++ b/drivers/rtc/rtc-hid-sensor-time.c
@@ -331,7 +331,6 @@ static struct platform_driver hid_time_platform_driver = {
.id_table = hid_time_ids,
.driver = {
.name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
},
.probe = hid_time_probe,
.remove = hid_time_remove,
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index cd741c77e085..42f5570f42f8 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -499,7 +499,6 @@ MODULE_DEVICE_TABLE(of, dryice_dt_ids);
static struct platform_driver dryice_rtc_driver = {
.driver = {
.name = "imxdi_rtc",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(dryice_dt_ids),
},
.remove = __exit_p(dryice_rtc_remove),
diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c
index 455b601d731d..6e1fcfb5d7e6 100644
--- a/drivers/rtc/rtc-isl12057.c
+++ b/drivers/rtc/rtc-isl12057.c
@@ -41,6 +41,7 @@
#define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */
#define ISL12057_REG_RTC_DT 0x04 /* Date */
#define ISL12057_REG_RTC_MO 0x05 /* Month */
+#define ISL12057_REG_RTC_MO_CEN BIT(7) /* Century bit */
#define ISL12057_REG_RTC_YR 0x06 /* Year */
#define ISL12057_RTC_SEC_LEN 7
@@ -88,7 +89,7 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs)
tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]);
if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */
- tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x0f);
+ tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x1f);
if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM)
tm->tm_hour += 12;
} else { /* 24 hour mode */
@@ -97,26 +98,37 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs)
tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]);
tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */
- tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO]) - 1; /* starts at 1 */
+ tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO] & 0x1f) - 1; /* ditto */
tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100;
+
+ /* Check if years register has overflown from 99 to 00 */
+ if (regs[ISL12057_REG_RTC_MO] & ISL12057_REG_RTC_MO_CEN)
+ tm->tm_year += 100;
}
static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm)
{
+ u8 century_bit;
+
/*
* The clock has an 8 bit wide bcd-coded register for the year.
+ * It also has a century bit encoded in MO flag which provides
+ * information about overflow of year register from 99 to 00.
* tm_year is an offset from 1900 and we are interested in the
- * 2000-2099 range, so any value less than 100 is invalid.
+ * 2000-2199 range, so any value less than 100 or larger than
+ * 299 is invalid.
*/
- if (tm->tm_year < 100)
+ if (tm->tm_year < 100 || tm->tm_year > 299)
return -EINVAL;
+ century_bit = (tm->tm_year > 199) ? ISL12057_REG_RTC_MO_CEN : 0;
+
regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec);
regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min);
regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */
regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday);
- regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1);
- regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year - 100);
+ regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1) | century_bit;
+ regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year % 100);
regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1);
return 0;
@@ -152,17 +164,33 @@ static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct isl12057_rtc_data *data = dev_get_drvdata(dev);
u8 regs[ISL12057_RTC_SEC_LEN];
+ unsigned int sr;
int ret;
mutex_lock(&data->lock);
+ ret = regmap_read(data->regmap, ISL12057_REG_SR, &sr);
+ if (ret) {
+ dev_err(dev, "%s: unable to read oscillator status flag (%d)\n",
+ __func__, ret);
+ goto out;
+ } else {
+ if (sr & ISL12057_REG_SR_OSF) {
+ ret = -ENODATA;
+ goto out;
+ }
+ }
+
ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs,
ISL12057_RTC_SEC_LEN);
+ if (ret)
+ dev_err(dev, "%s: unable to read RTC time section (%d)\n",
+ __func__, ret);
+
+out:
mutex_unlock(&data->lock);
- if (ret) {
- dev_err(dev, "%s: RTC read failed\n", __func__);
+ if (ret)
return ret;
- }
isl12057_rtc_regs_to_tm(tm, regs);
@@ -182,10 +210,24 @@ static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm)
mutex_lock(&data->lock);
ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs,
ISL12057_RTC_SEC_LEN);
- mutex_unlock(&data->lock);
+ if (ret) {
+ dev_err(dev, "%s: unable to write RTC time section (%d)\n",
+ __func__, ret);
+ goto out;
+ }
- if (ret)
- dev_err(dev, "%s: RTC write failed\n", __func__);
+ /*
+ * Now that RTC time has been updated, let's clear oscillator
+ * failure flag, if needed.
+ */
+ ret = regmap_update_bits(data->regmap, ISL12057_REG_SR,
+ ISL12057_REG_SR_OSF, 0);
+ if (ret < 0)
+ dev_err(dev, "%s: unable to clear osc. failure bit (%d)\n",
+ __func__, ret);
+
+out:
+ mutex_unlock(&data->lock);
return ret;
}
@@ -203,15 +245,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap)
ret = regmap_update_bits(regmap, ISL12057_REG_INT,
ISL12057_REG_INT_EOSC, 0);
if (ret < 0) {
- dev_err(dev, "Unable to enable oscillator\n");
- return ret;
- }
-
- /* Clear oscillator failure bit if needed */
- ret = regmap_update_bits(regmap, ISL12057_REG_SR,
- ISL12057_REG_SR_OSF, 0);
- if (ret < 0) {
- dev_err(dev, "Unable to clear oscillator failure bit\n");
+ dev_err(dev, "%s: unable to enable oscillator (%d)\n",
+ __func__, ret);
return ret;
}
@@ -219,7 +254,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap)
ret = regmap_update_bits(regmap, ISL12057_REG_SR,
ISL12057_REG_SR_A1F, 0);
if (ret < 0) {
- dev_err(dev, "Unable to clear alarm bit\n");
+ dev_err(dev, "%s: unable to clear alarm bit (%d)\n",
+ __func__, ret);
return ret;
}
@@ -253,7 +289,8 @@ static int isl12057_probe(struct i2c_client *client,
regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
- dev_err(dev, "regmap allocation failed: %d\n", ret);
+ dev_err(dev, "%s: regmap allocation failed (%d)\n",
+ __func__, ret);
return ret;
}
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
index 08f5160fb6d4..b2bcfc0bf2e5 100644
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -299,7 +299,6 @@ static struct platform_driver jz4740_rtc_driver = {
.probe = jz4740_rtc_probe,
.driver = {
.name = "jz4740-rtc",
- .owner = THIS_MODULE,
.pm = JZ4740_RTC_PM_OPS,
},
};
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index c4cf05731118..e6bfb9c42a10 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -45,16 +45,20 @@ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
}
EXPORT_SYMBOL(rtc_year_days);
+
/*
+ * rtc_time_to_tm64 - Converts time64_t to rtc_time.
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
*/
-void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
{
unsigned int month, year;
+ unsigned long secs;
int days;
- days = time / 86400;
- time -= (unsigned int) days * 86400;
+ /* time must be positive */
+ days = div_s64(time, 86400);
+ secs = time - (unsigned int) days * 86400;
/* day of the week, 1970-01-01 was a Thursday */
tm->tm_wday = (days + 4) % 7;
@@ -81,14 +85,14 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
tm->tm_mon = month;
tm->tm_mday = days + 1;
- tm->tm_hour = time / 3600;
- time -= tm->tm_hour * 3600;
- tm->tm_min = time / 60;
- tm->tm_sec = time - tm->tm_min * 60;
+ tm->tm_hour = secs / 3600;
+ secs -= tm->tm_hour * 3600;
+ tm->tm_min = secs / 60;
+ tm->tm_sec = secs - tm->tm_min * 60;
tm->tm_isdst = 0;
}
-EXPORT_SYMBOL(rtc_time_to_tm);
+EXPORT_SYMBOL(rtc_time64_to_tm);
/*
* Does the rtc_time represent a valid date/time?
@@ -109,24 +113,22 @@ int rtc_valid_tm(struct rtc_time *tm)
EXPORT_SYMBOL(rtc_valid_tm);
/*
+ * rtc_tm_to_time64 - Converts rtc_time to time64_t.
* Convert Gregorian date to seconds since 01-01-1970 00:00:00.
*/
-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+time64_t rtc_tm_to_time64(struct rtc_time *tm)
{
- *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
- return 0;
}
-EXPORT_SYMBOL(rtc_tm_to_time);
+EXPORT_SYMBOL(rtc_tm_to_time64);
/*
* Convert rtc_time to ktime
*/
ktime_t rtc_tm_to_ktime(struct rtc_time tm)
{
- time_t time;
- rtc_tm_to_time(&tm, &time);
- return ktime_set(time, 0);
+ return ktime_set(rtc_tm_to_time64(&tm), 0);
}
EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
@@ -135,14 +137,14 @@ EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
*/
struct rtc_time rtc_ktime_to_tm(ktime_t kt)
{
- struct timespec ts;
+ struct timespec64 ts;
struct rtc_time ret;
- ts = ktime_to_timespec(kt);
+ ts = ktime_to_timespec64(kt);
/* Round up any ns */
if (ts.tv_nsec)
ts.tv_sec++;
- rtc_time_to_tm(ts.tv_sec, &ret);
+ rtc_time64_to_tm(ts.tv_sec, &ret);
return ret;
}
EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c
index 4ff6c73253b3..e20e7bd822e0 100644
--- a/drivers/rtc/rtc-lp8788.c
+++ b/drivers/rtc/rtc-lp8788.c
@@ -316,7 +316,6 @@ static struct platform_driver lp8788_rtc_driver = {
.probe = lp8788_rtc_probe,
.driver = {
.name = LP8788_DEV_RTC,
- .owner = THIS_MODULE,
},
};
module_platform_driver(lp8788_rtc_driver);
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
index f130c08c98f8..f923f7324788 100644
--- a/drivers/rtc/rtc-lpc32xx.c
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -379,7 +379,6 @@ static struct platform_driver lpc32xx_rtc_driver = {
.remove = lpc32xx_rtc_remove,
.driver = {
.name = RTC_NAME,
- .owner = THIS_MODULE,
.pm = LPC32XX_RTC_PM_OPS,
.of_match_table = of_match_ptr(lpc32xx_rtc_match),
},
diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c
index 682ecb094839..8445e564094a 100644
--- a/drivers/rtc/rtc-ls1x.c
+++ b/drivers/rtc/rtc-ls1x.c
@@ -188,7 +188,6 @@ err:
static struct platform_driver ls1x_rtc_driver = {
.driver = {
.name = "ls1x-rtc",
- .owner = THIS_MODULE,
},
.probe = ls1x_rtc_probe,
};
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
index 411adb3f86a1..c62b51217ecf 100644
--- a/drivers/rtc/rtc-m48t35.c
+++ b/drivers/rtc/rtc-m48t35.c
@@ -181,7 +181,6 @@ static int m48t35_probe(struct platform_device *pdev)
static struct platform_driver m48t35_platform_driver = {
.driver = {
.name = "rtc-m48t35",
- .owner = THIS_MODULE,
},
.probe = m48t35_probe,
};
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 11880c1e9dac..90abb5bd589c 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -504,7 +504,6 @@ MODULE_ALIAS("platform:rtc-m48t59");
static struct platform_driver m48t59_rtc_driver = {
.driver = {
.name = "rtc-m48t59",
- .owner = THIS_MODULE,
},
.probe = m48t59_rtc_probe,
.remove = m48t59_rtc_remove,
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index 32f64c942621..a17b7a3ceece 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -169,7 +169,6 @@ static int m48t86_rtc_probe(struct platform_device *dev)
static struct platform_driver m48t86_rtc_platform_driver = {
.driver = {
.name = "rtc-m48t86",
- .owner = THIS_MODULE,
},
.probe = m48t86_rtc_probe,
};
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index cf73e969c8cc..9d71328e59b9 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -513,7 +513,6 @@ static const struct platform_device_id rtc_id[] = {
static struct platform_driver max77686_rtc_driver = {
.driver = {
.name = "max77686-rtc",
- .owner = THIS_MODULE,
.pm = &max77686_rtc_pm_ops,
},
.probe = max77686_rtc_probe,
diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c
index 566471335b33..7f8adf8d6feb 100644
--- a/drivers/rtc/rtc-max77802.c
+++ b/drivers/rtc/rtc-max77802.c
@@ -488,7 +488,6 @@ static const struct platform_device_id rtc_id[] = {
static struct platform_driver max77802_rtc_driver = {
.driver = {
.name = "max77802-rtc",
- .owner = THIS_MODULE,
.pm = &max77802_rtc_pm_ops,
},
.probe = max77802_rtc_probe,
diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c
index 3032178bd9e6..19c29b72598d 100644
--- a/drivers/rtc/rtc-max8907.c
+++ b/drivers/rtc/rtc-max8907.c
@@ -215,7 +215,6 @@ static int max8907_rtc_probe(struct platform_device *pdev)
static struct platform_driver max8907_rtc_driver = {
.driver = {
.name = "max8907-rtc",
- .owner = THIS_MODULE,
},
.probe = max8907_rtc_probe,
};
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c
index 951d1a78e190..16d129a0bb3b 100644
--- a/drivers/rtc/rtc-max8925.c
+++ b/drivers/rtc/rtc-max8925.c
@@ -314,7 +314,6 @@ static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_re
static struct platform_driver max8925_rtc_driver = {
.driver = {
.name = "max8925-rtc",
- .owner = THIS_MODULE,
.pm = &max8925_rtc_pm_ops,
},
.probe = max8925_rtc_probe,
diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c
index 0777c01b58e0..67fbe559d535 100644
--- a/drivers/rtc/rtc-max8997.c
+++ b/drivers/rtc/rtc-max8997.c
@@ -523,7 +523,6 @@ static const struct platform_device_id rtc_id[] = {
static struct platform_driver max8997_rtc_driver = {
.driver = {
.name = "max8997-rtc",
- .owner = THIS_MODULE,
},
.probe = max8997_rtc_probe,
.shutdown = max8997_rtc_shutdown,
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c
index f098ad8382de..5726ef7bd56e 100644
--- a/drivers/rtc/rtc-max8998.c
+++ b/drivers/rtc/rtc-max8998.c
@@ -313,7 +313,6 @@ static const struct platform_device_id max8998_rtc_id[] = {
static struct platform_driver max8998_rtc_driver = {
.driver = {
.name = "max8998-rtc",
- .owner = THIS_MODULE,
},
.probe = max8998_rtc_probe,
.id_table = max8998_rtc_id,
diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c
index 0765606a2d14..5bce904b7ee6 100644
--- a/drivers/rtc/rtc-mc13xxx.c
+++ b/drivers/rtc/rtc-mc13xxx.c
@@ -370,7 +370,6 @@ static struct platform_driver mc13xxx_rtc_driver = {
.remove = mc13xxx_rtc_remove,
.driver = {
.name = DRIVER_NAME,
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c
index c31846238871..73759c9a4527 100644
--- a/drivers/rtc/rtc-moxart.c
+++ b/drivers/rtc/rtc-moxart.c
@@ -317,7 +317,6 @@ static struct platform_driver moxart_rtc_driver = {
.probe = moxart_rtc_probe,
.driver = {
.name = "moxart-rtc",
- .owner = THIS_MODULE,
.of_match_table = moxart_rtc_match,
},
};
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index 3b965ad6f4d5..1767e18d5bd4 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -411,7 +411,6 @@ static const struct of_device_id mpc5121_rtc_match[] = {
static struct platform_driver mpc5121_rtc_driver = {
.driver = {
.name = "mpc5121-rtc",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(mpc5121_rtc_match),
},
.probe = mpc5121_rtc_probe,
diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c
index 426cb5189daa..9bf877bdf836 100644
--- a/drivers/rtc/rtc-msm6242.c
+++ b/drivers/rtc/rtc-msm6242.c
@@ -225,7 +225,6 @@ static int __init msm6242_rtc_probe(struct platform_device *pdev)
static struct platform_driver msm6242_rtc_driver = {
.driver = {
.name = "rtc-msm6242",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index 6aaec2fc7c0d..423762241042 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -329,7 +329,6 @@ static struct platform_driver mv_rtc_driver = {
.remove = __exit_p(mv_rtc_remove),
.driver = {
.name = "rtc-mv",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(rtc_mv_of_match_table),
},
};
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
index 419874fefa4b..3c3f8d10ab43 100644
--- a/drivers/rtc/rtc-mxc.c
+++ b/drivers/rtc/rtc-mxc.c
@@ -489,7 +489,6 @@ static struct platform_driver mxc_rtc_driver = {
.driver = {
.name = "mxc_rtc",
.pm = &mxc_rtc_pm_ops,
- .owner = THIS_MODULE,
},
.id_table = imx_rtc_devtype,
.probe = mxc_rtc_probe,
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c
index a53da0958e95..09fc1c19f0df 100644
--- a/drivers/rtc/rtc-nuc900.c
+++ b/drivers/rtc/rtc-nuc900.c
@@ -262,7 +262,6 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev)
static struct platform_driver nuc900_rtc_driver = {
.driver = {
.name = "nuc900-rtc",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 21142e6574a9..8e5851aa4369 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -1,10 +1,11 @@
/*
- * TI OMAP1 Real Time Clock interface for Linux
+ * TI OMAP Real Time Clock interface for Linux
*
* Copyright (C) 2003 MontaVista Software, Inc.
* Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
*
* Copyright (C) 2006 David Brownell (new RTC framework)
+ * Copyright (C) 2014 Johan Hovold <johan@kernel.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,7 +26,8 @@
#include <linux/pm_runtime.h>
#include <linux/io.h>
-/* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock
+/*
+ * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
* with century-range alarm matching, driven by the 32kHz clock.
*
* The main user-visible ways it differs from PC RTCs are by omitting
@@ -39,10 +41,6 @@
* the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment.
*/
-#define DRIVER_NAME "omap_rtc"
-
-#define OMAP_RTC_BASE 0xfffb4800
-
/* RTC registers */
#define OMAP_RTC_SECONDS_REG 0x00
#define OMAP_RTC_MINUTES_REG 0x04
@@ -72,6 +70,15 @@
#define OMAP_RTC_IRQWAKEEN 0x7c
+#define OMAP_RTC_ALARM2_SECONDS_REG 0x80
+#define OMAP_RTC_ALARM2_MINUTES_REG 0x84
+#define OMAP_RTC_ALARM2_HOURS_REG 0x88
+#define OMAP_RTC_ALARM2_DAYS_REG 0x8c
+#define OMAP_RTC_ALARM2_MONTHS_REG 0x90
+#define OMAP_RTC_ALARM2_YEARS_REG 0x94
+
+#define OMAP_RTC_PMIC_REG 0x98
+
/* OMAP_RTC_CTRL_REG bit fields: */
#define OMAP_RTC_CTRL_SPLIT BIT(7)
#define OMAP_RTC_CTRL_DISABLE BIT(6)
@@ -84,6 +91,7 @@
/* OMAP_RTC_STATUS_REG bit fields: */
#define OMAP_RTC_STATUS_POWER_UP BIT(7)
+#define OMAP_RTC_STATUS_ALARM2 BIT(7)
#define OMAP_RTC_STATUS_ALARM BIT(6)
#define OMAP_RTC_STATUS_1D_EVENT BIT(5)
#define OMAP_RTC_STATUS_1H_EVENT BIT(4)
@@ -93,6 +101,7 @@
#define OMAP_RTC_STATUS_BUSY BIT(0)
/* OMAP_RTC_INTERRUPTS_REG bit fields: */
+#define OMAP_RTC_INTERRUPTS_IT_ALARM2 BIT(4)
#define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3)
#define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2)
@@ -102,61 +111,82 @@
/* OMAP_RTC_IRQWAKEEN bit fields: */
#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1)
+/* OMAP_RTC_PMIC bit fields: */
+#define OMAP_RTC_PMIC_POWER_EN_EN BIT(16)
+
/* OMAP_RTC_KICKER values */
#define KICK0_VALUE 0x83e70b13
#define KICK1_VALUE 0x95a4f1e0
-#define OMAP_RTC_HAS_KICKER BIT(0)
-
-/*
- * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup
- * generation for event Alarm.
- */
-#define OMAP_RTC_HAS_IRQWAKEEN BIT(1)
+struct omap_rtc_device_type {
+ bool has_32kclk_en;
+ bool has_kicker;
+ bool has_irqwakeen;
+ bool has_pmic_mode;
+ bool has_power_up_reset;
+};
-/*
- * Some RTC IP revisions (like those in AM335x and DRA7x) need
- * the 32KHz clock to be explicitly enabled.
- */
-#define OMAP_RTC_HAS_32KCLK_EN BIT(2)
+struct omap_rtc {
+ struct rtc_device *rtc;
+ void __iomem *base;
+ int irq_alarm;
+ int irq_timer;
+ u8 interrupts_reg;
+ bool is_pmic_controller;
+ const struct omap_rtc_device_type *type;
+};
-static void __iomem *rtc_base;
+static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg)
+{
+ return readb(rtc->base + reg);
+}
-#define rtc_read(addr) readb(rtc_base + (addr))
-#define rtc_write(val, addr) writeb(val, rtc_base + (addr))
+static inline u32 rtc_readl(struct omap_rtc *rtc, unsigned int reg)
+{
+ return readl(rtc->base + reg);
+}
-#define rtc_writel(val, addr) writel(val, rtc_base + (addr))
+static inline void rtc_write(struct omap_rtc *rtc, unsigned int reg, u8 val)
+{
+ writeb(val, rtc->base + reg);
+}
+static inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val)
+{
+ writel(val, rtc->base + reg);
+}
-/* we rely on the rtc framework to handle locking (rtc->ops_lock),
+/*
+ * We rely on the rtc framework to handle locking (rtc->ops_lock),
* so the only other requirement is that register accesses which
* require BUSY to be clear are made with IRQs locally disabled
*/
-static void rtc_wait_not_busy(void)
+static void rtc_wait_not_busy(struct omap_rtc *rtc)
{
- int count = 0;
- u8 status;
+ int count;
+ u8 status;
/* BUSY may stay active for 1/32768 second (~30 usec) */
for (count = 0; count < 50; count++) {
- status = rtc_read(OMAP_RTC_STATUS_REG);
- if ((status & (u8)OMAP_RTC_STATUS_BUSY) == 0)
+ status = rtc_read(rtc, OMAP_RTC_STATUS_REG);
+ if (!(status & OMAP_RTC_STATUS_BUSY))
break;
udelay(1);
}
/* now we have ~15 usec to read/write various registers */
}
-static irqreturn_t rtc_irq(int irq, void *rtc)
+static irqreturn_t rtc_irq(int irq, void *dev_id)
{
- unsigned long events = 0;
- u8 irq_data;
+ struct omap_rtc *rtc = dev_id;
+ unsigned long events = 0;
+ u8 irq_data;
- irq_data = rtc_read(OMAP_RTC_STATUS_REG);
+ irq_data = rtc_read(rtc, OMAP_RTC_STATUS_REG);
/* alarm irq? */
if (irq_data & OMAP_RTC_STATUS_ALARM) {
- rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+ rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM);
events |= RTC_IRQF | RTC_AF;
}
@@ -164,23 +194,21 @@ static irqreturn_t rtc_irq(int irq, void *rtc)
if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
events |= RTC_IRQF | RTC_UF;
- rtc_update_irq(rtc, 1, events);
+ rtc_update_irq(rtc->rtc, 1, events);
return IRQ_HANDLED;
}
static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
u8 reg, irqwake_reg = 0;
- struct platform_device *pdev = to_platform_device(dev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(pdev);
local_irq_disable();
- rtc_wait_not_busy();
- reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
+ rtc_wait_not_busy(rtc);
+ reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ if (rtc->type->has_irqwakeen)
+ irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
if (enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
@@ -189,10 +217,10 @@ static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
}
- rtc_wait_not_busy();
- rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
+ rtc_wait_not_busy(rtc);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
+ if (rtc->type->has_irqwakeen)
+ rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
local_irq_enable();
return 0;
@@ -230,39 +258,47 @@ static void bcd2tm(struct rtc_time *tm)
tm->tm_year = bcd2bin(tm->tm_year) + 100;
}
+static void omap_rtc_read_time_raw(struct omap_rtc *rtc, struct rtc_time *tm)
+{
+ tm->tm_sec = rtc_read(rtc, OMAP_RTC_SECONDS_REG);
+ tm->tm_min = rtc_read(rtc, OMAP_RTC_MINUTES_REG);
+ tm->tm_hour = rtc_read(rtc, OMAP_RTC_HOURS_REG);
+ tm->tm_mday = rtc_read(rtc, OMAP_RTC_DAYS_REG);
+ tm->tm_mon = rtc_read(rtc, OMAP_RTC_MONTHS_REG);
+ tm->tm_year = rtc_read(rtc, OMAP_RTC_YEARS_REG);
+}
static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+
/* we don't report wday/yday/isdst ... */
local_irq_disable();
- rtc_wait_not_busy();
-
- tm->tm_sec = rtc_read(OMAP_RTC_SECONDS_REG);
- tm->tm_min = rtc_read(OMAP_RTC_MINUTES_REG);
- tm->tm_hour = rtc_read(OMAP_RTC_HOURS_REG);
- tm->tm_mday = rtc_read(OMAP_RTC_DAYS_REG);
- tm->tm_mon = rtc_read(OMAP_RTC_MONTHS_REG);
- tm->tm_year = rtc_read(OMAP_RTC_YEARS_REG);
-
+ rtc_wait_not_busy(rtc);
+ omap_rtc_read_time_raw(rtc, tm);
local_irq_enable();
bcd2tm(tm);
+
return 0;
}
static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+
if (tm2bcd(tm) < 0)
return -EINVAL;
+
local_irq_disable();
- rtc_wait_not_busy();
+ rtc_wait_not_busy(rtc);
- rtc_write(tm->tm_year, OMAP_RTC_YEARS_REG);
- rtc_write(tm->tm_mon, OMAP_RTC_MONTHS_REG);
- rtc_write(tm->tm_mday, OMAP_RTC_DAYS_REG);
- rtc_write(tm->tm_hour, OMAP_RTC_HOURS_REG);
- rtc_write(tm->tm_min, OMAP_RTC_MINUTES_REG);
- rtc_write(tm->tm_sec, OMAP_RTC_SECONDS_REG);
+ rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year);
+ rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon);
+ rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday);
+ rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour);
+ rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min);
+ rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec);
local_irq_enable();
@@ -271,48 +307,50 @@ static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+ u8 interrupts;
+
local_irq_disable();
- rtc_wait_not_busy();
+ rtc_wait_not_busy(rtc);
- alm->time.tm_sec = rtc_read(OMAP_RTC_ALARM_SECONDS_REG);
- alm->time.tm_min = rtc_read(OMAP_RTC_ALARM_MINUTES_REG);
- alm->time.tm_hour = rtc_read(OMAP_RTC_ALARM_HOURS_REG);
- alm->time.tm_mday = rtc_read(OMAP_RTC_ALARM_DAYS_REG);
- alm->time.tm_mon = rtc_read(OMAP_RTC_ALARM_MONTHS_REG);
- alm->time.tm_year = rtc_read(OMAP_RTC_ALARM_YEARS_REG);
+ alm->time.tm_sec = rtc_read(rtc, OMAP_RTC_ALARM_SECONDS_REG);
+ alm->time.tm_min = rtc_read(rtc, OMAP_RTC_ALARM_MINUTES_REG);
+ alm->time.tm_hour = rtc_read(rtc, OMAP_RTC_ALARM_HOURS_REG);
+ alm->time.tm_mday = rtc_read(rtc, OMAP_RTC_ALARM_DAYS_REG);
+ alm->time.tm_mon = rtc_read(rtc, OMAP_RTC_ALARM_MONTHS_REG);
+ alm->time.tm_year = rtc_read(rtc, OMAP_RTC_ALARM_YEARS_REG);
local_irq_enable();
bcd2tm(&alm->time);
- alm->enabled = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG)
- & OMAP_RTC_INTERRUPTS_IT_ALARM);
+
+ interrupts = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ alm->enabled = !!(interrupts & OMAP_RTC_INTERRUPTS_IT_ALARM);
return 0;
}
static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
u8 reg, irqwake_reg = 0;
- struct platform_device *pdev = to_platform_device(dev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(pdev);
if (tm2bcd(&alm->time) < 0)
return -EINVAL;
local_irq_disable();
- rtc_wait_not_busy();
+ rtc_wait_not_busy(rtc);
- rtc_write(alm->time.tm_year, OMAP_RTC_ALARM_YEARS_REG);
- rtc_write(alm->time.tm_mon, OMAP_RTC_ALARM_MONTHS_REG);
- rtc_write(alm->time.tm_mday, OMAP_RTC_ALARM_DAYS_REG);
- rtc_write(alm->time.tm_hour, OMAP_RTC_ALARM_HOURS_REG);
- rtc_write(alm->time.tm_min, OMAP_RTC_ALARM_MINUTES_REG);
- rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
+ rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year);
+ rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon);
+ rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday);
+ rtc_write(rtc, OMAP_RTC_ALARM_HOURS_REG, alm->time.tm_hour);
+ rtc_write(rtc, OMAP_RTC_ALARM_MINUTES_REG, alm->time.tm_min);
+ rtc_write(rtc, OMAP_RTC_ALARM_SECONDS_REG, alm->time.tm_sec);
- reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
+ reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ if (rtc->type->has_irqwakeen)
+ irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
if (alm->enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
@@ -321,15 +359,79 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
}
- rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
+ if (rtc->type->has_irqwakeen)
+ rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
local_irq_enable();
return 0;
}
+static struct omap_rtc *omap_rtc_power_off_rtc;
+
+/*
+ * omap_rtc_poweroff: RTC-controlled power off
+ *
+ * The RTC can be used to control an external PMIC via the pmic_power_en pin,
+ * which can be configured to transition to OFF on ALARM2 events.
+ *
+ * Notes:
+ * The two-second alarm offset is the shortest offset possible as the alarm
+ * registers must be set before the next timer update and the offset
+ * calculation is too heavy for everything to be done within a single access
+ * period (~15 us).
+ *
+ * Called with local interrupts disabled.
+ */
+static void omap_rtc_power_off(void)
+{
+ struct omap_rtc *rtc = omap_rtc_power_off_rtc;
+ struct rtc_time tm;
+ unsigned long now;
+ u32 val;
+
+ /* enable pmic_power_en control */
+ val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
+ rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
+
+ /* set alarm two seconds from now */
+ omap_rtc_read_time_raw(rtc, &tm);
+ bcd2tm(&tm);
+ rtc_tm_to_time(&tm, &now);
+ rtc_time_to_tm(now + 2, &tm);
+
+ if (tm2bcd(&tm) < 0) {
+ dev_err(&rtc->rtc->dev, "power off failed\n");
+ return;
+ }
+
+ rtc_wait_not_busy(rtc);
+
+ rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec);
+ rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min);
+ rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour);
+ rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday);
+ rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon);
+ rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year);
+
+ /*
+ * enable ALARM2 interrupt
+ *
+ * NOTE: this fails on AM3352 if rtc_write (writeb) is used
+ */
+ val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG,
+ val | OMAP_RTC_INTERRUPTS_IT_ALARM2);
+
+ /*
+ * Wait for alarm to trigger (within two seconds) and external PMIC to
+ * power off the system. Add a 500 ms margin for external latencies
+ * (e.g. debounce circuits).
+ */
+ mdelay(2500);
+}
+
static struct rtc_class_ops omap_rtc_ops = {
.read_time = omap_rtc_read_time,
.set_time = omap_rtc_set_time,
@@ -338,137 +440,140 @@ static struct rtc_class_ops omap_rtc_ops = {
.alarm_irq_enable = omap_rtc_alarm_irq_enable,
};
-static int omap_rtc_alarm;
-static int omap_rtc_timer;
+static const struct omap_rtc_device_type omap_rtc_default_type = {
+ .has_power_up_reset = true,
+};
-#define OMAP_RTC_DATA_AM3352_IDX 1
-#define OMAP_RTC_DATA_DA830_IDX 2
+static const struct omap_rtc_device_type omap_rtc_am3352_type = {
+ .has_32kclk_en = true,
+ .has_kicker = true,
+ .has_irqwakeen = true,
+ .has_pmic_mode = true,
+};
-static struct platform_device_id omap_rtc_devtype[] = {
+static const struct omap_rtc_device_type omap_rtc_da830_type = {
+ .has_kicker = true,
+};
+
+static const struct platform_device_id omap_rtc_id_table[] = {
{
- .name = DRIVER_NAME,
- },
- [OMAP_RTC_DATA_AM3352_IDX] = {
+ .name = "omap_rtc",
+ .driver_data = (kernel_ulong_t)&omap_rtc_default_type,
+ }, {
.name = "am3352-rtc",
- .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN |
- OMAP_RTC_HAS_32KCLK_EN,
- },
- [OMAP_RTC_DATA_DA830_IDX] = {
+ .driver_data = (kernel_ulong_t)&omap_rtc_am3352_type,
+ }, {
.name = "da830-rtc",
- .driver_data = OMAP_RTC_HAS_KICKER,
- },
- {},
+ .driver_data = (kernel_ulong_t)&omap_rtc_da830_type,
+ }, {
+ /* sentinel */
+ }
};
-MODULE_DEVICE_TABLE(platform, omap_rtc_devtype);
+MODULE_DEVICE_TABLE(platform, omap_rtc_id_table);
static const struct of_device_id omap_rtc_of_match[] = {
- { .compatible = "ti,da830-rtc",
- .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX],
- },
- { .compatible = "ti,am3352-rtc",
- .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX],
- },
- {},
+ {
+ .compatible = "ti,am3352-rtc",
+ .data = &omap_rtc_am3352_type,
+ }, {
+ .compatible = "ti,da830-rtc",
+ .data = &omap_rtc_da830_type,
+ }, {
+ /* sentinel */
+ }
};
MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
static int __init omap_rtc_probe(struct platform_device *pdev)
{
- struct resource *res;
- struct rtc_device *rtc;
- u8 reg, new_ctrl;
+ struct omap_rtc *rtc;
+ struct resource *res;
+ u8 reg, mask, new_ctrl;
const struct platform_device_id *id_entry;
const struct of_device_id *of_id;
+ int ret;
- of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
- if (of_id)
- pdev->id_entry = of_id->data;
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
- id_entry = platform_get_device_id(pdev);
- if (!id_entry) {
- dev_err(&pdev->dev, "no matching device entry\n");
- return -ENODEV;
+ of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
+ if (of_id) {
+ rtc->type = of_id->data;
+ rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
+ of_property_read_bool(pdev->dev.of_node,
+ "system-power-controller");
+ } else {
+ id_entry = platform_get_device_id(pdev);
+ rtc->type = (void *)id_entry->driver_data;
}
- omap_rtc_timer = platform_get_irq(pdev, 0);
- if (omap_rtc_timer <= 0) {
- pr_debug("%s: no update irq?\n", pdev->name);
+ rtc->irq_timer = platform_get_irq(pdev, 0);
+ if (rtc->irq_timer <= 0)
return -ENOENT;
- }
- omap_rtc_alarm = platform_get_irq(pdev, 1);
- if (omap_rtc_alarm <= 0) {
- pr_debug("%s: no alarm irq?\n", pdev->name);
+ rtc->irq_alarm = platform_get_irq(pdev, 1);
+ if (rtc->irq_alarm <= 0)
return -ENOENT;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rtc_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rtc_base))
- return PTR_ERR(rtc_base);
+ rtc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtc->base))
+ return PTR_ERR(rtc->base);
+
+ platform_set_drvdata(pdev, rtc);
/* Enable the clock/module so that we can access the registers */
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) {
- rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG);
- rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG);
- }
-
- rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
- &omap_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- pr_debug("%s: can't register RTC device, err %ld\n",
- pdev->name, PTR_ERR(rtc));
- goto fail0;
+ if (rtc->type->has_kicker) {
+ rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE);
+ rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE);
}
- platform_set_drvdata(pdev, rtc);
- /* clear pending irqs, and set 1/second periodic,
- * which we'll use instead of update irqs
+ /*
+ * disable interrupts
+ *
+ * NOTE: ALARM2 is not cleared on AM3352 if rtc_write (writeb) is used
*/
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
/* enable RTC functional clock */
- if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN)
- rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG);
+ if (rtc->type->has_32kclk_en) {
+ reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
+ rtc_writel(rtc, OMAP_RTC_OSC_REG,
+ reg | OMAP_RTC_OSC_32KCLK_EN);
+ }
/* clear old status */
- reg = rtc_read(OMAP_RTC_STATUS_REG);
- if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {
- pr_info("%s: RTC power up reset detected\n",
- pdev->name);
- rtc_write(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
- }
- if (reg & (u8) OMAP_RTC_STATUS_ALARM)
- rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+ reg = rtc_read(rtc, OMAP_RTC_STATUS_REG);
- /* handle periodic and alarm irqs */
- if (devm_request_irq(&pdev->dev, omap_rtc_timer, rtc_irq, 0,
- dev_name(&rtc->dev), rtc)) {
- pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
- pdev->name, omap_rtc_timer);
- goto fail0;
- }
- if ((omap_rtc_timer != omap_rtc_alarm) &&
- (devm_request_irq(&pdev->dev, omap_rtc_alarm, rtc_irq, 0,
- dev_name(&rtc->dev), rtc))) {
- pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
- pdev->name, omap_rtc_alarm);
- goto fail0;
+ mask = OMAP_RTC_STATUS_ALARM;
+
+ if (rtc->type->has_pmic_mode)
+ mask |= OMAP_RTC_STATUS_ALARM2;
+
+ if (rtc->type->has_power_up_reset) {
+ mask |= OMAP_RTC_STATUS_POWER_UP;
+ if (reg & OMAP_RTC_STATUS_POWER_UP)
+ dev_info(&pdev->dev, "RTC power up reset detected\n");
}
+ if (reg & mask)
+ rtc_write(rtc, OMAP_RTC_STATUS_REG, reg & mask);
+
/* On boards with split power, RTC_ON_NOFF won't reset the RTC */
- reg = rtc_read(OMAP_RTC_CTRL_REG);
- if (reg & (u8) OMAP_RTC_CTRL_STOP)
- pr_info("%s: already running\n", pdev->name);
+ reg = rtc_read(rtc, OMAP_RTC_CTRL_REG);
+ if (reg & OMAP_RTC_CTRL_STOP)
+ dev_info(&pdev->dev, "already running\n");
/* force to 24 hour mode */
- new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP);
+ new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT | OMAP_RTC_CTRL_AUTO_COMP);
new_ctrl |= OMAP_RTC_CTRL_STOP;
- /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
+ /*
+ * BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
*
* - Device wake-up capability setting should come through chip
* init logic. OMAP1 boards should initialize the "wakeup capable"
@@ -482,36 +587,70 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
* is write-only, and always reads as zero...)
*/
+ if (new_ctrl & OMAP_RTC_CTRL_SPLIT)
+ dev_info(&pdev->dev, "split power mode\n");
+
+ if (reg != new_ctrl)
+ rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl);
+
device_init_wakeup(&pdev->dev, true);
- if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
- pr_info("%s: split power mode\n", pdev->name);
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &omap_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ ret = PTR_ERR(rtc->rtc);
+ goto err;
+ }
- if (reg != new_ctrl)
- rtc_write(new_ctrl, OMAP_RTC_CTRL_REG);
+ /* handle periodic and alarm irqs */
+ ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0,
+ dev_name(&rtc->rtc->dev), rtc);
+ if (ret)
+ goto err;
+
+ if (rtc->irq_timer != rtc->irq_alarm) {
+ ret = devm_request_irq(&pdev->dev, rtc->irq_alarm, rtc_irq, 0,
+ dev_name(&rtc->rtc->dev), rtc);
+ if (ret)
+ goto err;
+ }
+
+ if (rtc->is_pmic_controller) {
+ if (!pm_power_off) {
+ omap_rtc_power_off_rtc = rtc;
+ pm_power_off = omap_rtc_power_off;
+ }
+ }
return 0;
-fail0:
- if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
- rtc_writel(0, OMAP_RTC_KICK0_REG);
+err:
+ device_init_wakeup(&pdev->dev, false);
+ if (rtc->type->has_kicker)
+ rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return -EIO;
+
+ return ret;
}
static int __exit omap_rtc_remove(struct platform_device *pdev)
{
- const struct platform_device_id *id_entry =
- platform_get_device_id(pdev);
+ struct omap_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (pm_power_off == omap_rtc_power_off &&
+ omap_rtc_power_off_rtc == rtc) {
+ pm_power_off = NULL;
+ omap_rtc_power_off_rtc = NULL;
+ }
device_init_wakeup(&pdev->dev, 0);
/* leave rtc running, but disable irqs */
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
- if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
- rtc_writel(0, OMAP_RTC_KICK0_REG);
+ if (rtc->type->has_kicker)
+ rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0);
/* Disable the clock/module */
pm_runtime_put_sync(&pdev->dev);
@@ -521,20 +660,21 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
-static u8 irqstat;
-
static int omap_rtc_suspend(struct device *dev)
{
- irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
- /* FIXME the RTC alarm is not currently acting as a wakeup event
+ rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+
+ /*
+ * FIXME: the RTC alarm is not currently acting as a wakeup event
* source on some platforms, and in fact this enable() call is just
* saving a flag that's never used...
*/
if (device_may_wakeup(dev))
- enable_irq_wake(omap_rtc_alarm);
+ enable_irq_wake(rtc->irq_alarm);
else
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
/* Disable the clock/module */
pm_runtime_put_sync(dev);
@@ -544,13 +684,15 @@ static int omap_rtc_suspend(struct device *dev)
static int omap_rtc_resume(struct device *dev)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+
/* Enable the clock/module so that we can access the registers */
pm_runtime_get_sync(dev);
if (device_may_wakeup(dev))
- disable_irq_wake(omap_rtc_alarm);
+ disable_irq_wake(rtc->irq_alarm);
else
- rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg);
return 0;
}
@@ -560,23 +702,31 @@ static SIMPLE_DEV_PM_OPS(omap_rtc_pm_ops, omap_rtc_suspend, omap_rtc_resume);
static void omap_rtc_shutdown(struct platform_device *pdev)
{
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ struct omap_rtc *rtc = platform_get_drvdata(pdev);
+ u8 mask;
+
+ /*
+ * Keep the ALARM interrupt enabled to allow the system to power up on
+ * alarm events.
+ */
+ mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ mask &= OMAP_RTC_INTERRUPTS_IT_ALARM;
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask);
}
-MODULE_ALIAS("platform:omap_rtc");
static struct platform_driver omap_rtc_driver = {
.remove = __exit_p(omap_rtc_remove),
.shutdown = omap_rtc_shutdown,
.driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
+ .name = "omap_rtc",
.pm = &omap_rtc_pm_ops,
.of_match_table = omap_rtc_of_match,
},
- .id_table = omap_rtc_devtype,
+ .id_table = omap_rtc_id_table,
};
module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe);
+MODULE_ALIAS("platform:omap_rtc");
MODULE_AUTHOR("George G. Davis (and others)");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c
new file mode 100644
index 000000000000..95f652165fe9
--- /dev/null
+++ b/drivers/rtc/rtc-opal.c
@@ -0,0 +1,261 @@
+/*
+ * IBM OPAL RTC driver
+ * Copyright (C) 2014 IBM
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ */
+
+#define DRVNAME "rtc-opal"
+#define pr_fmt(fmt) DRVNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <asm/opal.h>
+#include <asm/firmware.h>
+
+static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm)
+{
+ tm->tm_year = ((bcd2bin(y_m_d >> 24) * 100) +
+ bcd2bin((y_m_d >> 16) & 0xff)) - 1900;
+ tm->tm_mon = bcd2bin((y_m_d >> 8) & 0xff) - 1;
+ tm->tm_mday = bcd2bin(y_m_d & 0xff);
+ tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff);
+ tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff);
+ tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff);
+
+ GregorianDay(tm);
+}
+
+static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms)
+{
+ *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) / 100)) << 24;
+ *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) % 100)) << 16;
+ *y_m_d |= ((u32)bin2bcd((tm->tm_mon + 1))) << 8;
+ *y_m_d |= ((u32)bin2bcd(tm->tm_mday));
+
+ *h_m_s_ms |= ((u64)bin2bcd(tm->tm_hour)) << 56;
+ *h_m_s_ms |= ((u64)bin2bcd(tm->tm_min)) << 48;
+ *h_m_s_ms |= ((u64)bin2bcd(tm->tm_sec)) << 40;
+}
+
+static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+ long rc = OPAL_BUSY;
+ u32 y_m_d;
+ u64 h_m_s_ms;
+ __be32 __y_m_d;
+ __be64 __h_m_s_ms;
+
+ while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
+ rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
+ if (rc == OPAL_BUSY_EVENT)
+ opal_poll_events(NULL);
+ else
+ msleep(10);
+ }
+
+ if (rc != OPAL_SUCCESS)
+ return -EIO;
+
+ y_m_d = be32_to_cpu(__y_m_d);
+ h_m_s_ms = be64_to_cpu(__h_m_s_ms);
+ opal_to_tm(y_m_d, h_m_s_ms, tm);
+
+ return 0;
+}
+
+static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+ long rc = OPAL_BUSY;
+ u32 y_m_d = 0;
+ u64 h_m_s_ms = 0;
+
+ tm_to_opal(tm, &y_m_d, &h_m_s_ms);
+ while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
+ rc = opal_rtc_write(y_m_d, h_m_s_ms);
+ if (rc == OPAL_BUSY_EVENT)
+ opal_poll_events(NULL);
+ else
+ msleep(10);
+ }
+
+ return rc == OPAL_SUCCESS ? 0 : -EIO;
+}
+
+/*
+ * TPO Timed Power-On
+ *
+ * TPO get/set OPAL calls care about the hour and min and to make it consistent
+ * with the rtc utility time conversion functions, we use the 'u64' to store
+ * its value and perform bit shift by 32 before use..
+ */
+static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ __be32 __y_m_d, __h_m;
+ struct opal_msg msg;
+ int rc, token;
+ u64 h_m_s_ms;
+ u32 y_m_d;
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ if (token != -ERESTARTSYS)
+ pr_err("Failed to get the async token\n");
+
+ return token;
+ }
+
+ rc = opal_tpo_read(token, &__y_m_d, &__h_m);
+ if (rc != OPAL_ASYNC_COMPLETION) {
+ rc = -EIO;
+ goto exit;
+ }
+
+ rc = opal_async_wait_response(token, &msg);
+ if (rc) {
+ rc = -EIO;
+ goto exit;
+ }
+
+ rc = be64_to_cpu(msg.params[1]);
+ if (rc != OPAL_SUCCESS) {
+ rc = -EIO;
+ goto exit;
+ }
+
+ y_m_d = be32_to_cpu(__y_m_d);
+ h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
+ opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
+
+exit:
+ opal_async_release_token(token);
+ return rc;
+}
+
+/* Set Timed Power-On */
+static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ u64 h_m_s_ms = 0, token;
+ struct opal_msg msg;
+ u32 y_m_d = 0;
+ int rc;
+
+ tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
+
+ token = opal_async_get_token_interruptible();
+ if (token < 0) {
+ if (token != -ERESTARTSYS)
+ pr_err("Failed to get the async token\n");
+
+ return token;
+ }
+
+ /* TPO, we care about hour and minute */
+ rc = opal_tpo_write(token, y_m_d,
+ (u32)((h_m_s_ms >> 32) & 0xffff0000));
+ if (rc != OPAL_ASYNC_COMPLETION) {
+ rc = -EIO;
+ goto exit;
+ }
+
+ rc = opal_async_wait_response(token, &msg);
+ if (rc) {
+ rc = -EIO;
+ goto exit;
+ }
+
+ rc = be64_to_cpu(msg.params[1]);
+ if (rc != OPAL_SUCCESS)
+ rc = -EIO;
+
+exit:
+ opal_async_release_token(token);
+ return rc;
+}
+
+static const struct rtc_class_ops opal_rtc_ops = {
+ .read_time = opal_get_rtc_time,
+ .set_time = opal_set_rtc_time,
+ .read_alarm = opal_get_tpo_time,
+ .set_alarm = opal_set_tpo_time,
+};
+
+static int opal_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+
+ if (pdev->dev.of_node && of_get_property(pdev->dev.of_node, "has-tpo",
+ NULL))
+ device_set_wakeup_capable(&pdev->dev, true);
+
+ rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ rtc->uie_unsupported = 1;
+
+ return 0;
+}
+
+static const struct of_device_id opal_rtc_match[] = {
+ {
+ .compatible = "ibm,opal-rtc",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, opal_rtc_match);
+
+static const struct platform_device_id opal_rtc_driver_ids[] = {
+ {
+ .name = "opal-rtc",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, opal_rtc_driver_ids);
+
+static struct platform_driver opal_rtc_driver = {
+ .probe = opal_rtc_probe,
+ .id_table = opal_rtc_driver_ids,
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = opal_rtc_match,
+ },
+};
+
+static int __init opal_rtc_init(void)
+{
+ if (!firmware_has_feature(FW_FEATURE_OPAL))
+ return -ENODEV;
+
+ return platform_driver_register(&opal_rtc_driver);
+}
+
+static void __exit opal_rtc_exit(void)
+{
+ platform_driver_unregister(&opal_rtc_driver);
+}
+
+MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("IBM OPAL RTC driver");
+MODULE_LICENSE("GPL");
+
+module_init(opal_rtc_init);
+module_exit(opal_rtc_exit);
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
index 4dfe2d793fa3..3b01d567496d 100644
--- a/drivers/rtc/rtc-palmas.c
+++ b/drivers/rtc/rtc-palmas.c
@@ -363,7 +363,6 @@ static struct platform_driver palmas_rtc_driver = {
.probe = palmas_rtc_probe,
.remove = palmas_rtc_remove,
.driver = {
- .owner = THIS_MODULE,
.name = "palmas-rtc",
.pm = &palmas_rtc_pm_ops,
.of_match_table = of_match_ptr(of_palmas_rtc_match),
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c
index 40b5c630bc7d..c4433240d8a9 100644
--- a/drivers/rtc/rtc-pcap.c
+++ b/drivers/rtc/rtc-pcap.c
@@ -184,7 +184,6 @@ static struct platform_driver pcap_rtc_driver = {
.remove = __exit_p(pcap_rtc_remove),
.driver = {
.name = "pcap-rtc",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index c2ef0a22ee94..96fb32e7d6f8 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -28,6 +28,7 @@
#define PCF8563_REG_ST2 0x01
#define PCF8563_BIT_AIE (1 << 1)
#define PCF8563_BIT_AF (1 << 3)
+#define PCF8563_BITS_ST2_N (7 << 5)
#define PCF8563_REG_SC 0x02 /* datetime */
#define PCF8563_REG_MN 0x03
@@ -41,6 +42,13 @@
#define PCF8563_REG_CLKO 0x0D /* clock out */
#define PCF8563_REG_TMRC 0x0E /* timer control */
+#define PCF8563_TMRC_ENABLE BIT(7)
+#define PCF8563_TMRC_4096 0
+#define PCF8563_TMRC_64 1
+#define PCF8563_TMRC_1 2
+#define PCF8563_TMRC_1_60 3
+#define PCF8563_TMRC_MASK 3
+
#define PCF8563_REG_TMR 0x0F /* timer */
#define PCF8563_SC_LV 0x80 /* low voltage */
@@ -118,22 +126,21 @@ static int pcf8563_write_block_data(struct i2c_client *client,
static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
{
- unsigned char buf[2];
+ unsigned char buf;
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1);
+ err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
if (err < 0)
return err;
if (on)
- buf[1] |= PCF8563_BIT_AIE;
+ buf |= PCF8563_BIT_AIE;
else
- buf[1] &= ~PCF8563_BIT_AIE;
+ buf &= ~PCF8563_BIT_AIE;
- buf[1] &= ~PCF8563_BIT_AF;
- buf[0] = PCF8563_REG_ST2;
+ buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N);
- err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1);
+ err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return -EIO;
@@ -336,8 +343,8 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
__func__, buf[0], buf[1], buf[2], buf[3]);
tm->time.tm_min = bcd2bin(buf[0] & 0x7F);
- tm->time.tm_hour = bcd2bin(buf[1] & 0x7F);
- tm->time.tm_mday = bcd2bin(buf[2] & 0x1F);
+ tm->time.tm_hour = bcd2bin(buf[1] & 0x3F);
+ tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
tm->time.tm_mon = -1;
tm->time.tm_year = -1;
@@ -361,6 +368,14 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
struct i2c_client *client = to_i2c_client(dev);
unsigned char buf[4];
int err;
+ unsigned long alarm_time;
+
+ /* The alarm has no seconds, round up to nearest minute */
+ if (tm->time.tm_sec) {
+ rtc_tm_to_time(&tm->time, &alarm_time);
+ alarm_time += 60-tm->time.tm_sec;
+ rtc_time_to_tm(alarm_time, &tm->time);
+ }
dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d "
"enabled=%d pending=%d\n", __func__,
@@ -381,6 +396,7 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
{
+ dev_dbg(dev, "%s: en=%d\n", __func__, enabled);
return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled);
}
@@ -398,6 +414,8 @@ static int pcf8563_probe(struct i2c_client *client,
{
struct pcf8563 *pcf8563;
int err;
+ unsigned char buf;
+ unsigned char alm_pending;
dev_dbg(&client->dev, "%s\n", __func__);
@@ -415,6 +433,22 @@ static int pcf8563_probe(struct i2c_client *client,
pcf8563->client = client;
device_set_wakeup_capable(&client->dev, 1);
+ /* Set timer to lowest frequency to save power (ref Haoyu datasheet) */
+ buf = PCF8563_TMRC_1_60;
+ err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf);
+ if (err < 0) {
+ dev_err(&client->dev, "%s: write error\n", __func__);
+ return err;
+ }
+
+ err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
+ if (err < 0) {
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return err;
+ }
+ if (alm_pending)
+ pcf8563_set_alarm_mode(client, 0);
+
pcf8563->rtc = devm_rtc_device_register(&client->dev,
pcf8563_driver.driver.name,
&pcf8563_rtc_ops, THIS_MODULE);
@@ -435,6 +469,9 @@ static int pcf8563_probe(struct i2c_client *client,
}
+ /* the pcf8563 alarm only supports a minute accuracy */
+ pcf8563->rtc->uie_unsupported = 1;
+
return 0;
}
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 5adcf111fc14..795fcbd02ea3 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -531,7 +531,6 @@ static struct platform_driver pm8xxx_rtc_driver = {
.probe = pm8xxx_rtc_probe,
.driver = {
.name = "rtc-pm8xxx",
- .owner = THIS_MODULE,
.pm = &pm8xxx_rtc_pm_ops,
.of_match_table = pm8xxx_id_table,
},
diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c
index 554ada5e9b76..6a8f5d758eac 100644
--- a/drivers/rtc/rtc-ps3.c
+++ b/drivers/rtc/rtc-ps3.c
@@ -74,7 +74,6 @@ static int __init ps3_rtc_probe(struct platform_device *dev)
static struct platform_driver ps3_rtc_driver = {
.driver = {
.name = "rtc-ps3",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c
index 1cff2a21db67..c0a6e638c672 100644
--- a/drivers/rtc/rtc-puv3.c
+++ b/drivers/rtc/rtc-puv3.c
@@ -328,7 +328,6 @@ static struct platform_driver puv3_rtc_driver = {
.remove = puv3_rtc_remove,
.driver = {
.name = "PKUnity-v3-RTC",
- .owner = THIS_MODULE,
.pm = &puv3_rtc_pm_ops,
}
};
diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c
index e53e9b1c69b3..f28d57788951 100644
--- a/drivers/rtc/rtc-rc5t583.c
+++ b/drivers/rtc/rtc-rc5t583.c
@@ -310,7 +310,6 @@ static struct platform_driver rc5t583_rtc_driver = {
.probe = rc5t583_rtc_probe,
.remove = rc5t583_rtc_remove,
.driver = {
- .owner = THIS_MODULE,
.name = "rtc-rc5t583",
.pm = &rc5t583_rtc_pm_ops,
},
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
index 89d073679267..b548551f385c 100644
--- a/drivers/rtc/rtc-rp5c01.c
+++ b/drivers/rtc/rtc-rp5c01.c
@@ -273,7 +273,6 @@ static int __exit rp5c01_rtc_remove(struct platform_device *dev)
static struct platform_driver rp5c01_rtc_driver = {
.driver = {
.name = "rtc-rp5c01",
- .owner = THIS_MODULE,
},
.remove = __exit_p(rp5c01_rtc_remove),
};
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
index 68f7856422f1..5f48167c802a 100644
--- a/drivers/rtc/rtc-rs5c313.c
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -381,7 +381,6 @@ static int rs5c313_rtc_probe(struct platform_device *pdev)
static struct platform_driver rs5c313_rtc_platform_driver = {
.driver = {
.name = DRV_NAME,
- .owner = THIS_MODULE,
},
.probe = rs5c313_rtc_probe,
};
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 806072238c00..4241eeab3386 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -896,7 +896,6 @@ static struct platform_driver s3c_rtc_driver = {
.remove = s3c_rtc_remove,
.driver = {
.name = "s3c-rtc",
- .owner = THIS_MODULE,
.pm = &s3c_rtc_pm_ops,
.of_match_table = of_match_ptr(s3c_rtc_dt_match),
},
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index 8754c33361e8..b5e7c4670205 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -837,7 +837,6 @@ static const struct platform_device_id s5m_rtc_id[] = {
static struct platform_driver s5m_rtc_driver = {
.driver = {
.name = "s5m-rtc",
- .owner = THIS_MODULE,
.pm = &s5m_rtc_pm_ops,
},
.probe = s5m_rtc_probe,
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index d0d2b047658b..2b81dd4baf17 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -782,7 +782,6 @@ static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume);
static struct platform_driver sh_rtc_platform_driver = {
.driver = {
.name = DRV_NAME,
- .owner = THIS_MODULE,
.pm = &sh_rtc_pm_ops,
},
.remove = __exit_p(sh_rtc_remove),
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c
index 76e38007ba90..edc3b43282d4 100644
--- a/drivers/rtc/rtc-sirfsoc.c
+++ b/drivers/rtc/rtc-sirfsoc.c
@@ -47,6 +47,7 @@ struct sirfsoc_rtc_drv {
unsigned irq_wake;
/* Overflow for every 8 years extra time */
u32 overflow_rtc;
+ spinlock_t lock;
#ifdef CONFIG_PM
u32 saved_counter;
u32 saved_overflow_rtc;
@@ -61,7 +62,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev,
rtcdrv = dev_get_drvdata(dev);
- local_irq_disable();
+ spin_lock_irq(&rtcdrv->lock);
rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
@@ -84,7 +85,8 @@ static int sirfsoc_rtc_read_alarm(struct device *dev,
if (sirfsoc_rtc_iobrg_readl(
rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E)
alrm->enabled = 1;
- local_irq_enable();
+
+ spin_unlock_irq(&rtcdrv->lock);
return 0;
}
@@ -99,7 +101,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
if (alrm->enabled) {
rtc_tm_to_time(&(alrm->time), &rtc_alarm);
- local_irq_disable();
+ spin_lock_irq(&rtcdrv->lock);
rtc_status_reg = sirfsoc_rtc_iobrg_readl(
rtcdrv->rtc_base + RTC_STATUS);
@@ -123,14 +125,15 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
rtc_status_reg |= SIRFSOC_RTC_AL0E;
sirfsoc_rtc_iobrg_writel(
rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
- local_irq_enable();
+
+ spin_unlock_irq(&rtcdrv->lock);
} else {
/*
* if this function was called with enabled=0
* then it could mean that the application is
* trying to cancel an ongoing alarm
*/
- local_irq_disable();
+ spin_lock_irq(&rtcdrv->lock);
rtc_status_reg = sirfsoc_rtc_iobrg_readl(
rtcdrv->rtc_base + RTC_STATUS);
@@ -146,7 +149,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
rtcdrv->rtc_base + RTC_STATUS);
}
- local_irq_enable();
+ spin_unlock_irq(&rtcdrv->lock);
}
return 0;
@@ -209,12 +212,38 @@ static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd,
}
}
+static int sirfsoc_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ unsigned long rtc_status_reg = 0x0;
+ struct sirfsoc_rtc_drv *rtcdrv;
+
+ rtcdrv = dev_get_drvdata(dev);
+
+ spin_lock_irq(&rtcdrv->lock);
+
+ rtc_status_reg = sirfsoc_rtc_iobrg_readl(
+ rtcdrv->rtc_base + RTC_STATUS);
+ if (enabled)
+ rtc_status_reg |= SIRFSOC_RTC_AL0E;
+ else
+ rtc_status_reg &= ~SIRFSOC_RTC_AL0E;
+
+ sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
+
+ spin_unlock_irq(&rtcdrv->lock);
+
+ return 0;
+
+}
+
static const struct rtc_class_ops sirfsoc_rtc_ops = {
.read_time = sirfsoc_rtc_read_time,
.set_time = sirfsoc_rtc_set_time,
.read_alarm = sirfsoc_rtc_read_alarm,
.set_alarm = sirfsoc_rtc_set_alarm,
- .ioctl = sirfsoc_rtc_ioctl
+ .ioctl = sirfsoc_rtc_ioctl,
+ .alarm_irq_enable = sirfsoc_rtc_alarm_irq_enable
};
static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
@@ -223,6 +252,8 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
unsigned long rtc_status_reg = 0x0;
unsigned long events = 0x0;
+ spin_lock(&rtcdrv->lock);
+
rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS);
/* this bit will be set ONLY if an alarm was active
* and it expired NOW
@@ -240,6 +271,9 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
rtc_status_reg &= ~(SIRFSOC_RTC_AL0E);
}
sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
+
+ spin_unlock(&rtcdrv->lock);
+
/* this should wake up any apps polling/waiting on the read
* after setting the alarm
*/
@@ -267,6 +301,8 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
if (rtcdrv == NULL)
return -ENOMEM;
+ spin_lock_init(&rtcdrv->lock);
+
err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base);
if (err) {
dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n");
@@ -286,14 +322,6 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
rtc_div = ((32768 / RTC_HZ) / 2) - 1;
sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV);
- rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
- &sirfsoc_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtcdrv->rtc)) {
- err = PTR_ERR(rtcdrv->rtc);
- dev_err(&pdev->dev, "can't register RTC device\n");
- return err;
- }
-
/* 0x3 -> RTC_CLK */
sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK,
rtcdrv->rtc_base + RTC_CLOCK_SWITCH);
@@ -308,6 +336,14 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
rtcdrv->overflow_rtc =
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
+ rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &sirfsoc_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtcdrv->rtc)) {
+ err = PTR_ERR(rtcdrv->rtc);
+ dev_err(&pdev->dev, "can't register RTC device\n");
+ return err;
+ }
+
rtcdrv->irq = platform_get_irq(pdev, 0);
err = devm_request_irq(
&pdev->dev,
@@ -408,7 +444,6 @@ static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops,
static struct platform_driver sirfsoc_rtc_driver = {
.driver = {
.name = "sirfsoc-rtc",
- .owner = THIS_MODULE,
.pm = &sirfsoc_rtc_pm_ops,
.of_match_table = sirfsoc_rtc_of_match,
},
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c
index fa384fe28988..0479e807a776 100644
--- a/drivers/rtc/rtc-snvs.c
+++ b/drivers/rtc/rtc-snvs.c
@@ -17,6 +17,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/clk.h>
/* These register offsets are relative to LP (Low Power) range */
#define SNVS_LPCR 0x04
@@ -39,6 +40,7 @@ struct snvs_rtc_data {
void __iomem *ioaddr;
int irq;
spinlock_t lock;
+ struct clk *clk;
};
static u32 rtc_read_lp_counter(void __iomem *ioaddr)
@@ -260,6 +262,18 @@ static int snvs_rtc_probe(struct platform_device *pdev)
if (data->irq < 0)
return data->irq;
+ data->clk = devm_clk_get(&pdev->dev, "snvs-rtc");
+ if (IS_ERR(data->clk)) {
+ data->clk = NULL;
+ } else {
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not prepare or enable the snvs clock\n");
+ return ret;
+ }
+ }
+
platform_set_drvdata(pdev, data);
spin_lock_init(&data->lock);
@@ -280,7 +294,7 @@ static int snvs_rtc_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to request irq %d: %d\n",
data->irq, ret);
- return ret;
+ goto error_rtc_device_register;
}
data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
@@ -288,10 +302,16 @@ static int snvs_rtc_probe(struct platform_device *pdev)
if (IS_ERR(data->rtc)) {
ret = PTR_ERR(data->rtc);
dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
- return ret;
+ goto error_rtc_device_register;
}
return 0;
+
+error_rtc_device_register:
+ if (data->clk)
+ clk_disable_unprepare(data->clk);
+
+ return ret;
}
#ifdef CONFIG_PM_SLEEP
@@ -302,21 +322,41 @@ static int snvs_rtc_suspend(struct device *dev)
if (device_may_wakeup(dev))
enable_irq_wake(data->irq);
+ if (data->clk)
+ clk_disable_unprepare(data->clk);
+
return 0;
}
static int snvs_rtc_resume(struct device *dev)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
if (device_may_wakeup(dev))
disable_irq_wake(data->irq);
+ if (data->clk) {
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume);
+static const struct dev_pm_ops snvs_rtc_pm_ops = {
+ .suspend_noirq = snvs_rtc_suspend,
+ .resume_noirq = snvs_rtc_resume,
+};
+
+#define SNVS_RTC_PM_OPS (&snvs_rtc_pm_ops)
+
+#else
+
+#define SNVS_RTC_PM_OPS NULL
+
+#endif
static const struct of_device_id snvs_dt_ids[] = {
{ .compatible = "fsl,sec-v4.0-mon-rtc-lp", },
@@ -327,8 +367,7 @@ MODULE_DEVICE_TABLE(of, snvs_dt_ids);
static struct platform_driver snvs_rtc_driver = {
.driver = {
.name = "snvs_rtc",
- .owner = THIS_MODULE,
- .pm = &snvs_rtc_pm_ops,
+ .pm = SNVS_RTC_PM_OPS,
.of_match_table = snvs_dt_ids,
},
.probe = snvs_rtc_probe,
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
index f7d8a6db8078..83a057a03060 100644
--- a/drivers/rtc/rtc-starfire.c
+++ b/drivers/rtc/rtc-starfire.c
@@ -54,7 +54,6 @@ static int __init starfire_rtc_probe(struct platform_device *pdev)
static struct platform_driver starfire_rtc_driver = {
.driver = {
.name = "rtc-starfire",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 35ed49ea1f81..0e93b714ee41 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -358,7 +358,6 @@ static struct platform_driver stk17ta8_rtc_driver = {
.remove = stk17ta8_rtc_remove,
.driver = {
.name = "stk17ta8",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index ea96492357b0..2939cdcb2688 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -341,7 +341,6 @@ static struct platform_driver stmp3xxx_rtcdrv = {
.remove = stmp3xxx_rtc_remove,
.driver = {
.name = "stmp3xxx-rtc",
- .owner = THIS_MODULE,
.pm = &stmp3xxx_rtc_pm_ops,
.of_match_table = rtc_dt_ids,
},
diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
index bc97ff91341d..7c696c12f28f 100644
--- a/drivers/rtc/rtc-sun4v.c
+++ b/drivers/rtc/rtc-sun4v.c
@@ -95,7 +95,6 @@ static int __init sun4v_rtc_probe(struct platform_device *pdev)
static struct platform_driver sun4v_rtc_driver = {
.driver = {
.name = "rtc-sun4v",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c
index b6f21f73d508..6e678fa4dfaf 100644
--- a/drivers/rtc/rtc-sunxi.c
+++ b/drivers/rtc/rtc-sunxi.c
@@ -511,7 +511,6 @@ static struct platform_driver sunxi_rtc_driver = {
.remove = sunxi_rtc_remove,
.driver = {
.name = "sunxi-rtc",
- .owner = THIS_MODULE,
.of_match_table = sunxi_rtc_dt_ids,
},
};
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 76af92ad5a8a..d948277057d8 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -420,7 +420,6 @@ static struct platform_driver tegra_rtc_driver = {
.shutdown = tegra_rtc_shutdown,
.driver = {
.name = "tegra_rtc",
- .owner = THIS_MODULE,
.of_match_table = tegra_rtc_dt_match,
.pm = &tegra_rtc_pm_ops,
},
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index 6599c20bc454..8f86fa91de1a 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -129,7 +129,6 @@ static struct platform_driver test_driver = {
.remove = test_remove,
.driver = {
.name = "rtc-test",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c
index ff9632eb79f2..0b60867d8390 100644
--- a/drivers/rtc/rtc-tile.c
+++ b/drivers/rtc/rtc-tile.c
@@ -94,7 +94,6 @@ static int tile_rtc_probe(struct platform_device *dev)
static struct platform_driver tile_rtc_platform_driver = {
.driver = {
.name = "rtc-tile",
- .owner = THIS_MODULE,
},
.probe = tile_rtc_probe,
};
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 426901cef14f..3b6ce80a769c 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -337,7 +337,6 @@ static SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_rtc_suspend,
static struct platform_driver tps6586x_rtc_driver = {
.driver = {
.name = "tps6586x-rtc",
- .owner = THIS_MODULE,
.pm = &tps6586x_pm_ops,
},
.probe = tps6586x_rtc_probe,
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
index 2583349fbde5..f42aa2b2dcba 100644
--- a/drivers/rtc/rtc-tps65910.c
+++ b/drivers/rtc/rtc-tps65910.c
@@ -326,7 +326,6 @@ static struct platform_driver tps65910_rtc_driver = {
.probe = tps65910_rtc_probe,
.remove = tps65910_rtc_remove,
.driver = {
- .owner = THIS_MODULE,
.name = "tps65910-rtc",
.pm = &tps65910_rtc_pm_ops,
},
diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c
index 3e400dce2d06..27e254cde715 100644
--- a/drivers/rtc/rtc-tps80031.c
+++ b/drivers/rtc/rtc-tps80031.c
@@ -324,7 +324,6 @@ static SIMPLE_DEV_PM_OPS(tps80031_pm_ops, tps80031_rtc_suspend,
static struct platform_driver tps80031_rtc_driver = {
.driver = {
.name = "tps80031-rtc",
- .owner = THIS_MODULE,
.pm = &tps80031_pm_ops,
},
.probe = tps80031_rtc_probe,
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 1915464e4cd6..5baea3f54926 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -608,7 +608,6 @@ static struct platform_driver twl4030rtc_driver = {
.remove = twl_rtc_remove,
.shutdown = twl_rtc_shutdown,
.driver = {
- .owner = THIS_MODULE,
.name = "twl_rtc",
.pm = &twl_rtc_pm_ops,
.of_match_table = of_match_ptr(twl_rtc_of_match),
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index 2e678c681b13..cb7f94ede516 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -287,7 +287,6 @@ static struct platform_driver tx4939_rtc_driver = {
.remove = __exit_p(tx4939_rtc_remove),
.driver = {
.name = "tx4939rtc",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 25222cdccdc6..bfbfa7ed7bbf 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -382,7 +382,6 @@ static struct platform_driver rtc_device_driver = {
.remove = rtc_remove,
.driver = {
.name = "v3020",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 88c9c92e89fd..f64c282275b3 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -375,7 +375,6 @@ static struct platform_driver rtc_platform_driver = {
.probe = rtc_probe,
.driver = {
.name = rtc_name,
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
index 051da968da6d..a58b6d17e6f0 100644
--- a/drivers/rtc/rtc-vt8500.c
+++ b/drivers/rtc/rtc-vt8500.c
@@ -277,7 +277,6 @@ static struct platform_driver vt8500_rtc_driver = {
.remove = vt8500_rtc_remove,
.driver = {
.name = "vt8500-rtc",
- .owner = THIS_MODULE,
.of_match_table = wmt_dt_ids,
},
};
diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c
index 14129cc85bdb..65b432a096fe 100644
--- a/drivers/rtc/rtc-xgene.c
+++ b/drivers/rtc/rtc-xgene.c
@@ -264,7 +264,6 @@ static struct platform_driver xgene_rtc_driver = {
.probe = xgene_rtc_probe,
.remove = xgene_rtc_remove,
.driver = {
- .owner = THIS_MODULE,
.name = "xgene-rtc",
.pm = &xgene_rtc_pm_ops,
.of_match_table = of_match_ptr(xgene_rtc_of_match),