Patchwork [3/3] rtc: pxa: fix set time sync time issue

login
register
mail settings
Submitter Leo Song
Date Nov. 8, 2012, 1:45 p.m.
Message ID <1352382333-13979-3-git-send-email-liangs@marvell.com>
Download mbox | patch
Permalink /patch/197840/
State New
Headers show

Comments

Leo Song - Nov. 8, 2012, 1:45 p.m.
From: Leo Song <liangs@marvell.com>

fix set time and sync time issue, add some delay when set pxa rtc timer
according to spec

Change-Id: Ibfebf2b6644c981684fc52300d0bbeb9291c734d
Signed-off-by: Leo Song <liangs@marvell.com>
Leo Song - Nov. 8, 2012, 1:51 p.m.
Hi Alessandro,

Would you please help to review and merge these two patches for rtc-pxa.c?
[PATCH 1/3] rtc: pxa: fix alarm not match issue
[PATCH 2/3] rtc: pxa: fix alarm can't wake up system issue
[PATCH 3/3] rtc: pxa: fix set time sync time issue

Thanks a lot.

Best Wishes, 
  
Leo Song
Tel: 6194-9745, Marvell (Shanghai)
B3-F4-4D12, No. 399 of Keyuan Rd, Pudong District, Shanghai 


>-----Original Message-----
>From: Leo Song [mailto:liangs@marvell.com]
>Sent: 2012年11月8日 21:46
>To: Alessandro Zummo; rtc-linux@googlegroups.com
>Cc: Leo Song; Chao Xie
>Subject: [PATCH 3/3] rtc: pxa: fix set time sync time issue
>
>From: Leo Song <liangs@marvell.com>
>
>fix set time and sync time issue, add some delay when set pxa rtc timer
>according to spec
>
>Change-Id: Ibfebf2b6644c981684fc52300d0bbeb9291c734d
>Signed-off-by: Leo Song <liangs@marvell.com>
>
>diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
>index dbc24e9..eeadc28 100644
>--- a/drivers/rtc/rtc-pxa.c
>+++ b/drivers/rtc/rtc-pxa.c
>@@ -80,22 +80,29 @@
> #define RYAR1		0x1c
> #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))
>
> struct pxa_rtc {
> 	struct resource	*ress;
>+	struct resource	*ress_psbr;
> 	void __iomem		*base;
>+	void __iomem		*base_psbr;
> 	int			irq_1Hz;
> 	int			irq_Alrm;
> 	struct rtc_device	*rtc;
> 	spinlock_t		lock;		/* Protects this structure */
> };
>
>-
>+static struct pxa_rtc *rtc_info;
> static u32 ryxr_calc(struct rtc_time *tm)
> {
> 	return ((tm->tm_year + 1900) << RYxR_YEAR_S)
>@@ -117,7 +124,7 @@ static void tm_calc(u32 rycr, u32 rdcr, struct
>rtc_time *tm)
> 	tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900;
> 	tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1;
> 	tm->tm_mday = (rycr & RYxR_DAY_MASK);
>-	tm->tm_wday = ((rycr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1;
>+	tm->tm_wday = ((rdcr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1;
> 	tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S;
> 	tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S;
> 	tm->tm_sec = rdcr & RDxR_SEC_MASK;
>@@ -175,7 +182,6 @@ static irqreturn_t pxa_rtc_irq(int irq, void *dev_id)
>
> 	/* enable back rtc interrupts */
> 	rtc_writel(pxa_rtc, RTSR, rtsr & ~RTSR_TRIG_MASK);
>-
> 	spin_unlock(&pxa_rtc->lock);
> 	return IRQ_HANDLED;
> }
>@@ -250,12 +256,45 @@ static int pxa_rtc_read_time(struct device *dev,
>struct rtc_time *tm)
> 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 ((tm->tm_year < 70) || (tm->tm_year > 138))
>+		return -EINVAL;
>+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x01);
>+	udelay(100);
> 	rtc_writel(pxa_rtc, RYCR, ryxr_calc(tm));
> 	rtc_writel(pxa_rtc, RDCR, rdxr_calc(tm));
>+	udelay(100);
>+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x00);
>+	udelay(100);
>+	pxa_rtc_read_time(dev, tm);
>+	dev_info(dev, "tm.year = %d, tm.month = %d, tm.day = %d\n",
>+			tm->tm_year + 1900, tm->tm_mon, tm->tm_mday);
>+	return 0;
>+}
>
>+int pxa_rtc_sync_time(unsigned int ticks)
>+{
>+	/* 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
>+	*/
>+	struct rtc_time tm;
>+	rtc_time_to_tm(ticks, &tm);
>+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x01);
>+	udelay(100);
>+	rtc_writel(rtc_info, RYCR, ryxr_calc(&tm));
>+	rtc_writel(rtc_info, RDCR, rdxr_calc(&tm));
>+	udelay(100);
>+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x00);
>+	udelay(100);
> 	return 0;
> }
>+EXPORT_SYMBOL(pxa_rtc_sync_time);
>
> static int pxa_rtc_read_alarm(struct device *dev, struct rtc_wkalrm
>*alrm)
> {
>@@ -327,7 +366,7 @@ static int __init pxa_rtc_probe(struct
>platform_device *pdev)
> 	pxa_rtc = kzalloc(sizeof(struct pxa_rtc), GFP_KERNEL);
> 	if (!pxa_rtc)
> 		return -ENOMEM;
>-
>+	rtc_info = pxa_rtc;
> 	spin_lock_init(&pxa_rtc->lock);
> 	platform_set_drvdata(pdev, pxa_rtc);
>
>@@ -337,6 +376,11 @@ static int __init pxa_rtc_probe(struct
>platform_device *pdev)
> 		dev_err(dev, "No I/O memory resource defined\n");
> 		goto err_ress;
> 	}
>+	pxa_rtc->ress_psbr = platform_get_resource(pdev, IORESOURCE_MEM,
>1);
>+	if (!pxa_rtc->ress_psbr) {
>+		dev_err(dev, "No I/O memory resource defined\n");
>+		goto err_ress;
>+	}
>
> 	pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0);
> 	if (pxa_rtc->irq_1Hz < 0) {
>@@ -348,7 +392,6 @@ static int __init pxa_rtc_probe(struct
>platform_device *pdev)
> 		dev_err(dev, "No alarm IRQ resource defined\n");
> 		goto err_ress;
> 	}
>-	pxa_rtc_open(dev);
> 	ret = -ENOMEM;
> 	pxa_rtc->base = ioremap(pxa_rtc->ress->start,
> 				resource_size(pxa_rtc->ress));
>@@ -357,6 +400,12 @@ static int __init pxa_rtc_probe(struct
>platform_device *pdev)
> 		goto err_map;
> 	}
>
>+	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;
>+	}
> 	/*
> 	 * If the clock divider is uninitialized then reset it to the
> 	 * default value to get the 1Hz clock.
>@@ -379,7 +428,7 @@ static int __init pxa_rtc_probe(struct
>platform_device *pdev)
> 	}
>
> 	device_init_wakeup(dev, 1);
>-
>+	pxa_rtc_open(dev);
> 	return 0;
>
> err_rtc_reg:
>diff --git a/include/linux/rtc-pxa.h b/include/linux/rtc-pxa.h
>new file mode 100644
>index 0000000..71bc45f
>--- /dev/null
>+++ b/include/linux/rtc-pxa.h
>@@ -0,0 +1,18 @@
>+/*
>+ * include/linux/rtc-pxa.h
>+ *
>+ * RTC PXA Header file
>+ *
>+ * Copyright (C) 2010 Marvell International Ltd.
>+ *
>+ * This program is free software; you can redistribute it and/or modify
>+ * it under the terms of the GNU General Public License version 2 as
>+ * published by the Free Software Foundation.
>+ */
>+
>+#ifndef __LINUX_RTC_PXA_H
>+#define __LINUX_RTC_PXA_H
>+
>+extern int pxa_rtc_sync_time(unsigned int ticks);
>+
>+#endif /* __LINUX_RTC_PXA_H */
>--
>1.7.5.4

