the pxa95x rtc need access PBSR register before write to
RTTR, RCNR, RDCR, and RYCR registers.

Signed-off-by: Chao Xie <chao....@marvell.com>
---
 drivers/rtc/rtc-pxa.c |  100 +++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index f771b2e..aee23cb 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/delay.h>
 
 #include <mach/hardware.h>
 
@@ -77,14 +78,28 @@
 #define RTCPICR                0x34
 #define PIAR           0x38
 
+#define PSBR_RTC       0x00
+
 #define rtc_readl(pxa_rtc, reg)        \
        __raw_readl((pxa_rtc)->base + (reg))
 #define rtc_writel(pxa_rtc, reg, value)        \
        __raw_writel((value), (pxa_rtc)->base + (reg))
+#define rtc_readl_psbr(pxa_rtc, reg)   \
+       __raw_readl((pxa_rtc)->base_psbr + (reg))
+#define rtc_writel_psbr(pxa_rtc, reg, value)   \
+       __raw_writel((value), (pxa_rtc)->base_psbr + (reg))
+
+enum {
+       RTC_PXA27X,
+       RTC_PXA95X,
+};
 
 struct pxa_rtc {
        struct resource *ress;
+       struct resource *ress_psbr;
+       unsigned int            id;
        void __iomem            *base;
+       void __iomem            *base_psbr;
        int                     irq_1Hz;
        int                     irq_Alrm;
        struct rtc_device       *rtc;
@@ -242,9 +257,26 @@ static int pxa_rtc_set_time(struct device *dev, struct 
rtc_time *tm)
 {
        struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
 
+       /*
+        * sequence to wirte pxa rtc register RCNR RDCR RYCR is
+        * 1. set PSBR[RWE] bit, take 2x32-khz to complete
+        * 2. write to RTC register,take 2x32-khz to complete
+        * 3. clear PSBR[RWE] bit,take 2x32-khz to complete
+        */
+       if (pxa_rtc->id == RTC_PXA95X) {
+               rtc_writel_psbr(pxa_rtc, PSBR_RTC, 0x01);
+               udelay(100);
+       }
+
        rtc_writel(pxa_rtc, RYCR, ryxr_calc(tm));
        rtc_writel(pxa_rtc, RDCR, rdxr_calc(tm));
 
+       if (pxa_rtc->id == RTC_PXA95X) {
+               udelay(100);
+               rtc_writel_psbr(pxa_rtc, PSBR_RTC, 0x00);
+               udelay(100);
+       }
+
        return 0;
 }
 
@@ -310,6 +342,20 @@ static const struct rtc_class_ops pxa_rtc_ops = {
        .proc = pxa_rtc_proc,
 };
 
+static struct of_device_id pxa_rtc_dt_ids[] = {
+       { .compatible = "marvell,pxa-rtc", .data = (void *)RTC_PXA27X },
+       { .compatible = "marvell,pxa95x-rtc", .data = (void *)RTC_PXA95X },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids);
+
+static const struct platform_device_id pxa_rtc_id_table[] = {
+       { "pxa-rtc", RTC_PXA27X },
+       { "pxa95x-rtc", RTC_PXA95X },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, pxa_rtc_id_table);
+
 static int __init pxa_rtc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -324,13 +370,34 @@ static int __init pxa_rtc_probe(struct platform_device 
*pdev)
        spin_lock_init(&pxa_rtc->lock);
        platform_set_drvdata(pdev, pxa_rtc);
 
+       if (pdev->dev.of_node) {
+               const struct of_device_id *of_id =
+                               of_match_device(pxa_rtc_dt_ids, &pdev->dev);
+
+               pxa_rtc->id = (unsigned int)(of_id->data);
+       } else {
+               const struct platform_device_id *id =
+                               platform_get_device_id(pdev);
+
+               pxa_rtc->id = id->driver_data;
+       }
+
        ret = -ENXIO;
        pxa_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!pxa_rtc->ress) {
-               dev_err(dev, "No I/O memory resource defined\n");
+               dev_err(dev, "No I/O memory resource(id=0) defined\n");
                goto err_ress;
        }
 
+       if (pxa_rtc->id == RTC_PXA95X) {
+               pxa_rtc->ress_psbr =
+                       platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               if (!pxa_rtc->ress_psbr) {
+                       dev_err(dev, "No I/O memory resource(id=1) defined\n");
+                       goto err_ress;
+               }
+       }
+
        pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0);
        if (pxa_rtc->irq_1Hz < 0) {
                dev_err(dev, "No 1Hz IRQ resource defined\n");
@@ -347,7 +414,17 @@ static int __init pxa_rtc_probe(struct platform_device 
*pdev)
                                resource_size(pxa_rtc->ress));
        if (!pxa_rtc->base) {
                dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n");
-               goto err_map;
+               goto err_map_base;
+       }
+
+       if (pxa_rtc->id == RTC_PXA95X) {
+               pxa_rtc->base_psbr = ioremap(pxa_rtc->ress_psbr->start,
+                                       resource_size(pxa_rtc->ress_psbr));
+               if (!pxa_rtc->base_psbr) {
+                       dev_err(&pdev->dev,
+                               "Unable to map pxa RTC PSBR I/O memory\n");
+                       goto err_map_base_psbr;
+               }
        }
 
        /*
@@ -376,9 +453,12 @@ static int __init pxa_rtc_probe(struct platform_device 
*pdev)
        return 0;
 
 err_rtc_reg:
+       if (pxa_rtc->id == RTC_PXA95X)
+               iounmap(pxa_rtc->base_psbr);
+err_map_base_psbr:
         iounmap(pxa_rtc->base);
+err_map_base:
 err_ress:
-err_map:
        kfree(pxa_rtc);
        return ret;
 }
@@ -398,14 +478,6 @@ static int __exit pxa_rtc_remove(struct platform_device 
*pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
-static struct of_device_id pxa_rtc_dt_ids[] = {
-       { .compatible = "marvell,pxa-rtc" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids);
-#endif
-
 #ifdef CONFIG_PM
 static int pxa_rtc_suspend(struct device *dev)
 {
@@ -440,14 +512,12 @@ static struct platform_driver pxa_rtc_driver = {
                .pm     = &pxa_rtc_pm_ops,
 #endif
        },
+       .id_table       = pxa_rtc_id_table,
 };
 
 static int __init pxa_rtc_init(void)
 {
-       if (cpu_is_pxa27x() || cpu_is_pxa3xx())
-               return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe);
-
-       return -ENODEV;
+       return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe);
 }
 
 static void __exit pxa_rtc_exit(void)
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to