diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-ab3100.c | 41 | ||||
-rw-r--r-- | drivers/rtc/rtc-ab8500.c | 363 | ||||
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 88 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1302.c | 85 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1374.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-isl1208.c | 45 | ||||
-rw-r--r-- | drivers/rtc/rtc-m41t80.c | 22 | ||||
-rw-r--r-- | drivers/rtc/rtc-mpc5121.c | 14 | ||||
-rw-r--r-- | drivers/rtc/rtc-mxc.c | 25 | ||||
-rw-r--r-- | drivers/rtc/rtc-rx8025.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-s35390a.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 112 | ||||
-rw-r--r-- | drivers/rtc/rtc-wm831x.c | 16 |
15 files changed, 639 insertions, 188 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 50ac047cd13..10ba12c8c5e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -611,6 +611,13 @@ config RTC_DRV_AB3100 Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC support. This chip contains a battery- and capacitor-backed RTC. +config RTC_DRV_AB8500 + tristate "ST-Ericsson AB8500 RTC" + depends on AB8500_CORE + help + Select this to enable the ST-Ericsson AB8500 power management IC RTC + support. This chip contains a battery- and capacitor-backed RTC. + config RTC_DRV_NUC900 tristate "NUC910/NUC920 RTC driver" depends on RTC_CLASS && ARCH_W90X900 @@ -640,7 +647,7 @@ config RTC_DRV_OMAP config RTC_DRV_S3C tristate "Samsung S3C series SoC RTC" - depends on ARCH_S3C2410 + depends on ARCH_S3C2410 || ARCH_S3C64XX help RTC (Realtime Clock) driver for the clock inbuilt into the Samsung S3C24XX series of SoCs. This can provide periodic diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 245311a1348..5adbba7cf89 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -18,6 +18,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o # Keep the list ordered. obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o +obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c index 4704aac2b5a..d26780ea254 100644 --- a/drivers/rtc/rtc-ab3100.c +++ b/drivers/rtc/rtc-ab3100.c @@ -9,7 +9,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/rtc.h> -#include <linux/mfd/ab3100.h> +#include <linux/mfd/abx500.h> /* Clock rate in Hz */ #define AB3100_RTC_CLOCK_RATE 32768 @@ -45,7 +45,6 @@ */ static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs) { - struct ab3100 *ab3100_data = dev_get_drvdata(dev); u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2, AB3100_TI3, AB3100_TI4, AB3100_TI5}; unsigned char buf[6]; @@ -61,27 +60,26 @@ static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs) buf[5] = (fat_time >> 40) & 0xFF; for (i = 0; i < 6; i++) { - err = ab3100_set_register_interruptible(ab3100_data, + err = abx500_set_register_interruptible(dev, 0, regs[i], buf[i]); if (err) return err; } /* Set the flag to mark that the clock is now set */ - return ab3100_mask_and_set_register_interruptible(ab3100_data, + return abx500_mask_and_set_register_interruptible(dev, 0, AB3100_RTC, - 0xFE, 0x01); + 0x01, 0x01); } static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct ab3100 *ab3100_data = dev_get_drvdata(dev); unsigned long time; u8 rtcval; int err; - err = ab3100_get_register_interruptible(ab3100_data, + err = abx500_get_register_interruptible(dev, 0, AB3100_RTC, &rtcval); if (err) return err; @@ -94,7 +92,7 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm) u8 buf[6]; /* Read out time registers */ - err = ab3100_get_register_page_interruptible(ab3100_data, + err = abx500_get_register_page_interruptible(dev, 0, AB3100_TI0, buf, 6); if (err != 0) @@ -114,7 +112,6 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct ab3100 *ab3100_data = dev_get_drvdata(dev); unsigned long time; u64 fat_time; u8 buf[6]; @@ -122,7 +119,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) int err; /* Figure out if alarm is enabled or not */ - err = ab3100_get_register_interruptible(ab3100_data, + err = abx500_get_register_interruptible(dev, 0, AB3100_RTC, &rtcval); if (err) return err; @@ -133,7 +130,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) /* No idea how this could be represented */ alarm->pending = 0; /* Read out alarm registers, only 4 bytes */ - err = ab3100_get_register_page_interruptible(ab3100_data, + err = abx500_get_register_page_interruptible(dev, 0, AB3100_AL0, buf, 4); if (err) return err; @@ -148,7 +145,6 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct ab3100 *ab3100_data = dev_get_drvdata(dev); u8 regs[] = {AB3100_AL0, AB3100_AL1, AB3100_AL2, AB3100_AL3}; unsigned char buf[4]; unsigned long secs; @@ -165,21 +161,19 @@ static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) /* Set the alarm */ for (i = 0; i < 4; i++) { - err = ab3100_set_register_interruptible(ab3100_data, + err = abx500_set_register_interruptible(dev, 0, regs[i], buf[i]); if (err) return err; } /* Then enable the alarm */ - return ab3100_mask_and_set_register_interruptible(ab3100_data, - AB3100_RTC, ~(1 << 2), + return abx500_mask_and_set_register_interruptible(dev, 0, + AB3100_RTC, (1 << 2), alarm->enabled << 2); } static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled) { - struct ab3100 *ab3100_data = dev_get_drvdata(dev); - /* * It's not possible to enable/disable the alarm IRQ for this RTC. * It does not actually trigger any IRQ: instead its only function is @@ -188,12 +182,12 @@ static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled) * and need to be handled there instead. */ if (enabled) - return ab3100_mask_and_set_register_interruptible(ab3100_data, - AB3100_RTC, ~(1 << 2), + return abx500_mask_and_set_register_interruptible(dev, 0, + AB3100_RTC, (1 << 2), 1 << 2); else - return ab3100_mask_and_set_register_interruptible(ab3100_data, - AB3100_RTC, ~(1 << 2), + return abx500_mask_and_set_register_interruptible(dev, 0, + AB3100_RTC, (1 << 2), 0); } @@ -210,10 +204,9 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) int err; u8 regval; struct rtc_device *rtc; - struct ab3100 *ab3100_data = platform_get_drvdata(pdev); /* The first RTC register needs special treatment */ - err = ab3100_get_register_interruptible(ab3100_data, + err = abx500_get_register_interruptible(&pdev->dev, 0, AB3100_RTC, ®val); if (err) { dev_err(&pdev->dev, "unable to read RTC register\n"); @@ -231,7 +224,7 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) * This bit remains until RTC power is lost. */ regval = 1 | RTC_SETTING; - err = ab3100_set_register_interruptible(ab3100_data, + err = abx500_set_register_interruptible(&pdev->dev, 0, AB3100_RTC, regval); /* Ignore any error on this write */ } diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c new file mode 100644 index 00000000000..2fda03125e5 --- /dev/null +++ b/drivers/rtc/rtc-ab8500.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License terms: GNU General Public License (GPL) version 2 + * Author: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com> + * + * RTC clock driver for the RTC part of the AB8500 Power management chip. + * Based on RTC clock driver for the AB3100 Analog Baseband Chip by + * Linus Walleij <linus.walleij@stericsson.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/mfd/ab8500.h> +#include <linux/delay.h> + +#define AB8500_RTC_SOFF_STAT_REG 0x0F00 +#define AB8500_RTC_CC_CONF_REG 0x0F01 +#define AB8500_RTC_READ_REQ_REG 0x0F02 +#define AB8500_RTC_WATCH_TSECMID_REG 0x0F03 +#define AB8500_RTC_WATCH_TSECHI_REG 0x0F04 +#define AB8500_RTC_WATCH_TMIN_LOW_REG 0x0F05 +#define AB8500_RTC_WATCH_TMIN_MID_REG 0x0F06 +#define AB8500_RTC_WATCH_TMIN_HI_REG 0x0F07 +#define AB8500_RTC_ALRM_MIN_LOW_REG 0x0F08 +#define AB8500_RTC_ALRM_MIN_MID_REG 0x0F09 +#define AB8500_RTC_ALRM_MIN_HI_REG 0x0F0A +#define AB8500_RTC_STAT_REG 0x0F0B +#define AB8500_RTC_BKUP_CHG_REG 0x0F0C +#define AB8500_RTC_FORCE_BKUP_REG 0x0F0D +#define AB8500_RTC_CALIB_REG 0x0F0E +#define AB8500_RTC_SWITCH_STAT_REG 0x0F0F +#define AB8500_REV_REG 0x1080 + +/* RtcReadRequest bits */ +#define RTC_READ_REQUEST 0x01 +#define RTC_WRITE_REQUEST 0x02 + +/* RtcCtrl bits */ +#define RTC_ALARM_ENA 0x04 +#define RTC_STATUS_DATA 0x01 + +#define COUNTS_PER_SEC (0xF000 / 60) +#define AB8500_RTC_EPOCH 2000 + +static const unsigned long ab8500_rtc_time_regs[] = { + AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG, + AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG, + AB8500_RTC_WATCH_TSECMID_REG +}; + +static const unsigned long ab8500_rtc_alarm_regs[] = { + AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG, + AB8500_RTC_ALRM_MIN_LOW_REG +}; + +/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */ +static unsigned long get_elapsed_seconds(int year) +{ + unsigned long secs; + struct rtc_time tm = { + .tm_year = year - 1900, + .tm_mday = 1, + }; + + /* + * This function calculates secs from 1970 and not from + * 1900, even if we supply the offset from year 1900. + */ + rtc_tm_to_time(&tm, &secs); + return secs; +} + +static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); + unsigned long timeout = jiffies + HZ; + int retval, i; + unsigned long mins, secs; + unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; + + /* Request a data read */ + retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, + RTC_READ_REQUEST); + if (retval < 0) + return retval; + + /* Early AB8500 chips will not clear the rtc read request bit */ + if (ab8500->revision == 0) { + msleep(1); + } else { + /* Wait for some cycles after enabling the rtc read in ab8500 */ + while (time_before(jiffies, timeout)) { + retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG); + if (retval < 0) + return retval; + + if (!(retval & RTC_READ_REQUEST)) + break; + + msleep(1); + } + } + + /* Read the Watchtime registers */ + for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { + retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]); + if (retval < 0) + return retval; + buf[i] = retval; + } + + mins = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + + secs = (buf[3] << 8) | buf[4]; + secs = secs / COUNTS_PER_SEC; + secs = secs + (mins * 60); + + /* Add back the initially subtracted number of seconds */ + secs += get_elapsed_seconds(AB8500_RTC_EPOCH); + + rtc_time_to_tm(secs, tm); + return rtc_valid_tm(tm); +} + +static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); + int retval, i; + unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)]; + unsigned long no_secs, no_mins, secs = 0; + + if (tm->tm_year < (AB8500_RTC_EPOCH - 1900)) { + dev_dbg(dev, "year should be equal to or greater than %d\n", + AB8500_RTC_EPOCH); + return -EINVAL; + } + + /* Get the number of seconds since 1970 */ + rtc_tm_to_time(tm, &secs); + + /* + * Convert it to the number of seconds since 01-01-2000 00:00:00, since + * we only have a small counter in the RTC. + */ + secs -= get_elapsed_seconds(AB8500_RTC_EPOCH); + + no_mins = secs / 60; + + no_secs = secs % 60; + /* Make the seconds count as per the RTC resolution */ + no_secs = no_secs * COUNTS_PER_SEC; + + buf[4] = no_secs & 0xFF; + buf[3] = (no_secs >> 8) & 0xFF; + + buf[2] = no_mins & 0xFF; + buf[1] = (no_mins >> 8) & 0xFF; + buf[0] = (no_mins >> 16) & 0xFF; + + for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) { + retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]); + if (retval < 0) + return retval; + } + + /* Request a data write */ + return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST); +} + +static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); + int retval, i; + int rtc_ctrl; + unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; + unsigned long secs, mins; + + /* Check if the alarm is enabled or not */ + rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG); + if (rtc_ctrl < 0) + return rtc_ctrl; + + if (rtc_ctrl & RTC_ALARM_ENA) + alarm->enabled = 1; + else + alarm->enabled = 0; + + alarm->pending = 0; + + for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { + retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]); + if (retval < 0) + return retval; + buf[i] = retval; + } + + mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]); + secs = mins * 60; + + /* Add back the initially subtracted number of seconds */ + secs += get_elapsed_seconds(AB8500_RTC_EPOCH); + + rtc_time_to_tm(secs, &alarm->time); + + return rtc_valid_tm(&alarm->time); +} + +static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); + + return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA, + enabled ? RTC_ALARM_ENA : 0); +} + +static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct ab8500 *ab8500 = dev_get_drvdata(dev->parent); + int retval, i; + unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; + unsigned long mins, secs = 0; + + if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) { + dev_dbg(dev, "year should be equal to or greater than %d\n", + AB8500_RTC_EPOCH); + return -EINVAL; + } + + /* Get the number of seconds since 1970 */ + rtc_tm_to_time(&alarm->time, &secs); + + /* + * Convert it to the number of seconds since 01-01-2000 00:00:00, since + * we only have a small counter in the RTC. + */ + secs -= get_elapsed_seconds(AB8500_RTC_EPOCH); + + mins = secs / 60; + + buf[2] = mins & 0xFF; + buf[1] = (mins >> 8) & 0xFF; + buf[0] = (mins >> 16) & 0xFF; + + /* Set the alarm time */ + for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) { + retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]); + if (retval < 0) + return retval; + } + + return ab8500_rtc_irq_enable(dev, alarm->enabled); +} + +static irqreturn_t rtc_alarm_handler(int irq, void *data) +{ + struct rtc_device *rtc = data; + unsigned long events = RTC_IRQF | RTC_AF; + + dev_dbg(&rtc->dev, "%s\n", __func__); + rtc_update_irq(rtc, 1, events); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops ab8500_rtc_ops = { + .read_time = ab8500_rtc_read_time, + .set_time = ab8500_rtc_set_time, + .read_alarm = ab8500_rtc_read_alarm, + .set_alarm = ab8500_rtc_set_alarm, + .alarm_irq_enable = ab8500_rtc_irq_enable, +}; + +static int __devinit ab8500_rtc_probe(struct platform_device *pdev) +{ + struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); + int err; + struct rtc_device *rtc; + int rtc_ctrl; + int irq; + + irq = platform_get_irq_byname(pdev, "ALARM"); + if (irq < 0) + return irq; + + /* For RTC supply test */ + err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA, + RTC_STATUS_DATA); + if (err < 0) + return err; + + /* Wait for reset by the PorRtc */ + msleep(1); + + rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG); + if (rtc_ctrl < 0) + return rtc_ctrl; + + /* Check if the RTC Supply fails */ + if (!(rtc_ctrl & RTC_STATUS_DATA)) { + dev_err(&pdev->dev, "RTC supply failure\n"); + return -ENODEV; + } + + rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) { + dev_err(&pdev->dev, "Registration failed\n"); + err = PTR_ERR(rtc); + return err; + } + + err = request_threaded_irq(irq, NULL, rtc_alarm_handler, 0, + "ab8500-rtc", rtc); + if (err < 0) { + rtc_device_unregister(rtc); + return err; + } + + platform_set_drvdata(pdev, rtc); + + return 0; +} + +static int __devexit ab8500_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtc = platform_get_drvdata(pdev); + int irq = platform_get_irq_byname(pdev, "ALARM"); + + free_irq(irq, rtc); + rtc_device_unregister(rtc); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ab8500_rtc_driver = { + .driver = { + .name = "ab8500-rtc", + .owner = THIS_MODULE, + }, + .probe = ab8500_rtc_probe, + .remove = __devexit_p(ab8500_rtc_remove), +}; + +static int __init ab8500_rtc_init(void) +{ + return platform_driver_register(&ab8500_rtc_driver); +} + +static void __exit ab8500_rtc_exit(void) +{ + platform_driver_unregister(&ab8500_rtc_driver); +} + +module_init(ab8500_rtc_init); +module_exit(ab8500_rtc_exit); +MODULE_AUTHOR("Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>"); +MODULE_DESCRIPTION("AB8500 RTC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index ece4dbddc0e..11b8ea29d2b 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -238,31 +238,32 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) rtc_control = CMOS_READ(RTC_CONTROL); spin_unlock_irq(&rtc_lock); - /* REVISIT this assumes PC style usage: always BCD */ - - if (((unsigned)t->time.tm_sec) < 0x60) - t->time.tm_sec = bcd2bin(t->time.tm_sec); - else - t->time.tm_sec = -1; - if (((unsigned)t->time.tm_min) < 0x60) - t->time.tm_min = bcd2bin(t->time.tm_min); - else - t->time.tm_min = -1; - if (((unsigned)t->time.tm_hour) < 0x24) - t->time.tm_hour = bcd2bin(t->time.tm_hour); - else - t->time.tm_hour = -1; - - if (cmos->day_alrm) { - if (((unsigned)t->time.tm_mday) <= 0x31) - t->time.tm_mday = bcd2bin(t->time.tm_mday); + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + if (((unsigned)t->time.tm_sec) < 0x60) + t->time.tm_sec = bcd2bin(t->time.tm_sec); else - t->time.tm_mday = -1; - if (cmos->mon_alrm) { - if (((unsigned)t->time.tm_mon) <= 0x12) - t->time.tm_mon = bcd2bin(t->time.tm_mon) - 1; + t->time.tm_sec = -1; + if (((unsigned)t->time.tm_min) < 0x60) + t->time.tm_min = bcd2bin(t->time.tm_min); + else + t->time.tm_min = -1; + if (((unsigned)t->time.tm_hour) < 0x24) + t->time.tm_hour = bcd2bin(t->time.tm_hour); + else + t->time.tm_hour = -1; + + if (cmos->day_alrm) { + if (((unsigned)t->time.tm_mday) <= 0x31) + t->time.tm_mday = bcd2bin(t->time.tm_mday); else - t->time.tm_mon = -1; + t->time.tm_mday = -1; + + if (cmos->mon_alrm) { + if (((unsigned)t->time.tm_mon) <= 0x12) + t->time.tm_mon = bcd2bin(t->time.tm_mon)-1; + else + t->time.tm_mon = -1; + } } } t->time.tm_year = -1; @@ -322,29 +323,26 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask) static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); - unsigned char mon, mday, hrs, min, sec; + unsigned char mon, mday, hrs, min, sec, rtc_control; if (!is_valid_irq(cmos->irq)) return -EIO; - /* REVISIT this assumes PC style usage: always BCD */ - - /* Writing 0xff means "don't care" or "match all". */ - mon = t->time.tm_mon + 1; - mon = (mon <= 12) ? bin2bcd(mon) : 0xff; - mday = t->time.tm_mday; - mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; - hrs = t->time.tm_hour; - hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff; - min = t->time.tm_min; - min = (min < 60) ? bin2bcd(min) : 0xff; - sec = t->time.tm_sec; - sec = (sec < 60) ? bin2bcd(sec) : 0xff; + + rtc_control = CMOS_READ(RTC_CONTROL); + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + /* Writing 0xff means "don't care" or "match all". */ + mon = (mon <= 12) ? bin2bcd(mon) : 0xff; + mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; + hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff; + min = (min < 60) ? bin2bcd(min) : 0xff; + sec = (sec < 60) ? bin2bcd(sec) : 0xff; + } spin_lock_irq(&rtc_lock); @@ -478,7 +476,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq) "update_IRQ\t: %s\n" "HPET_emulated\t: %s\n" // "square_wave\t: %s\n" - // "BCD\t\t: %s\n" + "BCD\t\t: %s\n" "DST_enable\t: %s\n" "periodic_freq\t: %d\n" "batt_status\t: %s\n", @@ -486,7 +484,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq) (rtc_control & RTC_UIE) ? "yes" : "no", is_hpet_enabled() ? "yes" : "no", // (rtc_control & RTC_SQWE) ? "yes" : "no", - // (rtc_control & RTC_DM_BINARY) ? "no" : "yes", + (rtc_control & RTC_DM_BINARY) ? "no" : "yes", (rtc_control & RTC_DST_EN) ? "yes" : "no", cmos->rtc->irq_freq, (valid & RTC_VRT) ? "okay" : "dead"); @@ -721,6 +719,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) } } + cmos_rtc.dev = dev; + dev_set_drvdata(dev, &cmos_rtc); + cmos_rtc.rtc = rtc_device_register(driver_name, dev, &cmos_rtc_ops, THIS_MODULE); if (IS_ERR(cmos_rtc.rtc)) { @@ -728,8 +729,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup0; } - cmos_rtc.dev = dev; - dev_set_drvdata(dev, &cmos_rtc); rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); @@ -751,12 +750,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) spin_unlock_irq(&rtc_lock); - /* FIXME teach the alarm code how to handle binary mode; + /* FIXME: * <asm-generic/rtc.h> doesn't know 12-hour mode either. */ - if (is_valid_irq(rtc_irq) && - (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) { - dev_dbg(dev, "only 24-hr BCD mode supported\n"); + if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { + dev_warn(dev, "only 24-hr supported\n"); retval = -ENXIO; goto cleanup1; } diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 532acf9b05d..359d1e04626 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -16,7 +16,6 @@ #include <linux/rtc.h> #include <linux/io.h> #include <linux/bcd.h> -#include <asm/rtc.h> #define DRV_NAME "rtc-ds1302" #define DRV_VERSION "0.1.1" @@ -34,14 +33,55 @@ #define RTC_ADDR_MIN 0x01 /* Address of minute register */ #define RTC_ADDR_SEC 0x00 /* Address of second register */ +#ifdef CONFIG_SH_SECUREEDGE5410 +#include <asm/rtc.h> +#include <mach/snapgear.h> + #define RTC_RESET 0x1000 #define RTC_IODATA 0x0800 #define RTC_SCLK 0x0400 -#ifdef CONFIG_SH_SECUREEDGE5410 -#include <mach/snapgear.h> #define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00) #define get_dp() SECUREEDGE_READ_IOPORT() +#define ds1302_set_tx() +#define ds1302_set_rx() + +static inline int ds1302_hw_init(void) +{ + return 0; +} + +static inline void ds1302_reset(void) +{ + set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); +} + +static inline void ds1302_clock(void) +{ + set_dp(get_dp() | RTC_SCLK); /* clock high */ + set_dp(get_dp() & ~RTC_SCLK); /* clock low */ +} + +static inline void ds1302_start(void) +{ + set_dp(get_dp() | RTC_RESET); +} + +static inline void ds1302_stop(void) +{ + set_dp(get_dp() & ~RTC_RESET); +} + +static inline void ds1302_txbit(int bit) +{ + set_dp((get_dp() & ~RTC_IODATA) | (bit ? RTC_IODATA : 0)); +} + +static inline int ds1302_rxbit(void) +{ + return !!(get_dp() & RTC_IODATA); +} + #else #error "Add support for your platform" #endif @@ -50,11 +90,11 @@ static void ds1302_sendbits(unsigned int val) { int i; + ds1302_set_tx(); + for (i = 8; (i); i--, val >>= 1) { - set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ? - RTC_IODATA : 0)); - set_dp(get_dp() | RTC_SCLK); /* clock high */ - set_dp(get_dp() & ~RTC_SCLK); /* clock low */ + ds1302_txbit(val & 0x1); + ds1302_clock(); } } @@ -63,10 +103,11 @@ static unsigned int ds1302_recvbits(void) unsigned int val; int i; + ds1302_set_rx(); + for (i = 0, val = 0; (i < 8); i++) { - val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i); - set_dp(get_dp() | RTC_SCLK); /* clock high */ - set_dp(get_dp() & ~RTC_SCLK); /* clock low */ + val |= (ds1302_rxbit() << i); + ds1302_clock(); } return val; @@ -76,23 +117,24 @@ static unsigned int ds1302_readbyte(unsigned int addr) { unsigned int val; - set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + ds1302_reset(); - set_dp(get_dp() | RTC_RESET); + ds1302_start(); ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ); val = ds1302_recvbits(); - set_dp(get_dp() & ~RTC_RESET); + ds1302_stop(); return val; } static void ds1302_writebyte(unsigned int addr, unsigned int val) { - set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); - set_dp(get_dp() | RTC_RESET); + ds1302_reset(); + + ds1302_start(); ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE); ds1302_sendbits(val); - set_dp(get_dp() & ~RTC_RESET); + ds1302_stop(); } static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -167,13 +209,20 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; + if (ds1302_hw_init()) { + dev_err(&pdev->dev, "Failed to init communication channel"); + return -EINVAL; + } + /* Reset */ - set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + ds1302_reset(); /* Write a magic value to the DS1302 RAM, and see if it sticks. */ ds1302_writebyte(RTC_ADDR_RAM0, 0x42); - if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) + if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) { + dev_err(&pdev->dev, "Failed to probe"); return -ENODEV; + } rtc = rtc_device_register("ds1302", &pdev->dev, &ds1302_rtc_ops, THIS_MODULE); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 61945734ad0..1f0007fd443 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -403,7 +403,6 @@ out_irq: free_irq(client->irq, client); out_free: - i2c_set_clientdata(client, NULL); kfree(ds1374); return ret; } @@ -422,7 +421,6 @@ static int __devexit ds1374_remove(struct i2c_client *client) } rtc_device_unregister(ds1374->rtc); - i2c_set_clientdata(client, NULL); kfree(ds1374); return 0; } diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 054e05294af..468200c38ec 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -462,39 +462,16 @@ isl1208_sysfs_store_usr(struct device *dev, static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr, isl1208_sysfs_store_usr); -static int -isl1208_sysfs_register(struct device *dev) -{ - int err; - - err = device_create_file(dev, &dev_attr_atrim); - if (err) - return err; - - err = device_create_file(dev, &dev_attr_dtrim); - if (err) { - device_remove_file(dev, &dev_attr_atrim); - return err; - } - - err = device_create_file(dev, &dev_attr_usr); - if (err) { - device_remove_file(dev, &dev_attr_atrim); - device_remove_file(dev, &dev_attr_dtrim); - } - - return 0; -} - -static int -isl1208_sysfs_unregister(struct device *dev) -{ - device_remove_file(dev, &dev_attr_dtrim); - device_remove_file(dev, &dev_attr_atrim); - device_remove_file(dev, &dev_attr_usr); +static struct attribute *isl1208_rtc_attrs[] = { + &dev_attr_atrim.attr, + &dev_attr_dtrim.attr, + &dev_attr_usr.attr, + NULL +}; - return 0; -} +static const struct attribute_group isl1208_rtc_sysfs_files = { + .attrs = isl1208_rtc_attrs, +}; static int isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -529,7 +506,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_warn(&client->dev, "rtc power failure detected, " "please set clock.\n"); - rc = isl1208_sysfs_register(&client->dev); + rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); if (rc) goto exit_unregister; @@ -546,7 +523,7 @@ isl1208_remove(struct i2c_client *client) { struct rtc_device *rtc = i2c_get_clientdata(client); - isl1208_sysfs_unregister(&client->dev); + sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); rtc_device_unregister(rtc); return 0; diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 60fe266f0f4..6dc4e624141 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -595,10 +595,6 @@ static void wdt_disable(void) static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - /* Can't seek (pwrite) on this device - if (ppos != &file->f_pos) - return -ESPIPE; - */ if (count) { wdt_ping(); return 1; @@ -623,7 +619,7 @@ static ssize_t wdt_read(struct file *file, char __user *buf, * according to their available features. We only actually usefully support * querying capabilities and current status. */ -static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, +static int wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int new_margin, rv; @@ -676,6 +672,18 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -ENOTTY; } +static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + + lock_kernel(); + ret = wdt_ioctl(file, cmd, arg); + unlock_kernel(); + + return ret; +} + /** * wdt_open: * @inode: inode of device @@ -695,7 +703,7 @@ static int wdt_open(struct inode *inode, struct file *file) */ wdt_is_open = 1; unlock_kernel(); - return 0; + return nonseekable_open(inode, file); } return -ENODEV; } @@ -736,7 +744,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, static const struct file_operations wdt_fops = { .owner = THIS_MODULE, .read = wdt_read, - .ioctl = wdt_ioctl, + .unlocked_ioctl = wdt_unlocked_ioctl, .write = wdt_write, .open = wdt_open, .release = wdt_release, diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index f0dbf9cb8f9..db5d8c416d2 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -279,7 +279,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, if (!rtc) return -ENOMEM; - rtc->regs = of_iomap(op->node, 0); + rtc->regs = of_iomap(op->dev.of_node, 0); if (!rtc->regs) { dev_err(&op->dev, "%s: couldn't map io space\n", __func__); err = -ENOSYS; @@ -290,7 +290,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, dev_set_drvdata(&op->dev, rtc); - rtc->irq = irq_of_parse_and_map(op->node, 1); + rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1); err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED, "mpc5121-rtc", &op->dev); if (err) { @@ -299,7 +299,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op, goto out_dispose; } - rtc->irq_periodic = irq_of_parse_and_map(op->node, 0); + rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0); err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd, IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev); if (err) { @@ -365,9 +365,11 @@ static struct of_device_id mpc5121_rtc_match[] __devinitdata = { }; static struct of_platform_driver mpc5121_rtc_driver = { - .owner = THIS_MODULE, - .name = "mpc5121-rtc", - .match_table = mpc5121_rtc_match, + .driver = { + .name = "mpc5121-rtc", + .owner = THIS_MODULE, + .of_match_table = mpc5121_rtc_match, + }, .probe = mpc5121_rtc_probe, .remove = __devexit_p(mpc5121_rtc_remove), }; diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index d71fe61db1d..25ec921db07 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -379,7 +379,6 @@ static struct rtc_class_ops mxc_rtc_ops = { static int __init mxc_rtc_probe(struct platform_device *pdev) { - struct clk *clk; struct resource *res; struct rtc_device *rtc; struct rtc_plat_data *pdata = NULL; @@ -402,14 +401,15 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - clk = clk_get(&pdev->dev, "ckil"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + pdata->clk = clk_get(&pdev->dev, "rtc"); + if (IS_ERR(pdata->clk)) { + dev_err(&pdev->dev, "unable to get clock!\n"); + ret = PTR_ERR(pdata->clk); goto exit_free_pdata; } - rate = clk_get_rate(clk); - clk_put(clk); + clk_enable(pdata->clk); + rate = clk_get_rate(pdata->clk); if (rate == 32768) reg = RTC_INPUT_CLK_32768HZ; @@ -420,7 +420,7 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) else { dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate); ret = -EINVAL; - goto exit_free_pdata; + goto exit_put_clk; } reg |= RTC_ENABLE_BIT; @@ -428,18 +428,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) { dev_err(&pdev->dev, "hardware module can't be enabled!\n"); ret = -EIO; - goto exit_free_pdata; - } - - pdata->clk = clk_get(&pdev->dev, "rtc"); - if (IS_ERR(pdata->clk)) { - dev_err(&pdev->dev, "unable to get clock!\n"); - ret = PTR_ERR(pdata->clk); - goto exit_free_pdata; + goto exit_put_clk; } - clk_enable(pdata->clk); - rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index b65c82f792d..789f62f9b47 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -632,7 +632,6 @@ errout_reg: rtc_device_unregister(rx8025->rtc); errout_free: - i2c_set_clientdata(client, NULL); kfree(rx8025); errout: @@ -656,7 +655,6 @@ static int __devexit rx8025_remove(struct i2c_client *client) rx8025_sysfs_unregister(&client->dev); rtc_device_unregister(rx8025->rtc); - i2c_set_clientdata(client, NULL); kfree(rx8025); return 0; } diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index def4d396d0b..f789e002c9b 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -275,7 +275,6 @@ exit_dummy: if (s35390a->client[i]) i2c_unregister_device(s35390a->client[i]); kfree(s35390a); - i2c_set_clientdata(client, NULL); exit: return err; @@ -292,7 +291,6 @@ static int s35390a_remove(struct i2c_client *client) rtc_device_unregister(s35390a->rtc); kfree(s35390a); - i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 4969b6059c8..70b68d35f96 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -29,6 +29,11 @@ #include <asm/irq.h> #include <plat/regs-rtc.h> +enum s3c_cpu_type { + TYPE_S3C2410, + TYPE_S3C64XX, +}; + /* I have yet to find an S3C implementation with more than one * of these rtc blocks in */ @@ -37,6 +42,7 @@ static struct resource *s3c_rtc_mem; static void __iomem *s3c_rtc_base; static int s3c_rtc_alarmno = NO_IRQ; static int s3c_rtc_tickno = NO_IRQ; +static enum s3c_cpu_type s3c_rtc_cpu_type; static DEFINE_SPINLOCK(s3c_rtc_pie_lock); @@ -80,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) pr_debug("%s: pie=%d\n", __func__, enabled); spin_lock_irq(&s3c_rtc_pie_lock); - tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; - if (enabled) - tmp |= S3C2410_TICNT_ENABLE; + if (s3c_rtc_cpu_type == TYPE_S3C64XX) { + tmp = readb(s3c_rtc_base + S3C2410_RTCCON); + tmp &= ~S3C64XX_RTCCON_TICEN; + + if (enabled) + tmp |= S3C64XX_RTCCON_TICEN; + + writeb(tmp, s3c_rtc_base + S3C2410_RTCCON); + } else { + tmp = readb(s3c_rtc_base + S3C2410_TICNT); + tmp &= ~S3C2410_TICNT_ENABLE; + + if (enabled) + tmp |= S3C2410_TICNT_ENABLE; + + writeb(tmp, s3c_rtc_base + S3C2410_TICNT); + } - writeb(tmp, s3c_rtc_base + S3C2410_TICNT); spin_unlock_irq(&s3c_rtc_pie_lock); return 0; @@ -93,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) static int s3c_rtc_setfreq(struct device *dev, int freq) { - unsigned int tmp; + struct platform_device *pdev = to_platform_device(dev); + struct rtc_device *rtc_dev = platform_get_drvdata(pdev); + unsigned int tmp = 0; if (!is_power_of_2(freq)) return -EINVAL; spin_lock_irq(&s3c_rtc_pie_lock); - tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE; - tmp |= (128 / freq)-1; + if (s3c_rtc_cpu_type == TYPE_S3C2410) { + tmp = readb(s3c_rtc_base + S3C2410_TICNT); + tmp &= S3C2410_TICNT_ENABLE; + } + + tmp |= (rtc_dev->max_user_freq / freq)-1; writeb(tmp, s3c_rtc_base + S3C2410_TICNT); spin_unlock_irq(&s3c_rtc_pie_lock); @@ -283,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) { - unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT); + unsigned int ticnt; + + if (s3c_rtc_cpu_type == TYPE_S3C64XX) { + ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt &= S3C64XX_RTCCON_TICEN; + } else { + ticnt = readb(s3c_rtc_base + S3C2410_TICNT); + ticnt &= S3C2410_TICNT_ENABLE; + } - seq_printf(seq, "periodic_IRQ\t: %s\n", - (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" ); + seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); return 0; } @@ -353,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) if (!en) { tmp = readb(base + S3C2410_RTCCON); - writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON); - - tmp = readb(base + S3C2410_TICNT); - writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT); + if (s3c_rtc_cpu_type == TYPE_S3C64XX) + tmp &= ~S3C64XX_RTCCON_TICEN; + tmp &= ~S3C2410_RTCCON_RTCEN; + writeb(tmp, base + S3C2410_RTCCON); + + if (s3c_rtc_cpu_type == TYPE_S3C2410) { + tmp = readb(base + S3C2410_TICNT); + tmp &= ~S3C2410_TICNT_ENABLE; + writeb(tmp, base + S3C2410_TICNT); + } } else { /* re-enable the device, and check it is ok */ @@ -457,8 +495,6 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(s3c_rtc_base + S3C2410_RTCCON)); - s3c_rtc_setfreq(&pdev->dev, 1); - device_init_wakeup(&pdev->dev, 1); /* register RTC and exit */ @@ -472,9 +508,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) goto err_nortc; } - rtc->max_user_freq = 128; + s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; + + if (s3c_rtc_cpu_type == TYPE_S3C64XX) + rtc->max_user_freq = 32768; + else + rtc->max_user_freq = 128; platform_set_drvdata(pdev, rtc); + + s3c_rtc_setfreq(&pdev->dev, 1); + return 0; err_nortc: @@ -492,20 +536,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) /* RTC Power management control */ -static int ticnt_save; +static int ticnt_save, ticnt_en_save; static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) { /* save TICNT for anyone using periodic interrupts */ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); + if (s3c_rtc_cpu_type == TYPE_S3C64XX) { + ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt_en_save &= S3C64XX_RTCCON_TICEN; + } s3c_rtc_enable(pdev, 0); return 0; } static int s3c_rtc_resume(struct platform_device *pdev) { + unsigned int tmp; + s3c_rtc_enable(pdev, 1); writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); + if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { + tmp = readb(s3c_rtc_base + S3C2410_RTCCON); + writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); + } return 0; } #else @@ -513,13 +567,27 @@ static int s3c_rtc_resume(struct platform_device *pdev) #define s3c_rtc_resume NULL #endif -static struct platform_driver s3c2410_rtc_driver = { +static struct platform_device_id s3c_rtc_driver_ids[] = { + { + .name = "s3c2410-rtc", + .driver_data = TYPE_S3C2410, + }, { + .name = "s3c64xx-rtc", + .driver_data = TYPE_S3C64XX, + }, + { } +}; + +MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids); + +static struct platform_driver s3c_rtc_driver = { .probe = s3c_rtc_probe, .remove = __devexit_p(s3c_rtc_remove), .suspend = s3c_rtc_suspend, .resume = s3c_rtc_resume, + .id_table = s3c_rtc_driver_ids, .driver = { - .name = "s3c2410-rtc", + .name = "s3c-rtc", .owner = THIS_MODULE, }, }; @@ -529,12 +597,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics static int __init s3c_rtc_init(void) { printk(banner); - return platform_driver_register(&s3c2410_rtc_driver); + return platform_driver_register(&s3c_rtc_driver); } static void __exit s3c_rtc_exit(void) { - platform_driver_unregister(&s3c2410_rtc_driver); + platform_driver_unregister(&s3c_rtc_driver); } module_init(s3c_rtc_init); diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index b16cfe57a48..82931dc65c0 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -449,17 +449,17 @@ static int wm831x_rtc_probe(struct platform_device *pdev) goto err; } - ret = wm831x_request_irq(wm831x, per_irq, wm831x_per_irq, - IRQF_TRIGGER_RISING, "wm831x_rtc_per", - wm831x_rtc); + ret = request_threaded_irq(per_irq, NULL, wm831x_per_irq, + IRQF_TRIGGER_RISING, "RTC period", + wm831x_rtc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n", per_irq, ret); } - ret = wm831x_request_irq(wm831x, alm_irq, wm831x_alm_irq, - IRQF_TRIGGER_RISING, "wm831x_rtc_alm", - wm831x_rtc); + ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq, + IRQF_TRIGGER_RISING, "RTC alarm", + wm831x_rtc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", alm_irq, ret); @@ -478,8 +478,8 @@ static int __devexit wm831x_rtc_remove(struct platform_device *pdev) int per_irq = platform_get_irq_byname(pdev, "PER"); int alm_irq = platform_get_irq_byname(pdev, "ALM"); - wm831x_free_irq(wm831x_rtc->wm831x, alm_irq, wm831x_rtc); - wm831x_free_irq(wm831x_rtc->wm831x, per_irq, wm831x_rtc); + free_irq(alm_irq, wm831x_rtc); + free_irq(per_irq, wm831x_rtc); rtc_device_unregister(wm831x_rtc->rtc); kfree(wm831x_rtc); |