aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2009-09-22 19:46:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:45 -0400
commitd00ed3cf6e54312fb59cd1fd6300d787d22373c7 (patch)
treedfaae6528a866c908f3c7db55f23c3481c15a690 /drivers/rtc
parentf3d2570a1482a6d897ba29276964965f6fe970d8 (diff)
rtc: add driver for MXC's internal RTC module
This adds a driver for Freescale's MXC internal real time clock modules. The code is taken from Freescale's BSPs, but modified to fit the current kernel coding mechanisms. Also, the PMIC external clock function was removed for now to not add dead bits and keep the code as simple as possible. [akpm@linux-foundation.org: make PIE_BIT_DEF[] static] Signed-off-by: Daniel Mack <daniel@caiaq.de> Cc: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Alessandro Zummo <a.zummo@towertech.it> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Daniel Mack <daniel@caiaq.de> Cc: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig11
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-mxc.c507
3 files changed, 519 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2ccd351c52e..18c5be168a5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -509,6 +509,17 @@ config RTC_DRV_M48T59
509 This driver can also be built as a module, if so, the module 509 This driver can also be built as a module, if so, the module
510 will be called "rtc-m48t59". 510 will be called "rtc-m48t59".
511 511
512config RTC_MXC
513 tristate "Freescale MXC Real Time Clock"
514 depends on ARCH_MXC
515 depends on RTC_CLASS
516 help
517 If you say yes here you get support for the Freescale MXC
518 RTC module.
519
520 This driver can also be built as a module, if so, the module
521 will be called "rtc-mxc".
522
512config RTC_DRV_BQ4802 523config RTC_DRV_BQ4802
513 tristate "TI BQ4802" 524 tristate "TI BQ4802"
514 help 525 help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0e9414995ca..5c16333fd91 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
46obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o 46obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
47obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o 47obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
48obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o 48obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
49obj-$(CONFIG_RTC_MXC) += rtc-mxc.o
49obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o 50obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
50obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o 51obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
51obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o 52obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
new file mode 100644
index 00000000000..6bd5072d4eb
--- /dev/null
+++ b/drivers/rtc/rtc-mxc.c
@@ -0,0 +1,507 @@
1/*
2 * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
3 *
4 * The code contained herein is licensed under the GNU General Public
5 * License. You may obtain a copy of the GNU General Public License
6 * Version 2 or later at the following locations:
7 *
8 * http://www.opensource.org/licenses/gpl-license.html
9 * http://www.gnu.org/copyleft/gpl.html
10 */
11
12#include <linux/io.h>
13#include <linux/rtc.h>
14#include <linux/module.h>
15#include <linux/interrupt.h>
16#include <linux/platform_device.h>
17#include <linux/clk.h>
18
19#include <mach/hardware.h>
20
21#define RTC_INPUT_CLK_32768HZ (0x00 << 5)
22#define RTC_INPUT_CLK_32000HZ (0x01 << 5)
23#define RTC_INPUT_CLK_38400HZ (0x02 << 5)
24
25#define RTC_SW_BIT (1 << 0)
26#define RTC_ALM_BIT (1 << 2)
27#define RTC_1HZ_BIT (1 << 4)
28#define RTC_2HZ_BIT (1 << 7)
29#define RTC_SAM0_BIT (1 << 8)
30#define RTC_SAM1_BIT (1 << 9)
31#define RTC_SAM2_BIT (1 << 10)
32#define RTC_SAM3_BIT (1 << 11)
33#define RTC_SAM4_BIT (1 << 12)
34#define RTC_SAM5_BIT (1 << 13)
35#define RTC_SAM6_BIT (1 << 14)
36#define RTC_SAM7_BIT (1 << 15)
37#define PIT_ALL_ON (RTC_2HZ_BIT | RTC_SAM0_BIT | RTC_SAM1_BIT | \
38 RTC_SAM2_BIT | RTC_SAM3_BIT | RTC_SAM4_BIT | \
39 RTC_SAM5_BIT | RTC_SAM6_BIT | RTC_SAM7_BIT)
40
41#define RTC_ENABLE_BIT (1 << 7)
42
43#define MAX_PIE_NUM 9
44#define MAX_PIE_FREQ 512
45static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
46 { 2, RTC_2HZ_BIT },
47 { 4, RTC_SAM0_BIT },
48 { 8, RTC_SAM1_BIT },
49 { 16, RTC_SAM2_BIT },
50 { 32, RTC_SAM3_BIT },
51 { 64, RTC_SAM4_BIT },
52 { 128, RTC_SAM5_BIT },
53 { 256, RTC_SAM6_BIT },
54 { MAX_PIE_FREQ, RTC_SAM7_BIT },
55};
56
57/* Those are the bits from a classic RTC we want to mimic */
58#define RTC_IRQF 0x80 /* any of the following 3 is active */
59#define RTC_PF 0x40 /* Periodic interrupt */
60#define RTC_AF 0x20 /* Alarm interrupt */
61#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */
62
63#define MXC_RTC_TIME 0
64#define MXC_RTC_ALARM 1
65
66#define RTC_HOURMIN 0x00 /* 32bit rtc hour/min counter reg */
67#define RTC_SECOND 0x04 /* 32bit rtc seconds counter reg */
68#define RTC_ALRM_HM 0x08 /* 32bit rtc alarm hour/min reg */
69#define RTC_ALRM_SEC 0x0C /* 32bit rtc alarm seconds reg */
70#define RTC_RTCCTL 0x10 /* 32bit rtc control reg */
71#define RTC_RTCISR 0x14 /* 32bit rtc interrupt status reg */
72#define RTC_RTCIENR 0x18 /* 32bit rtc interrupt enable reg */
73#define RTC_STPWCH 0x1C /* 32bit rtc stopwatch min reg */
74#define RTC_DAYR 0x20 /* 32bit rtc days counter reg */
75#define RTC_DAYALARM 0x24 /* 32bit rtc day alarm reg */
76#define RTC_TEST1 0x28 /* 32bit rtc test reg 1 */
77#define RTC_TEST2 0x2C /* 32bit rtc test reg 2 */
78#define RTC_TEST3 0x30 /* 32bit rtc test reg 3 */
79
80struct rtc_plat_data {
81 struct rtc_device *rtc;
82 void __iomem *ioaddr;
83 int irq;
84 struct clk *clk;
85 unsigned int irqen;
86 int alrm_sec;
87 int alrm_min;
88 int alrm_hour;
89 int alrm_mday;
90 struct timespec mxc_rtc_delta;
91 struct rtc_time g_rtc_alarm;
92};
93
94/*
95 * This function is used to obtain the RTC time or the alarm value in
96 * second.
97 */
98static u32 get_alarm_or_time(struct device *dev, int time_alarm)
99{
100 struct platform_device *pdev = to_platform_device(dev);
101 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
102 void __iomem *ioaddr = pdata->ioaddr;
103 u32 day = 0, hr = 0, min = 0, sec = 0, hr_min = 0;
104
105 switch (time_alarm) {
106 case MXC_RTC_TIME:
107 day = readw(ioaddr + RTC_DAYR);
108 hr_min = readw(ioaddr + RTC_HOURMIN);
109 sec = readw(ioaddr + RTC_SECOND);
110 break;
111 case MXC_RTC_ALARM:
112 day = readw(ioaddr + RTC_DAYALARM);
113 hr_min = readw(ioaddr + RTC_ALRM_HM) & 0xffff;
114 sec = readw(ioaddr + RTC_ALRM_SEC);
115 break;
116 }
117
118 hr = hr_min >> 8;
119 min = hr_min & 0xff;
120
121 return (((day * 24 + hr) * 60) + min) * 60 + sec;
122}
123
124/*
125 * This function sets the RTC alarm value or the time value.
126 */
127static void set_alarm_or_time(struct device *dev, int time_alarm, u32 time)
128{
129 u32 day, hr, min, sec, temp;
130 struct platform_device *pdev = to_platform_device(dev);
131 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
132 void __iomem *ioaddr = pdata->ioaddr;
133
134 day = time / 86400;
135 time -= day * 86400;
136
137 /* time is within a day now */
138 hr = time / 3600;
139 time -= hr * 3600;
140
141 /* time is within an hour now */
142 min = time / 60;
143 sec = time - min * 60;
144
145 temp = (hr << 8) + min;
146
147 switch (time_alarm) {
148 case MXC_RTC_TIME:
149 writew(day, ioaddr + RTC_DAYR);
150 writew(sec, ioaddr + RTC_SECOND);
151 writew(temp, ioaddr + RTC_HOURMIN);
152 break;
153 case MXC_RTC_ALARM:
154 writew(day, ioaddr + RTC_DAYALARM);
155 writew(sec, ioaddr + RTC_ALRM_SEC);
156 writew(temp, ioaddr + RTC_ALRM_HM);
157 break;
158 }
159}
160
161/*
162 * This function updates the RTC alarm registers and then clears all the
163 * interrupt status bits.
164 */
165static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
166{
167 struct rtc_time alarm_tm, now_tm;
168 unsigned long now, time;
169 int ret;
170 struct platform_device *pdev = to_platform_device(dev);
171 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
172 void __iomem *ioaddr = pdata->ioaddr;
173
174 now = get_alarm_or_time(dev, MXC_RTC_TIME);
175 rtc_time_to_tm(now, &now_tm);
176 alarm_tm.tm_year = now_tm.tm_year;
177 alarm_tm.tm_mon = now_tm.tm_mon;
178 alarm_tm.tm_mday = now_tm.tm_mday;
179 alarm_tm.tm_hour = alrm->tm_hour;
180 alarm_tm.tm_min = alrm->tm_min;
181 alarm_tm.tm_sec = alrm->tm_sec;
182 rtc_tm_to_time(&now_tm, &now);
183 rtc_tm_to_time(&alarm_tm, &time);
184
185 if (time < now) {
186 time += 60 * 60 * 24;
187 rtc_time_to_tm(time, &alarm_tm);
188 }
189
190 ret = rtc_tm_to_time(&alarm_tm, &time);
191
192 /* clear all the interrupt status bits */
193 writew(readw(ioaddr + RTC_RTCISR), ioaddr + RTC_RTCISR);
194 set_alarm_or_time(dev, MXC_RTC_ALARM, time);
195
196 return ret;
197}
198
199/* This function is the RTC interrupt service routine. */
200static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
201{
202 struct platform_device *pdev = dev_id;
203 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
204 void __iomem *ioaddr = pdata->ioaddr;
205 u32 status;
206 u32 events = 0;
207
208 spin_lock_irq(&pdata->rtc->irq_lock);
209 status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR);
210 /* clear interrupt sources */
211 writew(status, ioaddr + RTC_RTCISR);
212
213 /* clear alarm interrupt if it has occurred */
214 if (status & RTC_ALM_BIT)
215 status &= ~RTC_ALM_BIT;
216
217 /* update irq data & counter */
218 if (status & RTC_ALM_BIT)
219 events |= (RTC_AF | RTC_IRQF);
220
221 if (status & RTC_1HZ_BIT)
222 events |= (RTC_UF | RTC_IRQF);
223
224 if (status & PIT_ALL_ON)
225 events |= (RTC_PF | RTC_IRQF);
226
227 if ((status & RTC_ALM_BIT) && rtc_valid_tm(&pdata->g_rtc_alarm))
228 rtc_update_alarm(&pdev->dev, &pdata->g_rtc_alarm);
229
230 rtc_update_irq(pdata->rtc, 1, events);
231 spin_unlock_irq(&pdata->rtc->irq_lock);
232
233 return IRQ_HANDLED;
234}
235
236/*
237 * Clear all interrupts and release the IRQ
238 */
239static void mxc_rtc_release(struct device *dev)
240{
241 struct platform_device *pdev = to_platform_device(dev);
242 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
243 void __iomem *ioaddr = pdata->ioaddr;
244
245 spin_lock_irq(&pdata->rtc->irq_lock);
246
247 /* Disable all rtc interrupts */
248 writew(0, ioaddr + RTC_RTCIENR);
249
250 /* Clear all interrupt status */
251 writew(0xffffffff, ioaddr + RTC_RTCISR);
252
253 spin_unlock_irq(&pdata->rtc->irq_lock);
254}
255
256static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
257 unsigned int enabled)
258{
259 struct platform_device *pdev = to_platform_device(dev);
260 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
261 void __iomem *ioaddr = pdata->ioaddr;
262 u32 reg;
263
264 spin_lock_irq(&pdata->rtc->irq_lock);
265 reg = readw(ioaddr + RTC_RTCIENR);
266
267 if (enabled)
268 reg |= bit;
269 else
270 reg &= ~bit;
271
272 writew(reg, ioaddr + RTC_RTCIENR);
273 spin_unlock_irq(&pdata->rtc->irq_lock);
274}
275
276static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
277{
278 mxc_rtc_irq_enable(dev, RTC_ALM_BIT, enabled);
279 return 0;
280}
281
282static int mxc_rtc_update_irq_enable(struct device *dev, unsigned int enabled)
283{
284 mxc_rtc_irq_enable(dev, RTC_1HZ_BIT, enabled);
285 return 0;
286}
287
288/*
289 * This function reads the current RTC time into tm in Gregorian date.
290 */
291static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
292{
293 u32 val;
294
295 /* Avoid roll-over from reading the different registers */
296 do {
297 val = get_alarm_or_time(dev, MXC_RTC_TIME);
298 } while (val != get_alarm_or_time(dev, MXC_RTC_TIME));
299
300 rtc_time_to_tm(val, tm);
301
302 return 0;
303}
304
305/*
306 * This function sets the internal RTC time based on tm in Gregorian date.
307 */
308static int mxc_rtc_set_mmss(struct device *dev, unsigned long time)
309{
310 /* Avoid roll-over from reading the different registers */
311 do {
312 set_alarm_or_time(dev, MXC_RTC_TIME, time);
313 } while (time != get_alarm_or_time(dev, MXC_RTC_TIME));
314
315 return 0;
316}
317
318/*
319 * This function reads the current alarm value into the passed in 'alrm'
320 * argument. It updates the alrm's pending field value based on the whether
321 * an alarm interrupt occurs or not.
322 */
323static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
324{
325 struct platform_device *pdev = to_platform_device(dev);
326 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
327 void __iomem *ioaddr = pdata->ioaddr;
328
329 rtc_time_to_tm(get_alarm_or_time(dev, MXC_RTC_ALARM), &alrm->time);
330 alrm->pending = ((readw(ioaddr + RTC_RTCISR) & RTC_ALM_BIT)) ? 1 : 0;
331
332 return 0;
333}
334
335/*
336 * This function sets the RTC alarm based on passed in alrm.
337 */
338static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
339{
340 struct platform_device *pdev = to_platform_device(dev);
341 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
342 int ret;
343
344 if (rtc_valid_tm(&alrm->time)) {
345 if (alrm->time.tm_sec > 59 ||
346 alrm->time.tm_hour > 23 ||
347 alrm->time.tm_min > 59)
348 return -EINVAL;
349
350 ret = rtc_update_alarm(dev, &alrm->time);
351 } else {
352 ret = rtc_valid_tm(&alrm->time);
353 if (ret)
354 return ret;
355
356 ret = rtc_update_alarm(dev, &alrm->time);
357 }
358
359 if (ret)
360 return ret;
361
362 memcpy(&pdata->g_rtc_alarm, &alrm->time, sizeof(struct rtc_time));
363 mxc_rtc_irq_enable(dev, RTC_ALM_BIT, alrm->enabled);
364
365 return 0;
366}
367
368/* RTC layer */
369static struct rtc_class_ops mxc_rtc_ops = {
370 .release = mxc_rtc_release,
371 .read_time = mxc_rtc_read_time,
372 .set_mmss = mxc_rtc_set_mmss,
373 .read_alarm = mxc_rtc_read_alarm,
374 .set_alarm = mxc_rtc_set_alarm,
375 .alarm_irq_enable = mxc_rtc_alarm_irq_enable,
376 .update_irq_enable = mxc_rtc_update_irq_enable,
377};
378
379static int __init mxc_rtc_probe(struct platform_device *pdev)
380{
381 struct clk *clk;
382 struct resource *res;
383 struct rtc_device *rtc;
384 struct rtc_plat_data *pdata = NULL;
385 u32 reg;
386 int ret, rate;
387
388 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
389 if (!res)
390 return -ENODEV;
391
392 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
393 if (!pdata)
394 return -ENOMEM;
395
396 pdata->ioaddr = ioremap(res->start, resource_size(res));
397
398 clk = clk_get(&pdev->dev, "ckil");
399 if (IS_ERR(clk))
400 return PTR_ERR(clk);
401
402 rate = clk_get_rate(clk);
403 clk_put(clk);
404
405 if (rate == 32768)
406 reg = RTC_INPUT_CLK_32768HZ;
407 else if (rate == 32000)
408 reg = RTC_INPUT_CLK_32000HZ;
409 else if (rate == 38400)
410 reg = RTC_INPUT_CLK_38400HZ;
411 else {
412 dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n",
413 clk_get_rate(clk));
414 ret = -EINVAL;
415 goto exit_free_pdata;
416 }
417
418 reg |= RTC_ENABLE_BIT;
419 writew(reg, (pdata->ioaddr + RTC_RTCCTL));
420 if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
421 dev_err(&pdev->dev, "hardware module can't be enabled!\n");
422 ret = -EIO;
423 goto exit_free_pdata;
424 }
425
426 pdata->clk = clk_get(&pdev->dev, "rtc");
427 if (IS_ERR(pdata->clk)) {
428 dev_err(&pdev->dev, "unable to get clock!\n");
429 ret = PTR_ERR(pdata->clk);
430 goto exit_free_pdata;
431 }
432
433 clk_enable(pdata->clk);
434
435 rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
436 THIS_MODULE);
437 if (IS_ERR(rtc)) {
438 ret = PTR_ERR(rtc);
439 goto exit_put_clk;
440 }
441
442 pdata->rtc = rtc;
443 platform_set_drvdata(pdev, pdata);
444
445 /* Configure and enable the RTC */
446 pdata->irq = platform_get_irq(pdev, 0);
447
448 if (pdata->irq >= 0 &&
449 request_irq(pdata->irq, mxc_rtc_interrupt, IRQF_SHARED,
450 pdev->name, pdev) < 0) {
451 dev_warn(&pdev->dev, "interrupt not available.\n");
452 pdata->irq = -1;
453 }
454
455 return 0;
456
457exit_put_clk:
458 clk_put(pdata->clk);
459
460exit_free_pdata:
461 kfree(pdata);
462
463 return ret;
464}
465
466static int __exit mxc_rtc_remove(struct platform_device *pdev)
467{
468 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
469
470 rtc_device_unregister(pdata->rtc);
471
472 if (pdata->irq >= 0)
473 free_irq(pdata->irq, pdev);
474
475 clk_disable(pdata->clk);
476 clk_put(pdata->clk);
477 kfree(pdata);
478 platform_set_drvdata(pdev, NULL);
479
480 return 0;
481}
482
483static struct platform_driver mxc_rtc_driver = {
484 .driver = {
485 .name = "mxc_rtc",
486 .owner = THIS_MODULE,
487 },
488 .remove = __exit_p(mxc_rtc_remove),
489};
490
491static int __init mxc_rtc_init(void)
492{
493 return platform_driver_probe(&mxc_rtc_driver, mxc_rtc_probe);
494}
495
496static void __exit mxc_rtc_exit(void)
497{
498 platform_driver_unregister(&mxc_rtc_driver);
499}
500
501module_init(mxc_rtc_init);
502module_exit(mxc_rtc_exit);
503
504MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
505MODULE_DESCRIPTION("RTC driver for Freescale MXC");
506MODULE_LICENSE("GPL");
507