]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/rtc/rtc-vr41xx.c
rtc: update vr41xx alarm handling
[karo-tx-linux.git] / drivers / rtc / rtc-vr41xx.c
index 277596c302e30426262db9392be87355cfeb7114..af7596ef29e2d837f2c9c8ea6b6d4fc7b7d37102 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/div64.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/vr41xx/vr41xx.h>
+#include <asm/vr41xx/irq.h>
 
 MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
 MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
@@ -81,7 +81,6 @@ MODULE_LICENSE("GPL");
 
 #define RTC_FREQUENCY          32768
 #define MAX_PERIODIC_RATE      6553
-#define MAX_USER_PERIODIC_RATE 64
 
 static void __iomem *rtc1_base;
 static void __iomem *rtc2_base;
@@ -94,10 +93,11 @@ static void __iomem *rtc2_base;
 
 static unsigned long epoch = 1970;     /* Jan 1 1970 00:00:00 */
 
-static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rtc_lock);
 static char rtc_name[] = "RTC";
 static unsigned long periodic_frequency;
 static unsigned long periodic_count;
+static unsigned int alarm_enabled;
 
 struct resource rtc_resource[2] = {
        {       .name   = rtc_name,
@@ -189,6 +189,7 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
        low = rtc1_read(ECMPLREG);
        mid = rtc1_read(ECMPMREG);
        high = rtc1_read(ECMPHREG);
+       wkalrm->enabled = alarm_enabled;
 
        spin_unlock_irq(&rtc_lock);
 
@@ -207,10 +208,18 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 
        spin_lock_irq(&rtc_lock);
 
+       if (alarm_enabled)
+               disable_irq(ELAPSEDTIME_IRQ);
+
        rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
        rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
        rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
 
+       if (wkalrm->enabled)
+               enable_irq(ELAPSEDTIME_IRQ);
+
+       alarm_enabled = wkalrm->enabled;
+
        spin_unlock_irq(&rtc_lock);
 
        return 0;
@@ -222,10 +231,24 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
 
        switch (cmd) {
        case RTC_AIE_ON:
-               enable_irq(ELAPSEDTIME_IRQ);
+               spin_lock_irq(&rtc_lock);
+
+               if (!alarm_enabled) {
+                       enable_irq(ELAPSEDTIME_IRQ);
+                       alarm_enabled = 1;
+               }
+
+               spin_unlock_irq(&rtc_lock);
                break;
        case RTC_AIE_OFF:
-               disable_irq(ELAPSEDTIME_IRQ);
+               spin_lock_irq(&rtc_lock);
+
+               if (alarm_enabled) {
+                       disable_irq(ELAPSEDTIME_IRQ);
+                       alarm_enabled = 0;
+               }
+
+               spin_unlock_irq(&rtc_lock);
                break;
        case RTC_PIE_ON:
                enable_irq(RTCLONG1_IRQ);
@@ -240,9 +263,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
                if (arg > MAX_PERIODIC_RATE)
                        return -EINVAL;
 
-               if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0)
-                       return -EACCES;
-
                periodic_frequency = arg;
 
                count = RTC_FREQUENCY;
@@ -263,10 +283,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
                /* Doesn't support before 1900 */
                if (arg < 1900)
                        return -EINVAL;
-
-               if (capable(CAP_SYS_TIME) == 0)
-                       return -EACCES;
-
                epoch = arg;
                break;
        default:
@@ -276,19 +292,19 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
        return 0;
 }
 
-static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = (struct platform_device *)dev_id;
        struct rtc_device *rtc = platform_get_drvdata(pdev);
 
        rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
 
-       rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+       rtc_update_irq(rtc, 1, RTC_AF);
 
        return IRQ_HANDLED;
 }
 
-static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = (struct platform_device *)dev_id;
        struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -299,12 +315,12 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *reg
        rtc1_write(RTCL1LREG, count);
        rtc1_write(RTCL1HREG, count >> 16);
 
-       rtc_update_irq(&rtc->class_dev, 1, RTC_PF);
+       rtc_update_irq(rtc, 1, RTC_PF);
 
        return IRQ_HANDLED;
 }
 
-static struct rtc_class_ops vr41xx_rtc_ops = {
+static const struct rtc_class_ops vr41xx_rtc_ops = {
        .release        = vr41xx_rtc_release,
        .ioctl          = vr41xx_rtc_ioctl,
        .read_time      = vr41xx_rtc_read_time,
@@ -353,11 +369,11 @@ static int __devinit rtc_probe(struct platform_device *pdev)
        spin_unlock_irq(&rtc_lock);
 
        irq = ELAPSEDTIME_IRQ;
-       retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT,
+       retval = request_irq(irq, elapsedtime_interrupt, IRQF_DISABLED,
                             "elapsed_time", pdev);
        if (retval == 0) {
                irq = RTCLONG1_IRQ;
-               retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT,
+               retval = request_irq(irq, rtclong1_interrupt, IRQF_DISABLED,
                                     "rtclong1", pdev);
        }