From aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 Mon Sep 17 00:00:00 2001 From: merge Date: Thu, 22 Jan 2009 13:55:32 +0000 Subject: MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green fix-stray-endmenu.patch Signed-off-by: Andy Green --- drivers/rtc/Kconfig | 146 ++++++++---- drivers/rtc/Makefile | 10 +- drivers/rtc/class.c | 16 +- drivers/rtc/interface.c | 70 +++++- drivers/rtc/rtc-at32ap700x.c | 4 +- drivers/rtc/rtc-at91sam9.c | 1 + drivers/rtc/rtc-au1xxx.c | 153 +++++++++++++ drivers/rtc/rtc-bfin.c | 2 +- drivers/rtc/rtc-cmos.c | 15 +- drivers/rtc/rtc-dev.c | 51 +++-- drivers/rtc/rtc-ds1216.c | 30 ++- drivers/rtc/rtc-ds1307.c | 154 ++++--------- drivers/rtc/rtc-ds1390.c | 192 ++++++++++++++++ drivers/rtc/rtc-ds1511.c | 21 +- drivers/rtc/rtc-ds1553.c | 15 +- drivers/rtc/rtc-ds1672.c | 28 +-- drivers/rtc/rtc-ds3234.c | 172 +++------------ drivers/rtc/rtc-ep93xx.c | 13 -- drivers/rtc/rtc-isl1208.c | 7 + drivers/rtc/rtc-m48t59.c | 2 +- drivers/rtc/rtc-max6900.c | 6 + drivers/rtc/rtc-max6902.c | 176 ++++----------- drivers/rtc/rtc-mv.c | 163 ++++++++++++++ drivers/rtc/rtc-parisc.c | 3 +- drivers/rtc/rtc-pcf50633.c | 266 ++++++++++++---------- drivers/rtc/rtc-pxa.c | 491 +++++++++++++++++++++++++++++++++++++++++ drivers/rtc/rtc-rx8581.c | 281 +++++++++++++++++++++++ drivers/rtc/rtc-s3c.c | 3 + drivers/rtc/rtc-sa1100.c | 12 +- drivers/rtc/rtc-sh.c | 13 +- drivers/rtc/rtc-starfire.c | 66 ++---- drivers/rtc/rtc-stk17ta8.c | 17 +- drivers/rtc/rtc-sun4v.c | 69 ++---- drivers/rtc/rtc-test.c | 8 +- drivers/rtc/rtc-twl4030.c | 54 ++--- drivers/rtc/rtc-tx4939.c | 317 ++++++++++++++++++++++++++ drivers/rtc/rtc-vr41xx.c | 11 +- drivers/rtc/rtc-wm8350.c | 514 +++++++++++++++++++++++++++++++++++++++++++ 38 files changed, 2747 insertions(+), 825 deletions(-) create mode 100644 drivers/rtc/rtc-au1xxx.c create mode 100644 drivers/rtc/rtc-ds1390.c create mode 100644 drivers/rtc/rtc-mv.c create mode 100644 drivers/rtc/rtc-pxa.c create mode 100644 drivers/rtc/rtc-rx8581.c create mode 100644 drivers/rtc/rtc-tx4939.c create mode 100644 drivers/rtc/rtc-wm8350.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cc3c077df37..cced4d10831 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -35,8 +35,8 @@ config RTC_HCTOSYS_DEVICE default "rtc0" help The RTC device that will be used to (re)initialize the system - clock, usually rtc0. Initialization is done when the system - starts up, and when it resumes from a low power state. This + clock, usually rtc0. Initialization is done when the system + starts up, and when it resumes from a low power state. This device should record time in UTC, since the kernel won't do timezone correction. @@ -44,7 +44,7 @@ config RTC_HCTOSYS_DEVICE functions run, so it must usually be statically linked. This clock should be battery-backed, so that it reads the correct - time when the system boots from a power-off state. Otherwise, your + time when the system boots from a power-off state. Otherwise, your system will need an external clock source (like an NTP server). If the clock you specify here is not battery backed, it may still @@ -69,8 +69,7 @@ config RTC_INTF_SYSFS Say yes here if you want to use your RTCs using sysfs interfaces, /sys/class/rtc/rtc0 through /sys/.../rtcN. - This driver can also be built as a module. If so, the module - will be called rtc-sysfs. + If unsure, say Y. config RTC_INTF_PROC boolean "/proc/driver/rtc (procfs for rtc0)" @@ -78,11 +77,10 @@ config RTC_INTF_PROC default RTC_CLASS help Say yes here if you want to use your first RTC through the proc - interface, /proc/driver/rtc. Other RTCs will not be available + interface, /proc/driver/rtc. Other RTCs will not be available through that API. - This driver can also be built as a module. If so, the module - will be called rtc-proc. + If unsure, say Y. config RTC_INTF_DEV boolean "/dev/rtcN (character devices)" @@ -90,21 +88,27 @@ config RTC_INTF_DEV help Say yes here if you want to use your RTCs using the /dev interfaces, which "udev" sets up as /dev/rtc0 through - /dev/rtcN. You may want to set up a symbolic link so one - of these can be accessed as /dev/rtc, which is a name - expected by "hwclock" and some other programs. + /dev/rtcN. - This driver can also be built as a module. If so, the module - will be called rtc-dev. + You may want to set up a symbolic link so one of these + can be accessed as /dev/rtc, which is a name + expected by "hwclock" and some other programs. Recent + versions of "udev" are known to set up the symlink for you. + + 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 + 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 @@ -128,14 +132,14 @@ config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" help If you say yes here you get support for various compatible RTC - chips (often with battery backup) connected with I2C. This driver + chips (often with battery backup) connected with I2C. This driver should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00, - and probably other chips. In some cases the RTC must already + and probably other chips. In some cases the RTC must already have been initialized (by manufacturing or a bootloader). The first seven registers on these chips hold an RTC, and other registers may add features such as NVRAM, a trickle charger for - the RTC/NVRAM backup power, and alarms. NVRAM is visible in + the RTC/NVRAM backup power, and alarms. NVRAM is visible in sysfs, but other chip features may not be available. This driver can also be built as a module. If so, the module @@ -146,10 +150,10 @@ config RTC_DRV_DS1374 depends on RTC_CLASS && I2C help If you say yes here you get support for Dallas Semiconductor - DS1374 real-time clock chips. If an interrupt is associated + DS1374 real-time clock chips. If an interrupt is associated with the device, the alarm functionality is supported. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called rtc-ds1374. config RTC_DRV_DS1672 @@ -219,18 +223,6 @@ config RTC_DRV_PCF8583 This driver can also be built as a module. If so, the module will be called rtc-pcf8583. -config RTC_DRV_PCF50633 - tristate "Philips PCF50633" - help - If you say yes here you get support for the Philips PCF50633 - PMU's RTC. - -config RTC_DRV_PCF50606 - tristate "Philips PCF50606" - help - If you say yes here you get support for the Philips PCF50606 - PMU's RTC. - config RTC_DRV_M41T80 tristate "ST M41T65/M41T80/81/82/83/84/85/87" help @@ -255,7 +247,7 @@ config RTC_DRV_TWL92330 help If you say yes here you get support for the RTC on the TWL92330 "Menelaus" power management chip, used with OMAP2 - platforms. The support is integrated with the rest of + platforms. The support is integrated with the rest of the Menelaus driver; it's not separate module. config RTC_DRV_TWL4030 @@ -289,6 +281,14 @@ config RTC_DRV_FM3130 This driver can also be built as a module. If so the module will be called rtc-fm3130. +config RTC_DRV_RX8581 + tristate "Epson RX-8581" + help + If you say yes here you will get support for the Epson RX-8581. + + This driver can also be built as a module. If so the module + will be called rtc-rx8581. + endif # I2C comment "SPI RTC drivers" @@ -308,12 +308,24 @@ config RTC_DRV_DS1305 tristate "Dallas/Maxim DS1305/DS1306" help Select this driver to get support for the Dallas/Maxim DS1305 - and DS1306 real time clock chips. These support a trickle + and DS1306 real time clock chips. These support a trickle charger, alarms, and NVRAM in addition to the clock. This driver can also be built as a module. If so, the module will be called rtc-ds1305. +config RTC_DRV_DS1390 + tristate "Dallas/Maxim DS1390/93/94" + help + If you say yes here you get support for the + Dallas/Maxim DS1390/93/94 chips. + + This driver only supports the RTC feature, and not other chip + features such as alarms and trickle charging. + + This driver can also be built as a module. If so, the module + will be called rtc-ds1390. + config RTC_DRV_MAX6902 tristate "Maxim MAX6902" help @@ -370,7 +382,7 @@ config RTC_DRV_CMOS or LPC bus chips, and so on. Your system will need to define the platform device used by - this driver, otherwise it won't be accessible. This means + this driver, otherwise it won't be accessible. This means you can safely enable this driver if you don't know whether or not your board has this kind of hardware. @@ -480,6 +492,23 @@ config RTC_DRV_V3020 This driver can also be built as a module. If so, the module will be called rtc-v3020. +config RTC_DRV_WM8350 + tristate "Wolfson Microelectronics WM8350 RTC" + depends on MFD_WM8350 + help + If you say yes here you will get support for the RTC subsystem + of the Wolfson Microelectronics WM8350. + + This driver can also be built as a module. If so, the module + will be called "rtc-wm8350". + +config RTC_DRV_PCF50633 + depends on MFD_PCF50633 + tristate "NXP PCF50633 RTC" + help + If you say yes here you get support for the RTC subsystem of the + NXP PCF50633 used in embedded systems. + comment "on-CPU RTC drivers" config RTC_DRV_OMAP @@ -577,7 +606,7 @@ config RTC_DRV_AT91RM9200 depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL help Driver for the internal RTC (Realtime Clock) module found on - Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips + Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips this is powered by the backup power supply. config RTC_DRV_AT91SAM9 @@ -599,8 +628,8 @@ config RTC_DRV_AT91SAM9_RTT prompt "RTT module Number" if ARCH_AT91SAM9263 depends on RTC_DRV_AT91SAM9 help - More than one RTT module is available. You can choose which - one will be used as an RTC. The default of zero is normally + More than one RTT module is available. You can choose which + one will be used as an RTC. The default of zero is normally OK to use, though some systems use that for non-RTC purposes. config RTC_DRV_AT91SAM9_GPBR @@ -612,10 +641,20 @@ config RTC_DRV_AT91SAM9_GPBR depends on RTC_DRV_AT91SAM9 help The RTC driver needs to use one of the General Purpose Backup - Registers (GPBRs) as well as the RTT. You can choose which one - will be used. The default of zero is normally OK to use, but + Registers (GPBRs) as well as the RTT. You can choose which one + will be used. The default of zero is normally OK to use, but on some systems other software needs to use that register. +config RTC_DRV_AU1XXX + tristate "Au1xxx Counter0 RTC support" + depends on SOC_AU1X00 + help + This is a driver for the Au1xxx on-chip Counter0 (Time-Of-Year + counter) to be used as a RTC. + + This driver can also be built as a module. If so, the module + will be called rtc-au1xxx. + config RTC_DRV_BFIN tristate "Blackfin On-Chip RTC" depends on BLACKFIN && !BF561 @@ -648,6 +687,17 @@ config RTC_DRV_PPC the RTC. This exposes that functionality through the generic RTC class. +config RTC_DRV_PXA + tristate "PXA27x/PXA3xx" + depends on ARCH_PXA + help + If you say Y here you will get access to the real time clock + built into your PXA27x or PXA3xx CPU. + + This RTC driver uses PXA RTC registers available since pxa27x + series (RDxR, RYxR) instead of legacy RCNR, RTAR. + + config RTC_DRV_SUN4V bool "SUN4V Hypervisor RTC" depends on SPARC64 @@ -662,4 +712,22 @@ config RTC_DRV_STARFIRE If you say Y here you will get support for the RTC found on Starfire systems. +config RTC_DRV_TX4939 + tristate "TX4939 SoC" + depends on SOC_TX4939 + help + Driver for the internal RTC (Realtime Clock) module found on + Toshiba TX4939 SoC. + +config RTC_DRV_MV + tristate "Marvell SoC RTC" + depends on ARCH_KIRKWOOD + help + If you say yes here you will get support for the in-chip RTC + that can be found in some of Marvell's SoC devices, such as + the Kirkwood 88F6281 and 88F6192. + + This driver can also be built as a module. If so, the module + will be called rtc-mv. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 50f337b338f..6e28021abb9 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -20,6 +20,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.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 +obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o @@ -28,6 +29,7 @@ obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o +obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds1390.o obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o @@ -46,19 +48,20 @@ obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o +obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o -obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o -obj-$(CONFIG_RTC_DRV_PCF50606) += rtc-pcf50606.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_PARISC) += rtc-parisc.o obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o +obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.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_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 @@ -66,6 +69,9 @@ obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.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_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 4dfdf019fcc..be5a6b73e60 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -48,9 +48,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) struct rtc_time tm; struct timespec ts = current_kernel_time(); - if (strncmp(rtc->dev.bus_id, - CONFIG_RTC_HCTOSYS_DEVICE, - BUS_ID_SIZE) != 0) + if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; rtc_read_time(rtc, &tm); @@ -71,20 +69,18 @@ static int rtc_resume(struct device *dev) time_t newtime; struct timespec time; - if (strncmp(rtc->dev.bus_id, - CONFIG_RTC_HCTOSYS_DEVICE, - BUS_ID_SIZE) != 0) + if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; rtc_read_time(rtc, &tm); if (rtc_valid_tm(&tm) != 0) { - pr_debug("%s: bogus resume time\n", rtc->dev.bus_id); + pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); return 0; } rtc_tm_to_time(&tm, &newtime); if (newtime <= oldtime) { if (newtime < oldtime) - pr_debug("%s: time travel!\n", rtc->dev.bus_id); + pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } @@ -156,7 +152,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, init_waitqueue_head(&rtc->irq_queue); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); - snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id); + dev_set_name(&rtc->dev, "rtc%d", id); rtc_dev_prepare(rtc); @@ -169,7 +165,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc_proc_add_device(rtc); dev_info(dev, "rtc core: registered %s as %s\n", - rtc->name, rtc->dev.bus_id); + rtc->name, dev_name(&rtc->dev)); return rtc; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a04c1b6b157..4348c4b0d45 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -50,10 +50,15 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) if (!rtc->ops) err = -ENODEV; - else if (!rtc->ops->set_time) - err = -EINVAL; - else + else if (rtc->ops->set_time) err = rtc->ops->set_time(rtc->dev.parent, tm); + else if (rtc->ops->set_mmss) { + unsigned long secs; + err = rtc_tm_to_time(tm, &secs); + if (err == 0) + err = rtc->ops->set_mmss(rtc->dev.parent, secs); + } else + err = -EINVAL; mutex_unlock(&rtc->ops_lock); return err; @@ -307,6 +312,60 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_set_alarm); +int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) +{ + int err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return err; + + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->alarm_irq_enable) + err = -EINVAL; + else + err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled); + + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); + +int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) +{ + int err = mutex_lock_interruptible(&rtc->ops_lock); + 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, enabled); + } +#endif + + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->update_irq_enable) + err = -EINVAL; + else + err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled); + + 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; +} +EXPORT_SYMBOL_GPL(rtc_update_irq_enable); + /** * rtc_update_irq - report RTC periodic, alarm, and/or update irqs * @rtc: the rtc device @@ -335,7 +394,7 @@ static int __rtc_match(struct device *dev, void *data) { char *name = (char *)data; - if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) + if (strcmp(dev_name(dev), name) == 0) return 1; return 0; } @@ -450,9 +509,6 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) if (rtc->ops->irq_set_freq == NULL) return -ENXIO; - if (!is_power_of_2(freq)) - return -EINVAL; - spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index 90b9a6503e1..e1ec33e40e3 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -205,7 +205,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) { struct resource *regs; struct rtc_at32ap700x *rtc; - int irq = -1; + int irq; int ret; rtc = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL); @@ -222,7 +222,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { + if (irq <= 0) { dev_dbg(&pdev->dev, "could not get irq\n"); ret = -ENXIO; goto out; diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 2133f37906f..d5e4e637dde 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -21,6 +21,7 @@ #include #include +#include /* diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c new file mode 100644 index 00000000000..8906a688e6a --- /dev/null +++ b/drivers/rtc/rtc-au1xxx.c @@ -0,0 +1,153 @@ +/* + * Au1xxx counter0 (aka Time-Of-Year counter) RTC interface driver. + * + * Copyright (C) 2008 Manuel Lauss + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +/* All current Au1xxx SoCs have 2 counters fed by an external 32.768 kHz + * crystal. Counter 0, which keeps counting during sleep/powerdown, is + * used to count seconds since the beginning of the unix epoch. + * + * The counters must be configured and enabled by bootloader/board code; + * no checks as to whether they really get a proper 32.768kHz clock are + * made as this would take far too long. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 32kHz clock enabled and detected */ +#define CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S) + +static int au1xtoy_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long t; + + t = au_readl(SYS_TOYREAD); + + rtc_time_to_tm(t, tm); + + return rtc_valid_tm(tm); +} + +static int au1xtoy_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long t; + + rtc_tm_to_time(tm, &t); + + au_writel(t, SYS_TOYWRITE); + au_sync(); + + /* wait for the pending register write to succeed. This can + * take up to 6 seconds... + */ + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S) + msleep(1); + + return 0; +} + +static struct rtc_class_ops au1xtoy_rtc_ops = { + .read_time = au1xtoy_rtc_read_time, + .set_time = au1xtoy_rtc_set_time, +}; + +static int __devinit au1xtoy_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtcdev; + unsigned long t; + int ret; + + t = au_readl(SYS_COUNTER_CNTRL); + if (!(t & CNTR_OK)) { + dev_err(&pdev->dev, "counters not working; aborting.\n"); + ret = -ENODEV; + goto out_err; + } + + ret = -ETIMEDOUT; + + /* set counter0 tickrate to 1Hz if necessary */ + if (au_readl(SYS_TOYTRIM) != 32767) { + /* wait until hardware gives access to TRIM register */ + t = 0x00100000; + while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S) && t--) + msleep(1); + + if (!t) { + /* timed out waiting for register access; assume + * counters are unusable. + */ + dev_err(&pdev->dev, "timeout waiting for access\n"); + goto out_err; + } + + /* set 1Hz TOY tick rate */ + au_writel(32767, SYS_TOYTRIM); + au_sync(); + } + + /* wait until the hardware allows writes to the counter reg */ + while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S) + msleep(1); + + rtcdev = rtc_device_register("rtc-au1xxx", &pdev->dev, + &au1xtoy_rtc_ops, THIS_MODULE); + if (IS_ERR(rtcdev)) { + ret = PTR_ERR(rtcdev); + goto out_err; + } + + platform_set_drvdata(pdev, rtcdev); + + return 0; + +out_err: + return ret; +} + +static int __devexit au1xtoy_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtcdev = platform_get_drvdata(pdev); + + rtc_device_unregister(rtcdev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver au1xrtc_driver = { + .driver = { + .name = "rtc-au1xxx", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(au1xtoy_rtc_remove), +}; + +static int __init au1xtoy_rtc_init(void) +{ + return platform_driver_probe(&au1xrtc_driver, au1xtoy_rtc_probe); +} + +static void __exit au1xtoy_rtc_exit(void) +{ + platform_driver_unregister(&au1xrtc_driver); +} + +module_init(au1xtoy_rtc_init); +module_exit(au1xtoy_rtc_exit); + +MODULE_DESCRIPTION("Au1xxx TOY-counter-based RTC driver"); +MODULE_AUTHOR("Manuel Lauss "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtc-au1xxx"); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 34439ce3967..aafd3e6ebb0 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -390,7 +390,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) /* Register our RTC with the RTC framework */ rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc))) { + if (unlikely(IS_ERR(rtc->rtc_dev))) { ret = PTR_ERR(rtc->rtc_dev); goto err_irq; } diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 6cf8e282338..b6d35f50e40 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -35,6 +35,7 @@ #include #include #include +#include /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include @@ -58,7 +59,7 @@ struct cmos_rtc { }; /* both platform and pnp busses use negative numbers for invalid irqs */ -#define is_valid_irq(n) ((n) >= 0) +#define is_valid_irq(n) ((n) > 0) static const char driver_name[] = "rtc_cmos"; @@ -384,6 +385,8 @@ static int cmos_irq_set_freq(struct device *dev, int freq) 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) @@ -729,7 +732,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) cmos_rtc.dev = dev; dev_set_drvdata(dev, &cmos_rtc); - rename_region(ports, cmos_rtc.rtc->dev.bus_id); + rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); @@ -777,7 +780,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) rtc_cmos_int_handler = cmos_interrupt; retval = request_irq(rtc_irq, rtc_cmos_int_handler, - IRQF_DISABLED, cmos_rtc.rtc->dev.bus_id, + IRQF_DISABLED, dev_name(&cmos_rtc.rtc->dev), cmos_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); @@ -795,7 +798,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) } pr_info("%s: alarms up to one %s%s, %zd bytes nvram%s\n", - cmos_rtc.rtc->dev.bus_id, + dev_name(&cmos_rtc.rtc->dev), is_valid_irq(rtc_irq) ? (cmos_rtc.mon_alrm ? "year" @@ -885,7 +888,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) } pr_debug("%s: suspend%s, ctrl %02x\n", - cmos_rtc.rtc->dev.bus_id, + dev_name(&cmos_rtc.rtc->dev), (tmp & RTC_AIE) ? ", alarm may wake" : "", tmp); @@ -941,7 +944,7 @@ static int cmos_resume(struct device *dev) } pr_debug("%s: resume, ctrl %02x\n", - cmos_rtc.rtc->dev.bus_id, + dev_name(&cmos_rtc.rtc->dev), tmp); return 0; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index ecdea44ae4e..45152f4952d 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -92,10 +92,10 @@ static void rtc_uie_timer(unsigned long data) spin_unlock_irqrestore(&rtc->irq_lock, flags); } -static void clear_uie(struct rtc_device *rtc) +static int clear_uie(struct rtc_device *rtc) { spin_lock_irq(&rtc->irq_lock); - if (rtc->irq_active) { + if (rtc->uie_irq_active) { rtc->stop_uie_polling = 1; if (rtc->uie_timer_active) { spin_unlock_irq(&rtc->irq_lock); @@ -108,9 +108,10 @@ static void clear_uie(struct rtc_device *rtc) flush_scheduled_work(); spin_lock_irq(&rtc->irq_lock); } - rtc->irq_active = 0; + rtc->uie_irq_active = 0; } spin_unlock_irq(&rtc->irq_lock); + return 0; } static int set_uie(struct rtc_device *rtc) @@ -122,8 +123,8 @@ static int set_uie(struct rtc_device *rtc) if (err) return err; spin_lock_irq(&rtc->irq_lock); - if (!rtc->irq_active) { - rtc->irq_active = 1; + 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; @@ -134,6 +135,16 @@ static int set_uie(struct rtc_device *rtc) 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 @@ -357,6 +368,22 @@ static long rtc_dev_ioctl(struct file *file, err = rtc_irq_set_state(rtc, NULL, 0); break; + case RTC_AIE_ON: + mutex_unlock(&rtc->ops_lock); + return rtc_alarm_irq_enable(rtc, 1); + + case RTC_AIE_OFF: + mutex_unlock(&rtc->ops_lock); + return rtc_alarm_irq_enable(rtc, 0); + + case RTC_UIE_ON: + mutex_unlock(&rtc->ops_lock); + return rtc_update_irq_enable(rtc, 1); + + case RTC_UIE_OFF: + mutex_unlock(&rtc->ops_lock); + return rtc_update_irq_enable(rtc, 0); + case RTC_IRQP_SET: err = rtc_irq_set_freq(rtc, NULL, arg); break; @@ -401,17 +428,6 @@ static long rtc_dev_ioctl(struct file *file, err = -EFAULT; return err; -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - case RTC_UIE_OFF: - mutex_unlock(&rtc->ops_lock); - clear_uie(rtc); - return 0; - - case RTC_UIE_ON: - mutex_unlock(&rtc->ops_lock); - err = set_uie(rtc); - return err; -#endif default: err = -ENOTTY; break; @@ -440,7 +456,10 @@ static int rtc_dev_release(struct inode *inode, struct file *file) * Leave the alarm alone; it may be set to trigger a system wakeup * later, or be used by kernel code, and is a one-shot event anyway. */ + + /* Keep ioctl until all drivers are converted */ rtc_dev_ioctl(file, RTC_UIE_OFF, 0); + rtc_update_irq_enable(rtc, 0); rtc_irq_set_state(rtc, NULL, 0); if (rtc->ops->release) diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c index 9a234a4ec06..4aedc705518 100644 --- a/drivers/rtc/rtc-ds1216.c +++ b/drivers/rtc/rtc-ds1216.c @@ -10,7 +10,7 @@ #include #include -#define DRV_VERSION "0.1" +#define DRV_VERSION "0.2" struct ds1216_regs { u8 tsec; @@ -101,7 +101,8 @@ static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_year = bcd2bin(regs.year); if (tm->tm_year < 70) tm->tm_year += 100; - return 0; + + return rtc_valid_tm(tm); } static int ds1216_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -138,9 +139,8 @@ static const struct rtc_class_ops ds1216_rtc_ops = { .set_time = ds1216_rtc_set_time, }; -static int __devinit ds1216_rtc_probe(struct platform_device *pdev) +static int __init ds1216_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc; struct resource *res; struct ds1216_priv *priv; int ret = 0; @@ -152,7 +152,10 @@ static int __devinit ds1216_rtc_probe(struct platform_device *pdev) priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) return -ENOMEM; - priv->size = res->end - res->start + 1; + + platform_set_drvdata(pdev, priv); + + priv->size = resource_size(res); if (!request_mem_region(res->start, priv->size, pdev->name)) { ret = -EBUSY; goto out; @@ -163,22 +166,18 @@ static int __devinit ds1216_rtc_probe(struct platform_device *pdev) ret = -ENOMEM; goto out; } - rtc = rtc_device_register("ds1216", &pdev->dev, + priv->rtc = rtc_device_register("ds1216", &pdev->dev, &ds1216_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); + if (IS_ERR(priv->rtc)) { + ret = PTR_ERR(priv->rtc); goto out; } - priv->rtc = rtc; - platform_set_drvdata(pdev, priv); /* dummy read to get clock into a known state */ ds1216_read(priv->ioaddr, dummy); return 0; out: - if (priv->rtc) - rtc_device_unregister(priv->rtc); if (priv->ioaddr) iounmap(priv->ioaddr); if (priv->baseaddr) @@ -187,7 +186,7 @@ out: return ret; } -static int __devexit ds1216_rtc_remove(struct platform_device *pdev) +static int __exit ds1216_rtc_remove(struct platform_device *pdev) { struct ds1216_priv *priv = platform_get_drvdata(pdev); @@ -203,13 +202,12 @@ static struct platform_driver ds1216_rtc_platform_driver = { .name = "rtc-ds1216", .owner = THIS_MODULE, }, - .probe = ds1216_rtc_probe, - .remove = __devexit_p(ds1216_rtc_remove), + .remove = __exit_p(ds1216_rtc_remove), }; static int __init ds1216_rtc_init(void) { - return platform_driver_register(&ds1216_rtc_platform_driver); + return platform_driver_probe(&ds1216_rtc_platform_driver, ds1216_rtc_probe); } static void __exit ds1216_rtc_exit(void) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 162330b9d1d..7e5155e88ac 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -86,13 +86,11 @@ enum ds_type { struct ds1307 { - u8 reg_addr; u8 regs[11]; enum ds_type type; unsigned long flags; #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ #define HAS_ALARM 1 /* bit 1 == irq claimed */ - struct i2c_msg msg[2]; struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; @@ -204,13 +202,9 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) int tmp; /* read the RTC date and time registers all at once */ - ds1307->reg_addr = 0; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = 7; - - tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), - ds1307->msg, 2); - if (tmp != 2) { + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + DS1307_REG_SECS, 7, ds1307->regs); + if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); return -EIO; } @@ -257,7 +251,6 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) t->tm_hour, t->tm_mday, t->tm_mon, t->tm_year, t->tm_wday); - *buf++ = 0; /* first register addr */ buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec); buf[DS1307_REG_MIN] = bin2bcd(t->tm_min); buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour); @@ -282,23 +275,19 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) break; } - ds1307->msg[1].flags = 0; - ds1307->msg[1].len = 8; - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), - &ds1307->msg[1], 1); - if (result != 1) { - dev_err(dev, "%s error %d\n", "write", tmp); - return -EIO; + result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + if (result < 0) { + dev_err(dev, "%s error %d\n", "write", result); + return result; } return 0; } -static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) +static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -308,13 +297,9 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ds1307->reg_addr = DS1339_REG_ALARM1_SECS; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = 9; - - ret = i2c_transfer(to_i2c_adapter(client->dev.parent), - ds1307->msg, 2); - if (ret != 2) { + ret = i2c_smbus_read_i2c_block_data(client, + DS1339_REG_ALARM1_SECS, 9, ds1307->regs); + if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); return -EIO; } @@ -353,7 +338,7 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) +static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -371,13 +356,9 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled, t->pending); /* read current status of both alarms and the chip */ - ds1307->reg_addr = DS1339_REG_ALARM1_SECS; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = 9; - - ret = i2c_transfer(to_i2c_adapter(client->dev.parent), - ds1307->msg, 2); - if (ret != 2) { + ret = i2c_smbus_read_i2c_block_data(client, + DS1339_REG_ALARM1_SECS, 9, buf); + if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); return -EIO; } @@ -392,7 +373,6 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) ds1307->regs[6], control, status); /* set ALARM1, using 24 hour and day-of-month modes */ - *buf++ = DS1339_REG_ALARM1_SECS; /* first register addr */ buf[0] = bin2bcd(t->time.tm_sec); buf[1] = bin2bcd(t->time.tm_min); buf[2] = bin2bcd(t->time.tm_hour); @@ -411,14 +391,11 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ds1307->msg[1].flags = 0; - ds1307->msg[1].len = 10; - - ret = i2c_transfer(to_i2c_adapter(client->dev.parent), - &ds1307->msg[1], 1); - if (ret != 1) { + ret = i2c_smbus_write_i2c_block_data(client, + DS1339_REG_ALARM1_SECS, 9, buf); + if (ret < 0) { dev_err(dev, "can't set alarm time\n"); - return -EIO; + return ret; } return 0; @@ -475,8 +452,8 @@ static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) static const struct rtc_class_ops ds13xx_rtc_ops = { .read_time = ds1307_get_time, .set_time = ds1307_set_time, - .read_alarm = ds1307_read_alarm, - .set_alarm = ds1307_set_alarm, + .read_alarm = ds1337_read_alarm, + .set_alarm = ds1337_set_alarm, .ioctl = ds1307_ioctl, }; @@ -490,7 +467,6 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, { struct i2c_client *client; struct ds1307 *ds1307; - struct i2c_msg msg[2]; int result; client = kobj_to_i2c_client(kobj); @@ -503,24 +479,10 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = buf; - - buf[0] = 8 + off; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = count; - msg[1].buf = buf; - - result = i2c_transfer(to_i2c_adapter(client->dev.parent), msg, 2); - if (result != 2) { + result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); - return -EIO; - } - return count; + return result; } static ssize_t @@ -528,8 +490,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct i2c_client *client; - u8 buffer[NVRAM_SIZE + 1]; - int ret; + int result; client = kobj_to_i2c_client(kobj); @@ -540,11 +501,12 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - buffer[0] = 8 + off; - memcpy(buffer + 1, buf, count); - - ret = i2c_master_send(client, buffer, count + 1); - return (ret < 0) ? ret : (ret - 1); + result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + if (result < 0) { + dev_err(&client->dev, "%s error %d\n", "nvram write", result); + return result; + } + return count; } static struct bin_attribute nvram = { @@ -571,9 +533,11 @@ static int __devinit ds1307_probe(struct i2c_client *client, const struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int want_irq = false; + unsigned char *buf; if (!i2c_check_functionality(adapter, - I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + I2C_FUNC_SMBUS_WRITE_BYTE_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -581,18 +545,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, ds1307->client = client; i2c_set_clientdata(client, ds1307); - - ds1307->msg[0].addr = client->addr; - ds1307->msg[0].flags = 0; - ds1307->msg[0].len = 1; - ds1307->msg[0].buf = &ds1307->reg_addr; - - ds1307->msg[1].addr = client->addr; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = sizeof(ds1307->regs); - ds1307->msg[1].buf = ds1307->regs; - ds1307->type = id->driver_data; + buf = ds1307->regs; switch (ds1307->type) { case ds_1337: @@ -602,21 +556,15 @@ static int __devinit ds1307_probe(struct i2c_client *client, INIT_WORK(&ds1307->work, ds1307_work); want_irq = true; } - - ds1307->reg_addr = DS1337_REG_CONTROL; - ds1307->msg[1].len = 2; - /* get registers that the "rtc" read below won't read... */ - tmp = i2c_transfer(adapter, ds1307->msg, 2); + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); err = -EIO; goto exit_free; } - ds1307->reg_addr = 0; - ds1307->msg[1].len = sizeof(ds1307->regs); - /* oscillator off? turn it on, so clock can tick. */ if (ds1307->regs[0] & DS1337_BIT_nEOSC) ds1307->regs[0] &= ~DS1337_BIT_nEOSC; @@ -647,9 +595,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, read_rtc: /* read RTC registers */ - - tmp = i2c_transfer(adapter, ds1307->msg, 2); - if (tmp != 2) { + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; goto exit_free; @@ -707,22 +654,6 @@ read_rtc: break; } - tmp = ds1307->regs[DS1307_REG_SECS]; - tmp = bcd2bin(tmp & 0x7f); - if (tmp > 60) - goto exit_bad; - tmp = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f); - if (tmp > 60) - goto exit_bad; - - tmp = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f); - if (tmp == 0 || tmp > 31) - goto exit_bad; - - tmp = bcd2bin(ds1307->regs[DS1307_REG_MONTH] & 0x1f); - if (tmp == 0 || tmp > 12) - goto exit_bad; - tmp = ds1307->regs[DS1307_REG_HOUR]; switch (ds1307->type) { case ds_1340: @@ -779,13 +710,6 @@ read_rtc: return 0; -exit_bad: - dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", - "bogus register", - ds1307->regs[0], ds1307->regs[1], - ds1307->regs[2], ds1307->regs[3], - ds1307->regs[4], ds1307->regs[5], - ds1307->regs[6]); exit_irq: if (ds1307->rtc) rtc_device_unregister(ds1307->rtc); diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c new file mode 100644 index 00000000000..e54b5c619bd --- /dev/null +++ b/drivers/rtc/rtc-ds1390.c @@ -0,0 +1,192 @@ +/* + * rtc-ds1390.c -- driver for the Dallas/Maxim DS1390/93/94 SPI RTC + * + * Copyright (C) 2008 Mercury IMC Ltd + * Written by Mark Jackson + * + * 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. The extra features provided by the chip family + * (alarms, trickle charger, different control registers) are unavailable. + */ + +#include +#include +#include +#include +#include +#include + +#define DS1390_REG_100THS 0x00 +#define DS1390_REG_SECONDS 0x01 +#define DS1390_REG_MINUTES 0x02 +#define DS1390_REG_HOURS 0x03 +#define DS1390_REG_DAY 0x04 +#define DS1390_REG_DATE 0x05 +#define DS1390_REG_MONTH_CENT 0x06 +#define DS1390_REG_YEAR 0x07 + +#define DS1390_REG_ALARM_100THS 0x08 +#define DS1390_REG_ALARM_SECONDS 0x09 +#define DS1390_REG_ALARM_MINUTES 0x0A +#define DS1390_REG_ALARM_HOURS 0x0B +#define DS1390_REG_ALARM_DAY_DATE 0x0C + +#define DS1390_REG_CONTROL 0x0D +#define DS1390_REG_STATUS 0x0E +#define DS1390_REG_TRICKLE 0x0F + +struct ds1390 { + struct rtc_device *rtc; + u8 txrx_buf[9]; /* cmd + 8 registers */ +}; + +static int ds1390_get_reg(struct device *dev, unsigned char address, + unsigned char *data) +{ + struct spi_device *spi = to_spi_device(dev); + struct ds1390 *chip = dev_get_drvdata(dev); + int status; + + if (!data) + return -EINVAL; + + /* Clear MSB to indicate read */ + chip->txrx_buf[0] = address & 0x7f; + /* do the i/o */ + status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 1); + if (status != 0) + return status; + + *data = chip->txrx_buf[1]; + + return 0; +} + +static int ds1390_read_time(struct device *dev, struct rtc_time *dt) +{ + struct spi_device *spi = to_spi_device(dev); + struct ds1390 *chip = dev_get_drvdata(dev); + int status; + + /* build the message */ + chip->txrx_buf[0] = DS1390_REG_SECONDS; + + /* do the i/o */ + status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 8); + if (status != 0) + return status; + + /* The chip sends data in this order: + * Seconds, Minutes, Hours, Day, Date, Month / Century, Year */ + dt->tm_sec = bcd2bin(chip->txrx_buf[0]); + dt->tm_min = bcd2bin(chip->txrx_buf[1]); + dt->tm_hour = bcd2bin(chip->txrx_buf[2]); + dt->tm_wday = bcd2bin(chip->txrx_buf[3]); + dt->tm_mday = bcd2bin(chip->txrx_buf[4]); + /* mask off century bit */ + dt->tm_mon = bcd2bin(chip->txrx_buf[5] & 0x7f) - 1; + /* adjust for century bit */ + dt->tm_year = bcd2bin(chip->txrx_buf[6]) + ((chip->txrx_buf[5] & 0x80) ? 100 : 0); + + return rtc_valid_tm(dt); +} + +static int ds1390_set_time(struct device *dev, struct rtc_time *dt) +{ + struct spi_device *spi = to_spi_device(dev); + struct ds1390 *chip = dev_get_drvdata(dev); + + /* build the message */ + chip->txrx_buf[0] = DS1390_REG_SECONDS | 0x80; + chip->txrx_buf[1] = bin2bcd(dt->tm_sec); + chip->txrx_buf[2] = bin2bcd(dt->tm_min); + chip->txrx_buf[3] = bin2bcd(dt->tm_hour); + chip->txrx_buf[4] = bin2bcd(dt->tm_wday); + chip->txrx_buf[5] = bin2bcd(dt->tm_mday); + chip->txrx_buf[6] = bin2bcd(dt->tm_mon + 1) | + ((dt->tm_year > 99) ? 0x80 : 0x00); + chip->txrx_buf[7] = bin2bcd(dt->tm_year % 100); + + /* do the i/o */ + return spi_write_then_read(spi, chip->txrx_buf, 8, NULL, 0); +} + +static const struct rtc_class_ops ds1390_rtc_ops = { + .read_time = ds1390_read_time, + .set_time = ds1390_set_time, +}; + +static int __devinit ds1390_probe(struct spi_device *spi) +{ + struct rtc_device *rtc; + unsigned char tmp; + struct ds1390 *chip; + int res; + + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + + chip = kzalloc(sizeof *chip, GFP_KERNEL); + if (!chip) { + dev_err(&spi->dev, "unable to allocate device memory\n"); + return -ENOMEM; + } + dev_set_drvdata(&spi->dev, chip); + + res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp); + if (res != 0) { + dev_err(&spi->dev, "unable to read device\n"); + kfree(chip); + return res; + } + + chip->rtc = rtc_device_register("ds1390", + &spi->dev, &ds1390_rtc_ops, THIS_MODULE); + if (IS_ERR(chip->rtc)) { + dev_err(&spi->dev, "unable to register device\n"); + res = PTR_ERR(chip->rtc); + kfree(chip); + } + + return res; +} + +static int __devexit ds1390_remove(struct spi_device *spi) +{ + struct ds1390 *chip = platform_get_drvdata(spi); + + rtc_device_unregister(chip->rtc); + kfree(chip); + + return 0; +} + +static struct spi_driver ds1390_driver = { + .driver = { + .name = "rtc-ds1390", + .owner = THIS_MODULE, + }, + .probe = ds1390_probe, + .remove = __devexit_p(ds1390_remove), +}; + +static __init int ds1390_init(void) +{ + return spi_register_driver(&ds1390_driver); +} +module_init(ds1390_init); + +static __exit void ds1390_exit(void) +{ + spi_unregister_driver(&ds1390_driver); +} +module_exit(ds1390_exit); + +MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver"); +MODULE_AUTHOR("Mark Jackson "); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 25caada7839..0b6b7730c71 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -326,9 +326,9 @@ ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) { + if (pdata->irq <= 0) return -EINVAL; - } + pdata->alrm_mday = alrm->time.tm_mday; pdata->alrm_hour = alrm->time.tm_hour; pdata->alrm_min = alrm->time.tm_min; @@ -346,9 +346,9 @@ ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) { + if (pdata->irq <= 0) return -EINVAL; - } + alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min; @@ -385,7 +385,7 @@ ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) { + if (pdata->irq <= 0) { return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ } switch (cmd) { @@ -503,7 +503,6 @@ ds1511_rtc_probe(struct platform_device *pdev) if (!pdata) { return -ENOMEM; } - pdata->irq = -1; pdata->size = res->end - res->start + 1; if (!request_mem_region(res->start, pdata->size, pdev->name)) { ret = -EBUSY; @@ -545,13 +544,13 @@ ds1511_rtc_probe(struct platform_device *pdev) * if the platform has an interrupt in mind for this device, * then by all means, set it */ - if (pdata->irq >= 0) { + if (pdata->irq > 0) { rtc_read(RTC_CMD1); if (request_irq(pdata->irq, ds1511_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = -1; + pdata->irq = 0; } } @@ -572,7 +571,7 @@ ds1511_rtc_probe(struct platform_device *pdev) if (pdata->rtc) { rtc_device_unregister(pdata->rtc); } - if (pdata->irq >= 0) { + if (pdata->irq > 0) { free_irq(pdata->irq, pdev); } if (ds1511_base) { @@ -595,7 +594,7 @@ ds1511_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); rtc_device_unregister(pdata->rtc); pdata->rtc = NULL; - if (pdata->irq >= 0) { + if (pdata->irq > 0) { /* * disable the alarm interrupt */ @@ -631,7 +630,7 @@ ds1511_rtc_init(void) static void __exit ds1511_rtc_exit(void) { - return platform_driver_unregister(&ds1511_rtc_driver); + platform_driver_unregister(&ds1511_rtc_driver); } module_init(ds1511_rtc_init); diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index b9475cd2021..38d472b6340 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -162,7 +162,7 @@ static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; pdata->alrm_mday = alrm->time.tm_mday; pdata->alrm_hour = alrm->time.tm_hour; @@ -179,7 +179,7 @@ static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; @@ -213,7 +213,7 @@ static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ switch (cmd) { case RTC_AIE_OFF: @@ -301,7 +301,6 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->irq = -1; if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { ret = -EBUSY; goto out; @@ -327,13 +326,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) dev_warn(&pdev->dev, "voltage-low detected.\n"); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); if (request_irq(pdata->irq, ds1553_rtc_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = -1; + pdata->irq = 0; } } @@ -353,7 +352,7 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) out: if (pdata->rtc) rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) + if (pdata->irq > 0) free_irq(pdata->irq, pdev); if (ioaddr) iounmap(ioaddr); @@ -369,7 +368,7 @@ static int __devexit ds1553_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, pdata->ioaddr + RTC_INTERRUPTS); free_irq(pdata->irq, pdev); } diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 341d7a5b45a..06dfb54f99b 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -83,32 +83,11 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) return 0; } -static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm) -{ - unsigned long secs; - - dev_dbg(&client->dev, - "%s: secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - - rtc_tm_to_time(tm, &secs); - - return ds1672_set_mmss(client, secs); -} - static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm) { return ds1672_get_datetime(to_i2c_client(dev), tm); } -static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - return ds1672_set_datetime(to_i2c_client(dev), tm); -} - static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs) { return ds1672_set_mmss(to_i2c_client(dev), secs); @@ -152,7 +131,6 @@ static DEVICE_ATTR(control, S_IRUGO, show_control, NULL); static const struct rtc_class_ops ds1672_rtc_ops = { .read_time = ds1672_rtc_read_time, - .set_time = ds1672_rtc_set_time, .set_mmss = ds1672_rtc_set_mmss, }; @@ -209,12 +187,18 @@ static int ds1672_probe(struct i2c_client *client, return err; } +static struct i2c_device_id ds1672_id[] = { + { "ds1672", 0 }, + { } +}; + static struct i2c_driver ds1672_driver = { .driver = { .name = "rtc-ds1672", }, .probe = &ds1672_probe, .remove = &ds1672_remove, + .id_table = ds1672_id, }; static int __init ds1672_init(void) diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c index 45e5b106af7..c51589ede5b 100644 --- a/drivers/rtc/rtc-ds3234.c +++ b/drivers/rtc/rtc-ds3234.c @@ -1,4 +1,4 @@ -/* drivers/rtc/rtc-ds3234.c +/* rtc-ds3234.c * * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal * and SRAM. @@ -9,13 +9,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Changelog: - * - * 07-May-2008: Dennis Aberilla - * - Created based on the max6902 code. Only implements the - * date/time keeping functions; no SRAM yet. */ +#include +#include #include #include #include @@ -34,16 +31,7 @@ #define DS3234_REG_CONTROL 0x0E #define DS3234_REG_CONT_STAT 0x0F -#undef DS3234_DEBUG - -struct ds3234 { - struct rtc_device *rtc; - u8 buf[8]; /* Burst read: addr + 7 regs */ - u8 tx_buf[2]; - u8 rx_buf[2]; -}; - -static void ds3234_set_reg(struct device *dev, unsigned char address, +static int ds3234_set_reg(struct device *dev, unsigned char address, unsigned char data) { struct spi_device *spi = to_spi_device(dev); @@ -53,107 +41,45 @@ static void ds3234_set_reg(struct device *dev, unsigned char address, buf[0] = address | 0x80; buf[1] = data; - spi_write(spi, buf, 2); + return spi_write_then_read(spi, buf, 2, NULL, 0); } static int ds3234_get_reg(struct device *dev, unsigned char address, unsigned char *data) { struct spi_device *spi = to_spi_device(dev); - struct ds3234 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; - - if (!data) - return -EINVAL; - - /* Build our spi message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - - /* Address + dummy tx byte */ - xfer.len = 2; - xfer.tx_buf = chip->tx_buf; - xfer.rx_buf = chip->rx_buf; - - chip->tx_buf[0] = address; - chip->tx_buf[1] = 0xff; - spi_message_add_tail(&xfer, &message); + *data = address & 0x7f; - /* do the i/o */ - status = spi_sync(spi, &message); - if (status == 0) - status = message.status; - else - return status; - - *data = chip->rx_buf[1]; - - return status; + return spi_write_then_read(spi, data, 1, data, 1); } -static int ds3234_get_datetime(struct device *dev, struct rtc_time *dt) +static int ds3234_read_time(struct device *dev, struct rtc_time *dt) { + int err; + unsigned char buf[8]; struct spi_device *spi = to_spi_device(dev); - struct ds3234 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; - - /* build the message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - xfer.len = 1 + 7; /* Addr + 7 registers */ - xfer.tx_buf = chip->buf; - xfer.rx_buf = chip->buf; - chip->buf[0] = 0x00; /* Start address */ - spi_message_add_tail(&xfer, &message); - - /* do the i/o */ - status = spi_sync(spi, &message); - if (status == 0) - status = message.status; - else - return status; - /* Seconds, Minutes, Hours, Day, Date, Month, Year */ - dt->tm_sec = bcd2bin(chip->buf[1]); - dt->tm_min = bcd2bin(chip->buf[2]); - dt->tm_hour = bcd2bin(chip->buf[3] & 0x3f); - dt->tm_wday = bcd2bin(chip->buf[4]) - 1; /* 0 = Sun */ - dt->tm_mday = bcd2bin(chip->buf[5]); - dt->tm_mon = bcd2bin(chip->buf[6] & 0x1f) - 1; /* 0 = Jan */ - dt->tm_year = bcd2bin(chip->buf[7] & 0xff) + 100; /* Assume 20YY */ - -#ifdef DS3234_DEBUG - dev_dbg(dev, "\n%s : Read RTC values\n", __func__); - dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); - dev_dbg(dev, "tm_min : %i\n", dt->tm_min); - dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); - dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); - dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); - dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); - dev_dbg(dev, "tm_year: %i\n", dt->tm_year); -#endif + buf[0] = 0x00; /* Start address */ - return 0; + err = spi_write_then_read(spi, buf, 1, buf, 8); + if (err != 0) + return err; + + /* Seconds, Minutes, Hours, Day, Date, Month, Year */ + dt->tm_sec = bcd2bin(buf[0]); + dt->tm_min = bcd2bin(buf[1]); + dt->tm_hour = bcd2bin(buf[2] & 0x3f); + dt->tm_wday = bcd2bin(buf[3]) - 1; /* 0 = Sun */ + dt->tm_mday = bcd2bin(buf[4]); + dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */ + dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */ + + return rtc_valid_tm(dt); } -static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt) +static int ds3234_set_time(struct device *dev, struct rtc_time *dt) { -#ifdef DS3234_DEBUG - dev_dbg(dev, "\n%s : Setting RTC values\n", __func__); - dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); - dev_dbg(dev, "tm_min : %i\n", dt->tm_min); - dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); - dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); - dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); - dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); - dev_dbg(dev, "tm_year: %i\n", dt->tm_year); -#endif - ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec)); ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min)); ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f); @@ -174,16 +100,6 @@ static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt) return 0; } -static int ds3234_read_time(struct device *dev, struct rtc_time *tm) -{ - return ds3234_get_datetime(dev, tm); -} - -static int ds3234_set_time(struct device *dev, struct rtc_time *tm) -{ - return ds3234_set_datetime(dev, tm); -} - static const struct rtc_class_ops ds3234_rtc_ops = { .read_time = ds3234_read_time, .set_time = ds3234_set_time, @@ -193,31 +109,15 @@ static int __devinit ds3234_probe(struct spi_device *spi) { struct rtc_device *rtc; unsigned char tmp; - struct ds3234 *chip; int res; - rtc = rtc_device_register("ds3234", - &spi->dev, &ds3234_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); - chip = kzalloc(sizeof(struct ds3234), GFP_KERNEL); - if (!chip) { - rtc_device_unregister(rtc); - return -ENOMEM; - } - chip->rtc = rtc; - dev_set_drvdata(&spi->dev, chip); - res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp); - if (res) { - rtc_device_unregister(rtc); + if (res != 0) return res; - } /* Control settings * @@ -246,26 +146,27 @@ static int __devinit ds3234_probe(struct spi_device *spi) ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp); + rtc = rtc_device_register("ds3234", + &spi->dev, &ds3234_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + dev_set_drvdata(&spi->dev, rtc); + return 0; } static int __devexit ds3234_remove(struct spi_device *spi) { - struct ds3234 *chip = platform_get_drvdata(spi); - struct rtc_device *rtc = chip->rtc; - - if (rtc) - rtc_device_unregister(rtc); - - kfree(chip); + struct rtc_device *rtc = platform_get_drvdata(spi); + rtc_device_unregister(rtc); return 0; } static struct spi_driver ds3234_driver = { .driver = { .name = "ds3234", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ds3234_probe, @@ -274,7 +175,6 @@ static struct spi_driver ds3234_driver = { static __init int ds3234_init(void) { - printk(KERN_INFO "DS3234 SPI RTC Driver\n"); return spi_register_driver(&ds3234_driver); } module_init(ds3234_init); diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 36e4ac0bd69..f7a3283dd02 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -49,18 +49,6 @@ static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) return 0; } -static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - int err; - unsigned long secs; - - err = rtc_tm_to_time(tm, &secs); - if (err != 0) - return err; - - return ep93xx_rtc_set_mmss(dev, secs); -} - static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) { unsigned short preload, delete; @@ -75,7 +63,6 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) static const struct rtc_class_ops ep93xx_rtc_ops = { .read_time = ep93xx_rtc_read_time, - .set_time = ep93xx_rtc_set_time, .set_mmss = ep93xx_rtc_set_mmss, .proc = ep93xx_rtc_proc, }; diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 2cd77ab8fc6..054e05294af 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -328,6 +328,13 @@ isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) int sr; u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; + /* 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[ISL1208_REG_SC] = bin2bcd(tm->tm_sec); regs[ISL1208_REG_MN] = bin2bcd(tm->tm_min); regs[ISL1208_REG_HR] = bin2bcd(tm->tm_hour) | ISL1208_REG_HR_MIL; diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 43afb7ab528..33921a6b170 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -450,7 +450,7 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) * the mode without IRQ. */ m48t59->irq = platform_get_irq(pdev, 0); - if (m48t59->irq < 0) + if (m48t59->irq <= 0) m48t59->irq = NO_IRQ; if (m48t59->irq != NO_IRQ) { diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index 80782798763..a4f6665ab3c 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -247,12 +247,18 @@ max6900_probe(struct i2c_client *client, const struct i2c_device_id *id) return 0; } +static struct i2c_device_id max6900_id[] = { + { "max6900", 0 }, + { } +}; + static struct i2c_driver max6900_driver = { .driver = { .name = "rtc-max6900", }, .probe = max6900_probe, .remove = max6900_remove, + .id_table = max6900_id, }; static int __init max6900_init(void) diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 2f6507df7b4..36a8ea9ed8b 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -9,14 +9,6 @@ * * Driver for MAX6902 spi RTC * - * Changelog: - * - * 24-May-2006: Raphael Assenat - * - Major rework - * Converted to rtc_device and uses the SPI layer. - * - * ??-???-2005: Someone at Compulab - * - Initial driver creation. */ #include @@ -26,7 +18,6 @@ #include #include #include -#include #define MAX6902_REG_SECONDS 0x01 #define MAX6902_REG_MINUTES 0x03 @@ -38,16 +29,7 @@ #define MAX6902_REG_CONTROL 0x0F #define MAX6902_REG_CENTURY 0x13 -#undef MAX6902_DEBUG - -struct max6902 { - struct rtc_device *rtc; - u8 buf[9]; /* Burst read cmd + 8 registers */ - u8 tx_buf[2]; - u8 rx_buf[2]; -}; - -static void max6902_set_reg(struct device *dev, unsigned char address, +static int max6902_set_reg(struct device *dev, unsigned char address, unsigned char data) { struct spi_device *spi = to_spi_device(dev); @@ -57,113 +39,58 @@ static void max6902_set_reg(struct device *dev, unsigned char address, buf[0] = address & 0x7f; buf[1] = data; - spi_write(spi, buf, 2); + return spi_write_then_read(spi, buf, 2, NULL, 0); } static int max6902_get_reg(struct device *dev, unsigned char address, unsigned char *data) { struct spi_device *spi = to_spi_device(dev); - struct max6902 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; - - if (!data) - return -EINVAL; - - /* Build our spi message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - xfer.len = 2; - /* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */ - xfer.tx_buf = chip->tx_buf; - xfer.rx_buf = chip->rx_buf; /* Set MSB to indicate read */ - chip->tx_buf[0] = address | 0x80; - - spi_message_add_tail(&xfer, &message); + *data = address | 0x80; - /* do the i/o */ - status = spi_sync(spi, &message); - - if (status == 0) - *data = chip->rx_buf[1]; - return status; + return spi_write_then_read(spi, data, 1, data, 1); } -static int max6902_get_datetime(struct device *dev, struct rtc_time *dt) +static int max6902_read_time(struct device *dev, struct rtc_time *dt) { - unsigned char tmp; - int century; - int err; + int err, century; struct spi_device *spi = to_spi_device(dev); - struct max6902 *chip = dev_get_drvdata(dev); - struct spi_message message; - struct spi_transfer xfer; - int status; + unsigned char buf[8]; - err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp); - if (err) - return err; - - /* build the message */ - spi_message_init(&message); - memset(&xfer, 0, sizeof(xfer)); - xfer.len = 1 + 7; /* Burst read command + 7 registers */ - xfer.tx_buf = chip->buf; - xfer.rx_buf = chip->buf; - chip->buf[0] = 0xbf; /* Burst read */ - spi_message_add_tail(&xfer, &message); + buf[0] = 0xbf; /* Burst read */ - /* do the i/o */ - status = spi_sync(spi, &message); - if (status) - return status; + err = spi_write_then_read(spi, buf, 1, buf, 8); + if (err != 0) + return err; /* The chip sends data in this order: * Seconds, Minutes, Hours, Date, Month, Day, Year */ - dt->tm_sec = bcd2bin(chip->buf[1]); - dt->tm_min = bcd2bin(chip->buf[2]); - dt->tm_hour = bcd2bin(chip->buf[3]); - dt->tm_mday = bcd2bin(chip->buf[4]); - dt->tm_mon = bcd2bin(chip->buf[5]) - 1; - dt->tm_wday = bcd2bin(chip->buf[6]); - dt->tm_year = bcd2bin(chip->buf[7]); + dt->tm_sec = bcd2bin(buf[0]); + dt->tm_min = bcd2bin(buf[1]); + dt->tm_hour = bcd2bin(buf[2]); + dt->tm_mday = bcd2bin(buf[3]); + dt->tm_mon = bcd2bin(buf[4]) - 1; + dt->tm_wday = bcd2bin(buf[5]); + dt->tm_year = bcd2bin(buf[6]); + + /* Read century */ + err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &buf[0]); + if (err != 0) + return err; - century = bcd2bin(tmp) * 100; + century = bcd2bin(buf[0]) * 100; dt->tm_year += century; dt->tm_year -= 1900; -#ifdef MAX6902_DEBUG - printk("\n%s : Read RTC values\n",__func__); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_year: %i\n",dt->tm_year); - printk("tm_mon : %i\n",dt->tm_mon); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); -#endif - - return 0; + return rtc_valid_tm(dt); } -static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) +static int max6902_set_time(struct device *dev, struct rtc_time *dt) { - dt->tm_year = dt->tm_year+1900; - -#ifdef MAX6902_DEBUG - printk("\n%s : Setting RTC values\n",__func__); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); - printk("tm_year: %i\n",dt->tm_year); -#endif + dt->tm_year = dt->tm_year + 1900; /* Remove write protection */ max6902_set_reg(dev, 0xF, 0); @@ -173,10 +100,10 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) max6902_set_reg(dev, 0x05, bin2bcd(dt->tm_hour)); max6902_set_reg(dev, 0x07, bin2bcd(dt->tm_mday)); - max6902_set_reg(dev, 0x09, bin2bcd(dt->tm_mon+1)); + max6902_set_reg(dev, 0x09, bin2bcd(dt->tm_mon + 1)); max6902_set_reg(dev, 0x0B, bin2bcd(dt->tm_wday)); - max6902_set_reg(dev, 0x0D, bin2bcd(dt->tm_year%100)); - max6902_set_reg(dev, 0x13, bin2bcd(dt->tm_year/100)); + max6902_set_reg(dev, 0x0D, bin2bcd(dt->tm_year % 100)); + max6902_set_reg(dev, 0x13, bin2bcd(dt->tm_year / 100)); /* Compulab used a delay here. However, the datasheet * does not mention a delay being required anywhere... */ @@ -188,16 +115,6 @@ static int max6902_set_datetime(struct device *dev, struct rtc_time *dt) return 0; } -static int max6902_read_time(struct device *dev, struct rtc_time *tm) -{ - return max6902_get_datetime(dev, tm); -} - -static int max6902_set_time(struct device *dev, struct rtc_time *tm) -{ - return max6902_set_datetime(dev, tm); -} - static const struct rtc_class_ops max6902_rtc_ops = { .read_time = max6902_read_time, .set_time = max6902_set_time, @@ -207,45 +124,29 @@ static int __devinit max6902_probe(struct spi_device *spi) { struct rtc_device *rtc; unsigned char tmp; - struct max6902 *chip; int res; - rtc = rtc_device_register("max6902", - &spi->dev, &max6902_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); - chip = kzalloc(sizeof *chip, GFP_KERNEL); - if (!chip) { - rtc_device_unregister(rtc); - return -ENOMEM; - } - chip->rtc = rtc; - dev_set_drvdata(&spi->dev, chip); - res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp); - if (res) { - rtc_device_unregister(rtc); + if (res != 0) return res; - } + + rtc = rtc_device_register("max6902", + &spi->dev, &max6902_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); return 0; } static int __devexit max6902_remove(struct spi_device *spi) { - struct max6902 *chip = platform_get_drvdata(spi); - struct rtc_device *rtc = chip->rtc; - - if (rtc) - rtc_device_unregister(rtc); - - kfree(chip); + struct rtc_device *rtc = platform_get_drvdata(spi); + rtc_device_unregister(rtc); return 0; } @@ -261,7 +162,6 @@ static struct spi_driver max6902_driver = { static __init int max6902_init(void) { - printk("max6902 spi driver\n"); return spi_register_driver(&max6902_driver); } module_init(max6902_init); diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c new file mode 100644 index 00000000000..45f12dcd371 --- /dev/null +++ b/drivers/rtc/rtc-mv.c @@ -0,0 +1,163 @@ +/* + * Driver for the RTC in Marvell SoCs. + * + * 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 +#include +#include +#include +#include +#include + + +#define RTC_TIME_REG_OFFS 0 +#define RTC_SECONDS_OFFS 0 +#define RTC_MINUTES_OFFS 8 +#define RTC_HOURS_OFFS 16 +#define RTC_WDAY_OFFS 24 +#define RTC_HOURS_12H_MODE (1 << 22) /* 12 hours mode */ + +#define RTC_DATE_REG_OFFS 4 +#define RTC_MDAY_OFFS 0 +#define RTC_MONTH_OFFS 8 +#define RTC_YEAR_OFFS 16 + + +struct rtc_plat_data { + struct rtc_device *rtc; + void __iomem *ioaddr; +}; + +static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rtc_plat_data *pdata = dev_get_drvdata(dev); + void __iomem *ioaddr = pdata->ioaddr; + u32 rtc_reg; + + rtc_reg = (bin2bcd(tm->tm_sec) << RTC_SECONDS_OFFS) | + (bin2bcd(tm->tm_min) << RTC_MINUTES_OFFS) | + (bin2bcd(tm->tm_hour) << RTC_HOURS_OFFS) | + (bin2bcd(tm->tm_wday) << RTC_WDAY_OFFS); + writel(rtc_reg, ioaddr + RTC_TIME_REG_OFFS); + + rtc_reg = (bin2bcd(tm->tm_mday) << RTC_MDAY_OFFS) | + (bin2bcd(tm->tm_mon + 1) << RTC_MONTH_OFFS) | + (bin2bcd(tm->tm_year % 100) << RTC_YEAR_OFFS); + writel(rtc_reg, ioaddr + RTC_DATE_REG_OFFS); + + return 0; +} + +static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rtc_plat_data *pdata = dev_get_drvdata(dev); + void __iomem *ioaddr = pdata->ioaddr; + u32 rtc_time, rtc_date; + unsigned int year, month, day, hour, minute, second, wday; + + rtc_time = readl(ioaddr + RTC_TIME_REG_OFFS); + rtc_date = readl(ioaddr + RTC_DATE_REG_OFFS); + + second = rtc_time & 0x7f; + minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f; + hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */ + wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7; + + day = rtc_date & 0x3f; + month = (rtc_date >> RTC_MONTH_OFFS) & 0x3f; + year = (rtc_date >> RTC_YEAR_OFFS) & 0xff; + + tm->tm_sec = bcd2bin(second); + tm->tm_min = bcd2bin(minute); + tm->tm_hour = bcd2bin(hour); + tm->tm_mday = bcd2bin(day); + tm->tm_wday = bcd2bin(wday); + tm->tm_mon = bcd2bin(month) - 1; + /* hw counts from year 2000, but tm_year is relative to 1900 */ + tm->tm_year = bcd2bin(year) + 100; + + return rtc_valid_tm(tm); +} + +static const struct rtc_class_ops mv_rtc_ops = { + .read_time = mv_rtc_read_time, + .set_time = mv_rtc_set_time, +}; + +static int __init mv_rtc_probe(struct platform_device *pdev) +{ + struct resource *res; + struct rtc_plat_data *pdata; + resource_size_t size; + u32 rtc_time; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + size = resource_size(res); + if (!devm_request_mem_region(&pdev->dev, res->start, size, + pdev->name)) + return -EBUSY; + + pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, size); + if (!pdata->ioaddr) + return -ENOMEM; + + /* make sure the 24 hours mode is enabled */ + rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS); + if (rtc_time & RTC_HOURS_12H_MODE) { + dev_err(&pdev->dev, "24 Hours mode not supported.\n"); + return -EINVAL; + } + + platform_set_drvdata(pdev, pdata); + pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, + &mv_rtc_ops, THIS_MODULE); + if (IS_ERR(pdata->rtc)) + return PTR_ERR(pdata->rtc); + + return 0; +} + +static int __exit mv_rtc_remove(struct platform_device *pdev) +{ + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + rtc_device_unregister(pdata->rtc); + return 0; +} + +static struct platform_driver mv_rtc_driver = { + .remove = __exit_p(mv_rtc_remove), + .driver = { + .name = "rtc-mv", + .owner = THIS_MODULE, + }, +}; + +static __init int mv_init(void) +{ + return platform_driver_probe(&mv_rtc_driver, mv_rtc_probe); +} + +static __exit void mv_exit(void) +{ + platform_driver_unregister(&mv_rtc_driver); +} + +module_init(mv_init); +module_exit(mv_exit); + +MODULE_AUTHOR("Saeed Bishara "); +MODULE_DESCRIPTION("Marvell RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rtc-mv"); diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 346d633655e..c6bfa6fe1a2 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -34,7 +34,8 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) static int parisc_set_time(struct device *dev, struct rtc_time *tm) { struct parisc_rtc *p = dev_get_drvdata(dev); - unsigned long flags, ret; + unsigned long flags; + int ret; spin_lock_irqsave(&p->lock, flags); ret = set_rtc_time(tm); diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index e1576d24254..f4dd87e2907 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -1,4 +1,4 @@ -/* Philips PCF50633 RTC Driver +/* NXP PCF50633 RTC Driver * * (C) 2006-2008 by Openmoko, Inc. * Author: Balaji Rao @@ -7,31 +7,41 @@ * Broken down from monstrous PCF50633 driver mainly by * Harald Welte, Andy Green and Werner Almesberger * - * 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 free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA */ -#include +#include +#include +#include +#include #include +#include #include +#include #include -#include + +#define PCF50633_REG_RTCSC 0x59 /* Second */ +#define PCF50633_REG_RTCMN 0x5a /* Minute */ +#define PCF50633_REG_RTCHR 0x5b /* Hour */ +#define PCF50633_REG_RTCWD 0x5c /* Weekday */ +#define PCF50633_REG_RTCDT 0x5d /* Day */ +#define PCF50633_REG_RTCMT 0x5e /* Month */ +#define PCF50633_REG_RTCYR 0x5f /* Year */ +#define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */ +#define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */ +#define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */ +#define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */ +#define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */ +#define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */ +#define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */ enum pcf50633_time_indexes { - PCF50633_TI_SEC = 0, + PCF50633_TI_SEC, PCF50633_TI_MIN, PCF50633_TI_HOUR, PCF50633_TI_WKDAY, @@ -41,11 +51,18 @@ enum pcf50633_time_indexes { PCF50633_TI_EXTENT /* always last */ }; - struct pcf50633_time { u_int8_t time[PCF50633_TI_EXTENT]; }; +struct pcf50633_rtc { + int alarm_enabled; + int second_enabled; + + struct pcf50633 *pcf; + struct rtc_device *rtc_dev; +}; + static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf) { rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]); @@ -65,54 +82,62 @@ static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc) pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday); pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday); pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon); - pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year - 100); + pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100); } -static int pcf50633_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int +pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct pcf50633 *pcf; + struct pcf50633_rtc *rtc = dev_get_drvdata(dev); + int err; - pcf = dev_get_drvdata(dev); - - switch (cmd) { - case RTC_AIE_OFF: - /* disable the alarm interrupt */ - pcf->rtc.alarm_enabled = 0; - pcf50633_irq_mask(pcf, PCF50633_IRQ_ALARM); - return 0; - case RTC_AIE_ON: - /* enable the alarm interrupt */ - pcf->rtc.alarm_enabled = 1; - pcf50633_irq_unmask(pcf, PCF50633_IRQ_ALARM); - return 0; - case RTC_PIE_OFF: - /* disable periodic interrupt (hz tick) */ - pcf->rtc.second_enabled = 0; - pcf50633_irq_mask(pcf, PCF50633_IRQ_SECOND); - return 0; - case RTC_PIE_ON: - /* ensable periodic interrupt (hz tick) */ - pcf->rtc.second_enabled = 1; - pcf50633_irq_unmask(pcf, PCF50633_IRQ_SECOND); - return 0; - } - return -ENOIOCTLCMD; + if (enabled) + err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); + else + err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); + + if (err < 0) + return err; + + rtc->alarm_enabled = 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 *pcf; + struct pcf50633_rtc *rtc; struct pcf50633_time pcf_tm; int ret; - pcf = dev_get_drvdata(dev); + rtc = dev_get_drvdata(dev); - ret = pcf50633_read_block(pcf, PCF50633_REG_RTCSC, + ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC, PCF50633_TI_EXTENT, &pcf_tm.time[0]); - if (ret != PCF50633_TI_EXTENT) + if (ret != PCF50633_TI_EXTENT) { dev_err(dev, "Failed to read time\n"); + return -EIO; + } dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", pcf_tm.time[PCF50633_TI_DAY], @@ -128,22 +153,23 @@ static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); - return 0; + return rtc_valid_tm(tm); } static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct pcf50633 *pcf; + struct pcf50633_rtc *rtc; struct pcf50633_time pcf_tm; - int ret; - int second_masked, alarm_masked; + int second_masked, alarm_masked, ret = 0; - pcf = dev_get_drvdata(dev); + rtc = dev_get_drvdata(dev); dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); + rtc2pcf_time(&pcf_tm, tm); + dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", pcf_tm.time[PCF50633_TI_DAY], pcf_tm.time[PCF50633_TI_MONTH], @@ -153,126 +179,145 @@ 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(pcf, PCF50633_IRQ_SECOND); - alarm_masked = pcf50633_irq_mask_get(pcf, PCF50633_IRQ_ALARM); + 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(pcf, PCF50633_IRQ_SECOND); + pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); if (!alarm_masked) - pcf50633_irq_mask(pcf, PCF50633_IRQ_ALARM); + pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); - ret = pcf50633_write_block(pcf, PCF50633_REG_RTCSC, + /* Returns 0 on success */ + ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC, PCF50633_TI_EXTENT, &pcf_tm.time[0]); - if (ret) - dev_err(dev, "Failed to set time %d\n", ret); if (!second_masked) - pcf50633_irq_unmask(pcf, PCF50633_IRQ_SECOND); + pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); if (!alarm_masked) - pcf50633_irq_unmask(pcf, PCF50633_IRQ_ALARM); + pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); - - return 0; + return ret; } static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct pcf50633 *pcf; + struct pcf50633_rtc *rtc; struct pcf50633_time pcf_tm; - int ret; + int ret = 0; - pcf = dev_get_drvdata(dev); + rtc = dev_get_drvdata(dev); - alrm->enabled = pcf->rtc.alarm_enabled; + alrm->enabled = rtc->alarm_enabled; - ret = pcf50633_read_block(pcf, PCF50633_REG_RTCSCA, + ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA, PCF50633_TI_EXTENT, &pcf_tm.time[0]); - - if (ret != PCF50633_TI_EXTENT) - dev_err(dev, "Failed to read Alarm time :-(\n"); + if (ret != PCF50633_TI_EXTENT) { + dev_err(dev, "Failed to read time\n"); + return -EIO; + } pcf2rtc_time(&alrm->time, &pcf_tm); - return 0; + return rtc_valid_tm(&alrm->time); } static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct pcf50633 *pcf; + struct pcf50633_rtc *rtc; struct pcf50633_time pcf_tm; - int ret, alarm_masked; + int alarm_masked, ret = 0; - pcf = dev_get_drvdata(dev); + rtc = dev_get_drvdata(dev); rtc2pcf_time(&pcf_tm, &alrm->time); /* do like mktime does and ignore tm_wday */ pcf_tm.time[PCF50633_TI_WKDAY] = 7; - alarm_masked = pcf50633_irq_mask_get(pcf, PCF50633_IRQ_ALARM); + alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); /* disable alarm interrupt */ if (!alarm_masked) - pcf50633_irq_mask(pcf, PCF50633_IRQ_ALARM); + pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); - ret = pcf50633_write_block(pcf, PCF50633_REG_RTCSCA, - PCF50633_TI_EXTENT, &pcf_tm.time[0]); - if (ret) - dev_err(dev, "Failed to write alarm time %d\n", ret); + /* Returns 0 on success */ + ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA, + PCF50633_TI_EXTENT, &pcf_tm.time[0]); if (!alarm_masked) - pcf50633_irq_unmask(pcf, PCF50633_IRQ_ALARM); + pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); - return 0; + return ret; } + static struct rtc_class_ops pcf50633_rtc_ops = { - .ioctl = pcf50633_rtc_ioctl, - .read_time = pcf50633_rtc_read_time, - .set_time = pcf50633_rtc_set_time, - .read_alarm = pcf50633_rtc_read_alarm, - .set_alarm = pcf50633_rtc_set_alarm, + .read_time = pcf50633_rtc_read_time, + .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, }; -static void pcf50633_rtc_irq(struct pcf50633 *pcf, int irq, void *unused) +static void pcf50633_rtc_irq(int irq, void *data) { + struct pcf50633_rtc *rtc = data; + switch (irq) { case PCF50633_IRQ_ALARM: - rtc_update_irq(pcf->rtc.rtc_dev, 1, RTC_AF | RTC_IRQF); + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); break; case PCF50633_IRQ_SECOND: - rtc_update_irq(pcf->rtc.rtc_dev, 1, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); break; } } -static int pcf50633_rtc_probe(struct platform_device *pdev) +static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc; - struct pcf50633 *pcf; + struct pcf50633_subdev_pdata *pdata; + struct pcf50633_rtc *rtc; + - rtc = rtc_device_register("pcf50633", &pdev->dev, - &pcf50633_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return -ENODEV; + rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; - pcf = platform_get_drvdata(pdev); + pdata = pdev->dev.platform_data; + rtc->pcf = pdata->pcf; + platform_set_drvdata(pdev, rtc); + rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev, + &pcf50633_rtc_ops, THIS_MODULE); - /* Set up IRQ handlers */ - pcf->irq_handler[PCF50633_IRQ_ALARM].handler = pcf50633_rtc_irq; - pcf->irq_handler[PCF50633_IRQ_SECOND].handler = pcf50633_rtc_irq; + if (IS_ERR(rtc->rtc_dev)) { + kfree(rtc); + return PTR_ERR(rtc->rtc_dev); + } - pcf->rtc.rtc_dev = rtc; + 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; } -static int pcf50633_rtc_remove(struct platform_device *pdev) +static int __devexit pcf50633_rtc_remove(struct platform_device *pdev) { + struct pcf50633_rtc *rtc; + + 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); + return 0; } - static struct platform_driver pcf50633_rtc_driver = { .driver = { .name = "pcf50633-rtc", @@ -293,8 +338,7 @@ static void __exit pcf50633_rtc_exit(void) } module_exit(pcf50633_rtc_exit); - -MODULE_DESCRIPTION("RTC driver for NXP PCF50633 power management unit"); +MODULE_DESCRIPTION("PCF50633 RTC driver"); MODULE_AUTHOR("Balaji Rao "); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c new file mode 100644 index 00000000000..bd56a033bfd --- /dev/null +++ b/drivers/rtc/rtc-pxa.c @@ -0,0 +1,491 @@ +/* + * Real Time Clock interface for XScale PXA27x and PXA3xx + * + * Copyright (C) 2008 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TIMER_FREQ CLOCK_TICK_RATE +#define RTC_DEF_DIVIDER (32768 - 1) +#define RTC_DEF_TRIM 0 +#define MAXFREQ_PERIODIC 1000 + +/* + * PXA Registers and bits definitions + */ +#define RTSR_PICE (1 << 15) /* Periodic interrupt count enable */ +#define RTSR_PIALE (1 << 14) /* Periodic interrupt Alarm enable */ +#define RTSR_PIAL (1 << 13) /* Periodic interrupt detected */ +#define RTSR_SWALE2 (1 << 11) /* RTC stopwatch alarm2 enable */ +#define RTSR_SWAL2 (1 << 10) /* RTC stopwatch alarm2 detected */ +#define RTSR_SWALE1 (1 << 9) /* RTC stopwatch alarm1 enable */ +#define RTSR_SWAL1 (1 << 8) /* RTC stopwatch alarm1 detected */ +#define RTSR_RDALE2 (1 << 7) /* RTC alarm2 enable */ +#define RTSR_RDAL2 (1 << 6) /* RTC alarm2 detected */ +#define RTSR_RDALE1 (1 << 5) /* RTC alarm1 enable */ +#define RTSR_RDAL1 (1 << 4) /* RTC alarm1 detected */ +#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ +#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ +#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ +#define RTSR_AL (1 << 0) /* RTC alarm detected */ +#define RTSR_TRIG_MASK (RTSR_AL | RTSR_HZ | RTSR_RDAL1 | RTSR_RDAL2\ + | RTSR_SWAL1 | RTSR_SWAL2) +#define RYxR_YEAR_S 9 +#define RYxR_YEAR_MASK (0xfff << RYxR_YEAR_S) +#define RYxR_MONTH_S 5 +#define RYxR_MONTH_MASK (0xf << RYxR_MONTH_S) +#define RYxR_DAY_MASK 0x1f +#define RDxR_HOUR_S 12 +#define RDxR_HOUR_MASK (0x1f << RDxR_HOUR_S) +#define RDxR_MIN_S 6 +#define RDxR_MIN_MASK (0x3f << RDxR_MIN_S) +#define RDxR_SEC_MASK 0x3f + +#define RTSR 0x08 +#define RTTR 0x0c +#define RDCR 0x10 +#define RYCR 0x14 +#define RDAR1 0x18 +#define RYAR1 0x1c +#define RTCPICR 0x34 +#define PIAR 0x38 + +#define rtc_readl(pxa_rtc, reg) \ + __raw_readl((pxa_rtc)->base + (reg)) +#define rtc_writel(pxa_rtc, reg, value) \ + __raw_writel((value), (pxa_rtc)->base + (reg)) + +struct pxa_rtc { + struct resource *ress; + void __iomem *base; + int irq_1Hz; + int irq_Alrm; + struct rtc_device *rtc; + spinlock_t lock; /* Protects this structure */ + struct rtc_time rtc_alarm; +}; + +static u32 ryxr_calc(struct rtc_time *tm) +{ + return ((tm->tm_year + 1900) << RYxR_YEAR_S) + | ((tm->tm_mon + 1) << RYxR_MONTH_S) + | tm->tm_mday; +} + +static u32 rdxr_calc(struct rtc_time *tm) +{ + return (tm->tm_hour << RDxR_HOUR_S) | (tm->tm_min << RDxR_MIN_S) + | tm->tm_sec; +} + +static void tm_calc(u32 rycr, u32 rdcr, struct rtc_time *tm) +{ + tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900; + tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1; + tm->tm_mday = (rycr & RYxR_DAY_MASK); + tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S; + tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S; + tm->tm_sec = rdcr & RDxR_SEC_MASK; +} + +static void rtsr_clear_bits(struct pxa_rtc *pxa_rtc, u32 mask) +{ + u32 rtsr; + + rtsr = rtc_readl(pxa_rtc, RTSR); + rtsr &= ~RTSR_TRIG_MASK; + rtsr &= ~mask; + rtc_writel(pxa_rtc, RTSR, rtsr); +} + +static void rtsr_set_bits(struct pxa_rtc *pxa_rtc, u32 mask) +{ + u32 rtsr; + + rtsr = rtc_readl(pxa_rtc, RTSR); + rtsr &= ~RTSR_TRIG_MASK; + rtsr |= mask; + rtc_writel(pxa_rtc, RTSR, rtsr); +} + +static irqreturn_t pxa_rtc_irq(int irq, void *dev_id) +{ + struct platform_device *pdev = to_platform_device(dev_id); + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + u32 rtsr; + unsigned long events = 0; + + spin_lock(&pxa_rtc->lock); + + /* clear interrupt sources */ + rtsr = rtc_readl(pxa_rtc, RTSR); + rtc_writel(pxa_rtc, RTSR, rtsr); + + /* temporary disable rtc interrupts */ + rtsr_clear_bits(pxa_rtc, RTSR_RDALE1 | RTSR_PIALE | RTSR_HZE); + + /* clear alarm interrupt if it has occurred */ + if (rtsr & RTSR_RDAL1) + rtsr &= ~RTSR_RDALE1; + + /* update irq data & counter */ + if (rtsr & RTSR_RDAL1) + events |= RTC_AF | RTC_IRQF; + if (rtsr & RTSR_HZ) + events |= RTC_UF | RTC_IRQF; + if (rtsr & RTSR_PIAL) + events |= RTC_PF | RTC_IRQF; + + rtc_update_irq(pxa_rtc->rtc, 1, events); + + /* enable back rtc interrupts */ + rtc_writel(pxa_rtc, RTSR, rtsr & ~RTSR_TRIG_MASK); + + spin_unlock(&pxa_rtc->lock); + return IRQ_HANDLED; +} + +static int pxa_rtc_open(struct device *dev) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + int ret; + + ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, IRQF_DISABLED, + "rtc 1Hz", dev); + if (ret < 0) { + dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_1Hz, + ret); + goto err_irq_1Hz; + } + ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, IRQF_DISABLED, + "rtc Alrm", dev); + if (ret < 0) { + dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_Alrm, + ret); + goto err_irq_Alrm; + } + + return 0; + +err_irq_Alrm: + free_irq(pxa_rtc->irq_1Hz, dev); +err_irq_1Hz: + return ret; +} + +static void pxa_rtc_release(struct device *dev) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&pxa_rtc->lock); + rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); + spin_unlock_irq(&pxa_rtc->lock); + + free_irq(pxa_rtc->irq_Alrm, 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_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + int ret = 0; + + spin_lock_irq(&pxa_rtc->lock); + switch (cmd) { + case RTC_AIE_OFF: + rtsr_clear_bits(pxa_rtc, RTSR_RDALE1); + break; + case RTC_AIE_ON: + rtsr_set_bits(pxa_rtc, RTSR_RDALE1); + break; + case RTC_UIE_OFF: + rtsr_clear_bits(pxa_rtc, RTSR_HZE); + break; + case RTC_UIE_ON: + rtsr_set_bits(pxa_rtc, RTSR_HZE); + break; + default: + ret = -ENOIOCTLCMD; + } + + spin_unlock_irq(&pxa_rtc->lock); + return ret; +} + +static int pxa_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + u32 rycr, rdcr; + + rycr = rtc_readl(pxa_rtc, RYCR); + rdcr = rtc_readl(pxa_rtc, RDCR); + + tm_calc(rycr, rdcr, tm); + return 0; +} + +static int pxa_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + + rtc_writel(pxa_rtc, RYCR, ryxr_calc(tm)); + rtc_writel(pxa_rtc, RDCR, rdxr_calc(tm)); + + return 0; +} + +static int pxa_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + u32 rtsr, ryar, rdar; + + ryar = rtc_readl(pxa_rtc, RYAR1); + rdar = rtc_readl(pxa_rtc, RDAR1); + tm_calc(ryar, rdar, &alrm->time); + + rtsr = rtc_readl(pxa_rtc, RTSR); + alrm->enabled = (rtsr & RTSR_RDALE1) ? 1 : 0; + alrm->pending = (rtsr & RTSR_RDAL1) ? 1 : 0; + return 0; +} + +static int pxa_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + u32 rtsr; + + spin_lock_irq(&pxa_rtc->lock); + + rtc_writel(pxa_rtc, RYAR1, ryxr_calc(&alrm->time)); + rtc_writel(pxa_rtc, RDAR1, rdxr_calc(&alrm->time)); + + rtsr = rtc_readl(pxa_rtc, RTSR); + if (alrm->enabled) + rtsr |= RTSR_RDALE1; + else + rtsr &= ~RTSR_RDALE1; + rtc_writel(pxa_rtc, RTSR, rtsr); + + spin_unlock_irq(&pxa_rtc->lock); + + return 0; +} + +static int pxa_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); + + seq_printf(seq, "trim/divider\t: 0x%08x\n", rtc_readl(pxa_rtc, RTTR)); + seq_printf(seq, "update_IRQ\t: %s\n", + (rtc_readl(pxa_rtc, RTSR) & RTSR_HZE) ? "yes" : "no"); + seq_printf(seq, "periodic_IRQ\t: %s\n", + (rtc_readl(pxa_rtc, RTSR) & RTSR_PIALE) ? "yes" : "no"); + seq_printf(seq, "periodic_freq\t: %u\n", rtc_readl(pxa_rtc, PIAR)); + + return 0; +} + +static const struct rtc_class_ops pxa_rtc_ops = { + .open = pxa_rtc_open, + .release = pxa_rtc_release, + .ioctl = pxa_rtc_ioctl, + .read_time = pxa_rtc_read_time, + .set_time = pxa_rtc_set_time, + .read_alarm = pxa_rtc_read_alarm, + .set_alarm = pxa_rtc_set_alarm, + .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) +{ + struct device *dev = &pdev->dev; + struct pxa_rtc *pxa_rtc; + int ret; + u32 rttr; + + pxa_rtc = kzalloc(sizeof(struct pxa_rtc), GFP_KERNEL); + if (!pxa_rtc) + return -ENOMEM; + + spin_lock_init(&pxa_rtc->lock); + platform_set_drvdata(pdev, pxa_rtc); + + ret = -ENXIO; + pxa_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!pxa_rtc->ress) { + dev_err(dev, "No I/O memory resource defined\n"); + goto err_ress; + } + + pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0); + if (pxa_rtc->irq_1Hz < 0) { + dev_err(dev, "No 1Hz IRQ resource defined\n"); + goto err_ress; + } + pxa_rtc->irq_Alrm = platform_get_irq(pdev, 1); + if (pxa_rtc->irq_Alrm < 0) { + dev_err(dev, "No alarm IRQ resource defined\n"); + goto err_ress; + } + + ret = -ENOMEM; + pxa_rtc->base = ioremap(pxa_rtc->ress->start, + resource_size(pxa_rtc->ress)); + if (!pxa_rtc->base) { + dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n"); + goto err_map; + } + + /* + * If the clock divider is uninitialized then reset it to the + * default value to get the 1Hz clock. + */ + if (rtc_readl(pxa_rtc, RTTR) == 0) { + rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); + rtc_writel(pxa_rtc, RTTR, rttr); + dev_warn(dev, "warning: initializing default clock" + " divider/trim value\n"); + } + + rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); + + pxa_rtc->rtc = rtc_device_register("pxa-rtc", &pdev->dev, &pxa_rtc_ops, + THIS_MODULE); + ret = PTR_ERR(pxa_rtc->rtc); + if (IS_ERR(pxa_rtc->rtc)) { + dev_err(dev, "Failed to register RTC device -> %d\n", ret); + goto err_rtc_reg; + } + + device_init_wakeup(dev, 1); + + return 0; + +err_rtc_reg: + iounmap(pxa_rtc->base); +err_ress: +err_map: + kfree(pxa_rtc); + return ret; +} + +static int __exit pxa_rtc_remove(struct platform_device *pdev) +{ + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + + rtc_device_unregister(pxa_rtc->rtc); + + spin_lock_irq(&pxa_rtc->lock); + iounmap(pxa_rtc->base); + spin_unlock_irq(&pxa_rtc->lock); + + kfree(pxa_rtc); + + return 0; +} + +#ifdef CONFIG_PM +static int pxa_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(pxa_rtc->irq_Alrm); + return 0; +} + +static int pxa_rtc_resume(struct platform_device *pdev) +{ + struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(pxa_rtc->irq_Alrm); + return 0; +} +#else +#define pxa_rtc_suspend NULL +#define pxa_rtc_resume NULL +#endif + +static struct platform_driver pxa_rtc_driver = { + .remove = __exit_p(pxa_rtc_remove), + .suspend = pxa_rtc_suspend, + .resume = pxa_rtc_resume, + .driver = { + .name = "pxa-rtc", + }, +}; + +static int __init pxa_rtc_init(void) +{ + if (cpu_is_pxa27x() || cpu_is_pxa3xx()) + return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe); + + return -ENODEV; +} + +static void __exit pxa_rtc_exit(void) +{ + platform_driver_unregister(&pxa_rtc_driver); +} + +module_init(pxa_rtc_init); +module_exit(pxa_rtc_exit); + +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_DESCRIPTION("PXA27x/PXA3xx Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa-rtc"); diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c new file mode 100644 index 00000000000..c9522f3bc21 --- /dev/null +++ b/drivers/rtc/rtc-rx8581.c @@ -0,0 +1,281 @@ +/* + * An I2C driver for the Epson RX8581 RTC + * + * Author: Martyn Welch + * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) + * Copyright 2005-06 Tower Technologies + */ + +#include +#include +#include +#include +#include + +#define DRV_VERSION "0.1" + +#define RX8581_REG_SC 0x00 /* Second in BCD */ +#define RX8581_REG_MN 0x01 /* Minute in BCD */ +#define RX8581_REG_HR 0x02 /* Hour in BCD */ +#define RX8581_REG_DW 0x03 /* Day of Week */ +#define RX8581_REG_DM 0x04 /* Day of Month in BCD */ +#define RX8581_REG_MO 0x05 /* Month in BCD */ +#define RX8581_REG_YR 0x06 /* Year in BCD */ +#define RX8581_REG_RAM 0x07 /* RAM */ +#define RX8581_REG_AMN 0x08 /* Alarm Min in BCD*/ +#define RX8581_REG_AHR 0x09 /* Alarm Hour in BCD */ +#define RX8581_REG_ADM 0x0A +#define RX8581_REG_ADW 0x0A +#define RX8581_REG_TMR0 0x0B +#define RX8581_REG_TMR1 0x0C +#define RX8581_REG_EXT 0x0D /* Extension Register */ +#define RX8581_REG_FLAG 0x0E /* Flag Register */ +#define RX8581_REG_CTRL 0x0F /* Control Register */ + + +/* Flag Register bit definitions */ +#define RX8581_FLAG_UF 0x20 /* Update */ +#define RX8581_FLAG_TF 0x10 /* Timer */ +#define RX8581_FLAG_AF 0x08 /* Alarm */ +#define RX8581_FLAG_VLF 0x02 /* Voltage Low */ + +/* Control Register bit definitions */ +#define RX8581_CTRL_UIE 0x20 /* Update Interrupt Enable */ +#define RX8581_CTRL_TIE 0x10 /* Timer Interrupt Enable */ +#define RX8581_CTRL_AIE 0x08 /* Alarm Interrupt Enable */ +#define RX8581_CTRL_STOP 0x02 /* STOP bit */ +#define RX8581_CTRL_RESET 0x01 /* RESET bit */ + +static struct i2c_driver rx8581_driver; + +/* + * In the routines that deal directly with the rx8581 hardware, we use + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. + */ +static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + unsigned char date[7]; + int data, err; + + /* First we ensure that the "update flag" is not set, we read the + * time and date then re-read the "update flag". If the update flag + * has been set, we know that the time has changed during the read so + * we repeat the whole process again. + */ + data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG); + if (data < 0) { + dev_err(&client->dev, "Unable to read device flags\n"); + return -EIO; + } + + do { + /* If update flag set, clear it */ + if (data & RX8581_FLAG_UF) { + err = i2c_smbus_write_byte_data(client, + RX8581_REG_FLAG, (data & ~RX8581_FLAG_UF)); + if (err != 0) { + dev_err(&client->dev, "Unable to write device " + "flags\n"); + return -EIO; + } + } + + /* Now read time and date */ + err = i2c_smbus_read_i2c_block_data(client, RX8581_REG_SC, + 7, date); + if (err < 0) { + dev_err(&client->dev, "Unable to read date\n"); + return -EIO; + } + + /* Check flag register */ + data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG); + if (data < 0) { + dev_err(&client->dev, "Unable to read device flags\n"); + return -EIO; + } + } while (data & RX8581_FLAG_UF); + + if (data & RX8581_FLAG_VLF) + dev_info(&client->dev, + "low voltage detected, date/time is not reliable.\n"); + + dev_dbg(&client->dev, + "%s: raw data is sec=%02x, min=%02x, hr=%02x, " + "wday=%02x, mday=%02x, mon=%02x, year=%02x\n", + __func__, + date[0], date[1], date[2], date[3], date[4], date[5], date[6]); + + tm->tm_sec = bcd2bin(date[RX8581_REG_SC] & 0x7F); + tm->tm_min = bcd2bin(date[RX8581_REG_MN] & 0x7F); + tm->tm_hour = bcd2bin(date[RX8581_REG_HR] & 0x3F); /* rtc hr 0-23 */ + tm->tm_wday = ilog2(date[RX8581_REG_DW] & 0x7F); + tm->tm_mday = bcd2bin(date[RX8581_REG_DM] & 0x3F); + tm->tm_mon = bcd2bin(date[RX8581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(date[RX8581_REG_YR]); + if (tm->tm_year < 70) + tm->tm_year += 100; /* assume we are in 1970...2069 */ + + + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + err = rtc_valid_tm(tm); + if (err < 0) + dev_err(&client->dev, "retrieved date/time is not valid.\n"); + + return err; +} + +static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + int data, err; + unsigned char buf[7]; + + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + /* hours, minutes and seconds */ + buf[RX8581_REG_SC] = bin2bcd(tm->tm_sec); + buf[RX8581_REG_MN] = bin2bcd(tm->tm_min); + buf[RX8581_REG_HR] = bin2bcd(tm->tm_hour); + + buf[RX8581_REG_DM] = bin2bcd(tm->tm_mday); + + /* month, 1 - 12 */ + buf[RX8581_REG_MO] = bin2bcd(tm->tm_mon + 1); + + /* year and century */ + buf[RX8581_REG_YR] = bin2bcd(tm->tm_year % 100); + buf[RX8581_REG_DW] = (0x1 << tm->tm_wday); + + /* Stop the clock */ + data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL); + if (data < 0) { + dev_err(&client->dev, "Unable to read control register\n"); + return -EIO; + } + + err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG, + (data | RX8581_CTRL_STOP)); + if (err < 0) { + dev_err(&client->dev, "Unable to write control register\n"); + return -EIO; + } + + /* write register's data */ + err = i2c_smbus_write_i2c_block_data(client, RX8581_REG_SC, 7, buf); + if (err < 0) { + dev_err(&client->dev, "Unable to write to date registers\n"); + return -EIO; + } + + /* Restart the clock */ + data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL); + if (data < 0) { + dev_err(&client->dev, "Unable to read control register\n"); + return -EIO; + } + + err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG, + (data | ~(RX8581_CTRL_STOP))); + if (err != 0) { + dev_err(&client->dev, "Unable to write control register\n"); + return -EIO; + } + + return 0; +} + +static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + return rx8581_get_datetime(to_i2c_client(dev), tm); +} + +static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + return rx8581_set_datetime(to_i2c_client(dev), tm); +} + +static const struct rtc_class_ops rx8581_rtc_ops = { + .read_time = rx8581_rtc_read_time, + .set_time = rx8581_rtc_set_time, +}; + +static int __devinit rx8581_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rtc_device *rtc; + + dev_dbg(&client->dev, "%s\n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + + rtc = rtc_device_register(rx8581_driver.driver.name, + &client->dev, &rx8581_rtc_ops, THIS_MODULE); + + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + i2c_set_clientdata(client, rtc); + + return 0; +} + +static int __devexit rx8581_remove(struct i2c_client *client) +{ + struct rtc_device *rtc = i2c_get_clientdata(client); + + rtc_device_unregister(rtc); + + return 0; +} + +static const struct i2c_device_id rx8581_id[] = { + { "rx8581", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rx8581_id); + +static struct i2c_driver rx8581_driver = { + .driver = { + .name = "rtc-rx8581", + .owner = THIS_MODULE, + }, + .probe = rx8581_probe, + .remove = __devexit_p(rx8581_remove), + .id_table = rx8581_id, +}; + +static int __init rx8581_init(void) +{ + return i2c_add_driver(&rx8581_driver); +} + +static void __exit rx8581_exit(void) +{ + i2c_del_driver(&rx8581_driver); +} + +MODULE_AUTHOR("Martyn Welch "); +MODULE_DESCRIPTION("Epson RX-8581 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(rx8581_init); +module_exit(rx8581_exit); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 7a568beba3f..e0d7b999150 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -94,6 +94,9 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) { unsigned int tmp; + 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; diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 66a9bb85bbe..d26a5f82aab 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -38,11 +38,11 @@ #include #endif -#define TIMER_FREQ CLOCK_TICK_RATE #define RTC_DEF_DIVIDER 32768 - 1 #define RTC_DEF_TRIM 0 static unsigned long rtc_freq = 1024; +static unsigned long timer_freq; static struct rtc_time rtc_alarm; static DEFINE_SPINLOCK(sa1100_rtc_lock); @@ -157,7 +157,7 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); if (rtc_timer1_count == 1) - rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))); + rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2))); return IRQ_HANDLED; } @@ -166,7 +166,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) { if (data & RTC_PF) { /* interpolate missed periods and set match for the next */ - unsigned long period = TIMER_FREQ/rtc_freq; + unsigned long period = timer_freq / rtc_freq; unsigned long oscr = OSCR; unsigned long osmr1 = OSMR1; unsigned long missed = (oscr - osmr1)/period; @@ -263,7 +263,7 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, return 0; case RTC_PIE_ON: spin_lock_irq(&sa1100_rtc_lock); - OSMR1 = TIMER_FREQ/rtc_freq + OSCR; + OSMR1 = timer_freq / rtc_freq + OSCR; OIER |= OIER_E1; rtc_timer1_count = 1; spin_unlock_irq(&sa1100_rtc_lock); @@ -271,7 +271,7 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, case RTC_IRQP_READ: return put_user(rtc_freq, (unsigned long *)arg); case RTC_IRQP_SET: - if (arg < 1 || arg > TIMER_FREQ) + if (arg < 1 || arg > timer_freq) return -EINVAL; rtc_freq = arg; return 0; @@ -352,6 +352,8 @@ 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. diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index aaf9d6a337c..1c3fc6b428e 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #define DRV_NAME "sh-rtc" @@ -89,7 +90,9 @@ struct sh_rtc { void __iomem *regbase; unsigned long regsize; struct resource *res; - unsigned int alarm_irq, periodic_irq, carry_irq; + int alarm_irq; + int periodic_irq; + int carry_irq; struct rtc_device *rtc_dev; spinlock_t lock; unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */ @@ -549,6 +552,8 @@ static int sh_rtc_irq_set_state(struct device *dev, int enabled) static int sh_rtc_irq_set_freq(struct device *dev, int freq) { + if (!is_power_of_2(freq)) + return -EINVAL; return sh_rtc_ioctl(dev, RTC_IRQP_SET, freq); } @@ -578,7 +583,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) /* get periodic/carry/alarm irqs */ ret = platform_get_irq(pdev, 0); - if (unlikely(ret < 0)) { + if (unlikely(ret <= 0)) { ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for period\n"); goto err_badres; @@ -586,7 +591,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) rtc->periodic_irq = ret; ret = platform_get_irq(pdev, 1); - if (unlikely(ret < 0)) { + if (unlikely(ret <= 0)) { ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for carry\n"); goto err_badres; @@ -594,7 +599,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) rtc->carry_irq = ret; ret = platform_get_irq(pdev, 2); - if (unlikely(ret < 0)) { + if (unlikely(ret <= 0)) { ret = -ENOENT; dev_err(&pdev->dev, "No IRQ for alarm\n"); goto err_badres; diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c index 7ccb0dd700a..5be98bfd7ed 100644 --- a/drivers/rtc/rtc-starfire.c +++ b/drivers/rtc/rtc-starfire.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -16,11 +15,6 @@ MODULE_AUTHOR("David S. Miller "); MODULE_DESCRIPTION("Starfire RTC driver"); MODULE_LICENSE("GPL"); -struct starfire_rtc { - struct rtc_device *rtc; - spinlock_t lock; -}; - static u32 starfire_get_time(void) { static char obp_gettod[32]; @@ -35,64 +29,31 @@ static u32 starfire_get_time(void) static int starfire_read_time(struct device *dev, struct rtc_time *tm) { - struct starfire_rtc *p = dev_get_drvdata(dev); - unsigned long flags, secs; - - spin_lock_irqsave(&p->lock, flags); - secs = starfire_get_time(); - spin_unlock_irqrestore(&p->lock, flags); - - rtc_time_to_tm(secs, tm); - - return 0; -} - -static int starfire_set_time(struct device *dev, struct rtc_time *tm) -{ - unsigned long secs; - int err; - - err = rtc_tm_to_time(tm, &secs); - if (err) - return err; - - /* Do nothing, time is set using the service processor - * console on this platform. - */ - return 0; + rtc_time_to_tm(starfire_get_time(), tm); + return rtc_valid_tm(tm); } static const struct rtc_class_ops starfire_rtc_ops = { .read_time = starfire_read_time, - .set_time = starfire_set_time, }; -static int __devinit starfire_rtc_probe(struct platform_device *pdev) +static int __init starfire_rtc_probe(struct platform_device *pdev) { - struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL); - - if (!p) - return -ENOMEM; + struct rtc_device *rtc = rtc_device_register("starfire", &pdev->dev, + &starfire_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); - spin_lock_init(&p->lock); + platform_set_drvdata(pdev, rtc); - p->rtc = rtc_device_register("starfire", &pdev->dev, - &starfire_rtc_ops, THIS_MODULE); - if (IS_ERR(p->rtc)) { - int err = PTR_ERR(p->rtc); - kfree(p); - return err; - } - platform_set_drvdata(pdev, p); return 0; } -static int __devexit starfire_rtc_remove(struct platform_device *pdev) +static int __exit starfire_rtc_remove(struct platform_device *pdev) { - struct starfire_rtc *p = platform_get_drvdata(pdev); + struct rtc_device *rtc = platform_get_drvdata(pdev); - rtc_device_unregister(p->rtc); - kfree(p); + rtc_device_unregister(rtc); return 0; } @@ -102,13 +63,12 @@ static struct platform_driver starfire_rtc_driver = { .name = "rtc-starfire", .owner = THIS_MODULE, }, - .probe = starfire_rtc_probe, - .remove = __devexit_p(starfire_rtc_remove), + .remove = __exit_p(starfire_rtc_remove), }; static int __init starfire_rtc_init(void) { - return platform_driver_register(&starfire_rtc_driver); + return platform_driver_probe(&starfire_rtc_driver, starfire_rtc_probe); } static void __exit starfire_rtc_exit(void) diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index f4cd46e15af..7d1547b0070 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -170,7 +170,7 @@ static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; pdata->alrm_mday = alrm->time.tm_mday; pdata->alrm_hour = alrm->time.tm_hour; @@ -187,7 +187,7 @@ static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -EINVAL; alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; @@ -221,7 +221,7 @@ static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq < 0) + if (pdata->irq <= 0) return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ switch (cmd) { case RTC_AIE_OFF: @@ -303,7 +303,6 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->irq = -1; if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { ret = -EBUSY; goto out; @@ -329,13 +328,13 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) dev_warn(&pdev->dev, "voltage-low detected.\n"); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = -1; + pdata->irq = 0; } } @@ -355,7 +354,7 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) out: if (pdata->rtc) rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) + if (pdata->irq > 0) free_irq(pdata->irq, pdev); if (ioaddr) iounmap(ioaddr); @@ -371,7 +370,7 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); rtc_device_unregister(pdata->rtc); - if (pdata->irq >= 0) { + if (pdata->irq > 0) { writeb(0, pdata->ioaddr + RTC_INTERRUPTS); free_irq(pdata->irq, pdev); } @@ -400,7 +399,7 @@ static __init int stk17ta8_init(void) static __exit void stk17ta8_exit(void) { - return platform_driver_unregister(&stk17ta8_rtc_driver); + platform_driver_unregister(&stk17ta8_rtc_driver); } module_init(stk17ta8_init); diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c index 2012ccbb4a5..5b2261052a6 100644 --- a/drivers/rtc/rtc-sun4v.c +++ b/drivers/rtc/rtc-sun4v.c @@ -1,4 +1,4 @@ -/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems. +/* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems. * * Copyright (C) 2008 David S. Miller */ @@ -7,21 +7,11 @@ #include #include #include -#include #include #include #include -MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("SUN4V RTC driver"); -MODULE_LICENSE("GPL"); - -struct sun4v_rtc { - struct rtc_device *rtc; - spinlock_t lock; -}; - static unsigned long hypervisor_get_time(void) { unsigned long ret, time; @@ -45,15 +35,7 @@ retry: static int sun4v_read_time(struct device *dev, struct rtc_time *tm) { - struct sun4v_rtc *p = dev_get_drvdata(dev); - unsigned long flags, secs; - - spin_lock_irqsave(&p->lock, flags); - secs = hypervisor_get_time(); - spin_unlock_irqrestore(&p->lock, flags); - - rtc_time_to_tm(secs, tm); - + rtc_time_to_tm(hypervisor_get_time(), tm); return 0; } @@ -80,19 +62,14 @@ retry: static int sun4v_set_time(struct device *dev, struct rtc_time *tm) { - struct sun4v_rtc *p = dev_get_drvdata(dev); - unsigned long flags, secs; + unsigned long secs; int err; err = rtc_tm_to_time(tm, &secs); if (err) return err; - spin_lock_irqsave(&p->lock, flags); - err = hypervisor_set_time(secs); - spin_unlock_irqrestore(&p->lock, flags); - - return err; + return hypervisor_set_time(secs); } static const struct rtc_class_ops sun4v_rtc_ops = { @@ -100,33 +77,22 @@ static const struct rtc_class_ops sun4v_rtc_ops = { .set_time = sun4v_set_time, }; -static int __devinit sun4v_rtc_probe(struct platform_device *pdev) +static int __init sun4v_rtc_probe(struct platform_device *pdev) { - struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL); - - if (!p) - return -ENOMEM; - - spin_lock_init(&p->lock); - - p->rtc = rtc_device_register("sun4v", &pdev->dev, + struct rtc_device *rtc = rtc_device_register("sun4v", &pdev->dev, &sun4v_rtc_ops, THIS_MODULE); - if (IS_ERR(p->rtc)) { - int err = PTR_ERR(p->rtc); - kfree(p); - return err; - } - platform_set_drvdata(pdev, p); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(pdev, rtc); return 0; } -static int __devexit sun4v_rtc_remove(struct platform_device *pdev) +static int __exit sun4v_rtc_remove(struct platform_device *pdev) { - struct sun4v_rtc *p = platform_get_drvdata(pdev); - - rtc_device_unregister(p->rtc); - kfree(p); + struct rtc_device *rtc = platform_get_drvdata(pdev); + rtc_device_unregister(rtc); return 0; } @@ -135,13 +101,12 @@ static struct platform_driver sun4v_rtc_driver = { .name = "rtc-sun4v", .owner = THIS_MODULE, }, - .probe = sun4v_rtc_probe, - .remove = __devexit_p(sun4v_rtc_remove), + .remove = __exit_p(sun4v_rtc_remove), }; static int __init sun4v_rtc_init(void) { - return platform_driver_register(&sun4v_rtc_driver); + return platform_driver_probe(&sun4v_rtc_driver, sun4v_rtc_probe); } static void __exit sun4v_rtc_exit(void) @@ -151,3 +116,7 @@ static void __exit sun4v_rtc_exit(void) module_init(sun4v_rtc_init); module_exit(sun4v_rtc_exit); + +MODULE_AUTHOR("David S. Miller "); +MODULE_DESCRIPTION("SUN4V RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index bc930022004..e478280ff62 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -34,14 +34,9 @@ static int test_rtc_read_time(struct device *dev, return 0; } -static int test_rtc_set_time(struct device *dev, - struct rtc_time *tm) -{ - return 0; -} - static int test_rtc_set_mmss(struct device *dev, unsigned long secs) { + dev_info(dev, "%s, secs = %lu\n", __func__, secs); return 0; } @@ -78,7 +73,6 @@ static int test_rtc_ioctl(struct device *dev, unsigned int cmd, static const struct rtc_class_ops test_rtc_ops = { .proc = test_rtc_proc, .read_time = test_rtc_read_time, - .set_time = test_rtc_set_time, .read_alarm = test_rtc_read_alarm, .set_alarm = test_rtc_set_alarm, .set_mmss = test_rtc_set_mmss, diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c index abe87a4d266..ad35f76c46b 100644 --- a/drivers/rtc/rtc-twl4030.c +++ b/drivers/rtc/rtc-twl4030.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -119,7 +120,7 @@ static int twl4030_rtc_write_u8(u8 data, u8 reg) static unsigned char rtc_irq_bits; /* - * Enable timer and/or alarm interrupts. + * Enable 1/second update and/or alarm interrupts. */ static int set_rtc_irq_bit(unsigned char bit) { @@ -127,6 +128,7 @@ static int set_rtc_irq_bit(unsigned char bit) int ret; val = rtc_irq_bits | bit; + val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); if (ret == 0) rtc_irq_bits = val; @@ -135,7 +137,7 @@ static int set_rtc_irq_bit(unsigned char bit) } /* - * Disable timer and/or alarm interrupts. + * Disable update and/or alarm interrupts. */ static int mask_rtc_irq_bit(unsigned char bit) { @@ -150,7 +152,7 @@ static int mask_rtc_irq_bit(unsigned char bit) return ret; } -static inline int twl4030_rtc_alarm_irq_set_state(int enabled) +static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) { int ret; @@ -162,7 +164,7 @@ static inline int twl4030_rtc_alarm_irq_set_state(int enabled) return ret; } -static inline int twl4030_rtc_irq_set_state(int enabled) +static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled) { int ret; @@ -291,7 +293,7 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) unsigned char alarm_data[ALL_TIME_REGS + 1]; int ret; - ret = twl4030_rtc_alarm_irq_set_state(0); + ret = twl4030_rtc_alarm_irq_enable(dev, 0); if (ret) goto out; @@ -311,35 +313,11 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) } if (alm->enabled) - ret = twl4030_rtc_alarm_irq_set_state(1); + ret = twl4030_rtc_alarm_irq_enable(dev, 1); out: return ret; } -#ifdef CONFIG_RTC_INTF_DEV - -static int twl4030_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) -{ - switch (cmd) { - case RTC_AIE_OFF: - return twl4030_rtc_alarm_irq_set_state(0); - case RTC_AIE_ON: - return twl4030_rtc_alarm_irq_set_state(1); - case RTC_UIE_OFF: - return twl4030_rtc_irq_set_state(0); - case RTC_UIE_ON: - return twl4030_rtc_irq_set_state(1); - - default: - return -ENOIOCTLCMD; - } -} - -#else -#define omap_rtc_ioctl NULL -#endif - static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) { unsigned long events = 0; @@ -399,11 +377,12 @@ out: } static struct rtc_class_ops twl4030_rtc_ops = { - .ioctl = twl4030_rtc_ioctl, .read_time = twl4030_rtc_read_time, .set_time = twl4030_rtc_set_time, .read_alarm = twl4030_rtc_read_alarm, .set_alarm = twl4030_rtc_set_alarm, + .alarm_irq_enable = twl4030_rtc_alarm_irq_enable, + .update_irq_enable = twl4030_rtc_update_irq_enable, }; /*----------------------------------------------------------------------*/ @@ -415,13 +394,13 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) int irq = platform_get_irq(pdev, 0); u8 rd_reg; - if (irq < 0) - return irq; + if (irq <= 0) + return -EINVAL; rtc = rtc_device_register(pdev->name, &pdev->dev, &twl4030_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { - ret = -EINVAL; + ret = PTR_ERR(rtc); dev_err(&pdev->dev, "can't register RTC device, err %ld\n", PTR_ERR(rtc)); goto out0; @@ -431,7 +410,6 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); - if (ret < 0) goto out1; @@ -474,7 +452,6 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) return ret; - out2: free_irq(irq, rtc); out1: @@ -505,8 +482,9 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev) static void twl4030_rtc_shutdown(struct platform_device *pdev) { - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M | - BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + /* mask timer interrupts, but leave alarm interrupts on to enable + power-on when alarm is triggered */ + mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); } #ifdef CONFIG_PM diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c new file mode 100644 index 00000000000..4ee4857ff20 --- /dev/null +++ b/drivers/rtc/rtc-tx4939.c @@ -0,0 +1,317 @@ +/* + * TX4939 internal RTC driver + * Based on RBTX49xx patch from CELF patch archive. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * (C) Copyright TOSHIBA CORPORATION 2005-2007 + */ +#include +#include +#include +#include +#include + +struct tx4939rtc_plat_data { + struct rtc_device *rtc; + struct tx4939_rtc_reg __iomem *rtcreg; +}; + +static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) +{ + return platform_get_drvdata(to_platform_device(dev)); +} + +static int tx4939_rtc_cmd(struct tx4939_rtc_reg __iomem *rtcreg, int cmd) +{ + int i = 0; + + __raw_writel(cmd, &rtcreg->ctl); + /* This might take 30us (next 32.768KHz clock) */ + while (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_BUSY) { + /* timeout on approx. 100us (@ GBUS200MHz) */ + if (i++ > 200 * 100) + return -EBUSY; + cpu_relax(); + } + return 0; +} + +static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned char buf[6]; + + buf[0] = 0; + buf[1] = 0; + buf[2] = secs; + buf[3] = secs >> 8; + buf[4] = secs >> 16; + buf[5] = secs >> 24; + spin_lock_irq(&pdata->rtc->irq_lock); + __raw_writel(0, &rtcreg->adr); + for (i = 0; i < 6; i++) + __raw_writel(buf[i], &rtcreg->dat); + ret = tx4939_rtc_cmd(rtcreg, + TX4939_RTCCTL_COMMAND_SETTIME | + (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; +} + +static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned long sec; + unsigned char buf[6]; + + spin_lock_irq(&pdata->rtc->irq_lock); + ret = tx4939_rtc_cmd(rtcreg, + TX4939_RTCCTL_COMMAND_GETTIME | + (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); + if (ret) { + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; + } + __raw_writel(2, &rtcreg->adr); + for (i = 2; i < 6; i++) + buf[i] = __raw_readl(&rtcreg->dat); + spin_unlock_irq(&pdata->rtc->irq_lock); + sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + rtc_time_to_tm(sec, tm); + return rtc_valid_tm(tm); +} + +static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned long sec; + unsigned char buf[6]; + + if (alrm->time.tm_sec < 0 || + alrm->time.tm_min < 0 || + alrm->time.tm_hour < 0 || + alrm->time.tm_mday < 0 || + alrm->time.tm_mon < 0 || + alrm->time.tm_year < 0) + return -EINVAL; + rtc_tm_to_time(&alrm->time, &sec); + buf[0] = 0; + buf[1] = 0; + buf[2] = sec; + buf[3] = sec >> 8; + buf[4] = sec >> 16; + buf[5] = sec >> 24; + spin_lock_irq(&pdata->rtc->irq_lock); + __raw_writel(0, &rtcreg->adr); + for (i = 0; i < 6; i++) + __raw_writel(buf[i], &rtcreg->dat); + ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM | + (alrm->enabled ? TX4939_RTCCTL_ALME : 0)); + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; +} + +static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + int i, ret; + unsigned long sec; + unsigned char buf[6]; + u32 ctl; + + spin_lock_irq(&pdata->rtc->irq_lock); + ret = tx4939_rtc_cmd(rtcreg, + TX4939_RTCCTL_COMMAND_GETALARM | + (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); + if (ret) { + spin_unlock_irq(&pdata->rtc->irq_lock); + return ret; + } + __raw_writel(2, &rtcreg->adr); + for (i = 2; i < 6; i++) + buf[i] = __raw_readl(&rtcreg->dat); + ctl = __raw_readl(&rtcreg->ctl); + alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; + alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; + spin_unlock_irq(&pdata->rtc->irq_lock); + sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + rtc_time_to_tm(sec, &alrm->time); + return rtc_valid_tm(&alrm->time); +} + +static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + + spin_lock_irq(&pdata->rtc->irq_lock); + tx4939_rtc_cmd(pdata->rtcreg, + TX4939_RTCCTL_COMMAND_NOP | + (enabled ? TX4939_RTCCTL_ALME : 0)); + spin_unlock_irq(&pdata->rtc->irq_lock); + return 0; +} + +static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id) +{ + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev_id); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + unsigned long events = RTC_IRQF; + + spin_lock(&pdata->rtc->irq_lock); + if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) { + events |= RTC_AF; + tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP); + } + spin_unlock(&pdata->rtc->irq_lock); + rtc_update_irq(pdata->rtc, 1, events); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops tx4939_rtc_ops = { + .read_time = tx4939_rtc_read_time, + .read_alarm = tx4939_rtc_read_alarm, + .set_alarm = tx4939_rtc_set_alarm, + .set_mmss = tx4939_rtc_set_mmss, + .alarm_irq_enable = tx4939_rtc_alarm_irq_enable, +}; + +static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + ssize_t count; + + spin_lock_irq(&pdata->rtc->irq_lock); + for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; + count++, size--) { + __raw_writel(pos++, &rtcreg->adr); + *buf++ = __raw_readl(&rtcreg->dat); + } + spin_unlock_irq(&pdata->rtc->irq_lock); + return count; +} + +static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; + ssize_t count; + + spin_lock_irq(&pdata->rtc->irq_lock); + for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; + count++, size--) { + __raw_writel(pos++, &rtcreg->adr); + __raw_writel(*buf++, &rtcreg->dat); + } + spin_unlock_irq(&pdata->rtc->irq_lock); + return count; +} + +static struct bin_attribute tx4939_rtc_nvram_attr = { + .attr = { + .name = "nvram", + .mode = S_IRUGO | S_IWUSR, + }, + .size = TX4939_RTC_REG_RAMSIZE, + .read = tx4939_rtc_nvram_read, + .write = tx4939_rtc_nvram_write, +}; + +static int __init tx4939_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct tx4939rtc_plat_data *pdata; + struct resource *res; + int irq, ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + platform_set_drvdata(pdev, pdata); + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name)) + return -EBUSY; + pdata->rtcreg = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!pdata->rtcreg) + return -EBUSY; + + tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); + if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, + IRQF_DISABLED | IRQF_SHARED, + pdev->name, &pdev->dev) < 0) { + return -EBUSY; + } + rtc = rtc_device_register(pdev->name, &pdev->dev, + &tx4939_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + pdata->rtc = rtc; + ret = sysfs_create_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); + if (ret) + rtc_device_unregister(rtc); + return ret; +} + +static int __exit tx4939_rtc_remove(struct platform_device *pdev) +{ + struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev); + struct rtc_device *rtc = pdata->rtc; + + spin_lock_irq(&rtc->irq_lock); + tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); + spin_unlock_irq(&rtc->irq_lock); + sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); + rtc_device_unregister(rtc); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver tx4939_rtc_driver = { + .remove = __exit_p(tx4939_rtc_remove), + .driver = { + .name = "tx4939rtc", + .owner = THIS_MODULE, + }, +}; + +static int __init tx4939rtc_init(void) +{ + return platform_driver_probe(&tx4939_rtc_driver, tx4939_rtc_probe); +} + +static void __exit tx4939rtc_exit(void) +{ + platform_driver_unregister(&tx4939_rtc_driver); +} + +module_init(tx4939rtc_init); +module_exit(tx4939rtc_exit); + +MODULE_AUTHOR("Atsushi Nemoto "); +MODULE_DESCRIPTION("TX4939 internal RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tx4939rtc"); diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 834dcc6d785..f11297aff85 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -84,8 +85,8 @@ static DEFINE_SPINLOCK(rtc_lock); static char rtc_name[] = "RTC"; static unsigned long periodic_count; static unsigned int alarm_enabled; -static int aie_irq = -1; -static int pie_irq = -1; +static int aie_irq; +static int pie_irq; static inline unsigned long read_elapsed_second(void) { @@ -210,6 +211,8 @@ static int vr41xx_rtc_irq_set_freq(struct device *dev, int freq) { unsigned long count; + if (!is_power_of_2(freq)) + return -EINVAL; count = RTC_FREQUENCY; do_div(count, freq); @@ -360,7 +363,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) spin_unlock_irq(&rtc_lock); aie_irq = platform_get_irq(pdev, 0); - if (aie_irq < 0 || aie_irq >= nr_irqs) { + if (aie_irq <= 0) { retval = -EBUSY; goto err_device_unregister; } @@ -371,7 +374,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) goto err_device_unregister; pie_irq = platform_get_irq(pdev, 1); - if (pie_irq < 0 || pie_irq >= nr_irqs) + if (pie_irq <= 0) goto err_free_irq; retval = request_irq(pie_irq, rtclong1_interrupt, IRQF_DISABLED, diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c new file mode 100644 index 00000000000..5c5e3aa9138 --- /dev/null +++ b/drivers/rtc/rtc-wm8350.c @@ -0,0 +1,514 @@ +/* + * Real Time Clock driver for Wolfson Microelectronics WM8350 + * + * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC. + * + * Author: Liam Girdwood + * linux@wolfsonmicro.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WM8350_SET_ALM_RETRIES 5 +#define WM8350_SET_TIME_RETRIES 5 +#define WM8350_GET_TIME_RETRIES 5 + +#define to_wm8350_from_rtc_dev(d) container_of(d, struct wm8350, rtc.pdev.dev) + +/* + * Read current time and date in RTC + */ +static int wm8350_rtc_readtime(struct device *dev, struct rtc_time *tm) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + u16 time1[4], time2[4]; + int retries = WM8350_GET_TIME_RETRIES, ret; + + /* + * Read the time twice and compare. + * If time1 == time2, then time is valid else retry. + */ + do { + ret = wm8350_block_read(wm8350, WM8350_RTC_SECONDS_MINUTES, + 4, time1); + if (ret < 0) + return ret; + ret = wm8350_block_read(wm8350, WM8350_RTC_SECONDS_MINUTES, + 4, time2); + if (ret < 0) + return ret; + + if (memcmp(time1, time2, sizeof(time1)) == 0) { + tm->tm_sec = time1[0] & WM8350_RTC_SECS_MASK; + + tm->tm_min = (time1[0] & WM8350_RTC_MINS_MASK) + >> WM8350_RTC_MINS_SHIFT; + + tm->tm_hour = time1[1] & WM8350_RTC_HRS_MASK; + + tm->tm_wday = ((time1[1] >> WM8350_RTC_DAY_SHIFT) + & 0x7) - 1; + + tm->tm_mon = ((time1[2] & WM8350_RTC_MTH_MASK) + >> WM8350_RTC_MTH_SHIFT) - 1; + + tm->tm_mday = (time1[2] & WM8350_RTC_DATE_MASK); + + tm->tm_year = ((time1[3] & WM8350_RTC_YHUNDREDS_MASK) + >> WM8350_RTC_YHUNDREDS_SHIFT) * 100; + tm->tm_year += time1[3] & WM8350_RTC_YUNITS_MASK; + + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, + tm->tm_year); + tm->tm_year -= 1900; + + dev_dbg(dev, "Read (%d left): %04x %04x %04x %04x\n", + retries, + time1[0], time1[1], time1[2], time1[3]); + + return 0; + } + } while (retries--); + + dev_err(dev, "timed out reading RTC time\n"); + return -EIO; +} + +/* + * Set current time and date in RTC + */ +static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + u16 time[4]; + u16 rtc_ctrl; + int ret, retries = WM8350_SET_TIME_RETRIES; + + time[0] = tm->tm_sec; + time[0] |= tm->tm_min << WM8350_RTC_MINS_SHIFT; + time[1] = tm->tm_hour; + time[1] |= (tm->tm_wday + 1) << WM8350_RTC_DAY_SHIFT; + time[2] = tm->tm_mday; + time[2] |= (tm->tm_mon + 1) << WM8350_RTC_MTH_SHIFT; + time[3] = ((tm->tm_year + 1900) / 100) << WM8350_RTC_YHUNDREDS_SHIFT; + time[3] |= (tm->tm_year + 1900) % 100; + + dev_dbg(dev, "Setting: %04x %04x %04x %04x\n", + time[0], time[1], time[2], time[3]); + + /* Set RTC_SET to stop the clock */ + ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, WM8350_RTC_SET); + if (ret < 0) + return ret; + + /* Wait until confirmation of stopping */ + do { + rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); + schedule_timeout_uninterruptible(msecs_to_jiffies(1)); + } while (retries-- && !(rtc_ctrl & WM8350_RTC_STS)); + + if (!retries) { + dev_err(dev, "timed out on set confirmation\n"); + return -EIO; + } + + /* Write time to RTC */ + ret = wm8350_block_write(wm8350, WM8350_RTC_SECONDS_MINUTES, 4, time); + if (ret < 0) + return ret; + + /* Clear RTC_SET to start the clock */ + ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL, + WM8350_RTC_SET); + return ret; +} + +/* + * Read alarm time and date in RTC + */ +static int wm8350_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + u16 time[4]; + int ret; + + ret = wm8350_block_read(wm8350, WM8350_ALARM_SECONDS_MINUTES, 4, time); + if (ret < 0) + return ret; + + tm->tm_sec = time[0] & WM8350_RTC_ALMSECS_MASK; + if (tm->tm_sec == WM8350_RTC_ALMSECS_MASK) + tm->tm_sec = -1; + + tm->tm_min = time[0] & WM8350_RTC_ALMMINS_MASK; + if (tm->tm_min == WM8350_RTC_ALMMINS_MASK) + tm->tm_min = -1; + else + tm->tm_min >>= WM8350_RTC_ALMMINS_SHIFT; + + tm->tm_hour = time[1] & WM8350_RTC_ALMHRS_MASK; + if (tm->tm_hour == WM8350_RTC_ALMHRS_MASK) + tm->tm_hour = -1; + + tm->tm_wday = ((time[1] >> WM8350_RTC_ALMDAY_SHIFT) & 0x7) - 1; + if (tm->tm_wday > 7) + tm->tm_wday = -1; + + tm->tm_mon = time[2] & WM8350_RTC_ALMMTH_MASK; + if (tm->tm_mon == WM8350_RTC_ALMMTH_MASK) + tm->tm_mon = -1; + else + tm->tm_mon = (tm->tm_mon >> WM8350_RTC_ALMMTH_SHIFT) - 1; + + tm->tm_mday = (time[2] & WM8350_RTC_ALMDATE_MASK); + if (tm->tm_mday == WM8350_RTC_ALMDATE_MASK) + tm->tm_mday = -1; + + tm->tm_year = -1; + + alrm->enabled = !(time[3] & WM8350_RTC_ALMSTS); + + return 0; +} + +static int wm8350_rtc_stop_alarm(struct wm8350 *wm8350) +{ + int retries = WM8350_SET_ALM_RETRIES; + u16 rtc_ctrl; + int ret; + + /* Set RTC_SET to stop the clock */ + ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, + WM8350_RTC_ALMSET); + if (ret < 0) + return ret; + + /* Wait until confirmation of stopping */ + do { + rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); + schedule_timeout_uninterruptible(msecs_to_jiffies(1)); + } while (retries-- && !(rtc_ctrl & WM8350_RTC_ALMSTS)); + + if (!(rtc_ctrl & WM8350_RTC_ALMSTS)) + return -ETIMEDOUT; + + return 0; +} + +static int wm8350_rtc_start_alarm(struct wm8350 *wm8350) +{ + int ret; + int retries = WM8350_SET_ALM_RETRIES; + u16 rtc_ctrl; + + ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL, + WM8350_RTC_ALMSET); + if (ret < 0) + return ret; + + /* Wait until confirmation */ + do { + rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); + schedule_timeout_uninterruptible(msecs_to_jiffies(1)); + } while (retries-- && rtc_ctrl & WM8350_RTC_ALMSTS); + + if (rtc_ctrl & WM8350_RTC_ALMSTS) + return -ETIMEDOUT; + + return 0; +} + +static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + u16 time[3]; + int ret; + + memset(time, 0, sizeof(time)); + + if (tm->tm_sec != -1) + time[0] |= tm->tm_sec; + else + time[0] |= WM8350_RTC_ALMSECS_MASK; + + if (tm->tm_min != -1) + time[0] |= tm->tm_min << WM8350_RTC_ALMMINS_SHIFT; + else + time[0] |= WM8350_RTC_ALMMINS_MASK; + + if (tm->tm_hour != -1) + time[1] |= tm->tm_hour; + else + time[1] |= WM8350_RTC_ALMHRS_MASK; + + if (tm->tm_wday != -1) + time[1] |= (tm->tm_wday + 1) << WM8350_RTC_ALMDAY_SHIFT; + else + time[1] |= WM8350_RTC_ALMDAY_MASK; + + if (tm->tm_mday != -1) + time[2] |= tm->tm_mday; + else + time[2] |= WM8350_RTC_ALMDATE_MASK; + + if (tm->tm_mon != -1) + time[2] |= (tm->tm_mon + 1) << WM8350_RTC_ALMMTH_SHIFT; + else + time[2] |= WM8350_RTC_ALMMTH_MASK; + + ret = wm8350_rtc_stop_alarm(wm8350); + if (ret < 0) + return ret; + + /* Write time to RTC */ + ret = wm8350_block_write(wm8350, WM8350_ALARM_SECONDS_MINUTES, + 3, time); + if (ret < 0) + return ret; + + if (alrm->enabled) + ret = wm8350_rtc_start_alarm(wm8350); + + return ret; +} + +/* + * Handle commands from user-space + */ +static int wm8350_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + + switch (cmd) { + case RTC_AIE_OFF: + return wm8350_rtc_stop_alarm(wm8350); + case RTC_AIE_ON: + return wm8350_rtc_start_alarm(wm8350); + + case RTC_UIE_OFF: + wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); + break; + case RTC_UIE_ON: + wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC); + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq, + void *data) +{ + struct rtc_device *rtc = wm8350->rtc.rtc; + int ret; + + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); + + /* Make it one shot */ + ret = wm8350_set_bits(wm8350, WM8350_RTC_TIME_CONTROL, + WM8350_RTC_ALMSET); + if (ret != 0) { + dev_err(&(wm8350->rtc.pdev->dev), + "Failed to disable alarm: %d\n", ret); + } +} + +static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq, + void *data) +{ + struct rtc_device *rtc = wm8350->rtc.rtc; + + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_UF); +} + +static const struct rtc_class_ops wm8350_rtc_ops = { + .ioctl = wm8350_rtc_ioctl, + .read_time = wm8350_rtc_readtime, + .set_time = wm8350_rtc_settime, + .read_alarm = wm8350_rtc_readalarm, + .set_alarm = wm8350_rtc_setalarm, +}; + +#ifdef CONFIG_PM +static int wm8350_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); + int ret = 0; + u16 reg; + + reg = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); + + if (device_may_wakeup(&wm8350->rtc.pdev->dev) && + reg & WM8350_RTC_ALMSTS) { + ret = wm8350_rtc_stop_alarm(wm8350); + if (ret != 0) + dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", + ret); + } + + return ret; +} + +static int wm8350_rtc_resume(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); + int ret; + + if (wm8350->rtc.alarm_enabled) { + ret = wm8350_rtc_start_alarm(wm8350); + if (ret != 0) + dev_err(&pdev->dev, + "Failed to restart RTC alarm: %d\n", ret); + } + + return 0; +} + +#else +#define wm8350_rtc_suspend NULL +#define wm8350_rtc_resume NULL +#endif + +static int wm8350_rtc_probe(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct wm8350_rtc *wm_rtc = &wm8350->rtc; + int ret = 0; + u16 timectl, power5; + + timectl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); + if (timectl & WM8350_RTC_BCD) { + dev_err(&pdev->dev, "RTC BCD mode not supported\n"); + return -EINVAL; + } + if (timectl & WM8350_RTC_12HR) { + dev_err(&pdev->dev, "RTC 12 hour mode not supported\n"); + return -EINVAL; + } + + /* enable the RTC if it's not already enabled */ + power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); + if (!(power5 & WM8350_RTC_TICK_ENA)) { + dev_info(wm8350->dev, "Starting RTC\n"); + + wm8350_reg_unlock(wm8350); + + ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, + WM8350_RTC_TICK_ENA); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable RTC: %d\n", ret); + return ret; + } + + wm8350_reg_lock(wm8350); + } + + if (timectl & WM8350_RTC_STS) { + int retries; + + ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL, + WM8350_RTC_SET); + if (ret < 0) { + dev_err(&pdev->dev, "failed to start: %d\n", ret); + return ret; + } + + retries = WM8350_SET_TIME_RETRIES; + do { + timectl = wm8350_reg_read(wm8350, + WM8350_RTC_TIME_CONTROL); + } while (timectl & WM8350_RTC_STS && retries--); + + if (retries == 0) { + dev_err(&pdev->dev, "failed to start: timeout\n"); + return -ENODEV; + } + } + + device_init_wakeup(&pdev->dev, 1); + + wm_rtc->rtc = rtc_device_register("wm8350", &pdev->dev, + &wm8350_rtc_ops, THIS_MODULE); + if (IS_ERR(wm_rtc->rtc)) { + ret = PTR_ERR(wm_rtc->rtc); + dev_err(&pdev->dev, "failed to register RTC: %d\n", ret); + return ret; + } + + wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); + wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_PER); + + wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, + wm8350_rtc_update_handler, NULL); + + wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM, + wm8350_rtc_alarm_handler, NULL); + wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_ALM); + + return 0; +} + +static int __devexit wm8350_rtc_remove(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct wm8350_rtc *wm_rtc = &wm8350->rtc; + + wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); + + wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC); + wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM); + + rtc_device_unregister(wm_rtc->rtc); + + return 0; +} + +static struct platform_driver wm8350_rtc_driver = { + .probe = wm8350_rtc_probe, + .remove = __devexit_p(wm8350_rtc_remove), + .suspend = wm8350_rtc_suspend, + .resume = wm8350_rtc_resume, + .driver = { + .name = "wm8350-rtc", + }, +}; + +static int __init wm8350_rtc_init(void) +{ + return platform_driver_register(&wm8350_rtc_driver); +} +module_init(wm8350_rtc_init); + +static void __exit wm8350_rtc_exit(void) +{ + platform_driver_unregister(&wm8350_rtc_driver); +} +module_exit(wm8350_rtc_exit); + +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("RTC driver for the WM8350"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-rtc"); -- cgit v1.2.3