xref: /openbmc/linux/drivers/rtc/rtc-sa1100.c (revision 0c4eae66591a292fee70051ea363a8d27aa54102)
1e842f1c8SRichard Purdie /*
2e842f1c8SRichard Purdie  * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx
3e842f1c8SRichard Purdie  *
4e842f1c8SRichard Purdie  * Copyright (c) 2000 Nils Faerber
5e842f1c8SRichard Purdie  *
6e842f1c8SRichard Purdie  * Based on rtc.c by Paul Gortmaker
7e842f1c8SRichard Purdie  *
8e842f1c8SRichard Purdie  * Original Driver by Nils Faerber <nils@kernelconcepts.de>
9e842f1c8SRichard Purdie  *
10e842f1c8SRichard Purdie  * Modifications from:
11e842f1c8SRichard Purdie  *   CIH <cih@coventive.com>
122f82af08SNicolas Pitre  *   Nicolas Pitre <nico@fluxnic.net>
13e842f1c8SRichard Purdie  *   Andrew Christian <andrew.christian@hp.com>
14e842f1c8SRichard Purdie  *
15e842f1c8SRichard Purdie  * Converted to the RTC subsystem and Driver Model
16e842f1c8SRichard Purdie  *   by Richard Purdie <rpurdie@rpsys.net>
17e842f1c8SRichard Purdie  *
18e842f1c8SRichard Purdie  * This program is free software; you can redistribute it and/or
19e842f1c8SRichard Purdie  * modify it under the terms of the GNU General Public License
20e842f1c8SRichard Purdie  * as published by the Free Software Foundation; either version
21e842f1c8SRichard Purdie  * 2 of the License, or (at your option) any later version.
22e842f1c8SRichard Purdie  */
23e842f1c8SRichard Purdie 
24e842f1c8SRichard Purdie #include <linux/platform_device.h>
25e842f1c8SRichard Purdie #include <linux/module.h>
26e842f1c8SRichard Purdie #include <linux/rtc.h>
27e842f1c8SRichard Purdie #include <linux/init.h>
28e842f1c8SRichard Purdie #include <linux/fs.h>
29e842f1c8SRichard Purdie #include <linux/interrupt.h>
30e842f1c8SRichard Purdie #include <linux/pm.h>
317cea0065SJett.Zhou #include <linux/slab.h>
327cea0065SJett.Zhou #include <linux/clk.h>
337cea0065SJett.Zhou #include <linux/io.h>
34e842f1c8SRichard Purdie 
35a09e64fbSRussell King #include <mach/hardware.h>
36e842f1c8SRichard Purdie #include <asm/irq.h>
37e842f1c8SRichard Purdie 
38a404ad1fSMarcelo Roberto Jimenez #define RTC_DEF_DIVIDER		(32768 - 1)
39e842f1c8SRichard Purdie #define RTC_DEF_TRIM		0
407cea0065SJett.Zhou #define RTC_FREQ		1024
41e842f1c8SRichard Purdie 
427cea0065SJett.Zhou #define RCNR		0x00	/* RTC Count Register */
437cea0065SJett.Zhou #define RTAR		0x04	/* RTC Alarm Register */
447cea0065SJett.Zhou #define RTSR		0x08	/* RTC Status Register */
457cea0065SJett.Zhou #define RTTR		0x0c	/* RTC Timer Trim Register */
46e842f1c8SRichard Purdie 
477cea0065SJett.Zhou #define RTSR_HZE	(1 << 3)	/* HZ interrupt enable */
487cea0065SJett.Zhou #define RTSR_ALE	(1 << 2)	/* RTC alarm interrupt enable */
497cea0065SJett.Zhou #define RTSR_HZ		(1 << 1)	/* HZ rising-edge detected */
507cea0065SJett.Zhou #define RTSR_AL		(1 << 0)	/* RTC alarm detected */
517cea0065SJett.Zhou 
527cea0065SJett.Zhou #define rtc_readl(sa1100_rtc, reg)	\
537cea0065SJett.Zhou 	readl_relaxed((sa1100_rtc)->base + (reg))
547cea0065SJett.Zhou #define rtc_writel(sa1100_rtc, reg, value)	\
557cea0065SJett.Zhou 	writel_relaxed((value), (sa1100_rtc)->base + (reg))
567cea0065SJett.Zhou 
577cea0065SJett.Zhou struct sa1100_rtc {
587cea0065SJett.Zhou 	struct resource		*ress;
597cea0065SJett.Zhou 	void __iomem		*base;
607cea0065SJett.Zhou 	struct clk		*clk;
617cea0065SJett.Zhou 	int			irq_1Hz;
627cea0065SJett.Zhou 	int			irq_Alrm;
637cea0065SJett.Zhou 	struct rtc_device	*rtc;
647cea0065SJett.Zhou 	spinlock_t		lock;		/* Protects this structure */
657cea0065SJett.Zhou };
66797276ecSRussell King /*
67797276ecSRussell King  * Calculate the next alarm time given the requested alarm time mask
68797276ecSRussell King  * and the current time.
69797276ecSRussell King  */
70a404ad1fSMarcelo Roberto Jimenez static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
71a404ad1fSMarcelo Roberto Jimenez 	struct rtc_time *alrm)
72797276ecSRussell King {
73797276ecSRussell King 	unsigned long next_time;
74797276ecSRussell King 	unsigned long now_time;
75797276ecSRussell King 
76797276ecSRussell King 	next->tm_year = now->tm_year;
77797276ecSRussell King 	next->tm_mon = now->tm_mon;
78797276ecSRussell King 	next->tm_mday = now->tm_mday;
79797276ecSRussell King 	next->tm_hour = alrm->tm_hour;
80797276ecSRussell King 	next->tm_min = alrm->tm_min;
81797276ecSRussell King 	next->tm_sec = alrm->tm_sec;
82797276ecSRussell King 
83797276ecSRussell King 	rtc_tm_to_time(now, &now_time);
84797276ecSRussell King 	rtc_tm_to_time(next, &next_time);
85797276ecSRussell King 
86797276ecSRussell King 	if (next_time < now_time) {
87797276ecSRussell King 		/* Advance one day */
88797276ecSRussell King 		next_time += 60 * 60 * 24;
89797276ecSRussell King 		rtc_time_to_tm(next_time, next);
90797276ecSRussell King 	}
91797276ecSRussell King }
92797276ecSRussell King 
937d12e780SDavid Howells static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
94e842f1c8SRichard Purdie {
95e842f1c8SRichard Purdie 	struct platform_device *pdev = to_platform_device(dev_id);
967cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = platform_get_drvdata(pdev);
97e842f1c8SRichard Purdie 	unsigned int rtsr;
98e842f1c8SRichard Purdie 	unsigned long events = 0;
99e842f1c8SRichard Purdie 
1007cea0065SJett.Zhou 	spin_lock(&sa1100_rtc->lock);
101e842f1c8SRichard Purdie 
102e842f1c8SRichard Purdie 	/* clear interrupt sources */
1037cea0065SJett.Zhou 	rtsr = rtc_readl(sa1100_rtc, RTSR);
1047cea0065SJett.Zhou 	rtc_writel(sa1100_rtc, RTSR, 0);
1057cea0065SJett.Zhou 
1067decaa55SMarcelo Roberto Jimenez 	/* Fix for a nasty initialization problem the in SA11xx RTSR register.
1077decaa55SMarcelo Roberto Jimenez 	 * See also the comments in sa1100_rtc_probe(). */
1087decaa55SMarcelo Roberto Jimenez 	if (rtsr & (RTSR_ALE | RTSR_HZE)) {
1097decaa55SMarcelo Roberto Jimenez 		/* This is the original code, before there was the if test
1107decaa55SMarcelo Roberto Jimenez 		 * above. This code does not clear interrupts that were not
1117decaa55SMarcelo Roberto Jimenez 		 * enabled. */
1127cea0065SJett.Zhou 		rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ) & (rtsr >> 2));
1137decaa55SMarcelo Roberto Jimenez 	} else {
1147decaa55SMarcelo Roberto Jimenez 		/* For some reason, it is possible to enter this routine
1157decaa55SMarcelo Roberto Jimenez 		 * without interruptions enabled, it has been tested with
1167decaa55SMarcelo Roberto Jimenez 		 * several units (Bug in SA11xx chip?).
1177decaa55SMarcelo Roberto Jimenez 		 *
1187decaa55SMarcelo Roberto Jimenez 		 * This situation leads to an infinite "loop" of interrupt
1197decaa55SMarcelo Roberto Jimenez 		 * routine calling and as a result the processor seems to
1207decaa55SMarcelo Roberto Jimenez 		 * lock on its first call to open(). */
1217cea0065SJett.Zhou 		rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ));
1227decaa55SMarcelo Roberto Jimenez 	}
123e842f1c8SRichard Purdie 
124e842f1c8SRichard Purdie 	/* clear alarm interrupt if it has occurred */
125e842f1c8SRichard Purdie 	if (rtsr & RTSR_AL)
126e842f1c8SRichard Purdie 		rtsr &= ~RTSR_ALE;
1277cea0065SJett.Zhou 	rtc_writel(sa1100_rtc, RTSR, rtsr & (RTSR_ALE | RTSR_HZE));
128e842f1c8SRichard Purdie 
129e842f1c8SRichard Purdie 	/* update irq data & counter */
130e842f1c8SRichard Purdie 	if (rtsr & RTSR_AL)
131e842f1c8SRichard Purdie 		events |= RTC_AF | RTC_IRQF;
132e842f1c8SRichard Purdie 	if (rtsr & RTSR_HZ)
133e842f1c8SRichard Purdie 		events |= RTC_UF | RTC_IRQF;
134e842f1c8SRichard Purdie 
1357cea0065SJett.Zhou 	rtc_update_irq(sa1100_rtc->rtc, 1, events);
136e842f1c8SRichard Purdie 
1377cea0065SJett.Zhou 	spin_unlock(&sa1100_rtc->lock);
138e842f1c8SRichard Purdie 
139e842f1c8SRichard Purdie 	return IRQ_HANDLED;
140e842f1c8SRichard Purdie }
141e842f1c8SRichard Purdie 
142e842f1c8SRichard Purdie static int sa1100_rtc_open(struct device *dev)
143e842f1c8SRichard Purdie {
1447cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
145e842f1c8SRichard Purdie 	int ret;
146e842f1c8SRichard Purdie 
1477cea0065SJett.Zhou 	ret = request_irq(sa1100_rtc->irq_1Hz, sa1100_rtc_interrupt,
1487cea0065SJett.Zhou 				IRQF_DISABLED, "rtc 1Hz", dev);
149e842f1c8SRichard Purdie 	if (ret) {
1507cea0065SJett.Zhou 		dev_err(dev, "IRQ %d already in use.\n", sa1100_rtc->irq_1Hz);
151e842f1c8SRichard Purdie 		goto fail_ui;
152e842f1c8SRichard Purdie 	}
1537cea0065SJett.Zhou 	ret = request_irq(sa1100_rtc->irq_Alrm, sa1100_rtc_interrupt,
1547cea0065SJett.Zhou 				IRQF_DISABLED, "rtc Alrm", dev);
155e842f1c8SRichard Purdie 	if (ret) {
1567cea0065SJett.Zhou 		dev_err(dev, "IRQ %d already in use.\n", sa1100_rtc->irq_Alrm);
157e842f1c8SRichard Purdie 		goto fail_ai;
158e842f1c8SRichard Purdie 	}
1597cea0065SJett.Zhou 	sa1100_rtc->rtc->max_user_freq = RTC_FREQ;
1607cea0065SJett.Zhou 	rtc_irq_set_freq(sa1100_rtc->rtc, NULL, RTC_FREQ);
161d2ccb52dSMarcelo Roberto Jimenez 
162e842f1c8SRichard Purdie 	return 0;
163e842f1c8SRichard Purdie 
164e842f1c8SRichard Purdie  fail_ai:
1657cea0065SJett.Zhou 	free_irq(sa1100_rtc->irq_1Hz, dev);
166e842f1c8SRichard Purdie  fail_ui:
167e842f1c8SRichard Purdie 	return ret;
168e842f1c8SRichard Purdie }
169e842f1c8SRichard Purdie 
170e842f1c8SRichard Purdie static void sa1100_rtc_release(struct device *dev)
171e842f1c8SRichard Purdie {
1727cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
173e842f1c8SRichard Purdie 
1747cea0065SJett.Zhou 	spin_lock_irq(&sa1100_rtc->lock);
1757cea0065SJett.Zhou 	rtc_writel(sa1100_rtc, RTSR, 0);
1767cea0065SJett.Zhou 	spin_unlock_irq(&sa1100_rtc->lock);
1777cea0065SJett.Zhou 
1787cea0065SJett.Zhou 	free_irq(sa1100_rtc->irq_Alrm, dev);
1797cea0065SJett.Zhou 	free_irq(sa1100_rtc->irq_1Hz, dev);
180e842f1c8SRichard Purdie }
181e842f1c8SRichard Purdie 
18216380c15SJohn Stultz static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
18316380c15SJohn Stultz {
1847cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
1857cea0065SJett.Zhou 	unsigned int rtsr;
1867cea0065SJett.Zhou 
1877cea0065SJett.Zhou 	spin_lock_irq(&sa1100_rtc->lock);
1887cea0065SJett.Zhou 
1897cea0065SJett.Zhou 	rtsr = rtc_readl(sa1100_rtc, RTSR);
19016380c15SJohn Stultz 	if (enabled)
1917cea0065SJett.Zhou 		rtsr |= RTSR_ALE;
19216380c15SJohn Stultz 	else
1937cea0065SJett.Zhou 		rtsr &= ~RTSR_ALE;
1947cea0065SJett.Zhou 	rtc_writel(sa1100_rtc, RTSR, rtsr);
1957cea0065SJett.Zhou 
1967cea0065SJett.Zhou 	spin_unlock_irq(&sa1100_rtc->lock);
19716380c15SJohn Stultz 	return 0;
19816380c15SJohn Stultz }
19916380c15SJohn Stultz 
200e842f1c8SRichard Purdie static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
201e842f1c8SRichard Purdie {
2027cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
2037cea0065SJett.Zhou 
2047cea0065SJett.Zhou 	rtc_time_to_tm(rtc_readl(sa1100_rtc, RCNR), tm);
205e842f1c8SRichard Purdie 	return 0;
206e842f1c8SRichard Purdie }
207e842f1c8SRichard Purdie 
208e842f1c8SRichard Purdie static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
209e842f1c8SRichard Purdie {
2107cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
211e842f1c8SRichard Purdie 	unsigned long time;
212e842f1c8SRichard Purdie 	int ret;
213e842f1c8SRichard Purdie 
214e842f1c8SRichard Purdie 	ret = rtc_tm_to_time(tm, &time);
215e842f1c8SRichard Purdie 	if (ret == 0)
2167cea0065SJett.Zhou 		rtc_writel(sa1100_rtc, RCNR, time);
217e842f1c8SRichard Purdie 	return ret;
218e842f1c8SRichard Purdie }
219e842f1c8SRichard Purdie 
220e842f1c8SRichard Purdie static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
221e842f1c8SRichard Purdie {
2227cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
2237cea0065SJett.Zhou 	unsigned long time;
2247cea0065SJett.Zhou 	unsigned int rtsr;
22532b49da4SDavid Brownell 
2267cea0065SJett.Zhou 	time = rtc_readl(sa1100_rtc, RCNR);
2277cea0065SJett.Zhou 	rtc_time_to_tm(time, &alrm->time);
2287cea0065SJett.Zhou 	rtsr = rtc_readl(sa1100_rtc, RTSR);
22932b49da4SDavid Brownell 	alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
23032b49da4SDavid Brownell 	alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
231e842f1c8SRichard Purdie 	return 0;
232e842f1c8SRichard Purdie }
233e842f1c8SRichard Purdie 
234e842f1c8SRichard Purdie static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
235e842f1c8SRichard Purdie {
2367cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
23742874759SJett.Zhou 	struct rtc_time now_tm, alarm_tm;
2387cea0065SJett.Zhou 	unsigned long time, alarm;
2397cea0065SJett.Zhou 	unsigned int rtsr;
240e842f1c8SRichard Purdie 
2417cea0065SJett.Zhou 	spin_lock_irq(&sa1100_rtc->lock);
24242874759SJett.Zhou 
2437cea0065SJett.Zhou 	time = rtc_readl(sa1100_rtc, RCNR);
2447cea0065SJett.Zhou 	rtc_time_to_tm(time, &now_tm);
2457cea0065SJett.Zhou 	rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
2467cea0065SJett.Zhou 	rtc_tm_to_time(&alarm_tm, &alarm);
2477cea0065SJett.Zhou 	rtc_writel(sa1100_rtc, RTAR, alarm);
2487cea0065SJett.Zhou 
2497cea0065SJett.Zhou 	rtsr = rtc_readl(sa1100_rtc, RTSR);
250e842f1c8SRichard Purdie 	if (alrm->enabled)
2517cea0065SJett.Zhou 		rtsr |= RTSR_ALE;
252e842f1c8SRichard Purdie 	else
2537cea0065SJett.Zhou 		rtsr &= ~RTSR_ALE;
2547cea0065SJett.Zhou 	rtc_writel(sa1100_rtc, RTSR, rtsr);
25542874759SJett.Zhou 
2567cea0065SJett.Zhou 	spin_unlock_irq(&sa1100_rtc->lock);
257e842f1c8SRichard Purdie 
2587cea0065SJett.Zhou 	return 0;
259e842f1c8SRichard Purdie }
260e842f1c8SRichard Purdie 
261e842f1c8SRichard Purdie static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
262e842f1c8SRichard Purdie {
2637cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
264e842f1c8SRichard Purdie 
2657cea0065SJett.Zhou 	seq_printf(seq, "trim/divider\t\t: 0x%08x\n",
2667cea0065SJett.Zhou 			rtc_readl(sa1100_rtc, RTTR));
2677cea0065SJett.Zhou 	seq_printf(seq, "RTSR\t\t\t: 0x%08x\n",
2687cea0065SJett.Zhou 			rtc_readl(sa1100_rtc, RTSR));
269e842f1c8SRichard Purdie 	return 0;
270e842f1c8SRichard Purdie }
271e842f1c8SRichard Purdie 
272ff8371acSDavid Brownell static const struct rtc_class_ops sa1100_rtc_ops = {
273e842f1c8SRichard Purdie 	.open = sa1100_rtc_open,
274e842f1c8SRichard Purdie 	.release = sa1100_rtc_release,
275e842f1c8SRichard Purdie 	.read_time = sa1100_rtc_read_time,
276e842f1c8SRichard Purdie 	.set_time = sa1100_rtc_set_time,
277e842f1c8SRichard Purdie 	.read_alarm = sa1100_rtc_read_alarm,
278e842f1c8SRichard Purdie 	.set_alarm = sa1100_rtc_set_alarm,
279e842f1c8SRichard Purdie 	.proc = sa1100_rtc_proc,
28016380c15SJohn Stultz 	.alarm_irq_enable = sa1100_rtc_alarm_irq_enable,
281e842f1c8SRichard Purdie };
282e842f1c8SRichard Purdie 
283e842f1c8SRichard Purdie static int sa1100_rtc_probe(struct platform_device *pdev)
284e842f1c8SRichard Purdie {
2857cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc;
2867cea0065SJett.Zhou 	unsigned int rttr;
2877cea0065SJett.Zhou 	int ret;
2887cea0065SJett.Zhou 
2897cea0065SJett.Zhou 	sa1100_rtc = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL);
2907cea0065SJett.Zhou 	if (!sa1100_rtc)
2917cea0065SJett.Zhou 		return -ENOMEM;
2927cea0065SJett.Zhou 
2937cea0065SJett.Zhou 	spin_lock_init(&sa1100_rtc->lock);
2947cea0065SJett.Zhou 	platform_set_drvdata(pdev, sa1100_rtc);
2957cea0065SJett.Zhou 
2967cea0065SJett.Zhou 	ret = -ENXIO;
2977cea0065SJett.Zhou 	sa1100_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2987cea0065SJett.Zhou 	if (!sa1100_rtc->ress) {
2997cea0065SJett.Zhou 		dev_err(&pdev->dev, "No I/O memory resource defined\n");
3007cea0065SJett.Zhou 		goto err_ress;
3017cea0065SJett.Zhou 	}
3027cea0065SJett.Zhou 
3037cea0065SJett.Zhou 	sa1100_rtc->irq_1Hz = platform_get_irq(pdev, 0);
3047cea0065SJett.Zhou 	if (sa1100_rtc->irq_1Hz < 0) {
3057cea0065SJett.Zhou 		dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n");
3067cea0065SJett.Zhou 		goto err_ress;
3077cea0065SJett.Zhou 	}
3087cea0065SJett.Zhou 	sa1100_rtc->irq_Alrm = platform_get_irq(pdev, 1);
3097cea0065SJett.Zhou 	if (sa1100_rtc->irq_Alrm < 0) {
3107cea0065SJett.Zhou 		dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
3117cea0065SJett.Zhou 		goto err_ress;
3127cea0065SJett.Zhou 	}
3137cea0065SJett.Zhou 
3147cea0065SJett.Zhou 	ret = -ENOMEM;
3157cea0065SJett.Zhou 	sa1100_rtc->base = ioremap(sa1100_rtc->ress->start,
3167cea0065SJett.Zhou 				resource_size(sa1100_rtc->ress));
3177cea0065SJett.Zhou 	if (!sa1100_rtc->base) {
3187cea0065SJett.Zhou 		dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n");
3197cea0065SJett.Zhou 		goto err_map;
3207cea0065SJett.Zhou 	}
3217cea0065SJett.Zhou 
3227cea0065SJett.Zhou 	sa1100_rtc->clk = clk_get(&pdev->dev, NULL);
3237cea0065SJett.Zhou 	if (IS_ERR(sa1100_rtc->clk)) {
3247cea0065SJett.Zhou 		dev_err(&pdev->dev, "failed to find rtc clock source\n");
3257cea0065SJett.Zhou 		ret = PTR_ERR(sa1100_rtc->clk);
3267cea0065SJett.Zhou 		goto err_clk;
3277cea0065SJett.Zhou 	}
3287cea0065SJett.Zhou 	clk_prepare(sa1100_rtc->clk);
3297cea0065SJett.Zhou 	clk_enable(sa1100_rtc->clk);
330e842f1c8SRichard Purdie 
331e842f1c8SRichard Purdie 	/*
332e842f1c8SRichard Purdie 	 * According to the manual we should be able to let RTTR be zero
333e842f1c8SRichard Purdie 	 * and then a default diviser for a 32.768KHz clock is used.
334e842f1c8SRichard Purdie 	 * Apparently this doesn't work, at least for my SA1110 rev 5.
335e842f1c8SRichard Purdie 	 * If the clock divider is uninitialized then reset it to the
336e842f1c8SRichard Purdie 	 * default value to get the 1Hz clock.
337e842f1c8SRichard Purdie 	 */
3387cea0065SJett.Zhou 	if (rtc_readl(sa1100_rtc, RTTR) == 0) {
3397cea0065SJett.Zhou 		rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
3407cea0065SJett.Zhou 		rtc_writel(sa1100_rtc, RTTR, rttr);
3417cea0065SJett.Zhou 		dev_warn(&pdev->dev, "warning: initializing default clock"
3427cea0065SJett.Zhou 			 " divider/trim value\n");
343e842f1c8SRichard Purdie 		/* The current RTC value probably doesn't make sense either */
3447cea0065SJett.Zhou 		rtc_writel(sa1100_rtc, RCNR, 0);
345e842f1c8SRichard Purdie 	}
346e842f1c8SRichard Purdie 
347e5a2c9ccSUli Luckas 	device_init_wakeup(&pdev->dev, 1);
348e5a2c9ccSUli Luckas 
3497cea0065SJett.Zhou 	sa1100_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
3507cea0065SJett.Zhou 						&sa1100_rtc_ops, THIS_MODULE);
3517cea0065SJett.Zhou 	if (IS_ERR(sa1100_rtc->rtc)) {
3527cea0065SJett.Zhou 		dev_err(&pdev->dev, "Failed to register RTC device -> %d\n",
3537cea0065SJett.Zhou 			ret);
3547cea0065SJett.Zhou 		goto err_rtc_reg;
3557cea0065SJett.Zhou 	}
3567decaa55SMarcelo Roberto Jimenez 	/* Fix for a nasty initialization problem the in SA11xx RTSR register.
3577decaa55SMarcelo Roberto Jimenez 	 * See also the comments in sa1100_rtc_interrupt().
3587decaa55SMarcelo Roberto Jimenez 	 *
3597decaa55SMarcelo Roberto Jimenez 	 * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an
3607decaa55SMarcelo Roberto Jimenez 	 * interrupt pending, even though interrupts were never enabled.
3617decaa55SMarcelo Roberto Jimenez 	 * In this case, this bit it must be reset before enabling
3627decaa55SMarcelo Roberto Jimenez 	 * interruptions to avoid a nonexistent interrupt to occur.
3637decaa55SMarcelo Roberto Jimenez 	 *
3647decaa55SMarcelo Roberto Jimenez 	 * In principle, the same problem would apply to bit 0, although it has
3657decaa55SMarcelo Roberto Jimenez 	 * never been observed to happen.
3667decaa55SMarcelo Roberto Jimenez 	 *
3677decaa55SMarcelo Roberto Jimenez 	 * This issue is addressed both here and in sa1100_rtc_interrupt().
3687decaa55SMarcelo Roberto Jimenez 	 * If the issue is not addressed here, in the times when the processor
3697decaa55SMarcelo Roberto Jimenez 	 * wakes up with the bit set there will be one spurious interrupt.
3707decaa55SMarcelo Roberto Jimenez 	 *
3717decaa55SMarcelo Roberto Jimenez 	 * The issue is also dealt with in sa1100_rtc_interrupt() to be on the
3727decaa55SMarcelo Roberto Jimenez 	 * safe side, once the condition that lead to this strange
3737decaa55SMarcelo Roberto Jimenez 	 * initialization is unknown and could in principle happen during
3747decaa55SMarcelo Roberto Jimenez 	 * normal processing.
3757decaa55SMarcelo Roberto Jimenez 	 *
3767decaa55SMarcelo Roberto Jimenez 	 * Notice that clearing bit 1 and 0 is accomplished by writting ONES to
3777decaa55SMarcelo Roberto Jimenez 	 * the corresponding bits in RTSR. */
3787cea0065SJett.Zhou 	rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ));
3797decaa55SMarcelo Roberto Jimenez 
380e842f1c8SRichard Purdie 	return 0;
3817cea0065SJett.Zhou 
3827cea0065SJett.Zhou err_rtc_reg:
3837cea0065SJett.Zhou err_clk:
3847cea0065SJett.Zhou 	iounmap(sa1100_rtc->base);
3857cea0065SJett.Zhou err_ress:
3867cea0065SJett.Zhou err_map:
3877cea0065SJett.Zhou 	kfree(sa1100_rtc);
3887cea0065SJett.Zhou 	return ret;
389e842f1c8SRichard Purdie }
390e842f1c8SRichard Purdie 
391e842f1c8SRichard Purdie static int sa1100_rtc_remove(struct platform_device *pdev)
392e842f1c8SRichard Purdie {
3937cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = platform_get_drvdata(pdev);
394e842f1c8SRichard Purdie 
3957cea0065SJett.Zhou 	rtc_device_unregister(sa1100_rtc->rtc);
3967cea0065SJett.Zhou 	clk_disable(sa1100_rtc->clk);
3977cea0065SJett.Zhou 	clk_unprepare(sa1100_rtc->clk);
3987cea0065SJett.Zhou 	iounmap(sa1100_rtc->base);
399e842f1c8SRichard Purdie 	return 0;
400e842f1c8SRichard Purdie }
401e842f1c8SRichard Purdie 
4026bc54e69SRussell King #ifdef CONFIG_PM
4035d027cd2SHaojian Zhuang static int sa1100_rtc_suspend(struct device *dev)
4046bc54e69SRussell King {
4057cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
4067cea0065SJett.Zhou 
4075d027cd2SHaojian Zhuang 	if (device_may_wakeup(dev))
4087cea0065SJett.Zhou 		enable_irq_wake(sa1100_rtc->irq_Alrm);
4096bc54e69SRussell King 	return 0;
4106bc54e69SRussell King }
4116bc54e69SRussell King 
4125d027cd2SHaojian Zhuang static int sa1100_rtc_resume(struct device *dev)
4136bc54e69SRussell King {
4147cea0065SJett.Zhou 	struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev);
4157cea0065SJett.Zhou 
4165d027cd2SHaojian Zhuang 	if (device_may_wakeup(dev))
4177cea0065SJett.Zhou 		disable_irq_wake(sa1100_rtc->irq_Alrm);
4186bc54e69SRussell King 	return 0;
4196bc54e69SRussell King }
4205d027cd2SHaojian Zhuang 
42147145210SAlexey Dobriyan static const struct dev_pm_ops sa1100_rtc_pm_ops = {
4225d027cd2SHaojian Zhuang 	.suspend	= sa1100_rtc_suspend,
4235d027cd2SHaojian Zhuang 	.resume		= sa1100_rtc_resume,
4245d027cd2SHaojian Zhuang };
4256bc54e69SRussell King #endif
4266bc54e69SRussell King 
427e842f1c8SRichard Purdie static struct platform_driver sa1100_rtc_driver = {
428e842f1c8SRichard Purdie 	.probe		= sa1100_rtc_probe,
429e842f1c8SRichard Purdie 	.remove		= sa1100_rtc_remove,
430e842f1c8SRichard Purdie 	.driver		= {
431e842f1c8SRichard Purdie 		.name	= "sa1100-rtc",
4325d027cd2SHaojian Zhuang #ifdef CONFIG_PM
4335d027cd2SHaojian Zhuang 		.pm	= &sa1100_rtc_pm_ops,
4345d027cd2SHaojian Zhuang #endif
435e842f1c8SRichard Purdie 	},
436e842f1c8SRichard Purdie };
437e842f1c8SRichard Purdie 
438*0c4eae66SAxel Lin module_platform_driver(sa1100_rtc_driver);
439e842f1c8SRichard Purdie 
440e842f1c8SRichard Purdie MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
441e842f1c8SRichard Purdie MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)");
442e842f1c8SRichard Purdie MODULE_LICENSE("GPL");
443ad28a07bSKay Sievers MODULE_ALIAS("platform:sa1100-rtc");
444