summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-mxc_v2.c104
-rw-r--r--drivers/rtc/rtc-mxs.c2
4 files changed, 89 insertions, 28 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 09492700cddf..bd320c1ab70c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -109,6 +109,16 @@ config RTC_INTF_DEV_UIE_EMUL
clock several times per second, please enable this option
only if you know that you really need it.
+config RTC_INTF_ALARM
+ bool "Android alarm driver"
+ depends on RTC_CLASS
+ default y
+ help
+ Provides non-wakeup and rtc backed wakeup alarms based on rtc or
+ elapsed realtime, and a non-wakeup alarm on the monotonic clock.
+ Also provides an ioctl to set the wall time which must be used
+ for elapsed realtime to work.
+
config RTC_DRV_TEST
tristate "Test driver/device"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 91da97eca589..c8df86258348 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o
+rtc-core-$(CONFIG_RTC_INTF_ALARM) += alarm.o
rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
index 5d410fd9d5d2..beb31415a4da 100644
--- a/drivers/rtc/rtc-mxc_v2.c
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -37,6 +37,10 @@
#include <linux/uaccess.h>
#include <mach/hardware.h>
#include <asm/io.h>
+#include <linux/mxc_srtc.h>
+
+
+#define SRTC_LPSCLR_LLPSC_LSH 17 /* start bit for LSB time value */
#define SRTC_LPPDR_INIT 0x41736166 /* init for glitch detect */
@@ -147,6 +151,12 @@ struct rtc_drv_data {
bool irq_enable;
};
+
+/* completion event for implementing RTC_WAIT_FOR_TIME_SET ioctl */
+DECLARE_COMPLETION(srtc_completion);
+/* global to save difference of 47-bit counter value */
+static int64_t time_diff;
+
/*!
* @defgroup RTC Real Time Clock (RTC) Driver
*/
@@ -313,6 +323,8 @@ static int mxc_rtc_ioctl(struct device *dev, unsigned int cmd,
void __iomem *ioaddr = pdata->ioaddr;
unsigned long lock_flags = 0;
u32 lp_cr;
+ u64 time_47bit;
+ int retVal;
switch (cmd) {
case RTC_AIE_OFF:
@@ -339,6 +351,36 @@ static int mxc_rtc_ioctl(struct device *dev, unsigned int cmd,
__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
spin_unlock_irqrestore(&rtc_lock, lock_flags);
return 0;
+
+ case RTC_READ_TIME_47BIT:
+ time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
+ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
+ time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
+
+ if (arg && copy_to_user((u64 *) arg, &time_47bit, sizeof(u64)))
+ return -EFAULT;
+
+ return 0;
+
+ case RTC_WAIT_TIME_SET:
+
+ /* don't block without releasing mutex first */
+ mutex_unlock(&pdata->rtc->ops_lock);
+
+ /* sleep until awakened by SRTC driver when LPSCMR is changed */
+ wait_for_completion(&srtc_completion);
+
+ /* relock mutex because rtc_dev_ioctl will unlock again */
+ retVal = mutex_lock_interruptible(&pdata->rtc->ops_lock);
+
+ /* copy the new time difference = new time - previous time
+ * to the user param. The difference is a signed value */
+ if (arg && copy_to_user((int64_t *) arg, &time_diff,
+ sizeof(int64_t)))
+ return -EFAULT;
+
+ return retVal;
+
}
return -ENOIOCTLCMD;
@@ -372,14 +414,31 @@ static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct rtc_drv_data *pdata = dev_get_drvdata(dev);
void __iomem *ioaddr = pdata->ioaddr;
unsigned long time;
+ u64 old_time_47bit, new_time_47bit;
int ret;
ret = rtc_tm_to_time(tm, &time);
if (ret != 0)
return ret;
+ old_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
+ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
+ old_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
+
__raw_writel(time, ioaddr + SRTC_LPSCMR);
rtc_write_sync_lp(ioaddr);
+ new_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
+ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
+ new_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
+
+ /* update the difference between previous time and new time */
+ time_diff = new_time_47bit - old_time_47bit;
+
+ /* signal all waiting threads that time changed */
+ complete_all(&srtc_completion);
+ /* reinitialize completion variable */
+ INIT_COMPLETION(srtc_completion);
+
return 0;
}
@@ -549,41 +608,30 @@ static int mxc_rtc_probe(struct platform_device *pdev)
/* clear lp interrupt status */
__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
- udelay(100);;
+ udelay(100);
plat_data = (struct mxc_srtc_platform_data *)pdev->dev.platform_data;
- clk = clk_get(NULL, "iim_clk");
- clk_enable(clk);
- srtc_secmode_addr = ioremap(plat_data->srtc_sec_mode_addr, 1);
-
- /* Check SRTC security mode */
- if (((__raw_readl(srtc_secmode_addr) & SRTC_SECMODE_MASK) ==
- SRTC_SECMODE_LOW) && (cpu_is_mx51_rev(CHIP_REV_1_0) == 1)) {
- /* Workaround for MX51 TO1 due to inaccurate CKIL clock */
- __raw_writel(SRTC_LPCR_EN_LP, ioaddr + SRTC_LPCR);
- udelay(100);
- } else {
- /* move out of init state */
- __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA),
- ioaddr + SRTC_LPCR);
- udelay(100);
+ /* move out of init state */
+ __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA),
+ ioaddr + SRTC_LPCR);
- while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0);
+ udelay(100);
- /* move out of non-valid state */
- __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
- SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
+ while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
+ ;
- udelay(100);
+ /* move out of non-valid state */
+ __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
+ SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
- while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0);
+ udelay(100);
- __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
- udelay(100);
- }
- clk_disable(clk);
- clk_put(clk);
+ while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
+ ;
+
+ __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+ udelay(100);
rtc = rtc_device_register(pdev->name, &pdev->dev,
&mxc_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-mxs.c b/drivers/rtc/rtc-mxs.c
index 0e2b0e1e14f6..bb4c33b1a0ba 100644
--- a/drivers/rtc/rtc-mxs.c
+++ b/drivers/rtc/rtc-mxs.c
@@ -254,6 +254,8 @@ static int mxs_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc_data);
+ device_init_wakeup(&pdev->dev, 1);
+
return 0;
}