Root/target/linux/coldfire/patches/026-Add-RTC-driver-support-for-MCF5445x.patch

1From 40563ab5aa698191dbd8a05fe6053aa790eee2a1 Mon Sep 17 00:00:00 2001
2From: Alison Wang <b18965@freescale.com>
3Date: Thu, 4 Aug 2011 09:59:46 +0800
4Subject: [PATCH 26/52] Add RTC driver support for MCF5445x
5
6On-chip RTC module support for MCF54451 and MCF54455.
7Using internal 32K clock to drive the rtc module.
8
9Signed-off-by: Alison Wang <b18965@freescale.com>
10---
11 drivers/rtc/Kconfig | 9 +
12 drivers/rtc/Makefile | 1 +
13 drivers/rtc/rtc-mcf.c | 583 +++++++++++++++++++++++++++++++++++++++++++++++++
14 3 files changed, 593 insertions(+), 0 deletions(-)
15 create mode 100644 drivers/rtc/rtc-mcf.c
16
17--- a/drivers/rtc/Kconfig
18+++ b/drivers/rtc/Kconfig
19@@ -919,6 +919,15 @@ config RTC_DRV_MV
20       This driver can also be built as a module. If so, the module
21       will be called rtc-mv.
22 
23+config RTC_MCF
24+ tristate "Freescale Coldfire Real Time Clock"
25+ depends on COLDFIRE
26+ help
27+ If you say yes here you will get support for the on-chip Coldfire
28+ Real-Time Clock.
29+
30+ If you build it as a module it will be call mcf-rtc.
31+
32 config RTC_DRV_PS3
33     tristate "PS3 RTC"
34     depends on PPC_PS3
35--- a/drivers/rtc/Makefile
36+++ b/drivers/rtc/Makefile
37@@ -102,3 +102,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41
38 obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
39 obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
40 obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
41+obj-$(CONFIG_RTC_MCF) += rtc-mcf.o
42--- /dev/null
43+++ b/drivers/rtc/rtc-mcf.c
44@@ -0,0 +1,583 @@
45+/*
46+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
47+ *
48+ * Implementation based on rtc-mxc.c
49+ * This file contains Real Time Clock interface for Linux.
50+ *
51+ * This is free software; you can redistribute it and/or modify
52+ * it under the terms of the GNU General Public License as published by
53+ * the Free Software Foundation; either version 2 of the License, or
54+ * (at your option) any later version.
55+ */
56+
57+#include <linux/rtc.h>
58+#include <linux/module.h>
59+#include <linux/fs.h>
60+#include <linux/init.h>
61+#include <linux/interrupt.h>
62+#include <linux/platform_device.h>
63+#include <linux/clk.h>
64+#include <linux/uaccess.h>
65+#include <asm/mcfsim.h>
66+#include <linux/slab.h>
67+#include <linux/io.h>
68+
69+#ifdef readl
70+#undef readl
71+#endif
72+
73+#ifdef writel
74+#undef writel
75+#endif
76+
77+#define readl(addr) in_be32(addr)
78+#define writel(val, addr) out_be32((addr), (val))
79+
80+#define RTC_INPUT_CLK_32768HZ 0x8000
81+#define RTC_INPUT_CLK_32000HZ 0x7D00
82+#define RTC_INPUT_CLK_38400HZ 0x9600
83+#define RTC_INPUT_CLK_48000HZ 0xBB80
84+
85+#define PIT_ALL_ON (MCF_RTC_ISR_2HZ | MCF_RTC_ISR_SAM0 | MCF_RTC_ISR_SAM1 | \
86+ MCF_RTC_ISR_SAM2 | MCF_RTC_ISR_SAM3 | MCF_RTC_ISR_SAM4 | \
87+ MCF_RTC_ISR_SAM5 | MCF_RTC_ISR_SAM6 | MCF_RTC_ISR_SAM7)
88+
89+#define MAX_PIE_NUM 9
90+#define MAX_PIE_FREQ 512
91+const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
92+ {2, MCF_RTC_ISR_2HZ},
93+ {4, MCF_RTC_ISR_SAM0},
94+ {8, MCF_RTC_ISR_SAM1},
95+ {16, MCF_RTC_ISR_SAM2},
96+ {32, MCF_RTC_ISR_SAM3},
97+ {64, MCF_RTC_ISR_SAM4},
98+ {128, MCF_RTC_ISR_SAM5},
99+ {256, MCF_RTC_ISR_SAM6},
100+ {MAX_PIE_FREQ, MCF_RTC_ISR_SAM7},
101+};
102+
103+/* Those are the bits from a classic RTC we want to mimic */
104+#define RTC_IRQF 0x80 /* any of the following 3 is active */
105+#define RTC_PF 0x40 /* Periodic interrupt */
106+#define RTC_AF 0x20 /* Alarm interrupt */
107+#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */
108+
109+#define MCF_RTC_TIME 0
110+#define MCF_RTC_ALARM 1
111+
112+struct rtc_plat_data {
113+ struct rtc_device *rtc;
114+ int irq;
115+ unsigned int irqen;
116+ int alrm_sec;
117+ int alrm_min;
118+ int alrm_hour;
119+ int alrm_mday;
120+};
121+
122+/*!
123+ * @defgroup RTC Real Time Clock (RTC) Driver
124+ */
125+/*!
126+ * @file rtc-mcf.c
127+ * @brief Real Time Clock interface
128+ *
129+ * This file contains Real Time Clock interface for Linux.
130+ *
131+ * @ingroup RTC
132+ */
133+
134+#define RTC_VERSION "0.1"
135+
136+static u32 rtc_freq = 2; /* minimun value for PIE */
137+static unsigned long rtc_status;
138+
139+static struct rtc_time g_rtc_alarm = {
140+ .tm_year = 0,
141+ .tm_mon = 0,
142+ .tm_mday = 0,
143+ .tm_hour = 0,
144+ .tm_mon = 0,
145+ .tm_sec = 0,
146+};
147+
148+static DEFINE_SPINLOCK(rtc_lock);
149+
150+/*!
151+ * This function is used to obtain the RTC time or the alarm value in
152+ * second.
153+ *
154+ * @param time_alarm use MCF_RTC_TIME for RTC time value;
155+ * MCF_RTC_ALARM for alarm value
156+ *
157+ * @return The RTC time or alarm time in second.
158+ */
159+static u32 get_alarm_or_time(struct device *dev, int time_alarm)
160+{
161+ u32 day, hr, min, sec, hr_min;
162+
163+ if (time_alarm == MCF_RTC_TIME) {
164+ day = MCF_RTC_DAYS_DAYS(readl(MCF_RTC_DAYS));
165+ hr_min = readl(MCF_RTC_HOURMIN);
166+ sec = MCF_RTC_SECONDS_SECONDS(readl(MCF_RTC_SECONDS));
167+ } else if (time_alarm == MCF_RTC_ALARM) {
168+ day = MCF_RTC_ALRM_DAY_DAYS(readl(MCF_RTC_ALRM_DAY));
169+ hr_min = readl(MCF_RTC_ALRM_HM);
170+ sec = MCF_RTC_ALRM_SEC_SECONDS(readl(MCF_RTC_ALRM_SEC));
171+ } else {
172+ panic("wrong value for time_alarm=%d\n", time_alarm);
173+ }
174+
175+ hr = (hr_min >> 8) & 0x001F;
176+ min = hr_min & 0x003F;
177+
178+ return (((day * 24 + hr) * 60) + min) * 60 + sec;
179+}
180+
181+/*!
182+ * This function sets the RTC alarm value or the time value.
183+ *
184+ * @param time_alarm the new alarm value to be updated in the RTC
185+ * @param time use MCF_RTC_TIME for RTC time value;
186+ * MCF_RTC_ALARM for alarm value
187+ */
188+static void set_alarm_or_time(struct device *dev, int time_alarm, u32 time)
189+{
190+ u32 day, hr, min, sec, temp;
191+
192+ day = time / 86400;
193+ time -= day * 86400;
194+ /* time is within a day now */
195+ hr = time / 3600;
196+ time -= hr * 3600;
197+ /* time is within an hour now */
198+ min = time / 60;
199+ sec = time - min * 60;
200+
201+ temp = (hr << 8) + min;
202+
203+ if (time_alarm == MCF_RTC_TIME) {
204+ writel(day, MCF_RTC_DAYS);
205+ writel(sec, MCF_RTC_SECONDS);
206+ writel(temp, MCF_RTC_HOURMIN);
207+ } else if (time_alarm == MCF_RTC_ALARM) {
208+ writel(day, MCF_RTC_ALRM_DAY);
209+ writel(sec, MCF_RTC_ALRM_SEC);
210+ writel(temp, MCF_RTC_ALRM_HM);
211+ } else {
212+ panic("wrong value for time_alarm=%d\n", time_alarm);
213+ }
214+}
215+
216+/*!
217+ * This function updates the RTC alarm registers and then clears all the
218+ * interrupt status bits.
219+ *
220+ * @param alrm the new alarm value to be updated in the RTC
221+ *
222+ * @return 0 if successful; non-zero otherwise.
223+ */
224+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
225+{
226+ struct rtc_time alarm_tm, now_tm;
227+ unsigned long now, time;
228+ int ret;
229+
230+ now = get_alarm_or_time(dev, MCF_RTC_TIME);
231+ rtc_time_to_tm(now, &now_tm);
232+ alarm_tm.tm_year = now_tm.tm_year;
233+ alarm_tm.tm_mon = now_tm.tm_mon;
234+ alarm_tm.tm_mday = now_tm.tm_mday;
235+ alarm_tm.tm_hour = alrm->tm_hour;
236+ alarm_tm.tm_min = alrm->tm_min;
237+ alarm_tm.tm_sec = alrm->tm_sec;
238+ rtc_tm_to_time(&now_tm, &now);
239+ rtc_tm_to_time(&alarm_tm, &time);
240+ if (time < now) {
241+ time += 60 * 60 * 24;
242+ rtc_time_to_tm(time, &alarm_tm);
243+ }
244+ ret = rtc_tm_to_time(&alarm_tm, &time);
245+
246+ /* clear all the interrupt status bits */
247+ writel(readl(MCF_RTC_ISR), MCF_RTC_ISR);
248+
249+ set_alarm_or_time(dev, MCF_RTC_ALARM, time);
250+
251+ return ret;
252+}
253+
254+/*!
255+ * This function is the RTC interrupt service routine.
256+ *
257+ * @param irq RTC IRQ number
258+ * @param dev_id device ID which is not used
259+ *
260+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
261+ */
262+static irqreturn_t mcf_rtc_interrupt(int irq, void *dev_id)
263+{
264+ struct platform_device *pdev = dev_id;
265+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
266+ u32 status, events = 0;
267+
268+ spin_lock(&rtc_lock);
269+
270+ /* clear interrupt sources */
271+ status = readl(MCF_RTC_ISR) & readl(MCF_RTC_IER);
272+ writel(status, MCF_RTC_ISR);
273+
274+ /* clear alarm interrupt if it has occurred */
275+ if (status & MCF_RTC_ISR_ALM)
276+ status &= ~MCF_RTC_ISR_ALM;
277+
278+ /* update irq data & counter */
279+ if (status & MCF_RTC_ISR_ALM)
280+ events |= (RTC_AF | RTC_IRQF);
281+ if (status & MCF_RTC_ISR_1HZ)
282+ events |= (RTC_UF | RTC_IRQF);
283+ if (status & PIT_ALL_ON)
284+ events |= (RTC_PF | RTC_IRQF);
285+
286+ if ((status & MCF_RTC_ISR_ALM) && rtc_valid_tm(&g_rtc_alarm))
287+ rtc_update_alarm(&pdev->dev, &g_rtc_alarm);
288+
289+ spin_unlock(&rtc_lock);
290+ rtc_update_irq(pdata->rtc, 1, events);
291+ return IRQ_HANDLED;
292+}
293+
294+/*!
295+ * clear all interrupts and release the IRQ
296+ */
297+static void mcf_rtc_release(struct device *dev)
298+{
299+ spin_lock_irq(&rtc_lock);
300+ writel(0, MCF_RTC_IER); /* Disable all rtc interrupts */
301+ writel(0x0000FFBF, MCF_RTC_ISR); /* Clear all interrupt status */
302+ spin_unlock_irq(&rtc_lock);
303+ rtc_status = 0;
304+}
305+
306+/*!
307+ * This function is used to support some ioctl calls directly.
308+ * Other ioctl calls are supported indirectly through the
309+ * arm/common/rtctime.c file.
310+ *
311+ * @param cmd ioctl command as defined in include/linux/rtc.h
312+ * @param arg value for the ioctl command
313+ *
314+ * @return 0 if successful or negative value otherwise.
315+ */
316+static int mcf_rtc_ioctl(struct device *dev, unsigned int cmd,
317+ unsigned long arg)
318+{
319+ int i;
320+
321+ switch (cmd) {
322+ case RTC_PIE_OFF:
323+ writel((readl(MCF_RTC_IER) & ~PIT_ALL_ON), MCF_RTC_IER);
324+ return 0;
325+ case RTC_IRQP_SET:
326+ if (arg < 2 || arg > MAX_PIE_FREQ || (arg % 2) != 0)
327+ return -EINVAL; /* Also make sure a power of 2Hz */
328+ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
329+ return -EACCES;
330+ rtc_freq = arg;
331+ return 0;
332+ case RTC_IRQP_READ:
333+ return put_user(rtc_freq, (u32 *) arg);
334+ case RTC_PIE_ON:
335+ for (i = 0; i < MAX_PIE_NUM; i++) {
336+ if (PIE_BIT_DEF[i][0] == rtc_freq)
337+ break;
338+ }
339+ if (i == MAX_PIE_NUM)
340+ return -EACCES;
341+ spin_lock_irq(&rtc_lock);
342+ writel((readl(MCF_RTC_IER) | PIE_BIT_DEF[i][1]), MCF_RTC_IER);
343+ spin_unlock_irq(&rtc_lock);
344+ return 0;
345+ case RTC_AIE_OFF:
346+ spin_lock_irq(&rtc_lock);
347+ writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER);
348+ spin_unlock_irq(&rtc_lock);
349+ return 0;
350+
351+ case RTC_AIE_ON:
352+ spin_lock_irq(&rtc_lock);
353+ writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER);
354+ spin_unlock_irq(&rtc_lock);
355+ return 0;
356+
357+ case RTC_UIE_OFF: /* UIE is for the 1Hz interrupt */
358+ spin_lock_irq(&rtc_lock);
359+ writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_1HZ), MCF_RTC_IER);
360+ spin_unlock_irq(&rtc_lock);
361+ return 0;
362+
363+ case RTC_UIE_ON:
364+ spin_lock_irq(&rtc_lock);
365+ writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_1HZ), MCF_RTC_IER);
366+ spin_unlock_irq(&rtc_lock);
367+ return 0;
368+ }
369+ return -ENOIOCTLCMD;
370+}
371+
372+/*!
373+ * This function reads the current RTC time into tm in Gregorian date.
374+ *
375+ * @param tm contains the RTC time value upon return
376+ *
377+ * @return 0 if successful; non-zero otherwise.
378+ */
379+static int mcf_rtc_read_time(struct device *dev, struct rtc_time *tm)
380+{
381+ u32 val;
382+
383+ /* Avoid roll-over from reading the different registers */
384+ do {
385+ val = get_alarm_or_time(dev, MCF_RTC_TIME);
386+ } while (val != get_alarm_or_time(dev, MCF_RTC_TIME));
387+
388+ rtc_time_to_tm(val, tm);
389+ return 0;
390+}
391+
392+/*!
393+ * This function sets the internal RTC time based on tm in Gregorian date.
394+ *
395+ * @param tm the time value to be set in the RTC
396+ *
397+ * @return 0 if successful; non-zero otherwise.
398+ */
399+static int mcf_rtc_set_time(struct device *dev, struct rtc_time *tm)
400+{
401+ unsigned long time;
402+ int ret;
403+
404+ ret = rtc_tm_to_time(tm, &time);
405+ if (ret != 0)
406+ return ret;
407+
408+ /* Avoid roll-over from reading the different registers */
409+ do {
410+ set_alarm_or_time(dev, MCF_RTC_TIME, time);
411+ } while (time != get_alarm_or_time(dev, MCF_RTC_TIME));
412+
413+ return ret;
414+}
415+
416+/*!
417+ * This function reads the current alarm value into the passed in \b alrm
418+ * argument. It updates the \b alrm's pending field value based on the whether
419+ * an alarm interrupt occurs or not.
420+ *
421+ * @param alrm contains the RTC alarm value upon return
422+ *
423+ * @return 0 if successful; non-zero otherwise.
424+ */
425+static int mcf_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
426+{
427+ rtc_time_to_tm(get_alarm_or_time(dev, MCF_RTC_ALARM), &alrm->time);
428+ alrm->pending = ((readl(MCF_RTC_ISR) & MCF_RTC_ISR_ALM) != 0) ? 1 : 0;
429+
430+ return 0;
431+}
432+
433+/*!
434+ * This function sets the RTC alarm based on passed in alrm.
435+ *
436+ * @param alrm the alarm value to be set in the RTC
437+ *
438+ * @return 0 if successful; non-zero otherwise.
439+ */
440+static int mcf_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
441+{
442+ int ret;
443+
444+ spin_lock_irq(&rtc_lock);
445+ if (rtc_valid_tm(&alrm->time)) {
446+ if (alrm->time.tm_sec > 59 ||
447+ alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) {
448+ ret = -EINVAL;
449+ goto out;
450+ }
451+ ret = rtc_update_alarm(dev, &alrm->time);
452+ } else {
453+ ret = rtc_valid_tm(&alrm->time);
454+ if (ret)
455+ goto out;
456+ ret = rtc_update_alarm(dev, &alrm->time);
457+ }
458+
459+ if (ret == 0) {
460+ memcpy(&g_rtc_alarm, &alrm->time, sizeof(struct rtc_time));
461+
462+ if (alrm->enabled) {
463+ writel((readl(MCF_RTC_IER) | MCF_RTC_ISR_ALM),
464+ MCF_RTC_IER);
465+ } else {
466+ writel((readl(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM),
467+ MCF_RTC_IER);
468+ }
469+ }
470+out:
471+ spin_unlock_irq(&rtc_lock);
472+
473+ return ret;
474+}
475+
476+/*!
477+ * This function is used to provide the content for the /proc/driver/rtc
478+ * file.
479+ *
480+ * @param buf the buffer to hold the information that the driver
481+ * wants to write
482+ *
483+ * @return The number of bytes written into the rtc file.
484+ */
485+static int mcf_rtc_proc(struct device *dev, struct seq_file *sq)
486+{
487+ char *p = sq->buf;
488+
489+ p += sprintf(p, "alarm_IRQ\t: %s\n",
490+ (((readl(MCF_RTC_IER)) & MCF_RTC_ISR_ALM) !=
491+ 0) ? "yes" : "no");
492+ p += sprintf(p, "update_IRQ\t: %s\n",
493+ (((readl(MCF_RTC_IER)) & MCF_RTC_ISR_1HZ) !=
494+ 0) ? "yes" : "no");
495+ p += sprintf(p, "periodic_IRQ\t: %s\n",
496+ (((readl(MCF_RTC_IER)) & PIT_ALL_ON) !=
497+ 0) ? "yes" : "no");
498+ p += sprintf(p, "periodic_freq\t: %d\n", rtc_freq);
499+
500+ return p - (sq->buf);
501+}
502+
503+/*!
504+ * The RTC driver structure
505+ */
506+static struct rtc_class_ops mcf_rtc_ops = {
507+ .ioctl = mcf_rtc_ioctl,
508+ .read_time = mcf_rtc_read_time,
509+ .set_time = mcf_rtc_set_time,
510+ .read_alarm = mcf_rtc_read_alarm,
511+ .set_alarm = mcf_rtc_set_alarm,
512+ .proc = mcf_rtc_proc,
513+};
514+
515+static int __devinit mcf_rtc_probe(struct platform_device *pdev)
516+{
517+ struct timespec tv;
518+ struct rtc_device *rtc;
519+ struct rtc_plat_data *pdata = NULL;
520+ u32 ret = 0;
521+
522+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
523+ if (!pdata)
524+ return -ENOMEM;
525+ /* External clock is hard wired to 32768Hz.
526+ * Clock settings 32K, 38.4K and 48K are defined above. */
527+#if defined(CONFIG_M5227x) | defined(CONFIG_M5445X)
528+ writel(0, MCF_RTC_GOCU);
529+ writel(RTC_INPUT_CLK_32768HZ, MCF_RTC_GOCL);
530+#endif
531+ /* Configure and enable the RTC */
532+ pdata->irq = MCFINT_VECBASE + MCFINT_RTC;
533+ if (request_irq(pdata->irq, mcf_rtc_interrupt, IRQF_DISABLED,
534+ pdev->name, pdev) < 0) {
535+ dev_warn(&pdev->dev, "interrupt not available.\n");
536+ pdata->irq = -1;
537+ }
538+
539+ if (test_and_set_bit(1, &rtc_status))
540+ return -EBUSY;
541+
542+ rtc = rtc_device_register(pdev->name, &pdev->dev, &mcf_rtc_ops,
543+ THIS_MODULE);
544+ if (IS_ERR(rtc)) {
545+ ret = PTR_ERR(rtc);
546+ if (pdata->irq >= 0)
547+ free_irq(pdata->irq, pdev);
548+ kfree(pdata);
549+ return ret;
550+ }
551+ pdata->rtc = rtc;
552+ platform_set_drvdata(pdev, pdata);
553+
554+ tv.tv_nsec = 0;
555+ tv.tv_sec = get_alarm_or_time(&pdev->dev, MCF_RTC_TIME);
556+
557+#ifdef CONFIG_M5301x
558+ writel(RTC_INPUT_CLK_32768HZ, MCF_RTC_GOC);
559+ writel(0x08, MCF_RTC_OCEN);
560+#endif
561+ writeb(4, MCFSIM_ICR_RTC);
562+
563+ writel(MCF_RTC_IER_1HZ, MCF_RTC_IER); /* Unmask the 1Hz timer */
564+
565+ writel(MCF_RTC_CR_EN, MCF_RTC_CR);
566+ if ((readl(MCF_RTC_CR) & MCF_RTC_CR_EN) == 0) {
567+ printk(KERN_ALERT "RTC Hardware couldn't be enabled!\n");
568+ return -EPERM;
569+ }
570+
571+ printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
572+ return ret;
573+}
574+
575+static int __devexit mcf_rtc_remove(struct platform_device *pdev)
576+{
577+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
578+
579+ rtc_device_unregister(pdata->rtc);
580+ if (pdata->irq >= 0)
581+ free_irq(pdata->irq, pdev);
582+ kfree(pdata);
583+ mcf_rtc_release(NULL);
584+ return 0;
585+}
586+
587+/*!
588+ * Contains pointers to the power management callback functions.
589+ */
590+MODULE_ALIAS("mcf-rtc");
591+static struct platform_driver mcf_rtc_driver = {
592+ .driver = {
593+ .name = "mcf-rtc",
594+ .owner = THIS_MODULE,
595+ },
596+ .probe = mcf_rtc_probe,
597+ .remove = __devexit_p(mcf_rtc_remove),
598+};
599+
600+/*!
601+ * This function creates the /proc/driver/rtc file and registers the device RTC
602+ * in the /dev/misc directory. It also reads the RTC value from external source
603+ * and setup the internal RTC properly.
604+ *
605+ * @return -1 if RTC is failed to initialize; 0 is successful.
606+ */
607+static int __init mcf_rtc_init(void)
608+{
609+ return platform_driver_register(&mcf_rtc_driver);
610+}
611+
612+/*!
613+ * This function removes the /proc/driver/rtc file and un-registers the
614+ * device RTC from the /dev/misc directory.
615+ */
616+static void __exit mcf_rtc_exit(void)
617+{
618+ platform_driver_unregister(&mcf_rtc_driver);
619+
620+}
621+
622+module_init(mcf_rtc_init);
623+module_exit(mcf_rtc_exit);
624+
625+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
626+MODULE_DESCRIPTION("Real Time Clock Driver (MCF)");
627+MODULE_LICENSE("GPL");
628

Archive Download this file



interactive