Patch

diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index dbc24e9..eeadc28 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -80,22 +80,29 @@ 
 #define RYAR1		0x1c
 #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))
 
 struct pxa_rtc {
 	struct resource	*ress;
+	struct resource	*ress_psbr;
 	void __iomem		*base;
+	void __iomem		*base_psbr;
 	int			irq_1Hz;
 	int			irq_Alrm;
 	struct rtc_device	*rtc;
 	spinlock_t		lock;		/* Protects this structure */
 };
 
-
+static struct pxa_rtc *rtc_info;
 static u32 ryxr_calc(struct rtc_time *tm)
 {
 	return ((tm->tm_year + 1900) << RYxR_YEAR_S)
@@ -117,7 +124,7 @@  static void tm_calc(u32 rycr, u32 rdcr, struct rtc_time *tm)
 	tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900;
 	tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1;
 	tm->tm_mday = (rycr & RYxR_DAY_MASK);
-	tm->tm_wday = ((rycr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1;
+	tm->tm_wday = ((rdcr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1;
 	tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S;
 	tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S;
 	tm->tm_sec = rdcr & RDxR_SEC_MASK;
@@ -175,7 +182,6 @@  static irqreturn_t pxa_rtc_irq(int irq, void *dev_id)
 
 	/* enable back rtc interrupts */
 	rtc_writel(pxa_rtc, RTSR, rtsr & ~RTSR_TRIG_MASK);
-
 	spin_unlock(&pxa_rtc->lock);
 	return IRQ_HANDLED;
 }
@@ -250,12 +256,45 @@  static int pxa_rtc_read_time(struct device *dev, struct rtc_time *tm)
 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 ((tm->tm_year < 70) || (tm->tm_year > 138))
+		return -EINVAL;
+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x01);
+	udelay(100);
 	rtc_writel(pxa_rtc, RYCR, ryxr_calc(tm));
 	rtc_writel(pxa_rtc, RDCR, rdxr_calc(tm));
+	udelay(100);
+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x00);
+	udelay(100);
+	pxa_rtc_read_time(dev, tm);
+	dev_info(dev, "tm.year = %d, tm.month = %d, tm.day = %d\n",
+			tm->tm_year + 1900, tm->tm_mon, tm->tm_mday);
+	return 0;
+}
 
+int pxa_rtc_sync_time(unsigned int ticks)
+{
+	/* 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
+	*/
+	struct rtc_time tm;
+	rtc_time_to_tm(ticks, &tm);
+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x01);
+	udelay(100);
+	rtc_writel(rtc_info, RYCR, ryxr_calc(&tm));
+	rtc_writel(rtc_info, RDCR, rdxr_calc(&tm));
+	udelay(100);
+	rtc_writel_psbr(rtc_info, PSBR_RTC, 0x00);
+	udelay(100);
 	return 0;
 }
