]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/rtc/rtc-spear.c
selinuxfs: merge dentry allocation into sel_make_dir()
[mv-sheeva.git] / drivers / rtc / rtc-spear.c
index 19a28a671a8e74f8abbd5ed149f4aebc4769b75d..e38da0dc41872070e4d0abe40da9280b6ddf747a 100644 (file)
 #define STATUS_FAIL            (LOST_WR_TIME | LOST_WR_DATE)
 
 struct spear_rtc_config {
+       struct rtc_device *rtc;
        struct clk *clk;
        spinlock_t lock;
        void __iomem *ioaddr;
+       unsigned int irq_wake;
 };
 
 static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)
@@ -149,8 +151,7 @@ static void rtc_wait_not_busy(struct spear_rtc_config *config)
 
 static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
 {
-       struct rtc_device *rtc = (struct rtc_device *)dev_id;
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_id;
        unsigned long flags, events = 0;
        unsigned int irq_data;
 
@@ -161,7 +162,7 @@ static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
        if ((irq_data & RTC_INT_MASK)) {
                spear_rtc_clear_interrupt(config);
                events = RTC_IRQF | RTC_AF;
-               rtc_update_irq(rtc, 1, events);
+               rtc_update_irq(config->rtc, 1, events);
                return IRQ_HANDLED;
        } else
                return IRQ_NONE;
@@ -203,9 +204,7 @@ static void bcd2tm(struct rtc_time *tm)
  */
 static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date;
 
        /* we don't report wday/yday/isdst ... */
@@ -234,9 +233,7 @@ static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
  */
 static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date, err = 0;
 
        if (tm2bcd(tm) < 0)
@@ -266,9 +263,7 @@ static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
  */
 static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date;
 
        rtc_wait_not_busy(config);
@@ -298,9 +293,7 @@ static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
  */
 static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date, err = 0;
 
        if (tm2bcd(&alm->time) < 0)
@@ -326,17 +319,42 @@ static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
        return 0;
 }
+
+static int spear_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
+       int ret = 0;
+
+       spear_rtc_clear_interrupt(config);
+
+       switch (enabled) {
+       case 0:
+               /* alarm off */
+               spear_rtc_disable_interrupt(config);
+               break;
+       case 1:
+               /* alarm on */
+               spear_rtc_enable_interrupt(config);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static struct rtc_class_ops spear_rtc_ops = {
        .read_time = spear_rtc_read_time,
        .set_time = spear_rtc_set_time,
        .read_alarm = spear_rtc_read_alarm,
        .set_alarm = spear_rtc_set_alarm,
+       .alarm_irq_enable = spear_alarm_irq_enable,
 };
 
 static int __devinit spear_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
-       struct rtc_device *rtc;
        struct spear_rtc_config *config;
        unsigned int status = 0;
        int irq;
@@ -376,19 +394,17 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)
        }
 
        spin_lock_init(&config->lock);
+       platform_set_drvdata(pdev, config);
 
-       rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops,
-                       THIS_MODULE);
-       if (IS_ERR(rtc)) {
+       config->rtc = rtc_device_register(pdev->name, &pdev->dev,
+                       &spear_rtc_ops, THIS_MODULE);
+       if (IS_ERR(config->rtc)) {
                dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
-                               PTR_ERR(rtc));
-               status = PTR_ERR(rtc);
+                               PTR_ERR(config->rtc));
+               status = PTR_ERR(config->rtc);
                goto err_iounmap;
        }
 
-       platform_set_drvdata(pdev, rtc);
-       dev_set_drvdata(&rtc->dev, config);
-
        /* alarm irqs */
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
@@ -397,7 +413,7 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)
                goto err_clear_platdata;
        }
 
-       status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc);
+       status = request_irq(irq, spear_rtc_irq, 0, pdev->name, config);
        if (status) {
                dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \
                                claimed\n", irq);
@@ -411,8 +427,7 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)
 
 err_clear_platdata:
        platform_set_drvdata(pdev, NULL);
-       dev_set_drvdata(&rtc->dev, NULL);
-       rtc_device_unregister(rtc);
+       rtc_device_unregister(config->rtc);
 err_iounmap:
        iounmap(config->ioaddr);
 err_disable_clock:
@@ -429,8 +444,7 @@ err_release_region:
 
 static int __devexit spear_rtc_remove(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
        int irq;
        struct resource *res;
 
@@ -448,8 +462,7 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev)
        if (res)
                release_mem_region(res->start, resource_size(res));
        platform_set_drvdata(pdev, NULL);
-       dev_set_drvdata(&rtc->dev, NULL);
-       rtc_device_unregister(rtc);
+       rtc_device_unregister(config->rtc);
 
        return 0;
 }
@@ -458,14 +471,14 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev)
 
 static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
        int irq;
 
        irq = platform_get_irq(pdev, 0);
-       if (device_may_wakeup(&pdev->dev))
-               enable_irq_wake(irq);
-       else {
+       if (device_may_wakeup(&pdev->dev)) {
+               if (!enable_irq_wake(irq))
+                       config->irq_wake = 1;
+       } else {
                spear_rtc_disable_interrupt(config);
                clk_disable(config->clk);
        }
@@ -475,15 +488,17 @@ static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 
 static int spear_rtc_resume(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
        int irq;
 
        irq = platform_get_irq(pdev, 0);
 
-       if (device_may_wakeup(&pdev->dev))
-               disable_irq_wake(irq);
-       else {
+       if (device_may_wakeup(&pdev->dev)) {
+               if (config->irq_wake) {
+                       disable_irq_wake(irq);
+                       config->irq_wake = 0;
+               }
+       } else {
                clk_enable(config->clk);
                spear_rtc_enable_interrupt(config);
        }
@@ -498,8 +513,7 @@ static int spear_rtc_resume(struct platform_device *pdev)
 
 static void spear_rtc_shutdown(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
 
        spear_rtc_disable_interrupt(config);
        clk_disable(config->clk);