xref: /openbmc/linux/drivers/rtc/rtc-sa1100.c (revision e842f1c8ff8a88f290e26d1139e89aad02c4e0c3)
1*e842f1c8SRichard Purdie /*
2*e842f1c8SRichard Purdie  * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx
3*e842f1c8SRichard Purdie  *
4*e842f1c8SRichard Purdie  * Copyright (c) 2000 Nils Faerber
5*e842f1c8SRichard Purdie  *
6*e842f1c8SRichard Purdie  * Based on rtc.c by Paul Gortmaker
7*e842f1c8SRichard Purdie  *
8*e842f1c8SRichard Purdie  * Original Driver by Nils Faerber <nils@kernelconcepts.de>
9*e842f1c8SRichard Purdie  *
10*e842f1c8SRichard Purdie  * Modifications from:
11*e842f1c8SRichard Purdie  *   CIH <cih@coventive.com>
12*e842f1c8SRichard Purdie  *   Nicolas Pitre <nico@cam.org>
13*e842f1c8SRichard Purdie  *   Andrew Christian <andrew.christian@hp.com>
14*e842f1c8SRichard Purdie  *
15*e842f1c8SRichard Purdie  * Converted to the RTC subsystem and Driver Model
16*e842f1c8SRichard Purdie  *   by Richard Purdie <rpurdie@rpsys.net>
17*e842f1c8SRichard Purdie  *
18*e842f1c8SRichard Purdie  * This program is free software; you can redistribute it and/or
19*e842f1c8SRichard Purdie  * modify it under the terms of the GNU General Public License
20*e842f1c8SRichard Purdie  * as published by the Free Software Foundation; either version
21*e842f1c8SRichard Purdie  * 2 of the License, or (at your option) any later version.
22*e842f1c8SRichard Purdie  */
23*e842f1c8SRichard Purdie 
24*e842f1c8SRichard Purdie #include <linux/platform_device.h>
25*e842f1c8SRichard Purdie #include <linux/module.h>
26*e842f1c8SRichard Purdie #include <linux/rtc.h>
27*e842f1c8SRichard Purdie #include <linux/init.h>
28*e842f1c8SRichard Purdie #include <linux/fs.h>
29*e842f1c8SRichard Purdie #include <linux/interrupt.h>
30*e842f1c8SRichard Purdie #include <linux/string.h>
31*e842f1c8SRichard Purdie #include <linux/pm.h>
32*e842f1c8SRichard Purdie 
33*e842f1c8SRichard Purdie #include <asm/bitops.h>
34*e842f1c8SRichard Purdie #include <asm/hardware.h>
35*e842f1c8SRichard Purdie #include <asm/irq.h>
36*e842f1c8SRichard Purdie #include <asm/rtc.h>
37*e842f1c8SRichard Purdie 
38*e842f1c8SRichard Purdie #ifdef CONFIG_ARCH_PXA
39*e842f1c8SRichard Purdie #include <asm/arch/pxa-regs.h>
40*e842f1c8SRichard Purdie #endif
41*e842f1c8SRichard Purdie 
42*e842f1c8SRichard Purdie #define TIMER_FREQ		CLOCK_TICK_RATE
43*e842f1c8SRichard Purdie #define RTC_DEF_DIVIDER		32768 - 1
44*e842f1c8SRichard Purdie #define RTC_DEF_TRIM		0
45*e842f1c8SRichard Purdie 
46*e842f1c8SRichard Purdie static unsigned long rtc_freq = 1024;
47*e842f1c8SRichard Purdie static struct rtc_time rtc_alarm;
48*e842f1c8SRichard Purdie static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED;
49*e842f1c8SRichard Purdie 
50*e842f1c8SRichard Purdie static int rtc_update_alarm(struct rtc_time *alrm)
51*e842f1c8SRichard Purdie {
52*e842f1c8SRichard Purdie 	struct rtc_time alarm_tm, now_tm;
53*e842f1c8SRichard Purdie 	unsigned long now, time;
54*e842f1c8SRichard Purdie 	int ret;
55*e842f1c8SRichard Purdie 
56*e842f1c8SRichard Purdie 	do {
57*e842f1c8SRichard Purdie 		now = RCNR;
58*e842f1c8SRichard Purdie 		rtc_time_to_tm(now, &now_tm);
59*e842f1c8SRichard Purdie 		rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
60*e842f1c8SRichard Purdie 		ret = rtc_tm_to_time(&alarm_tm, &time);
61*e842f1c8SRichard Purdie 		if (ret != 0)
62*e842f1c8SRichard Purdie 			break;
63*e842f1c8SRichard Purdie 
64*e842f1c8SRichard Purdie 		RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
65*e842f1c8SRichard Purdie 		RTAR = time;
66*e842f1c8SRichard Purdie 	} while (now != RCNR);
67*e842f1c8SRichard Purdie 
68*e842f1c8SRichard Purdie 	return ret;
69*e842f1c8SRichard Purdie }
70*e842f1c8SRichard Purdie 
71*e842f1c8SRichard Purdie static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id,
72*e842f1c8SRichard Purdie 		struct pt_regs *regs)
73*e842f1c8SRichard Purdie {
74*e842f1c8SRichard Purdie 	struct platform_device *pdev = to_platform_device(dev_id);
75*e842f1c8SRichard Purdie 	struct rtc_device *rtc = platform_get_drvdata(pdev);
76*e842f1c8SRichard Purdie 	unsigned int rtsr;
77*e842f1c8SRichard Purdie 	unsigned long events = 0;
78*e842f1c8SRichard Purdie 
79*e842f1c8SRichard Purdie 	spin_lock(&sa1100_rtc_lock);
80*e842f1c8SRichard Purdie 
81*e842f1c8SRichard Purdie 	rtsr = RTSR;
82*e842f1c8SRichard Purdie 	/* clear interrupt sources */
83*e842f1c8SRichard Purdie 	RTSR = 0;
84*e842f1c8SRichard Purdie 	RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
85*e842f1c8SRichard Purdie 
86*e842f1c8SRichard Purdie 	/* clear alarm interrupt if it has occurred */
87*e842f1c8SRichard Purdie 	if (rtsr & RTSR_AL)
88*e842f1c8SRichard Purdie 		rtsr &= ~RTSR_ALE;
89*e842f1c8SRichard Purdie 	RTSR = rtsr & (RTSR_ALE | RTSR_HZE);
90*e842f1c8SRichard Purdie 
91*e842f1c8SRichard Purdie 	/* update irq data & counter */
92*e842f1c8SRichard Purdie 	if (rtsr & RTSR_AL)
93*e842f1c8SRichard Purdie 		events |= RTC_AF | RTC_IRQF;
94*e842f1c8SRichard Purdie 	if (rtsr & RTSR_HZ)
95*e842f1c8SRichard Purdie 		events |= RTC_UF | RTC_IRQF;
96*e842f1c8SRichard Purdie 
97*e842f1c8SRichard Purdie 	rtc_update_irq(&rtc->class_dev, 1, events);
98*e842f1c8SRichard Purdie 
99*e842f1c8SRichard Purdie 	if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
100*e842f1c8SRichard Purdie 		rtc_update_alarm(&rtc_alarm);
101*e842f1c8SRichard Purdie 
102*e842f1c8SRichard Purdie 	spin_unlock(&sa1100_rtc_lock);
103*e842f1c8SRichard Purdie 
104*e842f1c8SRichard Purdie 	return IRQ_HANDLED;
105*e842f1c8SRichard Purdie }
106*e842f1c8SRichard Purdie 
107*e842f1c8SRichard Purdie static int rtc_timer1_count;
108*e842f1c8SRichard Purdie 
109*e842f1c8SRichard Purdie static irqreturn_t timer1_interrupt(int irq, void *dev_id,
110*e842f1c8SRichard Purdie 		struct pt_regs *regs)
111*e842f1c8SRichard Purdie {
112*e842f1c8SRichard Purdie 	struct platform_device *pdev = to_platform_device(dev_id);
113*e842f1c8SRichard Purdie 	struct rtc_device *rtc = platform_get_drvdata(pdev);
114*e842f1c8SRichard Purdie 
115*e842f1c8SRichard Purdie 	/*
116*e842f1c8SRichard Purdie 	 * If we match for the first time, rtc_timer1_count will be 1.
117*e842f1c8SRichard Purdie 	 * Otherwise, we wrapped around (very unlikely but
118*e842f1c8SRichard Purdie 	 * still possible) so compute the amount of missed periods.
119*e842f1c8SRichard Purdie 	 * The match reg is updated only when the data is actually retrieved
120*e842f1c8SRichard Purdie 	 * to avoid unnecessary interrupts.
121*e842f1c8SRichard Purdie 	 */
122*e842f1c8SRichard Purdie 	OSSR = OSSR_M1;	/* clear match on timer1 */
123*e842f1c8SRichard Purdie 
124*e842f1c8SRichard Purdie 	rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF);
125*e842f1c8SRichard Purdie 
126*e842f1c8SRichard Purdie 	if (rtc_timer1_count == 1)
127*e842f1c8SRichard Purdie 		rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2)));
128*e842f1c8SRichard Purdie 
129*e842f1c8SRichard Purdie 	return IRQ_HANDLED;
130*e842f1c8SRichard Purdie }
131*e842f1c8SRichard Purdie 
132*e842f1c8SRichard Purdie static int sa1100_rtc_read_callback(struct device *dev, int data)
133*e842f1c8SRichard Purdie {
134*e842f1c8SRichard Purdie 	if (data & RTC_PF) {
135*e842f1c8SRichard Purdie 		/* interpolate missed periods and set match for the next */
136*e842f1c8SRichard Purdie 		unsigned long period = TIMER_FREQ/rtc_freq;
137*e842f1c8SRichard Purdie 		unsigned long oscr = OSCR;
138*e842f1c8SRichard Purdie 		unsigned long osmr1 = OSMR1;
139*e842f1c8SRichard Purdie 		unsigned long missed = (oscr - osmr1)/period;
140*e842f1c8SRichard Purdie 		data += missed << 8;
141*e842f1c8SRichard Purdie 		OSSR = OSSR_M1;	/* clear match on timer 1 */
142*e842f1c8SRichard Purdie 		OSMR1 = osmr1 + (missed + 1)*period;
143*e842f1c8SRichard Purdie 		/* Ensure we didn't miss another match in the mean time.
144*e842f1c8SRichard Purdie 		 * Here we compare (match - OSCR) 8 instead of 0 --
145*e842f1c8SRichard Purdie 		 * see comment in pxa_timer_interrupt() for explanation.
146*e842f1c8SRichard Purdie 		 */
147*e842f1c8SRichard Purdie 		while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) {
148*e842f1c8SRichard Purdie 			data += 0x100;
149*e842f1c8SRichard Purdie 			OSSR = OSSR_M1;	/* clear match on timer 1 */
150*e842f1c8SRichard Purdie 			OSMR1 = osmr1 + period;
151*e842f1c8SRichard Purdie 		}
152*e842f1c8SRichard Purdie 	}
153*e842f1c8SRichard Purdie 	return data;
154*e842f1c8SRichard Purdie }
155*e842f1c8SRichard Purdie 
156*e842f1c8SRichard Purdie static int sa1100_rtc_open(struct device *dev)
157*e842f1c8SRichard Purdie {
158*e842f1c8SRichard Purdie 	int ret;
159*e842f1c8SRichard Purdie 
160*e842f1c8SRichard Purdie 	ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT,
161*e842f1c8SRichard Purdie 				"rtc 1Hz", dev);
162*e842f1c8SRichard Purdie 	if (ret) {
163*e842f1c8SRichard Purdie 		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz);
164*e842f1c8SRichard Purdie 		goto fail_ui;
165*e842f1c8SRichard Purdie 	}
166*e842f1c8SRichard Purdie 	ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT,
167*e842f1c8SRichard Purdie 				"rtc Alrm", dev);
168*e842f1c8SRichard Purdie 	if (ret) {
169*e842f1c8SRichard Purdie 		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm);
170*e842f1c8SRichard Purdie 		goto fail_ai;
171*e842f1c8SRichard Purdie 	}
172*e842f1c8SRichard Purdie 	ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT,
173*e842f1c8SRichard Purdie 				"rtc timer", dev);
174*e842f1c8SRichard Purdie 	if (ret) {
175*e842f1c8SRichard Purdie 		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1);
176*e842f1c8SRichard Purdie 		goto fail_pi;
177*e842f1c8SRichard Purdie 	}
178*e842f1c8SRichard Purdie 	return 0;
179*e842f1c8SRichard Purdie 
180*e842f1c8SRichard Purdie  fail_pi:
181*e842f1c8SRichard Purdie 	free_irq(IRQ_RTCAlrm, NULL);
182*e842f1c8SRichard Purdie  fail_ai:
183*e842f1c8SRichard Purdie 	free_irq(IRQ_RTC1Hz, NULL);
184*e842f1c8SRichard Purdie  fail_ui:
185*e842f1c8SRichard Purdie 	return ret;
186*e842f1c8SRichard Purdie }
187*e842f1c8SRichard Purdie 
188*e842f1c8SRichard Purdie static void sa1100_rtc_release(struct device *dev)
189*e842f1c8SRichard Purdie {
190*e842f1c8SRichard Purdie 	spin_lock_irq(&sa1100_rtc_lock);
191*e842f1c8SRichard Purdie 	RTSR = 0;
192*e842f1c8SRichard Purdie 	OIER &= ~OIER_E1;
193*e842f1c8SRichard Purdie 	OSSR = OSSR_M1;
194*e842f1c8SRichard Purdie 	spin_unlock_irq(&sa1100_rtc_lock);
195*e842f1c8SRichard Purdie 
196*e842f1c8SRichard Purdie 	free_irq(IRQ_OST1, dev);
197*e842f1c8SRichard Purdie 	free_irq(IRQ_RTCAlrm, dev);
198*e842f1c8SRichard Purdie 	free_irq(IRQ_RTC1Hz, dev);
199*e842f1c8SRichard Purdie }
200*e842f1c8SRichard Purdie 
201*e842f1c8SRichard Purdie 
202*e842f1c8SRichard Purdie static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
203*e842f1c8SRichard Purdie 		unsigned long arg)
204*e842f1c8SRichard Purdie {
205*e842f1c8SRichard Purdie 	switch(cmd) {
206*e842f1c8SRichard Purdie 	case RTC_AIE_OFF:
207*e842f1c8SRichard Purdie 		spin_lock_irq(&sa1100_rtc_lock);
208*e842f1c8SRichard Purdie 		RTSR &= ~RTSR_ALE;
209*e842f1c8SRichard Purdie 		spin_unlock_irq(&sa1100_rtc_lock);
210*e842f1c8SRichard Purdie 		return 0;
211*e842f1c8SRichard Purdie 	case RTC_AIE_ON:
212*e842f1c8SRichard Purdie 		spin_lock_irq(&sa1100_rtc_lock);
213*e842f1c8SRichard Purdie 		RTSR |= RTSR_ALE;
214*e842f1c8SRichard Purdie 		spin_unlock_irq(&sa1100_rtc_lock);
215*e842f1c8SRichard Purdie 		return 0;
216*e842f1c8SRichard Purdie 	case RTC_UIE_OFF:
217*e842f1c8SRichard Purdie 		spin_lock_irq(&sa1100_rtc_lock);
218*e842f1c8SRichard Purdie 		RTSR &= ~RTSR_HZE;
219*e842f1c8SRichard Purdie 		spin_unlock_irq(&sa1100_rtc_lock);
220*e842f1c8SRichard Purdie 		return 0;
221*e842f1c8SRichard Purdie 	case RTC_UIE_ON:
222*e842f1c8SRichard Purdie 		spin_lock_irq(&sa1100_rtc_lock);
223*e842f1c8SRichard Purdie 		RTSR |= RTSR_HZE;
224*e842f1c8SRichard Purdie 		spin_unlock_irq(&sa1100_rtc_lock);
225*e842f1c8SRichard Purdie 		return 0;
226*e842f1c8SRichard Purdie 	case RTC_PIE_OFF:
227*e842f1c8SRichard Purdie 		spin_lock_irq(&sa1100_rtc_lock);
228*e842f1c8SRichard Purdie 		OIER &= ~OIER_E1;
229*e842f1c8SRichard Purdie 		spin_unlock_irq(&sa1100_rtc_lock);
230*e842f1c8SRichard Purdie 		return 0;
231*e842f1c8SRichard Purdie 	case RTC_PIE_ON:
232*e842f1c8SRichard Purdie 		if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
233*e842f1c8SRichard Purdie 			return -EACCES;
234*e842f1c8SRichard Purdie 		spin_lock_irq(&sa1100_rtc_lock);
235*e842f1c8SRichard Purdie 		OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
236*e842f1c8SRichard Purdie 		OIER |= OIER_E1;
237*e842f1c8SRichard Purdie 		rtc_timer1_count = 1;
238*e842f1c8SRichard Purdie 		spin_unlock_irq(&sa1100_rtc_lock);
239*e842f1c8SRichard Purdie 		return 0;
240*e842f1c8SRichard Purdie 	case RTC_IRQP_READ:
241*e842f1c8SRichard Purdie 		return put_user(rtc_freq, (unsigned long *)arg);
242*e842f1c8SRichard Purdie 	case RTC_IRQP_SET:
243*e842f1c8SRichard Purdie 		if (arg < 1 || arg > TIMER_FREQ)
244*e842f1c8SRichard Purdie 			return -EINVAL;
245*e842f1c8SRichard Purdie 		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
246*e842f1c8SRichard Purdie 			return -EACCES;
247*e842f1c8SRichard Purdie 		rtc_freq = arg;
248*e842f1c8SRichard Purdie 		return 0;
249*e842f1c8SRichard Purdie 	}
250*e842f1c8SRichard Purdie 	return -EINVAL;
251*e842f1c8SRichard Purdie }
252*e842f1c8SRichard Purdie 
253*e842f1c8SRichard Purdie static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
254*e842f1c8SRichard Purdie {
255*e842f1c8SRichard Purdie 	rtc_time_to_tm(RCNR, tm);
256*e842f1c8SRichard Purdie 	return 0;
257*e842f1c8SRichard Purdie }
258*e842f1c8SRichard Purdie 
259*e842f1c8SRichard Purdie static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
260*e842f1c8SRichard Purdie {
261*e842f1c8SRichard Purdie 	unsigned long time;
262*e842f1c8SRichard Purdie 	int ret;
263*e842f1c8SRichard Purdie 
264*e842f1c8SRichard Purdie 	ret = rtc_tm_to_time(tm, &time);
265*e842f1c8SRichard Purdie 	if (ret == 0)
266*e842f1c8SRichard Purdie 		RCNR = time;
267*e842f1c8SRichard Purdie 	return ret;
268*e842f1c8SRichard Purdie }
269*e842f1c8SRichard Purdie 
270*e842f1c8SRichard Purdie static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
271*e842f1c8SRichard Purdie {
272*e842f1c8SRichard Purdie 	memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
273*e842f1c8SRichard Purdie 	alrm->pending = RTSR & RTSR_AL ? 1 : 0;
274*e842f1c8SRichard Purdie 	return 0;
275*e842f1c8SRichard Purdie }
276*e842f1c8SRichard Purdie 
277*e842f1c8SRichard Purdie static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
278*e842f1c8SRichard Purdie {
279*e842f1c8SRichard Purdie 	int ret;
280*e842f1c8SRichard Purdie 
281*e842f1c8SRichard Purdie 	spin_lock_irq(&sa1100_rtc_lock);
282*e842f1c8SRichard Purdie 	ret = rtc_update_alarm(&alrm->time);
283*e842f1c8SRichard Purdie 	if (ret == 0) {
284*e842f1c8SRichard Purdie 		memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
285*e842f1c8SRichard Purdie 
286*e842f1c8SRichard Purdie 		if (alrm->enabled)
287*e842f1c8SRichard Purdie 			enable_irq_wake(IRQ_RTCAlrm);
288*e842f1c8SRichard Purdie 		else
289*e842f1c8SRichard Purdie 			disable_irq_wake(IRQ_RTCAlrm);
290*e842f1c8SRichard Purdie 	}
291*e842f1c8SRichard Purdie 	spin_unlock_irq(&sa1100_rtc_lock);
292*e842f1c8SRichard Purdie 
293*e842f1c8SRichard Purdie 	return ret;
294*e842f1c8SRichard Purdie }
295*e842f1c8SRichard Purdie 
296*e842f1c8SRichard Purdie static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
297*e842f1c8SRichard Purdie {
298*e842f1c8SRichard Purdie 	seq_printf(seq, "trim/divider\t: 0x%08x\n", RTTR);
299*e842f1c8SRichard Purdie 	seq_printf(seq, "alarm_IRQ\t: %s\n",
300*e842f1c8SRichard Purdie 			(RTSR & RTSR_ALE) ? "yes" : "no" );
301*e842f1c8SRichard Purdie 	seq_printf(seq, "update_IRQ\t: %s\n",
302*e842f1c8SRichard Purdie 			(RTSR & RTSR_HZE) ? "yes" : "no");
303*e842f1c8SRichard Purdie 	seq_printf(seq, "periodic_IRQ\t: %s\n",
304*e842f1c8SRichard Purdie 			(OIER & OIER_E1) ? "yes" : "no");
305*e842f1c8SRichard Purdie 	seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq);
306*e842f1c8SRichard Purdie 
307*e842f1c8SRichard Purdie 	return 0;
308*e842f1c8SRichard Purdie }
309*e842f1c8SRichard Purdie 
310*e842f1c8SRichard Purdie static struct rtc_class_ops sa1100_rtc_ops = {
311*e842f1c8SRichard Purdie 	.open = sa1100_rtc_open,
312*e842f1c8SRichard Purdie 	.read_callback = sa1100_rtc_read_callback,
313*e842f1c8SRichard Purdie 	.release = sa1100_rtc_release,
314*e842f1c8SRichard Purdie 	.ioctl = sa1100_rtc_ioctl,
315*e842f1c8SRichard Purdie 	.read_time = sa1100_rtc_read_time,
316*e842f1c8SRichard Purdie 	.set_time = sa1100_rtc_set_time,
317*e842f1c8SRichard Purdie 	.read_alarm = sa1100_rtc_read_alarm,
318*e842f1c8SRichard Purdie 	.set_alarm = sa1100_rtc_set_alarm,
319*e842f1c8SRichard Purdie 	.proc = sa1100_rtc_proc,
320*e842f1c8SRichard Purdie };
321*e842f1c8SRichard Purdie 
322*e842f1c8SRichard Purdie static int sa1100_rtc_probe(struct platform_device *pdev)
323*e842f1c8SRichard Purdie {
324*e842f1c8SRichard Purdie 	struct rtc_device *rtc;
325*e842f1c8SRichard Purdie 
326*e842f1c8SRichard Purdie 	/*
327*e842f1c8SRichard Purdie 	 * According to the manual we should be able to let RTTR be zero
328*e842f1c8SRichard Purdie 	 * and then a default diviser for a 32.768KHz clock is used.
329*e842f1c8SRichard Purdie 	 * Apparently this doesn't work, at least for my SA1110 rev 5.
330*e842f1c8SRichard Purdie 	 * If the clock divider is uninitialized then reset it to the
331*e842f1c8SRichard Purdie 	 * default value to get the 1Hz clock.
332*e842f1c8SRichard Purdie 	 */
333*e842f1c8SRichard Purdie 	if (RTTR == 0) {
334*e842f1c8SRichard Purdie 		RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
335*e842f1c8SRichard Purdie 		printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
336*e842f1c8SRichard Purdie 		/* The current RTC value probably doesn't make sense either */
337*e842f1c8SRichard Purdie 		RCNR = 0;
338*e842f1c8SRichard Purdie 	}
339*e842f1c8SRichard Purdie 
340*e842f1c8SRichard Purdie 	rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
341*e842f1c8SRichard Purdie 				THIS_MODULE);
342*e842f1c8SRichard Purdie 
343*e842f1c8SRichard Purdie 	if (IS_ERR(rtc)) {
344*e842f1c8SRichard Purdie 		dev_err(&pdev->dev, "Unable to register the RTC device\n");
345*e842f1c8SRichard Purdie 		return PTR_ERR(rtc);
346*e842f1c8SRichard Purdie 	}
347*e842f1c8SRichard Purdie 
348*e842f1c8SRichard Purdie 	platform_set_drvdata(pdev, rtc);
349*e842f1c8SRichard Purdie 
350*e842f1c8SRichard Purdie 	dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n");
351*e842f1c8SRichard Purdie 
352*e842f1c8SRichard Purdie 	return 0;
353*e842f1c8SRichard Purdie }
354*e842f1c8SRichard Purdie 
355*e842f1c8SRichard Purdie static int sa1100_rtc_remove(struct platform_device *pdev)
356*e842f1c8SRichard Purdie {
357*e842f1c8SRichard Purdie 	struct rtc_device *rtc = platform_get_drvdata(pdev);
358*e842f1c8SRichard Purdie 
359*e842f1c8SRichard Purdie  	if (rtc)
360*e842f1c8SRichard Purdie 		rtc_device_unregister(rtc);
361*e842f1c8SRichard Purdie 
362*e842f1c8SRichard Purdie 	return 0;
363*e842f1c8SRichard Purdie }
364*e842f1c8SRichard Purdie 
365*e842f1c8SRichard Purdie static struct platform_driver sa1100_rtc_driver = {
366*e842f1c8SRichard Purdie 	.probe		= sa1100_rtc_probe,
367*e842f1c8SRichard Purdie 	.remove		= sa1100_rtc_remove,
368*e842f1c8SRichard Purdie 	.driver		= {
369*e842f1c8SRichard Purdie 		.name		= "sa1100-rtc",
370*e842f1c8SRichard Purdie 	},
371*e842f1c8SRichard Purdie };
372*e842f1c8SRichard Purdie 
373*e842f1c8SRichard Purdie static int __init sa1100_rtc_init(void)
374*e842f1c8SRichard Purdie {
375*e842f1c8SRichard Purdie 	return platform_driver_register(&sa1100_rtc_driver);
376*e842f1c8SRichard Purdie }
377*e842f1c8SRichard Purdie 
378*e842f1c8SRichard Purdie static void __exit sa1100_rtc_exit(void)
379*e842f1c8SRichard Purdie {
380*e842f1c8SRichard Purdie 	platform_driver_unregister(&sa1100_rtc_driver);
381*e842f1c8SRichard Purdie }
382*e842f1c8SRichard Purdie 
383*e842f1c8SRichard Purdie module_init(sa1100_rtc_init);
384*e842f1c8SRichard Purdie module_exit(sa1100_rtc_exit);
385*e842f1c8SRichard Purdie 
386*e842f1c8SRichard Purdie MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
387*e842f1c8SRichard Purdie MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)");
388*e842f1c8SRichard Purdie MODULE_LICENSE("GPL");
389