diff options
Diffstat (limited to 'target/linux/coldfire/patches/027-Add-RTC-driver-support-on-MCF5441x-platform.patch')
-rw-r--r-- | target/linux/coldfire/patches/027-Add-RTC-driver-support-on-MCF5441x-platform.patch | 681 |
1 files changed, 0 insertions, 681 deletions
diff --git a/target/linux/coldfire/patches/027-Add-RTC-driver-support-on-MCF5441x-platform.patch b/target/linux/coldfire/patches/027-Add-RTC-driver-support-on-MCF5441x-platform.patch deleted file mode 100644 index 78ae75d..0000000 --- a/target/linux/coldfire/patches/027-Add-RTC-driver-support-on-MCF5441x-platform.patch +++ /dev/null @@ -1,681 +0,0 @@ -From 6462d09dad154b69ea6180c0acb2d009627ff1be Mon Sep 17 00:00:00 2001 -From: Alison Wang <b18965@freescale.com> -Date: Thu, 4 Aug 2011 09:59:46 +0800 -Subject: [PATCH 27/52] Add RTC driver support on MCF5441x platform - -Support on-chip robust-RTC module on MCF5441x platform. - -Signed-off-by: Alison Wang <b18965@freescale.com> ---- - drivers/rtc/Kconfig | 9 + - drivers/rtc/Makefile | 1 + - drivers/rtc/rtc-m5441x.c | 638 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 648 insertions(+), 0 deletions(-) - create mode 100644 drivers/rtc/rtc-m5441x.c - ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -928,6 +928,15 @@ config RTC_MCF - - If you build it as a module it will be call mcf-rtc. - -+config RTC_M5441X -+ tristate "Freescale Coldfire M5441X platform Real Time Clock" -+ depends on COLDFIRE -+ help -+ If you say yes here you will get support for the on-chip Coldfire -+ Real-Time Clock for mcf5441x platform. -+ -+ If you build it as a module it will be call rtc-m5441x. -+ - config RTC_DRV_PS3 - tristate "PS3 RTC" - depends on PPC_PS3 ---- a/drivers/rtc/Makefile -+++ b/drivers/rtc/Makefile -@@ -103,3 +103,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm83 - obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o - obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o - obj-$(CONFIG_RTC_MCF) += rtc-mcf.o -+obj-$(CONFIG_RTC_M5441X) += rtc-m5441x.o ---- /dev/null -+++ b/drivers/rtc/rtc-m5441x.c -@@ -0,0 +1,638 @@ -+/* -+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * -+ * Lanttor.Guo@freescale.com -+ * -+ * The code contained herein is licensed under the GNU General Public -+ * License. You may obtain a copy of the GNU General Public License -+ * Version 2 or later at the following locations: -+ * -+ * http://www.opensource.org/licenses/gpl-license.html -+ * http://www.gnu.org/copyleft/gpl.html -+ */ -+ -+/* -+ * Implementation based on rtc-mcf.c -+ */ -+ -+/* -+ * RTC Real Time Clock (RTC) Driver -+ * -+ * @file rtc-m5441x.c -+ * @brief Real Time Clock interface -+ * -+ * This file contains Real Time Clock interface for Linux. -+ * -+ */ -+#include <linux/rtc.h> -+#include <linux/module.h> -+#include <linux/fs.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+#include <linux/clk.h> -+#include <linux/uaccess.h> -+#include <asm/mcfsim.h> -+#include <linux/slab.h> -+#include <linux/io.h> -+ -+#ifdef readw -+#undef readw -+#endif -+ -+#ifdef writew -+#undef writew -+#endif -+ -+#define readw(addr) in_be16(addr) -+#define writew(val, addr) out_be16((addr), (val)) -+ -+ -+#define PIT_ALL_ON (MCF_RTC_ISR_2HZ | MCF_RTC_ISR_SAM0 | MCF_RTC_ISR_SAM1 | \ -+ MCF_RTC_ISR_SAM2 | MCF_RTC_ISR_SAM3 | MCF_RTC_ISR_SAM4 | \ -+ MCF_RTC_ISR_SAM5 | MCF_RTC_ISR_SAM6 | MCF_RTC_ISR_SAM7) -+ -+#define MAX_PIE_NUM 9 -+#define MAX_PIE_FREQ 512 -+const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { -+ {2, MCF_RTC_ISR_2HZ}, -+ {4, MCF_RTC_ISR_SAM0}, -+ {8, MCF_RTC_ISR_SAM1}, -+ {16, MCF_RTC_ISR_SAM2}, -+ {32, MCF_RTC_ISR_SAM3}, -+ {64, MCF_RTC_ISR_SAM4}, -+ {128, MCF_RTC_ISR_SAM5}, -+ {256, MCF_RTC_ISR_SAM6}, -+ {MAX_PIE_FREQ, MCF_RTC_ISR_SAM7}, -+}; -+ -+/* Those are the bits from a classic RTC we want to mimic */ -+#define RTC_IRQF 0x80 /* any of the following 3 is active */ -+#define RTC_PF 0x40 /* Periodic interrupt */ -+#define RTC_AF 0x20 /* Alarm interrupt */ -+#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */ -+ -+#define MCF_RTC_TIME 0 -+#define MCF_RTC_ALARM 1 -+ -+struct rtc_plat_data { -+ struct rtc_device *rtc; -+ int irq; -+ unsigned int irqen; -+ int alrm_sec; -+ int alrm_min; -+ int alrm_hour; -+ int alrm_mday; -+}; -+ -+static const int year_cal_basic = 2112; -+ -+#define RTC_VERSION "0.1" -+ -+static u32 rtc_freq = 2; /* minimun value for PIE */ -+static unsigned long rtc_status; -+ -+static struct rtc_time g_rtc_alarm = { -+ .tm_year = 0, -+ .tm_mon = 0, -+ .tm_mday = 0, -+ .tm_hour = 0, -+ .tm_mon = 0, -+ .tm_sec = 0, -+}; -+ -+static DEFINE_SPINLOCK(rtc_lock); -+ -+ -+/* -+ * This funciton is used to disable RTC register write protection -+ */ -+static void disable_register_write_protection(void) -+{ -+ if (readw(MCF_RTC_SR) & MCF_RTC_SR_WPE) { -+ writew(0x0000, MCF_RTC_CR); -+ writew(0x0001, MCF_RTC_CR); -+ writew(0x0003, MCF_RTC_CR); -+ writew(0x0002, MCF_RTC_CR); -+ } -+ -+} -+ -+/* -+ * This function is used to obtain the RTC time or the alarm value in -+ * second. -+ * -+ * @param time_alarm use MCF_RTC_TIME for RTC time value; -+ * MCF_RTC_ALARM for alarm value -+ * -+ * @return The RTC time or alarm time in second. -+ */ -+static u32 get_alarm_or_time(struct device *dev, int time_alarm, -+ struct rtc_time *tm) -+{ -+ dev_dbg(dev, "debug function %s()!\n", __func__); -+ -+ if (time_alarm == MCF_RTC_TIME) { -+ /*check register information */ -+ dev_dbg(dev, "RTC_YEARMON:0x%x,RTC_DAYS:0x%x,RTC_HOURMIN:0x%x," -+ "RTC_SECONDS:0x%x\n", readw(MCF_RTC_YEARMON), -+ readw(MCF_RTC_DAYS), readw(MCF_RTC_HOURMIN), -+ readw(MCF_RTC_SECONDS)); -+ -+ /* get year */ -+ tm->tm_year = year_cal_basic + -+ (char)(MCF_RTC_YEARMON_YEAR_RD(readw(MCF_RTC_YEARMON))); -+ /* get month */ -+ tm->tm_mon = -+ MCF_RTC_YEARMON_MON_RD(readw(MCF_RTC_YEARMON)) - 1; -+ /* get month day */ -+ tm->tm_mday = MCF_RTC_DAYS_DAY_RD(readw(MCF_RTC_DAYS)); -+ /* get year day */ -+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, -+ tm->tm_year); -+ /* year minus 1900 */ -+ tm->tm_year = tm->tm_year - 1900; -+ /* get week day */ -+ tm->tm_wday = MCF_RTC_DAYS_DAYWEEK_RD(readw(MCF_RTC_DAYS)); -+ /* get hours */ -+ tm->tm_hour = -+ MCF_RTC_HOURMIN_HOURS_RD(readw(MCF_RTC_HOURMIN)); -+ /* get minutes */ -+ tm->tm_min = -+ MCF_RTC_HOURMIN_MINUTES_RD(readw(MCF_RTC_HOURMIN)); -+ /* get seconds */ -+ tm->tm_sec = -+ MCF_RTC_SECONDS_SECONDS_RD(readw(MCF_RTC_SECONDS)); -+ /* no day saving time */ -+ tm->tm_isdst = -1; -+ -+ /* check rtc_tm fileds information */ -+ dev_dbg(dev, "RTC TIME --> year:%d,yday:%d,mon:%d,mday:%d," -+ "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year, -+ tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday, -+ tm->tm_hour, tm->tm_min, tm->tm_sec); -+ -+ } else if (time_alarm == MCF_RTC_ALARM) { -+ tm->tm_year = year_cal_basic + -+ (char)MCF_RTC_YEARMON_YEAR_RD -+ (readw(MCF_RTC_ALRM_YRMON)); -+ tm->tm_mon = -+ MCF_RTC_YEARMON_MON_RD(readw(MCF_RTC_ALRM_YRMON)) - 1; -+ tm->tm_mday = MCF_RTC_DAYS_DAY_RD(readw(MCF_RTC_ALRM_DAYS)); -+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, -+ tm->tm_year); -+ tm->tm_year = tm->tm_year - 1900; -+ tm->tm_wday = -+ MCF_RTC_DAYS_DAYWEEK_RD(readw(MCF_RTC_ALRM_DAYS)); -+ tm->tm_hour = -+ MCF_RTC_HOURMIN_HOURS_RD(readw(MCF_RTC_ALRM_HM)); -+ tm->tm_min = -+ MCF_RTC_HOURMIN_MINUTES_RD(readw(MCF_RTC_ALRM_HM)); -+ tm->tm_sec = -+ MCF_RTC_SECONDS_SECONDS_RD(readw(MCF_RTC_ALRM_SEC)); -+ tm->tm_isdst = -1; -+ -+ /* debug information */ -+ dev_dbg(dev, "RTC ALARM --> year:%d,yday:%d,mon:%d,mday:%d," -+ "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year, -+ tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday, -+ tm->tm_hour, tm->tm_min, tm->tm_sec); -+ -+ } else { -+ panic("wrong value for time_alarm=%d\n", time_alarm); -+ } -+ -+ return 0; -+} -+ -+/* -+ * This function sets the RTC alarm value or the time value. -+ * -+ * @param time_alarm the new alarm value to be updated in the RTC -+ * @param time use MCF_RTC_TIME for RTC time value; -+ * MCF_RTC_ALARM for alarm value -+ */ -+static void set_alarm_or_time(struct device *dev, int time_alarm, -+ struct rtc_time *tm) -+{ -+ char year; -+ -+ dev_dbg(dev, "debug function %s()!\n", __func__); -+ -+ /* wirte enable setting */ -+ disable_register_write_protection(); -+ -+ if (time_alarm == MCF_RTC_TIME) { -+ /* check rtc_time fields information */ -+ dev_dbg(dev, "RTC TIME --> year:%d,yday:%d,mon:%d,mday:%d," -+ "wday:%d,hour:%d,min:%d,sec:%d\n", tm->tm_year, -+ tm->tm_yday, tm->tm_mon, tm->tm_mday, tm->tm_wday, -+ tm->tm_hour, tm->tm_min, tm->tm_sec); -+ -+ year = ((tm->tm_year + 1900) - year_cal_basic); -+ /* write RTC_YEARMON register */ -+ writew((year << 8) | (tm->tm_mon + 1), MCF_RTC_YEARMON); -+ -+ /* write RTC_DAYS register */ -+ writew(MCF_RTC_DAYS_DAYWEEK_SET(tm->tm_wday) | -+ MCF_RTC_DAYS_DAY_SET(tm->tm_mday), MCF_RTC_DAYS); -+ -+ /* write RTC_HOURMIN register */ -+ writew(MCF_RTC_HOURMIN_HOURS_SET(tm->tm_hour) | -+ MCF_RTC_HOURMIN_MINUTES_SET(tm->tm_min), -+ MCF_RTC_HOURMIN); -+ -+ /* write RTC_SECONDS register */ -+ writew(MCF_RTC_SECONDS_SECONDS_SET -+ (tm->tm_sec), MCF_RTC_SECONDS); -+ -+ /* debug information */ -+ dev_dbg(dev, "RTC_YEARMON:0x%x, RTC_DAYS:0x%x, " -+ "RTC_HOURMIN:0x%x, RTC_SECONDS:0x%x\n", -+ readw(MCF_RTC_YEARMON), readw(MCF_RTC_DAYS), -+ readw(MCF_RTC_HOURMIN), readw(MCF_RTC_SECONDS)); -+ } else if (time_alarm == MCF_RTC_ALARM) { -+ -+ year = ((tm->tm_year + 1900) - year_cal_basic); -+ /* write RTC_YEARMON register */ -+ writew((year << 8) | (tm->tm_mon + 1), MCF_RTC_ALRM_YRMON); -+ -+ /* write RTC_DAYS register */ -+ writew(MCF_RTC_DAYS_DAYWEEK_SET(tm->tm_wday) | -+ MCF_RTC_DAYS_DAY_SET(tm->tm_mday), MCF_RTC_ALRM_DAYS); -+ -+ /* write RTC_HOURMIN register */ -+ writew(MCF_RTC_HOURMIN_HOURS_SET(tm->tm_hour) | -+ MCF_RTC_HOURMIN_MINUTES_SET(tm->tm_min), -+ MCF_RTC_ALRM_HM); -+ -+ /* write RTC_SECONDS register */ -+ writew(MCF_RTC_SECONDS_SECONDS_SET -+ (tm->tm_sec), MCF_RTC_ALRM_SEC); -+ -+ /* debug information */ -+ dev_dbg(dev, "ALRM_YRMON:0x%x,ALRM_DAYS:0x%x,ALRM_HM:0x%x," -+ "ALRM_SEC:0x%x\n", readw(MCF_RTC_ALRM_YRMON), -+ readw(MCF_RTC_ALRM_DAYS), readw(MCF_RTC_ALRM_HM), -+ readw(MCF_RTC_ALRM_SEC)); -+ } else { -+ panic("wrong value for time_alarm=%d\n", time_alarm); -+ } -+} -+ -+/*! -+ * This function updates the RTC alarm registers and then clears all the -+ * interrupt status bits. -+ * -+ * @param alrm the new alarm value to be updated in the RTC -+ * -+ * @return 0 if successful; non-zero otherwise. -+ */ -+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm) -+{ -+ /* clear all the interrupt status bits */ -+ disable_register_write_protection(); -+ -+ writew(readw(MCF_RTC_ISR), MCF_RTC_ISR); -+ -+ set_alarm_or_time(dev, MCF_RTC_ALARM, alrm); -+ -+ return 0; -+} -+ -+/*! -+ * This function is the RTC interrupt service routine. -+ * -+ * @param irq RTC IRQ number -+ * @param dev_id device ID which is not used -+ * -+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file. -+ */ -+static irqreturn_t mcf_rtc_interrupt(int irq, void *dev_id) -+{ -+ struct platform_device *pdev = dev_id; -+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev); -+ u16 status = 0; -+ u32 events = 0; -+ -+ spin_lock(&rtc_lock); -+ -+ /* clear interrupt sources */ -+ status = readw(MCF_RTC_ISR) & readw(MCF_RTC_IER); -+ -+ disable_register_write_protection(); -+ -+ writew(status, MCF_RTC_ISR); -+ -+ /* clear alarm interrupt if it has occurred */ -+ if (status & MCF_RTC_ISR_ALM) -+ status &= ~MCF_RTC_ISR_ALM; -+ -+ /* update irq data & counter */ -+ if (status & MCF_RTC_ISR_ALM) -+ events |= (RTC_AF | RTC_IRQF); -+ if (status & MCF_RTC_ISR_1HZ) -+ events |= (RTC_UF | RTC_IRQF); -+ if (status & PIT_ALL_ON) -+ events |= (RTC_PF | RTC_IRQF); -+ -+ if ((status & MCF_RTC_ISR_ALM) && rtc_valid_tm(&g_rtc_alarm)) -+ rtc_update_alarm(&pdev->dev, &g_rtc_alarm); -+ -+ spin_unlock(&rtc_lock); -+ rtc_update_irq(pdata->rtc, 1, events); -+ return IRQ_HANDLED; -+} -+ -+/*! -+ * clear all interrupts and release the IRQ -+ */ -+static void mcf_rtc_release(struct device *dev) -+{ -+ spin_lock_irq(&rtc_lock); -+ -+ disable_register_write_protection(); -+ -+ writew(0, MCF_RTC_IER); /* Disable all rtc interrupts */ -+ writew(readw(MCF_RTC_ISR), MCF_RTC_ISR); -+ spin_unlock_irq(&rtc_lock); -+ rtc_status = 0; -+} -+ -+/*! -+ * This function is used to support some ioctl calls directly. -+ * Other ioctl calls are supported indirectly through the -+ * arm/common/rtctime.c file. -+ * -+ * @param cmd ioctl command as defined in include/linux/rtc.h -+ * @param arg value for the ioctl command -+ * -+ * @return 0 if successful or negative value otherwise. -+ */ -+static int mcf_rtc_ioctl(struct device *dev, unsigned int cmd, -+ unsigned long arg) -+{ -+ int i; -+ -+ disable_register_write_protection(); -+ -+ switch (cmd) { -+ case RTC_PIE_OFF: -+ writew((readw(MCF_RTC_IER) & ~PIT_ALL_ON), MCF_RTC_IER); -+ return 0; -+ case RTC_IRQP_SET: -+ if (arg < 2 || arg > MAX_PIE_FREQ || (arg % 2) != 0) -+ return -EINVAL; /* Also make sure a power of 2Hz */ -+ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) -+ return -EACCES; -+ rtc_freq = arg; -+ return 0; -+ case RTC_IRQP_READ: -+ return put_user(rtc_freq, (u32 *) arg); -+ case RTC_PIE_ON: -+ for (i = 0; i < MAX_PIE_NUM; i++) { -+ if (PIE_BIT_DEF[i][0] == rtc_freq) -+ break; -+ } -+ if (i == MAX_PIE_NUM) -+ return -EACCES; -+ spin_lock_irq(&rtc_lock); -+ writew((readw(MCF_RTC_IER) | PIE_BIT_DEF[i][1]), MCF_RTC_IER); -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_AIE_OFF: -+ spin_lock_irq(&rtc_lock); -+ writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), MCF_RTC_IER); -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ -+ case RTC_AIE_ON: -+ spin_lock_irq(&rtc_lock); -+ writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM), MCF_RTC_IER); -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ -+ case RTC_UIE_OFF: /* UIE is for the 1Hz interrupt */ -+ spin_lock_irq(&rtc_lock); -+ writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_1HZ), MCF_RTC_IER); -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ -+ case RTC_UIE_ON: -+ spin_lock_irq(&rtc_lock); -+ writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_1HZ), MCF_RTC_IER); -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ } -+ return -ENOIOCTLCMD; -+} -+ -+/*! -+ * This function reads the current RTC time into tm in Gregorian date. -+ * -+ * @param tm contains the RTC time value upon return -+ * -+ * @return 0 if successful; non-zero otherwise. -+ */ -+static int mcf_rtc_read_time(struct device *dev, struct rtc_time *tm) -+{ -+ do { -+ get_alarm_or_time(dev, MCF_RTC_TIME, tm); -+ } while (0); -+ -+ return 0; -+} -+ -+/*! -+ * This function sets the internal RTC time based on tm in Gregorian date. -+ * -+ * @param tm the time value to be set in the RTC -+ * -+ * @return 0 if successful; non-zero otherwise. -+ */ -+static int mcf_rtc_set_time(struct device *dev, struct rtc_time *tm) -+{ -+ do { -+ set_alarm_or_time(dev, MCF_RTC_TIME, tm); -+ } while (0); -+ -+ return 0; -+} -+ -+/*! -+ * This function reads the current alarm value into the passed in \b alrm -+ * argument. It updates the \b alrm's pending field value based on the whether -+ * an alarm interrupt occurs or not. -+ * -+ * @param alrm contains the RTC alarm value upon return -+ * -+ * @return 0 if successful; non-zero otherwise. -+ */ -+static int mcf_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -+{ -+ do { -+ get_alarm_or_time(dev, MCF_RTC_ALARM, &alrm->time); -+ } while (0); -+ -+ alrm->pending = ((readw(MCF_RTC_ISR) & MCF_RTC_ISR_ALM) != 0) ? 1 : 0; -+ -+ return 0; -+} -+ -+/*! -+ * This function sets the RTC alarm based on passed in alrm. -+ * -+ * @param alrm the alarm value to be set in the RTC -+ * -+ * @return 0 if successful; non-zero otherwise. -+ */ -+static int mcf_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -+{ -+ int ret; -+ -+ spin_lock_irq(&rtc_lock); -+ -+ disable_register_write_protection(); -+ -+ if (rtc_valid_tm(&alrm->time)) { -+ if (alrm->time.tm_sec > 59 || -+ alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) { -+ ret = -EINVAL; -+ goto out; -+ } -+ ret = rtc_update_alarm(dev, &alrm->time); -+ } else { -+ ret = rtc_valid_tm(&alrm->time); -+ if (ret) -+ goto out; -+ ret = rtc_update_alarm(dev, &alrm->time); -+ } -+ -+ if (ret == 0) { -+ memcpy(&g_rtc_alarm, &alrm->time, sizeof(struct rtc_time)); -+ -+ if (alrm->enabled) { -+ writew((readw(MCF_RTC_IER) | MCF_RTC_ISR_ALM), -+ MCF_RTC_IER); -+ } else { -+ writew((readw(MCF_RTC_IER) & ~MCF_RTC_ISR_ALM), -+ MCF_RTC_IER); -+ } -+ } -+out: -+ spin_unlock_irq(&rtc_lock); -+ -+ return ret; -+} -+ -+/*! -+ * The RTC driver structure -+ */ -+static struct rtc_class_ops mcf_rtc_ops = { -+ .ioctl = mcf_rtc_ioctl, -+ .read_time = mcf_rtc_read_time, -+ .set_time = mcf_rtc_set_time, -+ .read_alarm = mcf_rtc_read_alarm, -+ .set_alarm = mcf_rtc_set_alarm, -+}; -+ -+static int __devinit mcf_rtc_probe(struct platform_device *pdev) -+{ -+ struct rtc_device *rtc; -+ struct rtc_plat_data *pdata = NULL; -+ u32 ret = 0; -+ -+ disable_register_write_protection(); -+ /* Clear interrupt before request irq */ -+ writew(0x0100, MCF_RTC_CR); -+ writew(0x0001, MCF_RTC_IER); -+ -+ if (!(readw(MCF_RTC_CFG_DATA) & MCF_RTC_CFG_DATA_OSCEN)) -+ writew(MCF_RTC_CFG_DATA_OSCEN, MCF_RTC_CFG_DATA); -+ -+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); -+ if (!pdata) -+ return -ENOMEM; -+ -+ pdata->irq = MCFINT_VECBASE + MCFINT_RTC; -+ if (request_irq(pdata->irq, mcf_rtc_interrupt, IRQF_DISABLED, -+ pdev->name, pdev) < 0) { -+ dev_warn(&pdev->dev, "interrupt not available.\n"); -+ pdata->irq = -1; -+ } -+ -+ if (test_and_set_bit(1, &rtc_status)) -+ return -EBUSY; -+ -+ rtc = rtc_device_register(pdev->name, &pdev->dev, &mcf_rtc_ops, -+ THIS_MODULE); -+ if (IS_ERR(rtc)) { -+ ret = PTR_ERR(rtc); -+ if (pdata->irq >= 0) -+ free_irq(pdata->irq, pdev); -+ kfree(pdata); -+ return ret; -+ } -+ pdata->rtc = rtc; -+ platform_set_drvdata(pdev, pdata); -+ -+ dev_dbg(&pdev->dev, "RTC_CR:0x%x, RTC_SR:0x%x\n", readw(MCF_RTC_CR), -+ readw(MCF_RTC_SR)); -+ -+ printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); -+ return ret; -+} -+ -+static int __devexit mcf_rtc_remove(struct platform_device *pdev) -+{ -+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev); -+ -+ rtc_device_unregister(pdata->rtc); -+ if (pdata->irq >= 0) -+ free_irq(pdata->irq, pdev); -+ kfree(pdata); -+ mcf_rtc_release(NULL); -+ return 0; -+} -+ -+/*! -+ * Contains pointers to the power management callback functions. -+ */ -+MODULE_ALIAS("rtc-m5441x"); -+static struct platform_driver mcf_rtc_driver = { -+ .driver = { -+ .name = "rtc-m5441x", -+ .owner = THIS_MODULE, -+ }, -+ .probe = mcf_rtc_probe, -+ .remove = __devexit_p(mcf_rtc_remove), -+}; -+ -+/*! -+ * This function creates the /proc/driver/rtc file and registers the device RTC -+ * in the /dev/misc directory. It also reads the RTC value from external source -+ * and setup the internal RTC properly. -+ * -+ * @return -1 if RTC is failed to initialize; 0 is successful. -+ */ -+static int __init mcf_rtc_init(void) -+{ -+ return platform_driver_register(&mcf_rtc_driver); -+} -+ -+/*! -+ * This function removes the /proc/driver/rtc file and un-registers the -+ * device RTC from the /dev/misc directory. -+ */ -+static void __exit mcf_rtc_exit(void) -+{ -+ platform_driver_unregister(&mcf_rtc_driver); -+ -+} -+ -+module_init(mcf_rtc_init); -+module_exit(mcf_rtc_exit); -+ -+MODULE_AUTHOR("Freescale Semiconductor, Inc."); -+MODULE_DESCRIPTION("Real Time Clock Driver (MCF)"); -+MODULE_LICENSE("GPL V2"); |