diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 20 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/class.c | 65 | ||||
-rw-r--r-- | drivers/rtc/interface.c | 55 | ||||
-rw-r--r-- | drivers/rtc/rtc-at32ap700x.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 6 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1286.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1511.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1742.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-m48t35.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-m48t59.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-mpc5121.c | 81 | ||||
-rw-r--r-- | drivers/rtc/rtc-mrst.c | 5 | ||||
-rw-r--r-- | drivers/rtc/rtc-omap.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-pm8xxx.c | 550 | ||||
-rw-r--r-- | drivers/rtc/rtc-puv3.c | 5 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 111 | ||||
-rw-r--r-- | drivers/rtc/rtc-stmp3xxx.c | 153 | ||||
-rw-r--r-- | drivers/rtc/rtc-tegra.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-twl.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-vt8500.c | 51 |
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(®s->second); + tm->tm_min = in_8(®s->minute); + + /* 12 hour format? */ + if (in_8(®s->hour) & 0x20) + tm->tm_hour = (in_8(®s->hour) >> 1) + + (in_8(®s->hour) & 1 ? 12 : 0); + else + tm->tm_hour = in_8(®s->hour); + + tmp = in_8(®s->wday_mday); + tm->tm_mday = tmp & 0x1f; + tm->tm_mon = in_8(®s->month) - 1; + tm->tm_year = in_be16(®s->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(®s->month_set, tm->tm_mon + 1); + out_8(®s->weekday_set, tm->tm_wday ? tm->tm_wday : 7); + out_8(®s->date_set, tm->tm_mday); + out_be16(®s->year_set, tm->tm_year + 1900); + + /* set date sequence */ + out_8(®s->set_date, 0x1); + out_8(®s->set_date, 0x3); + out_8(®s->set_date, 0x1); + out_8(®s->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, ®, 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, ®, 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); |