+ rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time);
+ return 0;
+}
+
+static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm)
+{
+ unsigned long time;
+ int ret;
+
+ /*
+ * At the moment, we can only deal with non-wildcarded alarm times.
+ */
+ ret = rtc_valid_tm(&alrm->time);
+ if (ret == 0)
+ ret = rtc_tm_to_time(&alrm->time, &time);
+ if (ret == 0)
+ writel(time, rtc_base + RTC_MR);
+ return ret;
+}
+
+static int integrator_rtc_read_time(struct rtc_time *tm)
+{
+ rtc_time_to_tm(readl(rtc_base + RTC_DR), tm);
+ return 0;
+}
+
+/*
+ * Set the RTC time. Unfortunately, we can't accurately set
+ * the point at which the counter updates.
+ *
+ * Also, since RTC_LR is transferred to RTC_CR on next rising
+ * edge of the 1Hz clock, we must write the time one second
+ * in advance.
+ */
+static inline int integrator_rtc_set_time(struct rtc_time *tm)
+{
+ unsigned long time;
+ int ret;
+
+ ret = rtc_tm_to_time(tm, &time);
+ if (ret == 0)
+ writel(time + 1, rtc_base + RTC_LR);
+
+ return ret;
+}
+
+static struct rtc_ops rtc_ops = {
+ .owner = THIS_MODULE,
+ .read_time = integrator_rtc_read_time,
+ .set_time = integrator_rtc_set_time,
+ .read_alarm = integrator_rtc_read_alarm,
+ .set_alarm = integrator_rtc_set_alarm,
+};
+
+static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id)
+{
+ writel(0, rtc_base + RTC_EOI);
+ return IRQ_HANDLED;
+}
+
+static int rtc_probe(struct amba_device *dev, void *id)
+{
+ int ret;
+
+ if (rtc_base)
+ return -EBUSY;
+
+ ret = amba_request_regions(dev, NULL);
+ if (ret)
+ goto out;
+
+ rtc_base = ioremap(dev->res.start, SZ_4K);
+ if (!rtc_base) {
+ ret = -ENOMEM;
+ goto res_out;
+ }
+
+ __raw_writel(0, rtc_base + RTC_CR);
+ __raw_writel(0, rtc_base + RTC_EOI);
+
+ xtime.tv_sec = __raw_readl(rtc_base + RTC_DR);
+
+ ret = request_irq(dev->irq[0], arm_rtc_interrupt, IRQF_DISABLED,
+ "rtc-pl030", dev);
+ if (ret)
+ goto map_out;