summaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig20
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c65
-rw-r--r--drivers/rtc/interface.c55
-rw-r--r--drivers/rtc/rtc-at32ap700x.c2
-rw-r--r--drivers/rtc/rtc-cmos.c6
-rw-r--r--drivers/rtc/rtc-ds1286.c2
-rw-r--r--drivers/rtc/rtc-ds1307.c1
-rw-r--r--drivers/rtc/rtc-ds1511.c2
-rw-r--r--drivers/rtc/rtc-ds1742.c2
-rw-r--r--drivers/rtc/rtc-m48t35.c2
-rw-r--r--drivers/rtc/rtc-m48t59.c2
-rw-r--r--drivers/rtc/rtc-mpc5121.c81
-rw-r--r--drivers/rtc/rtc-mrst.c5
-rw-r--r--drivers/rtc/rtc-omap.c2
-rw-r--r--drivers/rtc/rtc-pm8xxx.c550
-rw-r--r--drivers/rtc/rtc-puv3.c5
-rw-r--r--drivers/rtc/rtc-s3c.c111
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c153
-rw-r--r--drivers/rtc/rtc-tegra.c2
-rw-r--r--drivers/rtc/rtc-twl.c2
-rw-r--r--drivers/rtc/rtc-vt8500.c51
22 files changed, 887 insertions, 235 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ce2aabf5c55..5a538fc1cc8 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -981,11 +981,11 @@ config RTC_DRV_COH901331
config RTC_DRV_STMP
- tristate "Freescale STMP3xxx RTC"
- depends on ARCH_STMP3XXX
+ tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC"
+ depends on ARCH_MXS
help
If you say yes here you will get support for the onboard
- STMP3xxx RTC.
+ STMP3xxx/i.MX23/i.MX28 RTC.
This driver can also be built as a module. If so, the module
will be called rtc-stmp3xxx.
@@ -1006,10 +1006,10 @@ config RTC_DRV_MC13XXX
config RTC_DRV_MPC5121
tristate "Freescale MPC5121 built-in RTC"
- depends on PPC_MPC512x && RTC_CLASS
+ depends on PPC_MPC512x || PPC_MPC52xx
help
If you say yes here you will get support for the
- built-in RTC MPC5121.
+ built-in RTC on MPC5121 or on MPC5200.
This driver can also be built as a module. If so, the module
will be called rtc-mpc5121.
@@ -1034,6 +1034,16 @@ config RTC_DRV_LPC32XX
This driver can also be buillt as a module. If so, the module
will be called rtc-lpc32xx.
+config RTC_DRV_PM8XXX
+ tristate "Qualcomm PMIC8XXX RTC"
+ depends on MFD_PM8XXX
+ help
+ If you say yes here you get support for the
+ Qualcomm PMIC8XXX RTC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-pm8xxx.
+
config RTC_DRV_TEGRA
tristate "NVIDIA Tegra Internal RTC driver"
depends on RTC_CLASS && ARCH_TEGRA
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0ffefe877bf..6e6982335c1 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 4194e59e14c..01a7df5317c 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -41,20 +41,41 @@ static void rtc_device_release(struct device *dev)
* system's wall clock; restore it on resume().
*/
-static time_t oldtime;
-static struct timespec oldts;
+static struct timespec old_rtc, old_system, old_delta;
+
static int rtc_suspend(struct device *dev, pm_message_t mesg)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
-
+ struct timespec delta, delta_delta;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
+ /* snapshot the current RTC and system time at suspend*/
rtc_read_time(rtc, &tm);
- ktime_get_ts(&oldts);
- rtc_tm_to_time(&tm, &oldtime);
+ getnstimeofday(&old_system);
+ rtc_tm_to_time(&tm, &old_rtc.tv_sec);
+
+
+ /*
+ * To avoid drift caused by repeated suspend/resumes,
+ * which each can add ~1 second drift error,
+ * 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);
+ if (abs(delta_delta.tv_sec) >= 2) {
+ /*
+ * if delta_delta is too large, assume time correction
+ * has occured and set old_delta to the current delta.
+ */
+ old_delta = delta;
+ } else {
+ /* Otherwise try to adjust old_system to compensate */
+ old_system = timespec_sub(old_system, delta_delta);
+ }
return 0;
}
@@ -63,32 +84,42 @@ static int rtc_resume(struct device *dev)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- time_t newtime;
- struct timespec time;
- struct timespec newts;
+ struct timespec new_system, new_rtc;
+ struct timespec sleep_time;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
- ktime_get_ts(&newts);
+ /* snapshot the current rtc and system time at resume */
+ getnstimeofday(&new_system);
rtc_read_time(rtc, &tm);
if (rtc_valid_tm(&tm) != 0) {
pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev));
return 0;
}
- rtc_tm_to_time(&tm, &newtime);
- if (newtime <= oldtime) {
- if (newtime < oldtime)
+ rtc_tm_to_time(&tm, &new_rtc.tv_sec);
+ new_rtc.tv_nsec = 0;
+
+ if (new_rtc.tv_sec <= old_rtc.tv_sec) {
+ if (new_rtc.tv_sec < old_rtc.tv_sec)
pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
return 0;
}
- /* calculate the RTC time delta */
- set_normalized_timespec(&time, newtime - oldtime, 0);
- /* subtract kernel time between rtc_suspend to rtc_resume */
- time = timespec_sub(time, timespec_sub(newts, oldts));
+ /* calculate the RTC time delta (sleep time)*/
+ sleep_time = timespec_sub(new_rtc, old_rtc);
+
+ /*
+ * Since these RTC suspend/resume handlers are not called
+ * at the very end of suspend or the start of resume,
+ * some run-time may pass on either sides of the sleep time
+ * 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));
- timekeeping_inject_sleeptime(&time);
+ timekeeping_inject_sleeptime(&sleep_time);
return 0;
}
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index df68618f6db..44e91e598f8 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -636,6 +636,29 @@ void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
}
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
+static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
+{
+ /*
+ * We always cancel the timer here first, because otherwise
+ * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
+ * when we manage to start the timer before the callback
+ * returns HRTIMER_RESTART.
+ *
+ * We cannot use hrtimer_cancel() here as a running callback
+ * could be blocked on rtc->irq_task_lock and hrtimer_cancel()
+ * would spin forever.
+ */
+ if (hrtimer_try_to_cancel(&rtc->pie_timer) < 0)
+ return -1;
+
+ if (enabled) {
+ ktime_t period = ktime_set(0, NSEC_PER_SEC / rtc->irq_freq);
+
+ hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
+ }
+ return 0;
+}
+
/**
* rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
* @rtc: the rtc device
@@ -651,21 +674,21 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
int err = 0;
unsigned long flags;
+retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
-
- if (enabled) {
- ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
- hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
- } else {
- hrtimer_cancel(&rtc->pie_timer);
+ if (!err) {
+ if (rtc_update_hrtimer(rtc, enabled) < 0) {
+ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+ cpu_relax();
+ goto retry;
+ }
+ rtc->pie_enabled = enabled;
}
- rtc->pie_enabled = enabled;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
-
return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
@@ -685,22 +708,20 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
int err = 0;
unsigned long flags;
- if (freq <= 0)
+ if (freq <= 0 || freq > RTC_MAX_FREQ)
return -EINVAL;
-
+retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
- if (err == 0) {
+ if (!err) {
rtc->irq_freq = freq;
- if (rtc->pie_enabled) {
- ktime_t period;
- hrtimer_cancel(&rtc->pie_timer);
- period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
- hrtimer_start(&rtc->pie_timer, period,
- HRTIMER_MODE_REL);
+ if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
+ spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+ cpu_relax();
+ goto retry;
}
}
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index e725d51e773..8dd08305aae 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -223,7 +223,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
}
rtc->irq = irq;
- rtc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ rtc->regs = ioremap(regs->start, resource_size(regs));
if (!rtc->regs) {
ret = -ENOMEM;
dev_dbg(&pdev->dev, "could not map I/O memory\n");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 911e75cdc12..05beb6c1ca7 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -606,7 +606,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* (needing ioremap etc), not i/o space resources like this ...
*/
ports = request_region(ports->start,
- ports->end + 1 - ports->start,
+ resource_size(ports),
driver_name);
if (!ports) {
dev_dbg(dev, "i/o registers already in use\n");
@@ -750,7 +750,7 @@ cleanup1:
cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
cleanup0:
- release_region(ports->start, ports->end + 1 - ports->start);
+ release_region(ports->start, resource_size(ports));
return retval;
}
@@ -779,7 +779,7 @@ static void __exit cmos_do_remove(struct device *dev)
cmos->rtc = NULL;
ports = cmos->iomem;
- release_region(ports->start, ports->end + 1 - ports->start);
+ release_region(ports->start, resource_size(ports));
cmos->iomem = NULL;
cmos->dev = NULL;
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c
index 47e681df31e..68e6caf2549 100644
--- a/drivers/rtc/rtc-ds1286.c
+++ b/drivers/rtc/rtc-ds1286.c
@@ -343,7 +343,7 @@ static int __devinit ds1286_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- priv->size = res->end - res->start + 1;
+ priv->size = resource_size(res);
if (!request_mem_region(res->start, priv->size, pdev->name)) {
ret = -EBUSY;
goto out;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 4724ba3acf1..b2005b44e4f 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -149,6 +149,7 @@ static const struct i2c_device_id ds1307_id[] = {
{ "ds1340", ds_1340 },
{ "ds3231", ds_3231 },
{ "m41t00", m41t00 },
+ { "pt7c4338", ds_1307 },
{ "rx8025", rx_8025 },
{ }
};
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index fbabc773dde..568ad30617e 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -490,7 +490,7 @@ ds1511_rtc_probe(struct platform_device *pdev)
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->size = res->end - res->start + 1;
+ pdata->size = resource_size(res);
if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
pdev->name))
return -EBUSY;
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 042630c90dd..d84a448dd75 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -173,7 +173,7 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->size = res->end - res->start + 1;
+ pdata->size = resource_size(res);
if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
pdev->name))
return -EBUSY;
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
index 7410875e583..8e2a24e33ed 100644
--- a/drivers/rtc/rtc-m48t35.c
+++ b/drivers/rtc/rtc-m48t35.c
@@ -154,7 +154,7 @@ static int __devinit m48t35_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- priv->size = res->end - res->start + 1;
+ priv->size = resource_size(res);
/*
* kludge: remove the #ifndef after ioc3 resource
* conflicts are resolved
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 3978f4caf72..28365388fb6 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -433,7 +433,7 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
if (!m48t59->ioaddr) {
/* ioaddr not mapped externally */
- m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1);
+ m48t59->ioaddr = ioremap(res->start, resource_size(res));
if (!m48t59->ioaddr)
goto out;
}
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index 09ccd8d3ba2..da60915818b 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -3,6 +3,7 @@
*
* Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
* Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright 2011, Dmitry Eremin-Solenikov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -145,6 +146,55 @@ static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
return 0;
}
+static int mpc5200_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int tmp;
+
+ tm->tm_sec = in_8(&regs->second);
+ tm->tm_min = in_8(&regs->minute);
+
+ /* 12 hour format? */
+ if (in_8(&regs->hour) & 0x20)
+ tm->tm_hour = (in_8(&regs->hour) >> 1) +
+ (in_8(&regs->hour) & 1 ? 12 : 0);
+ else
+ tm->tm_hour = in_8(&regs->hour);
+
+ tmp = in_8(&regs->wday_mday);
+ tm->tm_mday = tmp & 0x1f;
+ tm->tm_mon = in_8(&regs->month) - 1;
+ tm->tm_year = in_be16(&regs->year) - 1900;
+ tm->tm_wday = (tmp >> 5) % 7;
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_isdst = 0;
+
+ return 0;
+}
+
+static int mpc5200_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ mpc5121_rtc_update_smh(regs, tm);
+
+ /* date */
+ out_8(&regs->month_set, tm->tm_mon + 1);
+ out_8(&regs->weekday_set, tm->tm_wday ? tm->tm_wday : 7);
+ out_8(&regs->date_set, tm->tm_mday);
+ out_be16(&regs->year_set, tm->tm_year + 1900);
+
+ /* set date sequence */
+ out_8(&regs->set_date, 0x1);
+ out_8(&regs->set_date, 0x3);
+ out_8(&regs->set_date, 0x1);
+ out_8(&regs->set_date, 0x0);
+
+ return 0;
+}
+
static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
@@ -248,11 +298,18 @@ static const struct rtc_class_ops mpc5121_rtc_ops = {
.alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
};
+static const struct rtc_class_ops mpc5200_rtc_ops = {
+ .read_time = mpc5200_rtc_read_time,
+ .set_time = mpc5200_rtc_set_time,
+ .read_alarm = mpc5121_rtc_read_alarm,
+ .set_alarm = mpc5121_rtc_set_alarm,
+ .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
+};
+
static int __devinit mpc5121_rtc_probe(struct platform_device *op)
{
struct mpc5121_rtc_data *rtc;
int err = 0;
- u32 ka;
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (!rtc)
@@ -287,15 +344,22 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op)
goto out_dispose2;
}
- ka = in_be32(&rtc->regs->keep_alive);
- if (ka & 0x02) {
- dev_warn(&op->dev,
- "mpc5121-rtc: Battery or oscillator failure!\n");
- out_be32(&rtc->regs->keep_alive, ka);
+ if (of_device_is_compatible(op->dev.of_node, "fsl,mpc5121-rtc")) {
+ u32 ka;
+ ka = in_be32(&rtc->regs->keep_alive);
+ if (ka & 0x02) {
+ dev_warn(&op->dev,
+ "mpc5121-rtc: Battery or oscillator failure!\n");
+ out_be32(&rtc->regs->keep_alive, ka);
+ }
+
+ rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
+ &mpc5121_rtc_ops, THIS_MODULE);
+ } else {
+ rtc->rtc = rtc_device_register("mpc5200-rtc", &op->dev,
+ &mpc5200_rtc_ops, THIS_MODULE);
}
- rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
- &mpc5121_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
err = PTR_ERR(rtc->rtc);
goto out_free_irq;
@@ -340,6 +404,7 @@ static int __devexit mpc5121_rtc_remove(struct platform_device *op)
static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
{ .compatible = "fsl,mpc5121-rtc", },
+ { .compatible = "fsl,mpc5200-rtc", },
{},
};
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
index 0cec5650d56..d33544802a2 100644
--- a/drivers/rtc/rtc-mrst.c
+++ b/drivers/rtc/rtc-mrst.c
@@ -332,9 +332,8 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq)
if (!iomem)
return -ENODEV;
- iomem = request_mem_region(iomem->start,
- iomem->end + 1 - iomem->start,
- driver_name);
+ iomem = request_mem_region(iomem->start, resource_size(iomem),
+ driver_name);
if (!iomem) {
dev_dbg(dev, "i/o mem already in use.\n");
return -EBUSY;
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index bcae8dd4149..7789002bdd5 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -368,7 +368,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
pr_info("%s: already running\n", pdev->name);
/* 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:
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
new file mode 100644
index 00000000000..d420e9d877e
--- /dev/null
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -0,0 +1,550 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/rtc.h>
+
+
+/* RTC Register offsets from RTC CTRL REG */
+#define PM8XXX_ALARM_CTRL_OFFSET 0x01
+#define PM8XXX_RTC_WRITE_OFFSET 0x02
+#define PM8XXX_RTC_READ_OFFSET 0x06
+#define PM8XXX_ALARM_RW_OFFSET 0x0A
+
+/* RTC_CTRL register bit fields */
+#define PM8xxx_RTC_ENABLE BIT(7)
+#define PM8xxx_RTC_ALARM_ENABLE BIT(1)
+#define PM8xxx_RTC_ALARM_CLEAR BIT(0)
+
+#define NUM_8_BIT_RTC_REGS 0x4
+
+/**
+ * struct pm8xxx_rtc - rtc driver internal structure
+ * @rtc: rtc device for this driver.
+ * @rtc_alarm_irq: rtc alarm irq number.
+ * @rtc_base: address of rtc control register.
+ * @rtc_read_base: base address of read registers.
+ * @rtc_write_base: base address of write registers.
+ * @alarm_rw_base: base address of alarm registers.
+ * @ctrl_reg: rtc control register.
+ * @rtc_dev: device structure.
+ * @ctrl_reg_lock: spinlock protecting access to ctrl_reg.
+ */
+struct pm8xxx_rtc {
+ struct rtc_device *rtc;
+ int rtc_alarm_irq;
+ int rtc_base;
+ int rtc_read_base;
+ int rtc_write_base;
+ int alarm_rw_base;
+ u8 ctrl_reg;
+ struct device *rtc_dev;
+ spinlock_t ctrl_reg_lock;
+};
+
+/*
+ * The RTC registers need to be read/written one byte at a time. This is a
+ * hardware limitation.
+ */
+static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
+ int base, int count)
+{
+ int i, rc;
+ struct device *parent = rtc_dd->rtc_dev->parent;
+
+ for (i = 0; i < count; i++) {
+ rc = pm8xxx_readb(parent, base + i, &rtc_val[i]);
+ if (rc < 0) {
+ dev_err(rtc_dd->rtc_dev, "PMIC read failed\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val,
+ int base, int count)
+{
+ int i, rc;
+ struct device *parent = rtc_dd->rtc_dev->parent;
+
+ for (i = 0; i < count; i++) {
+ rc = pm8xxx_writeb(parent, base + i, rtc_val[i]);
+ if (rc < 0) {
+ dev_err(rtc_dd->rtc_dev, "PMIC write failed\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Steps to write the RTC registers.
+ * 1. Disable alarm if enabled.
+ * 2. Write 0x00 to LSB.
+ * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
+ * 4. Enable alarm if disabled in step 1.
+ */
+static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ int rc, i;
+ unsigned long secs, irq_flags;
+ u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg;
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ rtc_tm_to_time(tm, &secs);
+
+ for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
+ value[i] = secs & 0xFF;
+ secs >>= 8;
+ }
+
+ dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
+
+ spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+ ctrl_reg = rtc_dd->ctrl_reg;
+
+ if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) {
+ alarm_enabled = 1;
+ ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+ rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
+ 1);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC control register "
+ "failed\n");
+ goto rtc_rw_fail;
+ }
+ rtc_dd->ctrl_reg = ctrl_reg;
+ } else
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+
+ /* Write 0 to Byte[0] */
+ reg = 0;
+ rc = pm8xxx_write_wrapper(rtc_dd, &reg, rtc_dd->rtc_write_base, 1);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC write data register failed\n");
+ goto rtc_rw_fail;
+ }
+
+ /* Write Byte[1], Byte[2], Byte[3] */
+ rc = pm8xxx_write_wrapper(rtc_dd, value + 1,
+ rtc_dd->rtc_write_base + 1, 3);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC write data register failed\n");
+ goto rtc_rw_fail;
+ }
+
+ /* Write Byte[0] */
+ rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC write data register failed\n");
+ goto rtc_rw_fail;
+ }
+
+ if (alarm_enabled) {
+ ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE;
+ rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
+ 1);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC control register "
+ "failed\n");
+ goto rtc_rw_fail;
+ }
+ rtc_dd->ctrl_reg = ctrl_reg;
+ }
+
+rtc_rw_fail:
+ if (alarm_enabled)
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+
+ return rc;
+}
+
+static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ int rc;
+ u8 value[NUM_8_BIT_RTC_REGS], reg;
+ unsigned long secs;
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base,
+ NUM_8_BIT_RTC_REGS);
+ if (rc < 0) {
+ dev_err(dev, "RTC read data register failed\n");
+ return rc;
+ }
+
+ /*
+ * Read the LSB again and check if there has been a carry over.
+ * If there is, redo the read operation.
+ */
+ rc = pm8xxx_read_wrapper(rtc_dd, &reg, rtc_dd->rtc_read_base, 1);
+ if (rc < 0) {
+ dev_err(dev, "RTC read data register failed\n");
+ return rc;
+ }
+
+ if (unlikely(reg < value[0])) {
+ rc = pm8xxx_read_wrapper(rtc_dd, value,
+ rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS);
+ if (rc < 0) {
+ dev_err(dev, "RTC read data register failed\n");
+ return rc;
+ }
+ }
+
+ secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
+
+ rtc_time_to_tm(secs, tm);
+
+ rc = rtc_valid_tm(tm);
+ if (rc < 0) {
+ dev_err(dev, "Invalid time read from RTC\n");
+ return rc;
+ }
+
+ dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n",
+ secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ return 0;
+}
+
+static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ int rc, i;
+ u8 value[NUM_8_BIT_RTC_REGS], ctrl_reg;
+ unsigned long secs, irq_flags;
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ rtc_tm_to_time(&alarm->time, &secs);
+
+ for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
+ value[i] = secs & 0xFF;
+ secs >>= 8;
+ }
+
+ spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+
+ rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
+ NUM_8_BIT_RTC_REGS);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC ALARM register failed\n");
+ goto rtc_rw_fail;
+ }
+
+ ctrl_reg = rtc_dd->ctrl_reg;
+ ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
+ (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
+
+ rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC control register failed\n");
+ goto rtc_rw_fail;
+ }
+
+ rtc_dd->ctrl_reg = ctrl_reg;
+
+ dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
+ alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec, alarm->time.tm_mday,
+ alarm->time.tm_mon, alarm->time.tm_year);
+rtc_rw_fail:
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+ return rc;
+}
+
+static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ int rc;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ unsigned long secs;
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base,
+ NUM_8_BIT_RTC_REGS);
+ if (rc < 0) {
+ dev_err(dev, "RTC alarm time read failed\n");
+ return rc;
+ }
+
+ secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
+
+ rtc_time_to_tm(secs, &alarm->time);
+
+ rc = rtc_valid_tm(&alarm->time);
+ if (rc < 0) {
+ dev_err(dev, "Invalid alarm time read from RTC\n");
+ return rc;
+ }
+
+ dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
+ alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec, alarm->time.tm_mday,
+ alarm->time.tm_mon, alarm->time.tm_year);
+
+ return 0;
+}
+
+static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ int rc;
+ unsigned long irq_flags;
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ u8 ctrl_reg;
+
+ spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+ ctrl_reg = rtc_dd->ctrl_reg;
+ ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) :
+ (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE);
+
+ rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
+ if (rc < 0) {
+ dev_err(dev, "Write to RTC control register failed\n");
+ goto rtc_rw_fail;
+ }
+
+ rtc_dd->ctrl_reg = ctrl_reg;
+
+rtc_rw_fail:
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+ return rc;
+}
+
+static struct rtc_class_ops pm8xxx_rtc_ops = {
+ .read_time = pm8xxx_rtc_read_time,
+ .set_alarm = pm8xxx_rtc_set_alarm,
+ .read_alarm = pm8xxx_rtc_read_alarm,
+ .alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
+{
+ struct pm8xxx_rtc *rtc_dd = dev_id;
+ u8 ctrl_reg;
+ int rc;
+ unsigned long irq_flags;
+
+ rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF);
+
+ spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+
+ /* Clear the alarm enable bit */
+ ctrl_reg = rtc_dd->ctrl_reg;
+ ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE;
+
+ rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+ dev_err(rtc_dd->rtc_dev, "Write to RTC control register "
+ "failed\n");
+ goto rtc_alarm_handled;
+ }
+
+ rtc_dd->ctrl_reg = ctrl_reg;
+ spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
+
+ /* Clear RTC alarm register */
+ rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
+ PM8XXX_ALARM_CTRL_OFFSET, 1);
+ if (rc < 0) {
+ dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read "
+ "failed\n");
+ goto rtc_alarm_handled;
+ }
+
+ ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR;
+ rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base +
+ PM8XXX_ALARM_CTRL_OFFSET, 1);
+ if (rc < 0)
+ dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register"
+ " failed\n");
+
+rtc_alarm_handled:
+ return IRQ_HANDLED;
+}
+
+static int __devinit pm8xxx_rtc_probe(struct platform_device *pdev)
+{
+ int rc;
+ u8 ctrl_reg;
+ bool rtc_write_enable = false;
+ struct pm8xxx_rtc *rtc_dd;
+ struct resource *rtc_resource;
+ const struct pm8xxx_rtc_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+
+ if (pdata != NULL)
+ rtc_write_enable = pdata->rtc_write_enable;
+
+ rtc_dd = kzalloc(sizeof(*rtc_dd), GFP_KERNEL);
+ if (rtc_dd == NULL) {
+ dev_err(&pdev->dev, "Unable to allocate memory!\n");
+ return -ENOMEM;
+ }
+
+ /* Initialise spinlock to protect RTC control register */
+ spin_lock_init(&rtc_dd->ctrl_reg_lock);
+
+ rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
+ if (rtc_dd->rtc_alarm_irq < 0) {
+ dev_err(&pdev->dev, "Alarm IRQ resource absent!\n");
+ rc = -ENXIO;
+ goto fail_rtc_enable;
+ }
+
+ rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
+ "pmic_rtc_base");
+ if (!(rtc_resource && rtc_resource->start)) {
+ dev_err(&pdev->dev, "RTC IO resource absent!\n");
+ rc = -ENXIO;
+ goto fail_rtc_enable;
+ }
+
+ rtc_dd->rtc_base = rtc_resource->start;
+
+ /* Setup RTC register addresses */
+ rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET;
+ rtc_dd->rtc_read_base = rtc_dd->rtc_base + PM8XXX_RTC_READ_OFFSET;
+ rtc_dd->alarm_rw_base = rtc_dd->rtc_base + PM8XXX_ALARM_RW_OFFSET;
+
+ rtc_dd->rtc_dev = &pdev->dev;
+
+ /* Check if the RTC is on, else turn it on */
+ rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "RTC control register read failed!\n");
+ goto fail_rtc_enable;
+ }
+
+ if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
+ ctrl_reg |= PM8xxx_RTC_ENABLE;
+ rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base,
+ 1);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Write to RTC control register "
+ "failed\n");
+ goto fail_rtc_enable;
+ }
+ }
+
+ rtc_dd->ctrl_reg = ctrl_reg;
+ if (rtc_write_enable == true)
+ pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time;
+
+ platform_set_drvdata(pdev, rtc_dd);
+
+ /* Register the RTC device */
+ rtc_dd->rtc = rtc_device_register("pm8xxx_rtc", &pdev->dev,
+ &pm8xxx_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc_dd->rtc)) {
+ dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",
+ __func__, PTR_ERR(rtc_dd->rtc));
+ rc = PTR_ERR(rtc_dd->rtc);
+ goto fail_rtc_enable;
+ }
+
+ /* Request the alarm IRQ */
+ rc = request_any_context_irq(rtc_dd->rtc_alarm_irq,
+ pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING,
+ "pm8xxx_rtc_alarm", rtc_dd);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
+ goto fail_req_irq;
+ }
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ dev_dbg(&pdev->dev, "Probe success !!\n");
+
+ return 0;
+
+fail_req_irq:
+ rtc_device_unregister(rtc_dd->rtc);
+fail_rtc_enable:
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc_dd);
+ return rc;
+}
+
+static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, 0);
+ free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
+ rtc_device_unregister(rtc_dd->rtc);
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc_dd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pm8xxx_rtc_resume(struct device *dev)
+{
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(rtc_dd->rtc_alarm_irq);
+
+ return 0;
+}
+
+static int pm8xxx_rtc_suspend(struct device *dev)
+{
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(rtc_dd->rtc_alarm_irq);
+
+ return 0;
+}
+#endif
+
+SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
+
+static struct platform_driver pm8xxx_rtc_driver = {
+ .probe = pm8xxx_rtc_probe,
+ .remove = __devexit_p(pm8xxx_rtc_remove),
+ .driver = {
+ .name = PM8XXX_RTC_DEV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &pm8xxx_rtc_pm_ops,
+ },
+};
+
+static int __init pm8xxx_rtc_init(void)
+{
+ return platform_driver_register(&pm8xxx_rtc_driver);
+}
+module_init(pm8xxx_rtc_init);
+
+static void __exit pm8xxx_rtc_exit(void)
+{
+ platform_driver_unregister(&pm8xxx_rtc_driver);
+}
+module_exit(pm8xxx_rtc_exit);
+
+MODULE_ALIAS("platform:rtc-pm8xxx");
+MODULE_DESCRIPTION("PMIC8xxx RTC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>");
diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c
index 46f14b82f3a..b3eba3cddd4 100644
--- a/drivers/rtc/rtc-puv3.c
+++ b/drivers/rtc/rtc-puv3.c
@@ -267,9 +267,8 @@ static int puv3_rtc_probe(struct platform_device *pdev)
return -ENOENT;
}
- puv3_rtc_mem = request_mem_region(res->start,
- res->end-res->start+1,
- pdev->name);
+ puv3_rtc_mem = request_mem_region(res->start, resource_size(res),
+ pdev->name);
if (puv3_rtc_mem == NULL) {
dev_err(&pdev->dev, "failed to reserve memory region\n");
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 16512ecae31..4e7c04e773e 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -57,11 +57,13 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
{
struct rtc_device *rdev = id;
+ clk_enable(rtc_clk);
rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP);
+ clk_disable(rtc_clk);
return IRQ_HANDLED;
}
@@ -69,11 +71,13 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
{
struct rtc_device *rdev = id;
+ clk_enable(rtc_clk);
rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP);
+ clk_disable(rtc_clk);
return IRQ_HANDLED;
}
@@ -84,12 +88,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
pr_debug("%s: aie=%d\n", __func__, enabled);
+ clk_enable(rtc_clk);
tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
if (enabled)
tmp |= S3C2410_RTCALM_ALMEN;
writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
+ clk_disable(rtc_clk);
return 0;
}
@@ -103,6 +109,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq)
if (!is_power_of_2(freq))
return -EINVAL;
+ clk_enable(rtc_clk);
spin_lock_irq(&s3c_rtc_pie_lock);
if (s3c_rtc_cpu_type == TYPE_S3C2410) {
@@ -114,6 +121,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq)
writel(tmp, s3c_rtc_base + S3C2410_TICNT);
spin_unlock_irq(&s3c_rtc_pie_lock);
+ clk_disable(rtc_clk);
return 0;
}
@@ -125,6 +133,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
unsigned int have_retried = 0;
void __iomem *base = s3c_rtc_base;
+ clk_enable(rtc_clk);
retry_get_time:
rtc_tm->tm_min = readb(base + S3C2410_RTCMIN);
rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
@@ -143,10 +152,6 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
goto retry_get_time;
}
- pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
- 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
- rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
-
rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
@@ -155,8 +160,14 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
rtc_tm->tm_year += 100;
+
+ pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
+ 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+ rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
rtc_tm->tm_mon -= 1;
+ clk_disable(rtc_clk);
return rtc_valid_tm(rtc_tm);
}
@@ -165,6 +176,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
void __iomem *base = s3c_rtc_base;
int year = tm->tm_year - 100;
+ clk_enable(rtc_clk);
pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n",
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -182,6 +194,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);
writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);
writeb(bin2bcd(year), base + S3C2410_RTCYEAR);
+ clk_disable(rtc_clk);
return 0;
}
@@ -192,6 +205,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
void __iomem *base = s3c_rtc_base;
unsigned int alm_en;
+ clk_enable(rtc_clk);
alm_tm->tm_sec = readb(base + S3C2410_ALMSEC);
alm_tm->tm_min = readb(base + S3C2410_ALMMIN);
alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);
@@ -243,6 +257,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
else
alm_tm->tm_year = -1;
+ clk_disable(rtc_clk);
return 0;
}
@@ -252,12 +267,12 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
void __iomem *base = s3c_rtc_base;
unsigned int alrm_en;
+ clk_enable(rtc_clk);
pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alrm->enabled,
- 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
-
alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
writeb(0x00, base + S3C2410_RTCALM);
@@ -282,6 +297,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
s3c_rtc_setaie(dev, alrm->enabled);
+ clk_disable(rtc_clk);
return 0;
}
@@ -289,6 +305,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
{
unsigned int ticnt;
+ clk_enable(rtc_clk);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
ticnt = readw(s3c_rtc_base + S3C2410_RTCCON);
ticnt &= S3C64XX_RTCCON_TICEN;
@@ -298,52 +315,11 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
}
seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
+ clk_disable(rtc_clk);
return 0;
}
-static int s3c_rtc_open(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
- int ret;
-
- ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
- IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev);
-
- if (ret) {
- dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
- return ret;
- }
-
- ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
- IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev);
-
- if (ret) {
- dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
- goto tick_err;
- }
-
- return ret;
-
- tick_err:
- free_irq(s3c_rtc_alarmno, rtc_dev);
- return ret;
-}
-
-static void s3c_rtc_release(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
-
- /* do not clear AIE here, it may be needed for wake */
-
- free_irq(s3c_rtc_alarmno, rtc_dev);
- free_irq(s3c_rtc_tickno, rtc_dev);
-}
-
static const struct rtc_class_ops s3c_rtcops = {
- .open = s3c_rtc_open,
- .release = s3c_rtc_release,
.read_time = s3c_rtc_gettime,
.set_time = s3c_rtc_settime,
.read_alarm = s3c_rtc_getalarm,
@@ -360,6 +336,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
if (s3c_rtc_base == NULL)
return;
+ clk_enable(rtc_clk);
if (!en) {
tmp = readw(base + S3C2410_RTCCON);
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
@@ -399,18 +376,21 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
base + S3C2410_RTCCON);
}
}
+ clk_disable(rtc_clk);
}
static int __devexit s3c_rtc_remove(struct platform_device *dev)
{
struct rtc_device *rtc = platform_get_drvdata(dev);
+ free_irq(s3c_rtc_alarmno, rtc);
+ free_irq(s3c_rtc_tickno, rtc);
+
platform_set_drvdata(dev, NULL);
rtc_device_unregister(rtc);
s3c_rtc_setaie(&dev->dev, 0);
- clk_disable(rtc_clk);
clk_put(rtc_clk);
rtc_clk = NULL;
@@ -455,8 +435,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
return -ENOENT;
}
- s3c_rtc_mem = request_mem_region(res->start,
- res->end-res->start+1,
+ s3c_rtc_mem = request_mem_region(res->start, resource_size(res),
pdev->name);
if (s3c_rtc_mem == NULL) {
@@ -465,7 +444,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
goto err_nores;
}
- s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);
+ s3c_rtc_base = ioremap(res->start, resource_size(res));
if (s3c_rtc_base == NULL) {
dev_err(&pdev->dev, "failed ioremap()\n");
ret = -EINVAL;
@@ -530,8 +509,32 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
s3c_rtc_setfreq(&pdev->dev, 1);
+ ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
+ IRQF_DISABLED, "s3c2410-rtc alarm", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
+ goto err_alarm_irq;
+ }
+
+ ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
+ IRQF_DISABLED, "s3c2410-rtc tick", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
+ free_irq(s3c_rtc_alarmno, rtc);
+ goto err_tick_irq;
+ }
+
+ clk_disable(rtc_clk);
+
return 0;
+ err_tick_irq:
+ free_irq(s3c_rtc_alarmno, rtc);
+
+ err_alarm_irq:
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(rtc);
+
err_nortc:
s3c_rtc_enable(pdev, 0);
clk_disable(rtc_clk);
@@ -555,6 +558,7 @@ static int ticnt_save, ticnt_en_save;
static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
+ clk_enable(rtc_clk);
/* save TICNT for anyone using periodic interrupts */
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
@@ -569,6 +573,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
else
dev_err(&pdev->dev, "enable_irq_wake failed\n");
}
+ clk_disable(rtc_clk);
return 0;
}
@@ -577,6 +582,7 @@ static int s3c_rtc_resume(struct platform_device *pdev)
{
unsigned int tmp;
+ clk_enable(rtc_clk);
s3c_rtc_enable(pdev, 1);
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
@@ -588,6 +594,7 @@ static int s3c_rtc_resume(struct platform_device *pdev)
disable_irq_wake(s3c_rtc_alarmno);
wake_en = false;
}
+ clk_disable(rtc_clk);
return 0;
}
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index 572e9534b59..7315068daa5 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -6,6 +6,7 @@
*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ * Copyright 2011 Wolfram Sang, Pengutronix e.K.
*/
/*
@@ -18,21 +19,41 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/rtc.h>
#include <linux/slab.h>
-#include <mach/platform.h>
-#include <mach/stmp3xxx.h>
-#include <mach/regs-rtc.h>
+#include <mach/common.h>
+
+#define STMP3XXX_RTC_CTRL 0x0
+#define STMP3XXX_RTC_CTRL_SET 0x4
+#define STMP3XXX_RTC_CTRL_CLR 0x8
+#define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001
+#define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002
+#define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004
+
+#define STMP3XXX_RTC_STAT 0x10
+#define STMP3XXX_RTC_STAT_STALE_SHIFT 16
+#define STMP3XXX_RTC_STAT_RTC_PRESENT 0x80000000
+
+#define STMP3XXX_RTC_SECONDS 0x30
+
+#define STMP3XXX_RTC_ALARM 0x40
+
+#define STMP3XXX_RTC_PERSISTENT0 0x60
+#define STMP3XXX_RTC_PERSISTENT0_SET 0x64
+#define STMP3XXX_RTC_PERSISTENT0_CLR 0x68
+#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002
+#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004
+#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080
struct stmp3xxx_rtc_data {
struct rtc_device *rtc;
- unsigned irq_count;
void __iomem *io;
- int irq_alarm, irq_1msec;
+ int irq_alarm;
};
static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data)
@@ -42,8 +63,8 @@ static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data)
* NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0,
* 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS
*/
- while (__raw_readl(rtc_data->io + HW_RTC_STAT) &
- BF(0x80, RTC_STAT_STALE_REGS))
+ while (readl(rtc_data->io + STMP3XXX_RTC_STAT) &
+ (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT))
cpu_relax();
}
@@ -53,7 +74,7 @@ static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
stmp3xxx_wait_time(rtc_data);
- rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_SECONDS), rtc_tm);
+ rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm);
return 0;
}
@@ -61,7 +82,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t)
{
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
- __raw_writel(t, rtc_data->io + HW_RTC_SECONDS);
+ writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS);
stmp3xxx_wait_time(rtc_data);
return 0;
}
@@ -70,47 +91,34 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t)
static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id)
{
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev_id);
- u32 status;
- u32 events = 0;
-
- status = __raw_readl(rtc_data->io + HW_RTC_CTRL) &
- (BM_RTC_CTRL_ALARM_IRQ | BM_RTC_CTRL_ONEMSEC_IRQ);
+ u32 status = readl(rtc_data->io + STMP3XXX_RTC_CTRL);
- if (status & BM_RTC_CTRL_ALARM_IRQ) {
- stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ,
- rtc_data->io + HW_RTC_CTRL);
- events |= RTC_AF | RTC_IRQF;
+ if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) {
+ writel(STMP3XXX_RTC_CTRL_ALARM_IRQ,
+ rtc_data->io + STMP3XXX_RTC_CTRL_CLR);
+ rtc_update_irq(rtc_data->rtc, 1, RTC_AF | RTC_IRQF);
+ return IRQ_HANDLED;
}
- if (status & BM_RTC_CTRL_ONEMSEC_IRQ) {
- stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ,
- rtc_data->io + HW_RTC_CTRL);
- if (++rtc_data->irq_count % 1000 == 0) {
- events |= RTC_UF | RTC_IRQF;
- rtc_data->irq_count = 0;
- }
- }
-
- if (events)
- rtc_update_irq(rtc_data->rtc, 1, events);
-
- return IRQ_HANDLED;
+ return IRQ_NONE;
}
static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
- void __iomem *p = rtc_data->io + HW_RTC_PERSISTENT0,
- *ctl = rtc_data->io + HW_RTC_CTRL;
if (enabled) {
- stmp3xxx_setl(BM_RTC_PERSISTENT0_ALARM_EN |
- BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p);
- stmp3xxx_setl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl);
+ writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN |
+ STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN,
+ rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET);
+ writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
+ rtc_data->io + STMP3XXX_RTC_CTRL_SET);
} else {
- stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN |
- BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p);
- stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl);
+ writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN |
+ STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN,
+ rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR);
+ writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
+ rtc_data->io + STMP3XXX_RTC_CTRL_CLR);
}
return 0;
}
@@ -119,7 +127,7 @@ static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
- rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_ALARM), &alm->time);
+ rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_ALARM), &alm->time);
return 0;
}
@@ -129,7 +137,10 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
rtc_tm_to_time(&alm->time, &t);
- __raw_writel(t, rtc_data->io + HW_RTC_ALARM);
+ writel(t, rtc_data->io + STMP3XXX_RTC_ALARM);
+
+ stmp3xxx_alarm_irq_enable(dev, alm->enabled);
+
return 0;
}
@@ -149,11 +160,11 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev)
if (!rtc_data)
return 0;
- stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN,
- rtc_data->io + HW_RTC_CTRL);
+ writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
+ rtc_data->io + STMP3XXX_RTC_CTRL_CLR);
free_irq(rtc_data->irq_alarm, &pdev->dev);
- free_irq(rtc_data->irq_1msec, &pdev->dev);
rtc_device_unregister(rtc_data->rtc);
+ platform_set_drvdata(pdev, NULL);
iounmap(rtc_data->io);
kfree(rtc_data);
@@ -185,20 +196,26 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
}
rtc_data->irq_alarm = platform_get_irq(pdev, 0);
- rtc_data->irq_1msec = platform_get_irq(pdev, 1);
- if (!(__raw_readl(HW_RTC_STAT + rtc_data->io) &
- BM_RTC_STAT_RTC_PRESENT)) {
+ if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) &
+ STMP3XXX_RTC_STAT_RTC_PRESENT)) {
dev_err(&pdev->dev, "no device onboard\n");
err = -ENODEV;
goto out_remap;
}
- stmp3xxx_reset_block(rtc_data->io, true);
- stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN |
- BM_RTC_PERSISTENT0_ALARM_WAKE_EN |
- BM_RTC_PERSISTENT0_ALARM_WAKE,
- rtc_data->io + HW_RTC_PERSISTENT0);
+ platform_set_drvdata(pdev, rtc_data);
+
+ mxs_reset_block(rtc_data->io);
+ writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN |
+ STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN |
+ STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE,
+ rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR);
+
+ writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN |
+ STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
+ rtc_data->io + STMP3XXX_RTC_CTRL_CLR);
+
rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev,
&stmp3xxx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc_data->rtc)) {
@@ -206,33 +223,20 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
goto out_remap;
}
- rtc_data->irq_count = 0;
- err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt,
- IRQF_DISABLED, "RTC alarm", &pdev->dev);
+ err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, 0,
+ "RTC alarm", &pdev->dev);
if (err) {
dev_err(&pdev->dev, "Cannot claim IRQ%d\n",
rtc_data->irq_alarm);
goto out_irq_alarm;
}
- err = request_irq(rtc_data->irq_1msec, stmp3xxx_rtc_interrupt,
- IRQF_DISABLED, "RTC tick", &pdev->dev);
- if (err) {
- dev_err(&pdev->dev, "Cannot claim IRQ%d\n",
- rtc_data->irq_1msec);
- goto out_irq1;
- }
-
- platform_set_drvdata(pdev, rtc_data);
return 0;
-out_irq1:
- free_irq(rtc_data->irq_alarm, &pdev->dev);
out_irq_alarm:
- stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN,
- rtc_data->io + HW_RTC_CTRL);
rtc_device_unregister(rtc_data->rtc);
out_remap:
+ platform_set_drvdata(pdev, NULL);
iounmap(rtc_data->io);
out_free:
kfree(rtc_data);
@@ -249,11 +253,11 @@ static int stmp3xxx_rtc_resume(struct platform_device *dev)
{
struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev);
- stmp3xxx_reset_block(rtc_data->io, true);
- stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN |
- BM_RTC_PERSISTENT0_ALARM_WAKE_EN |
- BM_RTC_PERSISTENT0_ALARM_WAKE,
- rtc_data->io + HW_RTC_PERSISTENT0);
+ mxs_reset_block(rtc_data->io);
+ writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN |
+ STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN |
+ STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE,
+ rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR);
return 0;
}
#else
@@ -286,5 +290,6 @@ module_init(stmp3xxx_rtc_init);
module_exit(stmp3xxx_rtc_exit);
MODULE_DESCRIPTION("STMP3xxx RTC Driver");
-MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com>");
+MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com> and "
+ "Wolfram Sang <w.sang@pengutronix.de>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 2fc31aac3f4..75259fe3860 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -343,7 +343,7 @@ static int __devinit tegra_rtc_probe(struct platform_device *pdev)
/* set context info. */
info->pdev = pdev;
- info->tegra_rtc_lock = __SPIN_LOCK_UNLOCKED(info->tegra_rtc_lock);
+ spin_lock_init(&info->tegra_rtc_lock);
platform_set_drvdata(pdev, info);
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index f9a2799c44d..9a81f778d6b 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -275,7 +275,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
goto out;
save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
- twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+ ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
if (ret < 0)
goto out;
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
index b8bc862903a..f93f412423c 100644
--- a/drivers/rtc/rtc-vt8500.c
+++ b/drivers/rtc/rtc-vt8500.c
@@ -74,11 +74,12 @@
#define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */
#define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */
+#define VT8500_RTC_IS_ALARM (1 << 0) /* Alarm interrupt status */
+
struct vt8500_rtc {
void __iomem *regbase;
struct resource *res;
int irq_alarm;
- int irq_hz;
struct rtc_device *rtc;
spinlock_t lock; /* Protects this structure */
};
@@ -97,13 +98,9 @@ static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id)
spin_unlock(&vt8500_rtc->lock);
- if (isr & 1)
+ if (isr & VT8500_RTC_IS_ALARM)
events |= RTC_AF | RTC_IRQF;
- /* Only second/minute interrupts are supported */
- if (isr & 2)
- events |= RTC_UF | RTC_IRQF;
-
rtc_update_irq(vt8500_rtc->rtc, 1, events);
return IRQ_HANDLED;
@@ -166,8 +163,8 @@ static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK));
alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0;
+ alrm->pending = (isr & VT8500_RTC_IS_ALARM) ? 1 : 0;
- alrm->pending = (isr & 1) ? 1 : 0;
return rtc_valid_tm(&alrm->time);
}
@@ -199,27 +196,12 @@ static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled)
return 0;
}
-static int vt8500_update_irq_enable(struct device *dev, unsigned int enabled)
-{
- struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
- unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_CR);
-
- if (enabled)
- tmp |= VT8500_RTC_CR_SM_SEC | VT8500_RTC_CR_SM_ENABLE;
- else
- tmp &= ~VT8500_RTC_CR_SM_ENABLE;
-
- writel(tmp, vt8500_rtc->regbase + VT8500_RTC_CR);
- return 0;
-}
-
static const struct rtc_class_ops vt8500_rtc_ops = {
.read_time = vt8500_rtc_read_time,
.set_time = vt8500_rtc_set_time,
.read_alarm = vt8500_rtc_read_alarm,
.set_alarm = vt8500_rtc_set_alarm,
.alarm_irq_enable = vt8500_alarm_irq_enable,
- .update_irq_enable = vt8500_update_irq_enable,
};
static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
@@ -248,13 +230,6 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
goto err_free;
}
- vt8500_rtc->irq_hz = platform_get_irq(pdev, 1);
- if (vt8500_rtc->irq_hz < 0) {
- dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n");
- ret = -ENXIO;
- goto err_free;
- }
-
vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start,
resource_size(vt8500_rtc->res),
"vt8500-rtc");
@@ -272,9 +247,8 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
goto err_release;
}
- /* Enable the second/minute interrupt generation and enable RTC */
- writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H
- | VT8500_RTC_CR_SM_ENABLE | VT8500_RTC_CR_SM_SEC,
+ /* Enable RTC and set it to 24-hour mode */
+ writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H,
vt8500_rtc->regbase + VT8500_RTC_CR);
vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev,
@@ -286,26 +260,16 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
goto err_unmap;
}
- ret = request_irq(vt8500_rtc->irq_hz, vt8500_rtc_irq, 0,
- "rtc 1Hz", vt8500_rtc);
- if (ret < 0) {
- dev_err(&pdev->dev, "can't get irq %i, err %d\n",
- vt8500_rtc->irq_hz, ret);
- goto err_unreg;
- }
-
ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0,
"rtc alarm", vt8500_rtc);
if (ret < 0) {
dev_err(&pdev->dev, "can't get irq %i, err %d\n",
vt8500_rtc->irq_alarm, ret);
- goto err_free_hz;
+ goto err_unreg;
}
return 0;
-err_free_hz:
- free_irq(vt8500_rtc->irq_hz, vt8500_rtc);
err_unreg:
rtc_device_unregister(vt8500_rtc->rtc);
err_unmap:
@@ -323,7 +287,6 @@ static int __devexit vt8500_rtc_remove(struct platform_device *pdev)
struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
- free_irq(vt8500_rtc->irq_hz, vt8500_rtc);
rtc_device_unregister(vt8500_rtc->rtc);