• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/rtc/
1/*
2 * drivers/rtc/rtc-pl031.c
3 *
4 * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
5 *
6 * Author: Deepak Saxena <dsaxena@plexity.net>
7 *
8 * Copyright 2006 (c) MontaVista Software, Inc.
9 *
10 * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
11 * Copyright 2010 (c) ST-Ericsson AB
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
17 */
18#include <linux/module.h>
19#include <linux/rtc.h>
20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/amba/bus.h>
23#include <linux/io.h>
24#include <linux/bcd.h>
25#include <linux/delay.h>
26#include <linux/slab.h>
27
28/*
29 * Register definitions
30 */
31#define	RTC_DR		0x00	/* Data read register */
32#define	RTC_MR		0x04	/* Match register */
33#define	RTC_LR		0x08	/* Data load register */
34#define	RTC_CR		0x0c	/* Control register */
35#define	RTC_IMSC	0x10	/* Interrupt mask and set register */
36#define	RTC_RIS		0x14	/* Raw interrupt status register */
37#define	RTC_MIS		0x18	/* Masked interrupt status register */
38#define	RTC_ICR		0x1c	/* Interrupt clear register */
39/* ST variants have additional timer functionality */
40#define RTC_TDR		0x20	/* Timer data read register */
41#define RTC_TLR		0x24	/* Timer data load register */
42#define RTC_TCR		0x28	/* Timer control register */
43#define RTC_YDR		0x30	/* Year data read register */
44#define RTC_YMR		0x34	/* Year match register */
45#define RTC_YLR		0x38	/* Year data load register */
46
47#define RTC_CR_CWEN	(1 << 26)	/* Clockwatch enable bit */
48
49#define RTC_TCR_EN	(1 << 1) /* Periodic timer enable bit */
50
51/* Common bit definitions for Interrupt status and control registers */
52#define RTC_BIT_AI	(1 << 0) /* Alarm interrupt bit */
53#define RTC_BIT_PI	(1 << 1) /* Periodic interrupt bit. ST variants only. */
54
55/* Common bit definations for ST v2 for reading/writing time */
56#define RTC_SEC_SHIFT 0
57#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
58#define RTC_MIN_SHIFT 6
59#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
60#define RTC_HOUR_SHIFT 12
61#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
62#define RTC_WDAY_SHIFT 17
63#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
64#define RTC_MDAY_SHIFT 20
65#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
66#define RTC_MON_SHIFT 25
67#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
68
69#define RTC_TIMER_FREQ 32768
70
71struct pl031_local {
72	struct rtc_device *rtc;
73	void __iomem *base;
74	u8 hw_designer;
75	u8 hw_revision:4;
76};
77
78static int pl031_alarm_irq_enable(struct device *dev,
79	unsigned int enabled)
80{
81	struct pl031_local *ldata = dev_get_drvdata(dev);
82	unsigned long imsc;
83
84	/* Clear any pending alarm interrupts. */
85	writel(RTC_BIT_AI, ldata->base + RTC_ICR);
86
87	imsc = readl(ldata->base + RTC_IMSC);
88
89	if (enabled == 1)
90		writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC);
91	else
92		writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC);
93
94	return 0;
95}
96
97/*
98 * Convert Gregorian date to ST v2 RTC format.
99 */
100static int pl031_stv2_tm_to_time(struct device *dev,
101				 struct rtc_time *tm, unsigned long *st_time,
102	unsigned long *bcd_year)
103{
104	int year = tm->tm_year + 1900;
105	int wday = tm->tm_wday;
106
107	/* wday masking is not working in hardware so wday must be valid */
108	if (wday < -1 || wday > 6) {
109		dev_err(dev, "invalid wday value %d\n", tm->tm_wday);
110		return -EINVAL;
111	} else if (wday == -1) {
112		/* wday is not provided, calculate it here */
113		unsigned long time;
114		struct rtc_time calc_tm;
115
116		rtc_tm_to_time(tm, &time);
117		rtc_time_to_tm(time, &calc_tm);
118		wday = calc_tm.tm_wday;
119	}
120
121	*bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
122
123	*st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT)
124			|	(tm->tm_mday << RTC_MDAY_SHIFT)
125			|	((wday + 1) << RTC_WDAY_SHIFT)
126			|	(tm->tm_hour << RTC_HOUR_SHIFT)
127			|	(tm->tm_min << RTC_MIN_SHIFT)
128			|	(tm->tm_sec << RTC_SEC_SHIFT);
129
130	return 0;
131}
132
133/*
134 * Convert ST v2 RTC format to Gregorian date.
135 */
136static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
137	struct rtc_time *tm)
138{
139	tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
140	tm->tm_mon  = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1;
141	tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
142	tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
143	tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
144	tm->tm_min  = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
145	tm->tm_sec  = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
146
147	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
148	tm->tm_year -= 1900;
149
150	return 0;
151}
152
153static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm)
154{
155	struct pl031_local *ldata = dev_get_drvdata(dev);
156
157	pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR),
158			readl(ldata->base + RTC_YDR), tm);
159
160	return 0;
161}
162
163static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm)
164{
165	unsigned long time;
166	unsigned long bcd_year;
167	struct pl031_local *ldata = dev_get_drvdata(dev);
168	int ret;
169
170	ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year);
171	if (ret == 0) {
172		writel(bcd_year, ldata->base + RTC_YLR);
173		writel(time, ldata->base + RTC_LR);
174	}
175
176	return ret;
177}
178
179static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
180{
181	struct pl031_local *ldata = dev_get_drvdata(dev);
182	int ret;
183
184	ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR),
185			readl(ldata->base + RTC_YMR), &alarm->time);
186
187	alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
188	alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
189
190	return ret;
191}
192
193static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
194{
195	struct pl031_local *ldata = dev_get_drvdata(dev);
196	unsigned long time;
197	unsigned long bcd_year;
198	int ret;
199
200	/* At the moment, we can only deal with non-wildcarded alarm times. */
201	ret = rtc_valid_tm(&alarm->time);
202	if (ret == 0) {
203		ret = pl031_stv2_tm_to_time(dev, &alarm->time,
204					    &time, &bcd_year);
205		if (ret == 0) {
206			writel(bcd_year, ldata->base + RTC_YMR);
207			writel(time, ldata->base + RTC_MR);
208
209			pl031_alarm_irq_enable(dev, alarm->enabled);
210		}
211	}
212
213	return ret;
214}
215
216static irqreturn_t pl031_interrupt(int irq, void *dev_id)
217{
218	struct pl031_local *ldata = dev_id;
219	unsigned long rtcmis;
220	unsigned long events = 0;
221
222	rtcmis = readl(ldata->base + RTC_MIS);
223	if (rtcmis) {
224		writel(rtcmis, ldata->base + RTC_ICR);
225
226		if (rtcmis & RTC_BIT_AI)
227			events |= (RTC_AF | RTC_IRQF);
228
229		/* Timer interrupt is only available in ST variants */
230		if ((rtcmis & RTC_BIT_PI) &&
231			(ldata->hw_designer == AMBA_VENDOR_ST))
232			events |= (RTC_PF | RTC_IRQF);
233
234		rtc_update_irq(ldata->rtc, 1, events);
235
236		return IRQ_HANDLED;
237	}
238
239	return IRQ_NONE;
240}
241
242static int pl031_read_time(struct device *dev, struct rtc_time *tm)
243{
244	struct pl031_local *ldata = dev_get_drvdata(dev);
245
246	rtc_time_to_tm(readl(ldata->base + RTC_DR), tm);
247
248	return 0;
249}
250
251static int pl031_set_time(struct device *dev, struct rtc_time *tm)
252{
253	unsigned long time;
254	struct pl031_local *ldata = dev_get_drvdata(dev);
255	int ret;
256
257	ret = rtc_tm_to_time(tm, &time);
258
259	if (ret == 0)
260		writel(time, ldata->base + RTC_LR);
261
262	return ret;
263}
264
265static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
266{
267	struct pl031_local *ldata = dev_get_drvdata(dev);
268
269	rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time);
270
271	alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
272	alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
273
274	return 0;
275}
276
277static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
278{
279	struct pl031_local *ldata = dev_get_drvdata(dev);
280	unsigned long time;
281	int ret;
282
283	/* At the moment, we can only deal with non-wildcarded alarm times. */
284	ret = rtc_valid_tm(&alarm->time);
285	if (ret == 0) {
286		ret = rtc_tm_to_time(&alarm->time, &time);
287		if (ret == 0) {
288			writel(time, ldata->base + RTC_MR);
289			pl031_alarm_irq_enable(dev, alarm->enabled);
290		}
291	}
292
293	return ret;
294}
295
296/* Periodic interrupt is only available in ST variants. */
297static int pl031_irq_set_state(struct device *dev, int enabled)
298{
299	struct pl031_local *ldata = dev_get_drvdata(dev);
300
301	if (enabled == 1) {
302		/* Clear any pending timer interrupt. */
303		writel(RTC_BIT_PI, ldata->base + RTC_ICR);
304
305		writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI,
306			ldata->base + RTC_IMSC);
307
308		/* Now start the timer */
309		writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN,
310			ldata->base + RTC_TCR);
311
312	} else {
313		writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI),
314			ldata->base + RTC_IMSC);
315
316		/* Also stop the timer */
317		writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN),
318			ldata->base + RTC_TCR);
319	}
320	/* Wait at least 1 RTC32 clock cycle to ensure next access
321	 * to RTC_TCR will succeed.
322	 */
323	udelay(40);
324
325	return 0;
326}
327
328static int pl031_irq_set_freq(struct device *dev, int freq)
329{
330	struct pl031_local *ldata = dev_get_drvdata(dev);
331
332	/* Cant set timer if it is already enabled */
333	if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) {
334		dev_err(dev, "can't change frequency while timer enabled\n");
335		return -EINVAL;
336	}
337
338	/* If self start bit in RTC_TCR is set timer will start here,
339	 * but we never set that bit. Instead we start the timer when
340	 * set_state is called with enabled == 1.
341	 */
342	writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR);
343
344	return 0;
345}
346
347static int pl031_remove(struct amba_device *adev)
348{
349	struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
350
351	amba_set_drvdata(adev, NULL);
352	free_irq(adev->irq[0], ldata->rtc);
353	rtc_device_unregister(ldata->rtc);
354	iounmap(ldata->base);
355	kfree(ldata);
356	amba_release_regions(adev);
357
358	return 0;
359}
360
361static int pl031_probe(struct amba_device *adev, struct amba_id *id)
362{
363	int ret;
364	struct pl031_local *ldata;
365	struct rtc_class_ops *ops = id->data;
366
367	ret = amba_request_regions(adev, NULL);
368	if (ret)
369		goto err_req;
370
371	ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
372	if (!ldata) {
373		ret = -ENOMEM;
374		goto out;
375	}
376
377	ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
378
379	if (!ldata->base) {
380		ret = -ENOMEM;
381		goto out_no_remap;
382	}
383
384	amba_set_drvdata(adev, ldata);
385
386	ldata->hw_designer = amba_manf(adev);
387	ldata->hw_revision = amba_rev(adev);
388
389	dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
390	dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
391
392	/* Enable the clockwatch on ST Variants */
393	if ((ldata->hw_designer == AMBA_VENDOR_ST) &&
394	    (ldata->hw_revision > 1))
395		writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
396		       ldata->base + RTC_CR);
397
398	ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
399					THIS_MODULE);
400	if (IS_ERR(ldata->rtc)) {
401		ret = PTR_ERR(ldata->rtc);
402		goto out_no_rtc;
403	}
404
405	if (request_irq(adev->irq[0], pl031_interrupt,
406			IRQF_DISABLED, "rtc-pl031", ldata)) {
407		ret = -EIO;
408		goto out_no_irq;
409	}
410
411	return 0;
412
413out_no_irq:
414	rtc_device_unregister(ldata->rtc);
415out_no_rtc:
416	iounmap(ldata->base);
417	amba_set_drvdata(adev, NULL);
418out_no_remap:
419	kfree(ldata);
420out:
421	amba_release_regions(adev);
422err_req:
423
424	return ret;
425}
426
427/* Operations for the original ARM version */
428static struct rtc_class_ops arm_pl031_ops = {
429	.read_time = pl031_read_time,
430	.set_time = pl031_set_time,
431	.read_alarm = pl031_read_alarm,
432	.set_alarm = pl031_set_alarm,
433	.alarm_irq_enable = pl031_alarm_irq_enable,
434};
435
436/* The First ST derivative */
437static struct rtc_class_ops stv1_pl031_ops = {
438	.read_time = pl031_read_time,
439	.set_time = pl031_set_time,
440	.read_alarm = pl031_read_alarm,
441	.set_alarm = pl031_set_alarm,
442	.alarm_irq_enable = pl031_alarm_irq_enable,
443	.irq_set_state = pl031_irq_set_state,
444	.irq_set_freq = pl031_irq_set_freq,
445};
446
447/* And the second ST derivative */
448static struct rtc_class_ops stv2_pl031_ops = {
449	.read_time = pl031_stv2_read_time,
450	.set_time = pl031_stv2_set_time,
451	.read_alarm = pl031_stv2_read_alarm,
452	.set_alarm = pl031_stv2_set_alarm,
453	.alarm_irq_enable = pl031_alarm_irq_enable,
454	.irq_set_state = pl031_irq_set_state,
455	.irq_set_freq = pl031_irq_set_freq,
456};
457
458static struct amba_id pl031_ids[] = {
459	{
460		.id = 0x00041031,
461		.mask = 0x000fffff,
462		.data = &arm_pl031_ops,
463	},
464	/* ST Micro variants */
465	{
466		.id = 0x00180031,
467		.mask = 0x00ffffff,
468		.data = &stv1_pl031_ops,
469	},
470	{
471		.id = 0x00280031,
472		.mask = 0x00ffffff,
473		.data = &stv2_pl031_ops,
474	},
475	{0, 0},
476};
477
478static struct amba_driver pl031_driver = {
479	.drv = {
480		.name = "rtc-pl031",
481	},
482	.id_table = pl031_ids,
483	.probe = pl031_probe,
484	.remove = pl031_remove,
485};
486
487static int __init pl031_init(void)
488{
489	return amba_driver_register(&pl031_driver);
490}
491
492static void __exit pl031_exit(void)
493{
494	amba_driver_unregister(&pl031_driver);
495}
496
497module_init(pl031_init);
498module_exit(pl031_exit);
499
500MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
501MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
502MODULE_LICENSE("GPL");
503