diff options
Diffstat (limited to 'drivers/rtc')
100 files changed, 4898 insertions, 657 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 19c03ab2bdcb..79fbe3832dfc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -20,14 +20,24 @@ if RTC_CLASS config RTC_HCTOSYS bool "Set system time from RTC on startup and resume" default y + depends on !ALWAYS_USE_PERSISTENT_CLOCK help If you say yes here, the system time (wall clock) will be set using the value read from a specified RTC device. This is useful to avoid unnecessary fsck runs at boot time, and to network better. +config RTC_SYSTOHC + bool "Set the RTC time based on NTP synchronization" + default y + depends on !ALWAYS_USE_PERSISTENT_CLOCK + help + If you say yes here, the system time (wall clock) will be stored + in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11 + minutes if userspace reports synchronized NTP status. + config RTC_HCTOSYS_DEVICE string "RTC used to set the system time" - depends on RTC_HCTOSYS = y + depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y default "rtc0" help The RTC device that will be used to (re)initialize the system @@ -194,6 +204,12 @@ config RTC_DRV_DS3232 This driver can also be built as a module. If so, the module will be called rtc-ds3232. +config RTC_DRV_LP8788 + tristate "TI LP8788 RTC driver" + depends on MFD_LP8788 + help + Say Y to enable support for the LP8788 RTC/ALARM driver. + config RTC_DRV_MAX6900 tristate "Maxim MAX6900" help @@ -233,6 +249,26 @@ config RTC_DRV_MAX8998 This driver can also be built as a module. If so, the module will be called rtc-max8998. +config RTC_DRV_MAX8997 + tristate "Maxim MAX8997" + depends on MFD_MAX8997 + help + If you say yes here you will get support for the + RTC of Maxim MAX8997 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max8997. + +config RTC_DRV_MAX77686 + tristate "Maxim MAX77686" + depends on MFD_MAX77686 + help + If you say yes here you will get support for the + RTC of Maxim MAX77686 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max77686. + config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help @@ -269,6 +305,25 @@ config RTC_DRV_X1205 This driver can also be built as a module. If so, the module will be called rtc-x1205. +config RTC_DRV_PALMAS + tristate "TI Palmas RTC driver" + depends on MFD_PALMAS + help + If you say yes here you get support for the RTC of TI PALMA series PMIC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-palma. + +config RTC_DRV_PCF8523 + tristate "NXP PCF8523" + help + If you say yes here you get support for the NXP PCF8523 RTC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-pcf8523. + config RTC_DRV_PCF8563 tristate "Philips PCF8563/Epson RTC8564" help @@ -343,6 +398,14 @@ config RTC_DRV_TWL4030 This driver can also be built as a module. If so, the module will be called rtc-twl. +config RTC_DRV_TPS6586X + tristate "TI TPS6586X RTC driver" + depends on MFD_TPS6586X + help + TI Power Managment IC TPS6586X supports RTC functionality + along with alarm. This driver supports the RTC driver for + the TPS6586X RTC module. + config RTC_DRV_TPS65910 tristate "TI TPS65910 RTC driver" depends on RTC_CLASS && MFD_TPS65910 @@ -353,6 +416,14 @@ config RTC_DRV_TPS65910 This driver can also be built as a module. If so, the module will be called rtc-tps65910. +config RTC_DRV_TPS80031 + tristate "TI TPS80031/TPS80032 RTC driver" + depends on MFD_TPS80031 + help + TI Power Managment IC TPS80031 supports RTC functionality + along with alarm. This driver supports the RTC driver for + the TPS80031 RTC module. + config RTC_DRV_RC5T583 tristate "RICOH 5T583 RTC driver" depends on MFD_RC5T583 @@ -510,6 +581,14 @@ config RTC_DRV_PCF2123 This driver can also be built as a module. If so, the module will be called rtc-pcf2123. +config RTC_DRV_RX4581 + tristate "Epson RX-4581" + help + If you say yes here you will get support for the Epson RX-4581. + + This driver can also be built as a module. If so the module + will be called rtc-rx4581. + endif # SPI_MASTER comment "Platform RTC drivers" @@ -600,6 +679,16 @@ config RTC_DRV_DA9052 Say y here to support the RTC driver for Dialog Semiconductor DA9052-BC and DA9053-AA/Bx PMICs. +config RTC_DRV_DA9055 + tristate "Dialog Semiconductor DA9055 RTC" + depends on MFD_DA9055 + help + If you say yes here you will get support for the + RTC of the Dialog DA9055 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-da9055 + config RTC_DRV_EFI tristate "EFI RTC" depends on IA64 @@ -768,7 +857,7 @@ config RTC_DRV_DAVINCI config RTC_DRV_IMXDI tristate "Freescale IMX DryIce Real Time Clock" - depends on SOC_IMX25 + depends on ARCH_MXC help Support for Freescale IMX DryIce RTC @@ -777,11 +866,13 @@ config RTC_DRV_IMXDI config RTC_DRV_OMAP tristate "TI OMAP1" - depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX + depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX || SOC_AM33XX help - Say "yes" here to support the real time clock on TI OMAP1 and - DA8xx/OMAP-L13x chips. This driver can also be built as a - module called rtc-omap. + Say "yes" here to support the on chip real time clock + present on TI OMAP1, AM33xx and DA8xx/OMAP-L13x. + + This driver can also be built as a module, if so, module + will be called rtc-omap. config HAVE_S3C_RTC bool @@ -994,7 +1085,7 @@ config RTC_DRV_TX4939 config RTC_DRV_MV tristate "Marvell SoC RTC" - depends on ARCH_KIRKWOOD || ARCH_DOVE + depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU 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 @@ -1144,4 +1235,20 @@ config RTC_DRV_SNVS This driver can also be built as a module, if so, the module will be called "rtc-snvs". +comment "HID Sensor RTC drivers" + +config RTC_DRV_HID_SENSOR_TIME + tristate "HID Sensor Time" + depends on USB_HID + select IIO + select HID_SENSOR_HUB + select HID_SENSOR_IIO_COMMON + help + Say yes here to build support for the HID Sensors of type Time. + This drivers makes such sensors available as RTCs. + + If this driver is compiled as a module, it will be named + rtc-hid-sensor-time. + + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 56297f0fd388..c33f86f1a69b 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += rtc-lib.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o +obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o @@ -29,6 +30,7 @@ obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o +obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o @@ -51,10 +53,12 @@ obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o +obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o +obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o @@ -68,14 +72,18 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o +obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o +obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o +obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o +obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o @@ -93,6 +101,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o +obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o @@ -109,7 +118,9 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o +obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o +obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.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 diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index f8a0aab218cb..9b742d3ffb94 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/rtc.h> #include <linux/kdev_t.h> @@ -50,6 +52,10 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; struct timespec delta, delta_delta; + + if (has_persistent_clock()) + return 0; + if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; @@ -88,6 +94,9 @@ static int rtc_resume(struct device *dev) struct timespec new_system, new_rtc; struct timespec sleep_time; + if (has_persistent_clock()) + return 0; + rtc_hctosys_ret = -ENODEV; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; @@ -244,7 +253,6 @@ void rtc_device_unregister(struct rtc_device *rtc) rtc_proc_del_device(rtc); device_unregister(&rtc->dev); rtc->ops = NULL; - ida_simple_remove(&rtc_ida, rtc->id); mutex_unlock(&rtc->ops_lock); put_device(&rtc->dev); } @@ -255,7 +263,7 @@ static int __init rtc_init(void) { rtc_class = class_create(THIS_MODULE, "rtc"); if (IS_ERR(rtc_class)) { - printk(KERN_ERR "%s: couldn't create class\n", __FILE__); + pr_err("couldn't create class\n"); return PTR_ERR(rtc_class); } rtc_class->suspend = rtc_suspend; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 9592b936b71b..42bd57da239d 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -587,16 +587,16 @@ void rtc_update_irq(struct rtc_device *rtc, } EXPORT_SYMBOL_GPL(rtc_update_irq); -static int __rtc_match(struct device *dev, void *data) +static int __rtc_match(struct device *dev, const void *data) { - char *name = (char *)data; + const char *name = data; if (strcmp(dev_name(dev), name) == 0) return 1; return 0; } -struct rtc_device *rtc_class_open(char *name) +struct rtc_device *rtc_class_open(const char *name) { struct device *dev; struct rtc_device *rtc = NULL; diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 6367984e0565..63b17ebe90e8 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -248,7 +248,7 @@ static int pm80x_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume); -static int __devinit pm80x_rtc_probe(struct platform_device *pdev) +static int pm80x_rtc_probe(struct platform_device *pdev) { struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm80x_platform_data *pm80x_pdata; @@ -342,7 +342,7 @@ out: return ret; } -static int __devexit pm80x_rtc_remove(struct platform_device *pdev) +static int pm80x_rtc_remove(struct platform_device *pdev) { struct pm80x_rtc_info *info = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); @@ -358,7 +358,7 @@ static struct platform_driver pm80x_rtc_driver = { .pm = &pm80x_rtc_pm_ops, }, .probe = pm80x_rtc_probe, - .remove = __devexit_p(pm80x_rtc_remove), + .remove = pm80x_rtc_remove, }; module_platform_driver(pm80x_rtc_driver); diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index de9e854b326a..f663746f4603 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -286,8 +286,8 @@ out: #endif #ifdef CONFIG_OF -static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev, - struct pm860x_rtc_info *info) +static int pm860x_rtc_dt_init(struct platform_device *pdev, + struct pm860x_rtc_info *info) { struct device_node *np = pdev->dev.parent->of_node; int ret; @@ -307,7 +307,7 @@ static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev, #define pm860x_rtc_dt_init(x, y) (-1) #endif -static int __devinit pm860x_rtc_probe(struct platform_device *pdev) +static int pm860x_rtc_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_rtc_pdata *pdata = NULL; @@ -412,7 +412,7 @@ out: return ret; } -static int __devexit pm860x_rtc_remove(struct platform_device *pdev) +static int pm860x_rtc_remove(struct platform_device *pdev) { struct pm860x_rtc_info *info = platform_get_drvdata(pdev); @@ -459,7 +459,7 @@ static struct platform_driver pm860x_rtc_driver = { .pm = &pm860x_rtc_pm_ops, }, .probe = pm860x_rtc_probe, - .remove = __devexit_p(pm860x_rtc_remove), + .remove = pm860x_rtc_remove, }; module_platform_driver(pm860x_rtc_driver); diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 2e5970fe9eeb..57cde2b061e6 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -389,7 +389,7 @@ static const struct rtc_class_ops ab8500_rtc_ops = { .alarm_irq_enable = ab8500_rtc_irq_enable, }; -static int __devinit ab8500_rtc_probe(struct platform_device *pdev) +static int ab8500_rtc_probe(struct platform_device *pdev) { int err; struct rtc_device *rtc; @@ -448,7 +448,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit ab8500_rtc_remove(struct platform_device *pdev) +static int ab8500_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); int irq = platform_get_irq_byname(pdev, "ALARM"); @@ -468,7 +468,7 @@ static struct platform_driver ab8500_rtc_driver = { .owner = THIS_MODULE, }, .probe = ab8500_rtc_probe, - .remove = __devexit_p(ab8500_rtc_remove), + .remove = ab8500_rtc_remove, }; module_platform_driver(ab8500_rtc_driver); diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index fca9790c7de7..434ebc3a99dc 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -31,7 +31,7 @@ #include <asm/uaccess.h> -#include <mach/at91_rtc.h> +#include "rtc-at91rm9200.h" #define at91_rtc_read(field) \ __raw_readl(at91_rtc_regs + field) @@ -86,7 +86,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = tm->tm_year - 1900; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -100,7 +100,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long cr; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -145,7 +145,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM) ? 1 : 0; - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -183,7 +183,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM); } - pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, + dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -192,7 +192,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - pr_debug("%s(): cmd=%08x\n", __func__, enabled); + dev_dbg(dev, "%s(): cmd=%08x\n", __func__, enabled); if (enabled) { at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); @@ -240,7 +240,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, 1, events); - pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__, + dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__, events >> 8, events & 0x000000FF); return IRQ_HANDLED; @@ -296,8 +296,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) IRQF_SHARED, "at91_rtc", pdev); if (ret) { - printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", - irq); + dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); return ret; } @@ -315,7 +314,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rtc); - printk(KERN_INFO "AT91 Real Time Clock driver.\n"); + dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n"); return 0; } diff --git a/drivers/rtc/rtc-at91rm9200.h b/drivers/rtc/rtc-at91rm9200.h new file mode 100644 index 000000000000..da1945e5f714 --- /dev/null +++ b/drivers/rtc/rtc-at91rm9200.h @@ -0,0 +1,75 @@ +/* + * arch/arm/mach-at91/include/mach/at91_rtc.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Real Time Clock (RTC) - System peripheral registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91_RTC_H +#define AT91_RTC_H + +#define AT91_RTC_CR 0x00 /* Control Register */ +#define AT91_RTC_UPDTIM (1 << 0) /* Update Request Time Register */ +#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */ +#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */ +#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8) +#define AT91_RTC_TIMEVSEL_HOUR (1 << 8) +#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8) +#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8) +#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */ +#define AT91_RTC_CALEVSEL_WEEK (0 << 16) +#define AT91_RTC_CALEVSEL_MONTH (1 << 16) +#define AT91_RTC_CALEVSEL_YEAR (2 << 16) + +#define AT91_RTC_MR 0x04 /* Mode Register */ +#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */ + +#define AT91_RTC_TIMR 0x08 /* Time Register */ +#define AT91_RTC_SEC (0x7f << 0) /* Current Second */ +#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */ +#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */ +#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */ + +#define AT91_RTC_CALR 0x0c /* Calendar Register */ +#define AT91_RTC_CENT (0x7f << 0) /* Current Century */ +#define AT91_RTC_YEAR (0xff << 8) /* Current Year */ +#define AT91_RTC_MONTH (0x1f << 16) /* Current Month */ +#define AT91_RTC_DAY (7 << 21) /* Current Day */ +#define AT91_RTC_DATE (0x3f << 24) /* Current Date */ + +#define AT91_RTC_TIMALR 0x10 /* Time Alarm Register */ +#define AT91_RTC_SECEN (1 << 7) /* Second Alarm Enable */ +#define AT91_RTC_MINEN (1 << 15) /* Minute Alarm Enable */ +#define AT91_RTC_HOUREN (1 << 23) /* Hour Alarm Enable */ + +#define AT91_RTC_CALALR 0x14 /* Calendar Alarm Register */ +#define AT91_RTC_MTHEN (1 << 23) /* Month Alarm Enable */ +#define AT91_RTC_DATEEN (1 << 31) /* Date Alarm Enable */ + +#define AT91_RTC_SR 0x18 /* Status Register */ +#define AT91_RTC_ACKUPD (1 << 0) /* Acknowledge for Update */ +#define AT91_RTC_ALARM (1 << 1) /* Alarm Flag */ +#define AT91_RTC_SECEV (1 << 2) /* Second Event */ +#define AT91_RTC_TIMEV (1 << 3) /* Time Event */ +#define AT91_RTC_CALEV (1 << 4) /* Calendar Event */ + +#define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */ +#define AT91_RTC_IER 0x20 /* Interrupt Enable Register */ +#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */ +#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */ + +#define AT91_RTC_VER 0x2c /* Valid Entry Register */ +#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */ +#define AT91_RTC_NVCAL (1 << 1) /* Non valid Calendar */ +#define AT91_RTC_NVTIMALR (1 << 2) /* Non valid Time Alarm */ +#define AT91_RTC_NVCALALR (1 << 3) /* Non valid Calendar Alarm */ + +#endif diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 2dfe7a2fb998..39cfd2ee0042 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -19,8 +19,8 @@ #include <linux/interrupt.h> #include <linux/ioctl.h> #include <linux/slab.h> +#include <linux/platform_data/atmel.h> -#include <mach/board.h> #include <mach/at91_rtt.h> #include <mach/cpu.h> @@ -289,7 +289,7 @@ static const struct rtc_class_ops at91_rtc_ops = { /* * Initialize and install RTC driver */ -static int __devinit at91_rtc_probe(struct platform_device *pdev) +static int at91_rtc_probe(struct platform_device *pdev) { struct resource *r, *r_gpbr; struct sam9_rtc *rtc; @@ -387,7 +387,7 @@ fail: /* * Disable and remove the RTC driver */ -static int __devexit at91_rtc_remove(struct platform_device *pdev) +static int at91_rtc_remove(struct platform_device *pdev) { struct sam9_rtc *rtc = platform_get_drvdata(pdev); u32 mr = rtt_readl(rtc, MR); @@ -463,7 +463,7 @@ static int at91_rtc_resume(struct platform_device *pdev) static struct platform_driver at91_rtc_driver = { .probe = at91_rtc_probe, - .remove = __devexit_p(at91_rtc_remove), + .remove = at91_rtc_remove, .shutdown = at91_rtc_shutdown, .suspend = at91_rtc_suspend, .resume = at91_rtc_resume, diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index 979ed0406ce9..b309da4ec745 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -62,7 +62,7 @@ static struct rtc_class_ops au1xtoy_rtc_ops = { .set_time = au1xtoy_rtc_set_time, }; -static int __devinit au1xtoy_rtc_probe(struct platform_device *pdev) +static int au1xtoy_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtcdev; unsigned long t; @@ -116,7 +116,7 @@ out_err: return ret; } -static int __devexit au1xtoy_rtc_remove(struct platform_device *pdev) +static int au1xtoy_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtcdev = platform_get_drvdata(pdev); @@ -131,7 +131,7 @@ static struct platform_driver au1xrtc_driver = { .name = "rtc-au1xxx", .owner = THIS_MODULE, }, - .remove = __devexit_p(au1xtoy_rtc_remove), + .remove = au1xtoy_rtc_remove, }; static int __init au1xtoy_rtc_init(void) diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index abfc1a0c07d9..4ec614b0954d 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -342,7 +342,7 @@ static struct rtc_class_ops bfin_rtc_ops = { .alarm_irq_enable = bfin_rtc_alarm_irq_enable, }; -static int __devinit bfin_rtc_probe(struct platform_device *pdev) +static int bfin_rtc_probe(struct platform_device *pdev) { struct bfin_rtc *rtc; struct device *dev = &pdev->dev; @@ -388,7 +388,7 @@ err: return ret; } -static int __devexit bfin_rtc_remove(struct platform_device *pdev) +static int bfin_rtc_remove(struct platform_device *pdev) { struct bfin_rtc *rtc = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -451,7 +451,7 @@ static struct platform_driver bfin_rtc_driver = { .owner = THIS_MODULE, }, .probe = bfin_rtc_probe, - .remove = __devexit_p(bfin_rtc_remove), + .remove = bfin_rtc_remove, .suspend = bfin_rtc_suspend, .resume = bfin_rtc_resume, }; diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index f090159dce4a..036cb89f8188 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -163,7 +163,7 @@ static int bq32k_probe(struct i2c_client *client, return 0; } -static int __devexit bq32k_remove(struct i2c_client *client) +static int bq32k_remove(struct i2c_client *client) { struct rtc_device *rtc = i2c_get_clientdata(client); @@ -183,7 +183,7 @@ static struct i2c_driver bq32k_driver = { .owner = THIS_MODULE, }, .probe = bq32k_probe, - .remove = __devexit_p(bq32k_remove), + .remove = bq32k_remove, .id_table = bq32k_id, }; diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index bf612ef22941..693be71b5b18 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -140,7 +140,7 @@ static const struct rtc_class_ops bq4802_ops = { .set_time = bq4802_set_time, }; -static int __devinit bq4802_probe(struct platform_device *pdev) +static int bq4802_probe(struct platform_device *pdev) { struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL); int err = -ENOMEM; @@ -191,7 +191,7 @@ out_free: goto out; } -static int __devexit bq4802_remove(struct platform_device *pdev) +static int bq4802_remove(struct platform_device *pdev) { struct bq4802 *p = platform_get_drvdata(pdev); @@ -215,7 +215,7 @@ static struct platform_driver bq4802_driver = { .owner = THIS_MODULE, }, .probe = bq4802_probe, - .remove = __devexit_p(bq4802_remove), + .remove = bq4802_remove, }; module_platform_driver(bq4802_driver); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 4267789ca995..af97c94e8a3a 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -706,7 +706,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) rtc_cmos_int_handler = hpet_rtc_interrupt; err = hpet_register_irq_handler(cmos_interrupt); if (err != 0) { - printk(KERN_WARNING "hpet_register_irq_handler " + dev_warn(dev, "hpet_register_irq_handler " " failed in rtc_init()."); goto cleanup1; } @@ -731,8 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup2; } - pr_info("%s: %s%s, %zd bytes nvram%s\n", - dev_name(&cmos_rtc.rtc->dev), + dev_info(dev, "%s%s, %zd bytes nvram%s\n", !is_valid_irq(rtc_irq) ? "no alarms" : cmos_rtc.mon_alrm ? "alarms up to one year" : cmos_rtc.day_alrm ? "alarms up to one month" : @@ -820,8 +819,7 @@ static int cmos_suspend(struct device *dev) enable_irq_wake(cmos->irq); } - pr_debug("%s: suspend%s, ctrl %02x\n", - dev_name(&cmos_rtc.rtc->dev), + dev_dbg(dev, "suspend%s, ctrl %02x\n", (tmp & RTC_AIE) ? ", alarm may wake" : "", tmp); @@ -876,9 +874,7 @@ static int cmos_resume(struct device *dev) spin_unlock_irq(&rtc_lock); } - pr_debug("%s: resume, ctrl %02x\n", - dev_name(&cmos_rtc.rtc->dev), - tmp); + dev_dbg(dev, "resume, ctrl %02x\n", tmp); return 0; } @@ -947,8 +943,7 @@ static void rtc_wake_off(struct device *dev) */ static struct cmos_rtc_board_info acpi_rtc_info; -static void __devinit -cmos_wake_setup(struct device *dev) +static void cmos_wake_setup(struct device *dev) { if (acpi_disabled) return; @@ -980,8 +975,7 @@ cmos_wake_setup(struct device *dev) #else -static void __devinit -cmos_wake_setup(struct device *dev) +static void cmos_wake_setup(struct device *dev) { } @@ -991,8 +985,7 @@ cmos_wake_setup(struct device *dev) #include <linux/pnp.h> -static int __devinit -cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) +static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) { cmos_wake_setup(&pnp->dev); @@ -1101,7 +1094,6 @@ static __init void cmos_of_init(struct platform_device *pdev) } #else static inline void cmos_of_init(struct platform_device *pdev) {} -#define of_cmos_match NULL #endif /*----------------------------------------------------------------*/ @@ -1143,7 +1135,7 @@ static struct platform_driver cmos_platform_driver = { #ifdef CONFIG_PM .pm = &cmos_pm_ops, #endif - .of_match_table = of_cmos_match, + .of_match_table = of_match_ptr(of_cmos_match), } }; diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index c8115b83e5ab..2d28ec1aa1cd 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -157,7 +157,6 @@ static int __exit coh901331_remove(struct platform_device *pdev) if (rtap) { rtc_device_unregister(rtap->rtc); clk_unprepare(rtap->clk); - clk_put(rtap->clk); platform_set_drvdata(pdev, NULL); } @@ -196,7 +195,7 @@ static int __init coh901331_probe(struct platform_device *pdev) "RTC COH 901 331 Alarm", rtap)) return -EIO; - rtap->clk = clk_get(&pdev->dev, NULL); + rtap->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(rtap->clk)) { ret = PTR_ERR(rtap->clk); dev_err(&pdev->dev, "could not get clock\n"); @@ -207,7 +206,7 @@ static int __init coh901331_probe(struct platform_device *pdev) ret = clk_prepare_enable(rtap->clk); if (ret) { dev_err(&pdev->dev, "could not enable clock\n"); - goto out_no_clk_prepenable; + return ret; } clk_disable(rtap->clk); @@ -224,8 +223,6 @@ static int __init coh901331_probe(struct platform_device *pdev) out_no_rtc: platform_set_drvdata(pdev, NULL); clk_unprepare(rtap->clk); - out_no_clk_prepenable: - clk_put(rtap->clk); return ret; } diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 78070255bd3f..0dde688ca09b 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -228,7 +228,7 @@ static const struct rtc_class_ops da9052_rtc_ops = { .alarm_irq_enable = da9052_rtc_alarm_irq_enable, }; -static int __devinit da9052_rtc_probe(struct platform_device *pdev) +static int da9052_rtc_probe(struct platform_device *pdev) { struct da9052_rtc *rtc; int ret; @@ -240,9 +240,10 @@ static int __devinit da9052_rtc_probe(struct platform_device *pdev) rtc->da9052 = dev_get_drvdata(pdev->dev.parent); platform_set_drvdata(pdev, rtc); rtc->irq = platform_get_irq_byname(pdev, "ALM"); - ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "ALM", rtc); + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + da9052_rtc_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "ALM", rtc); if (ret != 0) { rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); return ret; @@ -250,24 +251,17 @@ static int __devinit da9052_rtc_probe(struct platform_device *pdev) rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &da9052_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc)) { - ret = PTR_ERR(rtc->rtc); - goto err_free_irq; - } + if (IS_ERR(rtc->rtc)) + return PTR_ERR(rtc->rtc); return 0; - -err_free_irq: - free_irq(rtc->irq, rtc); - return ret; } -static int __devexit da9052_rtc_remove(struct platform_device *pdev) +static int da9052_rtc_remove(struct platform_device *pdev) { struct da9052_rtc *rtc = pdev->dev.platform_data; rtc_device_unregister(rtc->rtc); - free_irq(rtc->irq, rtc); platform_set_drvdata(pdev, NULL); return 0; @@ -275,7 +269,7 @@ static int __devexit da9052_rtc_remove(struct platform_device *pdev) static struct platform_driver da9052_rtc_driver = { .probe = da9052_rtc_probe, - .remove = __devexit_p(da9052_rtc_remove), + .remove = da9052_rtc_remove, .driver = { .name = "da9052-rtc", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c new file mode 100644 index 000000000000..8f0dcfedb83c --- /dev/null +++ b/drivers/rtc/rtc-da9055.c @@ -0,0 +1,413 @@ +/* + * Real time clock driver for DA9055 + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: Dajun Dajun Chen <dajun.chen@diasemi.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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/reg.h> +#include <linux/mfd/da9055/pdata.h> + +struct da9055_rtc { + struct rtc_device *rtc; + struct da9055 *da9055; + int alarm_enable; +}; + +static int da9055_rtc_enable_alarm(struct da9055_rtc *rtc, bool enable) +{ + int ret; + if (enable) { + ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y, + DA9055_RTC_ALM_EN, + DA9055_RTC_ALM_EN); + if (ret != 0) + dev_err(rtc->da9055->dev, "Failed to enable ALM: %d\n", + ret); + rtc->alarm_enable = 1; + } else { + ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y, + DA9055_RTC_ALM_EN, 0); + if (ret != 0) + dev_err(rtc->da9055->dev, + "Failed to disable ALM: %d\n", ret); + rtc->alarm_enable = 0; + } + return ret; +} + +static irqreturn_t da9055_rtc_alm_irq(int irq, void *data) +{ + struct da9055_rtc *rtc = data; + + da9055_rtc_enable_alarm(rtc, 0); + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm) +{ + int ret; + uint8_t v[5]; + + ret = da9055_group_read(da9055, DA9055_REG_ALARM_MI, 5, v); + if (ret != 0) { + dev_err(da9055->dev, "Failed to group read ALM: %d\n", ret); + return ret; + } + + rtc_tm->tm_year = (v[4] & DA9055_RTC_ALM_YEAR) + 100; + rtc_tm->tm_mon = (v[3] & DA9055_RTC_ALM_MONTH) - 1; + rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY; + rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR; + rtc_tm->tm_min = v[0] & DA9055_RTC_ALM_MIN; + + return rtc_valid_tm(rtc_tm); +} + +static int da9055_set_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm) +{ + int ret; + uint8_t v[2]; + + rtc_tm->tm_year -= 100; + rtc_tm->tm_mon += 1; + + ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MI, + DA9055_RTC_ALM_MIN, rtc_tm->tm_min); + if (ret != 0) { + dev_err(da9055->dev, "Failed to write ALRM MIN: %d\n", ret); + return ret; + } + + v[0] = rtc_tm->tm_hour; + v[1] = rtc_tm->tm_mday; + + ret = da9055_group_write(da9055, DA9055_REG_ALARM_H, 2, v); + if (ret < 0) + return ret; + + ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO, + DA9055_RTC_ALM_MONTH, rtc_tm->tm_mon); + if (ret < 0) + dev_err(da9055->dev, "Failed to write ALM Month:%d\n", ret); + + ret = da9055_reg_update(da9055, DA9055_REG_ALARM_Y, + DA9055_RTC_ALM_YEAR, rtc_tm->tm_year); + if (ret < 0) + dev_err(da9055->dev, "Failed to write ALM Year:%d\n", ret); + + return ret; +} + +static int da9055_rtc_get_alarm_status(struct da9055 *da9055) +{ + int ret; + + ret = da9055_reg_read(da9055, DA9055_REG_ALARM_Y); + if (ret < 0) { + dev_err(da9055->dev, "Failed to read ALM: %d\n", ret); + return ret; + } + ret &= DA9055_RTC_ALM_EN; + return (ret > 0) ? 1 : 0; +} + +static int da9055_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) +{ + struct da9055_rtc *rtc = dev_get_drvdata(dev); + uint8_t v[6]; + int ret; + + ret = da9055_reg_read(rtc->da9055, DA9055_REG_COUNT_S); + if (ret < 0) + return ret; + + /* + * Registers are only valid when RTC_READ + * status bit is asserted + */ + if (!(ret & DA9055_RTC_READ)) + return -EBUSY; + + ret = da9055_group_read(rtc->da9055, DA9055_REG_COUNT_S, 6, v); + if (ret < 0) { + dev_err(rtc->da9055->dev, "Failed to read RTC time : %d\n", + ret); + return ret; + } + + rtc_tm->tm_year = (v[5] & DA9055_RTC_YEAR) + 100; + rtc_tm->tm_mon = (v[4] & DA9055_RTC_MONTH) - 1; + rtc_tm->tm_mday = v[3] & DA9055_RTC_DAY; + rtc_tm->tm_hour = v[2] & DA9055_RTC_HOUR; + rtc_tm->tm_min = v[1] & DA9055_RTC_MIN; + rtc_tm->tm_sec = v[0] & DA9055_RTC_SEC; + + return rtc_valid_tm(rtc_tm); +} + +static int da9055_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct da9055_rtc *rtc; + uint8_t v[6]; + + rtc = dev_get_drvdata(dev); + + v[0] = tm->tm_sec; + v[1] = tm->tm_min; + v[2] = tm->tm_hour; + v[3] = tm->tm_mday; + v[4] = tm->tm_mon + 1; + v[5] = tm->tm_year - 100; + + return da9055_group_write(rtc->da9055, DA9055_REG_COUNT_S, 6, v); +} + +static int da9055_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + int ret; + struct rtc_time *tm = &alrm->time; + struct da9055_rtc *rtc = dev_get_drvdata(dev); + + ret = da9055_read_alarm(rtc->da9055, tm); + + if (ret) + return ret; + + alrm->enabled = da9055_rtc_get_alarm_status(rtc->da9055); + + return 0; +} + +static int da9055_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + int ret; + struct rtc_time *tm = &alrm->time; + struct da9055_rtc *rtc = dev_get_drvdata(dev); + + ret = da9055_rtc_enable_alarm(rtc, 0); + if (ret < 0) + return ret; + + ret = da9055_set_alarm(rtc->da9055, tm); + if (ret) + return ret; + + ret = da9055_rtc_enable_alarm(rtc, 1); + + return ret; +} + +static int da9055_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct da9055_rtc *rtc = dev_get_drvdata(dev); + + return da9055_rtc_enable_alarm(rtc, enabled); +} + +static const struct rtc_class_ops da9055_rtc_ops = { + .read_time = da9055_rtc_read_time, + .set_time = da9055_rtc_set_time, + .read_alarm = da9055_rtc_read_alarm, + .set_alarm = da9055_rtc_set_alarm, + .alarm_irq_enable = da9055_rtc_alarm_irq_enable, +}; + +static int da9055_rtc_device_init(struct da9055 *da9055, + struct da9055_pdata *pdata) +{ + int ret; + + /* Enable RTC and the internal Crystal */ + ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, + DA9055_RTC_EN, DA9055_RTC_EN); + if (ret < 0) + return ret; + ret = da9055_reg_update(da9055, DA9055_REG_EN_32K, + DA9055_CRYSTAL_EN, DA9055_CRYSTAL_EN); + if (ret < 0) + return ret; + + /* Enable RTC in Power Down mode */ + ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, + DA9055_RTC_MODE_PD, DA9055_RTC_MODE_PD); + if (ret < 0) + return ret; + + /* Enable RTC in Reset mode */ + if (pdata && pdata->reset_enable) { + ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, + DA9055_RTC_MODE_SD, + DA9055_RTC_MODE_SD << + DA9055_RTC_MODE_SD_SHIFT); + if (ret < 0) + return ret; + } + + /* Disable the RTC TICK ALM */ + ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO, + DA9055_RTC_TICK_WAKE_MASK, 0); + if (ret < 0) + return ret; + + return 0; +} + +static int da9055_rtc_probe(struct platform_device *pdev) +{ + struct da9055_rtc *rtc; + struct da9055_pdata *pdata = NULL; + int ret, alm_irq; + + rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9055_rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->da9055 = dev_get_drvdata(pdev->dev.parent); + pdata = rtc->da9055->dev->platform_data; + platform_set_drvdata(pdev, rtc); + + ret = da9055_rtc_device_init(rtc->da9055, pdata); + if (ret < 0) + goto err_rtc; + + ret = da9055_reg_read(rtc->da9055, DA9055_REG_ALARM_Y); + if (ret < 0) + goto err_rtc; + + if (ret & DA9055_RTC_ALM_EN) + rtc->alarm_enable = 1; + + device_init_wakeup(&pdev->dev, 1); + + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &da9055_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + ret = PTR_ERR(rtc->rtc); + goto err_rtc; + } + + alm_irq = platform_get_irq_byname(pdev, "ALM"); + alm_irq = regmap_irq_get_virq(rtc->da9055->irq_data, alm_irq); + ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, + da9055_rtc_alm_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "ALM", rtc); + if (ret != 0) + dev_err(rtc->da9055->dev, "irq registration failed: %d\n", ret); + +err_rtc: + return ret; + +} + +static int da9055_rtc_remove(struct platform_device *pdev) +{ + struct da9055_rtc *rtc = pdev->dev.platform_data; + + rtc_device_unregister(rtc->rtc); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +/* Turn off the alarm if it should not be a wake source. */ +static int da9055_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); + int ret; + + if (!device_may_wakeup(&pdev->dev)) { + /* Disable the ALM IRQ */ + ret = da9055_rtc_enable_alarm(rtc, 0); + if (ret < 0) + dev_err(&pdev->dev, "Failed to disable RTC ALM\n"); + } + + return 0; +} + +/* Enable the alarm if it should be enabled (in case it was disabled to + * prevent use as a wake source). + */ +static int da9055_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); + int ret; + + if (!device_may_wakeup(&pdev->dev)) { + if (rtc->alarm_enable) { + ret = da9055_rtc_enable_alarm(rtc, 1); + if (ret < 0) + dev_err(&pdev->dev, + "Failed to restart RTC ALM\n"); + } + } + + return 0; +} + +/* Unconditionally disable the alarm */ +static int da9055_rtc_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); + int ret; + + ret = da9055_rtc_enable_alarm(rtc, 0); + if (ret < 0) + dev_err(&pdev->dev, "Failed to freeze RTC ALMs\n"); + + return 0; + +} +#else +#define da9055_rtc_suspend NULL +#define da9055_rtc_resume NULL +#define da9055_rtc_freeze NULL +#endif + +static const struct dev_pm_ops da9055_rtc_pm_ops = { + .suspend = da9055_rtc_suspend, + .resume = da9055_rtc_resume, + + .freeze = da9055_rtc_freeze, + .thaw = da9055_rtc_resume, + .restore = da9055_rtc_resume, + + .poweroff = da9055_rtc_suspend, +}; + +static struct platform_driver da9055_rtc_driver = { + .probe = da9055_rtc_probe, + .remove = da9055_rtc_remove, + .driver = { + .name = "da9055-rtc", + .owner = THIS_MODULE, + .pm = &da9055_rtc_pm_ops, + }, +}; + +module_platform_driver(da9055_rtc_driver); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("RTC driver for Dialog DA9055 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-rtc"); diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 14c2109dbaa3..56b73089bb29 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -485,7 +485,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) struct resource *res, *mem; int ret = 0; - davinci_rtc = kzalloc(sizeof(struct davinci_rtc), GFP_KERNEL); + davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL); if (!davinci_rtc) { dev_dbg(dev, "could not allocate memory for private data\n"); return -ENOMEM; @@ -494,34 +494,31 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) davinci_rtc->irq = platform_get_irq(pdev, 0); if (davinci_rtc->irq < 0) { dev_err(dev, "no RTC irq\n"); - ret = davinci_rtc->irq; - goto fail1; + return davinci_rtc->irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "no mem resource\n"); - ret = -EINVAL; - goto fail1; + return -EINVAL; } davinci_rtc->pbase = res->start; davinci_rtc->base_size = resource_size(res); - mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size, - pdev->name); + mem = devm_request_mem_region(dev, davinci_rtc->pbase, + davinci_rtc->base_size, pdev->name); if (!mem) { dev_err(dev, "RTC registers at %08x are not free\n", davinci_rtc->pbase); - ret = -EBUSY; - goto fail1; + return -EBUSY; } - davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size); + davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase, + davinci_rtc->base_size); if (!davinci_rtc->base) { dev_err(dev, "unable to ioremap MEM resource\n"); - ret = -ENOMEM; - goto fail2; + return -ENOMEM; } platform_set_drvdata(pdev, davinci_rtc); @@ -529,9 +526,10 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &davinci_rtc_ops, THIS_MODULE); if (IS_ERR(davinci_rtc->rtc)) { - dev_err(dev, "unable to register RTC device, err %ld\n", - PTR_ERR(davinci_rtc->rtc)); - goto fail3; + ret = PTR_ERR(davinci_rtc->rtc); + dev_err(dev, "unable to register RTC device, err %d\n", + ret); + goto fail1; } rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); @@ -541,11 +539,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL); rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL); - ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt, + ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt, 0, "davinci_rtc", davinci_rtc); if (ret < 0) { dev_err(dev, "unable to register davinci RTC interrupt\n"); - goto fail4; + goto fail2; } /* Enable interrupts */ @@ -559,20 +557,14 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) return 0; -fail4: - rtc_device_unregister(davinci_rtc->rtc); -fail3: - platform_set_drvdata(pdev, NULL); - iounmap(davinci_rtc->base); fail2: - release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); + rtc_device_unregister(davinci_rtc->rtc); fail1: - kfree(davinci_rtc); - + platform_set_drvdata(pdev, NULL); return ret; } -static int __devexit davinci_rtc_remove(struct platform_device *pdev) +static int davinci_rtc_remove(struct platform_device *pdev) { struct davinci_rtc *davinci_rtc = platform_get_drvdata(pdev); @@ -580,23 +572,16 @@ static int __devexit davinci_rtc_remove(struct platform_device *pdev) rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); - free_irq(davinci_rtc->irq, davinci_rtc); - rtc_device_unregister(davinci_rtc->rtc); - iounmap(davinci_rtc->base); - release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); - platform_set_drvdata(pdev, NULL); - kfree(davinci_rtc); - return 0; } static struct platform_driver davinci_rtc_driver = { .probe = davinci_rtc_probe, - .remove = __devexit_p(davinci_rtc_remove), + .remove = davinci_rtc_remove, .driver = { .name = "rtc_davinci", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index cace6d3aed9a..d04939369251 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/rtc.h> #include <linux/sched.h> @@ -379,25 +381,6 @@ static long rtc_dev_ioctl(struct file *file, err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); break; -#if 0 - case RTC_EPOCH_SET: -#ifndef rtc_epoch - /* - * There were no RTC clocks before 1900. - */ - if (arg < 1900) { - err = -EINVAL; - break; - } - rtc_epoch = arg; - err = 0; -#endif - break; - - case RTC_EPOCH_READ: - err = put_user(rtc_epoch, (unsigned long __user *)uarg); - break; -#endif case RTC_WKALM_SET: mutex_unlock(&rtc->ops_lock); if (copy_from_user(&alarm, uarg, sizeof(alarm))) @@ -481,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc) return; if (rtc->id >= RTC_DEV_MAX) { - pr_debug("%s: too many RTC devices\n", rtc->name); + dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name); return; } @@ -499,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc) void rtc_dev_add_device(struct rtc_device *rtc) { if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) - printk(KERN_WARNING "%s: failed to add char device %d:%d\n", + dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", rtc->name, MAJOR(rtc_devt), rtc->id); else - pr_debug("%s: dev (%d:%d)\n", rtc->name, + dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name, MAJOR(rtc_devt), rtc->id); } @@ -518,8 +501,7 @@ void __init rtc_dev_init(void) err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); if (err < 0) - printk(KERN_ERR "%s: failed to allocate char dev region\n", - __FILE__); + pr_err("failed to allocate char dev region\n"); } void __exit rtc_dev_exit(void) diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c index d4457afcba89..b2ed2c94b081 100644 --- a/drivers/rtc/rtc-dm355evm.c +++ b/drivers/rtc/rtc-dm355evm.c @@ -123,7 +123,7 @@ static struct rtc_class_ops dm355evm_rtc_ops = { /*----------------------------------------------------------------------*/ -static int __devinit dm355evm_rtc_probe(struct platform_device *pdev) +static int dm355evm_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; @@ -139,7 +139,7 @@ static int __devinit dm355evm_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit dm355evm_rtc_remove(struct platform_device *pdev) +static int dm355evm_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -154,7 +154,7 @@ static int __devexit dm355evm_rtc_remove(struct platform_device *pdev) */ static struct platform_driver rtc_dm355evm_driver = { .probe = dm355evm_rtc_probe, - .remove = __devexit_p(dm355evm_rtc_remove), + .remove = dm355evm_rtc_remove, .driver = { .owner = THIS_MODULE, .name = "rtc-dm355evm", diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 990c3ff489bf..d989412a348a 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -329,7 +329,7 @@ static const struct rtc_class_ops ds1286_ops = { .alarm_irq_enable = ds1286_alarm_irq_enable, }; -static int __devinit ds1286_probe(struct platform_device *pdev) +static int ds1286_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; @@ -376,7 +376,7 @@ out: return ret; } -static int __devexit ds1286_remove(struct platform_device *pdev) +static int ds1286_remove(struct platform_device *pdev) { struct ds1286_priv *priv = platform_get_drvdata(pdev); @@ -393,7 +393,7 @@ static struct platform_driver ds1286_platform_driver = { .owner = THIS_MODULE, }, .probe = ds1286_probe, - .remove = __devexit_p(ds1286_remove), + .remove = ds1286_remove, }; module_platform_driver(ds1286_platform_driver); diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index f0d638922644..fdbcdb289d60 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -234,7 +234,7 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit ds1302_rtc_remove(struct platform_device *pdev) +static int ds1302_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -249,7 +249,7 @@ static struct platform_driver ds1302_platform_driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, - .remove = __devexit_p(ds1302_rtc_remove), + .remove = ds1302_rtc_remove, }; static int __init ds1302_rtc_init(void) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 686a865913e1..b05a6dc96405 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -601,7 +601,7 @@ static struct bin_attribute nvram = { * Interface to SPI stack */ -static int __devinit ds1305_probe(struct spi_device *spi) +static int ds1305_probe(struct spi_device *spi) { struct ds1305 *ds1305; int status; @@ -635,9 +635,7 @@ static int __devinit ds1305_probe(struct spi_device *spi) goto fail0; } - dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n", - "read", ds1305->ctrl[0], - ds1305->ctrl[1], ds1305->ctrl[2]); + dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl); /* Sanity check register values ... partially compensating for the * fact that SPI has no device handshake. A pullup on MISO would @@ -723,9 +721,7 @@ static int __devinit ds1305_probe(struct spi_device *spi) goto fail0; } - dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n", - "write", ds1305->ctrl[0], - ds1305->ctrl[1], ds1305->ctrl[2]); + dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl); } /* see if non-Linux software set up AM/PM mode */ @@ -787,7 +783,7 @@ fail0: return status; } -static int __devexit ds1305_remove(struct spi_device *spi) +static int ds1305_remove(struct spi_device *spi) { struct ds1305 *ds1305 = spi_get_drvdata(spi); @@ -810,7 +806,7 @@ static struct spi_driver ds1305_driver = { .driver.name = "rtc-ds1305", .driver.owner = THIS_MODULE, .probe = ds1305_probe, - .remove = __devexit_p(ds1305_remove), + .remove = ds1305_remove, /* REVISIT add suspend/resume */ }; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 836710ce750e..970a236b147a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -322,12 +322,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) return -EIO; } - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", - "read", - ds1307->regs[0], ds1307->regs[1], - ds1307->regs[2], ds1307->regs[3], - ds1307->regs[4], ds1307->regs[5], - ds1307->regs[6]); + dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs); t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f); t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f); @@ -398,9 +393,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) break; } - 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]); + dev_dbg(dev, "%s: %7ph\n", "write", buf); result = ds1307->write_block_data(ds1307->client, ds1307->offset, 7, buf); @@ -617,8 +610,8 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, /*----------------------------------------------------------------------*/ -static int __devinit ds1307_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds1307_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds1307 *ds1307; int err = -ENODEV; @@ -938,7 +931,7 @@ exit_free: return err; } -static int __devexit ds1307_remove(struct i2c_client *client) +static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -963,7 +956,7 @@ static struct i2c_driver ds1307_driver = { .owner = THIS_MODULE, }, .probe = ds1307_probe, - .remove = __devexit_p(ds1307_remove), + .remove = ds1307_remove, .id_table = ds1307_id, }; diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 966316088b7f..fef76868aae0 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -391,7 +391,7 @@ out_free: return ret; } -static int __devexit ds1374_remove(struct i2c_client *client) +static int ds1374_remove(struct i2c_client *client) { struct ds1374 *ds1374 = i2c_get_clientdata(client); @@ -442,7 +442,7 @@ static struct i2c_driver ds1374_driver = { .pm = DS1374_PM, }, .probe = ds1374_probe, - .remove = __devexit_p(ds1374_remove), + .remove = ds1374_remove, .id_table = ds1374_id, }; diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index b0a99e1b25be..f994257981a0 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -121,7 +121,7 @@ static const struct rtc_class_ops ds1390_rtc_ops = { .set_time = ds1390_set_time, }; -static int __devinit ds1390_probe(struct spi_device *spi) +static int ds1390_probe(struct spi_device *spi) { unsigned char tmp; struct ds1390 *chip; @@ -156,7 +156,7 @@ static int __devinit ds1390_probe(struct spi_device *spi) return res; } -static int __devexit ds1390_remove(struct spi_device *spi) +static int ds1390_remove(struct spi_device *spi) { struct ds1390 *chip = spi_get_drvdata(spi); @@ -172,7 +172,7 @@ static struct spi_driver ds1390_driver = { .owner = THIS_MODULE, }, .probe = ds1390_probe, - .remove = __devexit_p(ds1390_remove), + .remove = ds1390_remove, }; module_spi_driver(ds1390_driver); diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 1f675f5294f5..6a3fcfe3b0e7 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -476,8 +476,7 @@ static struct bin_attribute ds1511_nvram_attr = { .write = ds1511_nvram_write, }; - static int __devinit -ds1511_rtc_probe(struct platform_device *pdev) +static int ds1511_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; @@ -551,8 +550,7 @@ ds1511_rtc_probe(struct platform_device *pdev) return ret; } - static int __devexit -ds1511_rtc_remove(struct platform_device *pdev) +static int ds1511_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); @@ -573,7 +571,7 @@ MODULE_ALIAS("platform:ds1511"); static struct platform_driver ds1511_rtc_driver = { .probe = ds1511_rtc_probe, - .remove = __devexit_p(ds1511_rtc_remove), + .remove = ds1511_rtc_remove, .driver = { .name = "ds1511", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 6ccedbbf923c..25ce0621ade9 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -276,7 +276,7 @@ static struct bin_attribute ds1553_nvram_attr = { .write = ds1553_nvram_write, }; -static int __devinit ds1553_rtc_probe(struct platform_device *pdev) +static int ds1553_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; @@ -338,7 +338,7 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) return ret; } -static int __devexit ds1553_rtc_remove(struct platform_device *pdev) +static int ds1553_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); @@ -354,7 +354,7 @@ MODULE_ALIAS("platform:rtc-ds1553"); static struct platform_driver ds1553_rtc_driver = { .probe = ds1553_rtc_probe, - .remove = __devexit_p(ds1553_rtc_remove), + .remove = ds1553_rtc_remove, .driver = { .name = "rtc-ds1553", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 76112667c507..609c870e2cc5 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -159,7 +159,7 @@ static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj, return count; } -static int __devinit ds1742_rtc_probe(struct platform_device *pdev) +static int ds1742_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; @@ -222,7 +222,7 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) return ret; } -static int __devexit ds1742_rtc_remove(struct platform_device *pdev) +static int ds1742_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); @@ -233,7 +233,7 @@ static int __devexit ds1742_rtc_remove(struct platform_device *pdev) static struct platform_driver ds1742_rtc_driver = { .probe = ds1742_rtc_probe, - .remove = __devexit_p(ds1742_rtc_remove), + .remove = ds1742_rtc_remove, .driver = { .name = "rtc-ds1742", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 5ea9df7c8c31..b04fc4272fb3 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -70,7 +70,7 @@ static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev, for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) { err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name); if (err) { - printk(KERN_ERR "error mapping gpio %s: %d\n", + dev_err(&pdev->dev, "error mapping gpio %s: %d\n", ds2404_gpio[i].name, err); goto err_request; } @@ -177,7 +177,7 @@ static void ds2404_write_memory(struct device *dev, u16 offset, for (i = 0; i < length; i++) { if (out[i] != ds2404_read_byte(dev)) { - printk(KERN_ERR "read invalid data\n"); + dev_err(dev, "read invalid data\n"); return; } } @@ -283,19 +283,7 @@ static struct platform_driver rtc_device_driver = { .owner = THIS_MODULE, }, }; - -static __init int ds2404_init(void) -{ - return platform_driver_register(&rtc_device_driver); -} - -static __exit void ds2404_exit(void) -{ - platform_driver_unregister(&rtc_device_driver); -} - -module_init(ds2404_init); -module_exit(ds2404_exit); +module_platform_driver(rtc_device_driver); MODULE_DESCRIPTION("DS2404 RTC"); MODULE_AUTHOR("Sven Schnelle"); diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index e1945095814e..db0ca08db315 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -391,8 +391,8 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .alarm_irq_enable = ds3232_alarm_irq_enable, }; -static int __devinit ds3232_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds3232_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds3232 *ds3232; int ret; @@ -439,7 +439,7 @@ out_free: return ret; } -static int __devexit ds3232_remove(struct i2c_client *client) +static int ds3232_remove(struct i2c_client *client) { struct ds3232 *ds3232 = i2c_get_clientdata(client); @@ -469,7 +469,7 @@ static struct i2c_driver ds3232_driver = { .owner = THIS_MODULE, }, .probe = ds3232_probe, - .remove = __devexit_p(ds3232_remove), + .remove = ds3232_remove, .id_table = ds3232_id, }; diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c index fda707926f02..7a4495ef1c39 100644 --- a/drivers/rtc/rtc-ds3234.c +++ b/drivers/rtc/rtc-ds3234.c @@ -105,7 +105,7 @@ static const struct rtc_class_ops ds3234_rtc_ops = { .set_time = ds3234_set_time, }; -static int __devinit ds3234_probe(struct spi_device *spi) +static int ds3234_probe(struct spi_device *spi) { struct rtc_device *rtc; unsigned char tmp; @@ -156,7 +156,7 @@ static int __devinit ds3234_probe(struct spi_device *spi) return 0; } -static int __devexit ds3234_remove(struct spi_device *spi) +static int ds3234_remove(struct spi_device *spi) { struct rtc_device *rtc = spi_get_drvdata(spi); @@ -170,7 +170,7 @@ static struct spi_driver ds3234_driver = { .owner = THIS_MODULE, }, .probe = ds3234_probe, - .remove = __devexit_p(ds3234_remove), + .remove = ds3234_remove, }; module_spi_driver(ds3234_driver); diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index c9f890b088da..1a0c37c9152b 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -13,6 +13,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/time.h> @@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft) int ndays = 0; if (eft->year < 1998) { - printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n"); + pr_err("EFI year < 1998, invalid date\n"); return -1; } @@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft) eft->day = wtime->tm_mday; eft->hour = wtime->tm_hour; eft->minute = wtime->tm_min; - eft->second = wtime->tm_sec; + eft->second = wtime->tm_sec; eft->nanosecond = 0; eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0; eft->timezone = EFI_UNSPECIFIED_TIMEZONE; @@ -142,7 +144,7 @@ static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) */ status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft); - printk(KERN_WARNING "write status is %d\n", (int)status); + dev_warn(dev, "write status is %d\n", (int)status); return status == EFI_SUCCESS ? 0 : -EINVAL; } @@ -157,7 +159,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm) if (status != EFI_SUCCESS) { /* should never happen */ - printk(KERN_ERR "efitime: can't read time\n"); + dev_err(dev, "can't read time\n"); return -EINVAL; } diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 9602278ff988..1a4e5e4a70cd 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -127,7 +127,7 @@ static const struct attribute_group ep93xx_rtc_sysfs_files = { .attrs = ep93xx_rtc_attrs, }; -static int __devinit ep93xx_rtc_probe(struct platform_device *pdev) +static int ep93xx_rtc_probe(struct platform_device *pdev) { struct ep93xx_rtc *ep93xx_rtc; struct resource *res; @@ -174,7 +174,7 @@ exit: return err; } -static int __devexit ep93xx_rtc_remove(struct platform_device *pdev) +static int ep93xx_rtc_remove(struct platform_device *pdev) { struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev); @@ -192,7 +192,7 @@ static struct platform_driver ep93xx_rtc_driver = { .owner = THIS_MODULE, }, .probe = ep93xx_rtc_probe, - .remove = __devexit_p(ep93xx_rtc_remove), + .remove = ep93xx_rtc_remove, }; module_platform_driver(ep93xx_rtc_driver); diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index 86b6ecce99f0..bff3cdc5140e 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t) fm3130_rtc_mode(dev, FM3130_MODE_NORMAL); - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x" - "%02x %02x %02x %02x %02x %02x %02x\n", - "read", - fm3130->regs[0], fm3130->regs[1], - fm3130->regs[2], fm3130->regs[3], - fm3130->regs[4], fm3130->regs[5], - fm3130->regs[6], fm3130->regs[7], - fm3130->regs[8], fm3130->regs[9], - fm3130->regs[0xa], fm3130->regs[0xb], - fm3130->regs[0xc], fm3130->regs[0xd], - fm3130->regs[0xe]); + dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs); t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); @@ -175,12 +165,7 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t) tmp = t->tm_year - 100; buf[FM3130_RTC_YEARS] = bin2bcd(tmp); - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x" - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - "write", buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[0xa], buf[0xb], - buf[0xc], buf[0xd], buf[0xe]); + dev_dbg(dev, "%s: %15ph\n", "write", buf); fm3130_rtc_mode(dev, FM3130_MODE_WRITE); @@ -361,8 +346,8 @@ static const struct rtc_class_ops fm3130_rtc_ops = { static struct i2c_driver fm3130_driver; -static int __devinit fm3130_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int fm3130_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct fm3130 *fm3130; int err = -ENODEV; @@ -517,18 +502,8 @@ bad_alarm: bad_clock: if (!fm3130->data_valid || !fm3130->alarm_valid) - dev_dbg(&client->dev, - "%s: %02x %02x %02x %02x %02x %02x %02x %02x" - "%02x %02x %02x %02x %02x %02x %02x\n", - "bogus registers", - fm3130->regs[0], fm3130->regs[1], - fm3130->regs[2], fm3130->regs[3], - fm3130->regs[4], fm3130->regs[5], - fm3130->regs[6], fm3130->regs[7], - fm3130->regs[8], fm3130->regs[9], - fm3130->regs[0xa], fm3130->regs[0xb], - fm3130->regs[0xc], fm3130->regs[0xd], - fm3130->regs[0xe]); + dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers", + fm3130->regs); /* We won't bail out here because we just got invalid data. Time setting from u-boot doesn't work anyway */ @@ -546,7 +521,7 @@ exit_free: return err; } -static int __devexit fm3130_remove(struct i2c_client *client) +static int fm3130_remove(struct i2c_client *client) { struct fm3130 *fm3130 = i2c_get_clientdata(client); @@ -561,7 +536,7 @@ static struct i2c_driver fm3130_driver = { .owner = THIS_MODULE, }, .probe = fm3130_probe, - .remove = __devexit_p(fm3130_remove), + .remove = fm3130_remove, .id_table = fm3130_id, }; diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c new file mode 100644 index 000000000000..31c5728ef629 --- /dev/null +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -0,0 +1,292 @@ +/* + * HID Sensor Time Driver + * Copyright (c) 2012, Alexander Holler. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/hid-sensor-hub.h> +#include <linux/iio/iio.h> +#include <linux/rtc.h> + +/* Format: HID-SENSOR-usage_id_in_hex */ +/* Usage ID from spec for Time: 0x2000A0 */ +#define DRIVER_NAME "HID-SENSOR-2000a0" /* must be lowercase */ + +enum hid_time_channel { + CHANNEL_SCAN_INDEX_YEAR, + CHANNEL_SCAN_INDEX_MONTH, + CHANNEL_SCAN_INDEX_DAY, + CHANNEL_SCAN_INDEX_HOUR, + CHANNEL_SCAN_INDEX_MINUTE, + CHANNEL_SCAN_INDEX_SECOND, + TIME_RTC_CHANNEL_MAX, +}; + +struct hid_time_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_common common_attributes; + struct hid_sensor_hub_attribute_info info[TIME_RTC_CHANNEL_MAX]; + struct rtc_time last_time; + spinlock_t lock_last_time; + struct completion comp_last_time; + struct rtc_time time_buf; + struct rtc_device *rtc; +}; + +static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = { + HID_USAGE_SENSOR_TIME_YEAR, + HID_USAGE_SENSOR_TIME_MONTH, + HID_USAGE_SENSOR_TIME_DAY, + HID_USAGE_SENSOR_TIME_HOUR, + HID_USAGE_SENSOR_TIME_MINUTE, + HID_USAGE_SENSOR_TIME_SECOND, +}; + +/* Channel names for verbose error messages */ +static const char * const hid_time_channel_names[TIME_RTC_CHANNEL_MAX] = { + "year", "month", "day", "hour", "minute", "second", +}; + +/* Callback handler to send event after all samples are received and captured */ +static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, void *priv) +{ + unsigned long flags; + struct hid_time_state *time_state = platform_get_drvdata(priv); + + spin_lock_irqsave(&time_state->lock_last_time, flags); + time_state->last_time = time_state->time_buf; + spin_unlock_irqrestore(&time_state->lock_last_time, flags); + complete(&time_state->comp_last_time); + return 0; +} + +static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, size_t raw_len, + char *raw_data, void *priv) +{ + struct hid_time_state *time_state = platform_get_drvdata(priv); + struct rtc_time *time_buf = &time_state->time_buf; + + switch (usage_id) { + case HID_USAGE_SENSOR_TIME_YEAR: + time_buf->tm_year = *(u8 *)raw_data; + if (time_buf->tm_year < 70) + /* assume we are in 1970...2069 */ + time_buf->tm_year += 100; + break; + case HID_USAGE_SENSOR_TIME_MONTH: + /* sensor sending the month as 1-12, we need 0-11 */ + time_buf->tm_mon = *(u8 *)raw_data-1; + break; + case HID_USAGE_SENSOR_TIME_DAY: + time_buf->tm_mday = *(u8 *)raw_data; + break; + case HID_USAGE_SENSOR_TIME_HOUR: + time_buf->tm_hour = *(u8 *)raw_data; + break; + case HID_USAGE_SENSOR_TIME_MINUTE: + time_buf->tm_min = *(u8 *)raw_data; + break; + case HID_USAGE_SENSOR_TIME_SECOND: + time_buf->tm_sec = *(u8 *)raw_data; + break; + default: + return -EINVAL; + } + return 0; +} + +/* small helper, haven't found any other way */ +static const char *hid_time_attrib_name(u32 attrib_id) +{ + static const char unknown[] = "unknown"; + unsigned i; + + for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) { + if (hid_time_addresses[i] == attrib_id) + return hid_time_channel_names[i]; + } + return unknown; /* should never happen */ +} + +static int hid_time_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + struct hid_time_state *time_state) +{ + int report_id, i; + + for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) + if (sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, usage_id, + hid_time_addresses[i], + &time_state->info[i]) < 0) + return -EINVAL; + /* Check the (needed) attributes for sanity */ + report_id = time_state->info[0].report_id; + if (report_id < 0) { + dev_err(&pdev->dev, "bad report ID!\n"); + return -EINVAL; + } + for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) { + if (time_state->info[i].report_id != report_id) { + dev_err(&pdev->dev, + "not all needed attributes inside the same report!\n"); + return -EINVAL; + } + if (time_state->info[i].size != 1) { + dev_err(&pdev->dev, + "attribute '%s' not 8 bits wide!\n", + hid_time_attrib_name( + time_state->info[i].attrib_id)); + return -EINVAL; + } + if (time_state->info[i].units != + HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED && + /* allow attribute seconds with unit seconds */ + !(time_state->info[i].attrib_id == + HID_USAGE_SENSOR_TIME_SECOND && + time_state->info[i].units == + HID_USAGE_SENSOR_UNITS_SECOND)) { + dev_err(&pdev->dev, + "attribute '%s' hasn't a unit of type 'none'!\n", + hid_time_attrib_name( + time_state->info[i].attrib_id)); + return -EINVAL; + } + if (time_state->info[i].unit_expo) { + dev_err(&pdev->dev, + "attribute '%s' hasn't a unit exponent of 1!\n", + hid_time_attrib_name( + time_state->info[i].attrib_id)); + return -EINVAL; + } + } + + return 0; +} + +static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long flags; + struct hid_time_state *time_state = + platform_get_drvdata(to_platform_device(dev)); + int ret; + + INIT_COMPLETION(time_state->comp_last_time); + /* get a report with all values through requesting one value */ + sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev, + HID_USAGE_SENSOR_TIME, hid_time_addresses[0], + time_state->info[0].report_id); + /* wait for all values (event) */ + ret = wait_for_completion_killable_timeout( + &time_state->comp_last_time, HZ*6); + if (ret > 0) { + /* no error */ + spin_lock_irqsave(&time_state->lock_last_time, flags); + *tm = time_state->last_time; + spin_unlock_irqrestore(&time_state->lock_last_time, flags); + return 0; + } + if (!ret) + return -EIO; /* timeouted */ + return ret; /* killed (-ERESTARTSYS) */ +} + +static const struct rtc_class_ops hid_time_rtc_ops = { + .read_time = hid_rtc_read_time, +}; + +static int hid_time_probe(struct platform_device *pdev) +{ + int ret = 0; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_time_state *time_state = devm_kzalloc(&pdev->dev, + sizeof(struct hid_time_state), GFP_KERNEL); + + if (time_state == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, time_state); + + spin_lock_init(&time_state->lock_last_time); + init_completion(&time_state->comp_last_time); + time_state->common_attributes.hsdev = hsdev; + time_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_TIME, + &time_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes!\n"); + return ret; + } + + ret = hid_time_parse_report(pdev, hsdev, HID_USAGE_SENSOR_TIME, + time_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes!\n"); + return ret; + } + + time_state->callbacks.send_event = hid_time_proc_event; + time_state->callbacks.capture_sample = hid_time_capture_sample; + time_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_TIME, + &time_state->callbacks); + if (ret < 0) { + dev_err(&pdev->dev, "register callback failed!\n"); + return ret; + } + + time_state->rtc = rtc_device_register("hid-sensor-time", + &pdev->dev, &hid_time_rtc_ops, THIS_MODULE); + + if (IS_ERR(time_state->rtc)) { + dev_err(&pdev->dev, "rtc device register failed!\n"); + return PTR_ERR(time_state->rtc); + } + + return ret; +} + +static int hid_time_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_time_state *time_state = platform_get_drvdata(pdev); + + rtc_device_unregister(time_state->rtc); + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); + + return 0; +} + +static struct platform_driver hid_time_platform_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = hid_time_probe, + .remove = hid_time_remove, +}; +module_platform_driver(hid_time_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Time"); +MODULE_AUTHOR("Alexander Holler <holler@ahsoftware.de>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 4eed51044c5d..82aad695979e 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -36,7 +36,9 @@ #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/sched.h> +#include <linux/spinlock.h> #include <linux/workqueue.h> +#include <linux/of.h> /* DryIce Register Definitions */ @@ -404,7 +406,7 @@ static int dryice_rtc_probe(struct platform_device *pdev) mutex_init(&imxdi->write_mutex); - imxdi->clk = clk_get(&pdev->dev, NULL); + imxdi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(imxdi->clk)) return PTR_ERR(imxdi->clk); clk_prepare_enable(imxdi->clk); @@ -473,12 +475,11 @@ static int dryice_rtc_probe(struct platform_device *pdev) err: clk_disable_unprepare(imxdi->clk); - clk_put(imxdi->clk); return rc; } -static int __devexit dryice_rtc_remove(struct platform_device *pdev) +static int dryice_rtc_remove(struct platform_device *pdev) { struct imxdi_dev *imxdi = platform_get_drvdata(pdev); @@ -490,17 +491,26 @@ static int __devexit dryice_rtc_remove(struct platform_device *pdev) rtc_device_unregister(imxdi->rtc); clk_disable_unprepare(imxdi->clk); - clk_put(imxdi->clk); return 0; } +#ifdef CONFIG_OF +static const struct of_device_id dryice_dt_ids[] = { + { .compatible = "fsl,imx25-rtc" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, dryice_dt_ids); +#endif + static struct platform_driver dryice_rtc_driver = { .driver = { .name = "imxdi_rtc", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(dryice_dt_ids), }, - .remove = __devexit_p(dryice_rtc_remove), + .remove = dryice_rtc_remove, }; static int __init dryice_rtc_init(void) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 1850104705c0..6b4298ea683d 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -227,7 +227,7 @@ static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[ISL12022_REG_SC + i]); if (ret) return -EIO; - }; + } return 0; } diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 26c81f233606..c016ad81767a 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -118,7 +118,7 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], return ret; } -/* simple check to see wether we have a isl1208 */ +/* simple check to see whether we have a isl1208 */ static int isl1208_i2c_validate_client(struct i2c_client *client) { @@ -506,6 +506,7 @@ isl1208_rtc_interrupt(int irq, void *data) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); struct i2c_client *client = data; + struct rtc_device *rtc = i2c_get_clientdata(client); int handled = 0, sr, err; /* @@ -528,6 +529,8 @@ isl1208_rtc_interrupt(int irq, void *data) if (sr & ISL1208_REG_SR_ALM) { dev_dbg(&client->dev, "alarm!\n"); + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); + /* Clear the alarm */ sr &= ~ISL1208_REG_SR_ALM; sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 1224182d3eab..1e48686ca6d2 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -210,7 +210,7 @@ void jz4740_rtc_poweroff(struct device *dev) } EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff); -static int __devinit jz4740_rtc_probe(struct platform_device *pdev) +static int jz4740_rtc_probe(struct platform_device *pdev) { int ret; struct jz4740_rtc *rtc; @@ -297,7 +297,7 @@ err_free: return ret; } -static int __devexit jz4740_rtc_remove(struct platform_device *pdev) +static int jz4740_rtc_remove(struct platform_device *pdev) { struct jz4740_rtc *rtc = platform_get_drvdata(pdev); @@ -347,7 +347,7 @@ static const struct dev_pm_ops jz4740_pm_ops = { static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, - .remove = __devexit_p(jz4740_rtc_remove), + .remove = jz4740_rtc_remove, .driver = { .name = "jz4740-rtc", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c new file mode 100644 index 000000000000..9a4631218f41 --- /dev/null +++ b/drivers/rtc/rtc-lp8788.c @@ -0,0 +1,338 @@ +/* + * TI LP8788 MFD - rtc driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/err.h> +#include <linux/irqdomain.h> +#include <linux/mfd/lp8788.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/slab.h> + +/* register address */ +#define LP8788_INTEN_3 0x05 +#define LP8788_RTC_UNLOCK 0x64 +#define LP8788_RTC_SEC 0x70 +#define LP8788_ALM1_SEC 0x77 +#define LP8788_ALM1_EN 0x7D +#define LP8788_ALM2_SEC 0x7E +#define LP8788_ALM2_EN 0x84 + +/* mask/shift bits */ +#define LP8788_INT_RTC_ALM1_M BIT(1) /* Addr 05h */ +#define LP8788_INT_RTC_ALM1_S 1 +#define LP8788_INT_RTC_ALM2_M BIT(2) /* Addr 05h */ +#define LP8788_INT_RTC_ALM2_S 2 +#define LP8788_ALM_EN_M BIT(7) /* Addr 7Dh or 84h */ +#define LP8788_ALM_EN_S 7 + +#define DEFAULT_ALARM_SEL LP8788_ALARM_1 +#define LP8788_MONTH_OFFSET 1 +#define LP8788_BASE_YEAR 2000 +#define MAX_WDAY_BITS 7 +#define LP8788_WDAY_SET 1 +#define RTC_UNLOCK 0x1 +#define RTC_LATCH 0x2 +#define ALARM_IRQ_FLAG (RTC_IRQF | RTC_AF) + +enum lp8788_time { + LPTIME_SEC, + LPTIME_MIN, + LPTIME_HOUR, + LPTIME_MDAY, + LPTIME_MON, + LPTIME_YEAR, + LPTIME_WDAY, + LPTIME_MAX, +}; + +struct lp8788_rtc { + struct lp8788 *lp; + struct rtc_device *rdev; + enum lp8788_alarm_sel alarm; + int irq; +}; + +static const u8 addr_alarm_sec[LP8788_ALARM_MAX] = { + LP8788_ALM1_SEC, + LP8788_ALM2_SEC, +}; + +static const u8 addr_alarm_en[LP8788_ALARM_MAX] = { + LP8788_ALM1_EN, + LP8788_ALM2_EN, +}; + +static const u8 mask_alarm_en[LP8788_ALARM_MAX] = { + LP8788_INT_RTC_ALM1_M, + LP8788_INT_RTC_ALM2_M, +}; + +static const u8 shift_alarm_en[LP8788_ALARM_MAX] = { + LP8788_INT_RTC_ALM1_S, + LP8788_INT_RTC_ALM2_S, +}; + +static int _to_tm_wday(u8 lp8788_wday) +{ + int i; + + if (lp8788_wday == 0) + return 0; + + /* lookup defined weekday from read register value */ + for (i = 0; i < MAX_WDAY_BITS; i++) { + if ((lp8788_wday >> i) == LP8788_WDAY_SET) + break; + } + + return i + 1; +} + +static inline int _to_lp8788_wday(int tm_wday) +{ + return LP8788_WDAY_SET << (tm_wday - 1); +} + +static void lp8788_rtc_unlock(struct lp8788 *lp) +{ + lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_UNLOCK); + lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_LATCH); +} + +static int lp8788_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + u8 data[LPTIME_MAX]; + int ret; + + lp8788_rtc_unlock(lp); + + ret = lp8788_read_multi_bytes(lp, LP8788_RTC_SEC, data, LPTIME_MAX); + if (ret) + return ret; + + tm->tm_sec = data[LPTIME_SEC]; + tm->tm_min = data[LPTIME_MIN]; + tm->tm_hour = data[LPTIME_HOUR]; + tm->tm_mday = data[LPTIME_MDAY]; + tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET; + tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900; + tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]); + + return 0; +} + +static int lp8788_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + u8 data[LPTIME_MAX - 1]; + int ret, i, year; + + year = tm->tm_year + 1900 - LP8788_BASE_YEAR; + if (year < 0) { + dev_err(lp->dev, "invalid year: %d\n", year); + return -EINVAL; + } + + /* because rtc weekday is a readonly register, do not update */ + data[LPTIME_SEC] = tm->tm_sec; + data[LPTIME_MIN] = tm->tm_min; + data[LPTIME_HOUR] = tm->tm_hour; + data[LPTIME_MDAY] = tm->tm_mday; + data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET; + data[LPTIME_YEAR] = year; + + for (i = 0; i < ARRAY_SIZE(data); i++) { + ret = lp8788_write_byte(lp, LP8788_RTC_SEC + i, data[i]); + if (ret) + return ret; + } + + return 0; +} + +static int lp8788_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + struct rtc_time *tm = &alarm->time; + u8 addr, data[LPTIME_MAX]; + int ret; + + addr = addr_alarm_sec[rtc->alarm]; + ret = lp8788_read_multi_bytes(lp, addr, data, LPTIME_MAX); + if (ret) + return ret; + + tm->tm_sec = data[LPTIME_SEC]; + tm->tm_min = data[LPTIME_MIN]; + tm->tm_hour = data[LPTIME_HOUR]; + tm->tm_mday = data[LPTIME_MDAY]; + tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET; + tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900; + tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]); + alarm->enabled = data[LPTIME_WDAY] & LP8788_ALM_EN_M; + + return 0; +} + +static int lp8788_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + struct rtc_time *tm = &alarm->time; + u8 addr, data[LPTIME_MAX]; + int ret, i, year; + + year = tm->tm_year + 1900 - LP8788_BASE_YEAR; + if (year < 0) { + dev_err(lp->dev, "invalid year: %d\n", year); + return -EINVAL; + } + + data[LPTIME_SEC] = tm->tm_sec; + data[LPTIME_MIN] = tm->tm_min; + data[LPTIME_HOUR] = tm->tm_hour; + data[LPTIME_MDAY] = tm->tm_mday; + data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET; + data[LPTIME_YEAR] = year; + data[LPTIME_WDAY] = _to_lp8788_wday(tm->tm_wday); + + for (i = 0; i < ARRAY_SIZE(data); i++) { + addr = addr_alarm_sec[rtc->alarm] + i; + ret = lp8788_write_byte(lp, addr, data[i]); + if (ret) + return ret; + } + + alarm->enabled = 1; + addr = addr_alarm_en[rtc->alarm]; + + return lp8788_update_bits(lp, addr, LP8788_ALM_EN_M, + alarm->enabled << LP8788_ALM_EN_S); +} + +static int lp8788_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct lp8788_rtc *rtc = dev_get_drvdata(dev); + struct lp8788 *lp = rtc->lp; + u8 mask, shift; + + if (!rtc->irq) + return -EIO; + + mask = mask_alarm_en[rtc->alarm]; + shift = shift_alarm_en[rtc->alarm]; + + return lp8788_update_bits(lp, LP8788_INTEN_3, mask, enable << shift); +} + +static const struct rtc_class_ops lp8788_rtc_ops = { + .read_time = lp8788_rtc_read_time, + .set_time = lp8788_rtc_set_time, + .read_alarm = lp8788_read_alarm, + .set_alarm = lp8788_set_alarm, + .alarm_irq_enable = lp8788_alarm_irq_enable, +}; + +static irqreturn_t lp8788_alarm_irq_handler(int irq, void *ptr) +{ + struct lp8788_rtc *rtc = ptr; + + rtc_update_irq(rtc->rdev, 1, ALARM_IRQ_FLAG); + return IRQ_HANDLED; +} + +static int lp8788_alarm_irq_register(struct platform_device *pdev, + struct lp8788_rtc *rtc) +{ + struct resource *r; + struct lp8788 *lp = rtc->lp; + struct irq_domain *irqdm = lp->irqdm; + int irq; + + rtc->irq = 0; + + /* even the alarm IRQ number is not specified, rtc time should work */ + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, LP8788_ALM_IRQ); + if (!r) + return 0; + + if (rtc->alarm == LP8788_ALARM_1) + irq = r->start; + else + irq = r->end; + + rtc->irq = irq_create_mapping(irqdm, irq); + + return devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + lp8788_alarm_irq_handler, + 0, LP8788_ALM_IRQ, rtc); +} + +static int lp8788_rtc_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + struct lp8788_rtc *rtc; + struct device *dev = &pdev->dev; + + rtc = devm_kzalloc(dev, sizeof(struct lp8788_rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->lp = lp; + rtc->alarm = lp->pdata ? lp->pdata->alarm_sel : DEFAULT_ALARM_SEL; + platform_set_drvdata(pdev, rtc); + + device_init_wakeup(dev, 1); + + rtc->rdev = rtc_device_register("lp8788_rtc", dev, + &lp8788_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rdev)) { + dev_err(dev, "can not register rtc device\n"); + return PTR_ERR(rtc->rdev); + } + + if (lp8788_alarm_irq_register(pdev, rtc)) + dev_warn(lp->dev, "no rtc irq handler\n"); + + return 0; +} + +static int lp8788_rtc_remove(struct platform_device *pdev) +{ + struct lp8788_rtc *rtc = platform_get_drvdata(pdev); + + rtc_device_unregister(rtc->rdev); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver lp8788_rtc_driver = { + .probe = lp8788_rtc_probe, + .remove = lp8788_rtc_remove, + .driver = { + .name = LP8788_DEV_RTC, + .owner = THIS_MODULE, + }, +}; +module_platform_driver(lp8788_rtc_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8788 RTC Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-rtc"); diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index d5218553741f..40a598332bac 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -197,7 +197,7 @@ static const struct rtc_class_ops lpc32xx_rtc_ops = { .alarm_irq_enable = lpc32xx_rtc_alarm_irq_enable, }; -static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev) +static int lpc32xx_rtc_probe(struct platform_device *pdev) { struct resource *res; struct lpc32xx_rtc *rtc; @@ -299,7 +299,7 @@ static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev) +static int lpc32xx_rtc_remove(struct platform_device *pdev) { struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev); @@ -397,7 +397,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match); static struct platform_driver lpc32xx_rtc_driver = { .probe = lpc32xx_rtc_probe, - .remove = __devexit_p(lpc32xx_rtc_remove), + .remove = lpc32xx_rtc_remove, .driver = { .name = RTC_NAME, .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c index 07e81c5f8247..f59b6349551a 100644 --- a/drivers/rtc/rtc-ls1x.c +++ b/drivers/rtc/rtc-ls1x.c @@ -143,7 +143,7 @@ static struct rtc_class_ops ls1x_rtc_ops = { .set_time = ls1x_rtc_set_time, }; -static int __devinit ls1x_rtc_probe(struct platform_device *pdev) +static int ls1x_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtcdev; unsigned long v; @@ -185,7 +185,7 @@ err: return ret; } -static int __devexit ls1x_rtc_remove(struct platform_device *pdev) +static int ls1x_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtcdev = platform_get_drvdata(pdev); @@ -200,7 +200,7 @@ static struct platform_driver ls1x_rtc_driver = { .name = "ls1x-rtc", .owner = THIS_MODULE, }, - .remove = __devexit_p(ls1x_rtc_remove), + .remove = ls1x_rtc_remove, .probe = ls1x_rtc_probe, }; diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c index efab3d48cb15..49169680786e 100644 --- a/drivers/rtc/rtc-m41t93.c +++ b/drivers/rtc/rtc-m41t93.c @@ -170,7 +170,7 @@ static const struct rtc_class_ops m41t93_rtc_ops = { static struct spi_driver m41t93_driver; -static int __devinit m41t93_probe(struct spi_device *spi) +static int m41t93_probe(struct spi_device *spi) { struct rtc_device *rtc; int res; @@ -195,7 +195,7 @@ static int __devinit m41t93_probe(struct spi_device *spi) } -static int __devexit m41t93_remove(struct spi_device *spi) +static int m41t93_remove(struct spi_device *spi) { struct rtc_device *rtc = spi_get_drvdata(spi); @@ -211,7 +211,7 @@ static struct spi_driver m41t93_driver = { .owner = THIS_MODULE, }, .probe = m41t93_probe, - .remove = __devexit_p(m41t93_remove), + .remove = m41t93_remove, }; module_spi_driver(m41t93_driver); diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c index 6e78193e026b..89266c6764bc 100644 --- a/drivers/rtc/rtc-m41t94.c +++ b/drivers/rtc/rtc-m41t94.c @@ -110,7 +110,7 @@ static const struct rtc_class_ops m41t94_rtc_ops = { static struct spi_driver m41t94_driver; -static int __devinit m41t94_probe(struct spi_device *spi) +static int m41t94_probe(struct spi_device *spi) { struct rtc_device *rtc; int res; @@ -134,7 +134,7 @@ static int __devinit m41t94_probe(struct spi_device *spi) return 0; } -static int __devexit m41t94_remove(struct spi_device *spi) +static int m41t94_remove(struct spi_device *spi) { struct rtc_device *rtc = spi_get_drvdata(spi); @@ -150,7 +150,7 @@ static struct spi_driver m41t94_driver = { .owner = THIS_MODULE, }, .probe = m41t94_probe, - .remove = __devexit_p(m41t94_remove), + .remove = m41t94_remove, }; module_spi_driver(m41t94_driver); diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index f9e3b3583733..31c9190a1fcb 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -141,7 +141,7 @@ static const struct rtc_class_ops m48t35_ops = { .set_time = m48t35_set_time, }; -static int __devinit m48t35_probe(struct platform_device *pdev) +static int m48t35_probe(struct platform_device *pdev) { struct resource *res; struct m48t35_priv *priv; @@ -194,7 +194,7 @@ out: return ret; } -static int __devexit m48t35_remove(struct platform_device *pdev) +static int m48t35_remove(struct platform_device *pdev) { struct m48t35_priv *priv = platform_get_drvdata(pdev); @@ -213,7 +213,7 @@ static struct platform_driver m48t35_platform_driver = { .owner = THIS_MODULE, }, .probe = m48t35_probe, - .remove = __devexit_p(m48t35_remove), + .remove = m48t35_remove, }; module_platform_driver(m48t35_platform_driver); diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 30ebfec9fd2b..130f29af3869 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -383,7 +383,7 @@ static struct bin_attribute m48t59_nvram_attr = { .write = m48t59_nvram_write, }; -static int __devinit m48t59_rtc_probe(struct platform_device *pdev) +static int m48t59_rtc_probe(struct platform_device *pdev) { struct m48t59_plat_data *pdata = pdev->dev.platform_data; struct m48t59_private *m48t59 = NULL; @@ -501,7 +501,7 @@ out: return ret; } -static int __devexit m48t59_rtc_remove(struct platform_device *pdev) +static int m48t59_rtc_remove(struct platform_device *pdev) { struct m48t59_private *m48t59 = platform_get_drvdata(pdev); struct m48t59_plat_data *pdata = pdev->dev.platform_data; @@ -527,7 +527,7 @@ static struct platform_driver m48t59_rtc_driver = { .owner = THIS_MODULE, }, .probe = m48t59_rtc_probe, - .remove = __devexit_p(m48t59_rtc_remove), + .remove = m48t59_rtc_remove, }; module_platform_driver(m48t59_rtc_driver); diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 863fb3363aa6..2ffbcacd2439 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -144,7 +144,7 @@ static const struct rtc_class_ops m48t86_rtc_ops = { .proc = m48t86_rtc_proc, }; -static int __devinit m48t86_rtc_probe(struct platform_device *dev) +static int m48t86_rtc_probe(struct platform_device *dev) { unsigned char reg; struct m48t86_ops *ops = dev->dev.platform_data; @@ -164,7 +164,7 @@ static int __devinit m48t86_rtc_probe(struct platform_device *dev) return 0; } -static int __devexit m48t86_rtc_remove(struct platform_device *dev) +static int m48t86_rtc_remove(struct platform_device *dev) { struct rtc_device *rtc = platform_get_drvdata(dev); @@ -182,7 +182,7 @@ static struct platform_driver m48t86_rtc_platform_driver = { .owner = THIS_MODULE, }, .probe = m48t86_rtc_probe, - .remove = __devexit_p(m48t86_rtc_remove), + .remove = m48t86_rtc_remove, }; module_platform_driver(m48t86_rtc_platform_driver); diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 36c74d22e8b5..7d0bf698b79e 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -120,7 +120,7 @@ static const struct rtc_class_ops max6902_rtc_ops = { .set_time = max6902_set_time, }; -static int __devinit max6902_probe(struct spi_device *spi) +static int max6902_probe(struct spi_device *spi) { struct rtc_device *rtc; unsigned char tmp; @@ -143,7 +143,7 @@ static int __devinit max6902_probe(struct spi_device *spi) return 0; } -static int __devexit max6902_remove(struct spi_device *spi) +static int max6902_remove(struct spi_device *spi) { struct rtc_device *rtc = dev_get_drvdata(&spi->dev); @@ -157,7 +157,7 @@ static struct spi_driver max6902_driver = { .owner = THIS_MODULE, }, .probe = max6902_probe, - .remove = __devexit_p(max6902_remove), + .remove = max6902_remove, }; module_spi_driver(max6902_driver); diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c new file mode 100644 index 000000000000..6b1337f9baf4 --- /dev/null +++ b/drivers/rtc/rtc-max77686.c @@ -0,0 +1,641 @@ +/* + * RTC driver for Maxim MAX77686 + * + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * + * based on rtc-max8997.c + * + * 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 <linux/slab.h> +#include <linux/rtc.h> +#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/max77686-private.h> +#include <linux/irqdomain.h> +#include <linux/regmap.h> + +/* RTC Control Register */ +#define BCD_EN_SHIFT 0 +#define BCD_EN_MASK (1 << BCD_EN_SHIFT) +#define MODEL24_SHIFT 1 +#define MODEL24_MASK (1 << MODEL24_SHIFT) +/* RTC Update Register1 */ +#define RTC_UDR_SHIFT 0 +#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +#define RTC_RBUDR_SHIFT 4 +#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) +/* WTSR and SMPL Register */ +#define WTSRT_SHIFT 0 +#define SMPLT_SHIFT 2 +#define WTSR_EN_SHIFT 6 +#define SMPL_EN_SHIFT 7 +#define WTSRT_MASK (3 << WTSRT_SHIFT) +#define SMPLT_MASK (3 << SMPLT_SHIFT) +#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT) +#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT) +/* RTC Hour register */ +#define HOUR_PM_SHIFT 6 +#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) +/* RTC Alarm Enable */ +#define ALARM_ENABLE_SHIFT 7 +#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) + +#define MAX77686_RTC_UPDATE_DELAY 16 +#undef MAX77686_RTC_WTSR_SMPL + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_MONTH, + RTC_YEAR, + RTC_DATE, + RTC_NR_TIME +}; + +struct max77686_rtc_info { + struct device *dev; + struct max77686_dev *max77686; + struct i2c_client *rtc; + struct rtc_device *rtc_dev; + struct mutex lock; + + struct regmap *regmap; + + int virq; + int rtc_24hr_mode; +}; + +enum MAX77686_RTC_OP { + MAX77686_RTC_WRITE, + MAX77686_RTC_READ, +}; + +static inline int max77686_rtc_calculate_wday(u8 shifted) +{ + int counter = -1; + while (shifted) { + shifted >>= 1; + counter++; + } + return counter; +} + +static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, + int rtc_24hr_mode) +{ + tm->tm_sec = data[RTC_SEC] & 0x7f; + tm->tm_min = data[RTC_MIN] & 0x7f; + if (rtc_24hr_mode) + tm->tm_hour = data[RTC_HOUR] & 0x1f; + else { + tm->tm_hour = data[RTC_HOUR] & 0x0f; + if (data[RTC_HOUR] & HOUR_PM_MASK) + tm->tm_hour += 12; + } + + tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f); + tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; + tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; + tm->tm_yday = 0; + tm->tm_isdst = 0; +} + +static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = tm->tm_sec; + data[RTC_MIN] = tm->tm_min; + data[RTC_HOUR] = tm->tm_hour; + data[RTC_WEEKDAY] = 1 << tm->tm_wday; + data[RTC_DATE] = tm->tm_mday; + data[RTC_MONTH] = tm->tm_mon + 1; + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ; + + if (tm->tm_year < 100) { + pr_warn("%s: MAX77686 RTC cannot handle the year %d." + "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); + return -EINVAL; + } + return 0; +} + +static int max77686_rtc_update(struct max77686_rtc_info *info, + enum MAX77686_RTC_OP op) +{ + int ret; + unsigned int data; + + if (op == MAX77686_RTC_WRITE) + data = 1 << RTC_UDR_SHIFT; + else + data = 1 << RTC_RBUDR_SHIFT; + + ret = regmap_update_bits(info->max77686->rtc_regmap, + MAX77686_RTC_UPDATE0, data, data); + if (ret < 0) + dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", + __func__, ret, data); + else { + /* Minimum 16ms delay required before RTC update. */ + msleep(MAX77686_RTC_UPDATE_DELAY); + } + + return ret; +} + +static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + mutex_lock(&info->lock); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_RTC_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); + + ret = rtc_valid_tm(tm); + +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max77686_rtc_tm_to_data(tm, data); + if (ret < 0) + return ret; + + mutex_lock(&info->lock); + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_RTC_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, + ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); + +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + unsigned int val; + int i, ret; + + mutex_lock(&info->lock); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + + alrm->enabled = 0; + for (i = 0; i < RTC_NR_TIME; i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } + } + + alrm->pending = 0; + ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS1, &val); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + if (val & (1 << 4)) /* RTCA1 */ + alrm->pending = 1; + +out: + mutex_unlock(&info->lock); + return 0; +} + +static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret, i; + struct rtc_time tm; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); + + for (i = 0; i < RTC_NR_TIME; i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); +out: + return ret; +} + +static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret; + struct rtc_time tm; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max77686_rtc_update(info, MAX77686_RTC_READ); + if (ret < 0) + goto out; + + ret = regmap_bulk_read(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); + + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_YEAR] & 0x7f) + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); +out: + return ret; +} + +static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max77686_rtc_tm_to_data(&alrm->time, data); + if (ret < 0) + return ret; + + mutex_lock(&info->lock); + + ret = max77686_rtc_stop_alarm(info); + if (ret < 0) + goto out; + + ret = regmap_bulk_write(info->max77686->rtc_regmap, + MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); + if (ret < 0) + goto out; + + if (alrm->enabled) + ret = max77686_rtc_start_alarm(info); +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max77686_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct max77686_rtc_info *info = dev_get_drvdata(dev); + int ret; + + mutex_lock(&info->lock); + if (enabled) + ret = max77686_rtc_start_alarm(info); + else + ret = max77686_rtc_stop_alarm(info); + mutex_unlock(&info->lock); + + return ret; +} + +static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data) +{ + struct max77686_rtc_info *info = data; + + dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops max77686_rtc_ops = { + .read_time = max77686_rtc_read_time, + .set_time = max77686_rtc_set_time, + .read_alarm = max77686_rtc_read_alarm, + .set_alarm = max77686_rtc_set_alarm, + .alarm_irq_enable = max77686_rtc_alarm_irq_enable, +}; + +#ifdef MAX77686_RTC_WTSR_SMPL +static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable) +{ + int ret; + unsigned int val, mask; + + if (enable) + val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); + else + val = 0; + + mask = WTSR_EN_MASK | WTSRT_MASK; + + dev_info(info->dev, "%s: %s WTSR\n", __func__, + enable ? "enable" : "disable"); + + ret = regmap_update_bits(info->max77686->rtc_regmap, + MAX77686_WTSR_SMPL_CNTL, mask, val); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", + __func__, ret); + return; + } + + max77686_rtc_update(info, MAX77686_RTC_WRITE); +} + +static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable) +{ + int ret; + unsigned int val, mask; + + if (enable) + val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); + else + val = 0; + + mask = SMPL_EN_MASK | SMPLT_MASK; + + dev_info(info->dev, "%s: %s SMPL\n", __func__, + enable ? "enable" : "disable"); + + ret = regmap_update_bits(info->max77686->rtc_regmap, + MAX77686_WTSR_SMPL_CNTL, mask, val); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", + __func__, ret); + return; + } + + max77686_rtc_update(info, MAX77686_RTC_WRITE); + + val = 0; + regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); + pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); +} +#endif /* MAX77686_RTC_WTSR_SMPL */ + +static int max77686_rtc_init_reg(struct max77686_rtc_info *info) +{ + u8 data[2]; + int ret; + + /* Set RTC control register : Binary mode, 24hour mdoe */ + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + + info->rtc_24hr_mode = 1; + + ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", + __func__, ret); + return ret; + } + + ret = max77686_rtc_update(info, MAX77686_RTC_WRITE); + return ret; +} + +static struct regmap_config max77686_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int max77686_rtc_probe(struct platform_device *pdev) +{ + struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); + struct max77686_rtc_info *info; + int ret, virq; + + dev_info(&pdev->dev, "%s\n", __func__); + + info = kzalloc(sizeof(struct max77686_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + mutex_init(&info->lock); + info->dev = &pdev->dev; + info->max77686 = max77686; + info->rtc = max77686->rtc; + info->max77686->rtc_regmap = regmap_init_i2c(info->max77686->rtc, + &max77686_rtc_regmap_config); + if (IS_ERR(info->max77686->rtc_regmap)) { + ret = PTR_ERR(info->max77686->rtc_regmap); + dev_err(info->max77686->dev, "Failed to allocate register map: %d\n", + ret); + kfree(info); + return ret; + } + platform_set_drvdata(pdev, info); + + ret = max77686_rtc_init_reg(info); + + if (ret < 0) { + dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); + goto err_rtc; + } + +#ifdef MAX77686_RTC_WTSR_SMPL + max77686_rtc_enable_wtsr(info, true); + max77686_rtc_enable_smpl(info, true); +#endif + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = rtc_device_register("max77686-rtc", &pdev->dev, + &max77686_rtc_ops, THIS_MODULE); + + if (IS_ERR(info->rtc_dev)) { + dev_info(&pdev->dev, "%s: fail\n", __func__); + + ret = PTR_ERR(info->rtc_dev); + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + if (ret == 0) + ret = -EINVAL; + goto err_rtc; + } + virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1); + if (!virq) + goto err_rtc; + info->virq = virq; + + ret = request_threaded_irq(virq, NULL, max77686_rtc_alarm_irq, 0, + "rtc-alarm0", info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->virq, ret); + goto err_rtc; + } + + goto out; +err_rtc: + kfree(info); + return ret; +out: + return ret; +} + +static int max77686_rtc_remove(struct platform_device *pdev) +{ + struct max77686_rtc_info *info = platform_get_drvdata(pdev); + + if (info) { + free_irq(info->virq, info); + rtc_device_unregister(info->rtc_dev); + kfree(info); + } + + return 0; +} + +static void max77686_rtc_shutdown(struct platform_device *pdev) +{ +#ifdef MAX77686_RTC_WTSR_SMPL + struct max77686_rtc_info *info = platform_get_drvdata(pdev); + int i; + u8 val = 0; + + for (i = 0; i < 3; i++) { + max77686_rtc_enable_wtsr(info, false); + regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val); + pr_info("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); + if (val & WTSR_EN_MASK) + pr_emerg("%s: fail to disable WTSR\n", __func__); + else { + pr_info("%s: success to disable WTSR\n", __func__); + break; + } + } + + /* Disable SMPL when power off */ + max77686_rtc_enable_smpl(info, false); +#endif /* MAX77686_RTC_WTSR_SMPL */ +} + +static const struct platform_device_id rtc_id[] = { + { "max77686-rtc", 0 }, + {}, +}; + +static struct platform_driver max77686_rtc_driver = { + .driver = { + .name = "max77686-rtc", + .owner = THIS_MODULE, + }, + .probe = max77686_rtc_probe, + .remove = max77686_rtc_remove, + .shutdown = max77686_rtc_shutdown, + .id_table = rtc_id, +}; + +static int __init max77686_rtc_init(void) +{ + return platform_driver_register(&max77686_rtc_driver); +} +module_init(max77686_rtc_init); + +static void __exit max77686_rtc_exit(void) +{ + platform_driver_unregister(&max77686_rtc_driver); +} +module_exit(max77686_rtc_exit); + +MODULE_DESCRIPTION("Maxim MAX77686 RTC driver"); +MODULE_AUTHOR("<woong.byun@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index e094ffa434f8..31ca8faf9f05 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -176,7 +176,7 @@ static const struct rtc_class_ops max8907_rtc_ops = { .set_alarm = max8907_rtc_set_alarm, }; -static int __devinit max8907_rtc_probe(struct platform_device *pdev) +static int max8907_rtc_probe(struct platform_device *pdev) { struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent); struct max8907_rtc *rtc; @@ -205,8 +205,9 @@ static int __devinit max8907_rtc_probe(struct platform_device *pdev) goto err_unregister; } - ret = request_threaded_irq(rtc->irq, NULL, max8907_irq_handler, - IRQF_ONESHOT, "max8907-alarm0", rtc); + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + max8907_irq_handler, + IRQF_ONESHOT, "max8907-alarm0", rtc); if (ret < 0) { dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n", rtc->irq, ret); @@ -220,11 +221,10 @@ err_unregister: return ret; } -static int __devexit max8907_rtc_remove(struct platform_device *pdev) +static int max8907_rtc_remove(struct platform_device *pdev) { struct max8907_rtc *rtc = platform_get_drvdata(pdev); - free_irq(rtc->irq, rtc); rtc_device_unregister(rtc->rtc_dev); return 0; @@ -236,7 +236,7 @@ static struct platform_driver max8907_rtc_driver = { .owner = THIS_MODULE, }, .probe = max8907_rtc_probe, - .remove = __devexit_p(max8907_rtc_remove), + .remove = max8907_rtc_remove, }; module_platform_driver(max8907_rtc_driver); diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 34e4349611db..a0c8265646d2 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -247,7 +247,7 @@ static const struct rtc_class_ops max8925_rtc_ops = { .set_alarm = max8925_rtc_set_alarm, }; -static int __devinit max8925_rtc_probe(struct platform_device *pdev) +static int max8925_rtc_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct max8925_rtc_info *info; @@ -292,7 +292,7 @@ out_irq: return ret; } -static int __devexit max8925_rtc_remove(struct platform_device *pdev) +static int max8925_rtc_remove(struct platform_device *pdev) { struct max8925_rtc_info *info = platform_get_drvdata(pdev); @@ -334,7 +334,7 @@ static struct platform_driver max8925_rtc_driver = { .pm = &max8925_rtc_pm_ops, }, .probe = max8925_rtc_probe, - .remove = __devexit_p(max8925_rtc_remove), + .remove = max8925_rtc_remove, }; module_platform_driver(max8925_rtc_driver); diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c new file mode 100644 index 000000000000..00e505b6bee3 --- /dev/null +++ b/drivers/rtc/rtc-max8997.c @@ -0,0 +1,552 @@ +/* + * RTC driver for Maxim MAX8997 + * + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * + * based on rtc-max8998.c + * + * 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 <linux/slab.h> +#include <linux/rtc.h> +#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/max8997-private.h> +#include <linux/irqdomain.h> + +/* Module parameter for WTSR function control */ +static int wtsr_en = 1; +module_param(wtsr_en, int, 0444); +MODULE_PARM_DESC(wtsr_en, "Wachdog Timeout & Sofware Reset (default=on)"); +/* Module parameter for SMPL function control */ +static int smpl_en = 1; +module_param(smpl_en, int, 0444); +MODULE_PARM_DESC(smpl_en, "Sudden Momentary Power Loss (default=on)"); + +/* RTC Control Register */ +#define BCD_EN_SHIFT 0 +#define BCD_EN_MASK (1 << BCD_EN_SHIFT) +#define MODEL24_SHIFT 1 +#define MODEL24_MASK (1 << MODEL24_SHIFT) +/* RTC Update Register1 */ +#define RTC_UDR_SHIFT 0 +#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +/* WTSR and SMPL Register */ +#define WTSRT_SHIFT 0 +#define SMPLT_SHIFT 2 +#define WTSR_EN_SHIFT 6 +#define SMPL_EN_SHIFT 7 +#define WTSRT_MASK (3 << WTSRT_SHIFT) +#define SMPLT_MASK (3 << SMPLT_SHIFT) +#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT) +#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT) +/* RTC Hour register */ +#define HOUR_PM_SHIFT 6 +#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) +/* RTC Alarm Enable */ +#define ALARM_ENABLE_SHIFT 7 +#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_MONTH, + RTC_YEAR, + RTC_DATE, + RTC_NR_TIME +}; + +struct max8997_rtc_info { + struct device *dev; + struct max8997_dev *max8997; + struct i2c_client *rtc; + struct rtc_device *rtc_dev; + struct mutex lock; + int virq; + int rtc_24hr_mode; +}; + +static void max8997_rtc_data_to_tm(u8 *data, struct rtc_time *tm, + int rtc_24hr_mode) +{ + tm->tm_sec = data[RTC_SEC] & 0x7f; + tm->tm_min = data[RTC_MIN] & 0x7f; + if (rtc_24hr_mode) + tm->tm_hour = data[RTC_HOUR] & 0x1f; + else { + tm->tm_hour = data[RTC_HOUR] & 0x0f; + if (data[RTC_HOUR] & HOUR_PM_MASK) + tm->tm_hour += 12; + } + + tm->tm_wday = fls(data[RTC_WEEKDAY] & 0x7f) - 1; + tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; + tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; + tm->tm_yday = 0; + tm->tm_isdst = 0; +} + +static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = tm->tm_sec; + data[RTC_MIN] = tm->tm_min; + data[RTC_HOUR] = tm->tm_hour; + data[RTC_WEEKDAY] = 1 << tm->tm_wday; + data[RTC_DATE] = tm->tm_mday; + data[RTC_MONTH] = tm->tm_mon + 1; + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ; + + if (tm->tm_year < 100) { + pr_warn("%s: MAX8997 RTC cannot handle the year %d." + "Assume it's 2000.\n", __func__, 1900 + tm->tm_year); + return -EINVAL; + } + return 0; +} + +static inline int max8997_rtc_set_update_reg(struct max8997_rtc_info *info) +{ + int ret; + + ret = max8997_write_reg(info->rtc, MAX8997_RTC_UPDATE1, + RTC_UDR_MASK); + if (ret < 0) + dev_err(info->dev, "%s: fail to write update reg(%d)\n", + __func__, ret); + else { + /* Minimum 16ms delay required before RTC update. + * Otherwise, we may read and update based on out-of-date + * value */ + msleep(20); + } + + return ret; +} + +static int max8997_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + mutex_lock(&info->lock); + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data); + mutex_unlock(&info->lock); + + if (ret < 0) { + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, + ret); + return ret; + } + + max8997_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); + + return rtc_valid_tm(tm); +} + +static int max8997_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max8997_rtc_tm_to_data(tm, data); + if (ret < 0) + return ret; + + mutex_lock(&info->lock); + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, + ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + u8 val; + int i, ret; + + mutex_lock(&info->lock); + + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + max8997_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + + alrm->enabled = 0; + for (i = 0; i < RTC_NR_TIME; i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } + } + + alrm->pending = 0; + ret = max8997_read_reg(info->max8997->i2c, MAX8997_REG_STATUS1, &val); + if (ret < 0) { + dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n", + __func__, __LINE__, ret); + goto out; + } + + if (val & (1 << 4)) /* RTCA1 */ + alrm->pending = 1; + +out: + mutex_unlock(&info->lock); + return 0; +} + +static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret, i; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + for (i = 0; i < RTC_NR_TIME; i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); +out: + return ret; +} + +static int max8997_rtc_start_alarm(struct max8997_rtc_info *info) +{ + u8 data[RTC_NR_TIME]; + int ret; + + if (!mutex_is_locked(&info->lock)) + dev_warn(info->dev, "%s: should have mutex locked\n", __func__); + + ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", + __func__, ret); + goto out; + } + + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_YEAR] & 0x7f) + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); +out: + return ret; +} +static int max8997_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = max8997_rtc_tm_to_data(&alrm->time, data); + if (ret < 0) + return ret; + + dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d\n", __func__, + data[RTC_YEAR] + 2000, data[RTC_MONTH], data[RTC_DATE], + data[RTC_HOUR], data[RTC_MIN], data[RTC_SEC]); + + mutex_lock(&info->lock); + + ret = max8997_rtc_stop_alarm(info); + if (ret < 0) + goto out; + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME, + data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", + __func__, ret); + goto out; + } + + ret = max8997_rtc_set_update_reg(info); + if (ret < 0) + goto out; + + if (alrm->enabled) + ret = max8997_rtc_start_alarm(info); +out: + mutex_unlock(&info->lock); + return ret; +} + +static int max8997_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct max8997_rtc_info *info = dev_get_drvdata(dev); + int ret; + + mutex_lock(&info->lock); + if (enabled) + ret = max8997_rtc_start_alarm(info); + else + ret = max8997_rtc_stop_alarm(info); + mutex_unlock(&info->lock); + + return ret; +} + +static irqreturn_t max8997_rtc_alarm_irq(int irq, void *data) +{ + struct max8997_rtc_info *info = data; + + dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops max8997_rtc_ops = { + .read_time = max8997_rtc_read_time, + .set_time = max8997_rtc_set_time, + .read_alarm = max8997_rtc_read_alarm, + .set_alarm = max8997_rtc_set_alarm, + .alarm_irq_enable = max8997_rtc_alarm_irq_enable, +}; + +static void max8997_rtc_enable_wtsr(struct max8997_rtc_info *info, bool enable) +{ + int ret; + u8 val, mask; + + if (!wtsr_en) + return; + + if (enable) + val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT); + else + val = 0; + + mask = WTSR_EN_MASK | WTSRT_MASK; + + dev_info(info->dev, "%s: %s WTSR\n", __func__, + enable ? "enable" : "disable"); + + ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", + __func__, ret); + return; + } + + max8997_rtc_set_update_reg(info); +} + +static void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable) +{ + int ret; + u8 val, mask; + + if (!smpl_en) + return; + + if (enable) + val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT); + else + val = 0; + + mask = SMPL_EN_MASK | SMPLT_MASK; + + dev_info(info->dev, "%s: %s SMPL\n", __func__, + enable ? "enable" : "disable"); + + ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask); + if (ret < 0) { + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", + __func__, ret); + return; + } + + max8997_rtc_set_update_reg(info); + + val = 0; + max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val); + pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val); +} + +static int max8997_rtc_init_reg(struct max8997_rtc_info *info) +{ + u8 data[2]; + int ret; + + /* Set RTC control register : Binary mode, 24hour mdoe */ + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + + info->rtc_24hr_mode = 1; + + ret = max8997_bulk_write(info->rtc, MAX8997_RTC_CTRLMASK, 2, data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", + __func__, ret); + return ret; + } + + ret = max8997_rtc_set_update_reg(info); + return ret; +} + +static int max8997_rtc_probe(struct platform_device *pdev) +{ + struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); + struct max8997_rtc_info *info; + int ret, virq; + + info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_rtc_info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + mutex_init(&info->lock); + info->dev = &pdev->dev; + info->max8997 = max8997; + info->rtc = max8997->rtc; + + platform_set_drvdata(pdev, info); + + ret = max8997_rtc_init_reg(info); + + if (ret < 0) { + dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); + return ret; + } + + max8997_rtc_enable_wtsr(info, true); + max8997_rtc_enable_smpl(info, true); + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = rtc_device_register("max8997-rtc", &pdev->dev, + &max8997_rtc_ops, THIS_MODULE); + + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + return ret; + } + + virq = irq_create_mapping(max8997->irq_domain, MAX8997_PMICIRQ_RTCA1); + if (!virq) { + dev_err(&pdev->dev, "Failed to create mapping alarm IRQ\n"); + goto err_out; + } + info->virq = virq; + + ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, + max8997_rtc_alarm_irq, 0, + "rtc-alarm0", info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->virq, ret); + goto err_out; + } + + return ret; + +err_out: + rtc_device_unregister(info->rtc_dev); + return ret; +} + +static int max8997_rtc_remove(struct platform_device *pdev) +{ + struct max8997_rtc_info *info = platform_get_drvdata(pdev); + + if (info) + rtc_device_unregister(info->rtc_dev); + + return 0; +} + +static void max8997_rtc_shutdown(struct platform_device *pdev) +{ + struct max8997_rtc_info *info = platform_get_drvdata(pdev); + + max8997_rtc_enable_wtsr(info, false); + max8997_rtc_enable_smpl(info, false); +} + +static const struct platform_device_id rtc_id[] = { + { "max8997-rtc", 0 }, + {}, +}; + +static struct platform_driver max8997_rtc_driver = { + .driver = { + .name = "max8997-rtc", + .owner = THIS_MODULE, + }, + .probe = max8997_rtc_probe, + .remove = max8997_rtc_remove, + .shutdown = max8997_rtc_shutdown, + .id_table = rtc_id, +}; + +module_platform_driver(max8997_rtc_driver); + +MODULE_DESCRIPTION("Maxim MAX8997 RTC driver"); +MODULE_AUTHOR("<ms925.kim@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index 7196f438c089..8f234a075e8f 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -249,7 +249,7 @@ static const struct rtc_class_ops max8998_rtc_ops = { .alarm_irq_enable = max8998_rtc_alarm_irq_enable, }; -static int __devinit max8998_rtc_probe(struct platform_device *pdev) +static int max8998_rtc_probe(struct platform_device *pdev) { struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev); @@ -298,7 +298,7 @@ out_rtc: return ret; } -static int __devexit max8998_rtc_remove(struct platform_device *pdev) +static int max8998_rtc_remove(struct platform_device *pdev) { struct max8998_rtc_info *info = platform_get_drvdata(pdev); @@ -323,7 +323,7 @@ static struct platform_driver max8998_rtc_driver = { .owner = THIS_MODULE, }, .probe = max8998_rtc_probe, - .remove = __devexit_p(max8998_rtc_remove), + .remove = max8998_rtc_remove, .id_table = max8998_rtc_id, }; diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 029e421baaed..bdcc60830aec 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/rtc.h> +#include <linux/of.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/io.h> @@ -306,7 +307,7 @@ static const struct rtc_class_ops mpc5200_rtc_ops = { .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable, }; -static int __devinit mpc5121_rtc_probe(struct platform_device *op) +static int mpc5121_rtc_probe(struct platform_device *op) { struct mpc5121_rtc_data *rtc; int err = 0; @@ -382,7 +383,7 @@ out_free: return err; } -static int __devexit mpc5121_rtc_remove(struct platform_device *op) +static int mpc5121_rtc_remove(struct platform_device *op) { struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev); struct mpc5121_rtc_regs __iomem *regs = rtc->regs; @@ -403,20 +404,22 @@ static int __devexit mpc5121_rtc_remove(struct platform_device *op) return 0; } -static struct of_device_id mpc5121_rtc_match[] __devinitdata = { +#ifdef CONFIG_OF +static struct of_device_id mpc5121_rtc_match[] = { { .compatible = "fsl,mpc5121-rtc", }, { .compatible = "fsl,mpc5200-rtc", }, {}, }; +#endif static struct platform_driver mpc5121_rtc_driver = { .driver = { .name = "mpc5121-rtc", .owner = THIS_MODULE, - .of_match_table = mpc5121_rtc_match, + .of_match_table = of_match_ptr(mpc5121_rtc_match), }, .probe = mpc5121_rtc_probe, - .remove = __devexit_p(mpc5121_rtc_remove), + .remove = mpc5121_rtc_remove, }; module_platform_driver(mpc5121_rtc_driver); diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index f51719bf4a75..578baf9d9725 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -322,8 +322,8 @@ static irqreturn_t mrst_rtc_irq(int irq, void *p) return IRQ_NONE; } -static int __devinit -vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) +static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, + int rtc_irq) { int retval = 0; unsigned char rtc_control; @@ -394,7 +394,7 @@ static void rtc_mrst_do_shutdown(void) spin_unlock_irq(&rtc_lock); } -static void __devexit rtc_mrst_do_remove(struct device *dev) +static void rtc_mrst_do_remove(struct device *dev) { struct mrst_rtc *mrst = dev_get_drvdata(dev); struct resource *iomem; @@ -503,14 +503,14 @@ static inline int mrst_poweroff(struct device *dev) #endif -static int __devinit vrtc_mrst_platform_probe(struct platform_device *pdev) +static int vrtc_mrst_platform_probe(struct platform_device *pdev) { return vrtc_mrst_do_probe(&pdev->dev, platform_get_resource(pdev, IORESOURCE_MEM, 0), platform_get_irq(pdev, 0)); } -static int __devexit vrtc_mrst_platform_remove(struct platform_device *pdev) +static int vrtc_mrst_platform_remove(struct platform_device *pdev) { rtc_mrst_do_remove(&pdev->dev); return 0; @@ -528,7 +528,7 @@ MODULE_ALIAS("platform:vrtc_mrst"); static struct platform_driver vrtc_mrst_platform_driver = { .probe = vrtc_mrst_platform_probe, - .remove = __devexit_p(vrtc_mrst_platform_remove), + .remove = vrtc_mrst_platform_remove, .shutdown = vrtc_mrst_platform_shutdown, .driver = { .name = (char *) driver_name, diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index ebc1649d45d6..8f87fec27ce7 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/of.h> #include <linux/delay.h> +#include <linux/clk.h> #include <linux/gfp.h> #include <linux/module.h> @@ -41,6 +42,7 @@ struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; int irq; + struct clk *clk; }; static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -215,12 +217,13 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = { .alarm_irq_enable = mv_rtc_alarm_irq_enable, }; -static int __devinit mv_rtc_probe(struct platform_device *pdev) +static int mv_rtc_probe(struct platform_device *pdev) { struct resource *res; struct rtc_plat_data *pdata; resource_size_t size; u32 rtc_time; + int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -239,11 +242,17 @@ static int __devinit mv_rtc_probe(struct platform_device *pdev) if (!pdata->ioaddr) return -ENOMEM; + pdata->clk = devm_clk_get(&pdev->dev, NULL); + /* Not all SoCs require a clock.*/ + if (!IS_ERR(pdata->clk)) + clk_prepare_enable(pdata->clk); + /* 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; + ret = -EINVAL; + goto out; } /* make sure it is actually functional */ @@ -252,7 +261,8 @@ static int __devinit mv_rtc_probe(struct platform_device *pdev) rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS); if (rtc_time == 0x01000000) { dev_err(&pdev->dev, "internal RTC not ticking\n"); - return -ENODEV; + ret = -ENODEV; + goto out; } } @@ -268,8 +278,10 @@ static int __devinit mv_rtc_probe(struct platform_device *pdev) } else pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, &mv_rtc_ops, THIS_MODULE); - if (IS_ERR(pdata->rtc)) - return PTR_ERR(pdata->rtc); + if (IS_ERR(pdata->rtc)) { + ret = PTR_ERR(pdata->rtc); + goto out; + } if (pdata->irq >= 0) { writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); @@ -282,6 +294,11 @@ static int __devinit mv_rtc_probe(struct platform_device *pdev) } return 0; +out: + if (!IS_ERR(pdata->clk)) + clk_disable_unprepare(pdata->clk); + + return ret; } static int __exit mv_rtc_remove(struct platform_device *pdev) @@ -292,6 +309,9 @@ static int __exit mv_rtc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); rtc_device_unregister(pdata->rtc); + if (!IS_ERR(pdata->clk)) + clk_disable_unprepare(pdata->clk); + return 0; } diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index cd0106293a49..1c3ef7289565 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -17,8 +17,6 @@ #include <linux/platform_device.h> #include <linux/clk.h> -#include <mach/hardware.h> - #define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5) #define RTC_INPUT_CLK_38400HZ (0x02 << 5) @@ -72,14 +70,38 @@ static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { #define RTC_TEST2 0x2C /* 32bit rtc test reg 2 */ #define RTC_TEST3 0x30 /* 32bit rtc test reg 3 */ +enum imx_rtc_type { + IMX1_RTC, + IMX21_RTC, +}; + struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; int irq; struct clk *clk; struct rtc_time g_rtc_alarm; + enum imx_rtc_type devtype; }; +static struct platform_device_id imx_rtc_devtype[] = { + { + .name = "imx1-rtc", + .driver_data = IMX1_RTC, + }, { + .name = "imx21-rtc", + .driver_data = IMX21_RTC, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imx_rtc_devtype); + +static inline int is_imx1_rtc(struct rtc_plat_data *data) +{ + return data->devtype == IMX1_RTC; +} + /* * This function is used to obtain the RTC time or the alarm value in * second. @@ -278,10 +300,13 @@ static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm) */ static int mxc_rtc_set_mmss(struct device *dev, unsigned long time) { + struct platform_device *pdev = to_platform_device(dev); + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + /* * TTC_DAYR register is 9-bit in MX1 SoC, save time and day of year only */ - if (cpu_is_mx1()) { + if (is_imx1_rtc(pdata)) { struct rtc_time tm; rtc_time_to_tm(time, &tm); @@ -343,7 +368,7 @@ static struct rtc_class_ops mxc_rtc_ops = { .alarm_irq_enable = mxc_rtc_alarm_irq_enable, }; -static int __devinit mxc_rtc_probe(struct platform_device *pdev) +static int mxc_rtc_probe(struct platform_device *pdev) { struct resource *res; struct rtc_device *rtc; @@ -360,6 +385,8 @@ static int __devinit mxc_rtc_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; + pdata->devtype = pdev->id_entry->driver_data; + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name)) return -EBUSY; @@ -433,7 +460,7 @@ exit_free_pdata: return ret; } -static int __devexit mxc_rtc_remove(struct platform_device *pdev) +static int mxc_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); @@ -480,8 +507,9 @@ static struct platform_driver mxc_rtc_driver = { #endif .owner = THIS_MODULE, }, + .id_table = imx_rtc_devtype, .probe = mxc_rtc_probe, - .remove = __devexit_p(mxc_rtc_remove), + .remove = mxc_rtc_remove, }; module_platform_driver(mxc_rtc_driver) diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index b79010987d1e..a63680850fef 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -222,7 +222,7 @@ static struct rtc_class_ops nuc900_rtc_ops = { .alarm_irq_enable = nuc900_alarm_irq_enable, }; -static int __devinit nuc900_rtc_probe(struct platform_device *pdev) +static int nuc900_rtc_probe(struct platform_device *pdev) { struct resource *res; struct nuc900_rtc *nuc900_rtc; @@ -284,7 +284,7 @@ fail1: kfree(nuc900_rtc); return err; } -static int __devexit nuc900_rtc_remove(struct platform_device *pdev) +static int nuc900_rtc_remove(struct platform_device *pdev) { struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev); struct resource *res; @@ -304,7 +304,7 @@ static int __devexit nuc900_rtc_remove(struct platform_device *pdev) } static struct platform_driver nuc900_rtc_driver = { - .remove = __devexit_p(nuc900_rtc_remove), + .remove = nuc900_rtc_remove, .driver = { .name = "nuc900-rtc", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 0b614e32653d..600971407aac 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -20,6 +20,9 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> #include <asm/io.h> @@ -38,6 +41,8 @@ * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. */ +#define DRIVER_NAME "omap_rtc" + #define OMAP_RTC_BASE 0xfffb4800 /* RTC registers */ @@ -64,6 +69,9 @@ #define OMAP_RTC_COMP_MSB_REG 0x50 #define OMAP_RTC_OSC_REG 0x54 +#define OMAP_RTC_KICK0_REG 0x6c +#define OMAP_RTC_KICK1_REG 0x70 + /* OMAP_RTC_CTRL_REG bit fields: */ #define OMAP_RTC_CTRL_SPLIT (1<<7) #define OMAP_RTC_CTRL_DISABLE (1<<6) @@ -88,10 +96,18 @@ #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) +/* OMAP_RTC_KICKER values */ +#define KICK0_VALUE 0x83e70b13 +#define KICK1_VALUE 0x95a4f1e0 + +#define OMAP_RTC_HAS_KICKER 0x1 + static void __iomem *rtc_base; -#define rtc_read(addr) __raw_readb(rtc_base + (addr)) -#define rtc_write(val, addr) __raw_writeb(val, rtc_base + (addr)) +#define rtc_read(addr) readb(rtc_base + (addr)) +#define rtc_write(val, addr) writeb(val, rtc_base + (addr)) + +#define rtc_writel(val, addr) writel(val, rtc_base + (addr)) /* we rely on the rtc framework to handle locking (rtc->ops_lock), @@ -285,11 +301,38 @@ static struct rtc_class_ops omap_rtc_ops = { static int omap_rtc_alarm; static int omap_rtc_timer; +#define OMAP_RTC_DATA_DA830_IDX 1 + +static struct platform_device_id omap_rtc_devtype[] = { + { + .name = DRIVER_NAME, + }, { + .name = "da830-rtc", + .driver_data = OMAP_RTC_HAS_KICKER, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, omap_rtc_devtype); + +static const struct of_device_id omap_rtc_of_match[] = { + { .compatible = "ti,da830-rtc", + .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], + }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap_rtc_of_match); + static int __init omap_rtc_probe(struct platform_device *pdev) { struct resource *res, *mem; struct rtc_device *rtc; u8 reg, new_ctrl; + const struct platform_device_id *id_entry; + const struct of_device_id *of_id; + + of_id = of_match_device(omap_rtc_of_match, &pdev->dev); + if (of_id) + pdev->id_entry = of_id->data; omap_rtc_timer = platform_get_irq(pdev, 0); if (omap_rtc_timer <= 0) { @@ -322,6 +365,16 @@ static int __init omap_rtc_probe(struct platform_device *pdev) goto fail; } + /* Enable the clock/module so that we can access the registers */ + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + id_entry = platform_get_device_id(pdev); + if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) { + rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG); + rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG); + } + rtc = rtc_device_register(pdev->name, &pdev->dev, &omap_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -398,6 +451,10 @@ fail2: fail1: rtc_device_unregister(rtc); fail0: + if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) + rtc_writel(0, OMAP_RTC_KICK0_REG); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); iounmap(rtc_base); fail: release_mem_region(mem->start, resource_size(mem)); @@ -408,6 +465,8 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); struct resource *mem = dev_get_drvdata(&rtc->dev); + const struct platform_device_id *id_entry = + platform_get_device_id(pdev); device_init_wakeup(&pdev->dev, 0); @@ -420,6 +479,13 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) free_irq(omap_rtc_alarm, rtc); rtc_device_unregister(rtc); + if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) + rtc_writel(0, OMAP_RTC_KICK0_REG); + + /* Disable the clock/module */ + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + iounmap(rtc_base); release_mem_region(mem->start, resource_size(mem)); return 0; @@ -442,11 +508,17 @@ static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state) else rtc_write(0, OMAP_RTC_INTERRUPTS_REG); + /* Disable the clock/module */ + pm_runtime_put_sync(&pdev->dev); + return 0; } static int omap_rtc_resume(struct platform_device *pdev) { + /* Enable the clock/module so that we can access the registers */ + pm_runtime_get_sync(&pdev->dev); + if (device_may_wakeup(&pdev->dev)) disable_irq_wake(omap_rtc_alarm); else @@ -471,9 +543,11 @@ static struct platform_driver omap_rtc_driver = { .resume = omap_rtc_resume, .shutdown = omap_rtc_shutdown, .driver = { - .name = "omap_rtc", + .name = DRIVER_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_rtc_of_match), }, + .id_table = omap_rtc_devtype, }; static int __init rtc_init(void) diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c new file mode 100644 index 000000000000..59c42986254e --- /dev/null +++ b/drivers/rtc/rtc-palmas.c @@ -0,0 +1,339 @@ +/* + * rtc-palmas.c -- Palmas Real Time Clock driver. + + * RTC driver for TI Palma series devices like TPS65913, + * TPS65914 power management IC. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/bcd.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/palmas.h> +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <linux/pm.h> + +struct palmas_rtc { + struct rtc_device *rtc; + struct device *dev; + unsigned int irq; +}; + +/* Total number of RTC registers needed to set time*/ +#define PALMAS_NUM_TIME_REGS (PALMAS_YEARS_REG - PALMAS_SECONDS_REG + 1) + +static int palmas_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[PALMAS_NUM_TIME_REGS]; + struct palmas *palmas = dev_get_drvdata(dev->parent); + int ret; + + /* Copy RTC counting registers to static registers or latches */ + ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, + PALMAS_RTC_CTRL_REG_GET_TIME, PALMAS_RTC_CTRL_REG_GET_TIME); + if (ret < 0) { + dev_err(dev, "RTC CTRL reg update failed, err: %d\n", ret); + return ret; + } + + ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG, + rtc_data, PALMAS_NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "RTC_SECONDS reg read failed, err = %d\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(rtc_data[0]); + tm->tm_min = bcd2bin(rtc_data[1]); + tm->tm_hour = bcd2bin(rtc_data[2]); + tm->tm_mday = bcd2bin(rtc_data[3]); + tm->tm_mon = bcd2bin(rtc_data[4]) - 1; + tm->tm_year = bcd2bin(rtc_data[5]) + 100; + + return ret; +} + +static int palmas_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[PALMAS_NUM_TIME_REGS]; + struct palmas *palmas = dev_get_drvdata(dev->parent); + int ret; + + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); + + /* Stop RTC while updating the RTC time registers */ + ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, + PALMAS_RTC_CTRL_REG_STOP_RTC, 0); + if (ret < 0) { + dev_err(dev, "RTC stop failed, err = %d\n", ret); + return ret; + } + + ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE, PALMAS_SECONDS_REG, + rtc_data, PALMAS_NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "RTC_SECONDS reg write failed, err = %d\n", ret); + return ret; + } + + /* Start back RTC */ + ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, + PALMAS_RTC_CTRL_REG_STOP_RTC, PALMAS_RTC_CTRL_REG_STOP_RTC); + if (ret < 0) + dev_err(dev, "RTC start failed, err = %d\n", ret); + return ret; +} + +static int palmas_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) +{ + struct palmas *palmas = dev_get_drvdata(dev->parent); + u8 val; + + val = enabled ? PALMAS_RTC_INTERRUPTS_REG_IT_ALARM : 0; + return palmas_write(palmas, PALMAS_RTC_BASE, + PALMAS_RTC_INTERRUPTS_REG, val); +} + +static int palmas_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char alarm_data[PALMAS_NUM_TIME_REGS]; + u32 int_val; + struct palmas *palmas = dev_get_drvdata(dev->parent); + int ret; + + ret = palmas_bulk_read(palmas, PALMAS_RTC_BASE, + PALMAS_ALARM_SECONDS_REG, + alarm_data, PALMAS_NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "RTC_ALARM_SECONDS read failed, err = %d\n", ret); + return ret; + } + + alm->time.tm_sec = bcd2bin(alarm_data[0]); + alm->time.tm_min = bcd2bin(alarm_data[1]); + alm->time.tm_hour = bcd2bin(alarm_data[2]); + alm->time.tm_mday = bcd2bin(alarm_data[3]); + alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1; + alm->time.tm_year = bcd2bin(alarm_data[5]) + 100; + + ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_INTERRUPTS_REG, + &int_val); + if (ret < 0) { + dev_err(dev, "RTC_INTERRUPTS reg read failed, err = %d\n", ret); + return ret; + } + + if (int_val & PALMAS_RTC_INTERRUPTS_REG_IT_ALARM) + alm->enabled = 1; + return ret; +} + +static int palmas_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char alarm_data[PALMAS_NUM_TIME_REGS]; + struct palmas *palmas = dev_get_drvdata(dev->parent); + int ret; + + ret = palmas_rtc_alarm_irq_enable(dev, 0); + if (ret < 0) { + dev_err(dev, "Disable RTC alarm failed\n"); + return ret; + } + + alarm_data[0] = bin2bcd(alm->time.tm_sec); + alarm_data[1] = bin2bcd(alm->time.tm_min); + alarm_data[2] = bin2bcd(alm->time.tm_hour); + alarm_data[3] = bin2bcd(alm->time.tm_mday); + alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[5] = bin2bcd(alm->time.tm_year - 100); + + ret = palmas_bulk_write(palmas, PALMAS_RTC_BASE, + PALMAS_ALARM_SECONDS_REG, alarm_data, PALMAS_NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "ALARM_SECONDS_REG write failed, err = %d\n", ret); + return ret; + } + + if (alm->enabled) + ret = palmas_rtc_alarm_irq_enable(dev, 1); + return ret; +} + +static int palmas_clear_interrupts(struct device *dev) +{ + struct palmas *palmas = dev_get_drvdata(dev->parent); + unsigned int rtc_reg; + int ret; + + ret = palmas_read(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG, + &rtc_reg); + if (ret < 0) { + dev_err(dev, "RTC_STATUS read failed, err = %d\n", ret); + return ret; + } + + ret = palmas_write(palmas, PALMAS_RTC_BASE, PALMAS_RTC_STATUS_REG, + rtc_reg); + if (ret < 0) { + dev_err(dev, "RTC_STATUS write failed, err = %d\n", ret); + return ret; + } + return 0; +} + +static irqreturn_t palmas_rtc_interrupt(int irq, void *context) +{ + struct palmas_rtc *palmas_rtc = context; + struct device *dev = palmas_rtc->dev; + int ret; + + ret = palmas_clear_interrupts(dev); + if (ret < 0) { + dev_err(dev, "RTC interrupt clear failed, err = %d\n", ret); + return IRQ_NONE; + } + + rtc_update_irq(palmas_rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static struct rtc_class_ops palmas_rtc_ops = { + .read_time = palmas_rtc_read_time, + .set_time = palmas_rtc_set_time, + .read_alarm = palmas_rtc_read_alarm, + .set_alarm = palmas_rtc_set_alarm, + .alarm_irq_enable = palmas_rtc_alarm_irq_enable, +}; + +static int palmas_rtc_probe(struct platform_device *pdev) +{ + struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); + struct palmas_rtc *palmas_rtc = NULL; + int ret; + + palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc), + GFP_KERNEL); + if (!palmas_rtc) + return -ENOMEM; + + /* Clear pending interrupts */ + ret = palmas_clear_interrupts(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "clear RTC int failed, err = %d\n", ret); + return ret; + } + + palmas_rtc->dev = &pdev->dev; + platform_set_drvdata(pdev, palmas_rtc); + + /* Start RTC */ + ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, + PALMAS_RTC_CTRL_REG_STOP_RTC, + PALMAS_RTC_CTRL_REG_STOP_RTC); + if (ret < 0) { + dev_err(&pdev->dev, "RTC_CTRL write failed, err = %d\n", ret); + return ret; + } + + palmas_rtc->irq = platform_get_irq(pdev, 0); + + palmas_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &palmas_rtc_ops, THIS_MODULE); + if (IS_ERR(palmas_rtc->rtc)) { + ret = PTR_ERR(palmas_rtc->rtc); + dev_err(&pdev->dev, "RTC register failed, err = %d\n", ret); + return ret; + } + + ret = request_threaded_irq(palmas_rtc->irq, NULL, + palmas_rtc_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT | + IRQF_EARLY_RESUME, + dev_name(&pdev->dev), palmas_rtc); + if (ret < 0) { + dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret); + rtc_device_unregister(palmas_rtc->rtc); + return ret; + } + + device_set_wakeup_capable(&pdev->dev, 1); + return 0; +} + +static int palmas_rtc_remove(struct platform_device *pdev) +{ + struct palmas_rtc *palmas_rtc = platform_get_drvdata(pdev); + + palmas_rtc_alarm_irq_enable(&pdev->dev, 0); + free_irq(palmas_rtc->irq, palmas_rtc); + rtc_device_unregister(palmas_rtc->rtc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int palmas_rtc_suspend(struct device *dev) +{ + struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(palmas_rtc->irq); + return 0; +} + +static int palmas_rtc_resume(struct device *dev) +{ + struct palmas_rtc *palmas_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(palmas_rtc->irq); + return 0; +} +#endif + +static const struct dev_pm_ops palmas_rtc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume) +}; + +static struct platform_driver palmas_rtc_driver = { + .probe = palmas_rtc_probe, + .remove = palmas_rtc_remove, + .driver = { + .owner = THIS_MODULE, + .name = "palmas-rtc", + .pm = &palmas_rtc_pm_ops, + }, +}; + +module_platform_driver(palmas_rtc_driver); + +MODULE_ALIAS("platform:palmas_rtc"); +MODULE_DESCRIPTION("TI PALMAS series RTC driver"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index cd4f198cc2ef..e0019cd0bf71 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -139,7 +139,7 @@ static const struct rtc_class_ops pcap_rtc_ops = { .alarm_irq_enable = pcap_rtc_alarm_irq_enable, }; -static int __devinit pcap_rtc_probe(struct platform_device *pdev) +static int pcap_rtc_probe(struct platform_device *pdev) { struct pcap_rtc *pcap_rtc; int timer_irq, alarm_irq; @@ -183,7 +183,7 @@ fail_rtc: return err; } -static int __devexit pcap_rtc_remove(struct platform_device *pdev) +static int pcap_rtc_remove(struct platform_device *pdev) { struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev); @@ -196,7 +196,7 @@ static int __devexit pcap_rtc_remove(struct platform_device *pdev) } static struct platform_driver pcap_rtc_driver = { - .remove = __devexit_p(pcap_rtc_remove), + .remove = pcap_rtc_remove, .driver = { .name = "pcap-rtc", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 13e4df63974f..02b742afa761 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -219,7 +219,7 @@ static const struct rtc_class_ops pcf2123_rtc_ops = { .set_time = pcf2123_rtc_set_time, }; -static int __devinit pcf2123_probe(struct spi_device *spi) +static int pcf2123_probe(struct spi_device *spi) { struct rtc_device *rtc; struct pcf2123_plat_data *pdata; @@ -319,7 +319,7 @@ kfree_exit: return ret; } -static int __devexit pcf2123_remove(struct spi_device *spi) +static int pcf2123_remove(struct spi_device *spi) { struct pcf2123_plat_data *pdata = spi->dev.platform_data; int i; @@ -345,7 +345,7 @@ static struct spi_driver pcf2123_driver = { .owner = THIS_MODULE, }, .probe = pcf2123_probe, - .remove = __devexit_p(pcf2123_remove), + .remove = pcf2123_remove, }; module_spi_driver(pcf2123_driver); diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index a20202f9ee57..e9f3135d305f 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -248,7 +248,7 @@ static void pcf50633_rtc_irq(int irq, void *data) rtc->alarm_pending = 1; } -static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) +static int pcf50633_rtc_probe(struct platform_device *pdev) { struct pcf50633_rtc *rtc; @@ -272,7 +272,7 @@ static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_rtc_remove(struct platform_device *pdev) +static int pcf50633_rtc_remove(struct platform_device *pdev) { struct pcf50633_rtc *rtc; @@ -291,7 +291,7 @@ static struct platform_driver pcf50633_rtc_driver = { .name = "pcf50633-rtc", }, .probe = pcf50633_rtc_probe, - .remove = __devexit_p(pcf50633_rtc_remove), + .remove = pcf50633_rtc_remove, }; module_platform_driver(pcf50633_rtc_driver); diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c new file mode 100644 index 000000000000..889e3160e701 --- /dev/null +++ b/drivers/rtc/rtc-pcf8523.c @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2012 Avionic Design GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bcd.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/of.h> + +#define DRIVER_NAME "rtc-pcf8523" + +#define REG_CONTROL1 0x00 +#define REG_CONTROL1_CAP_SEL (1 << 7) +#define REG_CONTROL1_STOP (1 << 5) + +#define REG_CONTROL3 0x02 +#define REG_CONTROL3_PM_BLD (1 << 7) /* battery low detection disabled */ +#define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */ +#define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */ +#define REG_CONTROL3_PM_MASK 0xe0 +#define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */ + +#define REG_SECONDS 0x03 +#define REG_SECONDS_OS (1 << 7) + +#define REG_MINUTES 0x04 +#define REG_HOURS 0x05 +#define REG_DAYS 0x06 +#define REG_WEEKDAYS 0x07 +#define REG_MONTHS 0x08 +#define REG_YEARS 0x09 + +struct pcf8523 { + struct rtc_device *rtc; +}; + +static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep) +{ + struct i2c_msg msgs[2]; + u8 value = 0; + int err; + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(reg); + msgs[0].buf = ® + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(value); + msgs[1].buf = &value; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err < 0) + return err; + + *valuep = value; + + return 0; +} + +static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) +{ + u8 buffer[2] = { reg, value }; + struct i2c_msg msg; + int err; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = sizeof(buffer); + msg.buf = buffer; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err < 0) + return err; + + return 0; +} + +static int pcf8523_select_capacitance(struct i2c_client *client, bool high) +{ + u8 value; + int err; + + err = pcf8523_read(client, REG_CONTROL1, &value); + if (err < 0) + return err; + + if (!high) + value &= ~REG_CONTROL1_CAP_SEL; + else + value |= REG_CONTROL1_CAP_SEL; + + err = pcf8523_write(client, REG_CONTROL1, value); + if (err < 0) + return err; + + return err; +} + +static int pcf8523_set_pm(struct i2c_client *client, u8 pm) +{ + u8 value; + int err; + + err = pcf8523_read(client, REG_CONTROL3, &value); + if (err < 0) + return err; + + value = (value & ~REG_CONTROL3_PM_MASK) | pm; + + err = pcf8523_write(client, REG_CONTROL3, value); + if (err < 0) + return err; + + return 0; +} + +static int pcf8523_stop_rtc(struct i2c_client *client) +{ + u8 value; + int err; + + err = pcf8523_read(client, REG_CONTROL1, &value); + if (err < 0) + return err; + + value |= REG_CONTROL1_STOP; + + err = pcf8523_write(client, REG_CONTROL1, value); + if (err < 0) + return err; + + return 0; +} + +static int pcf8523_start_rtc(struct i2c_client *client) +{ + u8 value; + int err; + + err = pcf8523_read(client, REG_CONTROL1, &value); + if (err < 0) + return err; + + value &= ~REG_CONTROL1_STOP; + + err = pcf8523_write(client, REG_CONTROL1, value); + if (err < 0) + return err; + + return 0; +} + +static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 start = REG_SECONDS, regs[7]; + struct i2c_msg msgs[2]; + int err; + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = &start; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(regs); + msgs[1].buf = regs; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err < 0) + return err; + + if (regs[0] & REG_SECONDS_OS) { + /* + * If the oscillator was stopped, try to clear the flag. Upon + * power-up the flag is always set, but if we cannot clear it + * the oscillator isn't running properly for some reason. The + * sensible thing therefore is to return an error, signalling + * that the clock cannot be assumed to be correct. + */ + + regs[0] &= ~REG_SECONDS_OS; + + err = pcf8523_write(client, REG_SECONDS, regs[0]); + if (err < 0) + return err; + + err = pcf8523_read(client, REG_SECONDS, ®s[0]); + if (err < 0) + return err; + + if (regs[0] & REG_SECONDS_OS) + return -EAGAIN; + } + + tm->tm_sec = bcd2bin(regs[0] & 0x7f); + tm->tm_min = bcd2bin(regs[1] & 0x7f); + tm->tm_hour = bcd2bin(regs[2] & 0x3f); + tm->tm_mday = bcd2bin(regs[3] & 0x3f); + tm->tm_wday = regs[4] & 0x7; + tm->tm_mon = bcd2bin(regs[5] & 0x1f); + tm->tm_year = bcd2bin(regs[6]) + 100; + + return rtc_valid_tm(tm); +} + +static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_msg msg; + u8 regs[8]; + int err; + + err = pcf8523_stop_rtc(client); + if (err < 0) + return err; + + regs[0] = REG_SECONDS; + regs[1] = bin2bcd(tm->tm_sec); + regs[2] = bin2bcd(tm->tm_min); + regs[3] = bin2bcd(tm->tm_hour); + regs[4] = bin2bcd(tm->tm_mday); + regs[5] = tm->tm_wday; + regs[6] = bin2bcd(tm->tm_mon); + regs[7] = bin2bcd(tm->tm_year - 100); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = sizeof(regs); + msg.buf = regs; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err < 0) { + /* + * If the time cannot be set, restart the RTC anyway. Note + * that errors are ignored if the RTC cannot be started so + * that we have a chance to propagate the original error. + */ + pcf8523_start_rtc(client); + return err; + } + + return pcf8523_start_rtc(client); +} + +#ifdef CONFIG_RTC_INTF_DEV +static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 value; + int ret = 0, err; + + switch (cmd) { + case RTC_VL_READ: + err = pcf8523_read(client, REG_CONTROL3, &value); + if (err < 0) + return err; + + if (value & REG_CONTROL3_BLF) + ret = 1; + + if (copy_to_user((void __user *)arg, &ret, sizeof(int))) + return -EFAULT; + + return 0; + default: + return -ENOIOCTLCMD; + } +} +#else +#define pcf8523_rtc_ioctl NULL +#endif + +static const struct rtc_class_ops pcf8523_rtc_ops = { + .read_time = pcf8523_rtc_read_time, + .set_time = pcf8523_rtc_set_time, + .ioctl = pcf8523_rtc_ioctl, +}; + +static int pcf8523_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pcf8523 *pcf; + int err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + pcf = devm_kzalloc(&client->dev, sizeof(*pcf), GFP_KERNEL); + if (!pcf) + return -ENOMEM; + + err = pcf8523_select_capacitance(client, true); + if (err < 0) + return err; + + err = pcf8523_set_pm(client, 0); + if (err < 0) + return err; + + pcf->rtc = rtc_device_register(DRIVER_NAME, &client->dev, + &pcf8523_rtc_ops, THIS_MODULE); + if (IS_ERR(pcf->rtc)) + return PTR_ERR(pcf->rtc); + + i2c_set_clientdata(client, pcf); + + return 0; +} + +static int pcf8523_remove(struct i2c_client *client) +{ + struct pcf8523 *pcf = i2c_get_clientdata(client); + + rtc_device_unregister(pcf->rtc); + + return 0; +} + +static const struct i2c_device_id pcf8523_id[] = { + { "pcf8523", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf8523_id); + +#ifdef CONFIG_OF +static const struct of_device_id pcf8523_of_match[] = { + { .compatible = "nxp,pcf8523" }, + { } +}; +MODULE_DEVICE_TABLE(of, pcf8523_of_match); +#endif + +static struct i2c_driver pcf8523_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pcf8523_of_match), + }, + .probe = pcf8523_probe, + .remove = pcf8523_remove, + .id_table = pcf8523_id, +}; +module_i2c_driver(pcf8523_driver); + +MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); +MODULE_DESCRIPTION("NXP PCF8523 RTC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 98e3a2b681e6..f7daf18a112e 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -181,7 +181,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) __func__, err, data[0], data[1]); return -EIO; } - }; + } return 0; } @@ -296,7 +296,7 @@ static const struct i2c_device_id pcf8563_id[] = { MODULE_DEVICE_TABLE(i2c, pcf8563_id); #ifdef CONFIG_OF -static const struct of_device_id pcf8563_of_match[] __devinitconst = { +static const struct of_device_id pcf8563_of_match[] = { { .compatible = "nxp,pcf8563" }, {} }; diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 019ff3571168..5f97c61247d5 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -185,8 +185,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ctrl & (CTRL_STOP | CTRL_HOLD)) { unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD); - printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n", - ctrl, new_ctrl); + dev_warn(dev, "resetting control %02x -> %02x\n", + ctrl, new_ctrl); if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0) return err; @@ -294,7 +294,7 @@ exit_kfree: return err; } -static int __devexit pcf8583_remove(struct i2c_client *client) +static int pcf8583_remove(struct i2c_client *client) { struct pcf8583 *pcf8583 = i2c_get_clientdata(client); @@ -316,7 +316,7 @@ static struct i2c_driver pcf8583_driver = { .owner = THIS_MODULE, }, .probe = pcf8583_probe, - .remove = __devexit_p(pcf8583_remove), + .remove = pcf8583_remove, .id_table = pcf8583_id, }; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 08378e3cc21c..8900ea784817 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -44,6 +44,7 @@ #define RTC_YMR 0x34 /* Year match register */ #define RTC_YLR 0x38 /* Year data load register */ +#define RTC_CR_EN (1 << 0) /* counter enable bit */ #define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */ #define RTC_TCR_EN (1 << 1) /* Periodic timer enable bit */ @@ -320,7 +321,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) struct pl031_local *ldata; struct pl031_vendor_data *vendor = id->data; struct rtc_class_ops *ops = &vendor->ops; - unsigned long time; + unsigned long time, data; ret = amba_request_regions(adev, NULL); if (ret) @@ -345,10 +346,13 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev)); dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev)); + data = readl(ldata->base + RTC_CR); /* Enable the clockwatch on ST Variants */ if (vendor->clockwatch) - writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN, - ldata->base + RTC_CR); + data |= RTC_CR_CWEN; + else + data |= RTC_CR_EN; + writel(data, ldata->base + RTC_CR); /* * On ST PL031 variants, the RTC reset value does not provide correct @@ -380,6 +384,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_irq; } + device_init_wakeup(&adev->dev, 1); + return 0; out_no_irq: diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index d00bd24342a3..f1a6557261f3 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -382,7 +382,7 @@ rtc_alarm_handled: return IRQ_HANDLED; } -static int __devinit pm8xxx_rtc_probe(struct platform_device *pdev) +static int pm8xxx_rtc_probe(struct platform_device *pdev) { int rc; u8 ctrl_reg; @@ -485,7 +485,7 @@ fail_rtc_enable: return rc; } -static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev) +static int pm8xxx_rtc_remove(struct platform_device *pdev) { struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev); @@ -524,7 +524,7 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resum static struct platform_driver pm8xxx_rtc_driver = { .probe = pm8xxx_rtc_probe, - .remove = __devexit_p(pm8xxx_rtc_remove), + .remove = pm8xxx_rtc_remove, .driver = { .name = PM8XXX_RTC_DEV_NAME, .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index ab0acaeb2371..0407e13d4de4 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -220,7 +220,7 @@ static void puv3_rtc_enable(struct platform_device *pdev, int en) } } -static int __devexit puv3_rtc_remove(struct platform_device *dev) +static int puv3_rtc_remove(struct platform_device *dev) { struct rtc_device *rtc = platform_get_drvdata(dev); @@ -236,7 +236,7 @@ static int __devexit puv3_rtc_remove(struct platform_device *dev) return 0; } -static int __devinit puv3_rtc_probe(struct platform_device *pdev) +static int puv3_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; @@ -328,7 +328,7 @@ static int puv3_rtc_resume(struct platform_device *pdev) static struct platform_driver puv3_rtc_driver = { .probe = puv3_rtc_probe, - .remove = __devexit_p(puv3_rtc_remove), + .remove = puv3_rtc_remove, .suspend = puv3_rtc_suspend, .resume = puv3_rtc_resume, .driver = { diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index f771b2ee4b18..03c85ee719a7 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -62,6 +62,10 @@ #define RYxR_MONTH_S 5 #define RYxR_MONTH_MASK (0xf << RYxR_MONTH_S) #define RYxR_DAY_MASK 0x1f +#define RDxR_WOM_S 20 +#define RDxR_WOM_MASK (0x7 << RDxR_WOM_S) +#define RDxR_DOW_S 17 +#define RDxR_DOW_MASK (0x7 << RDxR_DOW_S) #define RDxR_HOUR_S 12 #define RDxR_HOUR_MASK (0x1f << RDxR_HOUR_S) #define RDxR_MIN_S 6 @@ -91,6 +95,7 @@ struct pxa_rtc { spinlock_t lock; /* Protects this structure */ }; + static u32 ryxr_calc(struct rtc_time *tm) { return ((tm->tm_year + 1900) << RYxR_YEAR_S) @@ -100,7 +105,10 @@ static u32 ryxr_calc(struct rtc_time *tm) static u32 rdxr_calc(struct rtc_time *tm) { - return (tm->tm_hour << RDxR_HOUR_S) | (tm->tm_min << RDxR_MIN_S) + return ((((tm->tm_mday + 6) / 7) << RDxR_WOM_S) & RDxR_WOM_MASK) + | (((tm->tm_wday + 1) << RDxR_DOW_S) & RDxR_DOW_MASK) + | (tm->tm_hour << RDxR_HOUR_S) + | (tm->tm_min << RDxR_MIN_S) | tm->tm_sec; } @@ -109,6 +117,7 @@ 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_wday = ((rycr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1; 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; @@ -300,8 +309,6 @@ static int pxa_rtc_proc(struct device *dev, struct seq_file *seq) } static const struct rtc_class_ops pxa_rtc_ops = { - .open = pxa_rtc_open, - .release = pxa_rtc_release, .read_time = pxa_rtc_read_time, .set_time = pxa_rtc_set_time, .read_alarm = pxa_rtc_read_alarm, @@ -341,7 +348,7 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) dev_err(dev, "No alarm IRQ resource defined\n"); goto err_ress; } - + pxa_rtc_open(dev); ret = -ENOMEM; pxa_rtc->base = ioremap(pxa_rtc->ress->start, resource_size(pxa_rtc->ress)); @@ -387,6 +394,9 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev) { struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + pxa_rtc_release(dev); + rtc_device_unregister(pxa_rtc->rtc); spin_lock_irq(&pxa_rtc->lock); @@ -444,10 +454,7 @@ static struct platform_driver pxa_rtc_driver = { 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; + return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe); } static void __exit pxa_rtc_exit(void) diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 2c183ebff715..7726f4a4f2d0 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -119,7 +119,7 @@ static const struct rtc_class_ops r9701_rtc_ops = { .set_time = r9701_set_datetime, }; -static int __devinit r9701_probe(struct spi_device *spi) +static int r9701_probe(struct spi_device *spi) { struct rtc_device *rtc; struct rtc_time dt; @@ -164,7 +164,7 @@ static int __devinit r9701_probe(struct spi_device *spi) return 0; } -static int __devexit r9701_remove(struct spi_device *spi) +static int r9701_remove(struct spi_device *spi) { struct rtc_device *rtc = dev_get_drvdata(&spi->dev); @@ -178,7 +178,7 @@ static struct spi_driver r9701_driver = { .owner = THIS_MODULE, }, .probe = r9701_probe, - .remove = __devexit_p(r9701_remove), + .remove = r9701_remove, }; module_spi_driver(r9701_driver); diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c index cdb140c29c56..eb3194d664a8 100644 --- a/drivers/rtc/rtc-rc5t583.c +++ b/drivers/rtc/rtc-rc5t583.c @@ -211,7 +211,7 @@ static const struct rtc_class_ops rc5t583_rtc_ops = { .alarm_irq_enable = rc5t583_rtc_alarm_irq_enable, }; -static int __devinit rc5t583_rtc_probe(struct platform_device *pdev) +static int rc5t583_rtc_probe(struct platform_device *pdev) { struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); struct rc5t583_rtc *ricoh_rtc; @@ -271,7 +271,7 @@ static int __devinit rc5t583_rtc_probe(struct platform_device *pdev) * Disable rc5t583 RTC interrupts. * Sets status flag to free. */ -static int __devexit rc5t583_rtc_remove(struct platform_device *pdev) +static int rc5t583_rtc_remove(struct platform_device *pdev) { struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(&pdev->dev); @@ -317,7 +317,7 @@ static const struct dev_pm_ops rc5t583_rtc_pm_ops = { static struct platform_driver rc5t583_rtc_driver = { .probe = rc5t583_rtc_probe, - .remove = __devexit_p(rc5t583_rtc_remove), + .remove = rc5t583_rtc_remove, .driver = { .owner = THIS_MODULE, .name = "rtc-rc5t583", diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index e3ff179b99ca..d98ea5b759c8 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -39,6 +39,8 @@ * 1.13 Nobuhiro Iwamatsu: Updata driver. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/err.h> #include <linux/rtc.h> @@ -352,8 +354,7 @@ static void rs5c313_check_xstp_bit(void) tm.tm_year = 2000 - 1900; rs5c313_rtc_set_time(NULL, &tm); - printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to " - "1 Jan 2000\n"); + pr_err("invalid value, resetting to 1 Jan 2000\n"); } RS5C313_CEDISABLE; ndelay(700); /* CE:L */ @@ -377,7 +378,7 @@ static int rs5c313_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit rs5c313_rtc_remove(struct platform_device *pdev) +static int rs5c313_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata( pdev ); @@ -392,7 +393,7 @@ static struct platform_driver rs5c313_rtc_platform_driver = { .owner = THIS_MODULE, }, .probe = rs5c313_rtc_probe, - .remove = __devexit_p( rs5c313_rtc_remove ), + .remove = rs5c313_rtc_remove, }; static int __init rs5c313_rtc_init(void) diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index fd5c7af04ae5..72ef10be8662 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -152,7 +152,7 @@ static const struct rtc_class_ops rs5c348_rtc_ops = { static struct spi_driver rs5c348_driver; -static int __devinit rs5c348_probe(struct spi_device *spi) +static int rs5c348_probe(struct spi_device *spi) { int ret; struct rtc_device *rtc; @@ -218,7 +218,7 @@ static int __devinit rs5c348_probe(struct spi_device *spi) return ret; } -static int __devexit rs5c348_remove(struct spi_device *spi) +static int rs5c348_remove(struct spi_device *spi) { struct rs5c348_plat_data *pdata = spi->dev.platform_data; struct rtc_device *rtc = pdata->rtc; @@ -235,7 +235,7 @@ static struct spi_driver rs5c348_driver = { .owner = THIS_MODULE, }, .probe = rs5c348_probe, - .remove = __devexit_p(rs5c348_remove), + .remove = rs5c348_remove, }; module_spi_driver(rs5c348_driver); diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 76f565ae384d..581739f40097 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -311,8 +311,7 @@ static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) buf &= ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf) < 0) { - printk(KERN_WARNING "%s: can't update alarm\n", - rs5c->rtc->name); + dev_warn(dev, "can't update alarm\n"); status = -EIO; } else rs5c->regs[RS5C_REG_CTRL1] = buf; @@ -381,7 +380,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) { - pr_debug("%s: can't disable alarm\n", rs5c->rtc->name); + dev_dbg(dev, "can't disable alarm\n"); return -EIO; } rs5c->regs[RS5C_REG_CTRL1] = buf[0]; @@ -395,7 +394,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) for (i = 0; i < sizeof(buf); i++) { addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) { - pr_debug("%s: can't set alarm time\n", rs5c->rtc->name); + dev_dbg(dev, "can't set alarm time\n"); return -EIO; } } @@ -405,8 +404,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) - printk(KERN_WARNING "%s: can't enable alarm\n", - rs5c->rtc->name); + dev_warn(dev, "can't enable alarm\n"); rs5c->regs[RS5C_REG_CTRL1] = buf[0]; } diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 0fbe57b2f6d2..f8ee8ad7825e 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -385,8 +385,8 @@ static struct i2c_device_id rv3029c2_id[] = { }; MODULE_DEVICE_TABLE(i2c, rv3029c2_id); -static int __devinit -rv3029c2_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int rv3029c2_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct rtc_device *rtc; int rc = 0; @@ -418,7 +418,7 @@ exit_unregister: return rc; } -static int __devexit rv3029c2_remove(struct i2c_client *client) +static int rv3029c2_remove(struct i2c_client *client) { struct rtc_device *rtc = i2c_get_clientdata(client); @@ -432,7 +432,7 @@ static struct i2c_driver rv3029c2_driver = { .name = "rtc-rv3029c2", }, .probe = rv3029c2_probe, - .remove = __devexit_p(rv3029c2_remove), + .remove = rv3029c2_remove, .id_table = rv3029c2_id, }; diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c new file mode 100644 index 000000000000..599ec73ec886 --- /dev/null +++ b/drivers/rtc/rtc-rx4581.c @@ -0,0 +1,314 @@ +/* drivers/rtc/rtc-rx4581.c + * + * written by Torben Hohn <torbenh@linutronix.de> + * + * Based on: + * drivers/rtc/rtc-max6902.c + * + * Copyright (C) 2006 8D Technologies inc. + * Copyright (C) 2004 Compulab Ltd. + * + * 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. + * + * Driver for MAX6902 spi RTC + * + * and based on: + * drivers/rtc/rtc-rx8581.c + * + * An I2C driver for the Epson RX8581 RTC + * + * Author: Martyn Welch <martyn.welch@ge.com> + * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * 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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/rtc.h> +#include <linux/spi/spi.h> +#include <linux/bcd.h> + +#define RX4581_REG_SC 0x00 /* Second in BCD */ +#define RX4581_REG_MN 0x01 /* Minute in BCD */ +#define RX4581_REG_HR 0x02 /* Hour in BCD */ +#define RX4581_REG_DW 0x03 /* Day of Week */ +#define RX4581_REG_DM 0x04 /* Day of Month in BCD */ +#define RX4581_REG_MO 0x05 /* Month in BCD */ +#define RX4581_REG_YR 0x06 /* Year in BCD */ +#define RX4581_REG_RAM 0x07 /* RAM */ +#define RX4581_REG_AMN 0x08 /* Alarm Min in BCD*/ +#define RX4581_REG_AHR 0x09 /* Alarm Hour in BCD */ +#define RX4581_REG_ADM 0x0A +#define RX4581_REG_ADW 0x0A +#define RX4581_REG_TMR0 0x0B +#define RX4581_REG_TMR1 0x0C +#define RX4581_REG_EXT 0x0D /* Extension Register */ +#define RX4581_REG_FLAG 0x0E /* Flag Register */ +#define RX4581_REG_CTRL 0x0F /* Control Register */ + + +/* Flag Register bit definitions */ +#define RX4581_FLAG_UF 0x20 /* Update */ +#define RX4581_FLAG_TF 0x10 /* Timer */ +#define RX4581_FLAG_AF 0x08 /* Alarm */ +#define RX4581_FLAG_VLF 0x02 /* Voltage Low */ + +/* Control Register bit definitions */ +#define RX4581_CTRL_UIE 0x20 /* Update Interrupt Enable */ +#define RX4581_CTRL_TIE 0x10 /* Timer Interrupt Enable */ +#define RX4581_CTRL_AIE 0x08 /* Alarm Interrupt Enable */ +#define RX4581_CTRL_STOP 0x02 /* STOP bit */ +#define RX4581_CTRL_RESET 0x01 /* RESET bit */ + +static int rx4581_set_reg(struct device *dev, unsigned char address, + unsigned char data) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char buf[2]; + + /* high nibble must be '0' to write */ + buf[0] = address & 0x0f; + buf[1] = data; + + return spi_write_then_read(spi, buf, 2, NULL, 0); +} + +static int rx4581_get_reg(struct device *dev, unsigned char address, + unsigned char *data) +{ + struct spi_device *spi = to_spi_device(dev); + + /* Set MSB to indicate read */ + *data = address | 0x80; + + return spi_write_then_read(spi, data, 1, data, 1); +} + +/* + * 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 rx4581_get_datetime(struct device *dev, struct rtc_time *tm) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char date[7]; + unsigned char data; + int 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. + */ + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); + if (err != 0) { + dev_err(dev, "Unable to read device flags\n"); + return -EIO; + } + + do { + /* If update flag set, clear it */ + if (data & RX4581_FLAG_UF) { + err = rx4581_set_reg(dev, + RX4581_REG_FLAG, (data & ~RX4581_FLAG_UF)); + if (err != 0) { + dev_err(dev, "Unable to write device " + "flags\n"); + return -EIO; + } + } + + /* Now read time and date */ + date[0] = 0x80; + err = spi_write_then_read(spi, date, 1, date, 7); + if (err < 0) { + dev_err(dev, "Unable to read date\n"); + return -EIO; + } + + /* Check flag register */ + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); + if (err != 0) { + dev_err(dev, "Unable to read device flags\n"); + return -EIO; + } + } while (data & RX4581_FLAG_UF); + + if (data & RX4581_FLAG_VLF) + dev_info(dev, + "low voltage detected, date/time is not reliable.\n"); + + dev_dbg(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[RX4581_REG_SC] & 0x7F); + tm->tm_min = bcd2bin(date[RX4581_REG_MN] & 0x7F); + tm->tm_hour = bcd2bin(date[RX4581_REG_HR] & 0x3F); /* rtc hr 0-23 */ + tm->tm_wday = ilog2(date[RX4581_REG_DW] & 0x7F); + tm->tm_mday = bcd2bin(date[RX4581_REG_DM] & 0x3F); + tm->tm_mon = bcd2bin(date[RX4581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(date[RX4581_REG_YR]); + if (tm->tm_year < 70) + tm->tm_year += 100; /* assume we are in 1970...2069 */ + + + dev_dbg(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(dev, "retrieved date/time is not valid.\n"); + + return err; +} + +static int rx4581_set_datetime(struct device *dev, struct rtc_time *tm) +{ + struct spi_device *spi = to_spi_device(dev); + int err; + unsigned char buf[8], data; + + dev_dbg(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); + + buf[0] = 0x00; + /* hours, minutes and seconds */ + buf[RX4581_REG_SC+1] = bin2bcd(tm->tm_sec); + buf[RX4581_REG_MN+1] = bin2bcd(tm->tm_min); + buf[RX4581_REG_HR+1] = bin2bcd(tm->tm_hour); + + buf[RX4581_REG_DM+1] = bin2bcd(tm->tm_mday); + + /* month, 1 - 12 */ + buf[RX4581_REG_MO+1] = bin2bcd(tm->tm_mon + 1); + + /* year and century */ + buf[RX4581_REG_YR+1] = bin2bcd(tm->tm_year % 100); + buf[RX4581_REG_DW+1] = (0x1 << tm->tm_wday); + + /* Stop the clock */ + err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data); + if (err != 0) { + dev_err(dev, "Unable to read control register\n"); + return -EIO; + } + + err = rx4581_set_reg(dev, RX4581_REG_CTRL, + (data | RX4581_CTRL_STOP)); + if (err != 0) { + dev_err(dev, "Unable to write control register\n"); + return -EIO; + } + + /* write register's data */ + err = spi_write_then_read(spi, buf, 8, NULL, 0); + if (err != 0) { + dev_err(dev, "Unable to write to date registers\n"); + return -EIO; + } + + /* get VLF and clear it */ + err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data); + if (err != 0) { + dev_err(dev, "Unable to read flag register\n"); + return -EIO; + } + + err = rx4581_set_reg(dev, RX4581_REG_FLAG, + (data & ~(RX4581_FLAG_VLF))); + if (err != 0) { + dev_err(dev, "Unable to write flag register\n"); + return -EIO; + } + + /* Restart the clock */ + err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data); + if (err != 0) { + dev_err(dev, "Unable to read control register\n"); + return -EIO; + } + + err = rx4581_set_reg(dev, RX4581_REG_CTRL, + (data & ~(RX4581_CTRL_STOP))); + if (err != 0) { + dev_err(dev, "Unable to write control register\n"); + return -EIO; + } + + return 0; +} + +static const struct rtc_class_ops rx4581_rtc_ops = { + .read_time = rx4581_get_datetime, + .set_time = rx4581_set_datetime, +}; + +static int rx4581_probe(struct spi_device *spi) +{ + struct rtc_device *rtc; + unsigned char tmp; + int res; + + res = rx4581_get_reg(&spi->dev, RX4581_REG_SC, &tmp); + if (res != 0) + return res; + + rtc = rtc_device_register("rx4581", + &spi->dev, &rx4581_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + dev_set_drvdata(&spi->dev, rtc); + return 0; +} + +static int rx4581_remove(struct spi_device *spi) +{ + struct rtc_device *rtc = dev_get_drvdata(&spi->dev); + + rtc_device_unregister(rtc); + return 0; +} + +static const struct spi_device_id rx4581_id[] = { + { "rx4581", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, rx4581_id); + +static struct spi_driver rx4581_driver = { + .driver = { + .name = "rtc-rx4581", + .owner = THIS_MODULE, + }, + .probe = rx4581_probe, + .remove = rx4581_remove, + .id_table = rx4581_id, +}; + +module_spi_driver(rx4581_driver); + +MODULE_DESCRIPTION("rx4581 spi RTC driver"); +MODULE_AUTHOR("Torben Hohn"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-rx4581"); diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 0de902dc1cd5..0722d36b9c9a 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -534,8 +534,8 @@ static void rx8025_sysfs_unregister(struct device *dev) device_remove_file(dev, &dev_attr_clock_adjust_ppb); } -static int __devinit rx8025_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rx8025_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rx8025_data *rx8025; @@ -614,7 +614,7 @@ errout: return err; } -static int __devexit rx8025_remove(struct i2c_client *client) +static int rx8025_remove(struct i2c_client *client) { struct rx8025_data *rx8025 = i2c_get_clientdata(client); struct mutex *lock = &rx8025->rtc->ops_lock; @@ -640,7 +640,7 @@ static struct i2c_driver rx8025_driver = { .owner = THIS_MODULE, }, .probe = rx8025_probe, - .remove = __devexit_p(rx8025_remove), + .remove = rx8025_remove, .id_table = rx8025_id, }; diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index d84825124a7a..b0c272658fa2 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -228,8 +228,8 @@ static const struct rtc_class_ops rx8581_rtc_ops = { .set_time = rx8581_rtc_set_time, }; -static int __devinit rx8581_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rx8581_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct rtc_device *rtc; @@ -251,7 +251,7 @@ static int __devinit rx8581_probe(struct i2c_client *client, return 0; } -static int __devexit rx8581_remove(struct i2c_client *client) +static int rx8581_remove(struct i2c_client *client) { struct rtc_device *rtc = i2c_get_clientdata(client); @@ -272,7 +272,7 @@ static struct i2c_driver rx8581_driver = { .owner = THIS_MODULE, }, .probe = rx8581_probe, - .remove = __devexit_p(rx8581_remove), + .remove = rx8581_remove, .id_table = rx8581_id, }; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 77823d21d314..fb994e9ddc15 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -47,8 +47,6 @@ struct s3c_rtc_drv_data { /* I have yet to find an S3C implementation with more than one * of these rtc blocks in */ -static struct resource *s3c_rtc_mem; - static struct clk *rtc_clk; static void __iomem *s3c_rtc_base; static int s3c_rtc_alarmno = NO_IRQ; @@ -117,7 +115,7 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) { unsigned int tmp; - pr_debug("%s: aie=%d\n", __func__, enabled); + dev_dbg(dev, "%s: aie=%d\n", __func__, enabled); clk_enable(rtc_clk); tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; @@ -186,7 +184,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR); rtc_tm->tm_sec = readb(base + S3C2410_RTCSEC); - /* the only way to work out wether the system was mid-update + /* the only way to work out whether the system was mid-update * when we read it is to check the second counter, and if it * is zero, then we re-try the entire read */ @@ -205,7 +203,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_year += 100; - pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); @@ -220,7 +218,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) void __iomem *base = s3c_rtc_base; int year = tm->tm_year - 100; - pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -261,7 +259,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; - pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", alm_en, 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); @@ -312,7 +310,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned int alrm_en; clk_enable(rtc_clk); - pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", + dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -335,7 +333,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR); } - pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en); + dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en); writeb(alrm_en, base + S3C2410_RTCALM); @@ -423,25 +421,17 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) clk_disable(rtc_clk); } -static int __devexit s3c_rtc_remove(struct platform_device *dev) +static int s3c_rtc_remove(struct platform_device *dev) { struct rtc_device *rtc = platform_get_drvdata(dev); - free_irq(s3c_rtc_alarmno, rtc); - free_irq(s3c_rtc_tickno, rtc); - platform_set_drvdata(dev, NULL); rtc_device_unregister(rtc); s3c_rtc_setaie(&dev->dev, 0); - clk_put(rtc_clk); rtc_clk = NULL; - iounmap(s3c_rtc_base); - release_resource(s3c_rtc_mem); - kfree(s3c_rtc_mem); - return 0; } @@ -461,7 +451,7 @@ static inline int s3c_rtc_get_driver_data(struct platform_device *pdev) return platform_get_device_id(pdev)->driver_data; } -static int __devinit s3c_rtc_probe(struct platform_device *pdev) +static int s3c_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct rtc_time rtc_tm; @@ -469,7 +459,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) int ret; int tmp; - pr_debug("%s: probe=%p\n", __func__, pdev); + dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev); /* find the IRQs */ @@ -485,7 +475,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) return s3c_rtc_alarmno; } - pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", + dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n", s3c_rtc_tickno, s3c_rtc_alarmno); /* get the memory region */ @@ -496,28 +486,16 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) return -ENOENT; } - s3c_rtc_mem = request_mem_region(res->start, resource_size(res), - pdev->name); - - if (s3c_rtc_mem == NULL) { - dev_err(&pdev->dev, "failed to reserve memory region\n"); - ret = -ENOENT; - goto err_nores; - } - - s3c_rtc_base = ioremap(res->start, resource_size(res)); - if (s3c_rtc_base == NULL) { - dev_err(&pdev->dev, "failed ioremap()\n"); - ret = -EINVAL; - goto err_nomap; - } + s3c_rtc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(s3c_rtc_base)) + return PTR_ERR(s3c_rtc_base); - rtc_clk = clk_get(&pdev->dev, "rtc"); + rtc_clk = devm_clk_get(&pdev->dev, "rtc"); if (IS_ERR(rtc_clk)) { dev_err(&pdev->dev, "failed to find rtc clock source\n"); ret = PTR_ERR(rtc_clk); rtc_clk = NULL; - goto err_clk; + return ret; } clk_enable(rtc_clk); @@ -526,7 +504,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); - pr_debug("s3c2410_rtc: RTCCON=%02x\n", + dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", readw(s3c_rtc_base + S3C2410_RTCCON)); device_init_wakeup(&pdev->dev, 1); @@ -576,28 +554,24 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_setfreq(&pdev->dev, 1); - ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq, + ret = devm_request_irq(&pdev->dev, s3c_rtc_alarmno, s3c_rtc_alarmirq, 0, "s3c2410-rtc alarm", rtc); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret); goto err_alarm_irq; } - ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq, + ret = devm_request_irq(&pdev->dev, s3c_rtc_tickno, s3c_rtc_tickirq, 0, "s3c2410-rtc tick", rtc); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret); - free_irq(s3c_rtc_alarmno, rtc); - goto err_tick_irq; + goto err_alarm_irq; } clk_disable(rtc_clk); return 0; - err_tick_irq: - free_irq(s3c_rtc_alarmno, rtc); - err_alarm_irq: platform_set_drvdata(pdev, NULL); rtc_device_unregister(rtc); @@ -605,15 +579,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) err_nortc: s3c_rtc_enable(pdev, 0); clk_disable(rtc_clk); - clk_put(rtc_clk); - err_clk: - iounmap(s3c_rtc_base); - - err_nomap: - release_resource(s3c_rtc_mem); - - err_nores: return ret; } @@ -695,8 +661,6 @@ static const struct of_device_id s3c_rtc_dt_match[] = { {}, }; MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); -#else -#define s3c_rtc_dt_match NULL #endif static struct platform_device_id s3c_rtc_driver_ids[] = { @@ -720,14 +684,14 @@ MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids); static struct platform_driver s3c_rtc_driver = { .probe = s3c_rtc_probe, - .remove = __devexit_p(s3c_rtc_remove), + .remove = s3c_rtc_remove, .suspend = s3c_rtc_suspend, .resume = s3c_rtc_resume, .id_table = s3c_rtc_driver_ids, .driver = { .name = "s3c-rtc", .owner = THIS_MODULE, - .of_match_table = s3c_rtc_dt_match, + .of_match_table = of_match_ptr(s3c_rtc_dt_match), }, }; diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 50a5c4adee48..5ec5036df0bc 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -108,9 +108,6 @@ static int sa1100_rtc_open(struct device *dev) struct rtc_device *rtc = info->rtc; int ret; - ret = clk_prepare_enable(info->clk); - if (ret) - goto fail_clk; ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz); @@ -130,7 +127,6 @@ static int sa1100_rtc_open(struct device *dev) free_irq(info->irq_1hz, dev); fail_ui: clk_disable_unprepare(info->clk); - fail_clk: return ret; } @@ -144,7 +140,6 @@ static void sa1100_rtc_release(struct device *dev) free_irq(info->irq_alarm, dev); free_irq(info->irq_1hz, dev); - clk_disable_unprepare(info->clk); } static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) @@ -253,6 +248,9 @@ static int sa1100_rtc_probe(struct platform_device *pdev) spin_lock_init(&info->lock); platform_set_drvdata(pdev, info); + ret = clk_prepare_enable(info->clk); + if (ret) + goto err_enable_clk; /* * 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. @@ -305,6 +303,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) return 0; err_dev: + clk_disable_unprepare(info->clk); +err_enable_clk: platform_set_drvdata(pdev, NULL); clk_put(info->clk); err_clk: @@ -318,6 +318,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) if (info) { rtc_device_unregister(info->rtc); + clk_disable_unprepare(info->clk); clk_put(info->clk); platform_set_drvdata(pdev, NULL); kfree(info); @@ -349,12 +350,14 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = { }; #endif +#ifdef CONFIG_OF static struct of_device_id sa1100_rtc_dt_ids[] = { { .compatible = "mrvl,sa1100-rtc", }, { .compatible = "mrvl,mmp-rtc", }, {} }; MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); +#endif static struct platform_driver sa1100_rtc_driver = { .probe = sa1100_rtc_probe, @@ -364,7 +367,7 @@ static struct platform_driver sa1100_rtc_driver = { #ifdef CONFIG_PM .pm = &sa1100_rtc_pm_ops, #endif - .of_match_table = sa1100_rtc_dt_ids, + .of_match_table = of_match_ptr(sa1100_rtc_dt_ids), }, }; diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 3c0da333f465..f7d90703db5e 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -241,7 +241,7 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) return events ? IRQ_HANDLED : IRQ_NONE; } -static int __devinit snvs_rtc_probe(struct platform_device *pdev) +static int snvs_rtc_probe(struct platform_device *pdev) { struct snvs_rtc_data *data; struct resource *res; @@ -252,9 +252,9 @@ static int __devinit snvs_rtc_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->ioaddr = devm_request_and_ioremap(&pdev->dev, res); - if (!data->ioaddr) - return -EADDRNOTAVAIL; + data->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->ioaddr)) + return PTR_ERR(data->ioaddr); data->irq = platform_get_irq(pdev, 0); if (data->irq < 0) @@ -294,7 +294,7 @@ static int __devinit snvs_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit snvs_rtc_remove(struct platform_device *pdev) +static int snvs_rtc_remove(struct platform_device *pdev) { struct snvs_rtc_data *data = platform_get_drvdata(pdev); @@ -327,7 +327,7 @@ static int snvs_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume); -static const struct of_device_id __devinitconst snvs_dt_ids[] = { +static const struct of_device_id snvs_dt_ids[] = { { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, { /* sentinel */ } }; @@ -338,10 +338,10 @@ static struct platform_driver snvs_rtc_driver = { .name = "snvs_rtc", .owner = THIS_MODULE, .pm = &snvs_rtc_pm_ops, - .of_match_table = snvs_dt_ids, + .of_match_table = of_match_ptr(snvs_dt_ids), }, .probe = snvs_rtc_probe, - .remove = __devexit_p(snvs_rtc_remove), + .remove = snvs_rtc_remove, }; module_platform_driver(snvs_rtc_driver); diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index bb507d23f6ce..a18c3192ed40 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -351,7 +351,7 @@ static struct rtc_class_ops spear_rtc_ops = { .alarm_irq_enable = spear_alarm_irq_enable, }; -static int __devinit spear_rtc_probe(struct platform_device *pdev) +static int spear_rtc_probe(struct platform_device *pdev) { struct resource *res; struct spear_rtc_config *config; @@ -363,35 +363,40 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no resource defined\n"); return -EBUSY; } - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "rtc region already claimed\n"); - return -EBUSY; - } - config = kzalloc(sizeof(*config), GFP_KERNEL); + config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); if (!config) { dev_err(&pdev->dev, "out of memory\n"); - status = -ENOMEM; - goto err_release_region; + return -ENOMEM; } - config->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(config->clk)) { - status = PTR_ERR(config->clk); - goto err_kfree; + /* alarm irqs */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no update irq?\n"); + return irq; } - status = clk_enable(config->clk); - if (status < 0) - goto err_clk_put; - - config->ioaddr = ioremap(res->start, resource_size(res)); - if (!config->ioaddr) { - dev_err(&pdev->dev, "ioremap fail\n"); - status = -ENOMEM; - goto err_disable_clock; + status = devm_request_irq(&pdev->dev, irq, spear_rtc_irq, 0, pdev->name, + config); + if (status) { + dev_err(&pdev->dev, "Alarm interrupt IRQ%d already claimed\n", + irq); + return status; } + config->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(config->ioaddr)) + return PTR_ERR(config->ioaddr); + + config->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(config->clk)) + return PTR_ERR(config->clk); + + status = clk_prepare_enable(config->clk); + if (status < 0) + return status; + spin_lock_init(&config->lock); platform_set_drvdata(pdev, config); @@ -401,67 +406,31 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "can't register RTC device, err %ld\n", PTR_ERR(config->rtc)); status = PTR_ERR(config->rtc); - goto err_iounmap; - } - - /* alarm irqs */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no update irq?\n"); - status = irq; - goto err_clear_platdata; + goto err_disable_clock; } - status = request_irq(irq, spear_rtc_irq, 0, pdev->name, config); - if (status) { - dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \ - claimed\n", irq); - goto err_clear_platdata; - } + config->rtc->uie_unsupported = 1; if (!device_can_wakeup(&pdev->dev)) device_init_wakeup(&pdev->dev, 1); return 0; -err_clear_platdata: - platform_set_drvdata(pdev, NULL); - rtc_device_unregister(config->rtc); -err_iounmap: - iounmap(config->ioaddr); err_disable_clock: - clk_disable(config->clk); -err_clk_put: - clk_put(config->clk); -err_kfree: - kfree(config); -err_release_region: - release_mem_region(res->start, resource_size(res)); + platform_set_drvdata(pdev, NULL); + clk_disable_unprepare(config->clk); return status; } -static int __devexit spear_rtc_remove(struct platform_device *pdev) +static int spear_rtc_remove(struct platform_device *pdev) { struct spear_rtc_config *config = platform_get_drvdata(pdev); - int irq; - struct resource *res; - /* leave rtc running, but disable irqs */ + rtc_device_unregister(config->rtc); spear_rtc_disable_interrupt(config); + clk_disable_unprepare(config->clk); device_init_wakeup(&pdev->dev, 0); - irq = platform_get_irq(pdev, 0); - if (irq) - free_irq(irq, pdev); - clk_disable(config->clk); - clk_put(config->clk); - iounmap(config->ioaddr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - platform_set_drvdata(pdev, NULL); - rtc_device_unregister(config->rtc); - kfree(config); return 0; } @@ -528,7 +497,7 @@ MODULE_DEVICE_TABLE(of, spear_rtc_id_table); static struct platform_driver spear_rtc_driver = { .probe = spear_rtc_probe, - .remove = __devexit_p(spear_rtc_remove), + .remove = spear_rtc_remove, .suspend = spear_rtc_suspend, .resume = spear_rtc_resume, .shutdown = spear_rtc_shutdown, diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index 279f5cfa691a..7e4a6f65cb91 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -285,7 +285,7 @@ static struct bin_attribute stk17ta8_nvram_attr = { .write = stk17ta8_nvram_write, }; -static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) +static int stk17ta8_rtc_probe(struct platform_device *pdev) { struct resource *res; unsigned int cal; @@ -347,7 +347,7 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) return ret; } -static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) +static int stk17ta8_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); @@ -363,7 +363,7 @@ MODULE_ALIAS("platform:stk17ta8"); static struct platform_driver stk17ta8_rtc_driver = { .probe = stk17ta8_rtc_probe, - .remove = __devexit_p(stk17ta8_rtc_remove), + .remove = stk17ta8_rtc_remove, .driver = { .name = "stk17ta8", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 739ef55694f4..98f0d3c30738 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -26,6 +26,9 @@ #include <linux/rtc.h> #include <linux/slab.h> #include <linux/of_device.h> +#include <linux/of.h> +#include <linux/stmp_device.h> +#include <linux/stmp3xxx_rtc_wdt.h> #include <mach/common.h> @@ -35,6 +38,7 @@ #define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 #define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 #define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 +#define STMP3XXX_RTC_CTRL_WATCHDOGEN 0x00000010 #define STMP3XXX_RTC_STAT 0x10 #define STMP3XXX_RTC_STAT_STALE_SHIFT 16 @@ -44,6 +48,8 @@ #define STMP3XXX_RTC_ALARM 0x40 +#define STMP3XXX_RTC_WATCHDOG 0x50 + #define STMP3XXX_RTC_PERSISTENT0 0x60 #define STMP3XXX_RTC_PERSISTENT0_SET 0x64 #define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 @@ -51,12 +57,70 @@ #define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 #define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 +#define STMP3XXX_RTC_PERSISTENT1 0x70 +/* missing bitmask in headers */ +#define STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER 0x80000000 + struct stmp3xxx_rtc_data { struct rtc_device *rtc; void __iomem *io; int irq_alarm; }; +#if IS_ENABLED(CONFIG_STMP3XXX_RTC_WATCHDOG) +/** + * stmp3xxx_wdt_set_timeout - configure the watchdog inside the STMP3xxx RTC + * @dev: the parent device of the watchdog (= the RTC) + * @timeout: the desired value for the timeout register of the watchdog. + * 0 disables the watchdog + * + * The watchdog needs one register and two bits which are in the RTC domain. + * To handle the resource conflict, the RTC driver will create another + * platform_device for the watchdog driver as a child of the RTC device. + * The watchdog driver is passed the below accessor function via platform_data + * to configure the watchdog. Locking is not needed because accessing SET/CLR + * registers is atomic. + */ + +static void stmp3xxx_wdt_set_timeout(struct device *dev, u32 timeout) +{ + struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); + + if (timeout) { + writel(timeout, rtc_data->io + STMP3XXX_RTC_WATCHDOG); + writel(STMP3XXX_RTC_CTRL_WATCHDOGEN, + rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_SET); + writel(STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER, + rtc_data->io + STMP3XXX_RTC_PERSISTENT1 + STMP_OFFSET_REG_SET); + } else { + writel(STMP3XXX_RTC_CTRL_WATCHDOGEN, + rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); + writel(STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER, + rtc_data->io + STMP3XXX_RTC_PERSISTENT1 + STMP_OFFSET_REG_CLR); + } +} + +static struct stmp3xxx_wdt_pdata wdt_pdata = { + .wdt_set_timeout = stmp3xxx_wdt_set_timeout, +}; + +static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev) +{ + struct platform_device *wdt_pdev = + platform_device_alloc("stmp3xxx_rtc_wdt", rtc_pdev->id); + + if (wdt_pdev) { + wdt_pdev->dev.parent = &rtc_pdev->dev; + wdt_pdev->dev.platform_data = &wdt_pdata; + platform_device_add(wdt_pdev); + } +} +#else +static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev) +{ +} +#endif /* CONFIG_STMP3XXX_RTC_WATCHDOG */ + static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) { /* @@ -232,6 +296,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) goto out_irq_alarm; } + stmp3xxx_wdt_register(pdev); return 0; out_irq_alarm: @@ -280,7 +345,7 @@ static struct platform_driver stmp3xxx_rtcdrv = { .driver = { .name = "stmp3xxx-rtc", .owner = THIS_MODULE, - .of_match_table = rtc_dt_ids, + .of_match_table = of_match_ptr(rtc_dt_ids), }, }; diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c index 5b2261052a65..59b5c2dcb58c 100644 --- a/drivers/rtc/rtc-sun4v.c +++ b/drivers/rtc/rtc-sun4v.c @@ -3,6 +3,8 @@ * Copyright (C) 2008 David S. Miller <davem@davemloft.net> */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> @@ -26,10 +28,10 @@ retry: udelay(100); goto retry; } - printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); + pr_warn("tod_get() timed out.\n"); return 0; } - printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); + pr_warn("tod_get() not supported.\n"); return 0; } @@ -53,10 +55,10 @@ retry: udelay(100); goto retry; } - printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); + pr_warn("tod_set() timed out.\n"); return -EAGAIN; } - printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); + pr_warn("tod_set() not supported.\n"); return -EOPNOTSUPP; } diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index c006025cecc8..7c033756d6b5 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -303,7 +303,13 @@ static struct rtc_class_ops tegra_rtc_ops = { .alarm_irq_enable = tegra_rtc_alarm_irq_enable, }; -static int __devinit tegra_rtc_probe(struct platform_device *pdev) +static const struct of_device_id tegra_rtc_dt_match[] = { + { .compatible = "nvidia,tegra20-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match); + +static int tegra_rtc_probe(struct platform_device *pdev) { struct tegra_rtc_info *info; struct resource *res; @@ -321,11 +327,9 @@ static int __devinit tegra_rtc_probe(struct platform_device *pdev) return -EBUSY; } - info->rtc_base = devm_request_and_ioremap(&pdev->dev, res); - if (!info->rtc_base) { - dev_err(&pdev->dev, "Unable to request mem region and grab IOs for device.\n"); - return -EBUSY; - } + info->rtc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->rtc_base)) + return PTR_ERR(info->rtc_base); info->tegra_rtc_irq = platform_get_irq(pdev, 0); if (info->tegra_rtc_irq <= 0) @@ -375,7 +379,7 @@ err_dev_unreg: return ret; } -static int __devexit tegra_rtc_remove(struct platform_device *pdev) +static int tegra_rtc_remove(struct platform_device *pdev) { struct tegra_rtc_info *info = platform_get_drvdata(pdev); @@ -435,11 +439,12 @@ static void tegra_rtc_shutdown(struct platform_device *pdev) MODULE_ALIAS("platform:tegra_rtc"); static struct platform_driver tegra_rtc_driver = { - .remove = __devexit_p(tegra_rtc_remove), + .remove = tegra_rtc_remove, .shutdown = tegra_rtc_shutdown, .driver = { .name = "tegra_rtc", .owner = THIS_MODULE, + .of_match_table = tegra_rtc_dt_match, }, #ifdef CONFIG_PM .suspend = tegra_rtc_suspend, diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 7e96254bd365..b92e0f6383e6 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -119,7 +119,7 @@ err: return err; } -static int __devexit test_remove(struct platform_device *plat_dev) +static int test_remove(struct platform_device *plat_dev) { struct rtc_device *rtc = platform_get_drvdata(plat_dev); @@ -131,7 +131,7 @@ static int __devexit test_remove(struct platform_device *plat_dev) static struct platform_driver test_driver = { .probe = test_probe, - .remove = __devexit_p(test_remove), + .remove = test_remove, .driver = { .name = "rtc-test", .owner = THIS_MODULE, @@ -152,24 +152,24 @@ static int __init test_init(void) if ((test1 = platform_device_alloc("rtc-test", 1)) == NULL) { err = -ENOMEM; - goto exit_free_test0; + goto exit_put_test0; } if ((err = platform_device_add(test0))) - goto exit_free_test1; + goto exit_put_test1; if ((err = platform_device_add(test1))) - goto exit_device_unregister; + goto exit_del_test0; return 0; -exit_device_unregister: - platform_device_unregister(test0); +exit_del_test0: + platform_device_del(test0); -exit_free_test1: +exit_put_test1: platform_device_put(test1); -exit_free_test0: +exit_put_test0: platform_device_put(test0); exit_driver_unregister: diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c index eb65dafee66e..62db4841078b 100644 --- a/drivers/rtc/rtc-tile.c +++ b/drivers/rtc/rtc-tile.c @@ -76,7 +76,7 @@ static const struct rtc_class_ops tile_rtc_ops = { /* * Device probe routine. */ -static int __devinit tile_rtc_probe(struct platform_device *dev) +static int tile_rtc_probe(struct platform_device *dev) { struct rtc_device *rtc; @@ -94,7 +94,7 @@ static int __devinit tile_rtc_probe(struct platform_device *dev) /* * Device cleanup routine. */ -static int __devexit tile_rtc_remove(struct platform_device *dev) +static int tile_rtc_remove(struct platform_device *dev) { struct rtc_device *rtc = platform_get_drvdata(dev); @@ -112,7 +112,7 @@ static struct platform_driver tile_rtc_platform_driver = { .owner = THIS_MODULE, }, .probe = tile_rtc_probe, - .remove = __devexit_p(tile_rtc_remove), + .remove = tile_rtc_remove, }; /* diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c new file mode 100644 index 000000000000..aab4e8c93622 --- /dev/null +++ b/drivers/rtc/rtc-tps6586x.c @@ -0,0 +1,356 @@ +/* + * rtc-tps6586x.c: RTC driver for TI PMIC TPS6586X + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/tps6586x.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/rtc.h> +#include <linux/slab.h> + +#define RTC_CTRL 0xc0 +#define POR_RESET_N BIT(7) +#define OSC_SRC_SEL BIT(6) +#define RTC_ENABLE BIT(5) /* enables alarm */ +#define RTC_BUF_ENABLE BIT(4) /* 32 KHz buffer enable */ +#define PRE_BYPASS BIT(3) /* 0=1KHz or 1=32KHz updates */ +#define CL_SEL_MASK (BIT(2)|BIT(1)) +#define CL_SEL_POS 1 +#define RTC_ALARM1_HI 0xc1 +#define RTC_COUNT4 0xc6 + +/* start a PMU RTC access by reading the register prior to the RTC_COUNT4 */ +#define RTC_COUNT4_DUMMYREAD 0xc5 + +/*only 14-bits width in second*/ +#define ALM1_VALID_RANGE_IN_SEC 0x3FFF + +#define TPS6586X_RTC_CL_SEL_1_5PF 0x0 +#define TPS6586X_RTC_CL_SEL_6_5PF 0x1 +#define TPS6586X_RTC_CL_SEL_7_5PF 0x2 +#define TPS6586X_RTC_CL_SEL_12_5PF 0x3 + +struct tps6586x_rtc { + struct device *dev; + struct rtc_device *rtc; + int irq; + bool irq_en; + unsigned long long epoch_start; +}; + +static inline struct device *to_tps6586x_dev(struct device *dev) +{ + return dev->parent; +} + +static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct tps6586x_rtc *rtc = dev_get_drvdata(dev); + struct device *tps_dev = to_tps6586x_dev(dev); + unsigned long long ticks = 0; + unsigned long seconds; + u8 buff[6]; + int ret; + int i; + + ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD, sizeof(buff), buff); + if (ret < 0) { + dev_err(dev, "read counter failed with err %d\n", ret); + return ret; + } + + for (i = 1; i < sizeof(buff); i++) { + ticks <<= 8; + ticks |= buff[i]; + } + + seconds = ticks >> 10; + seconds += rtc->epoch_start; + rtc_time_to_tm(seconds, tm); + return rtc_valid_tm(tm); +} + +static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct tps6586x_rtc *rtc = dev_get_drvdata(dev); + struct device *tps_dev = to_tps6586x_dev(dev); + unsigned long long ticks; + unsigned long seconds; + u8 buff[5]; + int ret; + + rtc_tm_to_time(tm, &seconds); + if (seconds < rtc->epoch_start) { + dev_err(dev, "requested time unsupported\n"); + return -EINVAL; + } + seconds -= rtc->epoch_start; + + ticks = (unsigned long long)seconds << 10; + buff[0] = (ticks >> 32) & 0xff; + buff[1] = (ticks >> 24) & 0xff; + buff[2] = (ticks >> 16) & 0xff; + buff[3] = (ticks >> 8) & 0xff; + buff[4] = ticks & 0xff; + + /* Disable RTC before changing time */ + ret = tps6586x_clr_bits(tps_dev, RTC_CTRL, RTC_ENABLE); + if (ret < 0) { + dev_err(dev, "failed to clear RTC_ENABLE\n"); + return ret; + } + + ret = tps6586x_writes(tps_dev, RTC_COUNT4, sizeof(buff), buff); + if (ret < 0) { + dev_err(dev, "failed to program new time\n"); + return ret; + } + + /* Enable RTC */ + ret = tps6586x_set_bits(tps_dev, RTC_CTRL, RTC_ENABLE); + if (ret < 0) { + dev_err(dev, "failed to set RTC_ENABLE\n"); + return ret; + } + return 0; +} + +static int tps6586x_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct tps6586x_rtc *rtc = dev_get_drvdata(dev); + + if (enabled && !rtc->irq_en) { + enable_irq(rtc->irq); + rtc->irq_en = true; + } else if (!enabled && rtc->irq_en) { + disable_irq(rtc->irq); + rtc->irq_en = false; + } + return 0; +} + +static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tps6586x_rtc *rtc = dev_get_drvdata(dev); + struct device *tps_dev = to_tps6586x_dev(dev); + unsigned long seconds; + unsigned long ticks; + unsigned long rtc_current_time; + unsigned long long rticks = 0; + u8 buff[3]; + u8 rbuff[6]; + int ret; + int i; + + rtc_tm_to_time(&alrm->time, &seconds); + + if (alrm->enabled && (seconds < rtc->epoch_start)) { + dev_err(dev, "can't set alarm to requested time\n"); + return -EINVAL; + } + + ret = tps6586x_rtc_alarm_irq_enable(dev, alrm->enabled); + if (ret < 0) { + dev_err(dev, "can't set alarm irq, err %d\n", ret); + return ret; + } + + seconds -= rtc->epoch_start; + ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD, + sizeof(rbuff), rbuff); + if (ret < 0) { + dev_err(dev, "read counter failed with err %d\n", ret); + return ret; + } + + for (i = 1; i < sizeof(rbuff); i++) { + rticks <<= 8; + rticks |= rbuff[i]; + } + + rtc_current_time = rticks >> 10; + if ((seconds - rtc_current_time) > ALM1_VALID_RANGE_IN_SEC) + seconds = rtc_current_time - 1; + + ticks = (unsigned long long)seconds << 10; + buff[0] = (ticks >> 16) & 0xff; + buff[1] = (ticks >> 8) & 0xff; + buff[2] = ticks & 0xff; + + ret = tps6586x_writes(tps_dev, RTC_ALARM1_HI, sizeof(buff), buff); + if (ret) + dev_err(dev, "programming alarm failed with err %d\n", ret); + + return ret; +} + +static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct tps6586x_rtc *rtc = dev_get_drvdata(dev); + struct device *tps_dev = to_tps6586x_dev(dev); + unsigned long ticks; + unsigned long seconds; + u8 buff[3]; + int ret; + + ret = tps6586x_reads(tps_dev, RTC_ALARM1_HI, sizeof(buff), buff); + if (ret) { + dev_err(dev, "read RTC_ALARM1_HI failed with err %d\n", ret); + return ret; + } + + ticks = (buff[0] << 16) | (buff[1] << 8) | buff[2]; + seconds = ticks >> 10; + seconds += rtc->epoch_start; + + rtc_time_to_tm(seconds, &alrm->time); + return 0; +} + +static const struct rtc_class_ops tps6586x_rtc_ops = { + .read_time = tps6586x_rtc_read_time, + .set_time = tps6586x_rtc_set_time, + .set_alarm = tps6586x_rtc_set_alarm, + .read_alarm = tps6586x_rtc_read_alarm, + .alarm_irq_enable = tps6586x_rtc_alarm_irq_enable, +}; + +static irqreturn_t tps6586x_rtc_irq(int irq, void *data) +{ + struct tps6586x_rtc *rtc = data; + + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static int tps6586x_rtc_probe(struct platform_device *pdev) +{ + struct device *tps_dev = to_tps6586x_dev(&pdev->dev); + struct tps6586x_rtc *rtc; + int ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->dev = &pdev->dev; + rtc->irq = platform_get_irq(pdev, 0); + + /* Set epoch start as 00:00:00:01:01:2009 */ + rtc->epoch_start = mktime(2009, 1, 1, 0, 0, 0); + + /* 1 kHz tick mode, enable tick counting */ + ret = tps6586x_update(tps_dev, RTC_CTRL, + RTC_ENABLE | OSC_SRC_SEL | + ((TPS6586X_RTC_CL_SEL_1_5PF << CL_SEL_POS) & CL_SEL_MASK), + RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); + if (ret < 0) { + dev_err(&pdev->dev, "unable to start counter\n"); + return ret; + } + + platform_set_drvdata(pdev, rtc); + rtc->rtc = rtc_device_register(dev_name(&pdev->dev), &pdev->dev, + &tps6586x_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + ret = PTR_ERR(rtc->rtc); + dev_err(&pdev->dev, "RTC device register: ret %d\n", ret); + goto fail_rtc_register; + } + + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + tps6586x_rtc_irq, + IRQF_ONESHOT | IRQF_EARLY_RESUME, + dev_name(&pdev->dev), rtc); + if (ret < 0) { + dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n", + rtc->irq, ret); + goto fail_req_irq; + } + disable_irq(rtc->irq); + device_set_wakeup_capable(&pdev->dev, 1); + return 0; + +fail_req_irq: + rtc_device_unregister(rtc->rtc); + +fail_rtc_register: + tps6586x_update(tps_dev, RTC_CTRL, 0, + RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); + return ret; +}; + +static int tps6586x_rtc_remove(struct platform_device *pdev) +{ + struct tps6586x_rtc *rtc = platform_get_drvdata(pdev); + struct device *tps_dev = to_tps6586x_dev(&pdev->dev); + + tps6586x_update(tps_dev, RTC_CTRL, 0, + RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK); + rtc_device_unregister(rtc->rtc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tps6586x_rtc_suspend(struct device *dev) +{ + struct tps6586x_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + return 0; +} + +static int tps6586x_rtc_resume(struct device *dev) +{ + struct tps6586x_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + return 0; +} +#endif + +static const struct dev_pm_ops tps6586x_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tps6586x_rtc_suspend, tps6586x_rtc_resume) +}; + +static struct platform_driver tps6586x_rtc_driver = { + .driver = { + .name = "tps6586x-rtc", + .owner = THIS_MODULE, + .pm = &tps6586x_pm_ops, + }, + .probe = tps6586x_rtc_probe, + .remove = tps6586x_rtc_remove, +}; +module_platform_driver(tps6586x_rtc_driver); + +MODULE_ALIAS("platform:rtc-tps6586x"); +MODULE_DESCRIPTION("TI TPS6586x RTC driver"); +MODULE_AUTHOR("Laxman dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 7a82337e4dee..8bd8115329b5 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -22,13 +22,13 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/interrupt.h> #include <linux/mfd/tps65910.h> struct tps65910_rtc { struct rtc_device *rtc; - /* To store the list of enabled interrupts */ - u32 irqstat; + int irq; }; /* Total number of RTC registers needed to set time*/ @@ -222,7 +222,7 @@ static const struct rtc_class_ops tps65910_rtc_ops = { .alarm_irq_enable = tps65910_rtc_alarm_irq_enable, }; -static int __devinit tps65910_rtc_probe(struct platform_device *pdev) +static int tps65910_rtc_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = NULL; struct tps65910_rtc *tps_rtc = NULL; @@ -247,6 +247,13 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev) return ret; dev_dbg(&pdev->dev, "Enabling rtc-tps65910.\n"); + + /* Enable RTC digital power domain */ + ret = regmap_update_bits(tps65910->regmap, TPS65910_DEVCTRL, + DEVCTRL_RTC_PWDN_MASK, 0 << DEVCTRL_RTC_PWDN_SHIFT); + if (ret < 0) + return ret; + rtc_reg = TPS65910_RTC_CTRL_STOP_RTC; ret = regmap_write(tps65910->regmap, TPS65910_RTC_CTRL, rtc_reg); if (ret < 0) @@ -260,13 +267,14 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev) } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, - "rtc-tps65910", &pdev->dev); + tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME, + dev_name(&pdev->dev), &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); return ret; } - device_init_wakeup(&pdev->dev, 1); + tps_rtc->irq = irq; + device_set_wakeup_capable(&pdev->dev, 1); tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &tps65910_rtc_ops, THIS_MODULE); @@ -285,61 +293,48 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev) * Disable tps65910 RTC interrupts. * Sets status flag to free. */ -static int __devexit tps65910_rtc_remove(struct platform_device *pdev) +static int tps65910_rtc_remove(struct platform_device *pdev) { /* leave rtc running, but disable irqs */ - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct tps65910_rtc *tps_rtc = platform_get_drvdata(pdev); - tps65910_rtc_alarm_irq_enable(&rtc->dev, 0); + tps65910_rtc_alarm_irq_enable(&pdev->dev, 0); - rtc_device_unregister(rtc); + rtc_device_unregister(tps_rtc->rtc); return 0; } #ifdef CONFIG_PM_SLEEP - static int tps65910_rtc_suspend(struct device *dev) { - struct tps65910 *tps = dev_get_drvdata(dev->parent); - u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM; - int ret; - - /* Store current list of enabled interrupts*/ - ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, - &tps->rtc->irqstat); - if (ret < 0) - return ret; + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); - /* Enable RTC ALARM interrupt only */ - return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm); + if (device_may_wakeup(dev)) + enable_irq_wake(tps_rtc->irq); + return 0; } static int tps65910_rtc_resume(struct device *dev) { - struct tps65910 *tps = dev_get_drvdata(dev->parent); + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); - /* Restore list of enabled interrupts before suspend */ - return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, - tps->rtc->irqstat); + if (device_may_wakeup(dev)) + disable_irq_wake(tps_rtc->irq); + return 0; } +#endif static const struct dev_pm_ops tps65910_rtc_pm_ops = { - .suspend = tps65910_rtc_suspend, - .resume = tps65910_rtc_resume, + SET_SYSTEM_SLEEP_PM_OPS(tps65910_rtc_suspend, tps65910_rtc_resume) }; -#define DEV_PM_OPS (&tps65910_rtc_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - static struct platform_driver tps65910_rtc_driver = { .probe = tps65910_rtc_probe, - .remove = __devexit_p(tps65910_rtc_remove), + .remove = tps65910_rtc_remove, .driver = { .owner = THIS_MODULE, .name = "tps65910-rtc", - .pm = DEV_PM_OPS, + .pm = &tps65910_rtc_pm_ops, }, }; diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c new file mode 100644 index 000000000000..9aaf8aaebae9 --- /dev/null +++ b/drivers/rtc/rtc-tps80031.c @@ -0,0 +1,349 @@ +/* + * rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver + * + * RTC driver for TI TPS80031/TPS80032 Fully Integrated + * Power Management with Power Path and Battery Charger + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/bcd.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/tps80031.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/rtc.h> +#include <linux/slab.h> + +#define ENABLE_ALARM_INT 0x08 +#define ALARM_INT_STATUS 0x40 + +/** + * Setting bit to 1 in STOP_RTC will run the RTC and + * setting this bit to 0 will freeze RTC. + */ +#define STOP_RTC 0x1 + +/* Power on reset Values of RTC registers */ +#define TPS80031_RTC_POR_YEAR 0 +#define TPS80031_RTC_POR_MONTH 1 +#define TPS80031_RTC_POR_DAY 1 + +/* Numbers of registers for time and alarms */ +#define TPS80031_RTC_TIME_NUM_REGS 7 +#define TPS80031_RTC_ALARM_NUM_REGS 6 + +/** + * PMU RTC have only 2 nibbles to store year information, so using an + * offset of 100 to set the base year as 2000 for our driver. + */ +#define RTC_YEAR_OFFSET 100 + +struct tps80031_rtc { + struct rtc_device *rtc; + int irq; +}; + +static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + u8 buff[TPS80031_RTC_TIME_NUM_REGS]; + int ret; + + ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_SECONDS_REG, TPS80031_RTC_TIME_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev, "reading RTC_SECONDS_REG failed, err = %d\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(buff[0]); + tm->tm_min = bcd2bin(buff[1]); + tm->tm_hour = bcd2bin(buff[2]); + tm->tm_mday = bcd2bin(buff[3]); + tm->tm_mon = bcd2bin(buff[4]) - 1; + tm->tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; + tm->tm_wday = bcd2bin(buff[6]); + return 0; +} + +static int tps80031_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + u8 buff[7]; + int ret; + + buff[0] = bin2bcd(tm->tm_sec); + buff[1] = bin2bcd(tm->tm_min); + buff[2] = bin2bcd(tm->tm_hour); + buff[3] = bin2bcd(tm->tm_mday); + buff[4] = bin2bcd(tm->tm_mon + 1); + buff[5] = bin2bcd(tm->tm_year % RTC_YEAR_OFFSET); + buff[6] = bin2bcd(tm->tm_wday); + + /* Stop RTC while updating the RTC time registers */ + ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_CTRL_REG, STOP_RTC); + if (ret < 0) { + dev_err(dev->parent, "Stop RTC failed, err = %d\n", ret); + return ret; + } + + ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_SECONDS_REG, + TPS80031_RTC_TIME_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev, "writing RTC_SECONDS_REG failed, err %d\n", ret); + return ret; + } + + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_CTRL_REG, STOP_RTC); + if (ret < 0) + dev_err(dev->parent, "Start RTC failed, err = %d\n", ret); + return ret; +} + +static int tps80031_rtc_alarm_irq_enable(struct device *dev, + unsigned int enable) +{ + int ret; + + if (enable) + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); + else + ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); + if (ret < 0) { + dev_err(dev, "Update on RTC_INT failed, err = %d\n", ret); + return ret; + } + return 0; +} + +static int tps80031_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + u8 buff[TPS80031_RTC_ALARM_NUM_REGS]; + int ret; + + buff[0] = bin2bcd(alrm->time.tm_sec); + buff[1] = bin2bcd(alrm->time.tm_min); + buff[2] = bin2bcd(alrm->time.tm_hour); + buff[3] = bin2bcd(alrm->time.tm_mday); + buff[4] = bin2bcd(alrm->time.tm_mon + 1); + buff[5] = bin2bcd(alrm->time.tm_year % RTC_YEAR_OFFSET); + ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_ALARM_SECONDS_REG, + TPS80031_RTC_ALARM_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev, "Writing RTC_ALARM failed, err %d\n", ret); + return ret; + } + return tps80031_rtc_alarm_irq_enable(dev, alrm->enabled); +} + +static int tps80031_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + u8 buff[6]; + int ret; + + ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_ALARM_SECONDS_REG, + TPS80031_RTC_ALARM_NUM_REGS, buff); + if (ret < 0) { + dev_err(dev->parent, + "reading RTC_ALARM failed, err = %d\n", ret); + return ret; + } + + alrm->time.tm_sec = bcd2bin(buff[0]); + alrm->time.tm_min = bcd2bin(buff[1]); + alrm->time.tm_hour = bcd2bin(buff[2]); + alrm->time.tm_mday = bcd2bin(buff[3]); + alrm->time.tm_mon = bcd2bin(buff[4]) - 1; + alrm->time.tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; + return 0; +} + +static int clear_alarm_int_status(struct device *dev, struct tps80031_rtc *rtc) +{ + int ret; + u8 buf; + + /** + * As per datasheet, A dummy read of this RTC_STATUS_REG register + * is necessary before each I2C read in order to update the status + * register value. + */ + ret = tps80031_read(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_STATUS_REG, &buf); + if (ret < 0) { + dev_err(dev, "reading RTC_STATUS failed. err = %d\n", ret); + return ret; + } + + /* clear Alarm status bits.*/ + ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_STATUS_REG, ALARM_INT_STATUS); + if (ret < 0) { + dev_err(dev, "clear Alarm INT failed, err = %d\n", ret); + return ret; + } + return 0; +} + +static irqreturn_t tps80031_rtc_irq(int irq, void *data) +{ + struct device *dev = data; + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + int ret; + + ret = clear_alarm_int_status(dev, rtc); + if (ret < 0) + return ret; + + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops tps80031_rtc_ops = { + .read_time = tps80031_rtc_read_time, + .set_time = tps80031_rtc_set_time, + .set_alarm = tps80031_rtc_set_alarm, + .read_alarm = tps80031_rtc_read_alarm, + .alarm_irq_enable = tps80031_rtc_alarm_irq_enable, +}; + +static int tps80031_rtc_probe(struct platform_device *pdev) +{ + struct tps80031_rtc *rtc; + struct rtc_time tm; + int ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->irq = platform_get_irq(pdev, 0); + platform_set_drvdata(pdev, rtc); + + /* Start RTC */ + ret = tps80031_set_bits(pdev->dev.parent, TPS80031_SLAVE_ID1, + TPS80031_RTC_CTRL_REG, STOP_RTC); + if (ret < 0) { + dev_err(&pdev->dev, "failed to start RTC. err = %d\n", ret); + return ret; + } + + /* If RTC have POR values, set time 01:01:2000 */ + tps80031_rtc_read_time(&pdev->dev, &tm); + if ((tm.tm_year == RTC_YEAR_OFFSET + TPS80031_RTC_POR_YEAR) && + (tm.tm_mon == (TPS80031_RTC_POR_MONTH - 1)) && + (tm.tm_mday == TPS80031_RTC_POR_DAY)) { + tm.tm_year = 2000; + tm.tm_mday = 1; + tm.tm_mon = 1; + ret = tps80031_rtc_set_time(&pdev->dev, &tm); + if (ret < 0) { + dev_err(&pdev->dev, + "RTC set time failed, err = %d\n", ret); + return ret; + } + } + + /* Clear alarm intretupt status if it is there */ + ret = clear_alarm_int_status(&pdev->dev, rtc); + if (ret < 0) { + dev_err(&pdev->dev, "Clear alarm int failed, err = %d\n", ret); + return ret; + } + + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &tps80031_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + ret = PTR_ERR(rtc->rtc); + dev_err(&pdev->dev, "RTC registration failed, err %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + tps80031_rtc_irq, + IRQF_ONESHOT | IRQF_EARLY_RESUME, + dev_name(&pdev->dev), rtc); + if (ret < 0) { + dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n", + rtc->irq, ret); + rtc_device_unregister(rtc->rtc); + return ret; + } + device_set_wakeup_capable(&pdev->dev, 1); + return 0; +} + +static int tps80031_rtc_remove(struct platform_device *pdev) +{ + struct tps80031_rtc *rtc = platform_get_drvdata(pdev); + + rtc_device_unregister(rtc->rtc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tps80031_rtc_suspend(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + return 0; +} + +static int tps80031_rtc_resume(struct device *dev) +{ + struct tps80031_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + return 0; +}; +#endif + +static const struct dev_pm_ops tps80031_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tps80031_rtc_suspend, tps80031_rtc_resume) +}; + +static struct platform_driver tps80031_rtc_driver = { + .driver = { + .name = "tps80031-rtc", + .owner = THIS_MODULE, + .pm = &tps80031_pm_ops, + }, + .probe = tps80031_rtc_probe, + .remove = tps80031_rtc_remove, +}; + +module_platform_driver(tps80031_rtc_driver); + +MODULE_ALIAS("platform:tps80031-rtc"); +MODULE_DESCRIPTION("TI TPS80031/TPS80032 RTC driver"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 9277d945bf48..8bc6c80b184c 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -27,6 +27,7 @@ #include <linux/bcd.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/of.h> #include <linux/i2c/twl.h> @@ -233,7 +234,7 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) */ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; u8 save_control; u8 rtc_control; @@ -300,15 +301,15 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned char save_control; - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; - rtc_data[1] = bin2bcd(tm->tm_sec); - rtc_data[2] = bin2bcd(tm->tm_min); - rtc_data[3] = bin2bcd(tm->tm_hour); - rtc_data[4] = bin2bcd(tm->tm_mday); - rtc_data[5] = bin2bcd(tm->tm_mon + 1); - rtc_data[6] = bin2bcd(tm->tm_year - 100); + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); /* Stop RTC while updating the TC registers */ ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); @@ -341,7 +342,7 @@ out: */ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + unsigned char rtc_data[ALL_TIME_REGS]; int ret; ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, @@ -368,19 +369,19 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { - unsigned char alarm_data[ALL_TIME_REGS + 1]; + unsigned char alarm_data[ALL_TIME_REGS]; int ret; ret = twl_rtc_alarm_irq_enable(dev, 0); if (ret) goto out; - alarm_data[1] = bin2bcd(alm->time.tm_sec); - alarm_data[2] = bin2bcd(alm->time.tm_min); - alarm_data[3] = bin2bcd(alm->time.tm_hour); - alarm_data[4] = bin2bcd(alm->time.tm_mday); - alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); - alarm_data[6] = bin2bcd(alm->time.tm_year - 100); + alarm_data[0] = bin2bcd(alm->time.tm_sec); + alarm_data[1] = bin2bcd(alm->time.tm_min); + alarm_data[2] = bin2bcd(alm->time.tm_hour); + alarm_data[3] = bin2bcd(alm->time.tm_mday); + alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[5] = bin2bcd(alm->time.tm_year - 100); /* update all the alarm registers in one shot */ ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, @@ -458,7 +459,7 @@ static struct rtc_class_ops twl_rtc_ops = { /*----------------------------------------------------------------------*/ -static int __devinit twl_rtc_probe(struct platform_device *pdev) +static int twl_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; int ret = -EINVAL; @@ -535,7 +536,7 @@ out1: * Disable all TWL RTC module interrupts. * Sets status flag to free. */ -static int __devexit twl_rtc_remove(struct platform_device *pdev) +static int twl_rtc_remove(struct platform_device *pdev) { /* leave rtc running, but disable irqs */ struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -588,23 +589,26 @@ static int twl_rtc_resume(struct platform_device *pdev) #define twl_rtc_resume NULL #endif +#ifdef CONFIG_OF static const struct of_device_id twl_rtc_of_match[] = { {.compatible = "ti,twl4030-rtc", }, { }, }; MODULE_DEVICE_TABLE(of, twl_rtc_of_match); +#endif + MODULE_ALIAS("platform:twl_rtc"); static struct platform_driver twl4030rtc_driver = { .probe = twl_rtc_probe, - .remove = __devexit_p(twl_rtc_remove), + .remove = twl_rtc_remove, .shutdown = twl_rtc_shutdown, .suspend = twl_rtc_suspend, .resume = twl_rtc_resume, .driver = { .owner = THIS_MODULE, .name = "twl_rtc", - .of_match_table = twl_rtc_of_match, + .of_match_table = of_match_ptr(twl_rtc_of_match), }, }; diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 5f60a7c6a155..f91be04b9050 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -280,7 +280,7 @@ static const struct rtc_class_ops vr41xx_rtc_ops = { .set_alarm = vr41xx_rtc_set_alarm, }; -static int __devinit rtc_probe(struct platform_device *pdev) +static int rtc_probe(struct platform_device *pdev) { struct resource *res; struct rtc_device *rtc; @@ -352,7 +352,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) disable_irq(aie_irq); disable_irq(pie_irq); - printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n"); + dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n"); return 0; @@ -373,7 +373,7 @@ err_rtc1_iounmap: return retval; } -static int __devexit rtc_remove(struct platform_device *pdev) +static int rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc; @@ -398,7 +398,7 @@ MODULE_ALIAS("platform:RTC"); static struct platform_driver rtc_platform_driver = { .probe = rtc_probe, - .remove = __devexit_p(rtc_remove), + .remove = rtc_remove, .driver = { .name = rtc_name, .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 07bf19364a74..a000bc0a8bff 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -70,7 +70,7 @@ | ALARM_SEC_BIT) #define VT8500_RTC_CR_ENABLE (1 << 0) /* Enable RTC */ -#define VT8500_RTC_CR_24H (1 << 1) /* 24h time format */ +#define VT8500_RTC_CR_12H (1 << 1) /* 12h time format */ #define VT8500_RTC_CR_SM_ENABLE (1 << 2) /* Enable periodic irqs */ #define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */ #define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */ @@ -119,7 +119,7 @@ static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S); tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S); tm->tm_mday = bcd2bin(date & DATE_DAY_MASK); - tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S); + tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S) - 1; tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S) + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100); tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S; @@ -137,9 +137,10 @@ static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm) return -EINVAL; } - writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S) - | (bin2bcd(tm->tm_mon) << DATE_MONTH_S) - | (bin2bcd(tm->tm_mday)), + writel((bin2bcd(tm->tm_year % 100) << DATE_YEAR_S) + | (bin2bcd(tm->tm_mon + 1) << DATE_MONTH_S) + | (bin2bcd(tm->tm_mday)) + | ((tm->tm_year >= 200) << DATE_CENTURY_S), vt8500_rtc->regbase + VT8500_RTC_DS); writel((bin2bcd(tm->tm_wday) << TIME_DOW_S) | (bin2bcd(tm->tm_hour) << TIME_HOUR_S) @@ -205,12 +206,13 @@ static const struct rtc_class_ops vt8500_rtc_ops = { .alarm_irq_enable = vt8500_alarm_irq_enable, }; -static int __devinit vt8500_rtc_probe(struct platform_device *pdev) +static int vt8500_rtc_probe(struct platform_device *pdev) { struct vt8500_rtc *vt8500_rtc; int ret; - vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL); + vt8500_rtc = devm_kzalloc(&pdev->dev, + sizeof(struct vt8500_rtc), GFP_KERNEL); if (!vt8500_rtc) return -ENOMEM; @@ -220,36 +222,34 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!vt8500_rtc->res) { dev_err(&pdev->dev, "No I/O memory resource defined\n"); - ret = -ENXIO; - goto err_free; + return -ENXIO; } vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0); if (vt8500_rtc->irq_alarm < 0) { dev_err(&pdev->dev, "No alarm IRQ resource defined\n"); - ret = -ENXIO; - goto err_free; + return -ENXIO; } - vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, - resource_size(vt8500_rtc->res), - "vt8500-rtc"); + vt8500_rtc->res = devm_request_mem_region(&pdev->dev, + vt8500_rtc->res->start, + resource_size(vt8500_rtc->res), + "vt8500-rtc"); if (vt8500_rtc->res == NULL) { dev_err(&pdev->dev, "failed to request I/O memory\n"); - ret = -EBUSY; - goto err_free; + return -EBUSY; } - vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start, + vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start, resource_size(vt8500_rtc->res)); if (!vt8500_rtc->regbase) { dev_err(&pdev->dev, "Unable to map RTC I/O memory\n"); ret = -EBUSY; - goto err_release; + goto err_return; } /* Enable RTC and set it to 24-hour mode */ - writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H, + writel(VT8500_RTC_CR_ENABLE, vt8500_rtc->regbase + VT8500_RTC_CR); vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev, @@ -258,11 +258,11 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) ret = PTR_ERR(vt8500_rtc->rtc); dev_err(&pdev->dev, "Failed to register RTC device -> %d\n", ret); - goto err_unmap; + goto err_return; } - ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, - "rtc alarm", vt8500_rtc); + ret = devm_request_irq(&pdev->dev, vt8500_rtc->irq_alarm, + vt8500_rtc_irq, 0, "rtc alarm", vt8500_rtc); if (ret < 0) { dev_err(&pdev->dev, "can't get irq %i, err %d\n", vt8500_rtc->irq_alarm, ret); @@ -273,31 +273,19 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) err_unreg: rtc_device_unregister(vt8500_rtc->rtc); -err_unmap: - iounmap(vt8500_rtc->regbase); -err_release: - release_mem_region(vt8500_rtc->res->start, - resource_size(vt8500_rtc->res)); -err_free: - kfree(vt8500_rtc); +err_return: return ret; } -static int __devexit vt8500_rtc_remove(struct platform_device *pdev) +static int vt8500_rtc_remove(struct platform_device *pdev) { struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); - free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); - rtc_device_unregister(vt8500_rtc->rtc); /* Disable alarm matching */ writel(0, vt8500_rtc->regbase + VT8500_RTC_IS); - iounmap(vt8500_rtc->regbase); - release_mem_region(vt8500_rtc->res->start, - resource_size(vt8500_rtc->res)); - kfree(vt8500_rtc); platform_set_drvdata(pdev, NULL); return 0; @@ -310,7 +298,7 @@ static const struct of_device_id wmt_dt_ids[] = { static struct platform_driver vt8500_rtc_driver = { .probe = vt8500_rtc_probe, - .remove = __devexit_p(vt8500_rtc_remove), + .remove = vt8500_rtc_remove, .driver = { .name = "vt8500-rtc", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index ea5c6f857ca5..2f0ac7b30a0c 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -443,9 +443,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev) goto err; } - ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq, - IRQF_TRIGGER_RISING, "RTC alarm", - wm831x_rtc); + ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, + wm831x_alm_irq, + IRQF_TRIGGER_RISING, "RTC alarm", + wm831x_rtc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", alm_irq, ret); @@ -459,12 +460,10 @@ err: return ret; } -static int __devexit wm831x_rtc_remove(struct platform_device *pdev) +static int wm831x_rtc_remove(struct platform_device *pdev) { struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev); - int alm_irq = platform_get_irq_byname(pdev, "ALM"); - free_irq(alm_irq, wm831x_rtc); rtc_device_unregister(wm831x_rtc->rtc); return 0; @@ -483,7 +482,7 @@ static const struct dev_pm_ops wm831x_rtc_pm_ops = { static struct platform_driver wm831x_rtc_driver = { .probe = wm831x_rtc_probe, - .remove = __devexit_p(wm831x_rtc_remove), + .remove = wm831x_rtc_remove, .driver = { .name = "wm831x-rtc", .pm = &wm831x_rtc_pm_ops, diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index c2e52d15abb2..8ad86ae0d30f 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -459,7 +459,7 @@ static int wm8350_rtc_probe(struct platform_device *pdev) return 0; } -static int __devexit wm8350_rtc_remove(struct platform_device *pdev) +static int wm8350_rtc_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_rtc *wm_rtc = &wm8350->rtc; @@ -479,7 +479,7 @@ static struct dev_pm_ops wm8350_rtc_pm_ops = { static struct platform_driver wm8350_rtc_driver = { .probe = wm8350_rtc_probe, - .remove = __devexit_p(wm8350_rtc_remove), + .remove = wm8350_rtc_remove, .driver = { .name = "wm8350-rtc", .pm = &wm8350_rtc_pm_ops, diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c new file mode 100644 index 000000000000..bf3e242ccc5c --- /dev/null +++ b/drivers/rtc/systohc.c @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + */ +#include <linux/rtc.h> +#include <linux/time.h> + +/** + * rtc_set_ntp_time - Save NTP synchronized time to the RTC + * @now: Current time of day + * + * Replacement for the NTP platform function update_persistent_clock + * that stores time for later retrieval by rtc_hctosys. + * + * Returns 0 on successful RTC update, -ENODEV if a RTC update is not + * possible at all, and various other -errno for specific temporary failure + * cases. + * + * If temporary failure is indicated the caller should try again 'soon' + */ +int rtc_set_ntp_time(struct timespec now) +{ + struct rtc_device *rtc; + struct rtc_time tm; + int err = -ENODEV; + + if (now.tv_nsec < (NSEC_PER_SEC >> 1)) + rtc_time_to_tm(now.tv_sec, &tm); + else + rtc_time_to_tm(now.tv_sec + 1, &tm); + + rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (rtc) { + /* rtc_hctosys exclusively uses UTC, so we call set_time here, + * not set_mmss. */ + if (rtc->ops && (rtc->ops->set_time || rtc->ops->set_mmss)) + err = rtc_set_time(rtc, &tm); + rtc_class_close(rtc); + } + + return err; +} |