timers/nohz: Capitalize 'CPU' consistently
[cascardo/linux.git] / drivers / rtc / rtc-zynqmp.c
index 8b28762..da18a8a 100644 (file)
@@ -45,6 +45,7 @@
 #define RTC_INT_SEC            BIT(0)
 #define RTC_INT_ALRM           BIT(1)
 #define RTC_OSC_EN             BIT(24)
+#define RTC_BATT_EN            BIT(31)
 
 #define RTC_CALIB_DEF          0x198233
 #define RTC_CALIB_MASK         0x1FFFFF
@@ -55,6 +56,7 @@ struct xlnx_rtc_dev {
        void __iomem            *reg_base;
        int                     alarm_irq;
        int                     sec_irq;
+       int                     calibval;
 };
 
 static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
@@ -62,21 +64,63 @@ static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
        struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
        unsigned long new_time;
 
-       new_time = rtc_tm_to_time64(tm);
+       /*
+        * The value written will be updated after 1 sec into the
+        * seconds read register, so we need to program time +1 sec
+        * to get the correct time on read.
+        */
+       new_time = rtc_tm_to_time64(tm) + 1;
 
        if (new_time > RTC_SEC_MAX_VAL)
                return -EINVAL;
 
+       /*
+        * Writing into calibration register will clear the Tick Counter and
+        * force the next second to be signaled exactly in 1 second period
+        */
+       xrtcdev->calibval &= RTC_CALIB_MASK;
+       writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
+
        writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR);
 
+       /*
+        * Clear the rtc interrupt status register after setting the
+        * time. During a read_time function, the code should read the
+        * RTC_INT_STATUS register and if bit 0 is still 0, it means
+        * that one second has not elapsed yet since RTC was set and
+        * the current time should be read from SET_TIME_READ register;
+        * otherwise, CURRENT_TIME register is read to report the time
+        */
+       writel(RTC_INT_SEC, xrtcdev->reg_base + RTC_INT_STS);
+
        return 0;
 }
 
 static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
+       u32 status;
+       unsigned long read_time;
        struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
 
-       rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm);
+       status = readl(xrtcdev->reg_base + RTC_INT_STS);
+
+       if (status & RTC_INT_SEC) {
+               /*
+                * RTC has updated the CURRENT_TIME with the time written into
+                * SET_TIME_WRITE register.
+                */
+               rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm);
+       } else {
+               /*
+                * Time written in SET_TIME_WRITE has not yet updated into
+                * the seconds read register, so read the time from the
+                * SET_TIME_WRITE instead of CURRENT_TIME register.
+                * Since we add +1 sec while writing, we need to -1 sec while
+                * reading.
+                */
+               read_time = readl(xrtcdev->reg_base + RTC_SET_TM_RD) - 1;
+               rtc_time64_to_tm(read_time, tm);
+       }
 
        return rtc_valid_tm(tm);
 }
@@ -120,16 +164,23 @@ static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        return 0;
 }
 
-static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev, u32 calibval)
+static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
 {
+       u32 rtc_ctrl;
+
+       /* Enable RTC switch to battery when VCC_PSAUX is not available */
+       rtc_ctrl = readl(xrtcdev->reg_base + RTC_CTRL);
+       rtc_ctrl |= RTC_BATT_EN;
+       writel(rtc_ctrl, xrtcdev->reg_base + RTC_CTRL);
+
        /*
         * Based on crystal freq of 33.330 KHz
         * set the seconds counter and enable, set fractions counter
         * to default value suggested as per design spec
         * to correct RTC delay in frequency over period of time.
         */
-       calibval &= RTC_CALIB_MASK;
-       writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
+       xrtcdev->calibval &= RTC_CALIB_MASK;
+       writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
 }
 
 static const struct rtc_class_ops xlnx_rtc_ops = {
@@ -150,11 +201,9 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
        if (!(status & (RTC_INT_SEC | RTC_INT_ALRM)))
                return IRQ_NONE;
 
-       /* Clear interrupt */
-       writel(status, xrtcdev->reg_base + RTC_INT_STS);
+       /* Clear RTC_INT_ALRM interrupt only */
+       writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_STS);
 
-       if (status & RTC_INT_SEC)
-               rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_UF);
        if (status & RTC_INT_ALRM)
                rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF);
 
@@ -166,7 +215,6 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
        struct xlnx_rtc_dev *xrtcdev;
        struct resource *res;
        int ret;
-       unsigned int calibvalue;
 
        xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
        if (!xrtcdev)
@@ -207,11 +255,11 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
        }
 
        ret = of_property_read_u32(pdev->dev.of_node, "calibration",
-                                  &calibvalue);
+                                  &xrtcdev->calibval);
        if (ret)
-               calibvalue = RTC_CALIB_DEF;
+               xrtcdev->calibval = RTC_CALIB_DEF;
 
-       xlnx_init_rtc(xrtcdev, calibvalue);
+       xlnx_init_rtc(xrtcdev);
 
        device_init_wakeup(&pdev->dev, 1);