diff options
Diffstat (limited to 'drivers/rtc')
65 files changed, 3791 insertions, 1275 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cdd97192dc6..f822e13dc04 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -3,10 +3,10 @@ # config RTC_LIB - tristate + bool menuconfig RTC_CLASS - tristate "Real Time Clock" + bool "Real Time Clock" default n depends on !S390 select RTC_LIB @@ -15,9 +15,6 @@ menuconfig RTC_CLASS be allowed to plug one or more RTCs to your system. You will probably want to enable one or more of the interfaces below. - This driver can also be built as a module. If so, the module - will be called rtc-core. - if RTC_CLASS config RTC_HCTOSYS @@ -97,6 +94,18 @@ config RTC_INTF_DEV If unsure, say Y. +config RTC_INTF_DEV_UIE_EMUL + bool "RTC UIE emulation on dev interface" + depends on RTC_INTF_DEV + help + Provides an emulation for RTC_UIE if the underlying rtc chip + driver does not expose RTC_UIE ioctls. Those requests generate + once-per-second update interrupts, used for synchronization. + + The emulation code will read the time from the hardware + clock several times per second, please enable this option + only if you know that you really need it. + config RTC_DRV_TEST tristate "Test driver/device" help @@ -116,6 +125,16 @@ comment "I2C RTC drivers" if I2C +config RTC_DRV_88PM860X + tristate "Marvell 88PM860x" + depends on RTC_CLASS && I2C && MFD_88PM860X + help + If you say yes here you get support for RTC function in Marvell + 88PM860x chips. + + This driver can also be built as a module. If so, the module + will be called rtc-88pm860x. + config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" help @@ -342,12 +361,39 @@ config RTC_DRV_RX8025 This driver can also be built as a module. If so, the module will be called rtc-rx8025. +config RTC_DRV_EM3027 + tristate "EM Microelectronic EM3027" + help + If you say yes here you get support for the EM + Microelectronic EM3027 RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-em3027. + +config RTC_DRV_RV3029C2 + tristate "Micro Crystal RTC" + help + If you say yes here you get support for the Micro Crystal + RV3029-C2 RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-rv3029c2. + endif # I2C comment "SPI RTC drivers" if SPI_MASTER +config RTC_DRV_M41T93 + tristate "ST M41T93" + help + If you say yes here you will get support for the + ST M41T93 SPI RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-m41t93. + config RTC_DRV_M41T94 tristate "ST M41T94" help @@ -636,6 +682,14 @@ config RTC_DRV_WM8350 This driver can also be built as a module. If so, the module will be called "rtc-wm8350". +config RTC_DRV_SPEAR + tristate "SPEAR ST RTC" + depends on PLAT_SPEAR + default y + help + If you say Y here you will get support for the RTC found on + spear + config RTC_DRV_PCF50633 depends on MFD_PCF50633 tristate "NXP PCF50633 RTC" @@ -865,6 +919,13 @@ config RTC_DRV_PXA This RTC driver uses PXA RTC registers available since pxa27x series (RDxR, RYxR) instead of legacy RCNR, RTAR. +config RTC_DRV_VT8500 + tristate "VIA/WonderMedia 85xx SoC RTC" + depends on ARCH_VT8500 + help + If you say Y here you will get access to the real time clock + built into your VIA VT8500 SoC or its relatives. + config RTC_DRV_SUN4V bool "SUN4V Hypervisor RTC" @@ -973,4 +1034,21 @@ config RTC_DRV_LPC32XX This driver can also be buillt as a module. If so, the module will be called rtc-lpc32xx. +config RTC_DRV_TEGRA + tristate "NVIDIA Tegra Internal RTC driver" + depends on RTC_CLASS && ARCH_TEGRA + help + If you say yes here you get support for the + Tegra 200 series internal RTC module. + + This drive can also be built as a module. If so, the module + will be called rtc-tegra. + +config RTC_DRV_TILE + tristate "Tilera hypervisor RTC support" + depends on TILE + help + Enable support for the Linux driver side of the Tilera + hypervisor's real-time clock interface. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2afdaf3ff98..213d725f16d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -2,9 +2,7 @@ # Makefile for RTC class/drivers. # -ifeq ($(CONFIG_RTC_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += rtc-lib.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o @@ -17,6 +15,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o # Keep the list ordered. +obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o @@ -45,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o +obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o @@ -54,6 +54,7 @@ obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o +obj-$(CONFIG_RTC_DRV_M41T93) += rtc-m41t93.o obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o @@ -83,21 +84,26 @@ obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o +obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o +obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o +obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o +obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o +obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index c404b61386b..4194e59e14c 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -41,26 +41,21 @@ static void rtc_device_release(struct device *dev) * system's wall clock; restore it on resume(). */ -static struct timespec delta; static time_t oldtime; +static struct timespec oldts; static int rtc_suspend(struct device *dev, pm_message_t mesg) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; - struct timespec ts = current_kernel_time(); if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; rtc_read_time(rtc, &tm); + ktime_get_ts(&oldts); rtc_tm_to_time(&tm, &oldtime); - /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */ - set_normalized_timespec(&delta, - ts.tv_sec - oldtime, - ts.tv_nsec - (NSEC_PER_SEC >> 1)); - return 0; } @@ -70,10 +65,12 @@ static int rtc_resume(struct device *dev) struct rtc_time tm; time_t newtime; struct timespec time; + struct timespec newts; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; + ktime_get_ts(&newts); rtc_read_time(rtc, &tm); if (rtc_valid_tm(&tm) != 0) { pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); @@ -85,15 +82,13 @@ static int rtc_resume(struct device *dev) pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } + /* calculate the RTC time delta */ + set_normalized_timespec(&time, newtime - oldtime, 0); - /* restore wall clock using delta against this RTC; - * adjust again for avg 1/2 second RTC sampling error - */ - set_normalized_timespec(&time, - newtime + delta.tv_sec, - (NSEC_PER_SEC >> 1) + delta.tv_nsec); - do_settimeofday(&time); + /* subtract kernel time between rtc_suspend to rtc_resume */ + time = timespec_sub(time, timespec_sub(newts, oldts)); + timekeeping_inject_sleeptime(&time); return 0; } @@ -117,6 +112,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, struct module *owner) { struct rtc_device *rtc; + struct rtc_wkalrm alrm; int id, err; if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) { @@ -166,6 +162,12 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; + /* Check to see if there is an ALARM already set in hw */ + err = __rtc_read_alarm(rtc, &alrm); + + if (!err && !rtc_valid_tm(&alrm.time)) + rtc_initialize_alarm(rtc, &alrm); + strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); dev_set_name(&rtc->dev, "rtc%d", id); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a0c01967244..ef6316acec4 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -116,6 +116,186 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) } EXPORT_SYMBOL_GPL(rtc_set_mmss); +static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +{ + int err; + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return err; + + if (rtc->ops == NULL) + err = -ENODEV; + else if (!rtc->ops->read_alarm) + err = -EINVAL; + else { + memset(alarm, 0, sizeof(struct rtc_wkalrm)); + err = rtc->ops->read_alarm(rtc->dev.parent, alarm); + } + + mutex_unlock(&rtc->ops_lock); + return err; +} + +int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +{ + int err; + struct rtc_time before, now; + int first_time = 1; + unsigned long t_now, t_alm; + enum { none, day, month, year } missing = none; + unsigned days; + + /* The lower level RTC driver may return -1 in some fields, + * creating invalid alarm->time values, for reasons like: + * + * - The hardware may not be capable of filling them in; + * many alarms match only on time-of-day fields, not + * day/month/year calendar data. + * + * - Some hardware uses illegal values as "wildcard" match + * values, which non-Linux firmware (like a BIOS) may try + * to set up as e.g. "alarm 15 minutes after each hour". + * Linux uses only oneshot alarms. + * + * When we see that here, we deal with it by using values from + * a current RTC timestamp for any missing (-1) values. The + * RTC driver prevents "periodic alarm" modes. + * + * But this can be racey, because some fields of the RTC timestamp + * may have wrapped in the interval since we read the RTC alarm, + * which would lead to us inserting inconsistent values in place + * of the -1 fields. + * + * Reading the alarm and timestamp in the reverse sequence + * would have the same race condition, and not solve the issue. + * + * So, we must first read the RTC timestamp, + * then read the RTC alarm value, + * and then read a second RTC timestamp. + * + * If any fields of the second timestamp have changed + * when compared with the first timestamp, then we know + * our timestamp may be inconsistent with that used by + * the low-level rtc_read_alarm_internal() function. + * + * So, when the two timestamps disagree, we just loop and do + * the process again to get a fully consistent set of values. + * + * This could all instead be done in the lower level driver, + * but since more than one lower level RTC implementation needs it, + * then it's probably best best to do it here instead of there.. + */ + + /* Get the "before" timestamp */ + err = rtc_read_time(rtc, &before); + if (err < 0) + return err; + do { + if (!first_time) + memcpy(&before, &now, sizeof(struct rtc_time)); + first_time = 0; + + /* get the RTC alarm values, which may be incomplete */ + err = rtc_read_alarm_internal(rtc, alarm); + if (err) + return err; + + /* full-function RTCs won't have such missing fields */ + if (rtc_valid_tm(&alarm->time) == 0) + return 0; + + /* get the "after" timestamp, to detect wrapped fields */ + err = rtc_read_time(rtc, &now); + if (err < 0) + return err; + + /* note that tm_sec is a "don't care" value here: */ + } while ( before.tm_min != now.tm_min + || before.tm_hour != now.tm_hour + || before.tm_mon != now.tm_mon + || before.tm_year != now.tm_year); + + /* Fill in the missing alarm fields using the timestamp; we + * know there's at least one since alarm->time is invalid. + */ + if (alarm->time.tm_sec == -1) + alarm->time.tm_sec = now.tm_sec; + if (alarm->time.tm_min == -1) + alarm->time.tm_min = now.tm_min; + if (alarm->time.tm_hour == -1) + alarm->time.tm_hour = now.tm_hour; + + /* For simplicity, only support date rollover for now */ + if (alarm->time.tm_mday == -1) { + alarm->time.tm_mday = now.tm_mday; + missing = day; + } + if (alarm->time.tm_mon == -1) { + alarm->time.tm_mon = now.tm_mon; + if (missing == none) + missing = month; + } + if (alarm->time.tm_year == -1) { + alarm->time.tm_year = now.tm_year; + if (missing == none) + missing = year; + } + + /* with luck, no rollover is needed */ + rtc_tm_to_time(&now, &t_now); + rtc_tm_to_time(&alarm->time, &t_alm); + if (t_now < t_alm) + goto done; + + switch (missing) { + + /* 24 hour rollover ... if it's now 10am Monday, an alarm that + * that will trigger at 5am will do so at 5am Tuesday, which + * could also be in the next month or year. This is a common + * case, especially for PCs. + */ + case day: + dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); + t_alm += 24 * 60 * 60; + rtc_time_to_tm(t_alm, &alarm->time); + break; + + /* Month rollover ... if it's the 31th, an alarm on the 3rd will + * be next month. An alarm matching on the 30th, 29th, or 28th + * may end up in the month after that! Many newer PCs support + * this type of alarm. + */ + case month: + dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month"); + do { + if (alarm->time.tm_mon < 11) + alarm->time.tm_mon++; + else { + alarm->time.tm_mon = 0; + alarm->time.tm_year++; + } + days = rtc_month_days(alarm->time.tm_mon, + alarm->time.tm_year); + } while (days < alarm->time.tm_mday); + break; + + /* Year rollover ... easy except for leap years! */ + case year: + dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); + do { + alarm->time.tm_year++; + } while (rtc_valid_tm(&alarm->time) != 0); + break; + + default: + dev_warn(&rtc->dev, "alarm rollover not handled\n"); + } + +done: + return 0; +} + int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; @@ -195,6 +375,32 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_set_alarm); +/* Called once per device from rtc_device_register */ +int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +{ + int err; + + err = rtc_valid_tm(&alarm->time); + if (err != 0) + return err; + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return err; + + rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); + rtc->aie_timer.period = ktime_set(0, 0); + if (alarm->enabled) { + rtc->aie_timer.enabled = 1; + timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); + } + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_initialize_alarm); + + + int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) { int err = mutex_lock_interruptible(&rtc->ops_lock); @@ -209,9 +415,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) } if (err) - return err; - - if (!rtc->ops) + /* nothing */; + else if (!rtc->ops) err = -ENODEV; else if (!rtc->ops->alarm_irq_enable) err = -EINVAL; @@ -229,6 +434,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (err) return err; +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + if (enabled == 0 && rtc->uie_irq_active) { + mutex_unlock(&rtc->ops_lock); + return rtc_dev_update_irq_enable_emul(rtc, 0); + } +#endif /* make sure we're changing state */ if (rtc->uie_rtctimer.enabled == enabled) goto out; @@ -248,6 +459,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) out: mutex_unlock(&rtc->ops_lock); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + /* + * Enable emulation if the driver did not provide + * the update_irq_enable function pointer or if returned + * -EINVAL to signal that it has been configured without + * interrupts or that are not available at the moment. + */ + if (err == -EINVAL) + err = rtc_dev_update_irq_enable_emul(rtc, enabled); +#endif return err; } @@ -259,11 +480,11 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); * @rtc: pointer to the rtc device * * This function is called when an AIE, UIE or PIE mode interrupt - * has occured (or been emulated). + * has occurred (or been emulated). * * Triggers the registered irq_task function callback. */ -static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) +void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) { unsigned long flags; diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c new file mode 100644 index 00000000000..64b847b7f97 --- /dev/null +++ b/drivers/rtc/rtc-88pm860x.c @@ -0,0 +1,427 @@ +/* + * Real Time Clock driver for Marvell 88PM860x PMIC + * + * Copyright (c) 2010 Marvell International Ltd. + * Author: 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/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/rtc.h> +#include <linux/delay.h> +#include <linux/mfd/core.h> +#include <linux/mfd/88pm860x.h> + +#define VRTC_CALIBRATION + +struct pm860x_rtc_info { + struct pm860x_chip *chip; + struct i2c_client *i2c; + struct rtc_device *rtc_dev; + struct device *dev; + struct delayed_work calib_work; + + int irq; + int vrtc; + int (*sync)(unsigned int ticks); +}; + +#define REG_VRTC_MEAS1 0x7D + +#define REG0_ADDR 0xB0 +#define REG1_ADDR 0xB2 +#define REG2_ADDR 0xB4 +#define REG3_ADDR 0xB6 + +#define REG0_DATA 0xB1 +#define REG1_DATA 0xB3 +#define REG2_DATA 0xB5 +#define REG3_DATA 0xB7 + +/* bit definitions of Measurement Enable Register 2 (0x51) */ +#define MEAS2_VRTC (1 << 0) + +/* bit definitions of RTC Register 1 (0xA0) */ +#define ALARM_EN (1 << 3) +#define ALARM_WAKEUP (1 << 4) +#define ALARM (1 << 5) +#define RTC1_USE_XO (1 << 7) + +#define VRTC_CALIB_INTERVAL (HZ * 60 * 10) /* 10 minutes */ + +static irqreturn_t rtc_update_handler(int irq, void *data) +{ + struct pm860x_rtc_info *info = (struct pm860x_rtc_info *)data; + int mask; + + mask = ALARM | ALARM_WAKEUP; + pm860x_set_bits(info->i2c, PM8607_RTC1, mask | ALARM_EN, mask); + rtc_update_irq(info->rtc_dev, 1, RTC_AF); + return IRQ_HANDLED; +} + +static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + + if (enabled) + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM); + else + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0); + return 0; +} + +/* + * Calculate the next alarm time given the requested alarm time mask + * and the current time. + */ +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, + struct rtc_time *alrm) +{ + unsigned long next_time; + unsigned long now_time; + + next->tm_year = now->tm_year; + next->tm_mon = now->tm_mon; + next->tm_mday = now->tm_mday; + next->tm_hour = alrm->tm_hour; + next->tm_min = alrm->tm_min; + next->tm_sec = alrm->tm_sec; + + rtc_tm_to_time(now, &now_time); + rtc_tm_to_time(next, &next_time); + + if (next_time < now_time) { + /* Advance one day */ + next_time += 60 * 60 * 24; + rtc_time_to_tm(next_time, next); + } +} + +static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[8]; + unsigned long ticks, base, data; + + pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); + dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + + /* load 32-bit read-only counter */ + pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + ticks = base + data; + dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + rtc_time_to_tm(ticks, tm); + + return 0; +} + +static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[4]; + unsigned long ticks, base, data; + + if ((tm->tm_year < 70) || (tm->tm_year > 138)) { + dev_dbg(info->dev, "Set time %d out of range. " + "Please set time between 1970 to 2038.\n", + 1900 + tm->tm_year); + return -EINVAL; + } + rtc_tm_to_time(tm, &ticks); + + /* load 32-bit read-only counter */ + pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ticks - data; + dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + pm860x_page_reg_write(info->i2c, REG0_DATA, (base >> 24) & 0xFF); + pm860x_page_reg_write(info->i2c, REG1_DATA, (base >> 16) & 0xFF); + pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF); + pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF); + + if (info->sync) + info->sync(ticks); + return 0; +} + +static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[8]; + unsigned long ticks, base, data; + int ret; + + pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); + dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + + pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + ticks = base + data; + dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + rtc_time_to_tm(ticks, &alrm->time); + ret = pm860x_reg_read(info->i2c, PM8607_RTC1); + alrm->enabled = (ret & ALARM_EN) ? 1 : 0; + alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0; + return 0; +} + +static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + struct rtc_time now_tm, alarm_tm; + unsigned long ticks, base, data; + unsigned char buf[8]; + int mask; + + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0); + + pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); + dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + + /* load 32-bit read-only counter */ + pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + ticks = base + data; + dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + rtc_time_to_tm(ticks, &now_tm); + rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time); + /* get new ticks for alarm in 24 hours */ + rtc_tm_to_time(&alarm_tm, &ticks); + data = ticks - base; + + buf[0] = data & 0xff; + buf[1] = (data >> 8) & 0xff; + buf[2] = (data >> 16) & 0xff; + buf[3] = (data >> 24) & 0xff; + pm860x_bulk_write(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); + if (alrm->enabled) { + mask = ALARM | ALARM_WAKEUP | ALARM_EN; + pm860x_set_bits(info->i2c, PM8607_RTC1, mask, mask); + } else { + mask = ALARM | ALARM_WAKEUP | ALARM_EN; + pm860x_set_bits(info->i2c, PM8607_RTC1, mask, + ALARM | ALARM_WAKEUP); + } + return 0; +} + +static const struct rtc_class_ops pm860x_rtc_ops = { + .read_time = pm860x_rtc_read_time, + .set_time = pm860x_rtc_set_time, + .read_alarm = pm860x_rtc_read_alarm, + .set_alarm = pm860x_rtc_set_alarm, + .alarm_irq_enable = pm860x_rtc_alarm_irq_enable, +}; + +#ifdef VRTC_CALIBRATION +static void calibrate_vrtc_work(struct work_struct *work) +{ + struct pm860x_rtc_info *info = container_of(work, + struct pm860x_rtc_info, calib_work.work); + unsigned char buf[2]; + unsigned int sum, data, mean, vrtc_set; + int i; + + for (i = 0, sum = 0; i < 16; i++) { + msleep(100); + pm860x_bulk_read(info->i2c, REG_VRTC_MEAS1, 2, buf); + data = (buf[0] << 4) | buf[1]; + data = (data * 5400) >> 12; /* convert to mv */ + sum += data; + } + mean = sum >> 4; + vrtc_set = 2700 + (info->vrtc & 0x3) * 200; + dev_dbg(info->dev, "mean:%d, vrtc_set:%d\n", mean, vrtc_set); + + sum = pm860x_reg_read(info->i2c, PM8607_RTC_MISC1); + data = sum & 0x3; + if ((mean + 200) < vrtc_set) { + /* try higher voltage */ + if (++data == 4) + goto out; + data = (sum & 0xf8) | (data & 0x3); + pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data); + } else if ((mean - 200) > vrtc_set) { + /* try lower voltage */ + if (data-- == 0) + goto out; + data = (sum & 0xf8) | (data & 0x3); + pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data); + } else + goto out; + dev_dbg(info->dev, "set 0x%x to RTC_MISC1\n", data); + /* trigger next calibration since VRTC is updated */ + schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL); + return; +out: + /* disable measurement */ + pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); + dev_dbg(info->dev, "finish VRTC calibration\n"); + return; +} +#endif + +static int __devinit pm860x_rtc_probe(struct platform_device *pdev) +{ + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm860x_rtc_pdata *pdata = NULL; + struct pm860x_rtc_info *info; + struct rtc_time tm; + unsigned long ticks = 0; + int ret; + + pdata = pdev->dev.platform_data; + if (pdata == NULL) + dev_warn(&pdev->dev, "No platform data!\n"); + + info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + ret = -EINVAL; + goto out; + } + + info->chip = chip; + info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + info->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, info); + + ret = request_threaded_irq(info->irq, NULL, rtc_update_handler, + IRQF_ONESHOT, "rtc", info); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + info->irq, ret); + goto out; + } + + /* set addresses of 32-bit base value for RTC time */ + pm860x_page_reg_write(info->i2c, REG0_ADDR, REG0_DATA); + pm860x_page_reg_write(info->i2c, REG1_ADDR, REG1_DATA); + pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA); + pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA); + + ret = pm860x_rtc_read_time(&pdev->dev, &tm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read initial time.\n"); + goto out_rtc; + } + if ((tm.tm_year < 70) || (tm.tm_year > 138)) { + tm.tm_year = 70; + tm.tm_mon = 0; + tm.tm_mday = 1; + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + ret = pm860x_rtc_set_time(&pdev->dev, &tm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to set initial time.\n"); + goto out_rtc; + } + } + rtc_tm_to_time(&tm, &ticks); + if (pdata && pdata->sync) { + pdata->sync(ticks); + info->sync = pdata->sync; + } + + info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev, + &pm860x_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; + } + + /* + * enable internal XO instead of internal 3.25MHz clock since it can + * free running in PMIC power-down state. + */ + pm860x_set_bits(info->i2c, PM8607_RTC1, RTC1_USE_XO, RTC1_USE_XO); + +#ifdef VRTC_CALIBRATION + /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ + if (pdata && pdata->vrtc) + info->vrtc = pdata->vrtc & 0x3; + else + info->vrtc = 1; + pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); + + /* calibrate VRTC */ + INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work); + schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL); +#endif /* VRTC_CALIBRATION */ + return 0; +out_rtc: + free_irq(info->irq, info); +out: + kfree(info); + return ret; +} + +static int __devexit pm860x_rtc_remove(struct platform_device *pdev) +{ + struct pm860x_rtc_info *info = platform_get_drvdata(pdev); + +#ifdef VRTC_CALIBRATION + flush_scheduled_work(); + /* disable measurement */ + pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); +#endif /* VRTC_CALIBRATION */ + + platform_set_drvdata(pdev, NULL); + rtc_device_unregister(info->rtc_dev); + free_irq(info->irq, info); + kfree(info); + return 0; +} + +static struct platform_driver pm860x_rtc_driver = { + .driver = { + .name = "88pm860x-rtc", + .owner = THIS_MODULE, + }, + .probe = pm860x_rtc_probe, + .remove = __devexit_p(pm860x_rtc_remove), +}; + +static int __init pm860x_rtc_init(void) +{ + return platform_driver_register(&pm860x_rtc_driver); +} +module_init(pm860x_rtc_init); + +static void __exit pm860x_rtc_exit(void) +{ + platform_driver_unregister(&pm860x_rtc_driver); +} +module_exit(pm860x_rtc_exit); + +MODULE_DESCRIPTION("Marvell 88PM860x RTC driver"); +MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index b2752b6e7a2..e725d51e773 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -134,36 +134,29 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static int at32_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); int ret = 0; spin_lock_irq(&rtc->lock); - switch (cmd) { - case RTC_AIE_ON: + if(enabled) { if (rtc_readl(rtc, VAL) > rtc->alarm_time) { ret = -EINVAL; - break; + goto out; } rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | RTC_BIT(CTRL_TOPEN)); rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); rtc_writel(rtc, IER, RTC_BIT(IER_TOPI)); - break; - case RTC_AIE_OFF: + } else { rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) & ~RTC_BIT(CTRL_TOPEN)); rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); - break; - default: - ret = -ENOIOCTLCMD; - break; } - +out: spin_unlock_irq(&rtc->lock); return ret; @@ -195,11 +188,11 @@ static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id) } static struct rtc_class_ops at32_rtc_ops = { - .ioctl = at32_rtc_ioctl, .read_time = at32_rtc_readtime, .set_time = at32_rtc_settime, .read_alarm = at32_rtc_readalarm, .set_alarm = at32_rtc_setalarm, + .alarm_irq_enable = at32_rtc_alarm_irq_enable, }; static int __init at32_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index bc8bbca9a2e..e39b77a4609 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -60,7 +60,7 @@ static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg, /* * The Calendar Alarm register does not have a field for * the year - so these will return an invalid value. When an - * alarm is set, at91_alarm_year wille store the current year. + * alarm is set, at91_alarm_year will store the current year. */ tm->tm_year = bcd2bin(date & AT91_RTC_CENT) * 100; /* century */ tm->tm_year += bcd2bin((date & AT91_RTC_YEAR) >> 8); /* year */ @@ -183,40 +183,18 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) return 0; } -/* - * Handle commands from user-space - */ -static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - int ret = 0; + pr_debug("%s(): cmd=%08x\n", __func__, enabled); - pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg); - - /* important: scrub old status before enabling IRQs */ - switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM); - break; - case RTC_AIE_ON: /* alarm on */ + if (enabled) { at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM); at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); - break; - case RTC_UIE_OFF: /* update off */ - at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV); - break; - case RTC_UIE_ON: /* update on */ - at91_sys_write(AT91_RTC_SCCR, AT91_RTC_SECEV); - at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV); - break; - default: - ret = -ENOIOCTLCMD; - break; - } + } else + at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM); - return ret; + return 0; } - /* * Provide additional RTC information in /proc/driver/rtc */ @@ -264,12 +242,12 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) } static const struct rtc_class_ops at91_rtc_ops = { - .ioctl = at91_rtc_ioctl, .read_time = at91_rtc_readtime, .set_time = at91_rtc_settime, .read_alarm = at91_rtc_readalarm, .set_alarm = at91_rtc_setalarm, .proc = at91_rtc_proc, + .alarm_irq_enable = at91_rtc_alarm_irq_enable, }; /* diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index f677e0710ca..a3ad957507d 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -216,37 +216,17 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) return 0; } -/* - * Handle commands from user-space - */ -static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct sam9_rtc *rtc = dev_get_drvdata(dev); - int ret = 0; u32 mr = rtt_readl(rtc, MR); - dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr); - - switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); - break; - case RTC_AIE_ON: /* alarm on */ + dev_dbg(dev, "alarm_irq_enable: enabled=%08x, mr %08x\n", enabled, mr); + if (enabled) rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); - break; - case RTC_UIE_OFF: /* update off */ - rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); - break; - case RTC_UIE_ON: /* update on */ - rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN); - break; - default: - ret = -ENOIOCTLCMD; - break; - } - - return ret; + else + rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); + return 0; } /* @@ -296,12 +276,12 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) } static const struct rtc_class_ops at91_rtc_ops = { - .ioctl = at91_rtc_ioctl, .read_time = at91_rtc_readtime, .set_time = at91_rtc_settime, .read_alarm = at91_rtc_readalarm, .set_alarm = at91_rtc_setalarm, .proc = at91_rtc_proc, + .alarm_irq_enable = at91_rtc_alarm_irq_enable, }; /* diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index b4b6087f223..90d866272c8 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -20,9 +20,9 @@ * write would be discarded and things quickly fall apart. * * To keep this delay from significantly degrading performance (we, in theory, - * would have to sleep for up to 1 second everytime we wanted to write a + * would have to sleep for up to 1 second every time we wanted to write a * register), we only check the write pending status before we start to issue - * a new write. We bank on the idea that it doesnt matter when the sync + * a new write. We bank on the idea that it doesn't matter when the sync * happens so long as we don't attempt another write before it does. The only * time userspace would take this penalty is when they try and do multiple * operations right after another ... but in this case, they need to take the @@ -240,40 +240,18 @@ static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc) */ bfin_rtc_int_set(rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY); } -static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) + +static int bfin_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct bfin_rtc *rtc = dev_get_drvdata(dev); - int ret = 0; dev_dbg_stamp(dev); - - bfin_rtc_sync_pending(dev); - - switch (cmd) { - case RTC_UIE_ON: - dev_dbg_stamp(dev); - bfin_rtc_int_set(RTC_ISTAT_SEC); - break; - case RTC_UIE_OFF: - dev_dbg_stamp(dev); - bfin_rtc_int_clear(~RTC_ISTAT_SEC); - break; - - case RTC_AIE_ON: - dev_dbg_stamp(dev); + if (enabled) bfin_rtc_int_set_alarm(rtc); - break; - case RTC_AIE_OFF: - dev_dbg_stamp(dev); + else bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); - break; - default: - dev_dbg_stamp(dev); - ret = -ENOIOCTLCMD; - } - - return ret; + return 0; } static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -356,12 +334,12 @@ static int bfin_rtc_proc(struct device *dev, struct seq_file *seq) } static struct rtc_class_ops bfin_rtc_ops = { - .ioctl = bfin_rtc_ioctl, .read_time = bfin_rtc_read_time, .set_time = bfin_rtc_set_time, .read_alarm = bfin_rtc_read_alarm, .set_alarm = bfin_rtc_set_alarm, .proc = bfin_rtc_proc, + .alarm_irq_enable = bfin_rtc_alarm_irq_enable, }; static int __devinit bfin_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index c7ff8df347e..911e75cdc12 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -37,6 +37,8 @@ #include <linux/mod_devicetable.h> #include <linux/log2.h> #include <linux/pm.h> +#include <linux/of.h> +#include <linux/of_platform.h> /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <asm-generic/rtc.h> @@ -375,50 +377,6 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -static int cmos_irq_set_freq(struct device *dev, int freq) -{ - struct cmos_rtc *cmos = dev_get_drvdata(dev); - int f; - unsigned long flags; - - if (!is_valid_irq(cmos->irq)) - return -ENXIO; - - if (!is_power_of_2(freq)) - return -EINVAL; - /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */ - f = ffs(freq); - if (f-- > 16) - return -EINVAL; - f = 16 - f; - - spin_lock_irqsave(&rtc_lock, flags); - hpet_set_periodic_freq(freq); - CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); - spin_unlock_irqrestore(&rtc_lock, flags); - - return 0; -} - -static int cmos_irq_set_state(struct device *dev, int enabled) -{ - struct cmos_rtc *cmos = dev_get_drvdata(dev); - unsigned long flags; - - if (!is_valid_irq(cmos->irq)) - return -ENXIO; - - spin_lock_irqsave(&rtc_lock, flags); - - if (enabled) - cmos_irq_enable(cmos, RTC_PIE); - else - cmos_irq_disable(cmos, RTC_PIE); - - spin_unlock_irqrestore(&rtc_lock, flags); - return 0; -} - static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -438,25 +396,6 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int cmos_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct cmos_rtc *cmos = dev_get_drvdata(dev); - unsigned long flags; - - if (!is_valid_irq(cmos->irq)) - return -EINVAL; - - spin_lock_irqsave(&rtc_lock, flags); - - if (enabled) - cmos_irq_enable(cmos, RTC_UIE); - else - cmos_irq_disable(cmos, RTC_UIE); - - spin_unlock_irqrestore(&rtc_lock, flags); - return 0; -} - #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) static int cmos_procfs(struct device *dev, struct seq_file *seq) @@ -501,10 +440,7 @@ static const struct rtc_class_ops cmos_rtc_ops = { .read_alarm = cmos_read_alarm, .set_alarm = cmos_set_alarm, .proc = cmos_procfs, - .irq_set_freq = cmos_irq_set_freq, - .irq_set_state = cmos_irq_set_state, .alarm_irq_enable = cmos_alarm_irq_enable, - .update_irq_enable = cmos_update_irq_enable, }; /*----------------------------------------------------------------*/ @@ -1123,6 +1059,47 @@ static struct pnp_driver cmos_pnp_driver = { #endif /* CONFIG_PNP */ +#ifdef CONFIG_OF +static const struct of_device_id of_cmos_match[] = { + { + .compatible = "motorola,mc146818", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_cmos_match); + +static __init void cmos_of_init(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct rtc_time time; + int ret; + const __be32 *val; + + if (!node) + return; + + val = of_get_property(node, "ctrl-reg", NULL); + if (val) + CMOS_WRITE(be32_to_cpup(val), RTC_CONTROL); + + val = of_get_property(node, "freq-reg", NULL); + if (val) + CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT); + + get_rtc_time(&time); + ret = rtc_valid_tm(&time); + if (ret) { + struct rtc_time def_time = { + .tm_year = 1, + .tm_mday = 1, + }; + set_rtc_time(&def_time); + } +} +#else +static inline void cmos_of_init(struct platform_device *pdev) {} +#define of_cmos_match NULL +#endif /*----------------------------------------------------------------*/ /* Platform setup should have set up an RTC device, when PNP is @@ -1131,6 +1108,7 @@ static struct pnp_driver cmos_pnp_driver = { static int __init cmos_platform_probe(struct platform_device *pdev) { + cmos_of_init(pdev); cmos_wake_setup(&pdev->dev); return cmos_do_probe(&pdev->dev, platform_get_resource(pdev, IORESOURCE_IO, 0), @@ -1162,6 +1140,7 @@ static struct platform_driver cmos_platform_driver = { #ifdef CONFIG_PM .pm = &cmos_pm_ops, #endif + .of_match_table = of_cmos_match, } }; diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 316f484999b..80f9c88214c 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -220,6 +220,7 @@ static int __init coh901331_probe(struct platform_device *pdev) } clk_disable(rtap->clk); + platform_set_drvdata(pdev, rtap); rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, THIS_MODULE); if (IS_ERR(rtap->rtc)) { @@ -227,11 +228,10 @@ static int __init coh901331_probe(struct platform_device *pdev) goto out_no_rtc; } - platform_set_drvdata(pdev, rtap); - return 0; out_no_rtc: + platform_set_drvdata(pdev, NULL); out_no_clk_enable: clk_put(rtap->clk); out_no_clk: diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 34647fc1ee9..755e1fe914a 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -231,10 +231,6 @@ davinci_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 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; } @@ -473,55 +469,6 @@ static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) 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, @@ -529,8 +476,6 @@ static struct rtc_class_ops davinci_rtc_ops = { .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) @@ -579,6 +524,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) goto fail2; } + platform_set_drvdata(pdev, davinci_rtc); + davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &davinci_rtc_ops, THIS_MODULE); if (IS_ERR(davinci_rtc->rtc)) { @@ -608,8 +555,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) 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; @@ -617,6 +562,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) fail4: rtc_device_unregister(davinci_rtc->rtc); fail3: + platform_set_drvdata(pdev, NULL); iounmap(davinci_rtc->base); fail2: release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 212b16edafc..d0e06edb14c 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -46,6 +46,105 @@ static int rtc_dev_open(struct inode *inode, struct file *file) return err; } +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL +/* + * Routine to poll RTC seconds field for change as often as possible, + * after first RTC_UIE use timer to reduce polling + */ +static void rtc_uie_task(struct work_struct *work) +{ + struct rtc_device *rtc = + container_of(work, struct rtc_device, uie_task); + struct rtc_time tm; + int num = 0; + int err; + + err = rtc_read_time(rtc, &tm); + + spin_lock_irq(&rtc->irq_lock); + if (rtc->stop_uie_polling || err) { + rtc->uie_task_active = 0; + } else if (rtc->oldsecs != tm.tm_sec) { + num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; + rtc->oldsecs = tm.tm_sec; + rtc->uie_timer.expires = jiffies + HZ - (HZ/10); + rtc->uie_timer_active = 1; + rtc->uie_task_active = 0; + add_timer(&rtc->uie_timer); + } else if (schedule_work(&rtc->uie_task) == 0) { + rtc->uie_task_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + if (num) + rtc_handle_legacy_irq(rtc, num, RTC_UF); +} +static void rtc_uie_timer(unsigned long data) +{ + struct rtc_device *rtc = (struct rtc_device *)data; + unsigned long flags; + + spin_lock_irqsave(&rtc->irq_lock, flags); + rtc->uie_timer_active = 0; + rtc->uie_task_active = 1; + if ((schedule_work(&rtc->uie_task) == 0)) + rtc->uie_task_active = 0; + spin_unlock_irqrestore(&rtc->irq_lock, flags); +} + +static int clear_uie(struct rtc_device *rtc) +{ + spin_lock_irq(&rtc->irq_lock); + if (rtc->uie_irq_active) { + rtc->stop_uie_polling = 1; + if (rtc->uie_timer_active) { + spin_unlock_irq(&rtc->irq_lock); + del_timer_sync(&rtc->uie_timer); + spin_lock_irq(&rtc->irq_lock); + rtc->uie_timer_active = 0; + } + if (rtc->uie_task_active) { + spin_unlock_irq(&rtc->irq_lock); + flush_scheduled_work(); + spin_lock_irq(&rtc->irq_lock); + } + rtc->uie_irq_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +static int set_uie(struct rtc_device *rtc) +{ + struct rtc_time tm; + int err; + + err = rtc_read_time(rtc, &tm); + if (err) + return err; + spin_lock_irq(&rtc->irq_lock); + if (!rtc->uie_irq_active) { + rtc->uie_irq_active = 1; + rtc->stop_uie_polling = 0; + rtc->oldsecs = tm.tm_sec; + rtc->uie_task_active = 1; + if (schedule_work(&rtc->uie_task) == 0) + rtc->uie_task_active = 0; + } + rtc->irq_data = 0; + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) +{ + if (enabled) + return set_uie(rtc); + else + return clear_uie(rtc); +} +EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); + +#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ static ssize_t rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -154,19 +253,7 @@ static long rtc_dev_ioctl(struct file *file, if (err) goto done; - /* try the driver's ioctl interface */ - if (ops->ioctl) { - err = ops->ioctl(rtc->dev.parent, cmd, arg); - if (err != -ENOIOCTLCMD) { - mutex_unlock(&rtc->ops_lock); - return err; - } - } - - /* if the driver does not provide the ioctl interface - * or if that particular ioctl was not implemented - * (-ENOIOCTLCMD), we will try to emulate here. - * + /* * Drivers *SHOULD NOT* provide ioctl implementations * for these requests. Instead, provide methods to * support the following code, so that the RTC's main @@ -329,7 +416,12 @@ static long rtc_dev_ioctl(struct file *file, return err; default: - err = -ENOTTY; + /* Finally try the driver's ioctl interface */ + if (ops->ioctl) { + err = ops->ioctl(rtc->dev.parent, cmd, arg); + if (err == -ENOIOCTLCMD) + err = -ENOTTY; + } break; } @@ -394,6 +486,11 @@ void rtc_dev_prepare(struct rtc_device *rtc) rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + INIT_WORK(&rtc->uie_task, rtc_uie_task); + setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); +#endif + cdev_init(&rtc->char_dev, &rtc_dev_fops); rtc->char_dev.owner = rtc->owner; } diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index bf430f9091e..47e681df31e 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -40,6 +40,26 @@ static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg) __raw_writel(data, &priv->rtcregs[reg]); } + +static int ds1286_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1286_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + unsigned char val; + + /* Allow or mask alarm interrupts */ + spin_lock_irqsave(&priv->lock, flags); + val = ds1286_rtc_read(priv, RTC_CMD); + if (enabled) + val &= ~RTC_TDM; + else + val |= RTC_TDM; + ds1286_rtc_write(priv, val, RTC_CMD); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + #ifdef CONFIG_RTC_INTF_DEV static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) @@ -49,22 +69,6 @@ static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) unsigned char val; switch (cmd) { - case RTC_AIE_OFF: - /* Mask alarm int. enab. bit */ - spin_lock_irqsave(&priv->lock, flags); - val = ds1286_rtc_read(priv, RTC_CMD); - val |= RTC_TDM; - ds1286_rtc_write(priv, val, RTC_CMD); - spin_unlock_irqrestore(&priv->lock, flags); - break; - case RTC_AIE_ON: - /* Allow alarm interrupts. */ - spin_lock_irqsave(&priv->lock, flags); - val = ds1286_rtc_read(priv, RTC_CMD); - val &= ~RTC_TDM; - ds1286_rtc_write(priv, val, RTC_CMD); - spin_unlock_irqrestore(&priv->lock, flags); - break; case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */ spin_lock_irqsave(&priv->lock, flags); @@ -316,12 +320,13 @@ static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm) } static const struct rtc_class_ops ds1286_ops = { - .ioctl = ds1286_ioctl, - .proc = ds1286_proc, + .ioctl = ds1286_ioctl, + .proc = ds1286_proc, .read_time = ds1286_read_time, .set_time = ds1286_set_time, .read_alarm = ds1286_read_alarm, .set_alarm = ds1286_set_alarm, + .alarm_irq_enable = ds1286_alarm_irq_enable, }; static int __devinit ds1286_probe(struct platform_device *pdev) @@ -350,6 +355,7 @@ static int __devinit ds1286_probe(struct platform_device *pdev) goto out; } spin_lock_init(&priv->lock); + platform_set_drvdata(pdev, priv); rtc = rtc_device_register("ds1286", &pdev->dev, &ds1286_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -357,7 +363,6 @@ static int __devinit ds1286_probe(struct platform_device *pdev) goto out; } priv->rtc = rtc; - platform_set_drvdata(pdev, priv); return 0; out: diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 077af1d7b9e..57fbcc149ba 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -139,49 +139,32 @@ static u8 hour2bcd(bool hr12, int hour) * Interface to RTC framework */ -#ifdef CONFIG_RTC_INTF_DEV - -/* - * Context: caller holds rtc->ops_lock (to protect ds1305->ctrl) - */ -static int ds1305_ioctl(struct device *dev, unsigned cmd, unsigned long arg) +static int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct ds1305 *ds1305 = dev_get_drvdata(dev); u8 buf[2]; - int status = -ENOIOCTLCMD; + long err = -EINVAL; buf[0] = DS1305_WRITE | DS1305_CONTROL; buf[1] = ds1305->ctrl[0]; - switch (cmd) { - case RTC_AIE_OFF: - status = 0; - if (!(buf[1] & DS1305_AEI0)) - goto done; - buf[1] &= ~DS1305_AEI0; - break; - - case RTC_AIE_ON: - status = 0; + if (enabled) { if (ds1305->ctrl[0] & DS1305_AEI0) goto done; buf[1] |= DS1305_AEI0; - break; - } - if (status == 0) { - status = spi_write_then_read(ds1305->spi, buf, sizeof buf, - NULL, 0); - if (status >= 0) - ds1305->ctrl[0] = buf[1]; + } else { + if (!(buf[1] & DS1305_AEI0)) + goto done; + buf[1] &= ~DS1305_AEI0; } - + err = spi_write_then_read(ds1305->spi, buf, sizeof buf, NULL, 0); + if (err >= 0) + ds1305->ctrl[0] = buf[1]; done: - return status; + return err; + } -#else -#define ds1305_ioctl NULL -#endif /* * Get/set of date and time is pretty normal. @@ -460,12 +443,12 @@ done: #endif static const struct rtc_class_ops ds1305_ops = { - .ioctl = ds1305_ioctl, .read_time = ds1305_get_time, .set_time = ds1305_set_time, .read_alarm = ds1305_get_alarm, .set_alarm = ds1305_set_alarm, .proc = ds1305_proc, + .alarm_irq_enable = ds1305_alarm_irq_enable, }; static void ds1305_work(struct work_struct *work) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 0d559b6416d..4724ba3acf1 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -495,50 +495,27 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); int ret; - switch (cmd) { - case RTC_AIE_OFF: - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -ENOTTY; - - ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); - if (ret < 0) - return ret; - - ret &= ~DS1337_BIT_A1IE; - - ret = i2c_smbus_write_byte_data(client, - DS1337_REG_CONTROL, ret); - if (ret < 0) - return ret; - - break; - - case RTC_AIE_ON: - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -ENOTTY; + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -ENOTTY; - ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); - if (ret < 0) - return ret; + ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); + if (ret < 0) + return ret; + if (enabled) ret |= DS1337_BIT_A1IE; + else + ret &= ~DS1337_BIT_A1IE; - ret = i2c_smbus_write_byte_data(client, - DS1337_REG_CONTROL, ret); - if (ret < 0) - return ret; - - break; - - default: - return -ENOIOCTLCMD; - } + ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret); + if (ret < 0) + return ret; return 0; } @@ -548,7 +525,7 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { .set_time = ds1307_set_time, .read_alarm = ds1337_read_alarm, .set_alarm = ds1337_set_alarm, - .ioctl = ds1307_ioctl, + .alarm_irq_enable = ds1307_alarm_irq_enable, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 47fb6357c34..e6e71deb188 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -25,6 +25,7 @@ #include <linux/bcd.h> #include <linux/workqueue.h> #include <linux/slab.h> +#include <linux/pm.h> #define DS1374_REG_TOD0 0x00 /* Time of Day */ #define DS1374_REG_TOD1 0x01 @@ -307,42 +308,25 @@ unlock: mutex_unlock(&ds1374->mutex); } -static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct ds1374 *ds1374 = i2c_get_clientdata(client); - int ret = -ENOIOCTLCMD; + int ret; mutex_lock(&ds1374->mutex); - switch (cmd) { - case RTC_AIE_OFF: - ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); - if (ret < 0) - goto out; - - ret &= ~DS1374_REG_CR_WACE; - - ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); - if (ret < 0) - goto out; - - break; - - case RTC_AIE_ON: - ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); - if (ret < 0) - goto out; + ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); + if (ret < 0) + goto out; + if (enabled) { ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; ret &= ~DS1374_REG_CR_WDALM; - - ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); - if (ret < 0) - goto out; - - break; + } else { + ret &= ~DS1374_REG_CR_WACE; } + ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); out: mutex_unlock(&ds1374->mutex); @@ -354,7 +338,7 @@ static const struct rtc_class_ops ds1374_rtc_ops = { .set_time = ds1374_set_time, .read_alarm = ds1374_read_alarm, .set_alarm = ds1374_set_alarm, - .ioctl = ds1374_ioctl, + .alarm_irq_enable = ds1374_alarm_irq_enable, }; static int ds1374_probe(struct i2c_client *client, @@ -426,32 +410,38 @@ static int __devexit ds1374_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int ds1374_suspend(struct i2c_client *client, pm_message_t state) +static int ds1374_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + if (client->irq >= 0 && device_may_wakeup(&client->dev)) enable_irq_wake(client->irq); return 0; } -static int ds1374_resume(struct i2c_client *client) +static int ds1374_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + if (client->irq >= 0 && device_may_wakeup(&client->dev)) disable_irq_wake(client->irq); return 0; } + +static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume); + +#define DS1374_PM (&ds1374_pm) #else -#define ds1374_suspend NULL -#define ds1374_resume NULL +#define DS1374_PM NULL #endif static struct i2c_driver ds1374_driver = { .driver = { .name = "rtc-ds1374", .owner = THIS_MODULE, + .pm = DS1374_PM, }, .probe = ds1374_probe, - .suspend = ds1374_suspend, - .resume = ds1374_resume, .remove = __devexit_p(ds1374_remove), .id_table = ds1374_id, }; diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 26a86d23505..b038d2cfef2 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -158,7 +158,7 @@ static int __devinit ds1390_probe(struct spi_device *spi) static int __devexit ds1390_remove(struct spi_device *spi) { - struct ds1390 *chip = platform_get_drvdata(spi); + struct ds1390 *chip = spi_get_drvdata(spi); rtc_device_unregister(chip->rtc); kfree(chip); diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 37268e97de4..fbabc773dde 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -397,29 +397,12 @@ static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int ds1511_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - struct platform_device *pdev = to_platform_device(dev); - struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - - if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_UF; - else - pdata->irqen &= ~RTC_UF; - ds1511_rtc_update_alarm(pdata); - return 0; -} - static const struct rtc_class_ops ds1511_rtc_ops = { .read_time = ds1511_rtc_read_time, .set_time = ds1511_rtc_set_time, .read_alarm = ds1511_rtc_read_alarm, .set_alarm = ds1511_rtc_set_alarm, .alarm_irq_enable = ds1511_rtc_alarm_irq_enable, - .update_irq_enable = ds1511_rtc_update_irq_enable, }; static ssize_t @@ -485,7 +468,7 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj, static struct bin_attribute ds1511_nvram_attr = { .attr = { .name = "nvram", - .mode = S_IRUGO | S_IWUGO, + .mode = S_IRUGO | S_IWUSR, }, .size = DS1511_RAM_MAX, .read = ds1511_nvram_read, diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index ff432e2ca27..fee41b97c9e 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -227,29 +227,12 @@ static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int ds1553_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - struct platform_device *pdev = to_platform_device(dev); - struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - - if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_UF; - else - pdata->irqen &= ~RTC_UF; - ds1553_rtc_update_alarm(pdata); - return 0; -} - static const struct rtc_class_ops ds1553_rtc_ops = { .read_time = ds1553_rtc_read_time, .set_time = ds1553_rtc_set_time, .read_alarm = ds1553_rtc_read_alarm, .set_alarm = ds1553_rtc_set_alarm, .alarm_irq_enable = ds1553_rtc_alarm_irq_enable, - .update_irq_enable = ds1553_rtc_update_irq_enable, }; static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj, diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 23a9ee19764..27b7bf672ac 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -1,7 +1,7 @@ /* * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C * - * Copyright (C) 2009-2010 Freescale Semiconductor. + * Copyright (C) 2009-2011 Freescale Semiconductor. * Author: Jack Lan <jack.lan@freescale.com> * * This program is free software; you can redistribute it and/or modify it @@ -141,9 +141,11 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time) time->tm_hour = bcd2bin(hour); } - time->tm_wday = bcd2bin(week); + /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */ + time->tm_wday = bcd2bin(week) - 1; time->tm_mday = bcd2bin(day); - time->tm_mon = bcd2bin(month & 0x7F); + /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */ + time->tm_mon = bcd2bin(month & 0x7F) - 1; if (century) add_century = 100; @@ -162,9 +164,11 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) buf[0] = bin2bcd(time->tm_sec); buf[1] = bin2bcd(time->tm_min); buf[2] = bin2bcd(time->tm_hour); - buf[3] = bin2bcd(time->tm_wday); /* Day of the week */ + /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */ + buf[3] = bin2bcd(time->tm_wday + 1); buf[4] = bin2bcd(time->tm_mday); /* Date */ - buf[5] = bin2bcd(time->tm_mon); + /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */ + buf[5] = bin2bcd(time->tm_mon + 1); if (time->tm_year >= 100) { buf[5] |= 0x80; buf[6] = bin2bcd(time->tm_year - 100); @@ -335,23 +339,6 @@ static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ds3232 *ds3232 = i2c_get_clientdata(client); - - if (client->irq <= 0) - return -EINVAL; - - if (enabled) - ds3232->rtc->irq_data |= RTC_UF; - else - ds3232->rtc->irq_data &= ~RTC_UF; - - ds3232_update_alarm(client); - return 0; -} - static irqreturn_t ds3232_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; @@ -402,7 +389,6 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .read_alarm = ds3232_read_alarm, .set_alarm = ds3232_set_alarm, .alarm_irq_enable = ds3232_alarm_irq_enable, - .update_irq_enable = ds3232_update_irq_enable, }; static int __devinit ds3232_probe(struct i2c_client *client, diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c index a774ca35b5f..bbd26228f53 100644 --- a/drivers/rtc/rtc-ds3234.c +++ b/drivers/rtc/rtc-ds3234.c @@ -158,7 +158,7 @@ static int __devinit ds3234_probe(struct spi_device *spi) static int __devexit ds3234_remove(struct spi_device *spi) { - struct rtc_device *rtc = platform_get_drvdata(spi); + struct rtc_device *rtc = spi_get_drvdata(spi); rtc_device_unregister(rtc); return 0; diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c new file mode 100644 index 00000000000..d8e1c257855 --- /dev/null +++ b/drivers/rtc/rtc-em3027.c @@ -0,0 +1,161 @@ +/* + * An rtc/i2c driver for the EM Microelectronic EM3027 + * Copyright 2011 CompuLab, Ltd. + * + * Author: Mike Rapoport <mike@compulab.co.il> + * + * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it> + * + * 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/i2c.h> +#include <linux/rtc.h> +#include <linux/bcd.h> + +/* Registers */ +#define EM3027_REG_ON_OFF_CTRL 0x00 +#define EM3027_REG_IRQ_CTRL 0x01 +#define EM3027_REG_IRQ_FLAGS 0x02 +#define EM3027_REG_STATUS 0x03 +#define EM3027_REG_RST_CTRL 0x04 + +#define EM3027_REG_WATCH_SEC 0x08 +#define EM3027_REG_WATCH_MIN 0x09 +#define EM3027_REG_WATCH_HOUR 0x0a +#define EM3027_REG_WATCH_DATE 0x0b +#define EM3027_REG_WATCH_DAY 0x0c +#define EM3027_REG_WATCH_MON 0x0d +#define EM3027_REG_WATCH_YEAR 0x0e + +#define EM3027_REG_ALARM_SEC 0x10 +#define EM3027_REG_ALARM_MIN 0x11 +#define EM3027_REG_ALARM_HOUR 0x12 +#define EM3027_REG_ALARM_DATE 0x13 +#define EM3027_REG_ALARM_DAY 0x14 +#define EM3027_REG_ALARM_MON 0x15 +#define EM3027_REG_ALARM_YEAR 0x16 + +static struct i2c_driver em3027_driver; + +static int em3027_get_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + + unsigned char addr = EM3027_REG_WATCH_SEC; + unsigned char buf[7]; + + struct i2c_msg msgs[] = { + {client->addr, 0, 1, &addr}, /* setup read addr */ + {client->addr, I2C_M_RD, 7, buf}, /* read time/date */ + }; + + /* read time/date registers */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __func__); + return -EIO; + } + + tm->tm_sec = bcd2bin(buf[0]); + tm->tm_min = bcd2bin(buf[1]); + tm->tm_hour = bcd2bin(buf[2]); + tm->tm_mday = bcd2bin(buf[3]); + tm->tm_wday = bcd2bin(buf[4]); + tm->tm_mon = bcd2bin(buf[5]); + tm->tm_year = bcd2bin(buf[6]) + 100; + + return 0; +} + +static int em3027_set_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned char buf[8]; + + struct i2c_msg msg = { + client->addr, 0, 8, buf, /* write time/date */ + }; + + buf[0] = EM3027_REG_WATCH_SEC; + buf[1] = bin2bcd(tm->tm_sec); + buf[2] = bin2bcd(tm->tm_min); + buf[3] = bin2bcd(tm->tm_hour); + buf[4] = bin2bcd(tm->tm_mday); + buf[5] = bin2bcd(tm->tm_wday); + buf[6] = bin2bcd(tm->tm_mon); + buf[7] = bin2bcd(tm->tm_year % 100); + + /* write time/date registers */ + if ((i2c_transfer(client->adapter, &msg, 1)) != 1) { + dev_err(&client->dev, "%s: write error\n", __func__); + return -EIO; + } + + return 0; +} + +static const struct rtc_class_ops em3027_rtc_ops = { + .read_time = em3027_get_time, + .set_time = em3027_set_time, +}; + +static int em3027_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rtc_device *rtc; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + rtc = rtc_device_register(em3027_driver.driver.name, &client->dev, + &em3027_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + i2c_set_clientdata(client, rtc); + + return 0; +} + +static int em3027_remove(struct i2c_client *client) +{ + struct rtc_device *rtc = i2c_get_clientdata(client); + + if (rtc) + rtc_device_unregister(rtc); + + return 0; +} + +static struct i2c_device_id em3027_id[] = { + { "em3027", 0 }, + { } +}; + +static struct i2c_driver em3027_driver = { + .driver = { + .name = "rtc-em3027", + }, + .probe = &em3027_probe, + .remove = &em3027_remove, + .id_table = em3027_id, +}; + +static int __init em3027_init(void) +{ + return i2c_add_driver(&em3027_driver); +} + +static void __exit em3027_exit(void) +{ + i2c_del_driver(&em3027_driver); +} + +MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); +MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver"); +MODULE_LICENSE("GPL"); + +module_init(em3027_init); +module_exit(em3027_exit); diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 11ae64dcbf3..335551d333b 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -151,6 +151,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return -ENXIO; pdev->dev.platform_data = ep93xx_rtc; + platform_set_drvdata(pdev, rtc); rtc = rtc_device_register(pdev->name, &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); @@ -159,8 +160,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) goto exit; } - platform_set_drvdata(pdev, rtc); - err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); if (err) goto fail; @@ -168,9 +167,9 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return 0; fail: - platform_set_drvdata(pdev, NULL); rtc_device_unregister(rtc); exit: + platform_set_drvdata(pdev, NULL); pdev->dev.platform_data = NULL; return err; } diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 468200c38ec..da8beb8cae5 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -39,6 +39,8 @@ #define ISL1208_REG_SR_BAT (1<<1) /* battery */ #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ #define ISL1208_REG_INT 0x08 +#define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */ +#define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */ #define ISL1208_REG_09 0x09 /* reserved */ #define ISL1208_REG_ATR 0x0a #define ISL1208_REG_DTR 0x0b @@ -202,6 +204,30 @@ isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) } static int +isl1208_rtc_toggle_alarm(struct i2c_client *client, int enable) +{ + int icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT); + + if (icr < 0) { + dev_err(&client->dev, "%s: reading INT failed\n", __func__); + return icr; + } + + if (enable) + icr |= ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM; + else + icr &= ~(ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM); + + icr = i2c_smbus_write_byte_data(client, ISL1208_REG_INT, icr); + if (icr < 0) { + dev_err(&client->dev, "%s: writing INT failed\n", __func__); + return icr; + } + + return 0; +} + +static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) { struct i2c_client *const client = to_i2c_client(dev); @@ -288,9 +314,8 @@ isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; - int sr; + int icr, yr, sr = isl1208_i2c_get_sr(client); - sr = isl1208_i2c_get_sr(client); if (sr < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return sr; @@ -313,6 +338,73 @@ isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) bcd2bin(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1; tm->tm_wday = bcd2bin(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03); + /* The alarm doesn't store the year so get it from the rtc section */ + yr = i2c_smbus_read_byte_data(client, ISL1208_REG_YR); + if (yr < 0) { + dev_err(&client->dev, "%s: reading RTC YR failed\n", __func__); + return yr; + } + tm->tm_year = bcd2bin(yr) + 100; + + icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT); + if (icr < 0) { + dev_err(&client->dev, "%s: reading INT failed\n", __func__); + return icr; + } + alarm->enabled = !!(icr & ISL1208_REG_INT_ALME); + + return 0; +} + +static int +isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) +{ + struct rtc_time *alarm_tm = &alarm->time; + u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; + const int offs = ISL1208_REG_SCA; + unsigned long rtc_secs, alarm_secs; + struct rtc_time rtc_tm; + int err, enable; + + err = isl1208_i2c_read_time(client, &rtc_tm); + if (err) + return err; + err = rtc_tm_to_time(&rtc_tm, &rtc_secs); + if (err) + return err; + err = rtc_tm_to_time(alarm_tm, &alarm_secs); + if (err) + return err; + + /* If the alarm time is before the current time disable the alarm */ + if (!alarm->enabled || alarm_secs <= rtc_secs) + enable = 0x00; + else + enable = 0x80; + + /* Program the alarm and enable it for each setting */ + regs[ISL1208_REG_SCA - offs] = bin2bcd(alarm_tm->tm_sec) | enable; + regs[ISL1208_REG_MNA - offs] = bin2bcd(alarm_tm->tm_min) | enable; + regs[ISL1208_REG_HRA - offs] = bin2bcd(alarm_tm->tm_hour) | + ISL1208_REG_HR_MIL | enable; + + regs[ISL1208_REG_DTA - offs] = bin2bcd(alarm_tm->tm_mday) | enable; + regs[ISL1208_REG_MOA - offs] = bin2bcd(alarm_tm->tm_mon + 1) | enable; + regs[ISL1208_REG_DWA - offs] = bin2bcd(alarm_tm->tm_wday & 7) | enable; + + /* write ALARM registers */ + err = isl1208_i2c_set_regs(client, offs, regs, + ISL1208_ALARM_SECTION_LEN); + if (err < 0) { + dev_err(&client->dev, "%s: writing ALARM section failed\n", + __func__); + return err; + } + + err = isl1208_rtc_toggle_alarm(client, enable); + if (err) + return err; + return 0; } @@ -391,12 +483,63 @@ isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); } +static int +isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm); +} + +static irqreturn_t +isl1208_rtc_interrupt(int irq, void *data) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + struct i2c_client *client = data; + int handled = 0, sr, err; + + /* + * I2C reads get NAK'ed if we read straight away after an interrupt? + * Using a mdelay/msleep didn't seem to help either, so we work around + * this by continually trying to read the register for a short time. + */ + while (1) { + sr = isl1208_i2c_get_sr(client); + if (sr >= 0) + break; + + if (time_after(jiffies, timeout)) { + dev_err(&client->dev, "%s: reading SR failed\n", + __func__); + return sr; + } + } + + if (sr & ISL1208_REG_SR_ALM) { + dev_dbg(&client->dev, "alarm!\n"); + + /* Clear the alarm */ + sr &= ~ISL1208_REG_SR_ALM; + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); + if (sr < 0) + dev_err(&client->dev, "%s: writing SR failed\n", + __func__); + else + handled = 1; + + /* Disable the alarm */ + err = isl1208_rtc_toggle_alarm(client, 0); + if (err) + return err; + } + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + static const struct rtc_class_ops isl1208_rtc_ops = { .proc = isl1208_rtc_proc, .read_time = isl1208_rtc_read_time, .set_time = isl1208_rtc_set_time, .read_alarm = isl1208_rtc_read_alarm, - /*.set_alarm = isl1208_rtc_set_alarm, */ + .set_alarm = isl1208_rtc_set_alarm, }; /* sysfs interface */ @@ -488,11 +631,29 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + if (client->irq > 0) { + rc = request_threaded_irq(client->irq, NULL, + isl1208_rtc_interrupt, + IRQF_SHARED, + isl1208_driver.driver.name, client); + if (!rc) { + device_init_wakeup(&client->dev, 1); + enable_irq_wake(client->irq); + } else { + dev_err(&client->dev, + "Unable to request irq %d, no alarm support\n", + client->irq); + client->irq = 0; + } + } + rtc = rtc_device_register(isl1208_driver.driver.name, &client->dev, &isl1208_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (IS_ERR(rtc)) { + rc = PTR_ERR(rtc); + goto exit_free_irq; + } i2c_set_clientdata(client, rtc); @@ -514,6 +675,9 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) exit_unregister: rtc_device_unregister(rtc); +exit_free_irq: + if (client->irq) + free_irq(client->irq, client); return rc; } @@ -525,6 +689,8 @@ isl1208_remove(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); rtc_device_unregister(rtc); + if (client->irq) + free_irq(client->irq, client); return 0; } diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 2e16f72c905..b6473631d18 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -168,12 +168,6 @@ static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static int jz4740_rtc_update_irq_enable(struct device *dev, unsigned int enable) -{ - struct jz4740_rtc *rtc = dev_get_drvdata(dev); - return jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ_IRQ, enable); -} - static int jz4740_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { struct jz4740_rtc *rtc = dev_get_drvdata(dev); @@ -185,7 +179,6 @@ static struct rtc_class_ops jz4740_rtc_ops = { .set_mmss = jz4740_rtc_set_mmss, .read_alarm = jz4740_rtc_read_alarm, .set_alarm = jz4740_rtc_set_alarm, - .update_irq_enable = jz4740_rtc_update_irq_enable, .alarm_irq_enable = jz4740_rtc_alarm_irq_enable, }; diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index ec8701ce99f..ae16250c762 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -240,7 +240,7 @@ static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->lock); /* - * The RTC is on a seperate power domain and can keep it's state + * The RTC is on a separate power domain and can keep it's state * across a chip power cycle. If the RTC has never been previously * setup, then set it up now for the first time. */ diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 5a8daa35806..eda128fc1d3 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -213,41 +213,27 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) return m41t80_set_datetime(to_i2c_client(dev), tm); } -#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) -static int -m41t80_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int m41t80_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); int rc; - switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - break; - default: - return -ENOIOCTLCMD; - } - rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); if (rc < 0) goto err; - switch (cmd) { - case RTC_AIE_OFF: - rc &= ~M41T80_ALMON_AFE; - break; - case RTC_AIE_ON: + + if (enabled) rc |= M41T80_ALMON_AFE; - break; - } + else + rc &= ~M41T80_ALMON_AFE; + if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0) goto err; + return 0; err: return -EIO; } -#else -#define m41t80_rtc_ioctl NULL -#endif static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) { @@ -374,7 +360,7 @@ static struct rtc_class_ops m41t80_rtc_ops = { .read_alarm = m41t80_rtc_read_alarm, .set_alarm = m41t80_rtc_set_alarm, .proc = m41t80_rtc_proc, - .ioctl = m41t80_rtc_ioctl, + .alarm_irq_enable = m41t80_rtc_alarm_irq_enable, }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) @@ -797,6 +783,9 @@ static int m41t80_probe(struct i2c_client *client, goto exit; } + clientdata->features = id->driver_data; + i2c_set_clientdata(client, clientdata); + rtc = rtc_device_register(client->name, &client->dev, &m41t80_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -806,8 +795,6 @@ static int m41t80_probe(struct i2c_client *client, } clientdata->rtc = rtc; - clientdata->features = id->driver_data; - i2c_set_clientdata(client, clientdata); /* Make sure HT (Halt Update) bit is cleared */ rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c new file mode 100644 index 00000000000..1a84b3e227d --- /dev/null +++ b/drivers/rtc/rtc-m41t93.c @@ -0,0 +1,225 @@ +/* + * + * Driver for ST M41T93 SPI RTC + * + * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH + * + * 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/bcd.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/spi/spi.h> + +#define M41T93_REG_SSEC 0 +#define M41T93_REG_ST_SEC 1 +#define M41T93_REG_MIN 2 +#define M41T93_REG_CENT_HOUR 3 +#define M41T93_REG_WDAY 4 +#define M41T93_REG_DAY 5 +#define M41T93_REG_MON 6 +#define M41T93_REG_YEAR 7 + + +#define M41T93_REG_ALM_HOUR_HT 0xc +#define M41T93_REG_FLAGS 0xf + +#define M41T93_FLAG_ST (1 << 7) +#define M41T93_FLAG_OF (1 << 2) +#define M41T93_FLAG_BL (1 << 4) +#define M41T93_FLAG_HT (1 << 6) + +static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data) +{ + u8 buf[2]; + + /* MSB must be '1' to write */ + buf[0] = addr | 0x80; + buf[1] = data; + + return spi_write(spi, buf, sizeof(buf)); +} + +static int m41t93_set_time(struct device *dev, struct rtc_time *tm) +{ + struct spi_device *spi = to_spi_device(dev); + u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */ + u8 * const data = &buf[1]; /* ptr to first data byte */ + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "write", tm->tm_sec, tm->tm_min, + tm->tm_hour, tm->tm_mday, + tm->tm_mon, tm->tm_year, tm->tm_wday); + + if (tm->tm_year < 100) { + dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n"); + return -EINVAL; + } + + data[M41T93_REG_SSEC] = 0; + data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec); + data[M41T93_REG_MIN] = bin2bcd(tm->tm_min); + data[M41T93_REG_CENT_HOUR] = bin2bcd(tm->tm_hour) | + ((tm->tm_year/100-1) << 6); + data[M41T93_REG_DAY] = bin2bcd(tm->tm_mday); + data[M41T93_REG_WDAY] = bin2bcd(tm->tm_wday + 1); + data[M41T93_REG_MON] = bin2bcd(tm->tm_mon + 1); + data[M41T93_REG_YEAR] = bin2bcd(tm->tm_year % 100); + + return spi_write(spi, buf, sizeof(buf)); +} + + +static int m41t93_get_time(struct device *dev, struct rtc_time *tm) +{ + struct spi_device *spi = to_spi_device(dev); + const u8 start_addr = 0; + u8 buf[8]; + int century_after_1900; + int tmp; + int ret = 0; + + /* Check status of clock. Two states must be considered: + 1. halt bit (HT) is set: the clock is running but update of readout + registers has been disabled due to power failure. This is normal + case after poweron. Time is valid after resetting HT bit. + 2. oscillator fail bit (OF) is set. Oscillator has be stopped and + time is invalid: + a) OF can be immeditely reset. + b) OF cannot be immediately reset: oscillator has to be restarted. + */ + tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT); + if (tmp < 0) + return tmp; + + if (tmp & M41T93_FLAG_HT) { + dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n"); + m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT, + tmp & ~M41T93_FLAG_HT); + } + + tmp = spi_w8r8(spi, M41T93_REG_FLAGS); + if (tmp < 0) + return tmp; + + if (tmp & M41T93_FLAG_OF) { + ret = -EINVAL; + dev_warn(&spi->dev, "OF bit is set, resetting.\n"); + m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF); + + tmp = spi_w8r8(spi, M41T93_REG_FLAGS); + if (tmp < 0) + return tmp; + else if (tmp & M41T93_FLAG_OF) { + u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST; + + dev_warn(&spi->dev, + "OF bit is still set, kickstarting clock.\n"); + m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc); + reset_osc &= ~M41T93_FLAG_ST; + m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc); + } + } + + if (tmp & M41T93_FLAG_BL) + dev_warn(&spi->dev, "BL bit is set, replace battery.\n"); + + /* read actual time/date */ + tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf)); + if (tmp < 0) + return tmp; + + tm->tm_sec = bcd2bin(buf[M41T93_REG_ST_SEC]); + tm->tm_min = bcd2bin(buf[M41T93_REG_MIN]); + tm->tm_hour = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f); + tm->tm_mday = bcd2bin(buf[M41T93_REG_DAY]); + tm->tm_mon = bcd2bin(buf[M41T93_REG_MON]) - 1; + tm->tm_wday = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1; + + century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1; + tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100; + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "read", tm->tm_sec, tm->tm_min, + tm->tm_hour, tm->tm_mday, + tm->tm_mon, tm->tm_year, tm->tm_wday); + + return ret < 0 ? ret : rtc_valid_tm(tm); +} + + +static const struct rtc_class_ops m41t93_rtc_ops = { + .read_time = m41t93_get_time, + .set_time = m41t93_set_time, +}; + +static struct spi_driver m41t93_driver; + +static int __devinit m41t93_probe(struct spi_device *spi) +{ + struct rtc_device *rtc; + int res; + + spi->bits_per_word = 8; + spi_setup(spi); + + res = spi_w8r8(spi, M41T93_REG_WDAY); + if (res < 0 || (res & 0xf8) != 0) { + dev_err(&spi->dev, "not found 0x%x.\n", res); + return -ENODEV; + } + + rtc = rtc_device_register(m41t93_driver.driver.name, + &spi->dev, &m41t93_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + dev_set_drvdata(&spi->dev, rtc); + + return 0; +} + + +static int __devexit m41t93_remove(struct spi_device *spi) +{ + struct rtc_device *rtc = platform_get_drvdata(spi); + + if (rtc) + rtc_device_unregister(rtc); + + return 0; +} + +static struct spi_driver m41t93_driver = { + .driver = { + .name = "rtc-m41t93", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = m41t93_probe, + .remove = __devexit_p(m41t93_remove), +}; + +static __init int m41t93_init(void) +{ + return spi_register_driver(&m41t93_driver); +} +module_init(m41t93_init); + +static __exit void m41t93_exit(void) +{ + spi_unregister_driver(&m41t93_driver); +} +module_exit(m41t93_exit); + +MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>"); +MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-m41t93"); diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c index c8c97a4169d..e259ed76ae8 100644 --- a/drivers/rtc/rtc-m41t94.c +++ b/drivers/rtc/rtc-m41t94.c @@ -136,7 +136,7 @@ static int __devinit m41t94_probe(struct spi_device *spi) static int __devexit m41t94_remove(struct spi_device *spi) { - struct rtc_device *rtc = platform_get_drvdata(spi); + struct rtc_device *rtc = spi_get_drvdata(spi); if (rtc) rtc_device_unregister(rtc); diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index a99a0b554eb..3978f4caf72 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -263,30 +263,21 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) /* * Handle commands from user-space */ -static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct platform_device *pdev = to_platform_device(dev); struct m48t59_plat_data *pdata = pdev->dev.platform_data; struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; - int ret = 0; spin_lock_irqsave(&m48t59->lock, flags); - switch (cmd) { - case RTC_AIE_OFF: /* alarm interrupt off */ - M48T59_WRITE(0x00, M48T59_INTR); - break; - case RTC_AIE_ON: /* alarm interrupt on */ + if (enabled) M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR); - break; - default: - ret = -ENOIOCTLCMD; - break; - } + else + M48T59_WRITE(0x00, M48T59_INTR); spin_unlock_irqrestore(&m48t59->lock, flags); - return ret; + return 0; } static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq) @@ -330,12 +321,12 @@ static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id) } static const struct rtc_class_ops m48t59_rtc_ops = { - .ioctl = m48t59_rtc_ioctl, .read_time = m48t59_rtc_read_time, .set_time = m48t59_rtc_set_time, .read_alarm = m48t59_rtc_readalarm, .set_alarm = m48t59_rtc_setalarm, .proc = m48t59_rtc_proc, + .alarm_irq_enable = m48t59_rtc_alarm_irq_enable, }; static const struct rtc_class_ops m48t02_rtc_ops = { diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 174036dda78..3bc046f427e 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -257,6 +257,10 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_irq; } + dev_set_drvdata(&pdev->dev, info); + /* XXX - isn't this redundant? */ + platform_set_drvdata(pdev, info); + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); ret = PTR_ERR(info->rtc_dev); @@ -265,11 +269,9 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_rtc; } - dev_set_drvdata(&pdev->dev, info); - platform_set_drvdata(pdev, info); - return 0; out_rtc: + platform_set_drvdata(pdev, NULL); free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); out_irq: kfree(info); diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index 3f7bc6b9fef..2e48aa60427 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -265,6 +265,8 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) info->rtc = max8998->rtc; info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; + platform_set_drvdata(pdev, info); + info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev, &max8998_rtc_ops, THIS_MODULE); @@ -274,8 +276,6 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) goto out_rtc; } - platform_set_drvdata(pdev, info); - ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, "rtc-alarm0", info); @@ -293,6 +293,7 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) return 0; out_rtc: + platform_set_drvdata(pdev, NULL); kfree(info); return ret; } diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 5314b153bfb..a1a278bc340 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -282,12 +282,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev) return IRQ_HANDLED; } -static int mc13xxx_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_1HZ); -} - static int mc13xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { @@ -300,7 +294,6 @@ static const struct rtc_class_ops mc13xxx_rtc_ops = { .read_alarm = mc13xxx_rtc_read_alarm, .set_alarm = mc13xxx_rtc_set_alarm, .alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable, - .update_irq_enable = mc13xxx_rtc_update_irq_enable, }; static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev) @@ -356,11 +349,15 @@ static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev) if (ret) goto err_alarm_irq_request; + mc13xxx_unlock(mc13xxx); + priv->rtc = rtc_device_register(pdev->name, &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE); if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); + mc13xxx_lock(mc13xxx); + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); err_alarm_irq_request: @@ -372,12 +369,12 @@ err_reset_irq_status: mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); err_reset_irq_request: + mc13xxx_unlock(mc13xxx); + platform_set_drvdata(pdev, NULL); kfree(priv); } - mc13xxx_unlock(mc13xxx); - return ret; } @@ -408,6 +405,7 @@ const struct platform_device_id mc13xxx_rtc_idtable[] = { }, { .name = "mc13892-rtc", }, + { } }; static struct platform_driver mc13xxx_rtc_driver = { diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index dfcdf0901d2..09ccd8d3ba2 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -240,36 +240,15 @@ static int mpc5121_rtc_alarm_irq_enable(struct device *dev, 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(®s->int_enable); - - if (enabled) - val = (val & ~0x8) | 0x1; - else - val &= ~0x1; - - out_8(®s->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 platform_device *op, - const struct of_device_id *match) +static int __devinit mpc5121_rtc_probe(struct platform_device *op) { struct mpc5121_rtc_data *rtc; int err = 0; @@ -364,7 +343,7 @@ static struct of_device_id mpc5121_rtc_match[] __devinitdata = { {}, }; -static struct of_platform_driver mpc5121_rtc_driver = { +static struct platform_driver mpc5121_rtc_driver = { .driver = { .name = "mpc5121-rtc", .owner = THIS_MODULE, @@ -376,13 +355,13 @@ static struct of_platform_driver mpc5121_rtc_driver = { static int __init mpc5121_rtc_init(void) { - return of_register_platform_driver(&mpc5121_rtc_driver); + return platform_driver_register(&mpc5121_rtc_driver); } module_init(mpc5121_rtc_init); static void __exit mpc5121_rtc_exit(void) { - of_unregister_platform_driver(&mpc5121_rtc_driver); + platform_driver_unregister(&mpc5121_rtc_driver); } module_exit(mpc5121_rtc_exit); diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index bcd0cf63eb1..0cec5650d56 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -62,6 +62,17 @@ static inline int is_intr(u8 rtc_intr) return rtc_intr & RTC_IRQMASK; } +static inline unsigned char vrtc_is_updating(void) +{ + unsigned char uip; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + /* * rtc_time's year contains the increment over 1900, but vRTC's YEAR * register can't be programmed to value larger than 0x64, so vRTC @@ -76,7 +87,7 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time) { unsigned long flags; - if (rtc_is_updating()) + if (vrtc_is_updating()) mdelay(20); spin_lock_irqsave(&rtc_lock, flags); @@ -236,61 +247,21 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -static int mrst_irq_set_state(struct device *dev, int enabled) +/* Currently, the vRTC doesn't support UIE ON/OFF */ +static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct mrst_rtc *mrst = dev_get_drvdata(dev); unsigned long flags; - if (!mrst->irq) - return -ENXIO; - spin_lock_irqsave(&rtc_lock, flags); - if (enabled) - mrst_irq_enable(mrst, RTC_PIE); + mrst_irq_enable(mrst, RTC_AIE); else - mrst_irq_disable(mrst, RTC_PIE); - - spin_unlock_irqrestore(&rtc_lock, flags); - return 0; -} - -#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) - -/* Currently, the vRTC doesn't support UIE ON/OFF */ -static int -mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) -{ - struct mrst_rtc *mrst = dev_get_drvdata(dev); - unsigned long flags; - - switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - if (!mrst->irq) - return -EINVAL; - break; - default: - /* PIE ON/OFF is handled by mrst_irq_set_state() */ - return -ENOIOCTLCMD; - } - - spin_lock_irqsave(&rtc_lock, flags); - switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ mrst_irq_disable(mrst, RTC_AIE); - break; - case RTC_AIE_ON: /* alarm on */ - mrst_irq_enable(mrst, RTC_AIE); - break; - } spin_unlock_irqrestore(&rtc_lock, flags); return 0; } -#else -#define mrst_rtc_ioctl NULL -#endif #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) @@ -317,13 +288,12 @@ static int mrst_procfs(struct device *dev, struct seq_file *seq) #endif static const struct rtc_class_ops mrst_rtc_ops = { - .ioctl = mrst_rtc_ioctl, .read_time = mrst_read_time, .set_time = mrst_set_time, .read_alarm = mrst_read_alarm, .set_alarm = mrst_set_alarm, .proc = mrst_procfs, - .irq_set_state = mrst_irq_set_state, + .alarm_irq_enable = mrst_rtc_alarm_irq_enable, }; static struct mrst_rtc mrst_rtc; @@ -349,7 +319,7 @@ static irqreturn_t mrst_rtc_irq(int irq, void *p) return IRQ_NONE; } -static int __init +static int __devinit vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) { int retval = 0; @@ -372,6 +342,8 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) mrst_rtc.irq = rtc_irq; mrst_rtc.iomem = iomem; + mrst_rtc.dev = dev; + dev_set_drvdata(dev, &mrst_rtc); mrst_rtc.rtc = rtc_device_register(driver_name, dev, &mrst_rtc_ops, THIS_MODULE); @@ -380,8 +352,6 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) goto cleanup0; } - mrst_rtc.dev = dev; - dev_set_drvdata(dev, &mrst_rtc); rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); @@ -406,10 +376,11 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) return 0; cleanup1: - mrst_rtc.dev = NULL; rtc_device_unregister(mrst_rtc.rtc); cleanup0: - release_region(iomem->start, iomem->end + 1 - iomem->start); + dev_set_drvdata(dev, NULL); + mrst_rtc.dev = NULL; + release_mem_region(iomem->start, resource_size(iomem)); dev_err(dev, "rtc-mrst: unable to initialise\n"); return retval; } @@ -421,7 +392,7 @@ static void rtc_mrst_do_shutdown(void) spin_unlock_irq(&rtc_lock); } -static void __exit rtc_mrst_do_remove(struct device *dev) +static void __devexit rtc_mrst_do_remove(struct device *dev) { struct mrst_rtc *mrst = dev_get_drvdata(dev); struct resource *iomem; @@ -435,7 +406,7 @@ static void __exit rtc_mrst_do_remove(struct device *dev) mrst->rtc = NULL; iomem = mrst->iomem; - release_region(iomem->start, iomem->end + 1 - iomem->start); + release_mem_region(iomem->start, resource_size(iomem)); mrst->iomem = NULL; mrst->dev = NULL; @@ -530,14 +501,14 @@ static inline int mrst_poweroff(struct device *dev) #endif -static int __init vrtc_mrst_platform_probe(struct platform_device *pdev) +static int __devinit vrtc_mrst_platform_probe(struct platform_device *pdev) { return vrtc_mrst_do_probe(&pdev->dev, platform_get_resource(pdev, IORESOURCE_MEM, 0), platform_get_irq(pdev, 0)); } -static int __exit vrtc_mrst_platform_remove(struct platform_device *pdev) +static int __devexit vrtc_mrst_platform_remove(struct platform_device *pdev) { rtc_mrst_do_remove(&pdev->dev); return 0; @@ -555,7 +526,7 @@ MODULE_ALIAS("platform:vrtc_mrst"); static struct platform_driver vrtc_mrst_platform_driver = { .probe = vrtc_mrst_platform_probe, - .remove = __exit_p(vrtc_mrst_platform_remove), + .remove = __devexit_p(vrtc_mrst_platform_remove), .shutdown = vrtc_mrst_platform_shutdown, .driver = { .name = (char *) driver_name, diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index b2fff0ca49f..fcb113c1112 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -82,7 +82,7 @@ static inline unsigned int msm6242_read(struct msm6242_priv *priv, static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val, unsigned int reg) { - return __raw_writel(val, &priv->regs[reg]); + __raw_writel(val, &priv->regs[reg]); } static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val, @@ -214,6 +214,7 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) error = -ENOMEM; goto out_free_priv; } + platform_set_drvdata(dev, priv); rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops, THIS_MODULE); @@ -223,10 +224,10 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) } priv->rtc = rtc; - platform_set_drvdata(dev, priv); return 0; out_unmap: + platform_set_drvdata(dev, NULL); iounmap(priv->regs); out_free_priv: kfree(priv); diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index bcca4729855..60627a76451 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -169,25 +169,19 @@ static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return 0; } -static int mv_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int mv_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; if (pdata->irq < 0) - return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ - switch (cmd) { - case RTC_AIE_OFF: - writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - break; - case RTC_AIE_ON: + return -EINVAL; /* fall back into rtc-dev's emulation */ + + if (enabled) writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - break; - default: - return -ENOIOCTLCMD; - } + else + writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); return 0; } @@ -216,7 +210,7 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = { .set_time = mv_rtc_set_time, .read_alarm = mv_rtc_read_alarm, .set_alarm = mv_rtc_set_alarm, - .ioctl = mv_rtc_ioctl, + .alarm_irq_enable = mv_rtc_alarm_irq_enable, }; static int __devinit mv_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 0b06c1e03fd..39e41fbdf08 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -55,12 +55,6 @@ static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { { MAX_PIE_FREQ, RTC_SAM7_BIT }, }; -/* Those are the bits from a classic RTC we want to mimic */ -#define RTC_IRQF 0x80 /* any of the following 3 is active */ -#define RTC_PF 0x40 /* Periodic interrupt */ -#define RTC_AF 0x20 /* Alarm interrupt */ -#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */ - #define MXC_RTC_TIME 0 #define MXC_RTC_ALARM 1 @@ -274,12 +268,6 @@ static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int mxc_rtc_update_irq_enable(struct device *dev, unsigned int enabled) -{ - mxc_rtc_irq_enable(dev, RTC_1HZ_BIT, enabled); - return 0; -} - /* * This function reads the current RTC time into tm in Gregorian date. */ @@ -368,7 +356,6 @@ static struct rtc_class_ops mxc_rtc_ops = { .read_alarm = mxc_rtc_read_alarm, .set_alarm = mxc_rtc_set_alarm, .alarm_irq_enable = mxc_rtc_alarm_irq_enable, - .update_irq_enable = mxc_rtc_update_irq_enable, }; static int __init mxc_rtc_probe(struct platform_device *pdev) @@ -425,14 +412,6 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) goto exit_put_clk; } - rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, - THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - goto exit_put_clk; - } - - pdata->rtc = rtc; platform_set_drvdata(pdev, pdata); /* Configure and enable the RTC */ @@ -445,8 +424,19 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) pdata->irq = -1; } + rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto exit_clr_drvdata; + } + + pdata->rtc = rtc; + return 0; +exit_clr_drvdata: + platform_set_drvdata(pdev, NULL); exit_put_clk: clk_disable(pdata->clk); clk_put(pdata->clk); diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index ddb0857e15a..781068d62f2 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -134,20 +134,6 @@ static void nuc900_rtc_bin2bcd(struct device *dev, struct rtc_time *settm, gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16; } -static int nuc900_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - - if (enabled) - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| - (TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); - else - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& - (~TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); - - return 0; -} - static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct nuc900_rtc *rtc = dev_get_drvdata(dev); @@ -234,7 +220,6 @@ static struct rtc_class_ops nuc900_rtc_ops = { .read_alarm = nuc900_rtc_read_alarm, .set_alarm = nuc900_rtc_set_alarm, .alarm_irq_enable = nuc900_alarm_irq_enable, - .update_irq_enable = nuc900_update_irq_enable, }; static int __devinit nuc900_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index e72b523c79a..bcae8dd4149 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -135,42 +135,17 @@ static irqreturn_t rtc_irq(int irq, void *rtc) return IRQ_HANDLED; } -#ifdef CONFIG_RTC_INTF_DEV - -static int -omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { u8 reg; - switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - case RTC_UIE_OFF: - case RTC_UIE_ON: - break; - default: - return -ENOIOCTLCMD; - } - local_irq_disable(); rtc_wait_not_busy(); reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); - switch (cmd) { - /* AIE = Alarm Interrupt Enable */ - case RTC_AIE_OFF: - reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; - break; - case RTC_AIE_ON: + if (enabled) reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; - break; - /* UIE = Update Interrupt Enable (1/second) */ - case RTC_UIE_OFF: - reg &= ~OMAP_RTC_INTERRUPTS_IT_TIMER; - break; - case RTC_UIE_ON: - reg |= OMAP_RTC_INTERRUPTS_IT_TIMER; - break; - } + else + reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; rtc_wait_not_busy(); rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); local_irq_enable(); @@ -178,10 +153,6 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) return 0; } -#else -#define omap_rtc_ioctl NULL -#endif - /* this hardware doesn't support "don't care" alarm fields */ static int tm2bcd(struct rtc_time *tm) { @@ -304,11 +275,11 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) } static struct rtc_class_ops omap_rtc_ops = { - .ioctl = omap_rtc_ioctl, .read_time = omap_rtc_read_time, .set_time = omap_rtc_set_time, .read_alarm = omap_rtc_read_alarm, .set_alarm = omap_rtc_set_alarm, + .alarm_irq_enable = omap_rtc_alarm_irq_enable, }; static int omap_rtc_alarm; @@ -423,7 +394,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) return 0; fail2: - free_irq(omap_rtc_timer, NULL); + free_irq(omap_rtc_timer, rtc); fail1: rtc_device_unregister(rtc); fail0: diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index 25c0b3fd44f..cd4f198cc2e 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -131,18 +131,12 @@ static int pcap_rtc_alarm_irq_enable(struct device *dev, unsigned int en) return pcap_rtc_irq_enable(dev, PCAP_IRQ_TODA, en); } -static int pcap_rtc_update_irq_enable(struct device *dev, unsigned int en) -{ - return pcap_rtc_irq_enable(dev, PCAP_IRQ_1HZ, en); -} - static const struct rtc_class_ops pcap_rtc_ops = { .read_time = pcap_rtc_read_time, .read_alarm = pcap_rtc_read_alarm, .set_alarm = pcap_rtc_set_alarm, .set_mmss = pcap_rtc_set_mmss, .alarm_irq_enable = pcap_rtc_alarm_irq_enable, - .update_irq_enable = pcap_rtc_update_irq_enable, }; static int __devinit pcap_rtc_probe(struct platform_device *pdev) @@ -157,6 +151,8 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, pcap_rtc); + pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev, &pcap_rtc_ops, THIS_MODULE); if (IS_ERR(pcap_rtc->rtc)) { @@ -164,7 +160,6 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) goto fail_rtc; } - platform_set_drvdata(pdev, pcap_rtc); timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); @@ -183,6 +178,7 @@ fail_alarm: fail_timer: rtc_device_unregister(pcap_rtc->rtc); fail_rtc: + platform_set_drvdata(pdev, NULL); kfree(pcap_rtc); return err; } diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index 16edf94ab42..0c423892923 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -58,7 +58,6 @@ struct pcf50633_time { struct pcf50633_rtc { int alarm_enabled; - int second_enabled; int alarm_pending; struct pcf50633 *pcf; @@ -106,25 +105,6 @@ pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int -pcf50633_rtc_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct pcf50633_rtc *rtc = dev_get_drvdata(dev); - int err; - - if (enabled) - err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); - else - err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); - - if (err < 0) - return err; - - rtc->second_enabled = enabled; - - return 0; -} - static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf50633_rtc *rtc; @@ -162,7 +142,7 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct pcf50633_rtc *rtc; struct pcf50633_time pcf_tm; - int second_masked, alarm_masked, ret = 0; + int alarm_masked, ret = 0; rtc = dev_get_drvdata(dev); @@ -181,11 +161,8 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) pcf_tm.time[PCF50633_TI_SEC]); - second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND); alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); - if (!second_masked) - pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); if (!alarm_masked) pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); @@ -194,8 +171,6 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) PCF50633_TI_EXTENT, &pcf_tm.time[0]); - if (!second_masked) - pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); if (!alarm_masked) pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); @@ -262,23 +237,15 @@ static struct rtc_class_ops pcf50633_rtc_ops = { .set_time = pcf50633_rtc_set_time, .read_alarm = pcf50633_rtc_read_alarm, .set_alarm = pcf50633_rtc_set_alarm, - .alarm_irq_enable = pcf50633_rtc_alarm_irq_enable, - .update_irq_enable = pcf50633_rtc_update_irq_enable, + .alarm_irq_enable = pcf50633_rtc_alarm_irq_enable, }; static void pcf50633_rtc_irq(int irq, void *data) { struct pcf50633_rtc *rtc = data; - switch (irq) { - case PCF50633_IRQ_ALARM: - rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); - rtc->alarm_pending = 1; - break; - case PCF50633_IRQ_SECOND: - rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); - break; - } + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + rtc->alarm_pending = 1; } static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) @@ -302,9 +269,6 @@ static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, pcf50633_rtc_irq, rtc); - pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND, - pcf50633_rtc_irq, rtc); - return 0; } @@ -315,7 +279,6 @@ static int __devexit pcf50633_rtc_remove(struct platform_device *pdev) rtc = platform_get_drvdata(pdev); pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM); - pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND); rtc_device_unregister(rtc->rtc_dev); kfree(rtc); diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index bbdb2f02798..1d28d4451da 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -35,11 +35,6 @@ static irqreturn_t pl030_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int pl030_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) -{ - return -ENOIOCTLCMD; -} - static int pl030_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct pl030_rtc *rtc = dev_get_drvdata(dev); @@ -96,14 +91,13 @@ static int pl030_set_time(struct device *dev, struct rtc_time *tm) } static const struct rtc_class_ops pl030_ops = { - .ioctl = pl030_ioctl, .read_time = pl030_read_time, .set_time = pl030_set_time, .read_alarm = pl030_read_alarm, .set_alarm = pl030_set_alarm, }; -static int pl030_probe(struct amba_device *dev, struct amba_id *id) +static int pl030_probe(struct amba_device *dev, const struct amba_id *id) { struct pl030_rtc *rtc; int ret; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index b7a6690e5b3..ff1b84bd9bb 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -293,57 +293,6 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 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); - - /* Now start the timer */ - writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN, - ldata->base + RTC_TCR); - - } 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 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) { struct pl031_local *ldata = dev_get_drvdata(&adev->dev); @@ -358,7 +307,7 @@ static int pl031_remove(struct amba_device *adev) return 0; } -static int pl031_probe(struct amba_device *adev, struct amba_id *id) +static int pl031_probe(struct amba_device *adev, const struct amba_id *id) { int ret; struct pl031_local *ldata; @@ -440,8 +389,6 @@ static struct rtc_class_ops stv1_pl031_ops = { .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 */ @@ -451,8 +398,6 @@ static struct rtc_class_ops stv2_pl031_ops = { .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[] = { diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index c086fc30a84..0a59fda5c09 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -69,6 +69,14 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) alrm.enabled ? "yes" : "no"); seq_printf(seq, "alrm_pending\t: %s\n", alrm.pending ? "yes" : "no"); + seq_printf(seq, "update IRQ enabled\t: %s\n", + (rtc->uie_rtctimer.enabled) ? "yes" : "no"); + seq_printf(seq, "periodic IRQ enabled\t: %s\n", + (rtc->pie_enabled) ? "yes" : "no"); + seq_printf(seq, "periodic IRQ frequency\t: %d\n", + rtc->irq_freq); + seq_printf(seq, "max user IRQ frequency\t: %d\n", + rtc->max_user_freq); } seq_printf(seq, "24hr\t\t: yes\n"); @@ -81,12 +89,16 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) static int rtc_proc_open(struct inode *inode, struct file *file) { + int ret; struct rtc_device *rtc = PDE(inode)->data; if (!try_module_get(THIS_MODULE)) return -ENODEV; - return single_open(file, rtc_proc_show, rtc); + ret = single_open(file, rtc_proc_show, rtc); + if (ret) + module_put(THIS_MODULE); + return ret; } static int rtc_proc_release(struct inode *inode, struct file *file) diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index 29e867a1aaa..fc9f4991574 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -209,32 +209,6 @@ static void pxa_rtc_release(struct device *dev) free_irq(pxa_rtc->irq_1Hz, dev); } -static int pxa_periodic_irq_set_freq(struct device *dev, int freq) -{ - struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); - int period_ms; - - if (freq < 1 || freq > MAXFREQ_PERIODIC) - return -EINVAL; - - period_ms = 1000 / freq; - rtc_writel(pxa_rtc, PIAR, period_ms); - - return 0; -} - -static int pxa_periodic_irq_set_state(struct device *dev, int enabled) -{ - struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); - - if (enabled) - rtsr_set_bits(pxa_rtc, RTSR_PIALE | RTSR_PICE); - else - rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_PICE); - - return 0; -} - static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); @@ -250,21 +224,6 @@ static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int pxa_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); - - spin_lock_irq(&pxa_rtc->lock); - - if (enabled) - rtsr_set_bits(pxa_rtc, RTSR_HZE); - else - rtsr_clear_bits(pxa_rtc, RTSR_HZE); - - spin_unlock_irq(&pxa_rtc->lock); - return 0; -} - static int pxa_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); @@ -346,10 +305,7 @@ static const struct rtc_class_ops pxa_rtc_ops = { .read_alarm = pxa_rtc_read_alarm, .set_alarm = pxa_rtc_set_alarm, .alarm_irq_enable = pxa_alarm_irq_enable, - .update_irq_enable = pxa_update_irq_enable, .proc = pxa_rtc_proc, - .irq_set_state = pxa_periodic_irq_set_state, - .irq_set_freq = pxa_periodic_irq_set_freq, }; static int __init pxa_rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 36eb6618446..359da6d020b 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -76,7 +76,7 @@ static inline unsigned int rp5c01_read(struct rp5c01_priv *priv, static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val, unsigned int reg) { - return __raw_writel(val, &priv->regs[reg]); + __raw_writel(val, &priv->regs[reg]); } static void rp5c01_lock(struct rp5c01_priv *priv) @@ -249,15 +249,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) spin_lock_init(&priv->lock); + platform_set_drvdata(dev, priv); + rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { error = PTR_ERR(rtc); goto out_unmap; } - priv->rtc = rtc; - platform_set_drvdata(dev, priv); error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); if (error) @@ -268,6 +268,7 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) out_unregister: rtc_device_unregister(rtc); out_unmap: + platform_set_drvdata(dev, NULL); iounmap(priv->regs); out_free_priv: kfree(priv); diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index dd14e202c2c..85c1b848dd7 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -281,10 +281,8 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) return rs5c372_set_datetime(to_i2c_client(dev), tm); } -#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) -static int -rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct rs5c372 *rs5c = i2c_get_clientdata(client); @@ -292,45 +290,19 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) int status, addr; buf = rs5c->regs[RS5C_REG_CTRL1]; - switch (cmd) { - case RTC_UIE_OFF: - case RTC_UIE_ON: - /* some 327a modes use a different IRQ pin for 1Hz irqs */ - if (rs5c->type == rtc_rs5c372a - && (buf & RS5C372A_CTRL1_SL1)) - return -ENOIOCTLCMD; - case RTC_AIE_OFF: - case RTC_AIE_ON: - /* these irq management calls only make sense for chips - * which are wired up to an IRQ. - */ - if (!rs5c->has_irq) - return -ENOIOCTLCMD; - break; - default: - return -ENOIOCTLCMD; - } + + if (!rs5c->has_irq) + return -EINVAL; status = rs5c_get_regs(rs5c); if (status < 0) return status; addr = RS5C_ADDR(RS5C_REG_CTRL1); - switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - buf &= ~RS5C_CTRL1_AALE; - break; - case RTC_AIE_ON: /* alarm on */ + if (enabled) buf |= RS5C_CTRL1_AALE; - break; - case RTC_UIE_OFF: /* update off */ - buf &= ~RS5C_CTRL1_CT_MASK; - break; - case RTC_UIE_ON: /* update on */ - buf &= ~RS5C_CTRL1_CT_MASK; - buf |= RS5C_CTRL1_CT4; - break; - } + else + buf &= ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf) < 0) { printk(KERN_WARNING "%s: can't update alarm\n", @@ -342,10 +314,6 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) return status; } -#else -#define rs5c_rtc_ioctl NULL -#endif - /* NOTE: Since RTC_WKALM_{RD,SET} were originally defined for EFI, * which only exposes a polled programming interface; and since @@ -461,11 +429,11 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) static const struct rtc_class_ops rs5c372_rtc_ops = { .proc = rs5c372_rtc_proc, - .ioctl = rs5c_rtc_ioctl, .read_time = rs5c372_rtc_read_time, .set_time = rs5c372_rtc_set_time, .read_alarm = rs5c_read_alarm, .set_alarm = rs5c_set_alarm, + .alarm_irq_enable = rs5c_rtc_alarm_irq_enable, }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c new file mode 100644 index 00000000000..ea09ff211dc --- /dev/null +++ b/drivers/rtc/rtc-rv3029c2.c @@ -0,0 +1,454 @@ +/* + * Micro Crystal RV-3029C2 rtc class driver + * + * Author: Gregory Hermant <gregory.hermant@calao-systems.com> + * + * based on previously existing rtc class drivers + * + * 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. + * + * NOTE: Currently this driver only supports the bare minimum for read + * and write the RTC and alarms. The extra features provided by this chip + * (trickle charger, eeprom, T° compensation) are unavailable. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/rtc.h> + +/* Register map */ +/* control section */ +#define RV3029C2_ONOFF_CTRL 0x00 +#define RV3029C2_IRQ_CTRL 0x01 +#define RV3029C2_IRQ_CTRL_AIE (1 << 0) +#define RV3029C2_IRQ_FLAGS 0x02 +#define RV3029C2_IRQ_FLAGS_AF (1 << 0) +#define RV3029C2_STATUS 0x03 +#define RV3029C2_STATUS_VLOW1 (1 << 2) +#define RV3029C2_STATUS_VLOW2 (1 << 3) +#define RV3029C2_STATUS_SR (1 << 4) +#define RV3029C2_STATUS_PON (1 << 5) +#define RV3029C2_STATUS_EEBUSY (1 << 7) +#define RV3029C2_RST_CTRL 0x04 +#define RV3029C2_CONTROL_SECTION_LEN 0x05 + +/* watch section */ +#define RV3029C2_W_SEC 0x08 +#define RV3029C2_W_MINUTES 0x09 +#define RV3029C2_W_HOURS 0x0A +#define RV3029C2_REG_HR_12_24 (1<<6) /* 24h/12h mode */ +#define RV3029C2_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ +#define RV3029C2_W_DATE 0x0B +#define RV3029C2_W_DAYS 0x0C +#define RV3029C2_W_MONTHS 0x0D +#define RV3029C2_W_YEARS 0x0E +#define RV3029C2_WATCH_SECTION_LEN 0x07 + +/* alarm section */ +#define RV3029C2_A_SC 0x10 +#define RV3029C2_A_MN 0x11 +#define RV3029C2_A_HR 0x12 +#define RV3029C2_A_DT 0x13 +#define RV3029C2_A_DW 0x14 +#define RV3029C2_A_MO 0x15 +#define RV3029C2_A_YR 0x16 +#define RV3029C2_ALARM_SECTION_LEN 0x07 + +/* timer section */ +#define RV3029C2_TIMER_LOW 0x18 +#define RV3029C2_TIMER_HIGH 0x19 + +/* temperature section */ +#define RV3029C2_TEMP_PAGE 0x20 + +/* eeprom data section */ +#define RV3029C2_E2P_EEDATA1 0x28 +#define RV3029C2_E2P_EEDATA2 0x29 + +/* eeprom control section */ +#define RV3029C2_CONTROL_E2P_EECTRL 0x30 +#define RV3029C2_TRICKLE_1K (1<<0) /* 1K resistance */ +#define RV3029C2_TRICKLE_5K (1<<1) /* 5K resistance */ +#define RV3029C2_TRICKLE_20K (1<<2) /* 20K resistance */ +#define RV3029C2_TRICKLE_80K (1<<3) /* 80K resistance */ +#define RV3029C2_CONTROL_E2P_XTALOFFSET 0x31 +#define RV3029C2_CONTROL_E2P_QCOEF 0x32 +#define RV3029C2_CONTROL_E2P_TURNOVER 0x33 + +/* user ram section */ +#define RV3029C2_USR1_RAM_PAGE 0x38 +#define RV3029C2_USR1_SECTION_LEN 0x04 +#define RV3029C2_USR2_RAM_PAGE 0x3C +#define RV3029C2_USR2_SECTION_LEN 0x04 + +static int +rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, + unsigned len) +{ + int ret; + + if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || + (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) + return -EINVAL; + + ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf); + if (ret < 0) + return ret; + if (ret < len) + return -EIO; + return 0; +} + +static int +rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[], + unsigned len) +{ + if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || + (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) + return -EINVAL; + + return i2c_smbus_write_i2c_block_data(client, reg, len, buf); +} + +static int +rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf) +{ + int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1); + + if (ret < 0) + return -EIO; + dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); + return 0; +} + +static int +rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val) +{ + u8 buf[1]; + int sr; + + buf[0] = val; + sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1); + dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); + if (sr < 0) + return -EIO; + return 0; +} + +static int +rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) +{ + u8 buf[1]; + int ret; + u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, }; + + ret = rv3029c2_i2c_get_sr(client, buf); + if (ret < 0) { + dev_err(&client->dev, "%s: reading SR failed\n", __func__); + return -EIO; + } + + ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs, + RV3029C2_WATCH_SECTION_LEN); + if (ret < 0) { + dev_err(&client->dev, "%s: reading RTC section failed\n", + __func__); + return ret; + } + + tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]); + tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]); + + /* HR field has a more complex interpretation */ + { + const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC]; + if (_hr & RV3029C2_REG_HR_12_24) { + /* 12h format */ + tm->tm_hour = bcd2bin(_hr & 0x1f); + if (_hr & RV3029C2_REG_HR_PM) /* PM flag set */ + tm->tm_hour += 12; + } else /* 24h format */ + tm->tm_hour = bcd2bin(_hr & 0x3f); + } + + tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]); + tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1; + tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100; + tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1; + + return 0; +} + +static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + return rv3029c2_i2c_read_time(to_i2c_client(dev), tm); +} + +static int +rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) +{ + struct rtc_time *const tm = &alarm->time; + int ret; + u8 regs[8]; + + ret = rv3029c2_i2c_get_sr(client, regs); + if (ret < 0) { + dev_err(&client->dev, "%s: reading SR failed\n", __func__); + return -EIO; + } + + ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs, + RV3029C2_ALARM_SECTION_LEN); + + if (ret < 0) { + dev_err(&client->dev, "%s: reading alarm section failed\n", + __func__); + return ret; + } + + tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f); + tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f); + tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f); + tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f); + tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1; + tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100; + tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1; + + return 0; +} + +static int +rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm); +} + +static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client, + int enable) +{ + int ret; + u8 buf[1]; + + /* enable AIE irq */ + ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1); + if (ret < 0) { + dev_err(&client->dev, "can't read INT reg\n"); + return ret; + } + if (enable) + buf[0] |= RV3029C2_IRQ_CTRL_AIE; + else + buf[0] &= ~RV3029C2_IRQ_CTRL_AIE; + + ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1); + if (ret < 0) { + dev_err(&client->dev, "can't set INT reg\n"); + return ret; + } + + return 0; +} + +static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, + struct rtc_wkalrm *alarm) +{ + struct rtc_time *const tm = &alarm->time; + int ret; + u8 regs[8]; + + /* + * The clock has an 8 bit wide bcd-coded register (they never learn) + * for the year. tm_year is an offset from 1900 and we are interested + * in the 2000-2099 range, so any value less than 100 is invalid. + */ + if (tm->tm_year < 100) + return -EINVAL; + + ret = rv3029c2_i2c_get_sr(client, regs); + if (ret < 0) { + dev_err(&client->dev, "%s: reading SR failed\n", __func__); + return -EIO; + } + regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f); + regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f); + regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f); + regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f); + regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1); + regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1); + regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100); + + ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs, + RV3029C2_ALARM_SECTION_LEN); + if (ret < 0) + return ret; + + if (alarm->enabled) { + u8 buf[1]; + + /* clear AF flag */ + ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS, + buf, 1); + if (ret < 0) { + dev_err(&client->dev, "can't read alarm flag\n"); + return ret; + } + buf[0] &= ~RV3029C2_IRQ_FLAGS_AF; + ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS, + buf, 1); + if (ret < 0) { + dev_err(&client->dev, "can't set alarm flag\n"); + return ret; + } + /* enable AIE irq */ + ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1); + if (ret) + return ret; + + dev_dbg(&client->dev, "alarm IRQ armed\n"); + } else { + /* disable AIE irq */ + ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1); + if (ret) + return ret; + + dev_dbg(&client->dev, "alarm IRQ disabled\n"); + } + + return 0; +} + +static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm); +} + +static int +rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) +{ + u8 regs[8]; + int ret; + + /* + * The clock has an 8 bit wide bcd-coded register (they never learn) + * for the year. tm_year is an offset from 1900 and we are interested + * in the 2000-2099 range, so any value less than 100 is invalid. + */ + if (tm->tm_year < 100) + return -EINVAL; + + regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec); + regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min); + regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour); + regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday); + regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1); + regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1); + regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100); + + ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs, + RV3029C2_WATCH_SECTION_LEN); + if (ret < 0) + return ret; + + ret = rv3029c2_i2c_get_sr(client, regs); + if (ret < 0) { + dev_err(&client->dev, "%s: reading SR failed\n", __func__); + return ret; + } + /* clear PON bit */ + ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON)); + if (ret < 0) { + dev_err(&client->dev, "%s: reading SR failed\n", __func__); + return ret; + } + + return 0; +} + +static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + return rv3029c2_i2c_set_time(to_i2c_client(dev), tm); +} + +static const struct rtc_class_ops rv3029c2_rtc_ops = { + .read_time = rv3029c2_rtc_read_time, + .set_time = rv3029c2_rtc_set_time, + .read_alarm = rv3029c2_rtc_read_alarm, + .set_alarm = rv3029c2_rtc_set_alarm, +}; + +static struct i2c_device_id rv3029c2_id[] = { + { "rv3029c2", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rv3029c2_id); + +static int __devinit +rv3029c2_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct rtc_device *rtc; + int rc = 0; + u8 buf[1]; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL)) + return -ENODEV; + + rtc = rtc_device_register(client->name, + &client->dev, &rv3029c2_rtc_ops, + THIS_MODULE); + + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + i2c_set_clientdata(client, rtc); + + rc = rv3029c2_i2c_get_sr(client, buf); + if (rc < 0) { + dev_err(&client->dev, "reading status failed\n"); + goto exit_unregister; + } + + return 0; + +exit_unregister: + rtc_device_unregister(rtc); + + return rc; +} + +static int __devexit rv3029c2_remove(struct i2c_client *client) +{ + struct rtc_device *rtc = i2c_get_clientdata(client); + + rtc_device_unregister(rtc); + + return 0; +} + +static struct i2c_driver rv3029c2_driver = { + .driver = { + .name = "rtc-rv3029c2", + }, + .probe = rv3029c2_probe, + .remove = __devexit_p(rv3029c2_remove), + .id_table = rv3029c2_id, +}; + +static int __init rv3029c2_init(void) +{ + return i2c_add_driver(&rv3029c2_driver); +} + +static void __exit rv3029c2_exit(void) +{ + i2c_del_driver(&rv3029c2_driver); +} + +module_init(rv3029c2_init); +module_exit(rv3029c2_exit); + +MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>"); +MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index af32a62e12a..fde172fb2ab 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -424,37 +424,12 @@ static int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int rx8025_irq_set_state(struct device *dev, int enabled) -{ - struct i2c_client *client = to_i2c_client(dev); - struct rx8025_data *rx8025 = i2c_get_clientdata(client); - int ctrl1; - int err; - - if (client->irq <= 0) - return -ENXIO; - - ctrl1 = rx8025->ctrl1 & ~RX8025_BIT_CTRL1_CT; - if (enabled) - ctrl1 |= RX8025_BIT_CTRL1_CT_1HZ; - if (ctrl1 != rx8025->ctrl1) { - rx8025->ctrl1 = ctrl1; - err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, - rx8025->ctrl1); - if (err) - return err; - } - - return 0; -} - static struct rtc_class_ops rx8025_rtc_ops = { .read_time = rx8025_get_time, .set_time = rx8025_set_time, .read_alarm = rx8025_read_alarm, .set_alarm = rx8025_set_alarm, .alarm_irq_enable = rx8025_alarm_irq_enable, - .irq_set_state = rx8025_irq_set_state, }; /* diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index cf953ecbfca..16512ecae31 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -46,6 +46,7 @@ static struct clk *rtc_clk; static void __iomem *s3c_rtc_base; static int s3c_rtc_alarmno = NO_IRQ; static int s3c_rtc_tickno = NO_IRQ; +static bool wake_en; static enum s3c_cpu_type s3c_rtc_cpu_type; static DEFINE_SPINLOCK(s3c_rtc_pie_lock); @@ -77,47 +78,18 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id) } /* Update control registers */ -static void s3c_rtc_setaie(int to) +static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) { unsigned int tmp; - pr_debug("%s: aie=%d\n", __func__, to); + pr_debug("%s: aie=%d\n", __func__, enabled); tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; - if (to) + if (enabled) tmp |= S3C2410_RTCALM_ALMEN; writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); -} - -static int s3c_rtc_setpie(struct device *dev, int enabled) -{ - unsigned int tmp; - - pr_debug("%s: pie=%d\n", __func__, enabled); - - spin_lock_irq(&s3c_rtc_pie_lock); - - if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - tmp = readw(s3c_rtc_base + S3C2410_RTCCON); - tmp &= ~S3C64XX_RTCCON_TICEN; - - if (enabled) - tmp |= S3C64XX_RTCCON_TICEN; - - writew(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); - } - - spin_unlock_irq(&s3c_rtc_pie_lock); return 0; } @@ -308,7 +280,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(alrm_en, base + S3C2410_RTCALM); - s3c_rtc_setaie(alrm->enabled); + s3c_rtc_setaie(dev, alrm->enabled); return 0; } @@ -365,7 +337,6 @@ static void s3c_rtc_release(struct device *dev) /* do not clear AIE here, it may be needed for wake */ - s3c_rtc_setpie(dev, 0); free_irq(s3c_rtc_alarmno, rtc_dev); free_irq(s3c_rtc_tickno, rtc_dev); } @@ -377,8 +348,6 @@ static const struct rtc_class_ops s3c_rtcops = { .set_time = s3c_rtc_settime, .read_alarm = s3c_rtc_getalarm, .set_alarm = s3c_rtc_setalarm, - .irq_set_freq = s3c_rtc_setfreq, - .irq_set_state = s3c_rtc_setpie, .proc = s3c_rtc_proc, .alarm_irq_enable = s3c_rtc_setaie, }; @@ -439,8 +408,7 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); rtc_device_unregister(rtc); - s3c_rtc_setpie(&dev->dev, 0); - s3c_rtc_setaie(0); + s3c_rtc_setaie(&dev->dev, 0); clk_disable(rtc_clk); clk_put(rtc_clk); @@ -595,8 +563,12 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) } s3c_rtc_enable(pdev, 0); - if (device_may_wakeup(&pdev->dev)) - enable_irq_wake(s3c_rtc_alarmno); + if (device_may_wakeup(&pdev->dev) && !wake_en) { + if (enable_irq_wake(s3c_rtc_alarmno) == 0) + wake_en = true; + else + dev_err(&pdev->dev, "enable_irq_wake failed\n"); + } return 0; } @@ -612,8 +584,10 @@ static int s3c_rtc_resume(struct platform_device *pdev) writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); } - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev) && wake_en) { disable_irq_wake(s3c_rtc_alarmno); + wake_en = false; + } return 0; } diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 88ea52b8647..0b40bb88a88 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -43,7 +43,6 @@ #define RTC_DEF_TRIM 0 static const unsigned long RTC_FREQ = 1024; -static unsigned long timer_freq; static struct rtc_time rtc_alarm; static DEFINE_SPINLOCK(sa1100_rtc_lock); @@ -156,114 +155,11 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int sa1100_irq_set_freq(struct device *dev, int freq) -{ - if (freq < 1 || freq > timer_freq) { - return -EINVAL; - } else { - struct rtc_device *rtc = (struct rtc_device *)dev; - - rtc->irq_freq = freq; - - return 0; - } -} - -static int rtc_timer1_count; - -static int sa1100_irq_set_state(struct device *dev, int enabled) -{ - spin_lock_irq(&sa1100_rtc_lock); - if (enabled) { - struct rtc_device *rtc = (struct rtc_device *)dev; - - OSMR1 = timer_freq / rtc->irq_freq + OSCR; - OIER |= OIER_E1; - rtc_timer1_count = 1; - } else { - OIER &= ~OIER_E1; - } - spin_unlock_irq(&sa1100_rtc_lock); - - return 0; -} - -static inline int sa1100_timer1_retrigger(struct rtc_device *rtc) -{ - unsigned long diff; - unsigned long period = timer_freq / rtc->irq_freq; - - spin_lock_irq(&sa1100_rtc_lock); - - do { - OSMR1 += period; - diff = OSMR1 - OSCR; - /* If OSCR > OSMR1, diff is a very large number (unsigned - * math). This means we have a lost interrupt. */ - } while (diff > period); - OIER |= OIER_E1; - - spin_unlock_irq(&sa1100_rtc_lock); - - return 0; -} - -static irqreturn_t timer1_interrupt(int irq, void *dev_id) -{ - struct platform_device *pdev = to_platform_device(dev_id); - struct rtc_device *rtc = platform_get_drvdata(pdev); - - /* - * If we match for the first time, rtc_timer1_count will be 1. - * Otherwise, we wrapped around (very unlikely but - * still possible) so compute the amount of missed periods. - * The match reg is updated only when the data is actually retrieved - * to avoid unnecessary interrupts. - */ - OSSR = OSSR_M1; /* clear match on timer1 */ - - rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); - - if (rtc_timer1_count == 1) - rtc_timer1_count = - (rtc->irq_freq * ((1 << 30) / (timer_freq >> 2))); - - /* retrigger. */ - sa1100_timer1_retrigger(rtc); - - return IRQ_HANDLED; -} - -static int sa1100_rtc_read_callback(struct device *dev, int data) -{ - if (data & RTC_PF) { - struct rtc_device *rtc = (struct rtc_device *)dev; - - /* interpolate missed periods and set match for the next */ - unsigned long period = timer_freq / rtc->irq_freq; - unsigned long oscr = OSCR; - unsigned long osmr1 = OSMR1; - unsigned long missed = (oscr - osmr1)/period; - data += missed << 8; - OSSR = OSSR_M1; /* clear match on timer 1 */ - OSMR1 = osmr1 + (missed + 1)*period; - /* Ensure we didn't miss another match in the mean time. - * Here we compare (match - OSCR) 8 instead of 0 -- - * see comment in pxa_timer_interrupt() for explanation. - */ - while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) { - data += 0x100; - OSSR = OSSR_M1; /* clear match on timer 1 */ - OSMR1 = osmr1 + period; - } - } - return data; -} - static int sa1100_rtc_open(struct device *dev) { int ret; - struct rtc_device *rtc = (struct rtc_device *)dev; + struct platform_device *plat_dev = to_platform_device(dev); + struct rtc_device *rtc = platform_get_drvdata(plat_dev); ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, "rtc 1Hz", dev); @@ -277,19 +173,11 @@ static int sa1100_rtc_open(struct device *dev) dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); goto fail_ai; } - ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, - "rtc timer", dev); - if (ret) { - dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); - goto fail_pi; - } rtc->max_user_freq = RTC_FREQ; - sa1100_irq_set_freq(dev, RTC_FREQ); + rtc_irq_set_freq(rtc, NULL, RTC_FREQ); return 0; - fail_pi: - free_irq(IRQ_RTCAlrm, dev); fail_ai: free_irq(IRQ_RTC1Hz, dev); fail_ui: @@ -304,38 +192,19 @@ static void sa1100_rtc_release(struct device *dev) OSSR = OSSR_M1; spin_unlock_irq(&sa1100_rtc_lock); - free_irq(IRQ_OST1, dev); free_irq(IRQ_RTCAlrm, dev); free_irq(IRQ_RTC1Hz, dev); } - -static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - switch (cmd) { - case RTC_AIE_OFF: - spin_lock_irq(&sa1100_rtc_lock); - RTSR &= ~RTSR_ALE; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_AIE_ON: - spin_lock_irq(&sa1100_rtc_lock); + spin_lock_irq(&sa1100_rtc_lock); + if (enabled) RTSR |= RTSR_ALE; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_UIE_OFF: - spin_lock_irq(&sa1100_rtc_lock); - RTSR &= ~RTSR_HZE; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_UIE_ON: - spin_lock_irq(&sa1100_rtc_lock); - RTSR |= RTSR_HZE; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - } - return -ENOIOCTLCMD; + else + RTSR &= ~RTSR_ALE; + spin_unlock_irq(&sa1100_rtc_lock); + return 0; } static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -385,39 +254,27 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { - struct rtc_device *rtc = (struct rtc_device *)dev; - - seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR); - seq_printf(seq, "update_IRQ\t: %s\n", - (RTSR & RTSR_HZE) ? "yes" : "no"); - seq_printf(seq, "periodic_IRQ\t: %s\n", - (OIER & OIER_E1) ? "yes" : "no"); - seq_printf(seq, "periodic_freq\t: %d\n", rtc->irq_freq); - seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR); + seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR); + seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR); return 0; } static const struct rtc_class_ops sa1100_rtc_ops = { .open = sa1100_rtc_open, - .read_callback = sa1100_rtc_read_callback, .release = sa1100_rtc_release, - .ioctl = sa1100_rtc_ioctl, .read_time = sa1100_rtc_read_time, .set_time = sa1100_rtc_set_time, .read_alarm = sa1100_rtc_read_alarm, .set_alarm = sa1100_rtc_set_alarm, .proc = sa1100_rtc_proc, - .irq_set_freq = sa1100_irq_set_freq, - .irq_set_state = sa1100_irq_set_state, + .alarm_irq_enable = sa1100_rtc_alarm_irq_enable, }; static int sa1100_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; - timer_freq = get_clock_tick_rate(); - /* * According to the manual we should be able to let RTTR be zero * and then a default diviser for a 32.768KHz clock is used. @@ -443,11 +300,6 @@ static int sa1100_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); - /* Set the irq_freq */ - /*TODO: Find out who is messing with this value after we initialize - * it here.*/ - rtc->irq_freq = RTC_FREQ; - /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). * diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 06e41ed9323..6ac55fd4841 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -344,29 +344,10 @@ static inline void sh_rtc_setcie(struct device *dev, unsigned int enable) spin_unlock_irq(&rtc->lock); } -static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int ret = 0; - - switch (cmd) { - case RTC_AIE_OFF: - case RTC_AIE_ON: - sh_rtc_setaie(dev, cmd == RTC_AIE_ON); - break; - case RTC_UIE_OFF: - rtc->periodic_freq &= ~PF_OXS; - sh_rtc_setcie(dev, 0); - break; - case RTC_UIE_ON: - rtc->periodic_freq |= PF_OXS; - sh_rtc_setcie(dev, 1); - break; - default: - ret = -ENOIOCTLCMD; - } - - return ret; + sh_rtc_setaie(dev, enabled); + return 0; } static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -596,14 +577,12 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) } static struct rtc_class_ops sh_rtc_ops = { - .ioctl = sh_rtc_ioctl, .read_time = sh_rtc_read_time, .set_time = sh_rtc_set_time, .read_alarm = sh_rtc_read_alarm, .set_alarm = sh_rtc_set_alarm, - .irq_set_state = sh_rtc_irq_set_state, - .irq_set_freq = sh_rtc_irq_set_freq, .proc = sh_rtc_proc, + .alarm_irq_enable = sh_rtc_alarm_irq_enable, }; static int __init sh_rtc_probe(struct platform_device *pdev) @@ -803,11 +782,11 @@ static void sh_rtc_set_irq_wake(struct device *dev, int enabled) struct platform_device *pdev = to_platform_device(dev); struct sh_rtc *rtc = platform_get_drvdata(pdev); - set_irq_wake(rtc->periodic_irq, enabled); + irq_set_irq_wake(rtc->periodic_irq, enabled); if (rtc->carry_irq > 0) { - set_irq_wake(rtc->carry_irq, enabled); - set_irq_wake(rtc->alarm_irq, enabled); + irq_set_irq_wake(rtc->carry_irq, enabled); + irq_set_irq_wake(rtc->alarm_irq, enabled); } } diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c new file mode 100644 index 00000000000..893bac2bb21 --- /dev/null +++ b/drivers/rtc/rtc-spear.c @@ -0,0 +1,534 @@ +/* + * drivers/rtc/rtc-spear.c + * + * Copyright (C) 2010 ST Microelectronics + * Rajeev Kumar<rajeev-dlh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/bcd.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +/* RTC registers */ +#define TIME_REG 0x00 +#define DATE_REG 0x04 +#define ALARM_TIME_REG 0x08 +#define ALARM_DATE_REG 0x0C +#define CTRL_REG 0x10 +#define STATUS_REG 0x14 + +/* TIME_REG & ALARM_TIME_REG */ +#define SECONDS_UNITS (0xf<<0) /* seconds units position */ +#define SECONDS_TENS (0x7<<4) /* seconds tens position */ +#define MINUTES_UNITS (0xf<<8) /* minutes units position */ +#define MINUTES_TENS (0x7<<12) /* minutes tens position */ +#define HOURS_UNITS (0xf<<16) /* hours units position */ +#define HOURS_TENS (0x3<<20) /* hours tens position */ + +/* DATE_REG & ALARM_DATE_REG */ +#define DAYS_UNITS (0xf<<0) /* days units position */ +#define DAYS_TENS (0x3<<4) /* days tens position */ +#define MONTHS_UNITS (0xf<<8) /* months units position */ +#define MONTHS_TENS (0x1<<12) /* months tens position */ +#define YEARS_UNITS (0xf<<16) /* years units position */ +#define YEARS_TENS (0xf<<20) /* years tens position */ +#define YEARS_HUNDREDS (0xf<<24) /* years hundereds position */ +#define YEARS_MILLENIUMS (0xf<<28) /* years millenium position */ + +/* MASK SHIFT TIME_REG & ALARM_TIME_REG*/ +#define SECOND_SHIFT 0x00 /* seconds units */ +#define MINUTE_SHIFT 0x08 /* minutes units position */ +#define HOUR_SHIFT 0x10 /* hours units position */ +#define MDAY_SHIFT 0x00 /* Month day shift */ +#define MONTH_SHIFT 0x08 /* Month shift */ +#define YEAR_SHIFT 0x10 /* Year shift */ + +#define SECOND_MASK 0x7F +#define MIN_MASK 0x7F +#define HOUR_MASK 0x3F +#define DAY_MASK 0x3F +#define MONTH_MASK 0x7F +#define YEAR_MASK 0xFFFF + +/* date reg equal to time reg, for debug only */ +#define TIME_BYP (1<<9) +#define INT_ENABLE (1<<31) /* interrupt enable */ + +/* STATUS_REG */ +#define CLK_UNCONNECTED (1<<0) +#define PEND_WR_TIME (1<<2) +#define PEND_WR_DATE (1<<3) +#define LOST_WR_TIME (1<<4) +#define LOST_WR_DATE (1<<5) +#define RTC_INT_MASK (1<<31) +#define STATUS_BUSY (PEND_WR_TIME | PEND_WR_DATE) +#define STATUS_FAIL (LOST_WR_TIME | LOST_WR_DATE) + +struct spear_rtc_config { + struct clk *clk; + spinlock_t lock; + void __iomem *ioaddr; +}; + +static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config) +{ + unsigned int val; + unsigned long flags; + + spin_lock_irqsave(&config->lock, flags); + val = readl(config->ioaddr + STATUS_REG); + val |= RTC_INT_MASK; + writel(val, config->ioaddr + STATUS_REG); + spin_unlock_irqrestore(&config->lock, flags); +} + +static inline void spear_rtc_enable_interrupt(struct spear_rtc_config *config) +{ + unsigned int val; + + val = readl(config->ioaddr + CTRL_REG); + if (!(val & INT_ENABLE)) { + spear_rtc_clear_interrupt(config); + val |= INT_ENABLE; + writel(val, config->ioaddr + CTRL_REG); + } +} + +static inline void spear_rtc_disable_interrupt(struct spear_rtc_config *config) +{ + unsigned int val; + + val = readl(config->ioaddr + CTRL_REG); + if (val & INT_ENABLE) { + val &= ~INT_ENABLE; + writel(val, config->ioaddr + CTRL_REG); + } +} + +static inline int is_write_complete(struct spear_rtc_config *config) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&config->lock, flags); + if ((readl(config->ioaddr + STATUS_REG)) & STATUS_FAIL) + ret = -EIO; + spin_unlock_irqrestore(&config->lock, flags); + + return ret; +} + +static void rtc_wait_not_busy(struct spear_rtc_config *config) +{ + int status, count = 0; + unsigned long flags; + + /* Assuming BUSY may stay active for 80 msec) */ + for (count = 0; count < 80; count++) { + spin_lock_irqsave(&config->lock, flags); + status = readl(config->ioaddr + STATUS_REG); + spin_unlock_irqrestore(&config->lock, flags); + if ((status & STATUS_BUSY) == 0) + break; + /* check status busy, after each msec */ + msleep(1); + } +} + +static irqreturn_t spear_rtc_irq(int irq, void *dev_id) +{ + struct rtc_device *rtc = (struct rtc_device *)dev_id; + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + unsigned long flags, events = 0; + unsigned int irq_data; + + spin_lock_irqsave(&config->lock, flags); + irq_data = readl(config->ioaddr + STATUS_REG); + spin_unlock_irqrestore(&config->lock, flags); + + if ((irq_data & RTC_INT_MASK)) { + spear_rtc_clear_interrupt(config); + events = RTC_IRQF | RTC_AF; + rtc_update_irq(rtc, 1, events); + return IRQ_HANDLED; + } else + return IRQ_NONE; + +} + +static int tm2bcd(struct rtc_time *tm) +{ + if (rtc_valid_tm(tm) != 0) + return -EINVAL; + tm->tm_sec = bin2bcd(tm->tm_sec); + tm->tm_min = bin2bcd(tm->tm_min); + tm->tm_hour = bin2bcd(tm->tm_hour); + tm->tm_mday = bin2bcd(tm->tm_mday); + tm->tm_mon = bin2bcd(tm->tm_mon + 1); + tm->tm_year = bin2bcd(tm->tm_year); + + return 0; +} + +static void bcd2tm(struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(tm->tm_sec); + tm->tm_min = bcd2bin(tm->tm_min); + tm->tm_hour = bcd2bin(tm->tm_hour); + tm->tm_mday = bcd2bin(tm->tm_mday); + tm->tm_mon = bcd2bin(tm->tm_mon) - 1; + /* epoch == 1900 */ + tm->tm_year = bcd2bin(tm->tm_year); +} + +/* + * spear_rtc_read_time - set the time + * @dev: rtc device in use + * @tm: holds date and time + * + * This function read time and date. On success it will return 0 + * otherwise -ve error is returned. + */ +static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + unsigned int time, date; + + /* we don't report wday/yday/isdst ... */ + rtc_wait_not_busy(config); + + time = readl(config->ioaddr + TIME_REG); + date = readl(config->ioaddr + DATE_REG); + tm->tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK; + tm->tm_min = (time >> MINUTE_SHIFT) & MIN_MASK; + tm->tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK; + tm->tm_mday = (date >> MDAY_SHIFT) & DAY_MASK; + tm->tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK; + tm->tm_year = (date >> YEAR_SHIFT) & YEAR_MASK; + + bcd2tm(tm); + return 0; +} + +/* + * spear_rtc_set_time - set the time + * @dev: rtc device in use + * @tm: holds date and time + * + * This function set time and date. On success it will return 0 + * otherwise -ve error is returned. + */ +static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + unsigned int time, date, err = 0; + + if (tm2bcd(tm) < 0) + return -EINVAL; + + rtc_wait_not_busy(config); + time = (tm->tm_sec << SECOND_SHIFT) | (tm->tm_min << MINUTE_SHIFT) | + (tm->tm_hour << HOUR_SHIFT); + date = (tm->tm_mday << MDAY_SHIFT) | (tm->tm_mon << MONTH_SHIFT) | + (tm->tm_year << YEAR_SHIFT); + writel(time, config->ioaddr + TIME_REG); + writel(date, config->ioaddr + DATE_REG); + err = is_write_complete(config); + if (err < 0) + return err; + + return 0; +} + +/* + * spear_rtc_read_alarm - read the alarm time + * @dev: rtc device in use + * @alm: holds alarm date and time + * + * This function read alarm time and date. On success it will return 0 + * otherwise -ve error is returned. + */ +static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + unsigned int time, date; + + rtc_wait_not_busy(config); + + time = readl(config->ioaddr + ALARM_TIME_REG); + date = readl(config->ioaddr + ALARM_DATE_REG); + alm->time.tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK; + alm->time.tm_min = (time >> MINUTE_SHIFT) & MIN_MASK; + alm->time.tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK; + alm->time.tm_mday = (date >> MDAY_SHIFT) & DAY_MASK; + alm->time.tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK; + alm->time.tm_year = (date >> YEAR_SHIFT) & YEAR_MASK; + + bcd2tm(&alm->time); + alm->enabled = readl(config->ioaddr + CTRL_REG) & INT_ENABLE; + + return 0; +} + +/* + * spear_rtc_set_alarm - set the alarm time + * @dev: rtc device in use + * @alm: holds alarm date and time + * + * This function set alarm time and date. On success it will return 0 + * otherwise -ve error is returned. + */ +static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + unsigned int time, date, err = 0; + + if (tm2bcd(&alm->time) < 0) + return -EINVAL; + + rtc_wait_not_busy(config); + + time = (alm->time.tm_sec << SECOND_SHIFT) | (alm->time.tm_min << + MINUTE_SHIFT) | (alm->time.tm_hour << HOUR_SHIFT); + date = (alm->time.tm_mday << MDAY_SHIFT) | (alm->time.tm_mon << + MONTH_SHIFT) | (alm->time.tm_year << YEAR_SHIFT); + + writel(time, config->ioaddr + ALARM_TIME_REG); + writel(date, config->ioaddr + ALARM_DATE_REG); + err = is_write_complete(config); + if (err < 0) + return err; + + if (alm->enabled) + spear_rtc_enable_interrupt(config); + else + spear_rtc_disable_interrupt(config); + + return 0; +} +static struct rtc_class_ops spear_rtc_ops = { + .read_time = spear_rtc_read_time, + .set_time = spear_rtc_set_time, + .read_alarm = spear_rtc_read_alarm, + .set_alarm = spear_rtc_set_alarm, +}; + +static int __devinit spear_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct rtc_device *rtc; + struct spear_rtc_config *config; + unsigned int status = 0; + int irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no resource defined\n"); + return -EBUSY; + } + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { + dev_err(&pdev->dev, "rtc region already claimed\n"); + return -EBUSY; + } + + config = kzalloc(sizeof(*config), GFP_KERNEL); + if (!config) { + dev_err(&pdev->dev, "out of memory\n"); + status = -ENOMEM; + goto err_release_region; + } + + config->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(config->clk)) { + status = PTR_ERR(config->clk); + goto err_kfree; + } + + status = clk_enable(config->clk); + if (status < 0) + goto err_clk_put; + + config->ioaddr = ioremap(res->start, resource_size(res)); + if (!config->ioaddr) { + dev_err(&pdev->dev, "ioremap fail\n"); + status = -ENOMEM; + goto err_disable_clock; + } + + spin_lock_init(&config->lock); + + rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) { + dev_err(&pdev->dev, "can't register RTC device, err %ld\n", + PTR_ERR(rtc)); + status = PTR_ERR(rtc); + goto err_iounmap; + } + + platform_set_drvdata(pdev, rtc); + dev_set_drvdata(&rtc->dev, config); + + /* alarm irqs */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no update irq?\n"); + status = irq; + goto err_clear_platdata; + } + + status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc); + if (status) { + dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \ + claimed\n", irq); + goto err_clear_platdata; + } + + if (!device_can_wakeup(&pdev->dev)) + device_init_wakeup(&pdev->dev, 1); + + return 0; + +err_clear_platdata: + platform_set_drvdata(pdev, NULL); + dev_set_drvdata(&rtc->dev, NULL); + rtc_device_unregister(rtc); +err_iounmap: + iounmap(config->ioaddr); +err_disable_clock: + clk_disable(config->clk); +err_clk_put: + clk_put(config->clk); +err_kfree: + kfree(config); +err_release_region: + release_mem_region(res->start, resource_size(res)); + + return status; +} + +static int __devexit spear_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + int irq; + struct resource *res; + + /* leave rtc running, but disable irqs */ + spear_rtc_disable_interrupt(config); + device_init_wakeup(&pdev->dev, 0); + irq = platform_get_irq(pdev, 0); + if (irq) + free_irq(irq, pdev); + clk_disable(config->clk); + clk_put(config->clk); + iounmap(config->ioaddr); + kfree(config); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) + release_mem_region(res->start, resource_size(res)); + platform_set_drvdata(pdev, NULL); + dev_set_drvdata(&rtc->dev, NULL); + rtc_device_unregister(rtc); + + return 0; +} + +#ifdef CONFIG_PM + +static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + int irq; + + irq = platform_get_irq(pdev, 0); + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(irq); + else { + spear_rtc_disable_interrupt(config); + clk_disable(config->clk); + } + + return 0; +} + +static int spear_rtc_resume(struct platform_device *pdev) +{ + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + int irq; + + irq = platform_get_irq(pdev, 0); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(irq); + else { + clk_enable(config->clk); + spear_rtc_enable_interrupt(config); + } + + return 0; +} + +#else +#define spear_rtc_suspend NULL +#define spear_rtc_resume NULL +#endif + +static void spear_rtc_shutdown(struct platform_device *pdev) +{ + struct rtc_device *rtc = platform_get_drvdata(pdev); + struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev); + + spear_rtc_disable_interrupt(config); + clk_disable(config->clk); +} + +static struct platform_driver spear_rtc_driver = { + .probe = spear_rtc_probe, + .remove = __devexit_p(spear_rtc_remove), + .suspend = spear_rtc_suspend, + .resume = spear_rtc_resume, + .shutdown = spear_rtc_shutdown, + .driver = { + .name = "rtc-spear", + }, +}; + +static int __init rtc_init(void) +{ + return platform_driver_register(&spear_rtc_driver); +} +module_init(rtc_init); + +static void __exit rtc_exit(void) +{ + platform_driver_unregister(&spear_rtc_driver); +} +module_exit(rtc_exit); + +MODULE_ALIAS("platform:rtc-spear"); +MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); +MODULE_DESCRIPTION("ST SPEAr Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 7e7d0c806f2..572e9534b59 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -115,19 +115,6 @@ static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int stmp3xxx_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - - if (enabled) - stmp3xxx_setl(BM_RTC_CTRL_ONEMSEC_IRQ_EN, - rtc_data->io + HW_RTC_CTRL); - else - stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN, - rtc_data->io + HW_RTC_CTRL); - return 0; -} - static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); @@ -149,8 +136,6 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) static struct rtc_class_ops stmp3xxx_rtc_ops = { .alarm_irq_enable = stmp3xxx_alarm_irq_enable, - .update_irq_enable = - stmp3xxx_update_irq_enable, .read_time = stmp3xxx_rtc_gettime, .set_mmss = stmp3xxx_rtc_set_mmss, .read_alarm = stmp3xxx_rtc_read_alarm, diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c new file mode 100644 index 00000000000..2fc31aac3f4 --- /dev/null +++ b/drivers/rtc/rtc-tegra.c @@ -0,0 +1,488 @@ +/* + * An RTC driver for the NVIDIA Tegra 200 series internal RTC. + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */ +#define TEGRA_RTC_REG_BUSY 0x004 +#define TEGRA_RTC_REG_SECONDS 0x008 +/* when msec is read, the seconds are buffered into shadow seconds. */ +#define TEGRA_RTC_REG_SHADOW_SECONDS 0x00c +#define TEGRA_RTC_REG_MILLI_SECONDS 0x010 +#define TEGRA_RTC_REG_SECONDS_ALARM0 0x014 +#define TEGRA_RTC_REG_SECONDS_ALARM1 0x018 +#define TEGRA_RTC_REG_MILLI_SECONDS_ALARM0 0x01c +#define TEGRA_RTC_REG_INTR_MASK 0x028 +/* write 1 bits to clear status bits */ +#define TEGRA_RTC_REG_INTR_STATUS 0x02c + +/* bits in INTR_MASK */ +#define TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM (1<<4) +#define TEGRA_RTC_INTR_MASK_SEC_CDN_ALARM (1<<3) +#define TEGRA_RTC_INTR_MASK_MSEC_ALARM (1<<2) +#define TEGRA_RTC_INTR_MASK_SEC_ALARM1 (1<<1) +#define TEGRA_RTC_INTR_MASK_SEC_ALARM0 (1<<0) + +/* bits in INTR_STATUS */ +#define TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM (1<<4) +#define TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM (1<<3) +#define TEGRA_RTC_INTR_STATUS_MSEC_ALARM (1<<2) +#define TEGRA_RTC_INTR_STATUS_SEC_ALARM1 (1<<1) +#define TEGRA_RTC_INTR_STATUS_SEC_ALARM0 (1<<0) + +struct tegra_rtc_info { + struct platform_device *pdev; + struct rtc_device *rtc_dev; + void __iomem *rtc_base; /* NULL if not initialized. */ + int tegra_rtc_irq; /* alarm and periodic irq */ + spinlock_t tegra_rtc_lock; +}; + +/* RTC hardware is busy when it is updating its values over AHB once + * every eight 32kHz clocks (~250uS). + * outside of these updates the CPU is free to write. + * CPU is always free to read. + */ +static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info) +{ + return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1; +} + +/* Wait for hardware to be ready for writing. + * This function tries to maximize the amount of time before the next update. + * It does this by waiting for the RTC to become busy with its periodic update, + * then returning once the RTC first becomes not busy. + * This periodic update (where the seconds and milliseconds are copied to the + * AHB side) occurs every eight 32kHz clocks (~250uS). + * The behavior of this function allows us to make some assumptions without + * introducing a race, because 250uS is plenty of time to read/write a value. + */ +static int tegra_rtc_wait_while_busy(struct device *dev) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + + int retries = 500; /* ~490 us is the worst case, ~250 us is best. */ + + /* first wait for the RTC to become busy. this is when it + * posts its updated seconds+msec registers to AHB side. */ + while (tegra_rtc_check_busy(info)) { + if (!retries--) + goto retry_failed; + udelay(1); + } + + /* now we have about 250 us to manipulate registers */ + return 0; + +retry_failed: + dev_err(dev, "write failed:retry count exceeded.\n"); + return -ETIMEDOUT; +} + +static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec, msec; + unsigned long sl_irq_flags; + + /* RTC hardware copies seconds to shadow seconds when a read + * of milliseconds occurs. use a lock to keep other threads out. */ + spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + + msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS); + sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS); + + spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + + rtc_time_to_tm(sec, tm); + + dev_vdbg(dev, "time read as %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec + ); + + return 0; +} + +static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec; + int ret; + + /* convert tm to seconds. */ + ret = rtc_valid_tm(tm); + if (ret) + return ret; + + rtc_tm_to_time(tm, &sec); + + dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + tm->tm_mon+1, + tm->tm_mday, + tm->tm_year+1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec + ); + + /* seconds only written if wait succeeded. */ + ret = tegra_rtc_wait_while_busy(dev); + if (!ret) + writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS); + + dev_vdbg(dev, "time read back as %d\n", + readl(info->rtc_base + TEGRA_RTC_REG_SECONDS)); + + return ret; +} + +static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec; + unsigned tmp; + + sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + + if (sec == 0) { + /* alarm is disabled. */ + alarm->enabled = 0; + alarm->time.tm_mon = -1; + alarm->time.tm_mday = -1; + alarm->time.tm_year = -1; + alarm->time.tm_hour = -1; + alarm->time.tm_min = -1; + alarm->time.tm_sec = -1; + } else { + /* alarm is enabled. */ + alarm->enabled = 1; + rtc_time_to_tm(sec, &alarm->time); + } + + tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0; + + return 0; +} + +static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned status; + unsigned long sl_irq_flags; + + tegra_rtc_wait_while_busy(dev); + spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + + /* read the original value, and OR in the flag. */ + status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + if (enabled) + status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */ + else + status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */ + + writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + + spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + + return 0; +} + +static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec; + + if (alarm->enabled) + rtc_tm_to_time(&alarm->time, &sec); + else + sec = 0; + + tegra_rtc_wait_while_busy(dev); + writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + dev_vdbg(dev, "alarm read back as %d\n", + readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); + + /* if successfully written and alarm is enabled ... */ + if (sec) { + tegra_rtc_alarm_irq_enable(dev, 1); + + dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + alarm->time.tm_mon+1, + alarm->time.tm_mday, + alarm->time.tm_year+1900, + alarm->time.tm_hour, + alarm->time.tm_min, + alarm->time.tm_sec); + } else { + /* disable alarm if 0 or write error. */ + dev_vdbg(dev, "alarm disabled\n"); + tegra_rtc_alarm_irq_enable(dev, 0); + } + + return 0; +} + +static int tegra_rtc_proc(struct device *dev, struct seq_file *seq) +{ + if (!dev || !dev->driver) + return 0; + + return seq_printf(seq, "name\t\t: %s\n", dev_name(dev)); +} + +static irqreturn_t tegra_rtc_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long events = 0; + unsigned status; + unsigned long sl_irq_flags; + + status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + if (status) { + /* clear the interrupt masks and status on any irq. */ + tegra_rtc_wait_while_busy(dev); + spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + } + + /* check if Alarm */ + if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)) + events |= RTC_IRQF | RTC_AF; + + /* check if Periodic */ + if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)) + events |= RTC_IRQF | RTC_PF; + + rtc_update_irq(info->rtc_dev, 1, events); + + return IRQ_HANDLED; +} + +static struct rtc_class_ops tegra_rtc_ops = { + .read_time = tegra_rtc_read_time, + .set_time = tegra_rtc_set_time, + .read_alarm = tegra_rtc_read_alarm, + .set_alarm = tegra_rtc_set_alarm, + .proc = tegra_rtc_proc, + .alarm_irq_enable = tegra_rtc_alarm_irq_enable, +}; + +static int __devinit tegra_rtc_probe(struct platform_device *pdev) +{ + struct tegra_rtc_info *info; + struct resource *res; + int ret; + + info = kzalloc(sizeof(struct tegra_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Unable to allocate resources for device.\n"); + ret = -EBUSY; + goto err_free_info; + } + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { + dev_err(&pdev->dev, + "Unable to request mem region for device.\n"); + ret = -EBUSY; + goto err_free_info; + } + + info->tegra_rtc_irq = platform_get_irq(pdev, 0); + if (info->tegra_rtc_irq <= 0) { + ret = -EBUSY; + goto err_release_mem_region; + } + + info->rtc_base = ioremap_nocache(res->start, resource_size(res)); + if (!info->rtc_base) { + dev_err(&pdev->dev, "Unable to grab IOs for device.\n"); + ret = -EBUSY; + goto err_release_mem_region; + } + + /* set context info. */ + info->pdev = pdev; + info->tegra_rtc_lock = __SPIN_LOCK_UNLOCKED(info->tegra_rtc_lock); + + platform_set_drvdata(pdev, info); + + /* clear out the hardware. */ + writel(0, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = rtc_device_register( + pdev->name, &pdev->dev, &tegra_rtc_ops, THIS_MODULE); + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + info->rtc_dev = NULL; + dev_err(&pdev->dev, + "Unable to register device (err=%d).\n", + ret); + goto err_iounmap; + } + + ret = request_irq(info->tegra_rtc_irq, tegra_rtc_irq_handler, + IRQF_TRIGGER_HIGH, "rtc alarm", &pdev->dev); + if (ret) { + dev_err(&pdev->dev, + "Unable to request interrupt for device (err=%d).\n", + ret); + goto err_dev_unreg; + } + + dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); + + return 0; + +err_dev_unreg: + rtc_device_unregister(info->rtc_dev); +err_iounmap: + iounmap(info->rtc_base); +err_release_mem_region: + release_mem_region(res->start, resource_size(res)); +err_free_info: + kfree(info); + + return ret; +} + +static int __devexit tegra_rtc_remove(struct platform_device *pdev) +{ + struct tegra_rtc_info *info = platform_get_drvdata(pdev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + free_irq(info->tegra_rtc_irq, &pdev->dev); + rtc_device_unregister(info->rtc_dev); + iounmap(info->rtc_base); + release_mem_region(res->start, resource_size(res)); + kfree(info); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct device *dev = &pdev->dev; + struct tegra_rtc_info *info = platform_get_drvdata(pdev); + + tegra_rtc_wait_while_busy(dev); + + /* only use ALARM0 as a wake source. */ + writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0, + info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + + dev_vdbg(dev, "alarm sec = %d\n", + readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); + + dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n", + device_may_wakeup(dev), info->tegra_rtc_irq); + + /* leave the alarms on as a wake source. */ + if (device_may_wakeup(dev)) + enable_irq_wake(info->tegra_rtc_irq); + + return 0; +} + +static int tegra_rtc_resume(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_rtc_info *info = platform_get_drvdata(pdev); + + dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n", + device_may_wakeup(dev)); + /* alarms were left on as a wake source, turn them off. */ + if (device_may_wakeup(dev)) + disable_irq_wake(info->tegra_rtc_irq); + + return 0; +} +#endif + +static void tegra_rtc_shutdown(struct platform_device *pdev) +{ + dev_vdbg(&pdev->dev, "disabling interrupts.\n"); + tegra_rtc_alarm_irq_enable(&pdev->dev, 0); +} + +MODULE_ALIAS("platform:tegra_rtc"); +static struct platform_driver tegra_rtc_driver = { + .remove = __devexit_p(tegra_rtc_remove), + .shutdown = tegra_rtc_shutdown, + .driver = { + .name = "tegra_rtc", + .owner = THIS_MODULE, + }, +#ifdef CONFIG_PM + .suspend = tegra_rtc_suspend, + .resume = tegra_rtc_resume, +#endif +}; + +static int __init tegra_rtc_init(void) +{ + return platform_driver_probe(&tegra_rtc_driver, tegra_rtc_probe); +} +module_init(tegra_rtc_init); + +static void __exit tegra_rtc_exit(void) +{ + platform_driver_unregister(&tegra_rtc_driver); +} +module_exit(tegra_rtc_exit); + +MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>"); +MODULE_DESCRIPTION("driver for Tegra internal RTC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 51725f7755b..7e96254bd36 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -50,24 +50,9 @@ static int test_rtc_proc(struct device *dev, struct seq_file *seq) return 0; } -static int test_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { - /* We do support interrupts, they're generated - * using the sysfs interface. - */ - switch (cmd) { - case RTC_PIE_ON: - case RTC_PIE_OFF: - case RTC_UIE_ON: - case RTC_UIE_OFF: - case RTC_AIE_ON: - case RTC_AIE_OFF: - return 0; - - default: - return -ENOIOCTLCMD; - } + return 0; } static const struct rtc_class_ops test_rtc_ops = { @@ -76,7 +61,7 @@ static const struct rtc_class_ops test_rtc_ops = { .read_alarm = test_rtc_read_alarm, .set_alarm = test_rtc_set_alarm, .set_mmss = test_rtc_set_mmss, - .ioctl = test_rtc_ioctl, + .alarm_irq_enable = test_rtc_alarm_irq_enable, }; static ssize_t test_irq_show(struct device *dev, @@ -93,11 +78,16 @@ static ssize_t test_irq_store(struct device *dev, struct rtc_device *rtc = platform_get_drvdata(plat_dev); retval = count; - if (strncmp(buf, "tick", 4) == 0) + if (strncmp(buf, "tick", 4) == 0 && rtc->pie_enabled) rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF); - else if (strncmp(buf, "alarm", 5) == 0) - rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF); - else if (strncmp(buf, "update", 6) == 0) + else if (strncmp(buf, "alarm", 5) == 0) { + struct rtc_wkalrm alrm; + int err = rtc_read_alarm(rtc, &alrm); + + if (!err && alrm.enabled) + rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF); + + } else if (strncmp(buf, "update", 6) == 0 && rtc->uie_rtctimer.enabled) rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF); else retval = -EINVAL; diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c new file mode 100644 index 00000000000..eb65dafee66 --- /dev/null +++ b/drivers/rtc/rtc-tile.c @@ -0,0 +1,162 @@ +/* + * Copyright 2011 Tilera Corporation. 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 + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * Tilera-specific RTC driver. + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +/* Platform device pointer. */ +static struct platform_device *tile_rtc_platform_device; + +/* + * RTC read routine. Gets time info from RTC chip via hypervisor syscall. + */ +static int read_rtc_time(struct device *dev, struct rtc_time *tm) +{ + HV_RTCTime hvtm = hv_get_rtc(); + + tm->tm_sec = hvtm.tm_sec; + tm->tm_min = hvtm.tm_min; + tm->tm_hour = hvtm.tm_hour; + tm->tm_mday = hvtm.tm_mday; + tm->tm_mon = hvtm.tm_mon; + tm->tm_year = hvtm.tm_year; + tm->tm_wday = 0; + tm->tm_yday = 0; + tm->tm_isdst = 0; + + if (rtc_valid_tm(tm) < 0) + dev_warn(dev, "Read invalid date/time from RTC\n"); + + return 0; +} + +/* + * RTC write routine. Sends time info to hypervisor via syscall, to be + * written to RTC chip. + */ +static int set_rtc_time(struct device *dev, struct rtc_time *tm) +{ + HV_RTCTime hvtm; + + hvtm.tm_sec = tm->tm_sec; + hvtm.tm_min = tm->tm_min; + hvtm.tm_hour = tm->tm_hour; + hvtm.tm_mday = tm->tm_mday; + hvtm.tm_mon = tm->tm_mon; + hvtm.tm_year = tm->tm_year; + + hv_set_rtc(hvtm); + + return 0; +} + +/* + * RTC read/write ops. + */ +static const struct rtc_class_ops tile_rtc_ops = { + .read_time = read_rtc_time, + .set_time = set_rtc_time, +}; + +/* + * Device probe routine. + */ +static int __devinit tile_rtc_probe(struct platform_device *dev) +{ + struct rtc_device *rtc; + + rtc = rtc_device_register("tile", + &dev->dev, &tile_rtc_ops, THIS_MODULE); + + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(dev, rtc); + + return 0; +} + +/* + * Device cleanup routine. + */ +static int __devexit tile_rtc_remove(struct platform_device *dev) +{ + struct rtc_device *rtc = platform_get_drvdata(dev); + + if (rtc) + rtc_device_unregister(rtc); + + platform_set_drvdata(dev, NULL); + + return 0; +} + +static struct platform_driver tile_rtc_platform_driver = { + .driver = { + .name = "rtc-tile", + .owner = THIS_MODULE, + }, + .probe = tile_rtc_probe, + .remove = __devexit_p(tile_rtc_remove), +}; + +/* + * Driver init routine. + */ +static int __init tile_rtc_driver_init(void) +{ + int err; + + err = platform_driver_register(&tile_rtc_platform_driver); + if (err) + return err; + + tile_rtc_platform_device = platform_device_alloc("rtc-tile", 0); + if (tile_rtc_platform_device == NULL) { + err = -ENOMEM; + goto exit_driver_unregister; + } + + err = platform_device_add(tile_rtc_platform_device); + if (err) + goto exit_device_put; + + return 0; + +exit_device_put: + platform_device_put(tile_rtc_platform_device); + +exit_driver_unregister: + platform_driver_unregister(&tile_rtc_platform_driver); + return err; +} + +/* + * Driver cleanup routine. + */ +static void __exit tile_rtc_driver_exit(void) +{ + platform_driver_unregister(&tile_rtc_platform_driver); +} + +module_init(tile_rtc_driver_init); +module_exit(tile_rtc_driver_exit); + +MODULE_DESCRIPTION("Tilera-specific Real Time Clock Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtc-tile"); diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index ed1b8682812..f9a2799c44d 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -213,18 +213,6 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) return ret; } -static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled) -{ - int ret; - - if (enabled) - ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - else - ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - - return ret; -} - /* * Gets current TWL RTC time and date parameters. * @@ -433,7 +421,6 @@ static struct rtc_class_ops twl_rtc_ops = { .read_alarm = twl_rtc_read_alarm, .set_alarm = twl_rtc_set_alarm, .alarm_irq_enable = twl_rtc_alarm_irq_enable, - .update_irq_enable = twl_rtc_update_irq_enable, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index c3244244e8c..c5698cda366 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -207,59 +207,9 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) return 0; } -static int vr41xx_rtc_irq_set_freq(struct device *dev, int freq) -{ - u64 count; - - if (!is_power_of_2(freq)) - return -EINVAL; - count = RTC_FREQUENCY; - do_div(count, freq); - - spin_lock_irq(&rtc_lock); - - periodic_count = count; - rtc1_write(RTCL1LREG, periodic_count); - rtc1_write(RTCL1HREG, periodic_count >> 16); - - spin_unlock_irq(&rtc_lock); - - return 0; -} - -static int vr41xx_rtc_irq_set_state(struct device *dev, int enabled) -{ - if (enabled) - enable_irq(pie_irq); - else - disable_irq(pie_irq); - - return 0; -} - static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { switch (cmd) { - case RTC_AIE_ON: - spin_lock_irq(&rtc_lock); - - if (!alarm_enabled) { - enable_irq(aie_irq); - alarm_enabled = 1; - } - - spin_unlock_irq(&rtc_lock); - break; - case RTC_AIE_OFF: - spin_lock_irq(&rtc_lock); - - if (alarm_enabled) { - disable_irq(aie_irq); - alarm_enabled = 0; - } - - spin_unlock_irq(&rtc_lock); - break; case RTC_EPOCH_READ: return put_user(epoch, (unsigned long __user *)arg); case RTC_EPOCH_SET: @@ -275,6 +225,24 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long return 0; } +static int vr41xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + spin_lock_irq(&rtc_lock); + if (enabled) { + if (!alarm_enabled) { + enable_irq(aie_irq); + alarm_enabled = 1; + } + } else { + if (alarm_enabled) { + disable_irq(aie_irq); + alarm_enabled = 0; + } + } + spin_unlock_irq(&rtc_lock); + return 0; +} + static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id) { struct platform_device *pdev = (struct platform_device *)dev_id; @@ -310,8 +278,6 @@ static const struct rtc_class_ops vr41xx_rtc_ops = { .set_time = vr41xx_rtc_set_time, .read_alarm = vr41xx_rtc_read_alarm, .set_alarm = vr41xx_rtc_set_alarm, - .irq_set_freq = vr41xx_rtc_irq_set_freq, - .irq_set_state = vr41xx_rtc_irq_set_state, }; static int __devinit rtc_probe(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c new file mode 100644 index 00000000000..b8bc862903a --- /dev/null +++ b/drivers/rtc/rtc-vt8500.c @@ -0,0 +1,366 @@ +/* + * drivers/rtc/rtc-vt8500.c + * + * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> + * + * Based on rtc-pxa.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/bcd.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* + * Register definitions + */ +#define VT8500_RTC_TS 0x00 /* Time set */ +#define VT8500_RTC_DS 0x04 /* Date set */ +#define VT8500_RTC_AS 0x08 /* Alarm set */ +#define VT8500_RTC_CR 0x0c /* Control */ +#define VT8500_RTC_TR 0x10 /* Time read */ +#define VT8500_RTC_DR 0x14 /* Date read */ +#define VT8500_RTC_WS 0x18 /* Write status */ +#define VT8500_RTC_CL 0x20 /* Calibration */ +#define VT8500_RTC_IS 0x24 /* Interrupt status */ +#define VT8500_RTC_ST 0x28 /* Status */ + +#define INVALID_TIME_BIT (1 << 31) + +#define DATE_CENTURY_S 19 +#define DATE_YEAR_S 11 +#define DATE_YEAR_MASK (0xff << DATE_YEAR_S) +#define DATE_MONTH_S 6 +#define DATE_MONTH_MASK (0x1f << DATE_MONTH_S) +#define DATE_DAY_MASK 0x3f + +#define TIME_DOW_S 20 +#define TIME_DOW_MASK (0x07 << TIME_DOW_S) +#define TIME_HOUR_S 14 +#define TIME_HOUR_MASK (0x3f << TIME_HOUR_S) +#define TIME_MIN_S 7 +#define TIME_MIN_MASK (0x7f << TIME_MIN_S) +#define TIME_SEC_MASK 0x7f + +#define ALARM_DAY_S 20 +#define ALARM_DAY_MASK (0x3f << ALARM_DAY_S) + +#define ALARM_DAY_BIT (1 << 29) +#define ALARM_HOUR_BIT (1 << 28) +#define ALARM_MIN_BIT (1 << 27) +#define ALARM_SEC_BIT (1 << 26) + +#define ALARM_ENABLE_MASK (ALARM_DAY_BIT \ + | ALARM_HOUR_BIT \ + | ALARM_MIN_BIT \ + | ALARM_SEC_BIT) + +#define VT8500_RTC_CR_ENABLE (1 << 0) /* Enable RTC */ +#define VT8500_RTC_CR_24H (1 << 1) /* 24h time format */ +#define VT8500_RTC_CR_SM_ENABLE (1 << 2) /* Enable periodic irqs */ +#define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */ +#define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */ + +struct vt8500_rtc { + void __iomem *regbase; + struct resource *res; + int irq_alarm; + int irq_hz; + struct rtc_device *rtc; + spinlock_t lock; /* Protects this structure */ +}; + +static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id) +{ + struct vt8500_rtc *vt8500_rtc = dev_id; + u32 isr; + unsigned long events = 0; + + spin_lock(&vt8500_rtc->lock); + + /* clear interrupt sources */ + isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS); + writel(isr, vt8500_rtc->regbase + VT8500_RTC_IS); + + spin_unlock(&vt8500_rtc->lock); + + if (isr & 1) + events |= RTC_AF | RTC_IRQF; + + /* Only second/minute interrupts are supported */ + if (isr & 2) + events |= RTC_UF | RTC_IRQF; + + rtc_update_irq(vt8500_rtc->rtc, 1, events); + + return IRQ_HANDLED; +} + +static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); + u32 date, time; + + date = readl(vt8500_rtc->regbase + VT8500_RTC_DR); + time = readl(vt8500_rtc->regbase + VT8500_RTC_TR); + + tm->tm_sec = bcd2bin(time & TIME_SEC_MASK); + tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S); + tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S); + tm->tm_mday = bcd2bin(date & DATE_DAY_MASK); + tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S); + tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S) + + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100); + tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S; + + return 0; +} + +static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); + + if (tm->tm_year < 100) { + dev_warn(dev, "Only years 2000-2199 are supported by the " + "hardware!\n"); + return -EINVAL; + } + + writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S) + | (bin2bcd(tm->tm_mon) << DATE_MONTH_S) + | (bin2bcd(tm->tm_mday)), + vt8500_rtc->regbase + VT8500_RTC_DS); + writel((bin2bcd(tm->tm_wday) << TIME_DOW_S) + | (bin2bcd(tm->tm_hour) << TIME_HOUR_S) + | (bin2bcd(tm->tm_min) << TIME_MIN_S) + | (bin2bcd(tm->tm_sec)), + vt8500_rtc->regbase + VT8500_RTC_TS); + + return 0; +} + +static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); + u32 isr, alarm; + + alarm = readl(vt8500_rtc->regbase + VT8500_RTC_AS); + isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS); + + alrm->time.tm_mday = bcd2bin((alarm & ALARM_DAY_MASK) >> ALARM_DAY_S); + alrm->time.tm_hour = bcd2bin((alarm & TIME_HOUR_MASK) >> TIME_HOUR_S); + alrm->time.tm_min = bcd2bin((alarm & TIME_MIN_MASK) >> TIME_MIN_S); + alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK)); + + alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0; + + alrm->pending = (isr & 1) ? 1 : 0; + return rtc_valid_tm(&alrm->time); +} + +static int vt8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); + + writel((alrm->enabled ? ALARM_ENABLE_MASK : 0) + | (bin2bcd(alrm->time.tm_mday) << ALARM_DAY_S) + | (bin2bcd(alrm->time.tm_hour) << TIME_HOUR_S) + | (bin2bcd(alrm->time.tm_min) << TIME_MIN_S) + | (bin2bcd(alrm->time.tm_sec)), + vt8500_rtc->regbase + VT8500_RTC_AS); + + return 0; +} + +static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); + unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_AS); + + if (enabled) + tmp |= ALARM_ENABLE_MASK; + else + tmp &= ~ALARM_ENABLE_MASK; + + writel(tmp, vt8500_rtc->regbase + VT8500_RTC_AS); + return 0; +} + +static int vt8500_update_irq_enable(struct device *dev, unsigned int enabled) +{ + struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); + unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_CR); + + if (enabled) + tmp |= VT8500_RTC_CR_SM_SEC | VT8500_RTC_CR_SM_ENABLE; + else + tmp &= ~VT8500_RTC_CR_SM_ENABLE; + + writel(tmp, vt8500_rtc->regbase + VT8500_RTC_CR); + return 0; +} + +static const struct rtc_class_ops vt8500_rtc_ops = { + .read_time = vt8500_rtc_read_time, + .set_time = vt8500_rtc_set_time, + .read_alarm = vt8500_rtc_read_alarm, + .set_alarm = vt8500_rtc_set_alarm, + .alarm_irq_enable = vt8500_alarm_irq_enable, + .update_irq_enable = vt8500_update_irq_enable, +}; + +static int __devinit vt8500_rtc_probe(struct platform_device *pdev) +{ + struct vt8500_rtc *vt8500_rtc; + int ret; + + vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL); + if (!vt8500_rtc) + return -ENOMEM; + + spin_lock_init(&vt8500_rtc->lock); + platform_set_drvdata(pdev, vt8500_rtc); + + vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!vt8500_rtc->res) { + dev_err(&pdev->dev, "No I/O memory resource defined\n"); + ret = -ENXIO; + goto err_free; + } + + vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0); + if (vt8500_rtc->irq_alarm < 0) { + dev_err(&pdev->dev, "No alarm IRQ resource defined\n"); + ret = -ENXIO; + goto err_free; + } + + vt8500_rtc->irq_hz = platform_get_irq(pdev, 1); + if (vt8500_rtc->irq_hz < 0) { + dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n"); + ret = -ENXIO; + goto err_free; + } + + vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, + resource_size(vt8500_rtc->res), + "vt8500-rtc"); + if (vt8500_rtc->res == NULL) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + ret = -EBUSY; + goto err_free; + } + + vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start, + resource_size(vt8500_rtc->res)); + if (!vt8500_rtc->regbase) { + dev_err(&pdev->dev, "Unable to map RTC I/O memory\n"); + ret = -EBUSY; + goto err_release; + } + + /* Enable the second/minute interrupt generation and enable RTC */ + writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H + | VT8500_RTC_CR_SM_ENABLE | VT8500_RTC_CR_SM_SEC, + vt8500_rtc->regbase + VT8500_RTC_CR); + + vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev, + &vt8500_rtc_ops, THIS_MODULE); + if (IS_ERR(vt8500_rtc->rtc)) { + ret = PTR_ERR(vt8500_rtc->rtc); + dev_err(&pdev->dev, + "Failed to register RTC device -> %d\n", ret); + goto err_unmap; + } + + ret = request_irq(vt8500_rtc->irq_hz, vt8500_rtc_irq, 0, + "rtc 1Hz", vt8500_rtc); + if (ret < 0) { + dev_err(&pdev->dev, "can't get irq %i, err %d\n", + vt8500_rtc->irq_hz, ret); + goto err_unreg; + } + + ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, + "rtc alarm", vt8500_rtc); + if (ret < 0) { + dev_err(&pdev->dev, "can't get irq %i, err %d\n", + vt8500_rtc->irq_alarm, ret); + goto err_free_hz; + } + + return 0; + +err_free_hz: + free_irq(vt8500_rtc->irq_hz, vt8500_rtc); +err_unreg: + rtc_device_unregister(vt8500_rtc->rtc); +err_unmap: + iounmap(vt8500_rtc->regbase); +err_release: + release_mem_region(vt8500_rtc->res->start, + resource_size(vt8500_rtc->res)); +err_free: + kfree(vt8500_rtc); + return ret; +} + +static int __devexit vt8500_rtc_remove(struct platform_device *pdev) +{ + struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); + + free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); + free_irq(vt8500_rtc->irq_hz, vt8500_rtc); + + rtc_device_unregister(vt8500_rtc->rtc); + + /* Disable alarm matching */ + writel(0, vt8500_rtc->regbase + VT8500_RTC_IS); + iounmap(vt8500_rtc->regbase); + release_mem_region(vt8500_rtc->res->start, + resource_size(vt8500_rtc->res)); + + kfree(vt8500_rtc); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver vt8500_rtc_driver = { + .probe = vt8500_rtc_probe, + .remove = __devexit_p(vt8500_rtc_remove), + .driver = { + .name = "vt8500-rtc", + .owner = THIS_MODULE, + }, +}; + +static int __init vt8500_rtc_init(void) +{ + return platform_driver_register(&vt8500_rtc_driver); +} +module_init(vt8500_rtc_init); + +static void __exit vt8500_rtc_exit(void) +{ + platform_driver_unregister(&vt8500_rtc_driver); +} +module_exit(vt8500_rtc_exit); + +MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); +MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:vt8500-rtc"); diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 82931dc65c0..bdc909bd56d 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -315,21 +315,6 @@ static int wm831x_rtc_alarm_irq_enable(struct device *dev, return wm831x_rtc_stop_alarm(wm831x_rtc); } -static int wm831x_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); - int val; - - if (enabled) - val = 1 << WM831X_RTC_PINT_FREQ_SHIFT; - else - val = 0; - - return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, - WM831X_RTC_PINT_FREQ_MASK, val); -} - static irqreturn_t wm831x_alm_irq(int irq, void *data) { struct wm831x_rtc *wm831x_rtc = data; @@ -354,7 +339,6 @@ static const struct rtc_class_ops wm831x_rtc_ops = { .read_alarm = wm831x_rtc_readalarm, .set_alarm = wm831x_rtc_setalarm, .alarm_irq_enable = wm831x_rtc_alarm_irq_enable, - .update_irq_enable = wm831x_rtc_update_irq_enable, }; #ifdef CONFIG_PM diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 3d0dc76b38a..66421426e40 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -302,26 +302,6 @@ static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static int wm8350_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - 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; -} - static irqreturn_t wm8350_rtc_alarm_handler(int irq, void *data) { struct wm8350 *wm8350 = data; @@ -357,7 +337,6 @@ static const struct rtc_class_ops wm8350_rtc_ops = { .read_alarm = wm8350_rtc_readalarm, .set_alarm = wm8350_rtc_setalarm, .alarm_irq_enable = wm8350_rtc_alarm_irq_enable, - .update_irq_enable = wm8350_rtc_update_irq_enable, }; #ifdef CONFIG_PM diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 9aae49139a0..b00aad2620d 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -573,7 +573,7 @@ static int x1205_probe(struct i2c_client *client, i2c_set_clientdata(client, rtc); - /* Check for power failures and eventualy enable the osc */ + /* Check for power failures and eventually enable the osc */ if ((err = x1205_get_status(client, &sr)) == 0) { if (sr & X1205_SR_RTCF) { dev_err(&client->dev, |
