aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/rtc
diff options
context:
space:
mode:
authorMichal Marek <mmarek@suse.cz>2010-08-04 13:59:13 +0200
committerMichal Marek <mmarek@suse.cz>2010-08-04 13:59:13 +0200
commit772320e84588dcbe1600ffb83e5f328f2209ac2a (patch)
treea7de21b79340aeaa17c58126f6b801b82c77b53a /drivers/rtc
parentmodpost: support objects with more than 64k sections (diff)
parentLinux 2.6.35 (diff)
downloadwireguard-linux-772320e84588dcbe1600ffb83e5f328f2209ac2a.tar.xz
wireguard-linux-772320e84588dcbe1600ffb83e5f328f2209ac2a.zip
Merge commit 'v2.6.35' into kbuild/kbuild
Conflicts: arch/powerpc/Makefile
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig39
-rw-r--r--drivers/rtc/Makefile4
-rw-r--r--drivers/rtc/class.c2
-rw-r--r--drivers/rtc/hctosys.c59
-rw-r--r--drivers/rtc/rtc-ab3100.c41
-rw-r--r--drivers/rtc/rtc-ab8500.c363
-rw-r--r--drivers/rtc/rtc-at32ap700x.c1
-rw-r--r--drivers/rtc/rtc-at91sam9.c3
-rw-r--r--drivers/rtc/rtc-bfin.c1
-rw-r--r--drivers/rtc/rtc-bq4802.c1
-rw-r--r--drivers/rtc/rtc-cmos.c94
-rw-r--r--drivers/rtc/rtc-coh901331.c6
-rw-r--r--drivers/rtc/rtc-davinci.c674
-rw-r--r--drivers/rtc/rtc-ds1216.c1
-rw-r--r--drivers/rtc/rtc-ds1286.c1
-rw-r--r--drivers/rtc/rtc-ds1302.c85
-rw-r--r--drivers/rtc/rtc-ds1305.c7
-rw-r--r--drivers/rtc/rtc-ds1307.c10
-rw-r--r--drivers/rtc/rtc-ds1374.c3
-rw-r--r--drivers/rtc/rtc-ds1390.c1
-rw-r--r--drivers/rtc/rtc-ds1511.c11
-rw-r--r--drivers/rtc/rtc-ds1553.c5
-rw-r--r--drivers/rtc/rtc-ds1742.c6
-rw-r--r--drivers/rtc/rtc-ep93xx.c72
-rw-r--r--drivers/rtc/rtc-fm3130.c7
-rw-r--r--drivers/rtc/rtc-isl1208.c45
-rw-r--r--drivers/rtc/rtc-m41t80.c22
-rw-r--r--drivers/rtc/rtc-m48t35.c1
-rw-r--r--drivers/rtc/rtc-m48t59.c5
-rw-r--r--drivers/rtc/rtc-max8925.c315
-rw-r--r--drivers/rtc/rtc-mc13783.c230
-rw-r--r--drivers/rtc/rtc-mpc5121.c390
-rw-r--r--drivers/rtc/rtc-msm6242.c1
-rw-r--r--drivers/rtc/rtc-mv.c1
-rw-r--r--drivers/rtc/rtc-mxc.c53
-rw-r--r--drivers/rtc/rtc-nuc900.c1
-rw-r--r--drivers/rtc/rtc-pcap.c1
-rw-r--r--drivers/rtc/rtc-pcf2123.c3
-rw-r--r--drivers/rtc/rtc-pcf50633.c1
-rw-r--r--drivers/rtc/rtc-pcf8563.c1
-rw-r--r--drivers/rtc/rtc-pl030.c1
-rw-r--r--drivers/rtc/rtc-pl031.c366
-rw-r--r--drivers/rtc/rtc-pxa.c1
-rw-r--r--drivers/rtc/rtc-rp5c01.c1
-rw-r--r--drivers/rtc/rtc-rs5c348.c1
-rw-r--r--drivers/rtc/rtc-rs5c372.c1
-rw-r--r--drivers/rtc/rtc-rx8025.c3
-rw-r--r--drivers/rtc/rtc-rx8581.c26
-rw-r--r--drivers/rtc/rtc-s35390a.c2
-rw-r--r--drivers/rtc/rtc-s3c.c113
-rw-r--r--drivers/rtc/rtc-sh.c1
-rw-r--r--drivers/rtc/rtc-stk17ta8.c9
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c1
-rw-r--r--drivers/rtc/rtc-sysfs.c5
-rw-r--r--drivers/rtc/rtc-twl.c4
-rw-r--r--drivers/rtc/rtc-tx4939.c5
-rw-r--r--drivers/rtc/rtc-v3020.c1
-rw-r--r--drivers/rtc/rtc-wm831x.c17
-rw-r--r--drivers/rtc/rtc-wm8350.c11
59 files changed, 2762 insertions, 374 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8167e9e6827a..10ba12c8c5e0 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -175,6 +175,16 @@ config RTC_DRV_MAX6900
This driver can also be built as a module. If so, the module
will be called rtc-max6900.
+config RTC_DRV_MAX8925
+ tristate "Maxim MAX8925"
+ depends on MFD_MAX8925
+ help
+ If you say yes here you will get support for the
+ RTC of Maxim MAX8925 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max8925.
+
config RTC_DRV_RS5C372
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
help
@@ -601,6 +611,13 @@ config RTC_DRV_AB3100
Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC
support. This chip contains a battery- and capacitor-backed RTC.
+config RTC_DRV_AB8500
+ tristate "ST-Ericsson AB8500 RTC"
+ depends on AB8500_CORE
+ help
+ Select this to enable the ST-Ericsson AB8500 power management IC RTC
+ support. This chip contains a battery- and capacitor-backed RTC.
+
config RTC_DRV_NUC900
tristate "NUC910/NUC920 RTC driver"
depends on RTC_CLASS && ARCH_W90X900
@@ -610,6 +627,16 @@ config RTC_DRV_NUC900
comment "on-CPU RTC drivers"
+config RTC_DRV_DAVINCI
+ tristate "TI DaVinci RTC"
+ depends on ARCH_DAVINCI_DM365
+ help
+ If you say yes here you get support for the RTC on the
+ DaVinci platforms (DM365).
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-davinci.
+
config RTC_DRV_OMAP
tristate "TI OMAP1"
depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX
@@ -620,7 +647,7 @@ config RTC_DRV_OMAP
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
- depends on ARCH_S3C2410
+ depends on ARCH_S3C2410 || ARCH_S3C64XX
help
RTC (Realtime Clock) driver for the clock inbuilt into the
Samsung S3C24XX series of SoCs. This can provide periodic
@@ -868,4 +895,14 @@ config RTC_DRV_MC13783
help
This enables support for the Freescale MC13783 PMIC RTC
+config RTC_DRV_MPC5121
+ tristate "Freescale MPC5121 built-in RTC"
+ depends on PPC_MPC512x && RTC_CLASS
+ help
+ If you say yes here you will get support for the
+ built-in RTC MPC5121.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-mpc5121.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index e5160fddc446..5adbba7cf89c 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -18,6 +18,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
# Keep the list ordered.
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
+obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
@@ -52,9 +54,11 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
+obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
+obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index be5a6b73e601..565562ba6ac9 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -15,6 +15,7 @@
#include <linux/rtc.h>
#include <linux/kdev_t.h>
#include <linux/idr.h>
+#include <linux/slab.h>
#include "rtc-core.h"
@@ -226,6 +227,7 @@ static void __exit rtc_exit(void)
{
rtc_dev_exit();
class_destroy(rtc_class);
+ idr_destroy(&rtc_idr);
}
subsys_initcall(rtc_init);
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index 33c0e98243ee..bc90b091f195 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -22,48 +22,57 @@
* the best guess is to add 0.5s.
*/
+int rtc_hctosys_ret = -ENODEV;
+
static int __init rtc_hctosys(void)
{
- int err;
+ int err = -ENODEV;
struct rtc_time tm;
+ struct timespec tv = {
+ .tv_nsec = NSEC_PER_SEC >> 1,
+ };
struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
if (rtc == NULL) {
- printk("%s: unable to open rtc device (%s)\n",
+ pr_err("%s: unable to open rtc device (%s)\n",
__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
- return -ENODEV;
+ goto err_open;
}
err = rtc_read_time(rtc, &tm);
- if (err == 0) {
- err = rtc_valid_tm(&tm);
- if (err == 0) {
- struct timespec tv;
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: unable to read the hardware clock\n");
+ goto err_read;
- tv.tv_nsec = NSEC_PER_SEC >> 1;
+ }
- rtc_tm_to_time(&tm, &tv.tv_sec);
+ err = rtc_valid_tm(&tm);
+ if (err) {
+ dev_err(rtc->dev.parent,
+ "hctosys: invalid date/time\n");
+ goto err_invalid;
+ }
- do_settimeofday(&tv);
+ rtc_tm_to_time(&tm, &tv.tv_sec);
- dev_info(rtc->dev.parent,
- "setting system clock to "
- "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec,
- (unsigned int) tv.tv_sec);
- }
- else
- dev_err(rtc->dev.parent,
- "hctosys: invalid date/time\n");
- }
- else
- dev_err(rtc->dev.parent,
- "hctosys: unable to read the hardware clock\n");
+ do_settimeofday(&tv);
+ dev_info(rtc->dev.parent,
+ "setting system clock to "
+ "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (unsigned int) tv.tv_sec);
+
+err_invalid:
+err_read:
rtc_class_close(rtc);
- return 0;
+err_open:
+ rtc_hctosys_ret = err;
+
+ return err;
}
late_initcall(rtc_hctosys);
diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c
index 4704aac2b5af..d26780ea254b 100644
--- a/drivers/rtc/rtc-ab3100.c
+++ b/drivers/rtc/rtc-ab3100.c
@@ -9,7 +9,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
-#include <linux/mfd/ab3100.h>
+#include <linux/mfd/abx500.h>
/* Clock rate in Hz */
#define AB3100_RTC_CLOCK_RATE 32768
@@ -45,7 +45,6 @@
*/
static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs)
{
- struct ab3100 *ab3100_data = dev_get_drvdata(dev);
u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2,
AB3100_TI3, AB3100_TI4, AB3100_TI5};
unsigned char buf[6];
@@ -61,27 +60,26 @@ static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs)
buf[5] = (fat_time >> 40) & 0xFF;
for (i = 0; i < 6; i++) {
- err = ab3100_set_register_interruptible(ab3100_data,
+ err = abx500_set_register_interruptible(dev, 0,
regs[i], buf[i]);
if (err)
return err;
}
/* Set the flag to mark that the clock is now set */
- return ab3100_mask_and_set_register_interruptible(ab3100_data,
+ return abx500_mask_and_set_register_interruptible(dev, 0,
AB3100_RTC,
- 0xFE, 0x01);
+ 0x01, 0x01);
}
static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct ab3100 *ab3100_data = dev_get_drvdata(dev);
unsigned long time;
u8 rtcval;
int err;
- err = ab3100_get_register_interruptible(ab3100_data,
+ err = abx500_get_register_interruptible(dev, 0,
AB3100_RTC, &rtcval);
if (err)
return err;
@@ -94,7 +92,7 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
u8 buf[6];
/* Read out time registers */
- err = ab3100_get_register_page_interruptible(ab3100_data,
+ err = abx500_get_register_page_interruptible(dev, 0,
AB3100_TI0,
buf, 6);
if (err != 0)
@@ -114,7 +112,6 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct ab3100 *ab3100_data = dev_get_drvdata(dev);
unsigned long time;
u64 fat_time;
u8 buf[6];
@@ -122,7 +119,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
int err;
/* Figure out if alarm is enabled or not */
- err = ab3100_get_register_interruptible(ab3100_data,
+ err = abx500_get_register_interruptible(dev, 0,
AB3100_RTC, &rtcval);
if (err)
return err;
@@ -133,7 +130,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
/* No idea how this could be represented */
alarm->pending = 0;
/* Read out alarm registers, only 4 bytes */
- err = ab3100_get_register_page_interruptible(ab3100_data,
+ err = abx500_get_register_page_interruptible(dev, 0,
AB3100_AL0, buf, 4);
if (err)
return err;
@@ -148,7 +145,6 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct ab3100 *ab3100_data = dev_get_drvdata(dev);
u8 regs[] = {AB3100_AL0, AB3100_AL1, AB3100_AL2, AB3100_AL3};
unsigned char buf[4];
unsigned long secs;
@@ -165,21 +161,19 @@ static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
/* Set the alarm */
for (i = 0; i < 4; i++) {
- err = ab3100_set_register_interruptible(ab3100_data,
+ err = abx500_set_register_interruptible(dev, 0,
regs[i], buf[i]);
if (err)
return err;
}
/* Then enable the alarm */
- return ab3100_mask_and_set_register_interruptible(ab3100_data,
- AB3100_RTC, ~(1 << 2),
+ return abx500_mask_and_set_register_interruptible(dev, 0,
+ AB3100_RTC, (1 << 2),
alarm->enabled << 2);
}
static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
{
- struct ab3100 *ab3100_data = dev_get_drvdata(dev);
-
/*
* It's not possible to enable/disable the alarm IRQ for this RTC.
* It does not actually trigger any IRQ: instead its only function is
@@ -188,12 +182,12 @@ static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
* and need to be handled there instead.
*/
if (enabled)
- return ab3100_mask_and_set_register_interruptible(ab3100_data,
- AB3100_RTC, ~(1 << 2),
+ return abx500_mask_and_set_register_interruptible(dev, 0,
+ AB3100_RTC, (1 << 2),
1 << 2);
else
- return ab3100_mask_and_set_register_interruptible(ab3100_data,
- AB3100_RTC, ~(1 << 2),
+ return abx500_mask_and_set_register_interruptible(dev, 0,
+ AB3100_RTC, (1 << 2),
0);
}
@@ -210,10 +204,9 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
int err;
u8 regval;
struct rtc_device *rtc;
- struct ab3100 *ab3100_data = platform_get_drvdata(pdev);
/* The first RTC register needs special treatment */
- err = ab3100_get_register_interruptible(ab3100_data,
+ err = abx500_get_register_interruptible(&pdev->dev, 0,
AB3100_RTC, &regval);
if (err) {
dev_err(&pdev->dev, "unable to read RTC register\n");
@@ -231,7 +224,7 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
* This bit remains until RTC power is lost.
*/
regval = 1 | RTC_SETTING;
- err = ab3100_set_register_interruptible(ab3100_data,
+ err = abx500_set_register_interruptible(&pdev->dev, 0,
AB3100_RTC, regval);
/* Ignore any error on this write */
}
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
new file mode 100644
index 000000000000..2fda03125e55
--- /dev/null
+++ b/drivers/rtc/rtc-ab8500.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>
+ *
+ * RTC clock driver for the RTC part of the AB8500 Power management chip.
+ * Based on RTC clock driver for the AB3100 Analog Baseband Chip by
+ * Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/delay.h>
+
+#define AB8500_RTC_SOFF_STAT_REG 0x0F00
+#define AB8500_RTC_CC_CONF_REG 0x0F01
+#define AB8500_RTC_READ_REQ_REG 0x0F02
+#define AB8500_RTC_WATCH_TSECMID_REG 0x0F03
+#define AB8500_RTC_WATCH_TSECHI_REG 0x0F04
+#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x0F05
+#define AB8500_RTC_WATCH_TMIN_MID_REG 0x0F06
+#define AB8500_RTC_WATCH_TMIN_HI_REG 0x0F07
+#define AB8500_RTC_ALRM_MIN_LOW_REG 0x0F08
+#define AB8500_RTC_ALRM_MIN_MID_REG 0x0F09
+#define AB8500_RTC_ALRM_MIN_HI_REG 0x0F0A
+#define AB8500_RTC_STAT_REG 0x0F0B
+#define AB8500_RTC_BKUP_CHG_REG 0x0F0C
+#define AB8500_RTC_FORCE_BKUP_REG 0x0F0D
+#define AB8500_RTC_CALIB_REG 0x0F0E
+#define AB8500_RTC_SWITCH_STAT_REG 0x0F0F
+#define AB8500_REV_REG 0x1080
+
+/* RtcReadRequest bits */
+#define RTC_READ_REQUEST 0x01
+#define RTC_WRITE_REQUEST 0x02
+
+/* RtcCtrl bits */
+#define RTC_ALARM_ENA 0x04
+#define RTC_STATUS_DATA 0x01
+
+#define COUNTS_PER_SEC (0xF000 / 60)
+#define AB8500_RTC_EPOCH 2000
+
+static const unsigned long ab8500_rtc_time_regs[] = {
+ AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
+ AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG,
+ AB8500_RTC_WATCH_TSECMID_REG
+};
+
+static const unsigned long ab8500_rtc_alarm_regs[] = {
+ AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG,
+ AB8500_RTC_ALRM_MIN_LOW_REG
+};
+
+/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
+static unsigned long get_elapsed_seconds(int year)
+{
+ unsigned long secs;
+ struct rtc_time tm = {
+ .tm_year = year - 1900,
+ .tm_mday = 1,
+ };
+
+ /*
+ * This function calculates secs from 1970 and not from
+ * 1900, even if we supply the offset from year 1900.
+ */
+ rtc_tm_to_time(&tm, &secs);
+ return secs;
+}
+
+static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+ unsigned long timeout = jiffies + HZ;
+ int retval, i;
+ unsigned long mins, secs;
+ unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+
+ /* Request a data read */
+ retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG,
+ RTC_READ_REQUEST);
+ if (retval < 0)
+ return retval;
+
+ /* Early AB8500 chips will not clear the rtc read request bit */
+ if (ab8500->revision == 0) {
+ msleep(1);
+ } else {
+ /* Wait for some cycles after enabling the rtc read in ab8500 */
+ while (time_before(jiffies, timeout)) {
+ retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG);
+ if (retval < 0)
+ return retval;
+
+ if (!(retval & RTC_READ_REQUEST))
+ break;
+
+ msleep(1);
+ }
+ }
+
+ /* Read the Watchtime registers */
+ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
+ retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]);
+ if (retval < 0)
+ return retval;
+ buf[i] = retval;
+ }
+
+ mins = (buf[0] << 16) | (buf[1] << 8) | buf[2];
+
+ secs = (buf[3] << 8) | buf[4];
+ secs = secs / COUNTS_PER_SEC;
+ secs = secs + (mins * 60);
+
+ /* Add back the initially subtracted number of seconds */
+ secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+ rtc_time_to_tm(secs, tm);
+ return rtc_valid_tm(tm);
+}
+
+static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+ int retval, i;
+ unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+ unsigned long no_secs, no_mins, secs = 0;
+
+ if (tm->tm_year < (AB8500_RTC_EPOCH - 1900)) {
+ dev_dbg(dev, "year should be equal to or greater than %d\n",
+ AB8500_RTC_EPOCH);
+ return -EINVAL;
+ }
+
+ /* Get the number of seconds since 1970 */
+ rtc_tm_to_time(tm, &secs);
+
+ /*
+ * Convert it to the number of seconds since 01-01-2000 00:00:00, since
+ * we only have a small counter in the RTC.
+ */
+ secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+ no_mins = secs / 60;
+
+ no_secs = secs % 60;
+ /* Make the seconds count as per the RTC resolution */
+ no_secs = no_secs * COUNTS_PER_SEC;
+
+ buf[4] = no_secs & 0xFF;
+ buf[3] = (no_secs >> 8) & 0xFF;
+
+ buf[2] = no_mins & 0xFF;
+ buf[1] = (no_mins >> 8) & 0xFF;
+ buf[0] = (no_mins >> 16) & 0xFF;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
+ retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]);
+ if (retval < 0)
+ return retval;
+ }
+
+ /* Request a data write */
+ return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
+}
+
+static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+ int retval, i;
+ int rtc_ctrl;
+ unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
+ unsigned long secs, mins;
+
+ /* Check if the alarm is enabled or not */
+ rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
+ if (rtc_ctrl < 0)
+ return rtc_ctrl;
+
+ if (rtc_ctrl & RTC_ALARM_ENA)
+ alarm->enabled = 1;
+ else
+ alarm->enabled = 0;
+
+ alarm->pending = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
+ retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]);
+ if (retval < 0)
+ return retval;
+ buf[i] = retval;
+ }
+
+ mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
+ secs = mins * 60;
+
+ /* Add back the initially subtracted number of seconds */
+ secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+ rtc_time_to_tm(secs, &alarm->time);
+
+ return rtc_valid_tm(&alarm->time);
+}
+
+static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+
+ return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
+ enabled ? RTC_ALARM_ENA : 0);
+}
+
+static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+ int retval, i;
+ unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
+ unsigned long mins, secs = 0;
+
+ if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
+ dev_dbg(dev, "year should be equal to or greater than %d\n",
+ AB8500_RTC_EPOCH);
+ return -EINVAL;
+ }
+
+ /* Get the number of seconds since 1970 */
+ rtc_tm_to_time(&alarm->time, &secs);
+
+ /*
+ * Convert it to the number of seconds since 01-01-2000 00:00:00, since
+ * we only have a small counter in the RTC.
+ */
+ secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+ mins = secs / 60;
+
+ buf[2] = mins & 0xFF;
+ buf[1] = (mins >> 8) & 0xFF;
+ buf[0] = (mins >> 16) & 0xFF;
+
+ /* Set the alarm time */
+ for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
+ retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]);
+ if (retval < 0)
+ return retval;
+ }
+
+ return ab8500_rtc_irq_enable(dev, alarm->enabled);
+}
+
+static irqreturn_t rtc_alarm_handler(int irq, void *data)
+{
+ struct rtc_device *rtc = data;
+ unsigned long events = RTC_IRQF | RTC_AF;
+
+ dev_dbg(&rtc->dev, "%s\n", __func__);
+ rtc_update_irq(rtc, 1, events);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops ab8500_rtc_ops = {
+ .read_time = ab8500_rtc_read_time,
+ .set_time = ab8500_rtc_set_time,
+ .read_alarm = ab8500_rtc_read_alarm,
+ .set_alarm = ab8500_rtc_set_alarm,
+ .alarm_irq_enable = ab8500_rtc_irq_enable,
+};
+
+static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ int err;
+ struct rtc_device *rtc;
+ int rtc_ctrl;
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, "ALARM");
+ if (irq < 0)
+ return irq;
+
+ /* For RTC supply test */
+ err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA,
+ RTC_STATUS_DATA);
+ if (err < 0)
+ return err;
+
+ /* Wait for reset by the PorRtc */
+ msleep(1);
+
+ rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
+ if (rtc_ctrl < 0)
+ return rtc_ctrl;
+
+ /* Check if the RTC Supply fails */
+ if (!(rtc_ctrl & RTC_STATUS_DATA)) {
+ dev_err(&pdev->dev, "RTC supply failure\n");
+ return -ENODEV;
+ }
+
+ rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ dev_err(&pdev->dev, "Registration failed\n");
+ err = PTR_ERR(rtc);
+ return err;
+ }
+
+ err = request_threaded_irq(irq, NULL, rtc_alarm_handler, 0,
+ "ab8500-rtc", rtc);
+ if (err < 0) {
+ rtc_device_unregister(rtc);
+ return err;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ return 0;
+}
+
+static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ int irq = platform_get_irq_byname(pdev, "ALARM");
+
+ free_irq(irq, rtc);
+ rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_rtc_driver = {
+ .driver = {
+ .name = "ab8500-rtc",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_rtc_probe,
+ .remove = __devexit_p(ab8500_rtc_remove),
+};
+
+static int __init ab8500_rtc_init(void)
+{
+ return platform_driver_register(&ab8500_rtc_driver);
+}
+
+static void __exit ab8500_rtc_exit(void)
+{
+ platform_driver_unregister(&ab8500_rtc_driver);
+}
+
+module_init(ab8500_rtc_init);
+module_exit(ab8500_rtc_exit);
+MODULE_AUTHOR("Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>");
+MODULE_DESCRIPTION("AB8500 RTC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index 8825695777df..b2752b6e7a2f 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/io.h>
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 86c61f143515..f677e0710ca1 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -18,6 +18,7 @@
#include <linux/rtc.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
+#include <linux/slab.h>
#include <mach/board.h>
#include <mach/at91_rtt.h>
@@ -161,7 +162,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (offset == 0)
return -EILSEQ;
- memset(alrm, 0, sizeof(alrm));
+ memset(alrm, 0, sizeof(*alrm));
if (alarm != ALARM_DISABLED && offset != 0) {
rtc_time_to_tm(offset + alarm, tm);
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index b11485b9f21c..72b2bcc2c224 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -51,6 +51,7 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/seq_file.h>
+#include <linux/slab.h>
#include <asm/blackfin.h>
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
index 280fe48ada0b..128270ce355d 100644
--- a/drivers/rtc/rtc-bq4802.c
+++ b/drivers/rtc/rtc-bq4802.c
@@ -10,6 +10,7 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/slab.h>
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("TI BQ4802 RTC driver");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index e9aa814ddd23..11b8ea29d2b7 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -238,31 +238,32 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
rtc_control = CMOS_READ(RTC_CONTROL);
spin_unlock_irq(&rtc_lock);
- /* REVISIT this assumes PC style usage: always BCD */
-
- if (((unsigned)t->time.tm_sec) < 0x60)
- t->time.tm_sec = bcd2bin(t->time.tm_sec);
- else
- t->time.tm_sec = -1;
- if (((unsigned)t->time.tm_min) < 0x60)
- t->time.tm_min = bcd2bin(t->time.tm_min);
- else
- t->time.tm_min = -1;
- if (((unsigned)t->time.tm_hour) < 0x24)
- t->time.tm_hour = bcd2bin(t->time.tm_hour);
- else
- t->time.tm_hour = -1;
-
- if (cmos->day_alrm) {
- if (((unsigned)t->time.tm_mday) <= 0x31)
- t->time.tm_mday = bcd2bin(t->time.tm_mday);
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ if (((unsigned)t->time.tm_sec) < 0x60)
+ t->time.tm_sec = bcd2bin(t->time.tm_sec);
else
- t->time.tm_mday = -1;
- if (cmos->mon_alrm) {
- if (((unsigned)t->time.tm_mon) <= 0x12)
- t->time.tm_mon = bcd2bin(t->time.tm_mon) - 1;
+ t->time.tm_sec = -1;
+ if (((unsigned)t->time.tm_min) < 0x60)
+ t->time.tm_min = bcd2bin(t->time.tm_min);
+ else
+ t->time.tm_min = -1;
+ if (((unsigned)t->time.tm_hour) < 0x24)
+ t->time.tm_hour = bcd2bin(t->time.tm_hour);
+ else
+ t->time.tm_hour = -1;
+
+ if (cmos->day_alrm) {
+ if (((unsigned)t->time.tm_mday) <= 0x31)
+ t->time.tm_mday = bcd2bin(t->time.tm_mday);
else
- t->time.tm_mon = -1;
+ t->time.tm_mday = -1;
+
+ if (cmos->mon_alrm) {
+ if (((unsigned)t->time.tm_mon) <= 0x12)
+ t->time.tm_mon = bcd2bin(t->time.tm_mon)-1;
+ else
+ t->time.tm_mon = -1;
+ }
}
}
t->time.tm_year = -1;
@@ -322,29 +323,26 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
- unsigned char mon, mday, hrs, min, sec;
+ unsigned char mon, mday, hrs, min, sec, rtc_control;
if (!is_valid_irq(cmos->irq))
return -EIO;
- /* REVISIT this assumes PC style usage: always BCD */
-
- /* Writing 0xff means "don't care" or "match all". */
-
mon = t->time.tm_mon + 1;
- mon = (mon <= 12) ? bin2bcd(mon) : 0xff;
-
mday = t->time.tm_mday;
- mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff;
-
hrs = t->time.tm_hour;
- hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff;
-
min = t->time.tm_min;
- min = (min < 60) ? bin2bcd(min) : 0xff;
-
sec = t->time.tm_sec;
- sec = (sec < 60) ? bin2bcd(sec) : 0xff;
+
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ /* Writing 0xff means "don't care" or "match all". */
+ mon = (mon <= 12) ? bin2bcd(mon) : 0xff;
+ mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff;
+ hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff;
+ min = (min < 60) ? bin2bcd(min) : 0xff;
+ sec = (sec < 60) ? bin2bcd(sec) : 0xff;
+ }
spin_lock_irq(&rtc_lock);
@@ -478,7 +476,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
"update_IRQ\t: %s\n"
"HPET_emulated\t: %s\n"
// "square_wave\t: %s\n"
- // "BCD\t\t: %s\n"
+ "BCD\t\t: %s\n"
"DST_enable\t: %s\n"
"periodic_freq\t: %d\n"
"batt_status\t: %s\n",
@@ -486,7 +484,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
(rtc_control & RTC_UIE) ? "yes" : "no",
is_hpet_enabled() ? "yes" : "no",
// (rtc_control & RTC_SQWE) ? "yes" : "no",
- // (rtc_control & RTC_DM_BINARY) ? "no" : "yes",
+ (rtc_control & RTC_DM_BINARY) ? "no" : "yes",
(rtc_control & RTC_DST_EN) ? "yes" : "no",
cmos->rtc->irq_freq,
(valid & RTC_VRT) ? "okay" : "dead");
@@ -519,7 +517,8 @@ static const struct rtc_class_ops cmos_rtc_ops = {
#define NVRAM_OFFSET (RTC_REG_D + 1)
static ssize_t
-cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+cmos_nvram_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
int retval;
@@ -547,7 +546,8 @@ cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
}
static ssize_t
-cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+cmos_nvram_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct cmos_rtc *cmos;
@@ -719,6 +719,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
}
}
+ cmos_rtc.dev = dev;
+ dev_set_drvdata(dev, &cmos_rtc);
+
cmos_rtc.rtc = rtc_device_register(driver_name, dev,
&cmos_rtc_ops, THIS_MODULE);
if (IS_ERR(cmos_rtc.rtc)) {
@@ -726,8 +729,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup0;
}
- cmos_rtc.dev = dev;
- dev_set_drvdata(dev, &cmos_rtc);
rename_region(ports, dev_name(&cmos_rtc.rtc->dev));
spin_lock_irq(&rtc_lock);
@@ -749,12 +750,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
spin_unlock_irq(&rtc_lock);
- /* FIXME teach the alarm code how to handle binary mode;
+ /* FIXME:
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
- if (is_valid_irq(rtc_irq) &&
- (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) {
- dev_dbg(dev, "only 24-hr BCD mode supported\n");
+ if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
+ dev_warn(dev, "only 24-hr supported\n");
retval = -ENXIO;
goto cleanup1;
}
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index 03ea530981d1..316f484999b5 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -14,6 +14,7 @@
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/slab.h>
/*
* Registers in the COH 901 331
@@ -271,12 +272,13 @@ static int coh901331_resume(struct platform_device *pdev)
{
struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(rtap->irq);
- else
+ } else {
clk_enable(rtap->clk);
writel(rtap->irqmaskstore, rtap->virtbase + COH901331_IRQ_MASK);
clk_disable(rtap->clk);
+ }
return 0;
}
#else
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
new file mode 100644
index 000000000000..34647fc1ee98
--- /dev/null
+++ b/drivers/rtc/rtc-davinci.c
@@ -0,0 +1,674 @@
+/*
+ * DaVinci Power Management and Real Time Clock Driver for TI platforms
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/*
+ * The DaVinci RTC is a simple RTC with the following
+ * Sec: 0 - 59 : BCD count
+ * Min: 0 - 59 : BCD count
+ * Hour: 0 - 23 : BCD count
+ * Day: 0 - 0x7FFF(32767) : Binary count ( Over 89 years )
+ */
+
+/* PRTC interface registers */
+#define DAVINCI_PRTCIF_PID 0x00
+#define PRTCIF_CTLR 0x04
+#define PRTCIF_LDATA 0x08
+#define PRTCIF_UDATA 0x0C
+#define PRTCIF_INTEN 0x10
+#define PRTCIF_INTFLG 0x14
+
+/* PRTCIF_CTLR bit fields */
+#define PRTCIF_CTLR_BUSY BIT(31)
+#define PRTCIF_CTLR_SIZE BIT(25)
+#define PRTCIF_CTLR_DIR BIT(24)
+#define PRTCIF_CTLR_BENU_MSB BIT(23)
+#define PRTCIF_CTLR_BENU_3RD_BYTE BIT(22)
+#define PRTCIF_CTLR_BENU_2ND_BYTE BIT(21)
+#define PRTCIF_CTLR_BENU_LSB BIT(20)
+#define PRTCIF_CTLR_BENU_MASK (0x00F00000)
+#define PRTCIF_CTLR_BENL_MSB BIT(19)
+#define PRTCIF_CTLR_BENL_3RD_BYTE BIT(18)
+#define PRTCIF_CTLR_BENL_2ND_BYTE BIT(17)
+#define PRTCIF_CTLR_BENL_LSB BIT(16)
+#define PRTCIF_CTLR_BENL_MASK (0x000F0000)
+
+/* PRTCIF_INTEN bit fields */
+#define PRTCIF_INTEN_RTCSS BIT(1)
+#define PRTCIF_INTEN_RTCIF BIT(0)
+#define PRTCIF_INTEN_MASK (PRTCIF_INTEN_RTCSS \
+ | PRTCIF_INTEN_RTCIF)
+
+/* PRTCIF_INTFLG bit fields */
+#define PRTCIF_INTFLG_RTCSS BIT(1)
+#define PRTCIF_INTFLG_RTCIF BIT(0)
+#define PRTCIF_INTFLG_MASK (PRTCIF_INTFLG_RTCSS \
+ | PRTCIF_INTFLG_RTCIF)
+
+/* PRTC subsystem registers */
+#define PRTCSS_RTC_INTC_EXTENA1 (0x0C)
+#define PRTCSS_RTC_CTRL (0x10)
+#define PRTCSS_RTC_WDT (0x11)
+#define PRTCSS_RTC_TMR0 (0x12)
+#define PRTCSS_RTC_TMR1 (0x13)
+#define PRTCSS_RTC_CCTRL (0x14)
+#define PRTCSS_RTC_SEC (0x15)
+#define PRTCSS_RTC_MIN (0x16)
+#define PRTCSS_RTC_HOUR (0x17)
+#define PRTCSS_RTC_DAY0 (0x18)
+#define PRTCSS_RTC_DAY1 (0x19)
+#define PRTCSS_RTC_AMIN (0x1A)
+#define PRTCSS_RTC_AHOUR (0x1B)
+#define PRTCSS_RTC_ADAY0 (0x1C)
+#define PRTCSS_RTC_ADAY1 (0x1D)
+#define PRTCSS_RTC_CLKC_CNT (0x20)
+
+/* PRTCSS_RTC_INTC_EXTENA1 */
+#define PRTCSS_RTC_INTC_EXTENA1_MASK (0x07)
+
+/* PRTCSS_RTC_CTRL bit fields */
+#define PRTCSS_RTC_CTRL_WDTBUS BIT(7)
+#define PRTCSS_RTC_CTRL_WEN BIT(6)
+#define PRTCSS_RTC_CTRL_WDRT BIT(5)
+#define PRTCSS_RTC_CTRL_WDTFLG BIT(4)
+#define PRTCSS_RTC_CTRL_TE BIT(3)
+#define PRTCSS_RTC_CTRL_TIEN BIT(2)
+#define PRTCSS_RTC_CTRL_TMRFLG BIT(1)
+#define PRTCSS_RTC_CTRL_TMMD BIT(0)
+
+/* PRTCSS_RTC_CCTRL bit fields */
+#define PRTCSS_RTC_CCTRL_CALBUSY BIT(7)
+#define PRTCSS_RTC_CCTRL_DAEN BIT(5)
+#define PRTCSS_RTC_CCTRL_HAEN BIT(4)
+#define PRTCSS_RTC_CCTRL_MAEN BIT(3)
+#define PRTCSS_RTC_CCTRL_ALMFLG BIT(2)
+#define PRTCSS_RTC_CCTRL_AIEN BIT(1)
+#define PRTCSS_RTC_CCTRL_CAEN BIT(0)
+
+static DEFINE_SPINLOCK(davinci_rtc_lock);
+
+struct davinci_rtc {
+ struct rtc_device *rtc;
+ void __iomem *base;
+ resource_size_t pbase;
+ size_t base_size;
+ int irq;
+};
+
+static inline void rtcif_write(struct davinci_rtc *davinci_rtc,
+ u32 val, u32 addr)
+{
+ writel(val, davinci_rtc->base + addr);
+}
+
+static inline u32 rtcif_read(struct davinci_rtc *davinci_rtc, u32 addr)
+{
+ return readl(davinci_rtc->base + addr);
+}
+
+static inline void rtcif_wait(struct davinci_rtc *davinci_rtc)
+{
+ while (rtcif_read(davinci_rtc, PRTCIF_CTLR) & PRTCIF_CTLR_BUSY)
+ cpu_relax();
+}
+
+static inline void rtcss_write(struct davinci_rtc *davinci_rtc,
+ unsigned long val, u8 addr)
+{
+ rtcif_wait(davinci_rtc);
+
+ rtcif_write(davinci_rtc, PRTCIF_CTLR_BENL_LSB | addr, PRTCIF_CTLR);
+ rtcif_write(davinci_rtc, val, PRTCIF_LDATA);
+
+ rtcif_wait(davinci_rtc);
+}
+
+static inline u8 rtcss_read(struct davinci_rtc *davinci_rtc, u8 addr)
+{
+ rtcif_wait(davinci_rtc);
+
+ rtcif_write(davinci_rtc, PRTCIF_CTLR_DIR | PRTCIF_CTLR_BENL_LSB | addr,
+ PRTCIF_CTLR);
+
+ rtcif_wait(davinci_rtc);
+
+ return rtcif_read(davinci_rtc, PRTCIF_LDATA);
+}
+
+static inline void davinci_rtcss_calendar_wait(struct davinci_rtc *davinci_rtc)
+{
+ while (rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) &
+ PRTCSS_RTC_CCTRL_CALBUSY)
+ cpu_relax();
+}
+
+static irqreturn_t davinci_rtc_interrupt(int irq, void *class_dev)
+{
+ struct davinci_rtc *davinci_rtc = class_dev;
+ unsigned long events = 0;
+ u32 irq_flg;
+ u8 alm_irq, tmr_irq;
+ u8 rtc_ctrl, rtc_cctrl;
+ int ret = IRQ_NONE;
+
+ irq_flg = rtcif_read(davinci_rtc, PRTCIF_INTFLG) &
+ PRTCIF_INTFLG_RTCSS;
+
+ alm_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL) &
+ PRTCSS_RTC_CCTRL_ALMFLG;
+
+ tmr_irq = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL) &
+ PRTCSS_RTC_CTRL_TMRFLG;
+
+ if (irq_flg) {
+ if (alm_irq) {
+ events |= RTC_IRQF | RTC_AF;
+ rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL);
+ rtc_cctrl |= PRTCSS_RTC_CCTRL_ALMFLG;
+ rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL);
+ } else if (tmr_irq) {
+ events |= RTC_IRQF | RTC_PF;
+ rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL);
+ rtc_ctrl |= PRTCSS_RTC_CTRL_TMRFLG;
+ rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
+ }
+
+ rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS,
+ PRTCIF_INTFLG);
+ rtc_update_irq(davinci_rtc->rtc, 1, events);
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int
+davinci_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ u8 rtc_ctrl;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL);
+
+ switch (cmd) {
+ case RTC_WIE_ON:
+ rtc_ctrl |= PRTCSS_RTC_CTRL_WEN | PRTCSS_RTC_CTRL_WDTFLG;
+ break;
+ case RTC_WIE_OFF:
+ rtc_ctrl &= ~PRTCSS_RTC_CTRL_WEN;
+ break;
+ case RTC_UIE_OFF:
+ case RTC_UIE_ON:
+ ret = -ENOTTY;
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+
+ return ret;
+}
+
+static int convertfromdays(u16 days, struct rtc_time *tm)
+{
+ int tmp_days, year, mon;
+
+ for (year = 2000;; year++) {
+ tmp_days = rtc_year_days(1, 12, year);
+ if (days >= tmp_days)
+ days -= tmp_days;
+ else {
+ for (mon = 0;; mon++) {
+ tmp_days = rtc_month_days(mon, year);
+ if (days >= tmp_days) {
+ days -= tmp_days;
+ } else {
+ tm->tm_year = year - 1900;
+ tm->tm_mon = mon;
+ tm->tm_mday = days + 1;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static int convert2days(u16 *days, struct rtc_time *tm)
+{
+ int i;
+ *days = 0;
+
+ /* epoch == 1900 */
+ if (tm->tm_year < 100 || tm->tm_year > 199)
+ return -EINVAL;
+
+ for (i = 2000; i < 1900 + tm->tm_year; i++)
+ *days += rtc_year_days(1, 12, i);
+
+ *days += rtc_year_days(tm->tm_mday, tm->tm_mon, 1900 + tm->tm_year);
+
+ return 0;
+}
+
+static int davinci_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ u16 days = 0;
+ u8 day0, day1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ tm->tm_sec = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_SEC));
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ tm->tm_min = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_MIN));
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ tm->tm_hour = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_HOUR));
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ day0 = rtcss_read(davinci_rtc, PRTCSS_RTC_DAY0);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ day1 = rtcss_read(davinci_rtc, PRTCSS_RTC_DAY1);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+
+ days |= day1;
+ days <<= 8;
+ days |= day0;
+
+ if (convertfromdays(days, tm) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int davinci_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ u16 days;
+ u8 rtc_cctrl;
+ unsigned long flags;
+
+ if (convert2days(&days, tm) < 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, bin2bcd(tm->tm_sec), PRTCSS_RTC_SEC);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, bin2bcd(tm->tm_min), PRTCSS_RTC_MIN);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, bin2bcd(tm->tm_hour), PRTCSS_RTC_HOUR);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_DAY0);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_DAY1);
+
+ rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL);
+ rtc_cctrl |= PRTCSS_RTC_CCTRL_CAEN;
+ rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+
+ return 0;
+}
+
+static int davinci_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ unsigned long flags;
+ u8 rtc_cctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CCTRL);
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ if (enabled)
+ rtc_cctrl |= PRTCSS_RTC_CCTRL_DAEN |
+ PRTCSS_RTC_CCTRL_HAEN |
+ PRTCSS_RTC_CCTRL_MAEN |
+ PRTCSS_RTC_CCTRL_ALMFLG |
+ PRTCSS_RTC_CCTRL_AIEN;
+ else
+ rtc_cctrl &= ~PRTCSS_RTC_CCTRL_AIEN;
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, rtc_cctrl, PRTCSS_RTC_CCTRL);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+
+ return 0;
+}
+
+static int davinci_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ u16 days = 0;
+ u8 day0, day1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ alm->time.tm_min = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_AMIN));
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ alm->time.tm_hour = bcd2bin(rtcss_read(davinci_rtc, PRTCSS_RTC_AHOUR));
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ day0 = rtcss_read(davinci_rtc, PRTCSS_RTC_ADAY0);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ day1 = rtcss_read(davinci_rtc, PRTCSS_RTC_ADAY1);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+ days |= day1;
+ days <<= 8;
+ days |= day0;
+
+ if (convertfromdays(days, &alm->time) < 0)
+ return -EINVAL;
+
+ alm->pending = !!(rtcss_read(davinci_rtc,
+ PRTCSS_RTC_CCTRL) &
+ PRTCSS_RTC_CCTRL_AIEN);
+ alm->enabled = alm->pending && device_may_wakeup(dev);
+
+ return 0;
+}
+
+static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ unsigned long flags;
+ u16 days;
+
+ if (alm->time.tm_mday <= 0 && alm->time.tm_mon < 0
+ && alm->time.tm_year < 0) {
+ struct rtc_time tm;
+ unsigned long now, then;
+
+ davinci_rtc_read_time(dev, &tm);
+ rtc_tm_to_time(&tm, &now);
+
+ alm->time.tm_mday = tm.tm_mday;
+ alm->time.tm_mon = tm.tm_mon;
+ alm->time.tm_year = tm.tm_year;
+ rtc_tm_to_time(&alm->time, &then);
+
+ if (then < now) {
+ rtc_time_to_tm(now + 24 * 60 * 60, &tm);
+ alm->time.tm_mday = tm.tm_mday;
+ alm->time.tm_mon = tm.tm_mon;
+ alm->time.tm_year = tm.tm_year;
+ }
+ }
+
+ if (convert2days(&days, &alm->time) < 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_min), PRTCSS_RTC_AMIN);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, bin2bcd(alm->time.tm_hour), PRTCSS_RTC_AHOUR);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, days & 0xFF, PRTCSS_RTC_ADAY0);
+
+ davinci_rtcss_calendar_wait(davinci_rtc);
+ rtcss_write(davinci_rtc, (days & 0xFF00) >> 8, PRTCSS_RTC_ADAY1);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+
+ return 0;
+}
+
+static int davinci_rtc_irq_set_state(struct device *dev, int enabled)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ unsigned long flags;
+ u8 rtc_ctrl;
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL);
+
+ if (enabled) {
+ while (rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL)
+ & PRTCSS_RTC_CTRL_WDTBUS)
+ cpu_relax();
+
+ rtc_ctrl |= PRTCSS_RTC_CTRL_TE;
+ rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
+
+ rtcss_write(davinci_rtc, 0x0, PRTCSS_RTC_CLKC_CNT);
+
+ rtc_ctrl |= PRTCSS_RTC_CTRL_TIEN |
+ PRTCSS_RTC_CTRL_TMMD |
+ PRTCSS_RTC_CTRL_TMRFLG;
+ } else
+ rtc_ctrl &= ~PRTCSS_RTC_CTRL_TIEN;
+
+ rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+
+ return 0;
+}
+
+static int davinci_rtc_irq_set_freq(struct device *dev, int freq)
+{
+ struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
+ unsigned long flags;
+ u16 tmr_counter = (0x8000 >> (ffs(freq) - 1));
+
+ spin_lock_irqsave(&davinci_rtc_lock, flags);
+
+ rtcss_write(davinci_rtc, tmr_counter & 0xFF, PRTCSS_RTC_TMR0);
+ rtcss_write(davinci_rtc, (tmr_counter & 0xFF00) >> 8, PRTCSS_RTC_TMR1);
+
+ spin_unlock_irqrestore(&davinci_rtc_lock, flags);
+
+ return 0;
+}
+
+static struct rtc_class_ops davinci_rtc_ops = {
+ .ioctl = davinci_rtc_ioctl,
+ .read_time = davinci_rtc_read_time,
+ .set_time = davinci_rtc_set_time,
+ .alarm_irq_enable = davinci_rtc_alarm_irq_enable,
+ .read_alarm = davinci_rtc_read_alarm,
+ .set_alarm = davinci_rtc_set_alarm,
+ .irq_set_state = davinci_rtc_irq_set_state,
+ .irq_set_freq = davinci_rtc_irq_set_freq,
+};
+
+static int __init davinci_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct davinci_rtc *davinci_rtc;
+ struct resource *res, *mem;
+ int ret = 0;
+
+ davinci_rtc = kzalloc(sizeof(struct davinci_rtc), GFP_KERNEL);
+ if (!davinci_rtc) {
+ dev_dbg(dev, "could not allocate memory for private data\n");
+ return -ENOMEM;
+ }
+
+ davinci_rtc->irq = platform_get_irq(pdev, 0);
+ if (davinci_rtc->irq < 0) {
+ dev_err(dev, "no RTC irq\n");
+ ret = davinci_rtc->irq;
+ goto fail1;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "no mem resource\n");
+ ret = -EINVAL;
+ goto fail1;
+ }
+
+ davinci_rtc->pbase = res->start;
+ davinci_rtc->base_size = resource_size(res);
+
+ mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size,
+ pdev->name);
+ if (!mem) {
+ dev_err(dev, "RTC registers at %08x are not free\n",
+ davinci_rtc->pbase);
+ ret = -EBUSY;
+ goto fail1;
+ }
+
+ davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size);
+ if (!davinci_rtc->base) {
+ dev_err(dev, "unable to ioremap MEM resource\n");
+ ret = -ENOMEM;
+ goto fail2;
+ }
+
+ davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &davinci_rtc_ops, THIS_MODULE);
+ if (IS_ERR(davinci_rtc->rtc)) {
+ dev_err(dev, "unable to register RTC device, err %ld\n",
+ PTR_ERR(davinci_rtc->rtc));
+ goto fail3;
+ }
+
+ rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
+ rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
+ rtcss_write(davinci_rtc, 0, PRTCSS_RTC_INTC_EXTENA1);
+
+ rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL);
+ rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
+
+ ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt,
+ IRQF_DISABLED, "davinci_rtc", davinci_rtc);
+ if (ret < 0) {
+ dev_err(dev, "unable to register davinci RTC interrupt\n");
+ goto fail4;
+ }
+
+ /* Enable interrupts */
+ rtcif_write(davinci_rtc, PRTCIF_INTEN_RTCSS, PRTCIF_INTEN);
+ rtcss_write(davinci_rtc, PRTCSS_RTC_INTC_EXTENA1_MASK,
+ PRTCSS_RTC_INTC_EXTENA1);
+
+ rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL);
+
+ platform_set_drvdata(pdev, davinci_rtc);
+
+ device_init_wakeup(&pdev->dev, 0);
+
+ return 0;
+
+fail4:
+ rtc_device_unregister(davinci_rtc->rtc);
+fail3:
+ iounmap(davinci_rtc->base);
+fail2:
+ release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
+fail1:
+ kfree(davinci_rtc);
+
+ return ret;
+}
+
+static int __devexit davinci_rtc_remove(struct platform_device *pdev)
+{
+ struct davinci_rtc *davinci_rtc = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, 0);
+
+ rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
+
+ free_irq(davinci_rtc->irq, davinci_rtc);
+
+ rtc_device_unregister(davinci_rtc->rtc);
+
+ iounmap(davinci_rtc->base);
+ release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(davinci_rtc);
+
+ return 0;
+}
+
+static struct platform_driver davinci_rtc_driver = {
+ .probe = davinci_rtc_probe,
+ .remove = __devexit_p(davinci_rtc_remove),
+ .driver = {
+ .name = "rtc_davinci",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init rtc_init(void)
+{
+ return platform_driver_probe(&davinci_rtc_driver, davinci_rtc_probe);
+}
+module_init(rtc_init);
+
+static void __exit rtc_exit(void)
+{
+ platform_driver_unregister(&davinci_rtc_driver);
+}
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("Miguel Aguilar <miguel.aguilar@ridgerun.com>");
+MODULE_DESCRIPTION("Texas Instruments DaVinci PRTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c
index 4aedc705518c..45cd8c9f5a39 100644
--- a/drivers/rtc/rtc-ds1216.c
+++ b/drivers/rtc/rtc-ds1216.c
@@ -9,6 +9,7 @@
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/bcd.h>
+#include <linux/slab.h>
#define DRV_VERSION "0.2"
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c
index 4fcb16bbff4a..bf430f9091ed 100644
--- a/drivers/rtc/rtc-ds1286.c
+++ b/drivers/rtc/rtc-ds1286.c
@@ -18,6 +18,7 @@
#include <linux/bcd.h>
#include <linux/ds1286.h>
#include <linux/io.h>
+#include <linux/slab.h>
#define DRV_VERSION "1.0"
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 532acf9b05d8..359d1e04626c 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -16,7 +16,6 @@
#include <linux/rtc.h>
#include <linux/io.h>
#include <linux/bcd.h>
-#include <asm/rtc.h>
#define DRV_NAME "rtc-ds1302"
#define DRV_VERSION "0.1.1"
@@ -34,14 +33,55 @@
#define RTC_ADDR_MIN 0x01 /* Address of minute register */
#define RTC_ADDR_SEC 0x00 /* Address of second register */
+#ifdef CONFIG_SH_SECUREEDGE5410
+#include <asm/rtc.h>
+#include <mach/snapgear.h>
+
#define RTC_RESET 0x1000
#define RTC_IODATA 0x0800
#define RTC_SCLK 0x0400
-#ifdef CONFIG_SH_SECUREEDGE5410
-#include <mach/snapgear.h>
#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
#define get_dp() SECUREEDGE_READ_IOPORT()
+#define ds1302_set_tx()
+#define ds1302_set_rx()
+
+static inline int ds1302_hw_init(void)
+{
+ return 0;
+}
+
+static inline void ds1302_reset(void)
+{
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+}
+
+static inline void ds1302_clock(void)
+{
+ set_dp(get_dp() | RTC_SCLK); /* clock high */
+ set_dp(get_dp() & ~RTC_SCLK); /* clock low */
+}
+
+static inline void ds1302_start(void)
+{
+ set_dp(get_dp() | RTC_RESET);
+}
+
+static inline void ds1302_stop(void)
+{
+ set_dp(get_dp() & ~RTC_RESET);
+}
+
+static inline void ds1302_txbit(int bit)
+{
+ set_dp((get_dp() & ~RTC_IODATA) | (bit ? RTC_IODATA : 0));
+}
+
+static inline int ds1302_rxbit(void)
+{
+ return !!(get_dp() & RTC_IODATA);
+}
+
#else
#error "Add support for your platform"
#endif
@@ -50,11 +90,11 @@ static void ds1302_sendbits(unsigned int val)
{
int i;
+ ds1302_set_tx();
+
for (i = 8; (i); i--, val >>= 1) {
- set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
- RTC_IODATA : 0));
- set_dp(get_dp() | RTC_SCLK); /* clock high */
- set_dp(get_dp() & ~RTC_SCLK); /* clock low */
+ ds1302_txbit(val & 0x1);
+ ds1302_clock();
}
}
@@ -63,10 +103,11 @@ static unsigned int ds1302_recvbits(void)
unsigned int val;
int i;
+ ds1302_set_rx();
+
for (i = 0, val = 0; (i < 8); i++) {
- val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
- set_dp(get_dp() | RTC_SCLK); /* clock high */
- set_dp(get_dp() & ~RTC_SCLK); /* clock low */
+ val |= (ds1302_rxbit() << i);
+ ds1302_clock();
}
return val;
@@ -76,23 +117,24 @@ static unsigned int ds1302_readbyte(unsigned int addr)
{
unsigned int val;
- set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+ ds1302_reset();
- set_dp(get_dp() | RTC_RESET);
+ ds1302_start();
ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
val = ds1302_recvbits();
- set_dp(get_dp() & ~RTC_RESET);
+ ds1302_stop();
return val;
}
static void ds1302_writebyte(unsigned int addr, unsigned int val)
{
- set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
- set_dp(get_dp() | RTC_RESET);
+ ds1302_reset();
+
+ ds1302_start();
ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
ds1302_sendbits(val);
- set_dp(get_dp() & ~RTC_RESET);
+ ds1302_stop();
}
static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -167,13 +209,20 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
+ if (ds1302_hw_init()) {
+ dev_err(&pdev->dev, "Failed to init communication channel");
+ return -EINVAL;
+ }
+
/* Reset */
- set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+ ds1302_reset();
/* Write a magic value to the DS1302 RAM, and see if it sticks. */
ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
- if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
+ if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) {
+ dev_err(&pdev->dev, "Failed to probe");
return -ENODEV;
+ }
rtc = rtc_device_register("ds1302", &pdev->dev,
&ds1302_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 9630e7d3314e..48da85e97ca4 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/bcd.h>
+#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/workqueue.h>
@@ -541,7 +542,8 @@ static void msg_init(struct spi_message *m, struct spi_transfer *x,
}
static ssize_t
-ds1305_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+ds1305_nvram_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct spi_device *spi;
@@ -571,7 +573,8 @@ ds1305_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
}
static ssize_t
-ds1305_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+ds1305_nvram_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct spi_device *spi;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index c4ec5c158aa1..d827ce570a8c 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -556,7 +556,8 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
#define NVRAM_SIZE 56
static ssize_t
-ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+ds1307_nvram_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct i2c_client *client;
@@ -580,7 +581,8 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
}
static ssize_t
-ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+ds1307_nvram_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct i2c_client *client;
@@ -775,7 +777,7 @@ static int __devinit ds1307_probe(struct i2c_client *client,
read_rtc:
/* read RTC registers */
- tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf);
+ tmp = ds1307->read_block_data(ds1307->client, ds1307->offset, 8, buf);
if (tmp != 8) {
pr_debug("read error %d\n", tmp);
err = -EIO;
@@ -860,7 +862,7 @@ read_rtc:
if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
tmp += 12;
i2c_smbus_write_byte_data(client,
- DS1307_REG_HOUR,
+ ds1307->offset + DS1307_REG_HOUR,
bin2bcd(tmp));
}
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 5317bbcbc7a0..1f0007fd4431 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -24,6 +24,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/workqueue.h>
+#include <linux/slab.h>
#define DS1374_REG_TOD0 0x00 /* Time of Day */
#define DS1374_REG_TOD1 0x01
@@ -402,7 +403,6 @@ out_irq:
free_irq(client->irq, client);
out_free:
- i2c_set_clientdata(client, NULL);
kfree(ds1374);
return ret;
}
@@ -421,7 +421,6 @@ static int __devexit ds1374_remove(struct i2c_client *client)
}
rtc_device_unregister(ds1374->rtc);
- i2c_set_clientdata(client, NULL);
kfree(ds1374);
return 0;
}
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
index cdb705057091..26a86d235051 100644
--- a/drivers/rtc/rtc-ds1390.c
+++ b/drivers/rtc/rtc-ds1390.c
@@ -19,6 +19,7 @@
#include <linux/rtc.h>
#include <linux/spi/spi.h>
#include <linux/bcd.h>
+#include <linux/slab.h>
#define DS1390_REG_100THS 0x00
#define DS1390_REG_SECONDS 0x01
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 4166b84cb514..37268e97de49 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -17,6 +17,7 @@
#include <linux/bcd.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/rtc.h>
@@ -422,8 +423,9 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
};
static ssize_t
-ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
- char *buf, loff_t pos, size_t size)
+ds1511_nvram_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *ba,
+ char *buf, loff_t pos, size_t size)
{
ssize_t count;
@@ -451,8 +453,9 @@ ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
}
static ssize_t
-ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t size)
+ds1511_nvram_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
{
ssize_t count;
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index ed1ef7c9cc06..ff432e2ca275 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -11,6 +11,7 @@
#include <linux/bcd.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
@@ -251,7 +252,7 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
.update_irq_enable = ds1553_rtc_update_irq_enable,
};
-static ssize_t ds1553_nvram_read(struct kobject *kobj,
+static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
@@ -266,7 +267,7 @@ static ssize_t ds1553_nvram_read(struct kobject *kobj,
return count;
}
-static ssize_t ds1553_nvram_write(struct kobject *kobj,
+static ssize_t ds1553_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index a1273360a44e..042630c90dd3 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -15,6 +15,7 @@
#include <linux/bcd.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/rtc.h>
@@ -127,7 +128,7 @@ static const struct rtc_class_ops ds1742_rtc_ops = {
.set_time = ds1742_rtc_set_time,
};
-static ssize_t ds1742_nvram_read(struct kobject *kobj,
+static ssize_t ds1742_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
@@ -142,7 +143,7 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj,
return count;
}
-static ssize_t ds1742_nvram_write(struct kobject *kobj,
+static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
@@ -184,6 +185,7 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
pdata->size_nvram = pdata->size - RTC_SIZE;
pdata->ioaddr_rtc = ioaddr + pdata->size_nvram;
+ sysfs_bin_attr_init(&pdata->nvram_attr);
pdata->nvram_attr.attr.name = "nvram";
pdata->nvram_attr.attr.mode = S_IRUGO | S_IWUSR;
pdata->nvram_attr.read = ds1742_nvram_read;
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 9da02d108b73..11ae64dcbf3c 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -13,6 +13,7 @@
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/gfp.h>
#define EP93XX_RTC_DATA 0x000
#define EP93XX_RTC_MATCH 0x004
@@ -115,6 +116,15 @@ static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev,
}
static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL);
+static struct attribute *ep93xx_rtc_attrs[] = {
+ &dev_attr_comp_preload.attr,
+ &dev_attr_comp_delete.attr,
+ NULL
+};
+
+static const struct attribute_group ep93xx_rtc_sysfs_files = {
+ .attrs = ep93xx_rtc_attrs,
+};
static int __init ep93xx_rtc_probe(struct platform_device *pdev)
{
@@ -123,27 +133,22 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
struct rtc_device *rtc;
int err;
- ep93xx_rtc = kzalloc(sizeof(struct ep93xx_rtc), GFP_KERNEL);
- if (ep93xx_rtc == NULL)
+ ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
+ if (!ep93xx_rtc)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- err = -ENXIO;
- goto fail_free;
- }
+ if (!res)
+ return -ENXIO;
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (res == NULL) {
- err = -EBUSY;
- goto fail_free;
- }
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
- ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res));
- if (ep93xx_rtc->mmio_base == NULL) {
- err = -ENXIO;
- goto fail;
- }
+ ep93xx_rtc->mmio_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ep93xx_rtc->mmio_base)
+ return -ENXIO;
pdev->dev.platform_data = ep93xx_rtc;
@@ -151,53 +156,34 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
&pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
- goto fail;
+ goto exit;
}
platform_set_drvdata(pdev, rtc);
- err = device_create_file(&pdev->dev, &dev_attr_comp_preload);
+ err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
if (err)
goto fail;
- err = device_create_file(&pdev->dev, &dev_attr_comp_delete);
- if (err) {
- device_remove_file(&pdev->dev, &dev_attr_comp_preload);
- goto fail;
- }
return 0;
fail:
- if (ep93xx_rtc->mmio_base) {
- iounmap(ep93xx_rtc->mmio_base);
- pdev->dev.platform_data = NULL;
- }
- release_mem_region(res->start, resource_size(res));
-fail_free:
- kfree(ep93xx_rtc);
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(rtc);
+exit:
+ pdev->dev.platform_data = NULL;
return err;
}
static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
{
struct rtc_device *rtc = platform_get_drvdata(pdev);
- struct ep93xx_rtc *ep93xx_rtc = pdev->dev.platform_data;
- struct resource *res;
-
- /* cleanup sysfs */
- device_remove_file(&pdev->dev, &dev_attr_comp_delete);
- device_remove_file(&pdev->dev, &dev_attr_comp_preload);
+ sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
+ platform_set_drvdata(pdev, NULL);
rtc_device_unregister(rtc);
-
- iounmap(ep93xx_rtc->mmio_base);
pdev->dev.platform_data = NULL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index 3a7be11cc6b9..ff6fce61ea41 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -13,6 +13,7 @@
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/slab.h>
#define FM3130_RTC_CONTROL (0x0)
#define FM3130_CAL_CONTROL (0x1)
@@ -376,20 +377,22 @@ static int __devinit fm3130_probe(struct i2c_client *client,
}
/* Disabling calibration mode */
- if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL)
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) {
i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
fm3130->regs[FM3130_RTC_CONTROL] &
~(FM3130_RTC_CONTROL_BIT_CAL));
dev_warn(&client->dev, "Disabling calibration mode!\n");
+ }
/* Disabling read and write modes */
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE ||
- fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ)
+ fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) {
i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
fm3130->regs[FM3130_RTC_CONTROL] &
~(FM3130_RTC_CONTROL_BIT_READ |
FM3130_RTC_CONTROL_BIT_WRITE));
dev_warn(&client->dev, "Disabling READ or WRITE mode!\n");
+ }
/* oscillator off? turn it on, so clock can tick. */
if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN)
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index 054e05294af8..468200c38ecb 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -462,39 +462,16 @@ isl1208_sysfs_store_usr(struct device *dev,
static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
isl1208_sysfs_store_usr);
-static int
-isl1208_sysfs_register(struct device *dev)
-{
- int err;
-
- err = device_create_file(dev, &dev_attr_atrim);
- if (err)
- return err;
-
- err = device_create_file(dev, &dev_attr_dtrim);
- if (err) {
- device_remove_file(dev, &dev_attr_atrim);
- return err;
- }
-
- err = device_create_file(dev, &dev_attr_usr);
- if (err) {
- device_remove_file(dev, &dev_attr_atrim);
- device_remove_file(dev, &dev_attr_dtrim);
- }
-
- return 0;
-}
-
-static int
-isl1208_sysfs_unregister(struct device *dev)
-{
- device_remove_file(dev, &dev_attr_dtrim);
- device_remove_file(dev, &dev_attr_atrim);
- device_remove_file(dev, &dev_attr_usr);
+static struct attribute *isl1208_rtc_attrs[] = {
+ &dev_attr_atrim.attr,
+ &dev_attr_dtrim.attr,
+ &dev_attr_usr.attr,
+ NULL
+};
- return 0;
-}
+static const struct attribute_group isl1208_rtc_sysfs_files = {
+ .attrs = isl1208_rtc_attrs,
+};
static int
isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
@@ -529,7 +506,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_warn(&client->dev, "rtc power failure detected, "
"please set clock.\n");
- rc = isl1208_sysfs_register(&client->dev);
+ rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
if (rc)
goto exit_unregister;
@@ -546,7 +523,7 @@ isl1208_remove(struct i2c_client *client)
{
struct rtc_device *rtc = i2c_get_clientdata(client);
- isl1208_sysfs_unregister(&client->dev);
+ sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
rtc_device_unregister(rtc);
return 0;
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 60fe266f0f49..6dc4e6241418 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -595,10 +595,6 @@ static void wdt_disable(void)
static ssize_t wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- /* Can't seek (pwrite) on this device
- if (ppos != &file->f_pos)
- return -ESPIPE;
- */
if (count) {
wdt_ping();
return 1;
@@ -623,7 +619,7 @@ static ssize_t wdt_read(struct file *file, char __user *buf,
* according to their available features. We only actually usefully support
* querying capabilities and current status.
*/
-static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+static int wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_margin, rv;
@@ -676,6 +672,18 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -ENOTTY;
}
+static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = wdt_ioctl(file, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+
/**
* wdt_open:
* @inode: inode of device
@@ -695,7 +703,7 @@ static int wdt_open(struct inode *inode, struct file *file)
*/
wdt_is_open = 1;
unlock_kernel();
- return 0;
+ return nonseekable_open(inode, file);
}
return -ENODEV;
}
@@ -736,7 +744,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.read = wdt_read,
- .ioctl = wdt_ioctl,
+ .unlocked_ioctl = wdt_unlocked_ioctl,
.write = wdt_write,
.open = wdt_open,
.release = wdt_release,
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
index 8cb5b8959e5b..7410875e5838 100644
--- a/drivers/rtc/rtc-m48t35.c
+++ b/drivers/rtc/rtc-m48t35.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/rtc.h>
+#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/bcd.h>
#include <linux/io.h>
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index ede43b846859..be8359fdb65a 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -19,6 +19,7 @@
#include <linux/rtc.h>
#include <linux/rtc/m48t59.h>
#include <linux/bcd.h>
+#include <linux/slab.h>
#ifndef NO_IRQ
#define NO_IRQ (-1)
@@ -342,7 +343,7 @@ static const struct rtc_class_ops m48t02_rtc_ops = {
.set_time = m48t59_rtc_set_time,
};
-static ssize_t m48t59_nvram_read(struct kobject *kobj,
+static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
@@ -362,7 +363,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj,
return cnt;
}
-static ssize_t m48t59_nvram_write(struct kobject *kobj,
+static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c
new file mode 100644
index 000000000000..174036dda786
--- /dev/null
+++ b/drivers/rtc/rtc-max8925.c
@@ -0,0 +1,315 @@
+/*
+ * RTC driver for Maxim MAX8925
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max8925.h>
+
+enum {
+ RTC_SEC = 0,
+ RTC_MIN,
+ RTC_HOUR,
+ RTC_WEEKDAY,
+ RTC_DATE,
+ RTC_MONTH,
+ RTC_YEAR1,
+ RTC_YEAR2,
+};
+
+#define MAX8925_RTC_SEC 0x00
+#define MAX8925_RTC_MIN 0x01
+#define MAX8925_RTC_HOUR 0x02
+#define MAX8925_RTC_WEEKDAY 0x03
+#define MAX8925_RTC_DATE 0x04
+#define MAX8925_RTC_MONTH 0x05
+#define MAX8925_RTC_YEAR1 0x06
+#define MAX8925_RTC_YEAR2 0x07
+#define MAX8925_ALARM0_SEC 0x08
+#define MAX8925_ALARM0_MIN 0x09
+#define MAX8925_ALARM0_HOUR 0x0a
+#define MAX8925_ALARM0_WEEKDAY 0x0b
+#define MAX8925_ALARM0_DATE 0x0c
+#define MAX8925_ALARM0_MON 0x0d
+#define MAX8925_ALARM0_YEAR1 0x0e
+#define MAX8925_ALARM0_YEAR2 0x0f
+#define MAX8925_ALARM1_SEC 0x10
+#define MAX8925_ALARM1_MIN 0x11
+#define MAX8925_ALARM1_HOUR 0x12
+#define MAX8925_ALARM1_WEEKDAY 0x13
+#define MAX8925_ALARM1_DATE 0x14
+#define MAX8925_ALARM1_MON 0x15
+#define MAX8925_ALARM1_YEAR1 0x16
+#define MAX8925_ALARM1_YEAR2 0x17
+#define MAX8925_RTC_CNTL 0x1b
+#define MAX8925_RTC_STATUS 0x20
+
+#define TIME_NUM 8
+#define ALARM_1SEC (1 << 7)
+#define HOUR_12 (1 << 7)
+#define HOUR_AM_PM (1 << 5)
+#define ALARM0_IRQ (1 << 3)
+#define ALARM1_IRQ (1 << 2)
+#define ALARM0_STATUS (1 << 2)
+#define ALARM1_STATUS (1 << 1)
+
+
+struct max8925_rtc_info {
+ struct rtc_device *rtc_dev;
+ struct max8925_chip *chip;
+ struct i2c_client *rtc;
+ struct device *dev;
+};
+
+static irqreturn_t rtc_update_handler(int irq, void *data)
+{
+ struct max8925_rtc_info *info = (struct max8925_rtc_info *)data;
+
+ /* disable ALARM0 except for 1SEC alarm */
+ max8925_set_bits(info->rtc, MAX8925_ALARM0_CNTL, 0x7f, 0);
+ rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+ return IRQ_HANDLED;
+}
+
+static int tm_calc(struct rtc_time *tm, unsigned char *buf, int len)
+{
+ if (len < TIME_NUM)
+ return -EINVAL;
+ tm->tm_year = (buf[RTC_YEAR2] >> 4) * 1000
+ + (buf[RTC_YEAR2] & 0xf) * 100
+ + (buf[RTC_YEAR1] >> 4) * 10
+ + (buf[RTC_YEAR1] & 0xf);
+ tm->tm_year -= 1900;
+ tm->tm_mon = ((buf[RTC_MONTH] >> 4) & 0x01) * 10
+ + (buf[RTC_MONTH] & 0x0f);
+ tm->tm_mday = ((buf[RTC_DATE] >> 4) & 0x03) * 10
+ + (buf[RTC_DATE] & 0x0f);
+ tm->tm_wday = buf[RTC_WEEKDAY] & 0x07;
+ if (buf[RTC_HOUR] & HOUR_12) {
+ tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x1) * 10
+ + (buf[RTC_HOUR] & 0x0f);
+ if (buf[RTC_HOUR] & HOUR_AM_PM)
+ tm->tm_hour += 12;
+ } else
+ tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x03) * 10
+ + (buf[RTC_HOUR] & 0x0f);
+ tm->tm_min = ((buf[RTC_MIN] >> 4) & 0x7) * 10
+ + (buf[RTC_MIN] & 0x0f);
+ tm->tm_sec = ((buf[RTC_SEC] >> 4) & 0x7) * 10
+ + (buf[RTC_SEC] & 0x0f);
+ return 0;
+}
+
+static int data_calc(unsigned char *buf, struct rtc_time *tm, int len)
+{
+ unsigned char high, low;
+
+ if (len < TIME_NUM)
+ return -EINVAL;
+
+ high = (tm->tm_year + 1900) / 1000;
+ low = (tm->tm_year + 1900) / 100;
+ low = low - high * 10;
+ buf[RTC_YEAR2] = (high << 4) + low;
+ high = (tm->tm_year + 1900) / 10;
+ low = tm->tm_year + 1900;
+ low = low - high * 10;
+ high = high - (high / 10) * 10;
+ buf[RTC_YEAR1] = (high << 4) + low;
+ high = tm->tm_mon / 10;
+ low = tm->tm_mon;
+ low = low - high * 10;
+ buf[RTC_MONTH] = (high << 4) + low;
+ high = tm->tm_mday / 10;
+ low = tm->tm_mday;
+ low = low - high * 10;
+ buf[RTC_DATE] = (high << 4) + low;
+ buf[RTC_WEEKDAY] = tm->tm_wday;
+ high = tm->tm_hour / 10;
+ low = tm->tm_hour;
+ low = low - high * 10;
+ buf[RTC_HOUR] = (high << 4) + low;
+ high = tm->tm_min / 10;
+ low = tm->tm_min;
+ low = low - high * 10;
+ buf[RTC_MIN] = (high << 4) + low;
+ high = tm->tm_sec / 10;
+ low = tm->tm_sec;
+ low = low - high * 10;
+ buf[RTC_SEC] = (high << 4) + low;
+ return 0;
+}
+
+static int max8925_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = max8925_bulk_read(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf);
+ if (ret < 0)
+ goto out;
+ ret = tm_calc(tm, buf, TIME_NUM);
+out:
+ return ret;
+}
+
+static int max8925_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = data_calc(buf, tm, TIME_NUM);
+ if (ret < 0)
+ goto out;
+ ret = max8925_bulk_write(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf);
+out:
+ return ret;
+}
+
+static int max8925_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = max8925_bulk_read(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
+ if (ret < 0)
+ goto out;
+ ret = tm_calc(&alrm->time, buf, TIME_NUM);
+ if (ret < 0)
+ goto out;
+ ret = max8925_reg_read(info->rtc, MAX8925_RTC_IRQ_MASK);
+ if (ret < 0)
+ goto out;
+ if ((ret & ALARM0_IRQ) == 0)
+ alrm->enabled = 1;
+ else
+ alrm->enabled = 0;
+ ret = max8925_reg_read(info->rtc, MAX8925_RTC_STATUS);
+ if (ret < 0)
+ goto out;
+ if (ret & ALARM0_STATUS)
+ alrm->pending = 1;
+ else
+ alrm->pending = 0;
+out:
+ return ret;
+}
+
+static int max8925_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct max8925_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[TIME_NUM];
+ int ret;
+
+ ret = data_calc(buf, &alrm->time, TIME_NUM);
+ if (ret < 0)
+ goto out;
+ ret = max8925_bulk_write(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
+ if (ret < 0)
+ goto out;
+ /* only enable alarm on year/month/day/hour/min/sec */
+ ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
+ if (ret < 0)
+ goto out;
+out:
+ return ret;
+}
+
+static const struct rtc_class_ops max8925_rtc_ops = {
+ .read_time = max8925_rtc_read_time,
+ .set_time = max8925_rtc_set_time,
+ .read_alarm = max8925_rtc_read_alarm,
+ .set_alarm = max8925_rtc_set_alarm,
+};
+
+static int __devinit max8925_rtc_probe(struct platform_device *pdev)
+{
+ struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct max8925_rtc_info *info;
+ int irq, ret;
+
+ info = kzalloc(sizeof(struct max8925_rtc_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->chip = chip;
+ info->rtc = chip->rtc;
+ info->dev = &pdev->dev;
+ irq = chip->irq_base + MAX8925_IRQ_RTC_ALARM0;
+
+ ret = request_threaded_irq(irq, NULL, rtc_update_handler,
+ IRQF_ONESHOT, "rtc-alarm0", info);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+ irq, ret);
+ goto out_irq;
+ }
+
+ info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
+ &max8925_rtc_ops, THIS_MODULE);
+ ret = PTR_ERR(info->rtc_dev);
+ if (IS_ERR(info->rtc_dev)) {
+ dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+ goto out_rtc;
+ }
+
+ dev_set_drvdata(&pdev->dev, info);
+ platform_set_drvdata(pdev, info);
+
+ return 0;
+out_rtc:
+ free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info);
+out_irq:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit max8925_rtc_remove(struct platform_device *pdev)
+{
+ struct max8925_rtc_info *info = platform_get_drvdata(pdev);
+
+ if (info) {
+ free_irq(info->chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info);
+ rtc_device_unregister(info->rtc_dev);
+ kfree(info);
+ }
+ return 0;
+}
+
+static struct platform_driver max8925_rtc_driver = {
+ .driver = {
+ .name = "max8925-rtc",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8925_rtc_probe,
+ .remove = __devexit_p(max8925_rtc_remove),
+};
+
+static int __init max8925_rtc_init(void)
+{
+ return platform_driver_register(&max8925_rtc_driver);
+}
+module_init(max8925_rtc_init);
+
+static void __exit max8925_rtc_exit(void)
+{
+ platform_driver_unregister(&max8925_rtc_driver);
+}
+module_exit(max8925_rtc_exit);
+
+MODULE_DESCRIPTION("Maxim MAX8925 RTC driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c
index 850f983c039c..675bfb515367 100644
--- a/drivers/rtc/rtc-mc13783.c
+++ b/drivers/rtc/rtc-mc13783.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/rtc.h>
#define DRIVER_NAME "mc13783-rtc"
@@ -28,6 +29,34 @@ struct mc13783_rtc {
int valid;
};
+static int mc13783_rtc_irq_enable_unlocked(struct device *dev,
+ unsigned int enabled, int irq)
+{
+ struct mc13783_rtc *priv = dev_get_drvdata(dev);
+ int (*func)(struct mc13783 *mc13783, int irq);
+
+ if (!priv->valid)
+ return -ENODATA;
+
+ func = enabled ? mc13783_irq_unmask : mc13783_irq_mask;
+ return func(priv->mc13783, irq);
+}
+
+static int mc13783_rtc_irq_enable(struct device *dev,
+ unsigned int enabled, int irq)
+{
+ struct mc13783_rtc *priv = dev_get_drvdata(dev);
+ int ret;
+
+ mc13783_lock(priv->mc13783);
+
+ ret = mc13783_rtc_irq_enable_unlocked(dev, enabled, irq);
+
+ mc13783_unlock(priv->mc13783);
+
+ return ret;
+}
+
static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct mc13783_rtc *priv = dev_get_drvdata(dev);
@@ -78,6 +107,7 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs)
{
struct mc13783_rtc *priv = dev_get_drvdata(dev);
unsigned int seconds, days;
+ unsigned int alarmseconds;
int ret;
seconds = secs % 86400;
@@ -86,7 +116,22 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs)
mc13783_lock(priv->mc13783);
/*
- * first write seconds=0 to prevent a day switch between writing days
+ * temporarily invalidate alarm to prevent triggering it when the day is
+ * already updated while the time isn't yet.
+ */
+ ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &alarmseconds);
+ if (unlikely(ret))
+ goto out;
+
+ if (alarmseconds < 86400) {
+ ret = mc13783_reg_write(priv->mc13783,
+ MC13783_RTCTODA, 0x1ffff);
+ if (unlikely(ret))
+ goto out;
+ }
+
+ /*
+ * write seconds=0 to prevent a day switch between writing days
* and seconds below
*/
ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0);
@@ -101,11 +146,19 @@ static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs)
if (unlikely(ret))
goto out;
- ret = mc13783_ackirq(priv->mc13783, MC13783_IRQ_RTCRST);
+ /* restore alarm */
+ if (alarmseconds < 86400) {
+ ret = mc13783_reg_write(priv->mc13783,
+ MC13783_RTCTODA, alarmseconds);
+ if (unlikely(ret))
+ goto out;
+ }
+
+ ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_RTCRST);
if (unlikely(ret))
goto out;
- ret = mc13783_unmask(priv->mc13783, MC13783_IRQ_RTCRST);
+ ret = mc13783_irq_unmask(priv->mc13783, MC13783_IRQ_RTCRST);
out:
priv->valid = !ret;
@@ -114,41 +167,139 @@ out:
return ret;
}
-static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev)
+static int mc13783_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct mc13783_rtc *priv = dev;
- struct mc13783 *mc13783 = priv->mc13783;
+ struct mc13783_rtc *priv = dev_get_drvdata(dev);
+ unsigned seconds, days;
+ unsigned long s1970;
+ int enabled, pending;
+ int ret;
- dev_dbg(&priv->rtc->dev, "1HZ\n");
+ mc13783_lock(priv->mc13783);
- rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
+ ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTODA, &seconds);
+ if (unlikely(ret))
+ goto out;
+ if (seconds >= 86400) {
+ ret = -ENODATA;
+ goto out;
+ }
+
+ ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days);
+ if (unlikely(ret))
+ goto out;
- mc13783_ackirq(mc13783, irq);
+ ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_TODA,
+ &enabled, &pending);
- return IRQ_HANDLED;
+out:
+ mc13783_unlock(priv->mc13783);
+
+ if (ret)
+ return ret;
+
+ alarm->enabled = enabled;
+ alarm->pending = pending;
+
+ s1970 = days * 86400 + seconds;
+
+ rtc_time_to_tm(s1970, &alarm->time);
+ dev_dbg(dev, "%s: %lu\n", __func__, s1970);
+
+ return 0;
}
-static int mc13783_rtc_update_irq_enable(struct device *dev,
- unsigned int enabled)
+static int mc13783_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct mc13783_rtc *priv = dev_get_drvdata(dev);
- int ret = -ENODATA;
+ unsigned long s1970;
+ unsigned seconds, days;
+ int ret;
mc13783_lock(priv->mc13783);
- if (!priv->valid)
+
+ /* disable alarm to prevent false triggering */
+ ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, 0x1ffff);
+ if (unlikely(ret))
goto out;
- ret = (enabled ? mc13783_unmask : mc13783_mask)(priv->mc13783,
- MC13783_IRQ_1HZ);
+ ret = mc13783_irq_ack(priv->mc13783, MC13783_IRQ_TODA);
+ if (unlikely(ret))
+ goto out;
+
+ ret = rtc_tm_to_time(&alarm->time, &s1970);
+ if (unlikely(ret))
+ goto out;
+
+ dev_dbg(dev, "%s: o%2.s %lu\n", __func__, alarm->enabled ? "n" : "ff",
+ s1970);
+
+ ret = mc13783_rtc_irq_enable_unlocked(dev, alarm->enabled,
+ MC13783_IRQ_TODA);
+ if (unlikely(ret))
+ goto out;
+
+ seconds = s1970 % 86400;
+ days = s1970 / 86400;
+
+ ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAYA, days);
+ if (unlikely(ret))
+ goto out;
+
+ ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTODA, seconds);
+
out:
mc13783_unlock(priv->mc13783);
return ret;
}
+static irqreturn_t mc13783_rtc_alarm_handler(int irq, void *dev)
+{
+ struct mc13783_rtc *priv = dev;
+ struct mc13783 *mc13783 = priv->mc13783;
+
+ dev_dbg(&priv->rtc->dev, "Alarm\n");
+
+ rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
+
+ mc13783_irq_ack(mc13783, irq);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev)
+{
+ struct mc13783_rtc *priv = dev;
+ struct mc13783 *mc13783 = priv->mc13783;
+
+ dev_dbg(&priv->rtc->dev, "1HZ\n");
+
+ rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
+
+ mc13783_irq_ack(mc13783, irq);
+
+ return IRQ_HANDLED;
+}
+
+static int mc13783_rtc_update_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_1HZ);
+}
+
+static int mc13783_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ return mc13783_rtc_irq_enable(dev, enabled, MC13783_IRQ_TODA);
+}
+
static const struct rtc_class_ops mc13783_rtc_ops = {
.read_time = mc13783_rtc_read_time,
.set_mmss = mc13783_rtc_set_mmss,
+ .read_alarm = mc13783_rtc_read_alarm,
+ .set_alarm = mc13783_rtc_set_alarm,
+ .alarm_irq_enable = mc13783_rtc_alarm_irq_enable,
.update_irq_enable = mc13783_rtc_update_irq_enable,
};
@@ -160,7 +311,7 @@ static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev)
dev_dbg(&priv->rtc->dev, "RTCRST\n");
priv->valid = 0;
- mc13783_mask(mc13783, irq);
+ mc13783_irq_mask(mc13783, irq);
return IRQ_HANDLED;
}
@@ -169,50 +320,64 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
{
int ret;
struct mc13783_rtc *priv;
+ struct mc13783 *mc13783;
+ int rtcrst_pending;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
- platform_set_drvdata(pdev, priv);
+ mc13783 = dev_get_drvdata(pdev->dev.parent);
+ priv->mc13783 = mc13783;
- priv->valid = 1;
+ platform_set_drvdata(pdev, priv);
- mc13783_lock(priv->mc13783);
+ mc13783_lock(mc13783);
- ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST,
+ ret = mc13783_irq_request(mc13783, MC13783_IRQ_RTCRST,
mc13783_rtc_reset_handler, DRIVER_NAME, priv);
if (ret)
goto err_reset_irq_request;
- ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ,
+ ret = mc13783_irq_status(mc13783, MC13783_IRQ_RTCRST,
+ NULL, &rtcrst_pending);
+ if (ret)
+ goto err_reset_irq_status;
+
+ priv->valid = !rtcrst_pending;
+
+ ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_1HZ,
mc13783_rtc_update_handler, DRIVER_NAME, priv);
if (ret)
goto err_update_irq_request;
- mc13783_unlock(priv->mc13783);
+ ret = mc13783_irq_request_nounmask(mc13783, MC13783_IRQ_TODA,
+ mc13783_rtc_alarm_handler, DRIVER_NAME, priv);
+ if (ret)
+ goto err_alarm_irq_request;
priv->rtc = rtc_device_register(pdev->name,
&pdev->dev, &mc13783_rtc_ops, THIS_MODULE);
-
if (IS_ERR(priv->rtc)) {
ret = PTR_ERR(priv->rtc);
- mc13783_lock(priv->mc13783);
+ mc13783_irq_free(mc13783, MC13783_IRQ_TODA, priv);
+err_alarm_irq_request:
- mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv);
+ mc13783_irq_free(mc13783, MC13783_IRQ_1HZ, priv);
err_update_irq_request:
- mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv);
-err_reset_irq_request:
+err_reset_irq_status:
- mc13783_unlock(priv->mc13783);
+ mc13783_irq_free(mc13783, MC13783_IRQ_RTCRST, priv);
+err_reset_irq_request:
platform_set_drvdata(pdev, NULL);
kfree(priv);
}
+ mc13783_unlock(mc13783);
+
return ret;
}
@@ -220,10 +385,11 @@ static int __devexit mc13783_rtc_remove(struct platform_device *pdev)
{
struct mc13783_rtc *priv = platform_get_drvdata(pdev);
- rtc_device_unregister(priv->rtc);
-
mc13783_lock(priv->mc13783);
+ rtc_device_unregister(priv->rtc);
+
+ mc13783_irq_free(priv->mc13783, MC13783_IRQ_TODA, priv);
mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv);
mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv);
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
new file mode 100644
index 000000000000..db5d8c416d26
--- /dev/null
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -0,0 +1,390 @@
+/*
+ * Real-time clock driver for MPC5121
+ *
+ * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
+ * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+struct mpc5121_rtc_regs {
+ u8 set_time; /* RTC + 0x00 */
+ u8 hour_set; /* RTC + 0x01 */
+ u8 minute_set; /* RTC + 0x02 */
+ u8 second_set; /* RTC + 0x03 */
+
+ u8 set_date; /* RTC + 0x04 */
+ u8 month_set; /* RTC + 0x05 */
+ u8 weekday_set; /* RTC + 0x06 */
+ u8 date_set; /* RTC + 0x07 */
+
+ u8 write_sw; /* RTC + 0x08 */
+ u8 sw_set; /* RTC + 0x09 */
+ u16 year_set; /* RTC + 0x0a */
+
+ u8 alm_enable; /* RTC + 0x0c */
+ u8 alm_hour_set; /* RTC + 0x0d */
+ u8 alm_min_set; /* RTC + 0x0e */
+ u8 int_enable; /* RTC + 0x0f */
+
+ u8 reserved1;
+ u8 hour; /* RTC + 0x11 */
+ u8 minute; /* RTC + 0x12 */
+ u8 second; /* RTC + 0x13 */
+
+ u8 month; /* RTC + 0x14 */
+ u8 wday_mday; /* RTC + 0x15 */
+ u16 year; /* RTC + 0x16 */
+
+ u8 int_alm; /* RTC + 0x18 */
+ u8 int_sw; /* RTC + 0x19 */
+ u8 alm_status; /* RTC + 0x1a */
+ u8 sw_minute; /* RTC + 0x1b */
+
+ u8 bus_error_1; /* RTC + 0x1c */
+ u8 int_day; /* RTC + 0x1d */
+ u8 int_min; /* RTC + 0x1e */
+ u8 int_sec; /* RTC + 0x1f */
+
+ /*
+ * target_time:
+ * intended to be used for hibernation but hibernation
+ * does not work on silicon rev 1.5 so use it for non-volatile
+ * storage of offset between the actual_time register and linux
+ * time
+ */
+ u32 target_time; /* RTC + 0x20 */
+ /*
+ * actual_time:
+ * readonly time since VBAT_RTC was last connected
+ */
+ u32 actual_time; /* RTC + 0x24 */
+ u32 keep_alive; /* RTC + 0x28 */
+};
+
+struct mpc5121_rtc_data {
+ unsigned irq;
+ unsigned irq_periodic;
+ struct mpc5121_rtc_regs __iomem *regs;
+ struct rtc_device *rtc;
+ struct rtc_wkalrm wkalarm;
+};
+
+/*
+ * Update second/minute/hour registers.
+ *
+ * This is just so alarm will work.
+ */
+static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
+ struct rtc_time *tm)
+{
+ out_8(&regs->second_set, tm->tm_sec);
+ out_8(&regs->minute_set, tm->tm_min);
+ out_8(&regs->hour_set, tm->tm_hour);
+
+ /* set time sequence */
+ out_8(&regs->set_time, 0x1);
+ out_8(&regs->set_time, 0x3);
+ out_8(&regs->set_time, 0x1);
+ out_8(&regs->set_time, 0x0);
+}
+
+static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ unsigned long now;
+
+ /*
+ * linux time is actual_time plus the offset saved in target_time
+ */
+ now = in_be32(&regs->actual_time) + in_be32(&regs->target_time);
+
+ rtc_time_to_tm(now, tm);
+
+ /*
+ * update second minute hour registers
+ * so alarms will work
+ */
+ mpc5121_rtc_update_smh(regs, tm);
+
+ return rtc_valid_tm(tm);
+}
+
+static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int ret;
+ unsigned long now;
+
+ /*
+ * The actual_time register is read only so we write the offset
+ * between it and linux time to the target_time register.
+ */
+ ret = rtc_tm_to_time(tm, &now);
+ if (ret == 0)
+ out_be32(&regs->target_time, now - in_be32(&regs->actual_time));
+
+ /*
+ * update second minute hour registers
+ * so alarms will work
+ */
+ mpc5121_rtc_update_smh(regs, tm);
+
+ return 0;
+}
+
+static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ *alarm = rtc->wkalarm;
+
+ alarm->pending = in_8(&regs->alm_status);
+
+ return 0;
+}
+
+static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ /*
+ * the alarm has no seconds so deal with it
+ */
+ if (alarm->time.tm_sec) {
+ alarm->time.tm_sec = 0;
+ alarm->time.tm_min++;
+ if (alarm->time.tm_min >= 60) {
+ alarm->time.tm_min = 0;
+ alarm->time.tm_hour++;
+ if (alarm->time.tm_hour >= 24)
+ alarm->time.tm_hour = 0;
+ }
+ }
+
+ alarm->time.tm_mday = -1;
+ alarm->time.tm_mon = -1;
+ alarm->time.tm_year = -1;
+
+ out_8(&regs->alm_min_set, alarm->time.tm_min);
+ out_8(&regs->alm_hour_set, alarm->time.tm_hour);
+
+ out_8(&regs->alm_enable, alarm->enabled);
+
+ rtc->wkalarm = *alarm;
+ return 0;
+}
+
+static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ if (in_8(&regs->int_alm)) {
+ /* acknowledge and clear status */
+ out_8(&regs->int_alm, 1);
+ out_8(&regs->alm_status, 1);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
+ /* acknowledge */
+ out_8(&regs->int_sec, 1);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int val;
+
+ if (enabled)
+ val = 1;
+ else
+ val = 0;
+
+ out_8(&regs->alm_enable, val);
+ rtc->wkalarm.enabled = val;
+
+ return 0;
+}
+
+static int mpc5121_rtc_update_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+ int val;
+
+ val = in_8(&regs->int_enable);
+
+ if (enabled)
+ val = (val & ~0x8) | 0x1;
+ else
+ val &= ~0x1;
+
+ out_8(&regs->int_enable, val);
+
+ return 0;
+}
+
+static const struct rtc_class_ops mpc5121_rtc_ops = {
+ .read_time = mpc5121_rtc_read_time,
+ .set_time = mpc5121_rtc_set_time,
+ .read_alarm = mpc5121_rtc_read_alarm,
+ .set_alarm = mpc5121_rtc_set_alarm,
+ .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
+ .update_irq_enable = mpc5121_rtc_update_irq_enable,
+};
+
+static int __devinit mpc5121_rtc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct mpc5121_rtc_data *rtc;
+ int err = 0;
+ u32 ka;
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->regs = of_iomap(op->dev.of_node, 0);
+ if (!rtc->regs) {
+ dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
+ err = -ENOSYS;
+ goto out_free;
+ }
+
+ device_init_wakeup(&op->dev, 1);
+
+ dev_set_drvdata(&op->dev, rtc);
+
+ rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
+ err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
+ "mpc5121-rtc", &op->dev);
+ if (err) {
+ dev_err(&op->dev, "%s: could not request irq: %i\n",
+ __func__, rtc->irq);
+ goto out_dispose;
+ }
+
+ rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
+ err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
+ IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
+ if (err) {
+ dev_err(&op->dev, "%s: could not request irq: %i\n",
+ __func__, rtc->irq_periodic);
+ goto out_dispose2;
+ }
+
+ ka = in_be32(&rtc->regs->keep_alive);
+ if (ka & 0x02) {
+ dev_warn(&op->dev,
+ "mpc5121-rtc: Battery or oscillator failure!\n");
+ out_be32(&rtc->regs->keep_alive, ka);
+ }
+
+ rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
+ &mpc5121_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ err = PTR_ERR(rtc->rtc);
+ goto out_free_irq;
+ }
+
+ return 0;
+
+out_free_irq:
+ free_irq(rtc->irq_periodic, &op->dev);
+out_dispose2:
+ irq_dispose_mapping(rtc->irq_periodic);
+ free_irq(rtc->irq, &op->dev);
+out_dispose:
+ irq_dispose_mapping(rtc->irq);
+ iounmap(rtc->regs);
+out_free:
+ kfree(rtc);
+
+ return err;
+}
+
+static int __devexit mpc5121_rtc_remove(struct of_device *op)
+{
+ struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
+ struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+ /* disable interrupt, so there are no nasty surprises */
+ out_8(&regs->alm_enable, 0);
+ out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
+
+ rtc_device_unregister(rtc->rtc);
+ iounmap(rtc->regs);
+ free_irq(rtc->irq, &op->dev);
+ free_irq(rtc->irq_periodic, &op->dev);
+ irq_dispose_mapping(rtc->irq);
+ irq_dispose_mapping(rtc->irq_periodic);
+ dev_set_drvdata(&op->dev, NULL);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
+ { .compatible = "fsl,mpc5121-rtc", },
+ {},
+};
+
+static struct of_platform_driver mpc5121_rtc_driver = {
+ .driver = {
+ .name = "mpc5121-rtc",
+ .owner = THIS_MODULE,
+ .of_match_table = mpc5121_rtc_match,
+ },
+ .probe = mpc5121_rtc_probe,
+ .remove = __devexit_p(mpc5121_rtc_remove),
+};
+
+static int __init mpc5121_rtc_init(void)
+{
+ return of_register_platform_driver(&mpc5121_rtc_driver);
+}
+module_init(mpc5121_rtc_init);
+
+static void __exit mpc5121_rtc_exit(void)
+{
+ of_unregister_platform_driver(&mpc5121_rtc_driver);
+}
+module_exit(mpc5121_rtc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c
index 5f5968a48925..b2fff0ca49f8 100644
--- a/drivers/rtc/rtc-msm6242.c
+++ b/drivers/rtc/rtc-msm6242.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/slab.h>
enum {
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index dc052ce6e63a..bcca47298554 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/gfp.h>
#define RTC_TIME_REG_OFFS 0
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
index 6bd5072d4eb7..25ec921db07c 100644
--- a/drivers/rtc/rtc-mxc.c
+++ b/drivers/rtc/rtc-mxc.c
@@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/rtc.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
@@ -378,29 +379,37 @@ static struct rtc_class_ops mxc_rtc_ops = {
static int __init mxc_rtc_probe(struct platform_device *pdev)
{
- struct clk *clk;
struct resource *res;
struct rtc_device *rtc;
struct rtc_plat_data *pdata = NULL;
u32 reg;
- int ret, rate;
+ unsigned long rate;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->ioaddr = ioremap(res->start, resource_size(res));
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
- clk = clk_get(&pdev->dev, "ckil");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ pdata->ioaddr = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
- rate = clk_get_rate(clk);
- clk_put(clk);
+ pdata->clk = clk_get(&pdev->dev, "rtc");
+ if (IS_ERR(pdata->clk)) {
+ dev_err(&pdev->dev, "unable to get clock!\n");
+ ret = PTR_ERR(pdata->clk);
+ goto exit_free_pdata;
+ }
+
+ clk_enable(pdata->clk);
+ rate = clk_get_rate(pdata->clk);
if (rate == 32768)
reg = RTC_INPUT_CLK_32768HZ;
@@ -409,10 +418,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
else if (rate == 38400)
reg = RTC_INPUT_CLK_38400HZ;
else {
- dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n",
- clk_get_rate(clk));
+ dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate);
ret = -EINVAL;
- goto exit_free_pdata;
+ goto exit_put_clk;
}
reg |= RTC_ENABLE_BIT;
@@ -420,18 +428,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
dev_err(&pdev->dev, "hardware module can't be enabled!\n");
ret = -EIO;
- goto exit_free_pdata;
- }
-
- pdata->clk = clk_get(&pdev->dev, "rtc");
- if (IS_ERR(pdata->clk)) {
- dev_err(&pdev->dev, "unable to get clock!\n");
- ret = PTR_ERR(pdata->clk);
- goto exit_free_pdata;
+ goto exit_put_clk;
}
- clk_enable(pdata->clk);
-
rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc)) {
@@ -446,8 +445,8 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
pdata->irq = platform_get_irq(pdev, 0);
if (pdata->irq >= 0 &&
- request_irq(pdata->irq, mxc_rtc_interrupt, IRQF_SHARED,
- pdev->name, pdev) < 0) {
+ devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
+ IRQF_SHARED, pdev->name, pdev) < 0) {
dev_warn(&pdev->dev, "interrupt not available.\n");
pdata->irq = -1;
}
@@ -455,10 +454,10 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
return 0;
exit_put_clk:
+ clk_disable(pdata->clk);
clk_put(pdata->clk);
exit_free_pdata:
- kfree(pdata);
return ret;
}
@@ -469,12 +468,8 @@ static int __exit mxc_rtc_remove(struct platform_device *pdev)
rtc_device_unregister(pdata->rtc);
- if (pdata->irq >= 0)
- free_irq(pdata->irq, pdev);
-
clk_disable(pdata->clk);
clk_put(pdata->clk);
- kfree(pdata);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c
index bf59c9c586b2..a351bd5d8176 100644
--- a/drivers/rtc/rtc-nuc900.c
+++ b/drivers/rtc/rtc-nuc900.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/delay.h>
#include <linux/io.h>
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c
index a99c28992d21..25c0b3fd44f1 100644
--- a/drivers/rtc/rtc-pcap.c
+++ b/drivers/rtc/rtc-pcap.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/mfd/ezx-pcap.h>
#include <linux/rtc.h>
+#include <linux/slab.h>
#include <linux/platform_device.h>
struct pcap_rtc {
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index e75df9d50e27..71bab0ef5443 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -39,6 +39,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
@@ -315,7 +316,7 @@ kfree_exit:
return ret;
}
-static int pcf2123_remove(struct spi_device *spi)
+static int __devexit pcf2123_remove(struct spi_device *spi)
{
struct pcf2123_plat_data *pdata = spi->dev.platform_data;
int i;
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
index 854c3cb365a1..16edf94ab42f 100644
--- a/drivers/rtc/rtc-pcf50633.c
+++ b/drivers/rtc/rtc-pcf50633.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 65f346b2fbae..1af42b4a6f59 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
+#include <linux/slab.h>
#define DRV_VERSION "0.4.3"
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index 457231bb1029..bbdb2f02798a 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/io.h>
+#include <linux/slab.h>
#define RTC_DR (0)
#define RTC_MR (4)
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 0264b117893b..3587d9922f28 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -7,6 +7,9 @@
*
* Copyright 2006 (c) MontaVista Software, Inc.
*
+ * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ * Copyright 2010 (c) ST-Ericsson AB
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -18,6 +21,10 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/io.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/slab.h>
/*
* Register definitions
@@ -30,35 +37,207 @@
#define RTC_RIS 0x14 /* Raw interrupt status register */
#define RTC_MIS 0x18 /* Masked interrupt status register */
#define RTC_ICR 0x1c /* Interrupt clear register */
+/* ST variants have additional timer functionality */
+#define RTC_TDR 0x20 /* Timer data read register */
+#define RTC_TLR 0x24 /* Timer data load register */
+#define RTC_TCR 0x28 /* Timer control register */
+#define RTC_YDR 0x30 /* Year data read register */
+#define RTC_YMR 0x34 /* Year match register */
+#define RTC_YLR 0x38 /* Year data load register */
+
+#define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */
+
+#define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */
+
+/* Common bit definitions for Interrupt status and control registers */
+#define RTC_BIT_AI (1 << 0) /* Alarm interrupt bit */
+#define RTC_BIT_PI (1 << 1) /* Periodic interrupt bit. ST variants only. */
+
+/* Common bit definations for ST v2 for reading/writing time */
+#define RTC_SEC_SHIFT 0
+#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
+#define RTC_MIN_SHIFT 6
+#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
+#define RTC_HOUR_SHIFT 12
+#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
+#define RTC_WDAY_SHIFT 17
+#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
+#define RTC_MDAY_SHIFT 20
+#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
+#define RTC_MON_SHIFT 25
+#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
+
+#define RTC_TIMER_FREQ 32768
struct pl031_local {
struct rtc_device *rtc;
void __iomem *base;
+ u8 hw_designer;
+ u8 hw_revision:4;
};
-static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+static int pl031_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long imsc;
+
+ /* Clear any pending alarm interrupts. */
+ writel(RTC_BIT_AI, ldata->base + RTC_ICR);
+
+ imsc = readl(ldata->base + RTC_IMSC);
+
+ if (enabled == 1)
+ writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC);
+ else
+ writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC);
+
+ return 0;
+}
+
+/*
+ * Convert Gregorian date to ST v2 RTC format.
+ */
+static int pl031_stv2_tm_to_time(struct device *dev,
+ struct rtc_time *tm, unsigned long *st_time,
+ unsigned long *bcd_year)
+{
+ int year = tm->tm_year + 1900;
+ int wday = tm->tm_wday;
+
+ /* wday masking is not working in hardware so wday must be valid */
+ if (wday < -1 || wday > 6) {
+ dev_err(dev, "invalid wday value %d\n", tm->tm_wday);
+ return -EINVAL;
+ } else if (wday == -1) {
+ /* wday is not provided, calculate it here */
+ unsigned long time;
+ struct rtc_time calc_tm;
+
+ rtc_tm_to_time(tm, &time);
+ rtc_time_to_tm(time, &calc_tm);
+ wday = calc_tm.tm_wday;
+ }
+
+ *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
+
+ *st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT)
+ | (tm->tm_mday << RTC_MDAY_SHIFT)
+ | ((wday + 1) << RTC_WDAY_SHIFT)
+ | (tm->tm_hour << RTC_HOUR_SHIFT)
+ | (tm->tm_min << RTC_MIN_SHIFT)
+ | (tm->tm_sec << RTC_SEC_SHIFT);
+
+ return 0;
+}
+
+/*
+ * Convert ST v2 RTC format to Gregorian date.
+ */
+static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
+ struct rtc_time *tm)
+{
+ tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
+ tm->tm_mon = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1;
+ tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
+ tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
+ tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
+ tm->tm_min = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
+ tm->tm_sec = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
+
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_year -= 1900;
+
+ return 0;
+}
+
+static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR),
+ readl(ldata->base + RTC_YDR), tm);
+
+ return 0;
+}
+
+static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long time;
+ unsigned long bcd_year;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year);
+ if (ret == 0) {
+ writel(bcd_year, ldata->base + RTC_YLR);
+ writel(time, ldata->base + RTC_LR);
+ }
+
+ return ret;
+}
+
+static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- struct rtc_device *rtc = dev_id;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
- rtc_update_irq(rtc, 1, RTC_AF);
+ ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR),
+ readl(ldata->base + RTC_YMR), &alarm->time);
- return IRQ_HANDLED;
+ alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+ alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
+
+ return ret;
}
-static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long time;
+ unsigned long bcd_year;
+ int ret;
+
+ /* At the moment, we can only deal with non-wildcarded alarm times. */
+ ret = rtc_valid_tm(&alarm->time);
+ if (ret == 0) {
+ ret = pl031_stv2_tm_to_time(dev, &alarm->time,
+ &time, &bcd_year);
+ if (ret == 0) {
+ writel(bcd_year, ldata->base + RTC_YMR);
+ writel(time, ldata->base + RTC_MR);
+
+ pl031_alarm_irq_enable(dev, alarm->enabled);
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id)
+{
+ struct pl031_local *ldata = dev_id;
+ unsigned long rtcmis;
+ unsigned long events = 0;
+
+ rtcmis = readl(ldata->base + RTC_MIS);
+ if (rtcmis) {
+ writel(rtcmis, ldata->base + RTC_ICR);
+
+ if (rtcmis & RTC_BIT_AI)
+ events |= (RTC_AF | RTC_IRQF);
+
+ /* Timer interrupt is only available in ST variants */
+ if ((rtcmis & RTC_BIT_PI) &&
+ (ldata->hw_designer == AMBA_VENDOR_ST))
+ events |= (RTC_PF | RTC_IRQF);
+
+ rtc_update_irq(ldata->rtc, 1, events);
- switch (cmd) {
- case RTC_AIE_OFF:
- writel(1, ldata->base + RTC_MIS);
- return 0;
- case RTC_AIE_ON:
- writel(0, ldata->base + RTC_MIS);
- return 0;
+ return IRQ_HANDLED;
}
- return -ENOIOCTLCMD;
+ return IRQ_NONE;
}
static int pl031_read_time(struct device *dev, struct rtc_time *tm)
@@ -74,11 +253,14 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned long time;
struct pl031_local *ldata = dev_get_drvdata(dev);
+ int ret;
- rtc_tm_to_time(tm, &time);
- writel(time, ldata->base + RTC_LR);
+ ret = rtc_tm_to_time(tm, &time);
- return 0;
+ if (ret == 0)
+ writel(time, ldata->base + RTC_LR);
+
+ return ret;
}
static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
@@ -86,8 +268,9 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
struct pl031_local *ldata = dev_get_drvdata(dev);
rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time);
- alarm->pending = readl(ldata->base + RTC_RIS);
- alarm->enabled = readl(ldata->base + RTC_IMSC);
+
+ alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
+ alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
return 0;
}
@@ -96,22 +279,71 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct pl031_local *ldata = dev_get_drvdata(dev);
unsigned long time;
+ int ret;
+
+ /* At the moment, we can only deal with non-wildcarded alarm times. */
+ ret = rtc_valid_tm(&alarm->time);
+ if (ret == 0) {
+ ret = rtc_tm_to_time(&alarm->time, &time);
+ if (ret == 0) {
+ writel(time, ldata->base + RTC_MR);
+ pl031_alarm_irq_enable(dev, alarm->enabled);
+ }
+ }
+
+ return ret;
+}
+
+/* Periodic interrupt is only available in ST variants. */
+static int pl031_irq_set_state(struct device *dev, int enabled)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ if (enabled == 1) {
+ /* Clear any pending timer interrupt. */
+ writel(RTC_BIT_PI, ldata->base + RTC_ICR);
+
+ writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI,
+ ldata->base + RTC_IMSC);
- rtc_tm_to_time(&alarm->time, &time);
+ /* Now start the timer */
+ writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN,
+ ldata->base + RTC_TCR);
- writel(time, ldata->base + RTC_MR);
- writel(!alarm->enabled, ldata->base + RTC_MIS);
+ } else {
+ writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI),
+ ldata->base + RTC_IMSC);
+
+ /* Also stop the timer */
+ writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN),
+ ldata->base + RTC_TCR);
+ }
+ /* Wait at least 1 RTC32 clock cycle to ensure next access
+ * to RTC_TCR will succeed.
+ */
+ udelay(40);
return 0;
}
-static const struct rtc_class_ops pl031_ops = {
- .ioctl = pl031_ioctl,
- .read_time = pl031_read_time,
- .set_time = pl031_set_time,
- .read_alarm = pl031_read_alarm,
- .set_alarm = pl031_set_alarm,
-};
+static int pl031_irq_set_freq(struct device *dev, int freq)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ /* Cant set timer if it is already enabled */
+ if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) {
+ dev_err(dev, "can't change frequency while timer enabled\n");
+ return -EINVAL;
+ }
+
+ /* If self start bit in RTC_TCR is set timer will start here,
+ * but we never set that bit. Instead we start the timer when
+ * set_state is called with enabled == 1.
+ */
+ writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR);
+
+ return 0;
+}
static int pl031_remove(struct amba_device *adev)
{
@@ -131,18 +363,20 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
{
int ret;
struct pl031_local *ldata;
+ struct rtc_class_ops *ops = id->data;
ret = amba_request_regions(adev, NULL);
if (ret)
goto err_req;
- ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+ ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
if (!ldata) {
ret = -ENOMEM;
goto out;
}
ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
+
if (!ldata->base) {
ret = -ENOMEM;
goto out_no_remap;
@@ -150,24 +384,36 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)
amba_set_drvdata(adev, ldata);
- if (request_irq(adev->irq[0], pl031_interrupt, IRQF_DISABLED,
- "rtc-pl031", ldata->rtc)) {
- ret = -EIO;
- goto out_no_irq;
- }
+ ldata->hw_designer = amba_manf(adev);
+ ldata->hw_revision = amba_rev(adev);
+
+ dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
+ dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
- ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
- THIS_MODULE);
+ /* Enable the clockwatch on ST Variants */
+ if ((ldata->hw_designer == AMBA_VENDOR_ST) &&
+ (ldata->hw_revision > 1))
+ writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
+ ldata->base + RTC_CR);
+
+ ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
+ THIS_MODULE);
if (IS_ERR(ldata->rtc)) {
ret = PTR_ERR(ldata->rtc);
goto out_no_rtc;
}
+ if (request_irq(adev->irq[0], pl031_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) {
+ ret = -EIO;
+ goto out_no_irq;
+ }
+
return 0;
-out_no_rtc:
- free_irq(adev->irq[0], ldata->rtc);
out_no_irq:
+ rtc_device_unregister(ldata->rtc);
+out_no_rtc:
iounmap(ldata->base);
amba_set_drvdata(adev, NULL);
out_no_remap:
@@ -175,13 +421,57 @@ out_no_remap:
out:
amba_release_regions(adev);
err_req:
+
return ret;
}
+/* Operations for the original ARM version */
+static struct rtc_class_ops arm_pl031_ops = {
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+};
+
+/* The First ST derivative */
+static struct rtc_class_ops stv1_pl031_ops = {
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+ .irq_set_state = pl031_irq_set_state,
+ .irq_set_freq = pl031_irq_set_freq,
+};
+
+/* And the second ST derivative */
+static struct rtc_class_ops stv2_pl031_ops = {
+ .read_time = pl031_stv2_read_time,
+ .set_time = pl031_stv2_set_time,
+ .read_alarm = pl031_stv2_read_alarm,
+ .set_alarm = pl031_stv2_set_alarm,
+ .alarm_irq_enable = pl031_alarm_irq_enable,
+ .irq_set_state = pl031_irq_set_state,
+ .irq_set_freq = pl031_irq_set_freq,
+};
+
static struct amba_id pl031_ids[] __initdata = {
{
.id = 0x00041031,
.mask = 0x000fffff,
+ .data = &arm_pl031_ops,
+ },
+ /* ST Micro variants */
+ {
+ .id = 0x00180031,
+ .mask = 0x00ffffff,
+ .data = &stv1_pl031_ops,
+ },
+ {
+ .id = 0x00280031,
+ .mask = 0x00ffffff,
+ .data = &stv2_pl031_ops,
},
{0, 0},
};
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index e6351b743da6..e9c6fa035989 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -26,6 +26,7 @@
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <mach/hardware.h>
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
index e1313feb060f..a95f733bb15a 100644
--- a/drivers/rtc/rtc-rp5c01.c
+++ b/drivers/rtc/rtc-rp5c01.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/slab.h>
enum {
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index 2099037cb3ea..368d0e63cf83 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/slab.h>
#include <linux/rtc.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 2f2c68d476da..90cf0a6ff23e 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -13,6 +13,7 @@
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/slab.h>
#define DRV_VERSION "0.6"
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index b1a29bcfdf13..789f62f9b47d 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -20,6 +20,7 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/bcd.h>
#include <linux/i2c.h>
@@ -631,7 +632,6 @@ errout_reg:
rtc_device_unregister(rx8025->rtc);
errout_free:
- i2c_set_clientdata(client, NULL);
kfree(rx8025);
errout:
@@ -655,7 +655,6 @@ static int __devexit rx8025_remove(struct i2c_client *client)
rx8025_sysfs_unregister(&client->dev);
rtc_device_unregister(rx8025->rtc);
- i2c_set_clientdata(client, NULL);
kfree(rx8025);
return 0;
}
diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c
index c9522f3bc21c..600b890a3c15 100644
--- a/drivers/rtc/rtc-rx8581.c
+++ b/drivers/rtc/rtc-rx8581.c
@@ -1,8 +1,8 @@
/*
* An I2C driver for the Epson RX8581 RTC
*
- * Author: Martyn Welch <martyn.welch@gefanuc.com>
- * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -168,7 +168,7 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)
return -EIO;
}
- err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
+ err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL,
(data | RX8581_CTRL_STOP));
if (err < 0) {
dev_err(&client->dev, "Unable to write control register\n");
@@ -182,6 +182,20 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)
return -EIO;
}
+ /* get VLF and clear it */
+ data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG);
+ if (data < 0) {
+ dev_err(&client->dev, "Unable to read flag register\n");
+ return -EIO;
+ }
+
+ err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
+ (data & ~(RX8581_FLAG_VLF)));
+ if (err != 0) {
+ dev_err(&client->dev, "Unable to write flag register\n");
+ return -EIO;
+ }
+
/* Restart the clock */
data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL);
if (data < 0) {
@@ -189,8 +203,8 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)
return -EIO;
}
- err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
- (data | ~(RX8581_CTRL_STOP)));
+ err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL,
+ (data & ~(RX8581_CTRL_STOP)));
if (err != 0) {
dev_err(&client->dev, "Unable to write control register\n");
return -EIO;
@@ -272,7 +286,7 @@ static void __exit rx8581_exit(void)
i2c_del_driver(&rx8581_driver);
}
-MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com>");
+MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
MODULE_DESCRIPTION("Epson RX-8581 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index def4d396d0b0..f789e002c9b0 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -275,7 +275,6 @@ exit_dummy:
if (s35390a->client[i])
i2c_unregister_device(s35390a->client[i]);
kfree(s35390a);
- i2c_set_clientdata(client, NULL);
exit:
return err;
@@ -292,7 +291,6 @@ static int s35390a_remove(struct i2c_client *client)
rtc_device_unregister(s35390a->rtc);
kfree(s35390a);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e0d7b9991505..70b68d35f969 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -21,6 +21,7 @@
#include <linux/bcd.h>
#include <linux/clk.h>
#include <linux/log2.h>
+#include <linux/slab.h>
#include <mach/hardware.h>
#include <asm/uaccess.h>
@@ -28,6 +29,11 @@
#include <asm/irq.h>
#include <plat/regs-rtc.h>
+enum s3c_cpu_type {
+ TYPE_S3C2410,
+ TYPE_S3C64XX,
+};
+
/* I have yet to find an S3C implementation with more than one
* of these rtc blocks in */
@@ -36,6 +42,7 @@ static struct resource *s3c_rtc_mem;
static void __iomem *s3c_rtc_base;
static int s3c_rtc_alarmno = NO_IRQ;
static int s3c_rtc_tickno = NO_IRQ;
+static enum s3c_cpu_type s3c_rtc_cpu_type;
static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
@@ -79,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
pr_debug("%s: pie=%d\n", __func__, enabled);
spin_lock_irq(&s3c_rtc_pie_lock);
- tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
- if (enabled)
- tmp |= S3C2410_TICNT_ENABLE;
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+ tmp &= ~S3C64XX_RTCCON_TICEN;
+
+ if (enabled)
+ tmp |= S3C64XX_RTCCON_TICEN;
+
+ writeb(tmp, s3c_rtc_base + S3C2410_RTCCON);
+ } else {
+ tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+ tmp &= ~S3C2410_TICNT_ENABLE;
+
+ if (enabled)
+ tmp |= S3C2410_TICNT_ENABLE;
+
+ writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
+ }
- writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
spin_unlock_irq(&s3c_rtc_pie_lock);
return 0;
@@ -92,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
static int s3c_rtc_setfreq(struct device *dev, int freq)
{
- unsigned int tmp;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
+ unsigned int tmp = 0;
if (!is_power_of_2(freq))
return -EINVAL;
spin_lock_irq(&s3c_rtc_pie_lock);
- tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
- tmp |= (128 / freq)-1;
+ if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+ tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+ tmp &= S3C2410_TICNT_ENABLE;
+ }
+
+ tmp |= (rtc_dev->max_user_freq / freq)-1;
writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
spin_unlock_irq(&s3c_rtc_pie_lock);
@@ -282,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
{
- unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+ unsigned int ticnt;
+
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ ticnt = readb(s3c_rtc_base + S3C2410_RTCCON);
+ ticnt &= S3C64XX_RTCCON_TICEN;
+ } else {
+ ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+ ticnt &= S3C2410_TICNT_ENABLE;
+ }
- seq_printf(seq, "periodic_IRQ\t: %s\n",
- (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
+ seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
return 0;
}
@@ -352,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
if (!en) {
tmp = readb(base + S3C2410_RTCCON);
- writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
-
- tmp = readb(base + S3C2410_TICNT);
- writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+ tmp &= ~S3C64XX_RTCCON_TICEN;
+ tmp &= ~S3C2410_RTCCON_RTCEN;
+ writeb(tmp, base + S3C2410_RTCCON);
+
+ if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+ tmp = readb(base + S3C2410_TICNT);
+ tmp &= ~S3C2410_TICNT_ENABLE;
+ writeb(tmp, base + S3C2410_TICNT);
+ }
} else {
/* re-enable the device, and check it is ok */
@@ -456,8 +495,6 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
pr_debug("s3c2410_rtc: RTCCON=%02x\n",
readb(s3c_rtc_base + S3C2410_RTCCON));
- s3c_rtc_setfreq(&pdev->dev, 1);
-
device_init_wakeup(&pdev->dev, 1);
/* register RTC and exit */
@@ -471,9 +508,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
goto err_nortc;
}
- rtc->max_user_freq = 128;
+ s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
+
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+ rtc->max_user_freq = 32768;
+ else
+ rtc->max_user_freq = 128;
platform_set_drvdata(pdev, rtc);
+
+ s3c_rtc_setfreq(&pdev->dev, 1);
+
return 0;
err_nortc:
@@ -491,20 +536,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
/* RTC Power management control */
-static int ticnt_save;
+static int ticnt_save, ticnt_en_save;
static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
/* save TICNT for anyone using periodic interrupts */
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON);
+ ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+ }
s3c_rtc_enable(pdev, 0);
return 0;
}
static int s3c_rtc_resume(struct platform_device *pdev)
{
+ unsigned int tmp;
+
s3c_rtc_enable(pdev, 1);
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
+ tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+ writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+ }
return 0;
}
#else
@@ -512,13 +567,27 @@ static int s3c_rtc_resume(struct platform_device *pdev)
#define s3c_rtc_resume NULL
#endif
-static struct platform_driver s3c2410_rtc_driver = {
+static struct platform_device_id s3c_rtc_driver_ids[] = {
+ {
+ .name = "s3c2410-rtc",
+ .driver_data = TYPE_S3C2410,
+ }, {
+ .name = "s3c64xx-rtc",
+ .driver_data = TYPE_S3C64XX,
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
+
+static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = __devexit_p(s3c_rtc_remove),
.suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume,
+ .id_table = s3c_rtc_driver_ids,
.driver = {
- .name = "s3c2410-rtc",
+ .name = "s3c-rtc",
.owner = THIS_MODULE,
},
};
@@ -528,12 +597,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics
static int __init s3c_rtc_init(void)
{
printk(banner);
- return platform_driver_register(&s3c2410_rtc_driver);
+ return platform_driver_register(&s3c_rtc_driver);
}
static void __exit s3c_rtc_exit(void)
{
- platform_driver_unregister(&s3c2410_rtc_driver);
+ platform_driver_unregister(&s3c_rtc_driver);
}
module_init(s3c_rtc_init);
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index e95cc6f8d61e..5efbd5990ff8 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/log2.h>
#include <linux/clk.h>
+#include <linux/slab.h>
#include <asm/rtc.h>
#define DRV_NAME "sh-rtc"
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 67700831b5c9..3b943673cd3e 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -1,7 +1,7 @@
/*
* A RTC driver for the Simtek STK17TA8
*
- * By Thomas Hommel <thomas.hommel@gefanuc.com>
+ * By Thomas Hommel <thomas.hommel@ge.com>
*
* Based on the DS1553 driver from
* Atsushi Nemoto <anemo@mba.ocn.ne.jp>
@@ -14,6 +14,7 @@
#include <linux/bcd.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
@@ -243,7 +244,7 @@ static const struct rtc_class_ops stk17ta8_rtc_ops = {
.alarm_irq_enable = stk17ta8_rtc_alarm_irq_enable,
};
-static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
+static ssize_t stk17ta8_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t pos, size_t size)
{
@@ -258,7 +259,7 @@ static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
return count;
}
-static ssize_t stk17ta8_nvram_write(struct kobject *kobj,
+static ssize_t stk17ta8_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t pos, size_t size)
{
@@ -381,7 +382,7 @@ static __exit void stk17ta8_exit(void)
module_init(stk17ta8_init);
module_exit(stk17ta8_exit);
-MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>");
+MODULE_AUTHOR("Thomas Hommel <thomas.hommel@ge.com>");
MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index d7ce1a5c857d..7e7d0c806f2d 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/rtc.h>
+#include <linux/slab.h>
#include <mach/platform.h>
#include <mach/stmp3xxx.h>
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 7dd23a6fc825..380083ca572f 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -107,8 +107,9 @@ rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
char *buf)
{
#ifdef CONFIG_RTC_HCTOSYS_DEVICE
- if (strcmp(dev_name(&to_rtc_device(dev)->dev),
- CONFIG_RTC_HCTOSYS_DEVICE) == 0)
+ if (rtc_hctosys_ret == 0 &&
+ strcmp(dev_name(&to_rtc_device(dev)->dev),
+ CONFIG_RTC_HCTOSYS_DEVICE) == 0)
return sprintf(buf, "1\n");
else
#endif
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index c6a83a2a722c..ed1b86828124 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -57,7 +57,7 @@ enum {
REG_RTC_COMP_LSB_REG,
REG_RTC_COMP_MSB_REG,
};
-const static u8 twl4030_rtc_reg_map[] = {
+static const u8 twl4030_rtc_reg_map[] = {
[REG_SECONDS_REG] = 0x00,
[REG_MINUTES_REG] = 0x01,
[REG_HOURS_REG] = 0x02,
@@ -80,7 +80,7 @@ const static u8 twl4030_rtc_reg_map[] = {
[REG_RTC_COMP_LSB_REG] = 0x10,
[REG_RTC_COMP_MSB_REG] = 0x11,
};
-const static u8 twl6030_rtc_reg_map[] = {
+static const u8 twl6030_rtc_reg_map[] = {
[REG_SECONDS_REG] = 0x00,
[REG_MINUTES_REG] = 0x01,
[REG_HOURS_REG] = 0x02,
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index 9ee81d8aa7c0..ec6313d15359 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/gfp.h>
#include <asm/txx9/tx4939.h>
struct tx4939rtc_plat_data {
@@ -187,7 +188,7 @@ static const struct rtc_class_ops tx4939_rtc_ops = {
.alarm_irq_enable = tx4939_rtc_alarm_irq_enable,
};
-static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj,
+static ssize_t tx4939_rtc_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
@@ -206,7 +207,7 @@ static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj,
return count;
}
-static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj,
+static ssize_t tx4939_rtc_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index bed4cab07043..f71c3ce18036 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -28,6 +28,7 @@
#include <linux/rtc-v3020.h>
#include <linux/delay.h>
#include <linux/gpio.h>
+#include <linux/slab.h>
#include <linux/io.h>
diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c
index 000c7e481e59..82931dc65c0b 100644
--- a/drivers/rtc/rtc-wm831x.c
+++ b/drivers/rtc/rtc-wm831x.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/rtc.h>
+#include <linux/slab.h>
#include <linux/bcd.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
@@ -448,17 +449,17 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
goto err;
}
- ret = wm831x_request_irq(wm831x, per_irq, wm831x_per_irq,
- IRQF_TRIGGER_RISING, "wm831x_rtc_per",
- wm831x_rtc);
+ ret = request_threaded_irq(per_irq, NULL, wm831x_per_irq,
+ IRQF_TRIGGER_RISING, "RTC period",
+ wm831x_rtc);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n",
per_irq, ret);
}
- ret = wm831x_request_irq(wm831x, alm_irq, wm831x_alm_irq,
- IRQF_TRIGGER_RISING, "wm831x_rtc_alm",
- wm831x_rtc);
+ ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq,
+ IRQF_TRIGGER_RISING, "RTC alarm",
+ wm831x_rtc);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
alm_irq, ret);
@@ -477,8 +478,8 @@ static int __devexit wm831x_rtc_remove(struct platform_device *pdev)
int per_irq = platform_get_irq_byname(pdev, "PER");
int alm_irq = platform_get_irq_byname(pdev, "ALM");
- wm831x_free_irq(wm831x_rtc->wm831x, alm_irq, wm831x_rtc);
- wm831x_free_irq(wm831x_rtc->wm831x, per_irq, wm831x_rtc);
+ free_irq(alm_irq, wm831x_rtc);
+ free_irq(per_irq, wm831x_rtc);
rtc_device_unregister(wm831x_rtc->rtc);
kfree(wm831x_rtc);
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
index f1e440521c54..3d0dc76b38af 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -307,11 +307,18 @@ static int wm8350_rtc_update_irq_enable(struct device *dev,
{
struct wm8350 *wm8350 = dev_get_drvdata(dev);
+ /* Suppress duplicate changes since genirq nests enable and
+ * disable calls. */
+ if (enabled == wm8350->rtc.update_enabled)
+ return 0;
+
if (enabled)
wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC);
else
wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
+ wm8350->rtc.update_enabled = enabled;
+
return 0;
}
@@ -478,8 +485,8 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev)
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
struct wm8350_rtc *wm_rtc = &wm8350->rtc;
- wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC);
- wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM);
+ wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350);
+ wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350);
rtc_device_unregister(wm_rtc->rtc);