+EXPORT_SYMBOL(pxa_rtc_sync_time);
 
 static int pxa_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
@@ -327,7 +366,7 @@  static int __init pxa_rtc_probe(struct platform_device *pdev)
 	pxa_rtc = kzalloc(sizeof(struct pxa_rtc), GFP_KERNEL);
 	if (!pxa_rtc)
 		return -ENOMEM;
-
+	rtc_info = pxa_rtc;
 	spin_lock_init(&pxa_rtc->lock);
 	platform_set_drvdata(pdev, pxa_rtc);
 
@@ -337,6 +376,11 @@  static int __init pxa_rtc_probe(struct platform_device *pdev)
 		dev_err(dev, "No I/O memory resource defined\n");
 		goto err_ress;
 	}
+	pxa_rtc->ress_psbr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!pxa_rtc->ress_psbr) {
+		dev_err(dev, "No I/O memory resource defined\n");
+		goto err_ress;
+	}
 
 	pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0);
 	if (pxa_rtc->irq_1Hz < 0) {
@@ -348,7 +392,6 @@  static int __init pxa_rtc_probe(struct platform_device *pdev)
 		dev_err(dev, "No alarm IRQ resource defined\n");
 		goto err_ress;
 	}
-	pxa_rtc_open(dev);
 	ret = -ENOMEM;
 	pxa_rtc->base = ioremap(pxa_rtc->ress->start,
 				resource_size(pxa_rtc->ress));
@@ -357,6 +400,12 @@  static int __init pxa_rtc_probe(struct platform_device *pdev)
 		goto err_map;
 	}
 
+	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;
+	}
 	/*
 	 * If the clock divider is uninitialized then reset it to the
 	 * default value to get the 1Hz clock.
@@ -379,7 +428,7 @@  static int __init pxa_rtc_probe(struct platform_device *pdev)
 	}
 
 	device_init_wakeup(dev, 1);
-
+	pxa_rtc_open(dev);
 	return 0;
 
 err_rtc_reg:
diff --git a/include/linux/rtc-pxa.h b/include/linux/rtc-pxa.h
new file mode 100644
index 0000000..71bc45f
--- /dev/null
+++ b/include/linux/rtc-pxa.h
@@ -0,0 +1,18 @@ 
+/*
+ * include/linux/rtc-pxa.h
+ *
+ * RTC PXA Header file
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_RTC_PXA_H
+#define __LINUX_RTC_PXA_H
+
+extern int pxa_rtc_sync_time(unsigned int ticks);
+
+#endif /* __LINUX_RTC_PXA_H */