Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / rtc / rtc-pl031.c
index 6c418fe..f027c06 100644 (file)
@@ -293,57 +293,6 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        return ret;
 }
 
-/* Periodic interrupt is only available in ST variants. */
-static int pl031_irq_set_state(struct device *dev, int enabled)
-{
-       struct pl031_local *ldata = dev_get_drvdata(dev);
-
-       if (enabled == 1) {
-               /* Clear any pending timer interrupt. */
-               writel(RTC_BIT_PI, ldata->base + RTC_ICR);
-
-               writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI,
-                       ldata->base + RTC_IMSC);
-
-               /* Now start the timer */
-               writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN,
-                       ldata->base + RTC_TCR);
-
-       } else {
-               writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI),
-                       ldata->base + RTC_IMSC);
-
-               /* Also stop the timer */
-               writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN),
-                       ldata->base + RTC_TCR);
-       }
-       /* Wait at least 1 RTC32 clock cycle to ensure next access
-        * to RTC_TCR will succeed.
-        */
-       udelay(40);
-
-       return 0;
-}
-
-static int pl031_irq_set_freq(struct device *dev, int freq)
-{
-       struct pl031_local *ldata = dev_get_drvdata(dev);
-
-       /* Cant set timer if it is already enabled */
-       if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) {
-               dev_err(dev, "can't change frequency while timer enabled\n");
-               return -EINVAL;
-       }
-
-       /* If self start bit in RTC_TCR is set timer will start here,
-        * but we never set that bit. Instead we start the timer when
-        * set_state is called with enabled == 1.
-        */
-       writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR);
-
-       return 0;
-}
-
 static int pl031_remove(struct amba_device *adev)
 {
        struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
@@ -358,11 +307,12 @@ static int pl031_remove(struct amba_device *adev)
        return 0;
 }
 
-static int pl031_probe(struct amba_device *adev, struct amba_id *id)
+static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret;
        struct pl031_local *ldata;
        struct rtc_class_ops *ops = id->data;
+       unsigned long time;
 
        ret = amba_request_regions(adev, NULL);
        if (ret)
@@ -390,11 +340,27 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
        dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
 
        /* Enable the clockwatch on ST Variants */
-       if ((ldata->hw_designer == AMBA_VENDOR_ST) &&
-           (ldata->hw_revision > 1))
+       if (ldata->hw_designer == AMBA_VENDOR_ST)
                writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
                       ldata->base + RTC_CR);
 
+       /*
+        * On ST PL031 variants, the RTC reset value does not provide correct
+        * weekday for 2000-01-01. Correct the erroneous sunday to saturday.
+        */
+       if (ldata->hw_designer == AMBA_VENDOR_ST) {
+               if (readl(ldata->base + RTC_YDR) == 0x2000) {
+                       time = readl(ldata->base + RTC_DR);
+                       if ((time &
+                            (RTC_MON_MASK | RTC_MDAY_MASK | RTC_WDAY_MASK))
+                           == 0x02120000) {
+                               time = time | (0x7 << RTC_WDAY_SHIFT);
+                               writel(0x2000, ldata->base + RTC_YLR);
+                               writel(time, ldata->base + RTC_LR);
+                       }
+               }
+       }
+
        ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
                                        THIS_MODULE);
        if (IS_ERR(ldata->rtc)) {
@@ -403,7 +369,7 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
        }
 
        if (request_irq(adev->irq[0], pl031_interrupt,
-                       IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) {
+                       0, "rtc-pl031", ldata)) {
                ret = -EIO;
                goto out_no_irq;
        }
@@ -440,8 +406,6 @@ static struct rtc_class_ops stv1_pl031_ops = {
        .read_alarm = pl031_read_alarm,
        .set_alarm = pl031_set_alarm,
        .alarm_irq_enable = pl031_alarm_irq_enable,
-       .irq_set_state = pl031_irq_set_state,
-       .irq_set_freq = pl031_irq_set_freq,
 };
 
 /* And the second ST derivative */
@@ -451,8 +415,6 @@ static struct rtc_class_ops stv2_pl031_ops = {
        .read_alarm = pl031_stv2_read_alarm,
        .set_alarm = pl031_stv2_set_alarm,
        .alarm_irq_enable = pl031_alarm_irq_enable,
-       .irq_set_state = pl031_irq_set_state,
-       .irq_set_freq = pl031_irq_set_freq,
 };
 
 static struct amba_id pl031_ids[] = {
@@ -475,6 +437,8 @@ static struct amba_id pl031_ids[] = {
        {0, 0},
 };
 
+MODULE_DEVICE_TABLE(amba, pl031_ids);
+
 static struct amba_driver pl031_driver = {
        .drv = {
                .name = "rtc-pl031",
@@ -484,18 +448,7 @@ static struct amba_driver pl031_driver = {
        .remove = pl031_remove,
 };
 
-static int __init pl031_init(void)
-{
-       return amba_driver_register(&pl031_driver);
-}
-
-static void __exit pl031_exit(void)
-{
-       amba_driver_unregister(&pl031_driver);
-}
-
-module_init(pl031_init);
-module_exit(pl031_exit);
+module_amba_driver(pl031_driver);
 
 MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
 MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");