diff options
Diffstat (limited to 'drivers/rtc')
123 files changed, 7186 insertions, 2011 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b9838130a7b..0754f5c7cb3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -153,6 +153,16 @@ config RTC_DRV_88PM80X This driver can also be built as a module. If so, the module will be called rtc-88pm80x. +config RTC_DRV_AS3722 + tristate "ams AS3722 RTC driver" + depends on MFD_AS3722 + help + If you say yes here you get support for the RTC of ams AS3722 PMIC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-as3722. + config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" help @@ -202,6 +212,17 @@ 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_HYM8563 + tristate "Haoyu Microelectronics HYM8563" + depends on I2C && OF + help + Say Y to enable support for the HYM8563 I2C RTC chip. Apart + from the usual rtc functions it provides a clock output of + up to 32kHz. + + This driver can also be built as a module. If so, the module + will be called rtc-hym8563. + config RTC_DRV_LP8788 tristate "TI LP8788 RTC driver" depends on MFD_LP8788 @@ -294,6 +315,17 @@ config RTC_DRV_ISL12022 This driver can also be built as a module. If so, the module will be called rtc-isl12022. +config RTC_DRV_ISL12057 + depends on I2C + select REGMAP_I2C + tristate "Intersil ISL12057" + help + If you say yes here you get support for the Intersil ISL12057 + I2C RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-isl12057. + config RTC_DRV_X1205 tristate "Xicor/Intersil X1205" help @@ -313,6 +345,15 @@ config RTC_DRV_PALMAS This driver can also be built as a module. If so, the module will be called rtc-palma. +config RTC_DRV_PCF2127 + tristate "NXP PCF2127" + help + If you say yes here you get support for the NXP PCF2127/29 RTC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-pcf2127. + config RTC_DRV_PCF8523 tristate "NXP PCF8523" help @@ -345,12 +386,12 @@ config RTC_DRV_PCF8583 will be called rtc-pcf8583. config RTC_DRV_M41T80 - tristate "ST M41T62/65/M41T80/81/82/83/84/85/87" + tristate "ST M41T62/65/M41T80/81/82/83/84/85/87 and compatible" help If you say Y here you will get support for the ST M41T60 and M41T80 RTC chips series. Currently, the following chips are supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, - M41ST85, and M41ST87. + M41ST85, M41ST87, and MicroCrystal RV4162. This driver can also be built as a module. If so, the module will be called rtc-m41t80. @@ -488,6 +529,16 @@ config RTC_DRV_RV3029C2 This driver can also be built as a module. If so, the module will be called rtc-rv3029c2. +config RTC_DRV_S5M + tristate "Samsung S2M/S5M series" + depends on MFD_SEC_CORE + help + If you say yes here you will get support for the + RTC of Samsung S2MPS14 and S5M PMIC series. + + This driver can also be built as a module. If so, the module + will be called rtc-s5m. + endif # I2C comment "SPI RTC drivers" @@ -522,6 +573,29 @@ config RTC_DRV_DS1305 This driver can also be built as a module. If so, the module will be called rtc-ds1305. +config RTC_DRV_DS1343 + select REGMAP_SPI + tristate "Dallas/Maxim DS1343/DS1344" + help + If you say yes here you get support for the + Dallas/Maxim DS1343 and DS1344 real time clock chips. + Support for trickle charger, alarm is provided. + + This driver can also be built as a module. If so, the module + will be called rtc-ds1343. + +config RTC_DRV_DS1347 + tristate "Dallas/Maxim DS1347" + help + If you say yes here you get support for the + Dallas/Maxim DS1347 chips. + + This driver only supports the RTC feature, and not other chip + features such as alarms. + + This driver can also be built as a module. If so, the module + will be called rtc-ds1347. + config RTC_DRV_DS1390 tristate "Dallas/Maxim DS1390/93/94" help @@ -587,6 +661,14 @@ config RTC_DRV_RX4581 This driver can also be built as a module. If so the module will be called rtc-rx4581. +config RTC_DRV_MCP795 + tristate "Microchip MCP795" + help + If you say yes here you will get support for the Microchip MCP795. + + This driver can also be built as a module. If so the module + will be called rtc-mcp795. + endif # SPI_MASTER comment "Platform RTC drivers" @@ -597,7 +679,7 @@ comment "Platform RTC drivers" config RTC_DRV_CMOS tristate "PC-style 'CMOS'" - depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64 + depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 default y if X86 help Say "yes" here to get direct support for the real time clock @@ -614,6 +696,14 @@ config RTC_DRV_CMOS This driver can also be built as a module. If so, the module will be called rtc-cmos. +config RTC_DRV_ALPHA + bool "Alpha PC-style CMOS" + depends on ALPHA + default y + help + Direct support for the real-time clock found on every Alpha + system, specifically MC146818 compatibles. If in doubt, say Y. + config RTC_DRV_VRTC tristate "Virtual RTC for Intel MID platforms" depends on X86_INTEL_MID @@ -687,6 +777,16 @@ config RTC_DRV_DA9055 This driver can also be built as a module. If so, the module will be called rtc-da9055 +config RTC_DRV_DA9063 + tristate "Dialog Semiconductor DA9063 RTC" + depends on MFD_DA9063 + help + If you say yes here you will get support for the RTC subsystem + of the Dialog Semiconductor DA9063. + + This driver can also be built as a module. If so, the module + will be called "rtc-da9063". + config RTC_DRV_EFI tristate "EFI RTC" depends on IA64 @@ -1067,6 +1167,13 @@ config RTC_DRV_SUN4V If you say Y here you will get support for the Hypervisor based RTC on SUN4V systems. +config RTC_DRV_SUNXI + tristate "Allwinner sun4i/sun7i RTC" + depends on ARCH_SUNXI + help + If you say Y here you will get support for the RTC found on + Allwinner A10/A20. + config RTC_DRV_STARFIRE bool "Starfire RTC" depends on SPARC64 @@ -1233,6 +1340,31 @@ config RTC_DRV_SNVS This driver can also be built as a module, if so, the module will be called "rtc-snvs". +config RTC_DRV_SIRFSOC + tristate "SiRFSOC RTC" + depends on ARCH_SIRF + help + Say "yes" here to support the real time clock on SiRF SOC chips. + This driver can also be built as a module called rtc-sirfsoc. + +config RTC_DRV_MOXART + tristate "MOXA ART RTC" + help + If you say yes here you get support for the MOXA ART + RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-moxart + +config RTC_DRV_XGENE + tristate "APM X-Gene RTC" + help + If you say yes here you get support for the APM X-Gene SoC real time + clock. + + This driver can also be built as a module, if so, the module + will be called "rtc-xgene". + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c33f86f1a69..70347d041d1 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o +obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o @@ -31,6 +32,7 @@ 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_DA9063) += rtc-da9063.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 @@ -39,6 +41,8 @@ obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o +obj-$(CONFIG_RTC_DRV_DS1343) += rtc-ds1343.o +obj-$(CONFIG_RTC_DRV_DS1347) += rtc-ds1347.o obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds1390.o obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o @@ -54,9 +58,11 @@ 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_HYM8563) += rtc-hym8563.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_ISL12057) += rtc-isl12057.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 @@ -76,6 +82,7 @@ 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_MCP795) += rtc-mcp795.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 @@ -83,6 +90,7 @@ 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_PCF2127) += rtc-pcf2127.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 @@ -106,6 +114,7 @@ obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o +obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o @@ -114,6 +123,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o +obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o @@ -128,3 +138,6 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o +obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o +obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 66385402d20..589351ef75d 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -14,6 +14,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> +#include <linux/of.h> #include <linux/rtc.h> #include <linux/kdev_t.h> #include <linux/idr.h> @@ -38,7 +39,7 @@ static void rtc_device_release(struct device *dev) int rtc_hctosys_ret = -ENODEV; #endif -#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) +#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE) /* * On suspend(), measure the delta between one RTC and the * system's wall clock; restore it on resume(). @@ -47,7 +48,7 @@ int rtc_hctosys_ret = -ENODEV; static struct timespec old_rtc, old_system, old_delta; -static int rtc_suspend(struct device *dev, pm_message_t mesg) +static int rtc_suspend(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; @@ -135,9 +136,10 @@ static int rtc_resume(struct device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume); +#define RTC_CLASS_DEV_PM_OPS (&rtc_class_dev_pm_ops) #else -#define rtc_suspend NULL -#define rtc_resume NULL +#define RTC_CLASS_DEV_PM_OPS NULL #endif @@ -156,12 +158,27 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, { struct rtc_device *rtc; struct rtc_wkalrm alrm; - int id, err; + int of_id = -1, id = -1, err; + + if (dev->of_node) + of_id = of_alias_get_id(dev->of_node, "rtc"); + else if (dev->parent && dev->parent->of_node) + of_id = of_alias_get_id(dev->parent->of_node, "rtc"); + + if (of_id >= 0) { + id = ida_simple_get(&rtc_ida, of_id, of_id + 1, + GFP_KERNEL); + if (id < 0) + dev_warn(dev, "/aliases ID %d not available\n", + of_id); + } - id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); if (id < 0) { - err = id; - goto exit; + id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); + if (id < 0) { + err = id; + goto exit; + } } rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); @@ -336,8 +353,7 @@ static int __init rtc_init(void) pr_err("couldn't create class\n"); return PTR_ERR(rtc_class); } - rtc_class->suspend = rtc_suspend; - rtc_class->resume = rtc_resume; + rtc_class->pm = RTC_CLASS_DEV_PM_OPS; rtc_dev_init(); rtc_sysfs_init(rtc_class); return 0; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 42bd57da239..5813fa52c3d 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -72,6 +72,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) } else err = -EINVAL; + pm_stay_awake(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); /* A timer might have just expired */ schedule_work(&rtc->irqwork); @@ -109,10 +110,11 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) err = rtc->ops->set_time(rtc->dev.parent, &new); } - } - else + } else { err = -EINVAL; + } + pm_stay_awake(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); /* A timer might have just expired */ schedule_work(&rtc->irqwork); @@ -290,7 +292,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); do { alarm->time.tm_year++; - } while (rtc_valid_tm(&alarm->time) != 0); + } while (!is_leap_year(alarm->time.tm_year + 1900) + && rtc_valid_tm(&alarm->time) != 0); break; default: @@ -298,7 +301,16 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } done: - return 0; + err = rtc_valid_tm(&alarm->time); + + if (err) { + dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n", + alarm->time.tm_year + 1900, alarm->time.tm_mon + 1, + alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min, + alarm->time.tm_sec); + } + + return err; } int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) @@ -367,14 +379,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; - if (rtc->aie_timer.enabled) { + if (rtc->aie_timer.enabled) rtc_timer_remove(rtc, &rtc->aie_timer); - } + rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); rtc->aie_timer.period = ktime_set(0, 0); - if (alarm->enabled) { + if (alarm->enabled) err = rtc_timer_enqueue(rtc, &rtc->aie_timer); - } + mutex_unlock(&rtc->ops_lock); return err; } @@ -582,6 +594,9 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events) { + if (unlikely(IS_ERR_OR_NULL(rtc))) + return; + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); } @@ -698,9 +713,9 @@ retry: spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; - if (rtc->irq_task != task) + else if (rtc->irq_task != task) err = -EACCES; - if (!err) { + else { if (rtc_update_hrtimer(rtc, enabled) < 0) { spin_unlock_irqrestore(&rtc->irq_task_lock, flags); cpu_relax(); @@ -734,9 +749,9 @@ retry: spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; - if (rtc->irq_task != task) + else if (rtc->irq_task != task) err = -EACCES; - if (!err) { + else { rtc->irq_freq = freq; if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) { spin_unlock_irqrestore(&rtc->irq_task_lock, flags); @@ -771,9 +786,10 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) alarm.time = rtc_ktime_to_tm(timer->node.expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); - if (err == -ETIME) + if (err == -ETIME) { + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); - else if (err) { + } else if (err) { timerqueue_del(&rtc->timerqueue, &timer->node); timer->enabled = 0; return err; @@ -818,8 +834,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); - if (err == -ETIME) + if (err == -ETIME) { + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); + } } } @@ -845,7 +863,6 @@ void rtc_timer_do_work(struct work_struct *work) mutex_lock(&rtc->ops_lock); again: - pm_relax(rtc->dev.parent); __rtc_read_time(rtc, &tm); now = rtc_tm_to_ktime(tm); while ((next = timerqueue_getnext(&rtc->timerqueue))) { @@ -880,6 +897,7 @@ again: } else rtc_alarm_disable(rtc); + pm_relax(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); } @@ -891,7 +909,7 @@ again: * * Kernel interface to initializing an rtc_timer. */ -void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) +void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data) { timerqueue_init(&timer->node); timer->enabled = 0; @@ -907,7 +925,7 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) * * Kernel interface to set an rtc_timer */ -int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, +int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, ktime_t expires, ktime_t period) { int ret = 0; @@ -930,7 +948,7 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, * * Kernel interface to cancel an rtc_timer */ -int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) +int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer) { int ret = 0; mutex_lock(&rtc->ops_lock); diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index f3742f364eb..0916089c7c3 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -251,14 +251,15 @@ static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume); 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; + struct pm80x_platform_data *pm80x_pdata = + dev_get_platdata(pdev->dev.parent); struct pm80x_rtc_pdata *pdata = NULL; struct pm80x_rtc_info *info; struct rtc_time tm; unsigned long ticks = 0; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (pdata == NULL) dev_warn(&pdev->dev, "No platform data!\n"); @@ -326,8 +327,7 @@ static int pm80x_rtc_probe(struct platform_device *pdev) regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO, PM800_RTC1_USE_XO); - if (pdev->dev.parent->platform_data) { - pm80x_pdata = pdev->dev.parent->platform_data; + if (pm80x_pdata) { pdata = pm80x_pdata->rtc; if (pdata) info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; @@ -345,7 +345,6 @@ out: static int pm80x_rtc_remove(struct platform_device *pdev) { struct pm80x_rtc_info *info = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); pm80x_free_irq(info->chip, info->irq, info); return 0; } diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 0f2b91bfee3..0c6add1a38d 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -293,7 +293,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev, int ret; if (!np) return -ENODEV; - np = of_find_node_by_name(np, "rtc"); + np = of_get_child_by_name(np, "rtc"); if (!np) { dev_err(&pdev->dev, "failed to find rtc node\n"); return -ENODEV; @@ -301,6 +301,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev, ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc); if (ret) info->vrtc = 0; + of_node_put(np); return 0; } #else @@ -316,7 +317,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev) unsigned long ticks = 0; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_rtc_info), GFP_KERNEL); @@ -418,7 +419,6 @@ static int pm860x_rtc_remove(struct platform_device *pdev) pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); #endif /* VRTC_CALIBRATION */ - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c index 47a4f2c4d30..ff435343ba9 100644 --- a/drivers/rtc/rtc-ab3100.c +++ b/drivers/rtc/rtc-ab3100.c @@ -240,18 +240,11 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit ab3100_rtc_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - return 0; -} - static struct platform_driver ab3100_rtc_driver = { .driver = { .name = "ab3100-rtc", .owner = THIS_MODULE, }, - .remove = __exit_p(ab3100_rtc_remove), }; module_platform_driver_probe(ab3100_rtc_driver, ab3100_rtc_probe); diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 63cfa314a39..727e2f5d14d 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -35,6 +35,10 @@ #define AB8500_RTC_FORCE_BKUP_REG 0x0D #define AB8500_RTC_CALIB_REG 0x0E #define AB8500_RTC_SWITCH_STAT_REG 0x0F +#define AB8540_RTC_ALRM_SEC 0x22 +#define AB8540_RTC_ALRM_MIN_LOW_REG 0x23 +#define AB8540_RTC_ALRM_MIN_MID_REG 0x24 +#define AB8540_RTC_ALRM_MIN_HI_REG 0x25 /* RtcReadRequest bits */ #define RTC_READ_REQUEST 0x01 @@ -58,6 +62,11 @@ static const u8 ab8500_rtc_alarm_regs[] = { AB8500_RTC_ALRM_MIN_LOW_REG }; +static const u8 ab8540_rtc_alarm_regs[] = { + AB8540_RTC_ALRM_MIN_HI_REG, AB8540_RTC_ALRM_MIN_MID_REG, + AB8540_RTC_ALRM_MIN_LOW_REG, AB8540_RTC_ALRM_SEC +}; + /* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */ static unsigned long get_elapsed_seconds(int year) { @@ -267,6 +276,42 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) return ab8500_rtc_irq_enable(dev, alarm->enabled); } +static int ab8540_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + int retval, i; + unsigned char buf[ARRAY_SIZE(ab8540_rtc_alarm_regs)]; + unsigned long mins, secs = 0; + + if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) { + dev_dbg(dev, "year should be equal to or greater than %d\n", + AB8500_RTC_EPOCH); + return -EINVAL; + } + + /* Get the number of seconds since 1970 */ + rtc_tm_to_time(&alarm->time, &secs); + + /* + * Convert it to the number of seconds since 01-01-2000 00:00:00 + */ + secs -= get_elapsed_seconds(AB8500_RTC_EPOCH); + mins = secs / 60; + + buf[3] = secs % 60; + buf[2] = mins & 0xFF; + buf[1] = (mins >> 8) & 0xFF; + buf[0] = (mins >> 16) & 0xFF; + + /* Set the alarm time */ + for (i = 0; i < ARRAY_SIZE(ab8540_rtc_alarm_regs); i++) { + retval = abx500_set_register_interruptible(dev, AB8500_RTC, + ab8540_rtc_alarm_regs[i], buf[i]); + if (retval < 0) + return retval; + } + + return ab8500_rtc_irq_enable(dev, alarm->enabled); +} static int ab8500_rtc_set_calibration(struct device *dev, int calibration) { @@ -389,8 +434,22 @@ static const struct rtc_class_ops ab8500_rtc_ops = { .alarm_irq_enable = ab8500_rtc_irq_enable, }; +static const struct rtc_class_ops ab8540_rtc_ops = { + .read_time = ab8500_rtc_read_time, + .set_time = ab8500_rtc_set_time, + .read_alarm = ab8500_rtc_read_alarm, + .set_alarm = ab8540_rtc_set_alarm, + .alarm_irq_enable = ab8500_rtc_irq_enable, +}; + +static struct platform_device_id ab85xx_rtc_ids[] = { + { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, }, + { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, }, +}; + static int ab8500_rtc_probe(struct platform_device *pdev) { + const struct platform_device_id *platid = platform_get_device_id(pdev); int err; struct rtc_device *rtc; u8 rtc_ctrl; @@ -423,7 +482,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, true); rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc", - &ab8500_rtc_ops, THIS_MODULE); + (struct rtc_class_ops *)platid->driver_data, + THIS_MODULE); if (IS_ERR(rtc)) { dev_err(&pdev->dev, "Registration failed\n"); err = PTR_ERR(rtc); @@ -451,8 +511,6 @@ static int ab8500_rtc_remove(struct platform_device *pdev) { ab8500_sysfs_rtc_unregister(&pdev->dev); - platform_set_drvdata(pdev, NULL); - return 0; } @@ -463,6 +521,7 @@ static struct platform_driver ab8500_rtc_driver = { }, .probe = ab8500_rtc_probe, .remove = ab8500_rtc_remove, + .id_table = ab85xx_rtc_ids, }; module_platform_driver(ab8500_rtc_driver); diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c new file mode 100644 index 00000000000..9f38eda6915 --- /dev/null +++ b/drivers/rtc/rtc-as3722.c @@ -0,0 +1,261 @@ +/* + * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs + * + * Copyright (C) 2013 ams AG + * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. + * + * Author: Florian Lobmaier <florian.lobmaier@ams.com> + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/bcd.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/ioctl.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/as3722.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/time.h> + +#define AS3722_RTC_START_YEAR 2000 +struct as3722_rtc { + struct rtc_device *rtc; + struct device *dev; + struct as3722 *as3722; + int alarm_irq; + bool irq_enable; +}; + +static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm) +{ + rbuff[0] = bin2bcd(tm->tm_sec); + rbuff[1] = bin2bcd(tm->tm_min); + rbuff[2] = bin2bcd(tm->tm_hour); + rbuff[3] = bin2bcd(tm->tm_mday); + rbuff[4] = bin2bcd(tm->tm_mon); + rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900)); +} + +static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(rbuff[0] & 0x7F); + tm->tm_min = bcd2bin(rbuff[1] & 0x7F); + tm->tm_hour = bcd2bin(rbuff[2] & 0x3F); + tm->tm_mday = bcd2bin(rbuff[3] & 0x3F); + tm->tm_mon = bcd2bin(rbuff[4] & 0x1F); + tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F); + return; +} + +static int as3722_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + ret = as3722_block_read(as3722, AS3722_RTC_SECOND_REG, + 6, as_time_array); + if (ret < 0) { + dev_err(dev, "RTC_SECOND reg block read failed %d\n", ret); + return ret; + } + as3722_reg_to_time(as_time_array, tm); + return 0; +} + +static int as3722_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + if (tm->tm_year < (AS3722_RTC_START_YEAR - 1900)) + return -EINVAL; + + as3722_time_to_reg(as_time_array, tm); + ret = as3722_block_write(as3722, AS3722_RTC_SECOND_REG, 6, + as_time_array); + if (ret < 0) + dev_err(dev, "RTC_SECOND reg block write failed %d\n", ret); + return ret; +} + +static int as3722_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + + if (enabled && !as3722_rtc->irq_enable) { + enable_irq(as3722_rtc->alarm_irq); + as3722_rtc->irq_enable = true; + } else if (!enabled && as3722_rtc->irq_enable) { + disable_irq(as3722_rtc->alarm_irq); + as3722_rtc->irq_enable = false; + } + return 0; +} + +static int as3722_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + ret = as3722_block_read(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, + as_time_array); + if (ret < 0) { + dev_err(dev, "RTC_ALARM_SECOND block read failed %d\n", ret); + return ret; + } + + as3722_reg_to_time(as_time_array, &alrm->time); + return 0; +} + +static int as3722_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + struct as3722 *as3722 = as3722_rtc->as3722; + u8 as_time_array[6]; + int ret; + + if (alrm->time.tm_year < (AS3722_RTC_START_YEAR - 1900)) + return -EINVAL; + + ret = as3722_rtc_alarm_irq_enable(dev, 0); + if (ret < 0) { + dev_err(dev, "Disable RTC alarm failed\n"); + return ret; + } + + as3722_time_to_reg(as_time_array, &alrm->time); + ret = as3722_block_write(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, + as_time_array); + if (ret < 0) { + dev_err(dev, "RTC_ALARM_SECOND block write failed %d\n", ret); + return ret; + } + + if (alrm->enabled) + ret = as3722_rtc_alarm_irq_enable(dev, alrm->enabled); + return ret; +} + +static irqreturn_t as3722_alarm_irq(int irq, void *data) +{ + struct as3722_rtc *as3722_rtc = data; + + rtc_update_irq(as3722_rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops as3722_rtc_ops = { + .read_time = as3722_rtc_read_time, + .set_time = as3722_rtc_set_time, + .read_alarm = as3722_rtc_read_alarm, + .set_alarm = as3722_rtc_set_alarm, + .alarm_irq_enable = as3722_rtc_alarm_irq_enable, +}; + +static int as3722_rtc_probe(struct platform_device *pdev) +{ + struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); + struct as3722_rtc *as3722_rtc; + int ret; + + as3722_rtc = devm_kzalloc(&pdev->dev, sizeof(*as3722_rtc), GFP_KERNEL); + if (!as3722_rtc) + return -ENOMEM; + + as3722_rtc->as3722 = as3722; + as3722_rtc->dev = &pdev->dev; + platform_set_drvdata(pdev, as3722_rtc); + + /* Enable the RTC to make sure it is running. */ + ret = as3722_update_bits(as3722, AS3722_RTC_CONTROL_REG, + AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN, + AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN); + if (ret < 0) { + dev_err(&pdev->dev, "RTC_CONTROL reg write failed: %d\n", ret); + return ret; + } + + device_init_wakeup(&pdev->dev, 1); + + as3722_rtc->rtc = devm_rtc_device_register(&pdev->dev, "as3722-rtc", + &as3722_rtc_ops, THIS_MODULE); + if (IS_ERR(as3722_rtc->rtc)) { + ret = PTR_ERR(as3722_rtc->rtc); + dev_err(&pdev->dev, "RTC register failed: %d\n", ret); + return ret; + } + + as3722_rtc->alarm_irq = platform_get_irq(pdev, 0); + dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq); + + ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL, + as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, + "rtc-alarm", as3722_rtc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", + as3722_rtc->alarm_irq, ret); + return ret; + } + disable_irq(as3722_rtc->alarm_irq); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int as3722_rtc_suspend(struct device *dev) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(as3722_rtc->alarm_irq); + + return 0; +} + +static int as3722_rtc_resume(struct device *dev) +{ + struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(as3722_rtc->alarm_irq); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(as3722_rtc_pm_ops, as3722_rtc_suspend, + as3722_rtc_resume); + +static struct platform_driver as3722_rtc_driver = { + .probe = as3722_rtc_probe, + .driver = { + .name = "as3722-rtc", + .pm = &as3722_rtc_pm_ops, + }, +}; +module_platform_driver(as3722_rtc_driver); + +MODULE_DESCRIPTION("RTC driver for AS3722 PMICs"); +MODULE_ALIAS("platform:as3722-rtc"); +MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index f47fbb5eee8..aee3387fb09 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -141,7 +141,7 @@ static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) spin_lock_irq(&rtc->lock); - if(enabled) { + if (enabled) { if (rtc_readl(rtc, VAL) > rtc->alarm_time) { ret = -EINVAL; goto out; @@ -204,31 +204,26 @@ static int __init at32_rtc_probe(struct platform_device *pdev) rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x), GFP_KERNEL); - if (!rtc) { - dev_dbg(&pdev->dev, "out of memory\n"); + if (!rtc) return -ENOMEM; - } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_dbg(&pdev->dev, "no mmio resource defined\n"); - ret = -ENXIO; - goto out; + return -ENXIO; } irq = platform_get_irq(pdev, 0); if (irq <= 0) { dev_dbg(&pdev->dev, "could not get irq\n"); - ret = -ENXIO; - goto out; + return -ENXIO; } rtc->irq = irq; rtc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); if (!rtc->regs) { - ret = -ENOMEM; dev_dbg(&pdev->dev, "could not map I/O memory\n"); - goto out; + return -ENOMEM; } spin_lock_init(&rtc->lock); @@ -249,7 +244,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) "rtc", rtc); if (ret) { dev_dbg(&pdev->dev, "could not request irq %d\n", irq); - goto out; + return ret; } platform_set_drvdata(pdev, rtc); @@ -258,8 +253,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) &at32_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc)) { dev_dbg(&pdev->dev, "could not register rtc device\n"); - ret = PTR_ERR(rtc->rtc); - goto out; + return PTR_ERR(rtc->rtc); } device_init_wakeup(&pdev->dev, 1); @@ -268,18 +262,12 @@ static int __init at32_rtc_probe(struct platform_device *pdev) (unsigned long)rtc->regs, rtc->irq); return 0; - -out: - platform_set_drvdata(pdev, NULL); - return ret; } static int __exit at32_rtc_remove(struct platform_device *pdev) { device_init_wakeup(&pdev->dev, 0); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index f296f3f7db9..44fe83ee9be 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -31,8 +31,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_device.h> - -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "rtc-at91rm9200.h" @@ -49,6 +48,7 @@ struct at91_rtc_config { static const struct at91_rtc_config *at91_rtc_config; static DECLARE_COMPLETION(at91_rtc_updated); +static DECLARE_COMPLETION(at91_rtc_upd_rdy); static unsigned int at91_alarm_year = AT91_RTC_EPOCH; static void __iomem *at91_rtc_regs; static int irq; @@ -162,6 +162,8 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + wait_for_completion(&at91_rtc_upd_rdy); + /* Stop Time/Calendar from counting */ cr = at91_rtc_read(AT91_RTC_CR); at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM); @@ -184,7 +186,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) /* Restart Time/Calendar */ cr = at91_rtc_read(AT91_RTC_CR); + at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_SECEV); at91_rtc_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM)); + at91_rtc_write_ier(AT91_RTC_SECEV); return 0; } @@ -221,6 +225,8 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) at91_alarm_year = tm.tm_year; + tm.tm_mon = alrm->time.tm_mon; + tm.tm_mday = alrm->time.tm_mday; tm.tm_hour = alrm->time.tm_hour; tm.tm_min = alrm->time.tm_min; tm.tm_sec = alrm->time.tm_sec; @@ -289,8 +295,10 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) if (rtsr) { /* this interrupt is shared! Is it ours? */ if (rtsr & AT91_RTC_ALARM) events |= (RTC_AF | RTC_IRQF); - if (rtsr & AT91_RTC_SECEV) - events |= (RTC_UF | RTC_IRQF); + if (rtsr & AT91_RTC_SECEV) { + complete(&at91_rtc_upd_rdy); + at91_rtc_write_idr(AT91_RTC_SECEV); + } if (rtsr & AT91_RTC_ACKUPD) complete(&at91_rtc_updated); @@ -377,7 +385,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev) return -ENXIO; } - at91_rtc_regs = ioremap(regs->start, resource_size(regs)); + at91_rtc_regs = devm_ioremap(&pdev->dev, regs->start, + resource_size(regs)); if (!at91_rtc_regs) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); return -ENOMEM; @@ -391,12 +400,12 @@ static int __init at91_rtc_probe(struct platform_device *pdev) AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); - ret = request_irq(irq, at91_rtc_interrupt, + ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt, IRQF_SHARED, "at91_rtc", pdev); if (ret) { dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); - goto err_unmap; + return ret; } /* cpu init code should really have flagged this device as @@ -405,23 +414,19 @@ static int __init at91_rtc_probe(struct platform_device *pdev) if (!device_can_wakeup(&pdev->dev)) device_init_wakeup(&pdev->dev, 1); - rtc = rtc_device_register(pdev->name, &pdev->dev, + rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - goto err_free_irq; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); platform_set_drvdata(pdev, rtc); + /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy + * completion. + */ + at91_rtc_write_ier(AT91_RTC_SECEV); + dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n"); return 0; - -err_free_irq: - free_irq(irq, pdev); -err_unmap: - iounmap(at91_rtc_regs); - - return ret; } /* @@ -429,21 +434,22 @@ err_unmap: */ static int __exit at91_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(pdev); - /* Disable all interrupts */ at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM | AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); - free_irq(irq, pdev); - - rtc_device_unregister(rtc); - iounmap(at91_rtc_regs); - platform_set_drvdata(pdev, NULL); return 0; } +static void at91_rtc_shutdown(struct platform_device *pdev) +{ + /* Disable all interrupts */ + at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | + AT91_RTC_SECEV | AT91_RTC_TIMEV | + AT91_RTC_CALEV); +} + #ifdef CONFIG_PM_SLEEP /* AT91RM9200 RTC Power management control */ @@ -482,6 +488,7 @@ static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); static struct platform_driver at91_rtc_driver = { .remove = __exit_p(at91_rtc_remove), + .shutdown = at91_rtc_shutdown, .driver = { .name = "at91_rtc", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index b60a34cb145..59637430453 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -24,7 +24,7 @@ #include <mach/at91_rtt.h> #include <mach/cpu.h> - +#include <mach/hardware.h> /* * This driver uses two configurable hardware resources that live in the @@ -324,16 +324,14 @@ static int at91_rtc_probe(struct platform_device *pdev) rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r)); if (!rtc->rtt) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); - ret = -ENOMEM; - goto fail; + return -ENOMEM; } rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start, resource_size(r_gpbr)); if (!rtc->gpbr) { dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n"); - ret = -ENOMEM; - goto fail; + return -ENOMEM; } mr = rtt_readl(rtc, MR); @@ -350,17 +348,15 @@ static int at91_rtc_probe(struct platform_device *pdev) rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name, &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtcdev)) { - ret = PTR_ERR(rtc->rtcdev); - goto fail; - } + if (IS_ERR(rtc->rtcdev)) + return PTR_ERR(rtc->rtcdev); /* register irq handler after we know what name we'll use */ ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc); if (ret) { dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); - goto fail; + return ret; } /* NOTE: sam9260 rev A silicon has a ROM bug which resets the @@ -374,10 +370,6 @@ static int at91_rtc_probe(struct platform_device *pdev) dev_name(&rtc->rtcdev->dev)); return 0; - -fail: - platform_set_drvdata(pdev, NULL); - return ret; } /* @@ -391,7 +383,6 @@ static int at91_rtc_remove(struct platform_device *pdev) /* disable all interrupts */ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index 7995abc391f..ed526a192ce 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -116,19 +116,11 @@ out_err: return ret; } -static int au1xtoy_rtc_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - - return 0; -} - static struct platform_driver au1xrtc_driver = { .driver = { .name = "rtc-au1xxx", .owner = THIS_MODULE, }, - .remove = au1xtoy_rtc_remove, }; module_platform_driver_probe(au1xrtc_driver, au1xtoy_rtc_probe); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index ad44ec5dc29..fe4bdb06a55 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -346,7 +346,7 @@ static int bfin_rtc_probe(struct platform_device *pdev) { struct bfin_rtc *rtc; struct device *dev = &pdev->dev; - int ret = 0; + int ret; unsigned long timeout = jiffies + HZ; dev_dbg_stamp(dev); @@ -361,16 +361,17 @@ static int bfin_rtc_probe(struct platform_device *pdev) /* Register our RTC with the RTC framework */ rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc->rtc_dev))) { - ret = PTR_ERR(rtc->rtc_dev); - goto err; - } + if (unlikely(IS_ERR(rtc->rtc_dev))) + return PTR_ERR(rtc->rtc_dev); /* Grab the IRQ and init the hardware */ ret = devm_request_irq(dev, IRQ_RTC, bfin_rtc_interrupt, 0, pdev->name, dev); if (unlikely(ret)) - goto err; + dev_err(&pdev->dev, + "unable to request IRQ; alarm won't work, " + "and writes will be delayed\n"); + /* sometimes the bootloader touched things, but the write complete was not * enabled, so let's just do a quick timeout here since the IRQ will not fire ... */ @@ -381,9 +382,6 @@ static int bfin_rtc_probe(struct platform_device *pdev) bfin_write_RTC_SWCNT(0); return 0; - -err: - return ret; } static int bfin_rtc_remove(struct platform_device *pdev) @@ -391,7 +389,6 @@ static int bfin_rtc_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; bfin_rtc_reset(dev, 0); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index fea78bc713c..c74bf0dc52c 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -163,11 +163,6 @@ static int bq32k_probe(struct i2c_client *client, return 0; } -static int bq32k_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id bq32k_id[] = { { "bq32000", 0 }, { } @@ -180,7 +175,6 @@ static struct i2c_driver bq32k_driver = { .owner = THIS_MODULE, }, .probe = bq32k_probe, - .remove = bq32k_remove, .id_table = bq32k_id, }; diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index af2886784a7..fc0ff87aa5d 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -186,13 +186,6 @@ out: } -static int bq4802_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - - return 0; -} - /* work with hotplug and coldplug */ MODULE_ALIAS("platform:rtc-bq4802"); @@ -202,7 +195,6 @@ static struct platform_driver bq4802_driver = { .owner = THIS_MODULE, }, .probe = bq4802_probe, - .remove = bq4802_remove, }; module_platform_driver(bq4802_driver); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index f1cb706445c..b0e4a3eb33c 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -34,11 +34,11 @@ #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/platform_device.h> -#include <linux/mod_devicetable.h> #include <linux/log2.h> #include <linux/pm.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/dmi.h> /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <asm-generic/rtc.h> @@ -326,7 +326,7 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask) static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); - unsigned char mon, mday, hrs, min, sec, rtc_control; + unsigned char mon, mday, hrs, min, sec, rtc_control; if (!is_valid_irq(cmos->irq)) return -EIO; @@ -377,6 +377,51 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } +/* + * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. + */ +static bool alarm_disable_quirk; + +static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) +{ + alarm_disable_quirk = true; + pr_info("rtc-cmos: BIOS has alarm-disable quirk. "); + pr_info("RTC alarms disabled\n"); + return 0; +} + +static const struct dmi_system_id rtc_quirks[] __initconst = { + /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ + { + .callback = set_alarm_disable_quirk, + .ident = "IBM Truman", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), + }, + }, + /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ + { + .callback = set_alarm_disable_quirk, + .ident = "Gigabyte GA-990XA-UD3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), + }, + }, + /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ + { + .callback = set_alarm_disable_quirk, + .ident = "Toshiba Satellite L300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), + }, + }, + {} +}; + static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -385,6 +430,9 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) if (!is_valid_irq(cmos->irq)) return -EINVAL; + if (alarm_disable_quirk) + return 0; + spin_lock_irqsave(&rtc_lock, flags); if (enabled) @@ -556,17 +604,24 @@ static irqreturn_t cmos_interrupt(int irq, void *p) rtc_control = CMOS_READ(RTC_CONTROL); if (is_hpet_enabled()) irqstat = (unsigned long)irq & 0xF0; - irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; + + /* If we were suspended, RTC_CONTROL may not be accurate since the + * bios may have cleared it. + */ + if (!cmos_rtc.suspend_ctrl) + irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; + else + irqstat &= (cmos_rtc.suspend_ctrl & RTC_IRQMASK) | RTC_IRQF; /* All Linux RTC alarms should be treated as if they were oneshot. * Similar code may be needed in system wakeup paths, in case the * alarm woke the system. */ if (irqstat & RTC_AIE) { + cmos_rtc.suspend_ctrl &= ~RTC_AIE; rtc_control &= ~RTC_AIE; CMOS_WRITE(rtc_control, RTC_CONTROL); hpet_mask_rtc_irq_bit(RTC_AIE); - CMOS_READ(RTC_INTR_FLAGS); } spin_unlock(&rtc_lock); @@ -588,10 +643,11 @@ static irqreturn_t cmos_interrupt(int irq, void *p) static int INITSECTION cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) { - struct cmos_rtc_board_info *info = dev->platform_data; + struct cmos_rtc_board_info *info = dev_get_platdata(dev); int retval = 0; unsigned char rtc_control; unsigned address_space; + u32 flags = 0; /* there can be only one ... */ if (cmos_rtc.dev) @@ -605,9 +661,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) * REVISIT non-x86 systems may instead use memory space resources * (needing ioremap etc), not i/o space resources like this ... */ - ports = request_region(ports->start, - resource_size(ports), - driver_name); + if (RTC_IOMAPPED) + ports = request_region(ports->start, resource_size(ports), + driver_name); + else + ports = request_mem_region(ports->start, resource_size(ports), + driver_name); if (!ports) { dev_dbg(dev, "i/o registers already in use\n"); return -EBUSY; @@ -644,6 +703,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) * expect CMOS_READ and friends to handle. */ if (info) { + if (info->flags) + flags = info->flags; + if (info->address_space) + address_space = info->address_space; + if (info->rtc_day_alarm && info->rtc_day_alarm < 128) cmos_rtc.day_alrm = info->rtc_day_alarm; if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128) @@ -671,18 +735,21 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) spin_lock_irq(&rtc_lock); - /* force periodic irq to CMOS reset default of 1024Hz; - * - * REVISIT it's been reported that at least one x86_64 ALI mobo - * doesn't use 32KHz here ... for portability we might need to - * do something about other clock frequencies. - */ - cmos_rtc.rtc->irq_freq = 1024; - hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); - CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); + if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) { + /* force periodic irq to CMOS reset default of 1024Hz; + * + * REVISIT it's been reported that at least one x86_64 ALI + * mobo doesn't use 32KHz here ... for portability we might + * need to do something about other clock frequencies. + */ + cmos_rtc.rtc->irq_freq = 1024; + hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); + CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); + } /* disable irqs */ - cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); + if (is_valid_irq(rtc_irq)) + cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); rtc_control = CMOS_READ(RTC_CONTROL); @@ -691,7 +758,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) /* FIXME: * <asm-generic/rtc.h> doesn't know 12-hour mode either. */ - if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { + if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { dev_warn(dev, "only 24-hr supported\n"); retval = -ENXIO; goto cleanup1; @@ -701,11 +768,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) irq_handler_t rtc_cmos_int_handler; if (is_hpet_enabled()) { - int err; - rtc_cmos_int_handler = hpet_rtc_interrupt; - err = hpet_register_irq_handler(cmos_interrupt); - if (err != 0) { + retval = hpet_register_irq_handler(cmos_interrupt); + if (retval) { dev_warn(dev, "hpet_register_irq_handler " " failed in rtc_init()."); goto cleanup1; @@ -749,14 +814,18 @@ cleanup1: cmos_rtc.dev = NULL; rtc_device_unregister(cmos_rtc.rtc); cleanup0: - release_region(ports->start, resource_size(ports)); + if (RTC_IOMAPPED) + release_region(ports->start, resource_size(ports)); + else + release_mem_region(ports->start, resource_size(ports)); return retval; } -static void cmos_do_shutdown(void) +static void cmos_do_shutdown(int rtc_irq) { spin_lock_irq(&rtc_lock); - cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); + if (is_valid_irq(rtc_irq)) + cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); spin_unlock_irq(&rtc_lock); } @@ -765,7 +834,7 @@ static void __exit cmos_do_remove(struct device *dev) struct cmos_rtc *cmos = dev_get_drvdata(dev); struct resource *ports; - cmos_do_shutdown(); + cmos_do_shutdown(cmos->irq); sysfs_remove_bin_file(&dev->kobj, &nvram); @@ -778,14 +847,16 @@ static void __exit cmos_do_remove(struct device *dev) cmos->rtc = NULL; ports = cmos->iomem; - release_region(ports->start, resource_size(ports)); + if (RTC_IOMAPPED) + release_region(ports->start, resource_size(ports)); + else + release_mem_region(ports->start, resource_size(ports)); cmos->iomem = NULL; cmos->dev = NULL; - dev_set_drvdata(dev, NULL); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int cmos_suspend(struct device *dev) { @@ -839,21 +910,23 @@ static inline int cmos_poweroff(struct device *dev) static int cmos_resume(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); - unsigned char tmp = cmos->suspend_ctrl; + unsigned char tmp; + if (cmos->enabled_wake) { + if (cmos->wake_off) + cmos->wake_off(dev); + else + disable_irq_wake(cmos->irq); + cmos->enabled_wake = 0; + } + + spin_lock_irq(&rtc_lock); + tmp = cmos->suspend_ctrl; + cmos->suspend_ctrl = 0; /* re-enable any irqs previously active */ if (tmp & RTC_IRQMASK) { unsigned char mask; - if (cmos->enabled_wake) { - if (cmos->wake_off) - cmos->wake_off(dev); - else - disable_irq_wake(cmos->irq); - cmos->enabled_wake = 0; - } - - spin_lock_irq(&rtc_lock); if (device_may_wakeup(dev)) hpet_rtc_timer_init(); @@ -873,16 +946,14 @@ static int cmos_resume(struct device *dev) tmp &= ~RTC_AIE; hpet_mask_rtc_irq_bit(RTC_AIE); } while (mask & RTC_AIE); - spin_unlock_irq(&rtc_lock); } + spin_unlock_irq(&rtc_lock); dev_dbg(dev, "resume, ctrl %02x\n", tmp); return 0; } -static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); - #else static inline int cmos_poweroff(struct device *dev) @@ -892,6 +963,8 @@ static inline int cmos_poweroff(struct device *dev) #endif +static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); + /*----------------------------------------------------------------*/ /* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus. @@ -991,7 +1064,7 @@ static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) { cmos_wake_setup(&pnp->dev); - if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0)) + if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) /* Some machines contain a PNP entry for the RTC, but * don't define the IRQ. It should always be safe to * hardcode it in these cases @@ -1009,29 +1082,15 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp) cmos_do_remove(&pnp->dev); } -#ifdef CONFIG_PM - -static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg) -{ - return cmos_suspend(&pnp->dev); -} - -static int cmos_pnp_resume(struct pnp_dev *pnp) -{ - return cmos_resume(&pnp->dev); -} - -#else -#define cmos_pnp_suspend NULL -#define cmos_pnp_resume NULL -#endif - static void cmos_pnp_shutdown(struct pnp_dev *pnp) { - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev)) + struct device *dev = &pnp->dev; + struct cmos_rtc *cmos = dev_get_drvdata(dev); + + if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) return; - cmos_do_shutdown(); + cmos_do_shutdown(cmos->irq); } static const struct pnp_device_id rtc_ids[] = { @@ -1051,8 +1110,9 @@ static struct pnp_driver cmos_pnp_driver = { /* flag ensures resume() gets called, and stops syslog spam */ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, - .suspend = cmos_pnp_suspend, - .resume = cmos_pnp_resume, + .driver = { + .pm = &cmos_pm_ops, + }, }; #endif /* CONFIG_PNP */ @@ -1105,11 +1165,21 @@ static inline void cmos_of_init(struct platform_device *pdev) {} static int __init cmos_platform_probe(struct platform_device *pdev) { + struct resource *resource; + int irq; + cmos_of_init(pdev); cmos_wake_setup(&pdev->dev); - return cmos_do_probe(&pdev->dev, - platform_get_resource(pdev, IORESOURCE_IO, 0), - platform_get_irq(pdev, 0)); + + if (RTC_IOMAPPED) + resource = platform_get_resource(pdev, IORESOURCE_IO, 0); + else + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + irq = -1; + + return cmos_do_probe(&pdev->dev, resource, irq); } static int __exit cmos_platform_remove(struct platform_device *pdev) @@ -1120,10 +1190,13 @@ static int __exit cmos_platform_remove(struct platform_device *pdev) static void cmos_platform_shutdown(struct platform_device *pdev) { - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev)) + struct device *dev = &pdev->dev; + struct cmos_rtc *cmos = dev_get_drvdata(dev); + + if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) return; - cmos_do_shutdown(); + cmos_do_shutdown(cmos->irq); } /* work with hotplug and coldplug */ @@ -1133,7 +1206,7 @@ static struct platform_driver cmos_platform_driver = { .remove = __exit_p(cmos_platform_remove), .shutdown = cmos_platform_shutdown, .driver = { - .name = (char *) driver_name, + .name = driver_name, #ifdef CONFIG_PM .pm = &cmos_pm_ops, #endif @@ -1163,6 +1236,8 @@ static int __init cmos_init(void) platform_driver_registered = true; } + dmi_check_system(rtc_quirks); + if (retval == 0) return 0; diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 93c06588ddc..869cae27379 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -43,8 +43,6 @@ struct coh901331_port { struct rtc_device *rtc; struct clk *clk; - u32 phybase; - u32 physize; void __iomem *virtbase; int irq; #ifdef CONFIG_PM_SLEEP @@ -152,12 +150,10 @@ static struct rtc_class_ops coh901331_ops = { static int __exit coh901331_remove(struct platform_device *pdev) { - struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); + struct coh901331_port *rtap = platform_get_drvdata(pdev); - if (rtap) { + if (rtap) clk_unprepare(rtap->clk); - platform_set_drvdata(pdev, NULL); - } return 0; } @@ -175,19 +171,9 @@ static int __init coh901331_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOENT; - - rtap->phybase = res->start; - rtap->physize = resource_size(res); - - if (devm_request_mem_region(&pdev->dev, rtap->phybase, rtap->physize, - "rtc-coh901331") == NULL) - return -EBUSY; - - rtap->virtbase = devm_ioremap(&pdev->dev, rtap->phybase, rtap->physize); - if (!rtap->virtbase) - return -ENOMEM; + rtap->virtbase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rtap->virtbase)) + return PTR_ERR(rtap->virtbase); rtap->irq = platform_get_irq(pdev, 0); if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0, @@ -220,7 +206,6 @@ static int __init coh901331_probe(struct platform_device *pdev) return 0; out_no_rtc: - platform_set_drvdata(pdev, NULL); clk_unprepare(rtap->clk); return ret; } @@ -267,18 +252,24 @@ static SIMPLE_DEV_PM_OPS(coh901331_pm_ops, coh901331_suspend, coh901331_resume); static void coh901331_shutdown(struct platform_device *pdev) { - struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); + struct coh901331_port *rtap = platform_get_drvdata(pdev); clk_enable(rtap->clk); writel(0, rtap->virtbase + COH901331_IRQ_MASK); clk_disable_unprepare(rtap->clk); } +static const struct of_device_id coh901331_dt_match[] = { + { .compatible = "stericsson,coh901331" }, + {}, +}; + static struct platform_driver coh901331_driver = { .driver = { .name = "rtc-coh901331", .owner = THIS_MODULE, .pm = &coh901331_pm_ops, + .of_match_table = coh901331_dt_match, }, .remove = __exit_p(coh901331_remove), .shutdown = coh901331_shutdown, diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 7286b279cf2..e5c9486cf45 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -15,33 +15,33 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/rtc.h> +#include <linux/err.h> #include <linux/mfd/da9052/da9052.h> #include <linux/mfd/da9052/reg.h> -#define rtc_err(da9052, fmt, ...) \ - dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) +#define rtc_err(rtc, fmt, ...) \ + dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) struct da9052_rtc { struct rtc_device *rtc; struct da9052 *da9052; - int irq; }; -static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable) +static int da9052_rtc_enable_alarm(struct da9052_rtc *rtc, bool enable) { int ret; if (enable) { - ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, - DA9052_ALARM_Y_ALARM_ON, - DA9052_ALARM_Y_ALARM_ON); + ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, + DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, + DA9052_ALARM_Y_ALARM_ON); if (ret != 0) - rtc_err(da9052, "Failed to enable ALM: %d\n", ret); + rtc_err(rtc, "Failed to enable ALM: %d\n", ret); } else { - ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, - DA9052_ALARM_Y_ALARM_ON, 0); + ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, + DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, 0); if (ret != 0) - rtc_err(da9052, "Write error: %d\n", ret); + rtc_err(rtc, "Write error: %d\n", ret); } return ret; } @@ -49,31 +49,20 @@ static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable) static irqreturn_t da9052_rtc_irq(int irq, void *data) { struct da9052_rtc *rtc = data; - int ret; - - ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG); - if (ret < 0) { - rtc_err(rtc->da9052, "Read error: %d\n", ret); - return IRQ_NONE; - } - if (ret & DA9052_ALARMMI_ALARMTYPE) { - da9052_rtc_enable_alarm(rtc->da9052, 0); - rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); - } else - rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF); + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); return IRQ_HANDLED; } -static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) +static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) { int ret; uint8_t v[5]; - ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v); + ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v); if (ret != 0) { - rtc_err(da9052, "Failed to group read ALM: %d\n", ret); + rtc_err(rtc, "Failed to group read ALM: %d\n", ret); return ret; } @@ -84,23 +73,33 @@ static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) rtc_tm->tm_min = v[0] & DA9052_RTC_MIN; ret = rtc_valid_tm(rtc_tm); - if (ret != 0) - return ret; return ret; } -static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) +static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm) { + struct da9052 *da9052 = rtc->da9052; + unsigned long alm_time; int ret; uint8_t v[3]; + ret = rtc_tm_to_time(rtc_tm, &alm_time); + if (ret != 0) + return ret; + + if (rtc_tm->tm_sec > 0) { + alm_time += 60 - rtc_tm->tm_sec; + rtc_time_to_tm(alm_time, rtc_tm); + } + BUG_ON(rtc_tm->tm_sec); /* it will cause repeated irqs if not zero */ + rtc_tm->tm_year -= 100; rtc_tm->tm_mon += 1; ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG, DA9052_RTC_MIN, rtc_tm->tm_min); if (ret != 0) { - rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret); + rtc_err(rtc, "Failed to write ALRM MIN: %d\n", ret); return ret; } @@ -115,22 +114,22 @@ static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, DA9052_RTC_YEAR, rtc_tm->tm_year); if (ret != 0) - rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret); + rtc_err(rtc, "Failed to write ALRM YEAR: %d\n", ret); return ret; } -static int da9052_rtc_get_alarm_status(struct da9052 *da9052) +static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc) { int ret; - ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG); + ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_Y_REG); if (ret < 0) { - rtc_err(da9052, "Failed to read ALM: %d\n", ret); + rtc_err(rtc, "Failed to read ALM: %d\n", ret); return ret; } - ret &= DA9052_ALARM_Y_ALARM_ON; - return (ret > 0) ? 1 : 0; + + return !!(ret&DA9052_ALARM_Y_ALARM_ON); } static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) @@ -141,7 +140,7 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v); if (ret < 0) { - rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret); + rtc_err(rtc, "Failed to read RTC time : %d\n", ret); return ret; } @@ -153,18 +152,14 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_sec = v[0] & DA9052_RTC_SEC; ret = rtc_valid_tm(rtc_tm); - if (ret != 0) { - rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret); - return ret; - } - - return 0; + return ret; } static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct da9052_rtc *rtc; uint8_t v[6]; + int ret; rtc = dev_get_drvdata(dev); @@ -175,7 +170,10 @@ static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) v[4] = tm->tm_mon + 1; v[5] = tm->tm_year - 100; - return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); + ret = da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); + if (ret < 0) + rtc_err(rtc, "failed to set RTC time: %d\n", ret); + return ret; } static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -184,13 +182,13 @@ static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; struct da9052_rtc *rtc = dev_get_drvdata(dev); - ret = da9052_read_alarm(rtc->da9052, tm); - - if (ret) + ret = da9052_read_alarm(rtc, tm); + if (ret < 0) { + rtc_err(rtc, "failed to read RTC alarm: %d\n", ret); return ret; + } - alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052); - + alrm->enabled = da9052_rtc_get_alarm_status(rtc); return 0; } @@ -200,16 +198,15 @@ static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; struct da9052_rtc *rtc = dev_get_drvdata(dev); - ret = da9052_rtc_enable_alarm(rtc->da9052, 0); + ret = da9052_rtc_enable_alarm(rtc, 0); if (ret < 0) return ret; - ret = da9052_set_alarm(rtc->da9052, tm); - if (ret) + ret = da9052_set_alarm(rtc, tm); + if (ret < 0) return ret; - ret = da9052_rtc_enable_alarm(rtc->da9052, 1); - + ret = da9052_rtc_enable_alarm(rtc, 1); return ret; } @@ -217,7 +214,7 @@ static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct da9052_rtc *rtc = dev_get_drvdata(dev); - return da9052_rtc_enable_alarm(rtc->da9052, enabled); + return da9052_rtc_enable_alarm(rtc, enabled); } static const struct rtc_class_ops da9052_rtc_ops = { @@ -239,32 +236,33 @@ static int da9052_rtc_probe(struct platform_device *pdev) rtc->da9052 = dev_get_drvdata(pdev->dev.parent); platform_set_drvdata(pdev, rtc); - rtc->irq = DA9052_IRQ_ALARM; - ret = da9052_request_irq(rtc->da9052, rtc->irq, "ALM", + + ret = da9052_reg_write(rtc->da9052, DA9052_BBAT_CONT_REG, 0xFE); + if (ret < 0) { + rtc_err(rtc, + "Failed to setup RTC battery charging: %d\n", ret); + return ret; + } + + ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, + DA9052_ALARM_Y_TICK_ON, 0); + if (ret != 0) + rtc_err(rtc, "Failed to disable TICKS: %d\n", ret); + + ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM", da9052_rtc_irq, rtc); if (ret != 0) { - rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); + rtc_err(rtc, "irq registration failed: %d\n", ret); return ret; } rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &da9052_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc)) - return PTR_ERR(rtc->rtc); - - return 0; -} - -static int da9052_rtc_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - - return 0; + return PTR_ERR_OR_ZERO(rtc->rtc); } static struct platform_driver da9052_rtc_driver = { .probe = da9052_rtc_probe, - .remove = da9052_rtc_remove, .driver = { .name = "da9052-rtc", .owner = THIS_MODULE, @@ -273,7 +271,7 @@ static struct platform_driver da9052_rtc_driver = { module_platform_driver(da9052_rtc_driver); -MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>"); MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:da9052-rtc"); diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c index 73858ca9709..a825491331c 100644 --- a/drivers/rtc/rtc-da9055.c +++ b/drivers/rtc/rtc-da9055.c @@ -278,7 +278,7 @@ static int da9055_rtc_probe(struct platform_device *pdev) return -ENOMEM; rtc->da9055 = dev_get_drvdata(pdev->dev.parent); - pdata = rtc->da9055->dev->platform_data; + pdata = dev_get_platdata(rtc->da9055->dev); platform_set_drvdata(pdev, rtc); ret = da9055_rtc_device_init(rtc->da9055, pdata); @@ -302,7 +302,9 @@ static int da9055_rtc_probe(struct platform_device *pdev) } alm_irq = platform_get_irq_byname(pdev, "ALM"); - alm_irq = regmap_irq_get_virq(rtc->da9055->irq_data, alm_irq); + if (alm_irq < 0) + return alm_irq; + ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, da9055_rtc_alm_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, @@ -315,13 +317,6 @@ err_rtc: } -static int da9055_rtc_remove(struct platform_device *pdev) -{ - 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) @@ -394,7 +389,6 @@ static const struct dev_pm_ops da9055_rtc_pm_ops = { static struct platform_driver da9055_rtc_driver = { .probe = da9055_rtc_probe, - .remove = da9055_rtc_remove, .driver = { .name = "da9055-rtc", .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c new file mode 100644 index 00000000000..595393098b0 --- /dev/null +++ b/drivers/rtc/rtc-da9063.c @@ -0,0 +1,333 @@ +/* rtc-da9063.c - Real time clock device driver for DA9063 + * Copyright (C) 2013-14 Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/rtc.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/regmap.h> +#include <linux/mfd/da9063/registers.h> +#include <linux/mfd/da9063/core.h> + +#define YEARS_TO_DA9063(year) ((year) - 100) +#define MONTHS_TO_DA9063(month) ((month) + 1) +#define YEARS_FROM_DA9063(year) ((year) + 100) +#define MONTHS_FROM_DA9063(month) ((month) - 1) + +#define RTC_DATA_LEN (DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1) +#define RTC_SEC 0 +#define RTC_MIN 1 +#define RTC_HOUR 2 +#define RTC_DAY 3 +#define RTC_MONTH 4 +#define RTC_YEAR 5 + +struct da9063_rtc { + struct rtc_device *rtc_dev; + struct da9063 *hw; + struct rtc_time alarm_time; + bool rtc_sync; +}; + +static void da9063_data_to_tm(u8 *data, struct rtc_time *tm) +{ + tm->tm_sec = data[RTC_SEC] & DA9063_COUNT_SEC_MASK; + tm->tm_min = data[RTC_MIN] & DA9063_COUNT_MIN_MASK; + tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK; + tm->tm_mday = data[RTC_DAY] & DA9063_COUNT_DAY_MASK; + tm->tm_mon = MONTHS_FROM_DA9063(data[RTC_MONTH] & + DA9063_COUNT_MONTH_MASK); + tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] & + DA9063_COUNT_YEAR_MASK); +} + +static void da9063_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK; + data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK; + + data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK; + data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK; + + data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK; + data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK; + + data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK; + data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK; + + data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK; + data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) & + DA9063_COUNT_MONTH_MASK; + + data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK; + data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) & + DA9063_COUNT_YEAR_MASK; +} + +static int da9063_rtc_stop_alarm(struct device *dev) +{ + struct da9063_rtc *rtc = dev_get_drvdata(dev); + + return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, + DA9063_ALARM_ON, 0); +} + +static int da9063_rtc_start_alarm(struct device *dev) +{ + struct da9063_rtc *rtc = dev_get_drvdata(dev); + + return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, + DA9063_ALARM_ON, DA9063_ALARM_ON); +} + +static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct da9063_rtc *rtc = dev_get_drvdata(dev); + unsigned long tm_secs; + unsigned long al_secs; + u8 data[RTC_DATA_LEN]; + int ret; + + ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S, + data, RTC_DATA_LEN); + if (ret < 0) { + dev_err(dev, "Failed to read RTC time data: %d\n", ret); + return ret; + } + + if (!(data[RTC_SEC] & DA9063_RTC_READ)) { + dev_dbg(dev, "RTC not yet ready to be read by the host\n"); + return -EINVAL; + } + + da9063_data_to_tm(data, tm); + + rtc_tm_to_time(tm, &tm_secs); + rtc_tm_to_time(&rtc->alarm_time, &al_secs); + + /* handle the rtc synchronisation delay */ + if (rtc->rtc_sync == true && al_secs - tm_secs == 1) + memcpy(tm, &rtc->alarm_time, sizeof(struct rtc_time)); + else + rtc->rtc_sync = false; + + return rtc_valid_tm(tm); +} + +static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct da9063_rtc *rtc = dev_get_drvdata(dev); + u8 data[RTC_DATA_LEN]; + int ret; + + da9063_tm_to_data(tm, data); + ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S, + data, RTC_DATA_LEN); + if (ret < 0) + dev_err(dev, "Failed to set RTC time data: %d\n", ret); + + return ret; +} + +static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct da9063_rtc *rtc = dev_get_drvdata(dev); + u8 data[RTC_DATA_LEN]; + int ret; + unsigned int val; + + ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_ALARM_S, + &data[RTC_SEC], RTC_DATA_LEN); + if (ret < 0) + return ret; + + da9063_data_to_tm(data, &alrm->time); + + alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON); + + ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val); + if (ret < 0) + return ret; + + if (val & (DA9063_E_ALARM)) + alrm->pending = 1; + else + alrm->pending = 0; + + return 0; +} + +static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct da9063_rtc *rtc = dev_get_drvdata(dev); + u8 data[RTC_DATA_LEN]; + int ret; + + da9063_tm_to_data(&alrm->time, data); + + ret = da9063_rtc_stop_alarm(dev); + if (ret < 0) { + dev_err(dev, "Failed to stop alarm: %d\n", ret); + return ret; + } + + ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_ALARM_S, + data, RTC_DATA_LEN); + if (ret < 0) { + dev_err(dev, "Failed to write alarm: %d\n", ret); + return ret; + } + + rtc->alarm_time = alrm->time; + + if (alrm->enabled) { + ret = da9063_rtc_start_alarm(dev); + if (ret < 0) { + dev_err(dev, "Failed to start alarm: %d\n", ret); + return ret; + } + } + + return ret; +} + +static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + if (enabled) + return da9063_rtc_start_alarm(dev); + else + return da9063_rtc_stop_alarm(dev); +} + +static irqreturn_t da9063_alarm_event(int irq, void *data) +{ + struct da9063_rtc *rtc = data; + + regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, + DA9063_ALARM_ON, 0); + + rtc->rtc_sync = true; + rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops da9063_rtc_ops = { + .read_time = da9063_rtc_read_time, + .set_time = da9063_rtc_set_time, + .read_alarm = da9063_rtc_read_alarm, + .set_alarm = da9063_rtc_set_alarm, + .alarm_irq_enable = da9063_rtc_alarm_irq_enable, +}; + +static int da9063_rtc_probe(struct platform_device *pdev) +{ + struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); + struct da9063_rtc *rtc; + int irq_alarm; + u8 data[RTC_DATA_LEN]; + int ret; + + ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E, + DA9063_RTC_EN, DA9063_RTC_EN); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable RTC\n"); + goto err; + } + + ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K, + DA9063_CRYSTAL, DA9063_CRYSTAL); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n"); + goto err; + } + + ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S, + DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM, + 0); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); + goto err; + } + + ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S, + DA9063_ALARM_STATUS_ALARM, + DA9063_ALARM_STATUS_ALARM); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); + goto err; + } + + ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_Y, + DA9063_TICK_ON, 0); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to disable TICKs\n"); + goto err; + } + + ret = regmap_bulk_read(da9063->regmap, DA9063_REG_ALARM_S, + data, RTC_DATA_LEN); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n", + ret); + goto err; + } + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + platform_set_drvdata(pdev, rtc); + + irq_alarm = platform_get_irq_byname(pdev, "ALARM"); + ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, + da9063_alarm_event, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "ALARM", rtc); + if (ret) { + dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", + irq_alarm, ret); + goto err; + } + + rtc->hw = da9063; + rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, + &da9063_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + + da9063_data_to_tm(data, &rtc->alarm_time); + rtc->rtc_sync = false; +err: + return ret; +} + +static struct platform_driver da9063_rtc_driver = { + .probe = da9063_rtc_probe, + .driver = { + .name = DA9063_DRVNAME_RTC, + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da9063_rtc_driver); + +MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); +MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC); diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index a55048c3e26..c0a3b59f65a 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -117,10 +117,8 @@ static DEFINE_SPINLOCK(davinci_rtc_lock); struct davinci_rtc { - struct rtc_device *rtc; + struct rtc_device *rtc; void __iomem *base; - resource_size_t pbase; - size_t base_size; int irq; }; @@ -482,14 +480,12 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct davinci_rtc *davinci_rtc; - struct resource *res, *mem; + struct resource *res; int ret = 0; 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"); + if (!davinci_rtc) return -ENOMEM; - } davinci_rtc->irq = platform_get_irq(pdev, 0); if (davinci_rtc->irq < 0) { @@ -498,38 +494,18 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "no mem resource\n"); - return -EINVAL; - } - - davinci_rtc->pbase = res->start; - davinci_rtc->base_size = resource_size(res); - - 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); - return -EBUSY; - } - - 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"); - return -ENOMEM; - } + davinci_rtc->base = devm_ioremap_resource(dev, res); + if (IS_ERR(davinci_rtc->base)) + return PTR_ERR(davinci_rtc->base); platform_set_drvdata(pdev, davinci_rtc); davinci_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &davinci_rtc_ops, THIS_MODULE); if (IS_ERR(davinci_rtc->rtc)) { - ret = PTR_ERR(davinci_rtc->rtc); dev_err(dev, "unable to register RTC device, err %d\n", ret); - goto fail1; + return PTR_ERR(davinci_rtc->rtc); } rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG); @@ -543,7 +519,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) 0, "davinci_rtc", davinci_rtc); if (ret < 0) { dev_err(dev, "unable to register davinci RTC interrupt\n"); - goto fail1; + return ret; } /* Enable interrupts */ @@ -556,10 +532,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); return 0; - -fail1: - platform_set_drvdata(pdev, NULL); - return ret; } static int __exit davinci_rtc_remove(struct platform_device *pdev) @@ -570,8 +542,6 @@ static int __exit davinci_rtc_remove(struct platform_device *pdev) rtcif_write(davinci_rtc, 0, PRTCIF_INTEN); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c index 1e1ca63d58a..1aca08394c4 100644 --- a/drivers/rtc/rtc-dm355evm.c +++ b/drivers/rtc/rtc-dm355evm.c @@ -139,19 +139,12 @@ static int dm355evm_rtc_probe(struct platform_device *pdev) return 0; } -static int dm355evm_rtc_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - return 0; -} - /* * I2C is used to talk to the MSP430, but this platform device is * exposed by an MFD driver that manages I2C communications. */ static struct platform_driver rtc_dm355evm_driver = { .probe = dm355evm_rtc_probe, - .remove = dm355evm_rtc_remove, .driver = { .owner = THIS_MODULE, .name = "rtc-dm355evm", diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c index c7702b7269f..9c04fd2bc20 100644 --- a/drivers/rtc/rtc-ds1216.c +++ b/drivers/rtc/rtc-ds1216.c @@ -167,34 +167,17 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit ds1216_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver ds1216_rtc_platform_driver = { .driver = { .name = "rtc-ds1216", .owner = THIS_MODULE, }, - .remove = __exit_p(ds1216_rtc_remove), }; -static int __init ds1216_rtc_init(void) -{ - return platform_driver_probe(&ds1216_rtc_platform_driver, ds1216_rtc_probe); -} - -static void __exit ds1216_rtc_exit(void) -{ - platform_driver_unregister(&ds1216_rtc_platform_driver); -} +module_platform_driver_probe(ds1216_rtc_platform_driver, ds1216_rtc_probe); MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); MODULE_DESCRIPTION("DS1216 RTC driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_ALIAS("platform:rtc-ds1216"); - -module_init(ds1216_rtc_init); -module_exit(ds1216_rtc_exit); diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 398c96a98fc..50e109b7825 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -353,18 +353,12 @@ static int ds1286_probe(struct platform_device *pdev) return 0; } -static int ds1286_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver ds1286_platform_driver = { .driver = { .name = "rtc-ds1286", .owner = THIS_MODULE, }, .probe = ds1286_probe, - .remove = ds1286_remove, }; module_platform_driver(ds1286_platform_driver); diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index d1395434628..07e8d79b4a0 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -23,8 +23,12 @@ #define RTC_CMD_READ 0x81 /* Read command */ #define RTC_CMD_WRITE 0x80 /* Write command */ +#define RTC_CMD_WRITE_ENABLE 0x00 /* Write enable */ +#define RTC_CMD_WRITE_DISABLE 0x80 /* Write disable */ + #define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */ #define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */ +#define RTC_ADDR_CTRL 0x07 /* Address of control register */ #define RTC_ADDR_YEAR 0x06 /* Address of year register */ #define RTC_ADDR_DAY 0x05 /* Address of day of week register */ #define RTC_ADDR_MON 0x04 /* Address of month register */ @@ -161,6 +165,7 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm) { + ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_ENABLE); /* Stop RTC */ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80); @@ -175,6 +180,8 @@ static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm) /* Start RTC */ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80); + ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_DISABLE); + return 0; } @@ -234,19 +241,11 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit ds1302_rtc_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - - return 0; -} - static struct platform_driver ds1302_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, - .remove = __exit_p(ds1302_rtc_remove), }; module_platform_driver_probe(ds1302_platform_driver, ds1302_rtc_probe); diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index bb5f13f6363..129add77065 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -158,7 +158,7 @@ static int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled) goto done; buf[1] &= ~DS1305_AEI0; } - err = spi_write_then_read(ds1305->spi, buf, sizeof buf, NULL, 0); + err = spi_write_then_read(ds1305->spi, buf, sizeof(buf), NULL, 0); if (err >= 0) ds1305->ctrl[0] = buf[1]; done: @@ -181,8 +181,8 @@ static int ds1305_get_time(struct device *dev, struct rtc_time *time) /* Use write-then-read to get all the date/time registers * since dma from stack is nonportable */ - status = spi_write_then_read(ds1305->spi, &addr, sizeof addr, - buf, sizeof buf); + status = spi_write_then_read(ds1305->spi, &addr, sizeof(addr), + buf, sizeof(buf)); if (status < 0) return status; @@ -237,7 +237,7 @@ static int ds1305_set_time(struct device *dev, struct rtc_time *time) buf[4], buf[5], buf[6], buf[7]); /* use write-then-read since dma from stack is nonportable */ - return spi_write_then_read(ds1305->spi, buf, sizeof buf, + return spi_write_then_read(ds1305->spi, buf, sizeof(buf), NULL, 0); } @@ -286,8 +286,8 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm) * of EFI status is at best fragile anyway (given IRQ handlers). */ addr = DS1305_CONTROL; - status = spi_write_then_read(spi, &addr, sizeof addr, - ds1305->ctrl, sizeof ds1305->ctrl); + status = spi_write_then_read(spi, &addr, sizeof(addr), + ds1305->ctrl, sizeof(ds1305->ctrl)); if (status < 0) return status; @@ -296,8 +296,8 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm) /* get and check ALM0 registers */ addr = DS1305_ALM0(DS1305_SEC); - status = spi_write_then_read(spi, &addr, sizeof addr, - buf, sizeof buf); + status = spi_write_then_read(spi, &addr, sizeof(addr), + buf, sizeof(buf)); if (status < 0) return status; @@ -381,7 +381,7 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm) "alm0 write", buf[1 + DS1305_SEC], buf[1 + DS1305_MIN], buf[1 + DS1305_HOUR], buf[1 + DS1305_WDAY]); - status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0); + status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0); if (status < 0) return status; @@ -474,7 +474,7 @@ static void ds1305_work(struct work_struct *work) buf[1] = ds1305->ctrl[0]; buf[2] = 0; - status = spi_write_then_read(spi, buf, sizeof buf, + status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0); if (status < 0) dev_dbg(&spi->dev, "clear irq --> %d\n", status); @@ -606,7 +606,7 @@ static int ds1305_probe(struct spi_device *spi) struct ds1305 *ds1305; int status; u8 addr, value; - struct ds1305_platform_data *pdata = spi->dev.platform_data; + struct ds1305_platform_data *pdata = dev_get_platdata(&spi->dev); bool write_ctrl = false; /* Sanity check board setup data. This may be hooked up @@ -627,8 +627,8 @@ static int ds1305_probe(struct spi_device *spi) /* read and cache control registers */ addr = DS1305_CONTROL; - status = spi_write_then_read(spi, &addr, sizeof addr, - ds1305->ctrl, sizeof ds1305->ctrl); + status = spi_write_then_read(spi, &addr, sizeof(addr), + ds1305->ctrl, sizeof(ds1305->ctrl)); if (status < 0) { dev_dbg(&spi->dev, "can't %s, %d\n", "read", status); @@ -659,7 +659,7 @@ static int ds1305_probe(struct spi_device *spi) buf[0] = DS1305_WRITE | DS1305_CONTROL; buf[1] = ds1305->ctrl[0]; - status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0); + status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0); dev_dbg(&spi->dev, "clear WP --> %d\n", status); if (status < 0) @@ -713,7 +713,7 @@ static int ds1305_probe(struct spi_device *spi) buf[1] = ds1305->ctrl[0]; buf[2] = ds1305->ctrl[1]; buf[3] = ds1305->ctrl[2]; - status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0); + status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0); if (status < 0) { dev_dbg(&spi->dev, "can't %s, %d\n", "write", status); @@ -725,8 +725,8 @@ static int ds1305_probe(struct spi_device *spi) /* see if non-Linux software set up AM/PM mode */ addr = DS1305_HOUR; - status = spi_write_then_read(spi, &addr, sizeof addr, - &value, sizeof value); + status = spi_write_then_read(spi, &addr, sizeof(addr), + &value, sizeof(value)); if (status < 0) { dev_dbg(&spi->dev, "read HOUR --> %d\n", status); return status; @@ -756,19 +756,17 @@ static int ds1305_probe(struct spi_device *spi) status = devm_request_irq(&spi->dev, spi->irq, ds1305_irq, 0, dev_name(&ds1305->rtc->dev), ds1305); if (status < 0) { - dev_dbg(&spi->dev, "request_irq %d --> %d\n", + dev_err(&spi->dev, "request_irq %d --> %d\n", spi->irq, status); - return status; + } else { + device_set_wakeup_capable(&spi->dev, 1); } - - device_set_wakeup_capable(&spi->dev, 1); } /* export NVRAM */ status = sysfs_create_bin_file(&spi->dev.kobj, &nvram); if (status < 0) { - dev_dbg(&spi->dev, "register nvram --> %d\n", status); - return status; + dev_err(&spi->dev, "register nvram --> %d\n", status); } return 0; @@ -787,7 +785,6 @@ static int ds1305_remove(struct spi_device *spi) cancel_work_sync(&ds1305->work); } - spi_set_drvdata(spi, NULL); return 0; } diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index b53992ab309..f03d5ba96db 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -154,6 +154,7 @@ static const struct chip_desc chips[last_ds_type] = { .alarm = 1, }, [mcp7941x] = { + .alarm = 1, /* this is battery backed SRAM */ .nvram_offset = 0x20, .nvram_size = 0x40, @@ -606,6 +607,178 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { /*----------------------------------------------------------------------*/ +/* + * Alarm support for mcp7941x devices. + */ + +#define MCP7941X_REG_CONTROL 0x07 +# define MCP7941X_BIT_ALM0_EN 0x10 +# define MCP7941X_BIT_ALM1_EN 0x20 +#define MCP7941X_REG_ALARM0_BASE 0x0a +#define MCP7941X_REG_ALARM0_CTRL 0x0d +#define MCP7941X_REG_ALARM1_BASE 0x11 +#define MCP7941X_REG_ALARM1_CTRL 0x14 +# define MCP7941X_BIT_ALMX_IF (1 << 3) +# define MCP7941X_BIT_ALMX_C0 (1 << 4) +# define MCP7941X_BIT_ALMX_C1 (1 << 5) +# define MCP7941X_BIT_ALMX_C2 (1 << 6) +# define MCP7941X_BIT_ALMX_POL (1 << 7) +# define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \ + MCP7941X_BIT_ALMX_C1 | \ + MCP7941X_BIT_ALMX_C2) + +static void mcp7941x_work(struct work_struct *work) +{ + struct ds1307 *ds1307 = container_of(work, struct ds1307, work); + struct i2c_client *client = ds1307->client; + int reg, ret; + + mutex_lock(&ds1307->rtc->ops_lock); + + /* Check and clear alarm 0 interrupt flag. */ + reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL); + if (reg < 0) + goto out; + if (!(reg & MCP7941X_BIT_ALMX_IF)) + goto out; + reg &= ~MCP7941X_BIT_ALMX_IF; + ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg); + if (ret < 0) + goto out; + + /* Disable alarm 0. */ + reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); + if (reg < 0) + goto out; + reg &= ~MCP7941X_BIT_ALM0_EN; + ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); + if (ret < 0) + goto out; + + rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); + +out: + if (test_bit(HAS_ALARM, &ds1307->flags)) + enable_irq(client->irq); + mutex_unlock(&ds1307->rtc->ops_lock); +} + +static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1307 *ds1307 = i2c_get_clientdata(client); + u8 *regs = ds1307->regs; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + /* Read control and alarm 0 registers. */ + ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); + if (ret < 0) + return ret; + + t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN); + + /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ + t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f); + t->time.tm_min = bcd2bin(ds1307->regs[4] & 0x7f); + t->time.tm_hour = bcd2bin(ds1307->regs[5] & 0x3f); + t->time.tm_wday = bcd2bin(ds1307->regs[6] & 0x7) - 1; + t->time.tm_mday = bcd2bin(ds1307->regs[7] & 0x3f); + t->time.tm_mon = bcd2bin(ds1307->regs[8] & 0x1f) - 1; + t->time.tm_year = -1; + t->time.tm_yday = -1; + t->time.tm_isdst = -1; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " + "enabled=%d polarity=%d irq=%d match=%d\n", __func__, + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled, + !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL), + !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF), + (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4); + + return 0; +} + +static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1307 *ds1307 = i2c_get_clientdata(client); + unsigned char *regs = ds1307->regs; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " + "enabled=%d pending=%d\n", __func__, + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, + t->enabled, t->pending); + + /* Read control and alarm 0 registers. */ + ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); + if (ret < 0) + return ret; + + /* Set alarm 0, using 24-hour and day-of-month modes. */ + regs[3] = bin2bcd(t->time.tm_sec); + regs[4] = bin2bcd(t->time.tm_min); + regs[5] = bin2bcd(t->time.tm_hour); + regs[6] = bin2bcd(t->time.tm_wday) + 1; + regs[7] = bin2bcd(t->time.tm_mday); + regs[8] = bin2bcd(t->time.tm_mon) + 1; + + /* Clear the alarm 0 interrupt flag. */ + regs[6] &= ~MCP7941X_BIT_ALMX_IF; + /* Set alarm match: second, minute, hour, day, date, month. */ + regs[6] |= MCP7941X_MSK_ALMX_MATCH; + + if (t->enabled) + regs[0] |= MCP7941X_BIT_ALM0_EN; + else + regs[0] &= ~MCP7941X_BIT_ALM0_EN; + + ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs); + if (ret < 0) + return ret; + + return 0; +} + +static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1307 *ds1307 = i2c_get_clientdata(client); + int reg; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); + if (reg < 0) + return reg; + + if (enabled) + reg |= MCP7941X_BIT_ALM0_EN; + else + reg &= ~MCP7941X_BIT_ALM0_EN; + + return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); +} + +static const struct rtc_class_ops mcp7941x_rtc_ops = { + .read_time = ds1307_get_time, + .set_time = ds1307_set_time, + .read_alarm = mcp7941x_read_alarm, + .set_alarm = mcp7941x_set_alarm, + .alarm_irq_enable = mcp7941x_alarm_irq_enable, +}; + +/*----------------------------------------------------------------------*/ + static ssize_t ds1307_nvram_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, @@ -670,20 +843,21 @@ static int ds1307_probe(struct i2c_client *client, int tmp; const struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - int want_irq = false; + bool want_irq = false; unsigned char *buf; - struct ds1307_platform_data *pdata = client->dev.platform_data; + struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); static const int bbsqi_bitpos[] = { [ds_1337] = 0, [ds_1339] = DS1339_BIT_BBSQI, [ds_3231] = DS3231_BIT_BBSQW, }; + const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; - ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL); + ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL); if (!ds1307) return -ENOMEM; @@ -715,7 +889,7 @@ static int ds1307_probe(struct i2c_client *client, if (tmp != 2) { dev_dbg(&client->dev, "read error %d\n", tmp); err = -EIO; - goto exit_free; + goto exit; } /* oscillator off? turn it on, so clock can tick. */ @@ -754,7 +928,7 @@ static int ds1307_probe(struct i2c_client *client, if (tmp != 2) { dev_dbg(&client->dev, "read error %d\n", tmp); err = -EIO; - goto exit_free; + goto exit; } /* oscillator off? turn it on, so clock can tick. */ @@ -798,7 +972,7 @@ static int ds1307_probe(struct i2c_client *client, if (tmp != 2) { dev_dbg(&client->dev, "read error %d\n", tmp); err = -EIO; - goto exit_free; + goto exit; } /* correct hour */ @@ -816,6 +990,13 @@ static int ds1307_probe(struct i2c_client *client, case ds_1388: ds1307->offset = 1; /* Seconds starts at 1 */ break; + case mcp7941x: + rtc_ops = &mcp7941x_rtc_ops; + if (ds1307->client->irq > 0 && chip->alarm) { + INIT_WORK(&ds1307->work, mcp7941x_work); + want_irq = true; + } + break; default: break; } @@ -826,7 +1007,7 @@ read_rtc: if (tmp != 8) { dev_dbg(&client->dev, "read error %d\n", tmp); err = -EIO; - goto exit_free; + goto exit; } /* @@ -868,7 +1049,7 @@ read_rtc: if (tmp < 0) { dev_dbg(&client->dev, "read error %d\n", tmp); err = -EIO; - goto exit_free; + goto exit; } /* oscillator fault? clear flag, and warn */ @@ -927,59 +1108,62 @@ read_rtc: bin2bcd(tmp)); } - ds1307->rtc = rtc_device_register(client->name, &client->dev, - &ds13xx_rtc_ops, THIS_MODULE); + device_set_wakeup_capable(&client->dev, want_irq); + ds1307->rtc = devm_rtc_device_register(&client->dev, client->name, + rtc_ops, THIS_MODULE); if (IS_ERR(ds1307->rtc)) { - err = PTR_ERR(ds1307->rtc); - dev_err(&client->dev, - "unable to register the class device\n"); - goto exit_free; + return PTR_ERR(ds1307->rtc); } if (want_irq) { err = request_irq(client->irq, ds1307_irq, IRQF_SHARED, ds1307->rtc->name, client); if (err) { - dev_err(&client->dev, - "unable to request IRQ!\n"); - goto exit_irq; - } + client->irq = 0; + dev_err(&client->dev, "unable to request IRQ!\n"); + } else { - device_set_wakeup_capable(&client->dev, 1); - set_bit(HAS_ALARM, &ds1307->flags); - dev_dbg(&client->dev, "got IRQ %d\n", client->irq); + set_bit(HAS_ALARM, &ds1307->flags); + dev_dbg(&client->dev, "got IRQ %d\n", client->irq); + } } if (chip->nvram_size) { - ds1307->nvram = kzalloc(sizeof(struct bin_attribute), - GFP_KERNEL); + + ds1307->nvram = devm_kzalloc(&client->dev, + sizeof(struct bin_attribute), + GFP_KERNEL); if (!ds1307->nvram) { - err = -ENOMEM; - goto exit_nvram; - } - ds1307->nvram->attr.name = "nvram"; - ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; - sysfs_bin_attr_init(ds1307->nvram); - ds1307->nvram->read = ds1307_nvram_read; - ds1307->nvram->write = ds1307_nvram_write; - ds1307->nvram->size = chip->nvram_size; - ds1307->nvram_offset = chip->nvram_offset; - err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram); - if (err) { - kfree(ds1307->nvram); - goto exit_nvram; + dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n"); + } else { + + ds1307->nvram->attr.name = "nvram"; + ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; + + sysfs_bin_attr_init(ds1307->nvram); + + ds1307->nvram->read = ds1307_nvram_read; + ds1307->nvram->write = ds1307_nvram_write; + ds1307->nvram->size = chip->nvram_size; + ds1307->nvram_offset = chip->nvram_offset; + + err = sysfs_create_bin_file(&client->dev.kobj, + ds1307->nvram); + if (err) { + dev_err(&client->dev, + "unable to create sysfs file: %s\n", + ds1307->nvram->attr.name); + } else { + set_bit(HAS_NVRAM, &ds1307->flags); + dev_info(&client->dev, "%zu bytes nvram\n", + ds1307->nvram->size); + } } - set_bit(HAS_NVRAM, &ds1307->flags); - dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size); } return 0; -exit_nvram: -exit_irq: - rtc_device_unregister(ds1307->rtc); -exit_free: - kfree(ds1307); +exit: return err; } @@ -992,13 +1176,9 @@ static int ds1307_remove(struct i2c_client *client) cancel_work_sync(&ds1307->work); } - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) { + if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); - kfree(ds1307->nvram); - } - rtc_device_unregister(ds1307->rtc); - kfree(ds1307); return 0; } diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c new file mode 100644 index 00000000000..c3719189dd9 --- /dev/null +++ b/drivers/rtc/rtc-ds1343.c @@ -0,0 +1,689 @@ +/* rtc-ds1343.c + * + * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible + * Real Time Clock + * + * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.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/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/pm.h> +#include <linux/slab.h> + +#define DS1343_DRV_VERSION "01.00" +#define DALLAS_MAXIM_DS1343 0 +#define DALLAS_MAXIM_DS1344 1 + +/* RTC DS1343 Registers */ +#define DS1343_SECONDS_REG 0x00 +#define DS1343_MINUTES_REG 0x01 +#define DS1343_HOURS_REG 0x02 +#define DS1343_DAY_REG 0x03 +#define DS1343_DATE_REG 0x04 +#define DS1343_MONTH_REG 0x05 +#define DS1343_YEAR_REG 0x06 +#define DS1343_ALM0_SEC_REG 0x07 +#define DS1343_ALM0_MIN_REG 0x08 +#define DS1343_ALM0_HOUR_REG 0x09 +#define DS1343_ALM0_DAY_REG 0x0A +#define DS1343_ALM1_SEC_REG 0x0B +#define DS1343_ALM1_MIN_REG 0x0C +#define DS1343_ALM1_HOUR_REG 0x0D +#define DS1343_ALM1_DAY_REG 0x0E +#define DS1343_CONTROL_REG 0x0F +#define DS1343_STATUS_REG 0x10 +#define DS1343_TRICKLE_REG 0x11 + +/* DS1343 Control Registers bits */ +#define DS1343_EOSC 0x80 +#define DS1343_DOSF 0x20 +#define DS1343_EGFIL 0x10 +#define DS1343_SQW 0x08 +#define DS1343_INTCN 0x04 +#define DS1343_A1IE 0x02 +#define DS1343_A0IE 0x01 + +/* DS1343 Status Registers bits */ +#define DS1343_OSF 0x80 +#define DS1343_IRQF1 0x02 +#define DS1343_IRQF0 0x01 + +/* DS1343 Trickle Charger Registers bits */ +#define DS1343_TRICKLE_MAGIC 0xa0 +#define DS1343_TRICKLE_DS1 0x08 +#define DS1343_TRICKLE_1K 0x01 +#define DS1343_TRICKLE_2K 0x02 +#define DS1343_TRICKLE_4K 0x03 + +static const struct spi_device_id ds1343_id[] = { + { "ds1343", DALLAS_MAXIM_DS1343 }, + { "ds1344", DALLAS_MAXIM_DS1344 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ds1343_id); + +struct ds1343_priv { + struct spi_device *spi; + struct rtc_device *rtc; + struct regmap *map; + struct mutex mutex; + unsigned int irqen; + int irq; + int alarm_sec; + int alarm_min; + int alarm_hour; + int alarm_mday; +}; + +static int ds1343_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { +#ifdef RTC_SET_CHARGE + case RTC_SET_CHARGE: + { + int val; + + if (copy_from_user(&val, (int __user *)arg, sizeof(int))) + return -EFAULT; + + return regmap_write(priv->map, DS1343_TRICKLE_REG, val); + } + break; +#endif + } + + return -ENOIOCTLCMD; +} + +static ssize_t ds1343_show_glitchfilter(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int glitch_filt_status, data; + + regmap_read(priv->map, DS1343_CONTROL_REG, &data); + + glitch_filt_status = !!(data & DS1343_EGFIL); + + if (glitch_filt_status) + return sprintf(buf, "enabled\n"); + else + return sprintf(buf, "disabled\n"); +} + +static ssize_t ds1343_store_glitchfilter(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int data; + + regmap_read(priv->map, DS1343_CONTROL_REG, &data); + + if (strncmp(buf, "enabled", 7) == 0) + data |= DS1343_EGFIL; + + else if (strncmp(buf, "disabled", 8) == 0) + data &= ~(DS1343_EGFIL); + + else + return -EINVAL; + + regmap_write(priv->map, DS1343_CONTROL_REG, data); + + return count; +} + +static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter, + ds1343_store_glitchfilter); + +static ssize_t ds1343_show_alarmstatus(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int alarmstatus, data; + + regmap_read(priv->map, DS1343_CONTROL_REG, &data); + + alarmstatus = !!(data & DS1343_A0IE); + + if (alarmstatus) + return sprintf(buf, "enabled\n"); + else + return sprintf(buf, "disabled\n"); +} + +static DEVICE_ATTR(alarm_status, S_IRUGO, ds1343_show_alarmstatus, NULL); + +static ssize_t ds1343_show_alarmmode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int alarm_mode, data; + char *alarm_str; + + regmap_read(priv->map, DS1343_ALM0_SEC_REG, &data); + alarm_mode = (data & 0x80) >> 4; + + regmap_read(priv->map, DS1343_ALM0_MIN_REG, &data); + alarm_mode |= (data & 0x80) >> 5; + + regmap_read(priv->map, DS1343_ALM0_HOUR_REG, &data); + alarm_mode |= (data & 0x80) >> 6; + + regmap_read(priv->map, DS1343_ALM0_DAY_REG, &data); + alarm_mode |= (data & 0x80) >> 7; + + switch (alarm_mode) { + case 15: + alarm_str = "each second"; + break; + + case 7: + alarm_str = "seconds match"; + break; + + case 3: + alarm_str = "minutes and seconds match"; + break; + + case 1: + alarm_str = "hours, minutes and seconds match"; + break; + + case 0: + alarm_str = "day, hours, minutes and seconds match"; + break; + + default: + alarm_str = "invalid"; + break; + } + + return sprintf(buf, "%s\n", alarm_str); +} + +static DEVICE_ATTR(alarm_mode, S_IRUGO, ds1343_show_alarmmode, NULL); + +static ssize_t ds1343_show_tricklecharger(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int data; + char *diodes = "disabled", *resistors = " "; + + regmap_read(priv->map, DS1343_TRICKLE_REG, &data); + + if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) { + switch (data & 0x0c) { + case DS1343_TRICKLE_DS1: + diodes = "one diode,"; + break; + + default: + diodes = "no diode,"; + break; + } + + switch (data & 0x03) { + case DS1343_TRICKLE_1K: + resistors = "1k Ohm"; + break; + + case DS1343_TRICKLE_2K: + resistors = "2k Ohm"; + break; + + case DS1343_TRICKLE_4K: + resistors = "4k Ohm"; + break; + + default: + diodes = "disabled"; + break; + } + } + + return sprintf(buf, "%s %s\n", diodes, resistors); +} + +static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL); + +static int ds1343_sysfs_register(struct device *dev) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int err; + + err = device_create_file(dev, &dev_attr_glitch_filter); + if (err) + return err; + + err = device_create_file(dev, &dev_attr_trickle_charger); + if (err) + goto error1; + + if (priv->irq <= 0) + return err; + + err = device_create_file(dev, &dev_attr_alarm_mode); + if (err) + goto error2; + + err = device_create_file(dev, &dev_attr_alarm_status); + if (!err) + return err; + + device_remove_file(dev, &dev_attr_alarm_mode); + +error2: + device_remove_file(dev, &dev_attr_trickle_charger); + +error1: + device_remove_file(dev, &dev_attr_glitch_filter); + + return err; +} + +static void ds1343_sysfs_unregister(struct device *dev) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + + device_remove_file(dev, &dev_attr_glitch_filter); + device_remove_file(dev, &dev_attr_trickle_charger); + + if (priv->irq <= 0) + return; + + device_remove_file(dev, &dev_attr_alarm_status); + device_remove_file(dev, &dev_attr_alarm_mode); +} + +static int ds1343_read_time(struct device *dev, struct rtc_time *dt) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + unsigned char buf[7]; + int res; + + res = regmap_bulk_read(priv->map, DS1343_SECONDS_REG, buf, 7); + if (res) + return res; + + dt->tm_sec = bcd2bin(buf[0]); + dt->tm_min = bcd2bin(buf[1]); + dt->tm_hour = bcd2bin(buf[2] & 0x3F); + dt->tm_wday = bcd2bin(buf[3]) - 1; + dt->tm_mday = bcd2bin(buf[4]); + dt->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; + dt->tm_year = bcd2bin(buf[6]) + 100; /* year offset from 1900 */ + + return rtc_valid_tm(dt); +} + +static int ds1343_set_time(struct device *dev, struct rtc_time *dt) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int res; + + res = regmap_write(priv->map, DS1343_SECONDS_REG, + bin2bcd(dt->tm_sec)); + if (res) + return res; + + res = regmap_write(priv->map, DS1343_MINUTES_REG, + bin2bcd(dt->tm_min)); + if (res) + return res; + + res = regmap_write(priv->map, DS1343_HOURS_REG, + bin2bcd(dt->tm_hour) & 0x3F); + if (res) + return res; + + res = regmap_write(priv->map, DS1343_DAY_REG, + bin2bcd(dt->tm_wday + 1)); + if (res) + return res; + + res = regmap_write(priv->map, DS1343_DATE_REG, + bin2bcd(dt->tm_mday)); + if (res) + return res; + + res = regmap_write(priv->map, DS1343_MONTH_REG, + bin2bcd(dt->tm_mon + 1)); + if (res) + return res; + + dt->tm_year %= 100; + + res = regmap_write(priv->map, DS1343_YEAR_REG, + bin2bcd(dt->tm_year)); + if (res) + return res; + + return 0; +} + +static int ds1343_update_alarm(struct device *dev) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + unsigned int control, stat; + unsigned char buf[4]; + int res = 0; + + res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); + if (res) + return res; + + res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); + if (res) + return res; + + control &= ~(DS1343_A0IE); + stat &= ~(DS1343_IRQF0); + + res = regmap_write(priv->map, DS1343_CONTROL_REG, control); + if (res) + return res; + + res = regmap_write(priv->map, DS1343_STATUS_REG, stat); + if (res) + return res; + + buf[0] = priv->alarm_sec < 0 || (priv->irqen & RTC_UF) ? + 0x80 : bin2bcd(priv->alarm_sec) & 0x7F; + buf[1] = priv->alarm_min < 0 || (priv->irqen & RTC_UF) ? + 0x80 : bin2bcd(priv->alarm_min) & 0x7F; + buf[2] = priv->alarm_hour < 0 || (priv->irqen & RTC_UF) ? + 0x80 : bin2bcd(priv->alarm_hour) & 0x3F; + buf[3] = priv->alarm_mday < 0 || (priv->irqen & RTC_UF) ? + 0x80 : bin2bcd(priv->alarm_mday) & 0x7F; + + res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4); + if (res) + return res; + + if (priv->irqen) { + control |= DS1343_A0IE; + res = regmap_write(priv->map, DS1343_CONTROL_REG, control); + } + + return res; +} + +static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int res = 0; + unsigned int stat; + + if (priv->irq <= 0) + return -EINVAL; + + mutex_lock(&priv->mutex); + + res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); + if (res) + goto out; + + alarm->enabled = !!(priv->irqen & RTC_AF); + alarm->pending = !!(stat & DS1343_IRQF0); + + alarm->time.tm_sec = priv->alarm_sec < 0 ? 0 : priv->alarm_sec; + alarm->time.tm_min = priv->alarm_min < 0 ? 0 : priv->alarm_min; + alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour; + alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday; + + alarm->time.tm_mon = -1; + alarm->time.tm_year = -1; + alarm->time.tm_wday = -1; + alarm->time.tm_yday = -1; + alarm->time.tm_isdst = -1; + +out: + mutex_unlock(&priv->mutex); + return res; +} + +static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int res = 0; + + if (priv->irq <= 0) + return -EINVAL; + + mutex_lock(&priv->mutex); + + priv->alarm_sec = alarm->time.tm_sec; + priv->alarm_min = alarm->time.tm_min; + priv->alarm_hour = alarm->time.tm_hour; + priv->alarm_mday = alarm->time.tm_mday; + + if (alarm->enabled) + priv->irqen |= RTC_AF; + + res = ds1343_update_alarm(dev); + + mutex_unlock(&priv->mutex); + + return res; +} + +static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1343_priv *priv = dev_get_drvdata(dev); + int res = 0; + + if (priv->irq <= 0) + return -EINVAL; + + mutex_lock(&priv->mutex); + + if (enabled) + priv->irqen |= RTC_AF; + else + priv->irqen &= ~RTC_AF; + + res = ds1343_update_alarm(dev); + + mutex_unlock(&priv->mutex); + + return res; +} + +static irqreturn_t ds1343_thread(int irq, void *dev_id) +{ + struct ds1343_priv *priv = dev_id; + unsigned int stat, control; + int res = 0; + + mutex_lock(&priv->mutex); + + res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); + if (res) + goto out; + + if (stat & DS1343_IRQF0) { + stat &= ~DS1343_IRQF0; + regmap_write(priv->map, DS1343_STATUS_REG, stat); + + res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); + if (res) + goto out; + + control &= ~DS1343_A0IE; + regmap_write(priv->map, DS1343_CONTROL_REG, control); + + rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF); + } + +out: + mutex_unlock(&priv->mutex); + return IRQ_HANDLED; +} + +static const struct rtc_class_ops ds1343_rtc_ops = { + .ioctl = ds1343_ioctl, + .read_time = ds1343_read_time, + .set_time = ds1343_set_time, + .read_alarm = ds1343_read_alarm, + .set_alarm = ds1343_set_alarm, + .alarm_irq_enable = ds1343_alarm_irq_enable, +}; + +static int ds1343_probe(struct spi_device *spi) +{ + struct ds1343_priv *priv; + struct regmap_config config; + unsigned int data; + int res; + + memset(&config, 0, sizeof(config)); + config.reg_bits = 8; + config.val_bits = 8; + config.write_flag_mask = 0x80; + + priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->spi = spi; + mutex_init(&priv->mutex); + + /* RTC DS1347 works in spi mode 3 and + * its chip select is active high + */ + spi->mode = SPI_MODE_3 | SPI_CS_HIGH; + spi->bits_per_word = 8; + res = spi_setup(spi); + if (res) + return res; + + spi_set_drvdata(spi, priv); + + priv->map = devm_regmap_init_spi(spi, &config); + + if (IS_ERR(priv->map)) { + dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n"); + return PTR_ERR(priv->map); + } + + res = regmap_read(priv->map, DS1343_SECONDS_REG, &data); + if (res) + return res; + + regmap_read(priv->map, DS1343_CONTROL_REG, &data); + data |= DS1343_INTCN; + data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE); + regmap_write(priv->map, DS1343_CONTROL_REG, data); + + regmap_read(priv->map, DS1343_STATUS_REG, &data); + data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0); + regmap_write(priv->map, DS1343_STATUS_REG, data); + + priv->rtc = devm_rtc_device_register(&spi->dev, "ds1343", + &ds1343_rtc_ops, THIS_MODULE); + if (IS_ERR(priv->rtc)) { + dev_err(&spi->dev, "unable to register rtc ds1343\n"); + return PTR_ERR(priv->rtc); + } + + priv->irq = spi->irq; + + if (priv->irq >= 0) { + res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, + ds1343_thread, + IRQF_NO_SUSPEND | IRQF_ONESHOT, + "ds1343", priv); + if (res) { + priv->irq = -1; + dev_err(&spi->dev, + "unable to request irq for rtc ds1343\n"); + } else { + device_set_wakeup_capable(&spi->dev, 1); + } + } + + res = ds1343_sysfs_register(&spi->dev); + if (res) + dev_err(&spi->dev, + "unable to create sysfs entries for rtc ds1343\n"); + + return 0; +} + +static int ds1343_remove(struct spi_device *spi) +{ + struct ds1343_priv *priv = spi_get_drvdata(spi); + + if (spi->irq) { + mutex_lock(&priv->mutex); + priv->irqen &= ~RTC_AF; + mutex_unlock(&priv->mutex); + + devm_free_irq(&spi->dev, spi->irq, priv); + } + + spi_set_drvdata(spi, NULL); + + ds1343_sysfs_unregister(&spi->dev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int ds1343_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + + if (spi->irq >= 0 && device_may_wakeup(dev)) + enable_irq_wake(spi->irq); + + return 0; +} + +static int ds1343_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + + if (spi->irq >= 0 && device_may_wakeup(dev)) + disable_irq_wake(spi->irq); + + return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume); + +static struct spi_driver ds1343_driver = { + .driver = { + .name = "ds1343", + .owner = THIS_MODULE, + .pm = &ds1343_pm, + }, + .probe = ds1343_probe, + .remove = ds1343_remove, + .id_table = ds1343_id, +}; + +module_spi_driver(ds1343_driver); + +MODULE_DESCRIPTION("DS1343 RTC SPI Driver"); +MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DS1343_DRV_VERSION); diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c new file mode 100644 index 00000000000..c82b4c05032 --- /dev/null +++ b/drivers/rtc/rtc-ds1347.c @@ -0,0 +1,166 @@ +/* rtc-ds1347.c + * + * Driver for Dallas Semiconductor DS1347 Low Current, SPI Compatible + * Real Time Clock + * + * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.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/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/spi/spi.h> +#include <linux/bcd.h> + +/* Registers in ds1347 rtc */ + +#define DS1347_SECONDS_REG 0x01 +#define DS1347_MINUTES_REG 0x03 +#define DS1347_HOURS_REG 0x05 +#define DS1347_DATE_REG 0x07 +#define DS1347_MONTH_REG 0x09 +#define DS1347_DAY_REG 0x0B +#define DS1347_YEAR_REG 0x0D +#define DS1347_CONTROL_REG 0x0F +#define DS1347_STATUS_REG 0x17 +#define DS1347_CLOCK_BURST 0x3F + +static int ds1347_read_reg(struct device *dev, unsigned char address, + unsigned char *data) +{ + struct spi_device *spi = to_spi_device(dev); + + *data = address | 0x80; + + return spi_write_then_read(spi, data, 1, data, 1); +} + +static int ds1347_write_reg(struct device *dev, unsigned char address, + unsigned char data) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char buf[2]; + + buf[0] = address & 0x7F; + buf[1] = data; + + return spi_write_then_read(spi, buf, 2, NULL, 0); +} + +static int ds1347_read_time(struct device *dev, struct rtc_time *dt) +{ + struct spi_device *spi = to_spi_device(dev); + int err; + unsigned char buf[8]; + + buf[0] = DS1347_CLOCK_BURST | 0x80; + + err = spi_write_then_read(spi, buf, 1, buf, 8); + if (err) + return err; + + dt->tm_sec = bcd2bin(buf[0]); + dt->tm_min = bcd2bin(buf[1]); + dt->tm_hour = bcd2bin(buf[2] & 0x3F); + dt->tm_mday = bcd2bin(buf[3]); + dt->tm_mon = bcd2bin(buf[4]) - 1; + dt->tm_wday = bcd2bin(buf[5]) - 1; + dt->tm_year = bcd2bin(buf[6]) + 100; + + return rtc_valid_tm(dt); +} + +static int ds1347_set_time(struct device *dev, struct rtc_time *dt) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char buf[9]; + + buf[0] = DS1347_CLOCK_BURST & 0x7F; + buf[1] = bin2bcd(dt->tm_sec); + buf[2] = bin2bcd(dt->tm_min); + buf[3] = (bin2bcd(dt->tm_hour) & 0x3F); + buf[4] = bin2bcd(dt->tm_mday); + buf[5] = bin2bcd(dt->tm_mon + 1); + buf[6] = bin2bcd(dt->tm_wday + 1); + + /* year in linux is from 1900 i.e in range of 100 + in rtc it is from 00 to 99 */ + dt->tm_year = dt->tm_year % 100; + + buf[7] = bin2bcd(dt->tm_year); + buf[8] = bin2bcd(0x00); + + /* write the rtc settings */ + return spi_write_then_read(spi, buf, 9, NULL, 0); +} + +static const struct rtc_class_ops ds1347_rtc_ops = { + .read_time = ds1347_read_time, + .set_time = ds1347_set_time, +}; + +static int ds1347_probe(struct spi_device *spi) +{ + struct rtc_device *rtc; + unsigned char data; + int res; + + /* spi setup with ds1347 in mode 3 and bits per word as 8 */ + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + + /* RTC Settings */ + res = ds1347_read_reg(&spi->dev, DS1347_SECONDS_REG, &data); + if (res) + return res; + + /* Disable the write protect of rtc */ + ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data); + data = data & ~(1<<7); + ds1347_write_reg(&spi->dev, DS1347_CONTROL_REG, data); + + /* Enable the oscillator , disable the oscillator stop flag, + and glitch filter to reduce current consumption */ + ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data); + data = data & 0x1B; + ds1347_write_reg(&spi->dev, DS1347_STATUS_REG, data); + + /* display the settings */ + ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data); + dev_info(&spi->dev, "DS1347 RTC CTRL Reg = 0x%02x\n", data); + + ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data); + dev_info(&spi->dev, "DS1347 RTC Status Reg = 0x%02x\n", data); + + rtc = devm_rtc_device_register(&spi->dev, "ds1347", + &ds1347_rtc_ops, THIS_MODULE); + + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + spi_set_drvdata(spi, rtc); + + return 0; +} + +static struct spi_driver ds1347_driver = { + .driver = { + .name = "ds1347", + .owner = THIS_MODULE, + }, + .probe = ds1347_probe, +}; + +module_spi_driver(ds1347_driver); + +MODULE_DESCRIPTION("DS1347 SPI RTC DRIVER"); +MODULE_AUTHOR("Raghavendra C Ganiga <ravi23ganiga@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 94366e12f40..9e6e14fb53d 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -65,7 +65,7 @@ struct ds1374 { static struct i2c_driver ds1374_driver; static int ds1374_read_rtc(struct i2c_client *client, u32 *time, - int reg, int nbytes) + int reg, int nbytes) { u8 buf[4]; int ret; @@ -90,7 +90,7 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time, } static int ds1374_write_rtc(struct i2c_client *client, u32 time, - int reg, int nbytes) + int reg, int nbytes) { u8 buf[4]; int i; @@ -119,8 +119,7 @@ static int ds1374_check_rtc_status(struct i2c_client *client) if (stat & DS1374_REG_SR_OSF) dev_warn(&client->dev, - "oscillator discontinuity flagged, " - "time unreliable\n"); + "oscillator discontinuity flagged, time unreliable\n"); stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF); @@ -363,7 +362,7 @@ static int ds1374_probe(struct i2c_client *client, if (client->irq > 0) { ret = devm_request_irq(&client->dev, client->irq, ds1374_irq, 0, - "ds1374", client); + "ds1374", client); if (ret) { dev_err(&client->dev, "unable to request IRQ\n"); return ret; @@ -373,7 +372,7 @@ static int ds1374_probe(struct i2c_client *client, } ds1374->rtc = devm_rtc_device_register(&client->dev, client->name, - &ds1374_rtc_ops, THIS_MODULE); + &ds1374_rtc_ops, THIS_MODULE); if (IS_ERR(ds1374->rtc)) { dev_err(&client->dev, "unable to register the class device\n"); return PTR_ERR(ds1374->rtc); diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 289af419dff..e67bfcb3a1a 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -132,10 +132,9 @@ static int ds1390_probe(struct spi_device *spi) spi_setup(spi); chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) { - dev_err(&spi->dev, "unable to allocate device memory\n"); + if (!chip) return -ENOMEM; - } + spi_set_drvdata(spi, chip); res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp); @@ -154,18 +153,12 @@ static int ds1390_probe(struct spi_device *spi) return res; } -static int ds1390_remove(struct spi_device *spi) -{ - return 0; -} - static struct spi_driver ds1390_driver = { .driver = { .name = "rtc-ds1390", .owner = THIS_MODULE, }, .probe = ds1390_probe, - .remove = ds1390_remove, }; module_spi_driver(ds1390_driver); diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 6ce8a997cf5..b13d1399b81 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -89,7 +89,6 @@ enum ds1511reg { struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; /* virtual base address */ - int size; /* amount of memory mapped */ int irq; unsigned int irqen; int alrm_sec; @@ -104,31 +103,31 @@ static DEFINE_SPINLOCK(ds1511_lock); static __iomem char *ds1511_base; static u32 reg_spacing = 1; - static noinline void +static noinline void rtc_write(uint8_t val, uint32_t reg) { writeb(val, ds1511_base + (reg * reg_spacing)); } - static inline void +static inline void rtc_write_alarm(uint8_t val, enum ds1511reg reg) { rtc_write((val | 0x80), reg); } - static noinline uint8_t +static noinline uint8_t rtc_read(enum ds1511reg reg) { return readb(ds1511_base + (reg * reg_spacing)); } - static inline void +static inline void rtc_disable_update(void) { rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD); } - static void +static void rtc_enable_update(void) { rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD); @@ -145,7 +144,7 @@ rtc_enable_update(void) * just enough code to set the watchdog timer so that it * will reboot the system */ - void +void ds1511_wdog_set(unsigned long deciseconds) { /* @@ -163,7 +162,7 @@ ds1511_wdog_set(unsigned long deciseconds) rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD); } - void +void ds1511_wdog_disable(void) { /* @@ -191,13 +190,12 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) /* * won't have to change this for a while */ - if (rtc_tm->tm_year < 1900) { + if (rtc_tm->tm_year < 1900) rtc_tm->tm_year += 1900; - } - if (rtc_tm->tm_year < 1970) { + if (rtc_tm->tm_year < 1970) return -EINVAL; - } + yrs = rtc_tm->tm_year % 100; cen = rtc_tm->tm_year / 100; mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ @@ -207,17 +205,14 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) min = rtc_tm->tm_min; sec = rtc_tm->tm_sec; - if ((mon > 12) || (day == 0)) { + if ((mon > 12) || (day == 0)) return -EINVAL; - } - if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) { + if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) return -EINVAL; - } - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) { + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; - } /* * each register is a different number of valid bits @@ -299,7 +294,7 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) * date/hours/mins/secs matches. the ds1511 has many more * permutations, but the kernel doesn't. */ - static void +static void ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) { unsigned long flags; @@ -322,7 +317,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) spin_unlock_irqrestore(&pdata->lock, flags); } - static int +static int ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct platform_device *pdev = to_platform_device(dev); @@ -335,14 +330,14 @@ ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) pdata->alrm_hour = alrm->time.tm_hour; pdata->alrm_min = alrm->time.tm_min; pdata->alrm_sec = alrm->time.tm_sec; - if (alrm->enabled) { + if (alrm->enabled) pdata->irqen |= RTC_AF; - } + ds1511_rtc_update_alarm(pdata); return 0; } - static int +static int ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct platform_device *pdev = to_platform_device(dev); @@ -359,7 +354,7 @@ ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return 0; } - static irqreturn_t +static irqreturn_t ds1511_interrupt(int irq, void *dev_id) { struct platform_device *pdev = dev_id; @@ -376,8 +371,7 @@ ds1511_interrupt(int irq, void *dev_id) events |= RTC_UF; else events |= RTC_AF; - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); + rtc_update_irq(pdata->rtc, 1, events); } spin_unlock(&pdata->lock); return events ? IRQ_HANDLED : IRQ_NONE; @@ -406,7 +400,7 @@ static const struct rtc_class_ops ds1511_rtc_ops = { .alarm_irq_enable = ds1511_rtc_alarm_irq_enable, }; - static ssize_t +static ssize_t ds1511_nvram_read(struct file *filp, struct kobject *kobj, struct bin_attribute *ba, char *buf, loff_t pos, size_t size) @@ -417,26 +411,26 @@ ds1511_nvram_read(struct file *filp, struct kobject *kobj, * if count is more than one, turn on "burst" mode * turn it off when you're done */ - if (size > 1) { + if (size > 1) rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); - } - if (pos > DS1511_RAM_MAX) { + + if (pos > DS1511_RAM_MAX) pos = DS1511_RAM_MAX; - } - if (size + pos > DS1511_RAM_MAX + 1) { + + if (size + pos > DS1511_RAM_MAX + 1) size = DS1511_RAM_MAX - pos + 1; - } + rtc_write(pos, DS1511_RAMADDR_LSB); - for (count = 0; size > 0; count++, size--) { + for (count = 0; size > 0; count++, size--) *buf++ = rtc_read(DS1511_RAMDATA); - } - if (count > 1) { + + if (count > 1) rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); - } + return count; } - static ssize_t +static ssize_t ds1511_nvram_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t size) @@ -447,22 +441,22 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj, * if count is more than one, turn on "burst" mode * turn it off when you're done */ - if (size > 1) { + if (size > 1) rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); - } - if (pos > DS1511_RAM_MAX) { + + if (pos > DS1511_RAM_MAX) pos = DS1511_RAM_MAX; - } - if (size + pos > DS1511_RAM_MAX + 1) { + + if (size + pos > DS1511_RAM_MAX + 1) size = DS1511_RAM_MAX - pos + 1; - } + rtc_write(pos, DS1511_RAMADDR_LSB); - for (count = 0; size > 0; count++, size--) { + for (count = 0; size > 0; count++, size--) rtc_write(*buf++, DS1511_RAMDATA); - } - if (count > 1) { + + if (count > 1) rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); - } + return count; } @@ -478,25 +472,18 @@ static struct bin_attribute ds1511_nvram_attr = { static int ds1511_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc; struct resource *res; struct rtc_plat_data *pdata; int ret = 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - return -ENODEV; - } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->size = resource_size(res); - if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, - pdev->name)) - return -EBUSY; - ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size); - if (!ds1511_base) - return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ds1511_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ds1511_base)) + return PTR_ERR(ds1511_base); pdata->ioaddr = ds1511_base; pdata->irq = platform_get_irq(pdev, 0); @@ -518,12 +505,17 @@ static int ds1511_rtc_probe(struct platform_device *pdev) /* * check for a dying bat-tree */ - if (rtc_read(RTC_CMD1) & DS1511_BLF1) { + if (rtc_read(RTC_CMD1) & DS1511_BLF1) dev_warn(&pdev->dev, "voltage-low detected.\n"); - } spin_lock_init(&pdata->lock); platform_set_drvdata(pdev, pdata); + + pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &ds1511_rtc_ops, THIS_MODULE); + if (IS_ERR(pdata->rtc)) + return PTR_ERR(pdata->rtc); + /* * if the platform has an interrupt in mind for this device, * then by all means, set it @@ -538,15 +530,12 @@ static int ds1511_rtc_probe(struct platform_device *pdev) } } - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &ds1511_rtc_ops, - THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - pdata->rtc = rtc; - ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); + if (ret) + dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n", + ds1511_nvram_attr.attr.name); - return ret; + return 0; } static int ds1511_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 8c6c952e90b..ab56893aac7 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -206,8 +206,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id) events |= RTC_UF; else events |= RTC_AF; - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); + rtc_update_irq(pdata->rtc, 1, events); } spin_unlock(&pdata->lock); return events ? IRQ_HANDLED : IRQ_NONE; @@ -278,26 +277,20 @@ static struct bin_attribute ds1553_nvram_attr = { static int ds1553_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc; struct resource *res; unsigned int cen, sec; struct rtc_plat_data *pdata; void __iomem *ioaddr; int ret = 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, - pdev->name)) - return -EBUSY; - ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); - if (!ioaddr) - return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ioaddr)) + return PTR_ERR(ioaddr); pdata->ioaddr = ioaddr; pdata->irq = platform_get_irq(pdev, 0); @@ -316,6 +309,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev) spin_lock_init(&pdata->lock); pdata->last_jiffies = jiffies; platform_set_drvdata(pdev, pdata); + + pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &ds1553_rtc_ops, THIS_MODULE); + if (IS_ERR(pdata->rtc)) + return PTR_ERR(pdata->rtc); + if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); if (devm_request_irq(&pdev->dev, pdata->irq, @@ -326,15 +325,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev) } } - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &ds1553_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - pdata->rtc = rtc; - ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); + if (ret) + dev_err(&pdev->dev, "unable to create sysfs file: %s\n", + ds1553_nvram_attr.attr.name); - return ret; + return 0; } static int ds1553_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 3fc2a473802..a4888dbca2e 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -153,11 +153,6 @@ static const struct rtc_class_ops ds1672_rtc_ops = { .set_mmss = ds1672_rtc_set_mmss, }; -static int ds1672_remove(struct i2c_client *client) -{ - return 0; -} - static int ds1672_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -182,8 +177,9 @@ static int ds1672_probe(struct i2c_client *client, /* read control register */ err = ds1672_get_control(client, &control); - if (err) - goto exit_devreg; + if (err) { + dev_warn(&client->dev, "Unable to read the control register\n"); + } if (control & DS1672_REG_CONTROL_EOSC) dev_warn(&client->dev, "Oscillator not enabled. " @@ -192,12 +188,10 @@ static int ds1672_probe(struct i2c_client *client, /* Register sysfs hooks */ err = device_create_file(&client->dev, &dev_attr_control); if (err) - goto exit_devreg; + dev_err(&client->dev, "Unable to create sysfs entry: %s\n", + dev_attr_control.attr.name); return 0; - - exit_devreg: - return err; } static struct i2c_device_id ds1672_id[] = { @@ -210,7 +204,6 @@ static struct i2c_driver ds1672_driver = { .name = "rtc-ds1672", }, .probe = &ds1672_probe, - .remove = &ds1672_remove, .id_table = ds1672_id, }; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index eccdc62ae1c..c6b2191a412 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -13,12 +13,13 @@ */ #include <linux/bcd.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/gfp.h> #include <linux/delay.h> #include <linux/jiffies.h> #include <linux/rtc.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/io.h> #include <linux/module.h> @@ -52,11 +53,9 @@ #define RTC_BATT_FLAG 0x80 struct rtc_plat_data { - struct rtc_device *rtc; void __iomem *ioaddr_nvram; void __iomem *ioaddr_rtc; size_t size_nvram; - size_t size; unsigned long last_jiffies; struct bin_attribute nvram_attr; }; @@ -117,11 +116,7 @@ static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm) /* year is 1900 + tm->tm_year */ tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900; - if (rtc_valid_tm(tm) < 0) { - dev_err(dev, "retrieved date/time is not valid.\n"); - rtc_time_to_tm(0, tm); - } - return 0; + return rtc_valid_tm(tm); } static const struct rtc_class_ops ds1742_rtc_ops = { @@ -168,22 +163,17 @@ static int ds1742_rtc_probe(struct platform_device *pdev) void __iomem *ioaddr; int ret = 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->size = resource_size(res); - if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, - pdev->name)) - return -EBUSY; - ioaddr = devm_ioremap(&pdev->dev, res->start, pdata->size); - if (!ioaddr) - return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ioaddr)) + return PTR_ERR(ioaddr); pdata->ioaddr_nvram = ioaddr; - pdata->size_nvram = pdata->size - RTC_SIZE; + pdata->size_nvram = resource_size(res) - RTC_SIZE; pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; sysfs_bin_attr_init(&pdata->nvram_attr); @@ -212,11 +202,13 @@ static int ds1742_rtc_probe(struct platform_device *pdev) &ds1742_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); - pdata->rtc = rtc; ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); + if (ret) + dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n", + pdata->nvram_attr.attr.name); - return ret; + return 0; } static int ds1742_rtc_remove(struct platform_device *pdev) @@ -227,12 +219,19 @@ static int ds1742_rtc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id __maybe_unused ds1742_rtc_of_match[] = { + { .compatible = "maxim,ds1742", }, + { } +}; +MODULE_DEVICE_TABLE(of, ds1742_rtc_of_match); + static struct platform_driver ds1742_rtc_driver = { .probe = ds1742_rtc_probe, .remove = ds1742_rtc_remove, .driver = { .name = "rtc-ds1742", .owner = THIS_MODULE, + .of_match_table = ds1742_rtc_of_match, }, }; diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 2ca5a23aba8..fc209dc4e24 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -224,7 +224,7 @@ static const struct rtc_class_ops ds2404_rtc_ops = { static int rtc_probe(struct platform_device *pdev) { - struct ds2404_platform_data *pdata = pdev->dev.platform_data; + struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev); struct ds2404 *chip; int retval = -EBUSY; diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index b83bb5a527f..adaf06c4147 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -57,6 +57,7 @@ struct ds3232 { * in the remove function. */ struct mutex mutex; + bool suspended; int exiting; }; @@ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id) struct ds3232 *ds3232 = i2c_get_clientdata(client); disable_irq_nosync(irq); - schedule_work(&ds3232->work); + + /* + * If rtc as a wakeup source, can't schedule the work + * at system resume flow, because at this time the i2c bus + * has not been resumed. + */ + if (!ds3232->suspended) + schedule_work(&ds3232->work); + return IRQ_HANDLED; } @@ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work) if (stat & DS3232_REG_SR_A1F) { control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) - goto out; - /* disable alarm1 interrupt */ - control &= ~(DS3232_REG_CR_A1IE); - i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); - - /* clear the alarm pend flag */ - stat &= ~DS3232_REG_SR_A1F; - i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); - - rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); + if (control < 0) { + pr_warn("Read DS3232 Control Register error." + "Disable IRQ%d.\n", client->irq); + } else { + /* disable alarm1 interrupt */ + control &= ~(DS3232_REG_CR_A1IE); + i2c_smbus_write_byte_data(client, DS3232_REG_CR, + control); + + /* clear the alarm pend flag */ + stat &= ~DS3232_REG_SR_A1F; + i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + + rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); + + if (!ds3232->exiting) + enable_irq(client->irq); + } } -out: - if (!ds3232->exiting) - enable_irq(client->irq); unlock: mutex_unlock(&ds3232->mutex); } @@ -411,23 +424,17 @@ static int ds3232_probe(struct i2c_client *client, if (ret) return ret; - ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, - &ds3232_rtc_ops, THIS_MODULE); - if (IS_ERR(ds3232->rtc)) { - dev_err(&client->dev, "unable to register the class device\n"); - return PTR_ERR(ds3232->rtc); - } - - if (client->irq >= 0) { - ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, 0, - "ds3232", client); + if (client->irq > 0) { + ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, + IRQF_SHARED, "ds3232", client); if (ret) { dev_err(&client->dev, "unable to request IRQ\n"); - return ret; } + device_init_wakeup(&client->dev, 1); } - - return 0; + ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, + &ds3232_rtc_ops, THIS_MODULE); + return PTR_ERR_OR_ZERO(ds3232->rtc); } static int ds3232_remove(struct i2c_client *client) @@ -446,6 +453,42 @@ static int ds3232_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int ds3232_suspend(struct device *dev) +{ + struct ds3232 *ds3232 = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(dev); + + if (device_can_wakeup(dev)) { + ds3232->suspended = true; + irq_set_irq_wake(client->irq, 1); + } + + return 0; +} + +static int ds3232_resume(struct device *dev) +{ + struct ds3232 *ds3232 = dev_get_drvdata(dev); + struct i2c_client *client = to_i2c_client(dev); + + if (ds3232->suspended) { + ds3232->suspended = false; + + /* Clear the hardware alarm pend flag */ + schedule_work(&ds3232->work); + + irq_set_irq_wake(client->irq, 0); + } + + return 0; +} +#endif + +static const struct dev_pm_ops ds3232_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) +}; + static const struct i2c_device_id ds3232_id[] = { { "ds3232", 0 }, { } @@ -456,6 +499,7 @@ static struct i2c_driver ds3232_driver = { .driver = { .name = "rtc-ds3232", .owner = THIS_MODULE, + .pm = &ds3232_pm_ops, }, .probe = ds3232_probe, .remove = ds3232_remove, diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c index ba98c0e9580..4c9ba536846 100644 --- a/drivers/rtc/rtc-ds3234.c +++ b/drivers/rtc/rtc-ds3234.c @@ -73,7 +73,7 @@ static int ds3234_read_time(struct device *dev, struct rtc_time *dt) dt->tm_wday = bcd2bin(buf[3]) - 1; /* 0 = Sun */ dt->tm_mday = bcd2bin(buf[4]); dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */ - dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */ + dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */ return rtc_valid_tm(dt); } @@ -156,18 +156,12 @@ static int ds3234_probe(struct spi_device *spi) return 0; } -static int ds3234_remove(struct spi_device *spi) -{ - return 0; -} - static struct spi_driver ds3234_driver = { .driver = { .name = "ds3234", .owner = THIS_MODULE, }, .probe = ds3234_probe, - .remove = ds3234_remove, }; module_spi_driver(ds3234_driver); diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index b3c8c0b1709..c4c38431012 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -35,7 +35,7 @@ static inline int compute_yday(efi_time_t *eft) { /* efi_time_t.month is in the [1-12] so, we need -1 */ - return rtc_year_days(eft->day - 1, eft->month - 1, eft->year); + return rtc_year_days(eft->day, eft->month - 1, eft->year); } /* * returns day of the week [0-6] 0=Sunday @@ -201,17 +201,11 @@ static int __init efi_rtc_probe(struct platform_device *dev) return 0; } -static int __exit efi_rtc_remove(struct platform_device *dev) -{ - return 0; -} - static struct platform_driver efi_rtc_driver = { .driver = { .name = "rtc-efi", .owner = THIS_MODULE, }, - .remove = __exit_p(efi_rtc_remove), }; module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe); diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c index 3f9eb57d048..fccf3669924 100644 --- a/drivers/rtc/rtc-em3027.c +++ b/drivers/rtc/rtc-em3027.c @@ -131,11 +131,6 @@ static int em3027_probe(struct i2c_client *client, return 0; } -static int em3027_remove(struct i2c_client *client) -{ - return 0; -} - static struct i2c_device_id em3027_id[] = { { "em3027", 0 }, { } @@ -146,7 +141,6 @@ static struct i2c_driver em3027_driver = { .name = "rtc-em3027", }, .probe = &em3027_probe, - .remove = &em3027_remove, .id_table = em3027_id, }; diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 5807b77c444..5e4f5dc40ba 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -42,7 +42,7 @@ struct ep93xx_rtc { static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, unsigned short *delete) { - struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); unsigned long comp; comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP); @@ -60,7 +60,7 @@ static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); unsigned long time; time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); @@ -71,7 +71,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) { - struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); __raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD); return 0; @@ -138,17 +138,9 @@ static int ep93xx_rtc_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) - return -EBUSY; - - ep93xx_rtc->mmio_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!ep93xx_rtc->mmio_base) - return -ENXIO; + ep93xx_rtc->mmio_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ep93xx_rtc->mmio_base)) + return PTR_ERR(ep93xx_rtc->mmio_base); pdev->dev.platform_data = ep93xx_rtc; platform_set_drvdata(pdev, ep93xx_rtc); @@ -167,7 +159,6 @@ static int ep93xx_rtc_probe(struct platform_device *pdev) return 0; exit: - platform_set_drvdata(pdev, NULL); pdev->dev.platform_data = NULL; return err; } @@ -175,7 +166,6 @@ exit: static int ep93xx_rtc_remove(struct platform_device *pdev) { sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); - platform_set_drvdata(pdev, NULL); pdev->dev.platform_data = NULL; return 0; diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index 2835fb6c196..83c3b3029fa 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -47,7 +47,7 @@ struct fm3130 { u8 reg_addr_time; - u8 reg_addr_alarm; + u8 reg_addr_alarm; u8 regs[15]; struct i2c_msg msg[4]; struct i2c_client *client; @@ -520,18 +520,12 @@ exit_free: return err; } -static int fm3130_remove(struct i2c_client *client) -{ - return 0; -} - static struct i2c_driver fm3130_driver = { .driver = { .name = "rtc-fm3130", .owner = THIS_MODULE, }, .probe = fm3130_probe, - .remove = fm3130_remove, .id_table = fm3130_id, }; diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c index 06279ce6bff..9b6725ebbfb 100644 --- a/drivers/rtc/rtc-generic.c +++ b/drivers/rtc/rtc-generic.c @@ -48,17 +48,11 @@ static int __init generic_rtc_probe(struct platform_device *dev) return 0; } -static int __exit generic_rtc_remove(struct platform_device *dev) -{ - return 0; -} - static struct platform_driver generic_rtc_driver = { .driver = { .name = "rtc-generic", .owner = THIS_MODULE, }, - .remove = __exit_p(generic_rtc_remove), }; module_platform_driver_probe(generic_rtc_driver, generic_rtc_probe); diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 63024505ddd..965a9da7086 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -23,10 +23,6 @@ #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, @@ -76,6 +72,20 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, return 0; } +static u32 hid_time_value(size_t raw_len, char *raw_data) +{ + switch (raw_len) { + case 1: + return *(u8 *)raw_data; + case 2: + return *(u16 *)raw_data; + case 4: + return *(u32 *)raw_data; + default: + return (u32)(~0U); /* 0xff... or -1 to denote an error */ + } +} + static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, unsigned usage_id, size_t raw_len, char *raw_data, void *priv) @@ -85,26 +95,35 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, 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; + /* + * The draft for HID-sensors (HUTRR39) currently doesn't define + * the range for the year attribute. Therefor we support + * 8 bit (0-99) and 16 or 32 bits (full) as size for the year. + */ + if (raw_len == 1) { + time_buf->tm_year = *(u8 *)raw_data; + if (time_buf->tm_year < 70) + /* assume we are in 1970...2069 */ + time_buf->tm_year += 100; + } else + time_buf->tm_year = + (int)hid_time_value(raw_len, raw_data)-1900; 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; + /* sensors are sending the month as 1-12, we need 0-11 */ + time_buf->tm_mon = (int)hid_time_value(raw_len, raw_data)-1; break; case HID_USAGE_SENSOR_TIME_DAY: - time_buf->tm_mday = *(u8 *)raw_data; + time_buf->tm_mday = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_HOUR: - time_buf->tm_hour = *(u8 *)raw_data; + time_buf->tm_hour = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_MINUTE: - time_buf->tm_min = *(u8 *)raw_data; + time_buf->tm_min = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_SECOND: - time_buf->tm_sec = *(u8 *)raw_data; + time_buf->tm_sec = (int)hid_time_value(raw_len, raw_data); break; default: return -EINVAL; @@ -150,9 +169,10 @@ static int hid_time_parse_report(struct platform_device *pdev, "not all needed attributes inside the same report!\n"); return -EINVAL; } - if (time_state->info[i].size != 1) { + if (time_state->info[i].size == 3 || + time_state->info[i].size > 4) { dev_err(&pdev->dev, - "attribute '%s' not 8 bits wide!\n", + "attribute '%s' not 8, 16 or 32 bits wide!\n", hid_time_attrib_name( time_state->info[i].attrib_id)); return -EINVAL; @@ -189,7 +209,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) platform_get_drvdata(to_platform_device(dev)); int ret; - INIT_COMPLETION(time_state->comp_last_time); + reinit_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], @@ -216,7 +236,7 @@ static const struct rtc_class_ops hid_time_rtc_ops = { static int hid_time_probe(struct platform_device *pdev) { int ret = 0; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct hid_time_state *time_state = devm_kzalloc(&pdev->dev, sizeof(struct hid_time_state), GFP_KERNEL); @@ -255,30 +275,62 @@ static int hid_time_probe(struct platform_device *pdev) return ret; } + ret = sensor_hub_device_open(hsdev); + if (ret) { + dev_err(&pdev->dev, "failed to open sensor hub device!\n"); + goto err_open; + } + + /* + * Enable HID input processing early in order to be able to read the + * clock already in devm_rtc_device_register(). + */ + hid_device_io_start(hsdev->hdev); + time_state->rtc = devm_rtc_device_register(&pdev->dev, "hid-sensor-time", &hid_time_rtc_ops, THIS_MODULE); - if (IS_ERR(time_state->rtc)) { + if (IS_ERR_OR_NULL(time_state->rtc)) { + hid_device_io_stop(hsdev->hdev); + ret = time_state->rtc ? PTR_ERR(time_state->rtc) : -ENODEV; + time_state->rtc = NULL; dev_err(&pdev->dev, "rtc device register failed!\n"); - return PTR_ERR(time_state->rtc); + goto err_rtc; } return ret; + +err_rtc: + sensor_hub_device_close(hsdev); +err_open: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); + return ret; } static int hid_time_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); + sensor_hub_device_close(hsdev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); return 0; } +static struct platform_device_id hid_time_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-2000a0", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_time_ids); + static struct platform_driver hid_time_platform_driver = { + .id_table = hid_time_ids, .driver = { - .name = DRIVER_NAME, + .name = KBUILD_MODNAME, .owner = THIS_MODULE, }, .probe = hid_time_probe, diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c new file mode 100644 index 00000000000..b936bb4096b --- /dev/null +++ b/drivers/rtc/rtc-hym8563.c @@ -0,0 +1,612 @@ +/* + * Haoyu HYM8563 RTC driver + * + * Copyright (C) 2013 MundoReader S.L. + * Author: Heiko Stuebner <heiko@sntech.de> + * + * based on rtc-HYM8563 + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/clk-provider.h> +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/rtc.h> + +#define HYM8563_CTL1 0x00 +#define HYM8563_CTL1_TEST BIT(7) +#define HYM8563_CTL1_STOP BIT(5) +#define HYM8563_CTL1_TESTC BIT(3) + +#define HYM8563_CTL2 0x01 +#define HYM8563_CTL2_TI_TP BIT(4) +#define HYM8563_CTL2_AF BIT(3) +#define HYM8563_CTL2_TF BIT(2) +#define HYM8563_CTL2_AIE BIT(1) +#define HYM8563_CTL2_TIE BIT(0) + +#define HYM8563_SEC 0x02 +#define HYM8563_SEC_VL BIT(7) +#define HYM8563_SEC_MASK 0x7f + +#define HYM8563_MIN 0x03 +#define HYM8563_MIN_MASK 0x7f + +#define HYM8563_HOUR 0x04 +#define HYM8563_HOUR_MASK 0x3f + +#define HYM8563_DAY 0x05 +#define HYM8563_DAY_MASK 0x3f + +#define HYM8563_WEEKDAY 0x06 +#define HYM8563_WEEKDAY_MASK 0x07 + +#define HYM8563_MONTH 0x07 +#define HYM8563_MONTH_CENTURY BIT(7) +#define HYM8563_MONTH_MASK 0x1f + +#define HYM8563_YEAR 0x08 + +#define HYM8563_ALM_MIN 0x09 +#define HYM8563_ALM_HOUR 0x0a +#define HYM8563_ALM_DAY 0x0b +#define HYM8563_ALM_WEEK 0x0c + +/* Each alarm check can be disabled by setting this bit in the register */ +#define HYM8563_ALM_BIT_DISABLE BIT(7) + +#define HYM8563_CLKOUT 0x0d +#define HYM8563_CLKOUT_DISABLE BIT(7) +#define HYM8563_CLKOUT_32768 0 +#define HYM8563_CLKOUT_1024 1 +#define HYM8563_CLKOUT_32 2 +#define HYM8563_CLKOUT_1 3 +#define HYM8563_CLKOUT_MASK 3 + +#define HYM8563_TMR_CTL 0x0e +#define HYM8563_TMR_CTL_ENABLE BIT(7) +#define HYM8563_TMR_CTL_4096 0 +#define HYM8563_TMR_CTL_64 1 +#define HYM8563_TMR_CTL_1 2 +#define HYM8563_TMR_CTL_1_60 3 +#define HYM8563_TMR_CTL_MASK 3 + +#define HYM8563_TMR_CNT 0x0f + +struct hym8563 { + struct i2c_client *client; + struct rtc_device *rtc; + bool valid; +#ifdef CONFIG_COMMON_CLK + struct clk_hw clkout_hw; +#endif +}; + +/* + * RTC handling + */ + +static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct hym8563 *hym8563 = i2c_get_clientdata(client); + u8 buf[7]; + int ret; + + if (!hym8563->valid) { + dev_warn(&client->dev, "no valid clock/calendar values available\n"); + return -EPERM; + } + + ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf); + + tm->tm_sec = bcd2bin(buf[0] & HYM8563_SEC_MASK); + tm->tm_min = bcd2bin(buf[1] & HYM8563_MIN_MASK); + tm->tm_hour = bcd2bin(buf[2] & HYM8563_HOUR_MASK); + tm->tm_mday = bcd2bin(buf[3] & HYM8563_DAY_MASK); + tm->tm_wday = bcd2bin(buf[4] & HYM8563_WEEKDAY_MASK); /* 0 = Sun */ + tm->tm_mon = bcd2bin(buf[5] & HYM8563_MONTH_MASK) - 1; /* 0 = Jan */ + tm->tm_year = bcd2bin(buf[6]) + 100; + + return 0; +} + +static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct hym8563 *hym8563 = i2c_get_clientdata(client); + u8 buf[7]; + int ret; + + /* Years >= 2100 are to far in the future, 19XX is to early */ + if (tm->tm_year < 100 || tm->tm_year >= 200) + return -EINVAL; + + buf[0] = bin2bcd(tm->tm_sec); + buf[1] = bin2bcd(tm->tm_min); + buf[2] = bin2bcd(tm->tm_hour); + buf[3] = bin2bcd(tm->tm_mday); + buf[4] = bin2bcd(tm->tm_wday); + buf[5] = bin2bcd(tm->tm_mon + 1); + + /* + * While the HYM8563 has a century flag in the month register, + * it does not seem to carry it over a subsequent write/read. + * So we'll limit ourself to 100 years, starting at 2000 for now. + */ + buf[6] = tm->tm_year - 100; + + /* + * CTL1 only contains TEST-mode bits apart from stop, + * so no need to read the value first + */ + ret = i2c_smbus_write_byte_data(client, HYM8563_CTL1, + HYM8563_CTL1_STOP); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_i2c_block_data(client, HYM8563_SEC, 7, buf); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, HYM8563_CTL1, 0); + if (ret < 0) + return ret; + + hym8563->valid = true; + + return 0; +} + +static int hym8563_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + int data; + + data = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + if (data < 0) + return data; + + if (enabled) + data |= HYM8563_CTL2_AIE; + else + data &= ~HYM8563_CTL2_AIE; + + return i2c_smbus_write_byte_data(client, HYM8563_CTL2, data); +}; + +static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rtc_time *alm_tm = &alm->time; + u8 buf[4]; + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, HYM8563_ALM_MIN, 4, buf); + if (ret < 0) + return ret; + + /* The alarm only has a minute accuracy */ + alm_tm->tm_sec = -1; + + alm_tm->tm_min = (buf[0] & HYM8563_ALM_BIT_DISABLE) ? + -1 : + bcd2bin(buf[0] & HYM8563_MIN_MASK); + alm_tm->tm_hour = (buf[1] & HYM8563_ALM_BIT_DISABLE) ? + -1 : + bcd2bin(buf[1] & HYM8563_HOUR_MASK); + alm_tm->tm_mday = (buf[2] & HYM8563_ALM_BIT_DISABLE) ? + -1 : + bcd2bin(buf[2] & HYM8563_DAY_MASK); + alm_tm->tm_wday = (buf[3] & HYM8563_ALM_BIT_DISABLE) ? + -1 : + bcd2bin(buf[3] & HYM8563_WEEKDAY_MASK); + + alm_tm->tm_mon = -1; + alm_tm->tm_year = -1; + + ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + if (ret < 0) + return ret; + + if (ret & HYM8563_CTL2_AIE) + alm->enabled = 1; + + return 0; +} + +static int hym8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rtc_time *alm_tm = &alm->time; + u8 buf[4]; + int ret; + + /* + * The alarm has no seconds so deal with it + */ + if (alm_tm->tm_sec) { + alm_tm->tm_sec = 0; + alm_tm->tm_min++; + if (alm_tm->tm_min >= 60) { + alm_tm->tm_min = 0; + alm_tm->tm_hour++; + if (alm_tm->tm_hour >= 24) { + alm_tm->tm_hour = 0; + alm_tm->tm_mday++; + if (alm_tm->tm_mday > 31) + alm_tm->tm_mday = 0; + } + } + } + + ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + if (ret < 0) + return ret; + + ret &= ~HYM8563_CTL2_AIE; + + ret = i2c_smbus_write_byte_data(client, HYM8563_CTL2, ret); + if (ret < 0) + return ret; + + buf[0] = (alm_tm->tm_min < 60 && alm_tm->tm_min >= 0) ? + bin2bcd(alm_tm->tm_min) : HYM8563_ALM_BIT_DISABLE; + + buf[1] = (alm_tm->tm_hour < 24 && alm_tm->tm_hour >= 0) ? + bin2bcd(alm_tm->tm_hour) : HYM8563_ALM_BIT_DISABLE; + + buf[2] = (alm_tm->tm_mday <= 31 && alm_tm->tm_mday >= 1) ? + bin2bcd(alm_tm->tm_mday) : HYM8563_ALM_BIT_DISABLE; + + buf[3] = (alm_tm->tm_wday < 7 && alm_tm->tm_wday >= 0) ? + bin2bcd(alm_tm->tm_wday) : HYM8563_ALM_BIT_DISABLE; + + ret = i2c_smbus_write_i2c_block_data(client, HYM8563_ALM_MIN, 4, buf); + if (ret < 0) + return ret; + + return hym8563_rtc_alarm_irq_enable(dev, alm->enabled); +} + +static const struct rtc_class_ops hym8563_rtc_ops = { + .read_time = hym8563_rtc_read_time, + .set_time = hym8563_rtc_set_time, + .alarm_irq_enable = hym8563_rtc_alarm_irq_enable, + .read_alarm = hym8563_rtc_read_alarm, + .set_alarm = hym8563_rtc_set_alarm, +}; + +/* + * Handling of the clkout + */ + +#ifdef CONFIG_COMMON_CLK +#define clkout_hw_to_hym8563(_hw) container_of(_hw, struct hym8563, clkout_hw) + +static int clkout_rates[] = { + 32768, + 1024, + 32, + 1, +}; + +static unsigned long hym8563_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); + struct i2c_client *client = hym8563->client; + int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); + + if (ret < 0 || ret & HYM8563_CLKOUT_DISABLE) + return 0; + + ret &= HYM8563_CLKOUT_MASK; + return clkout_rates[ret]; +} + +static long hym8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] <= rate) + return clkout_rates[i]; + + return 0; +} + +static int hym8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); + struct i2c_client *client = hym8563->client; + int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); + int i; + + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] == rate) { + ret &= ~HYM8563_CLKOUT_MASK; + ret |= i; + return i2c_smbus_write_byte_data(client, + HYM8563_CLKOUT, ret); + } + + return -EINVAL; +} + +static int hym8563_clkout_control(struct clk_hw *hw, bool enable) +{ + struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); + struct i2c_client *client = hym8563->client; + int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); + + if (ret < 0) + return ret; + + if (enable) + ret &= ~HYM8563_CLKOUT_DISABLE; + else + ret |= HYM8563_CLKOUT_DISABLE; + + return i2c_smbus_write_byte_data(client, HYM8563_CLKOUT, ret); +} + +static int hym8563_clkout_prepare(struct clk_hw *hw) +{ + return hym8563_clkout_control(hw, 1); +} + +static void hym8563_clkout_unprepare(struct clk_hw *hw) +{ + hym8563_clkout_control(hw, 0); +} + +static int hym8563_clkout_is_prepared(struct clk_hw *hw) +{ + struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); + struct i2c_client *client = hym8563->client; + int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); + + if (ret < 0) + return ret; + + return !(ret & HYM8563_CLKOUT_DISABLE); +} + +static const struct clk_ops hym8563_clkout_ops = { + .prepare = hym8563_clkout_prepare, + .unprepare = hym8563_clkout_unprepare, + .is_prepared = hym8563_clkout_is_prepared, + .recalc_rate = hym8563_clkout_recalc_rate, + .round_rate = hym8563_clkout_round_rate, + .set_rate = hym8563_clkout_set_rate, +}; + +static struct clk *hym8563_clkout_register_clk(struct hym8563 *hym8563) +{ + struct i2c_client *client = hym8563->client; + struct device_node *node = client->dev.of_node; + struct clk *clk; + struct clk_init_data init; + int ret; + + ret = i2c_smbus_write_byte_data(client, HYM8563_CLKOUT, + HYM8563_CLKOUT_DISABLE); + if (ret < 0) + return ERR_PTR(ret); + + init.name = "hym8563-clkout"; + init.ops = &hym8563_clkout_ops; + init.flags = CLK_IS_ROOT; + init.parent_names = NULL; + init.num_parents = 0; + hym8563->clkout_hw.init = &init; + + /* optional override of the clockname */ + of_property_read_string(node, "clock-output-names", &init.name); + + /* register the clock */ + clk = clk_register(&client->dev, &hym8563->clkout_hw); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return clk; +} +#endif + +/* + * The alarm interrupt is implemented as a level-low interrupt in the + * hym8563, while the timer interrupt uses a falling edge. + * We don't use the timer at all, so the interrupt is requested to + * use the level-low trigger. + */ +static irqreturn_t hym8563_irq(int irq, void *dev_id) +{ + struct hym8563 *hym8563 = (struct hym8563 *)dev_id; + struct i2c_client *client = hym8563->client; + struct mutex *lock = &hym8563->rtc->ops_lock; + int data, ret; + + mutex_lock(lock); + + /* Clear the alarm flag */ + + data = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + if (data < 0) { + dev_err(&client->dev, "%s: error reading i2c data %d\n", + __func__, data); + goto out; + } + + data &= ~HYM8563_CTL2_AF; + + ret = i2c_smbus_write_byte_data(client, HYM8563_CTL2, data); + if (ret < 0) { + dev_err(&client->dev, "%s: error writing i2c data %d\n", + __func__, ret); + } + +out: + mutex_unlock(lock); + return IRQ_HANDLED; +} + +static int hym8563_init_device(struct i2c_client *client) +{ + int ret; + + /* Clear stop flag if present */ + ret = i2c_smbus_write_byte_data(client, HYM8563_CTL1, 0); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); + if (ret < 0) + return ret; + + /* Disable alarm and timer interrupts */ + ret &= ~HYM8563_CTL2_AIE; + ret &= ~HYM8563_CTL2_TIE; + + /* Clear any pending alarm and timer flags */ + if (ret & HYM8563_CTL2_AF) + ret &= ~HYM8563_CTL2_AF; + + if (ret & HYM8563_CTL2_TF) + ret &= ~HYM8563_CTL2_TF; + + ret &= ~HYM8563_CTL2_TI_TP; + + return i2c_smbus_write_byte_data(client, HYM8563_CTL2, ret); +} + +#ifdef CONFIG_PM_SLEEP +static int hym8563_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret; + + if (device_may_wakeup(dev)) { + ret = enable_irq_wake(client->irq); + if (ret) { + dev_err(dev, "enable_irq_wake failed, %d\n", ret); + return ret; + } + } + + return 0; +} + +static int hym8563_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(client->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(hym8563_pm_ops, hym8563_suspend, hym8563_resume); + +static int hym8563_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct hym8563 *hym8563; + int ret; + + hym8563 = devm_kzalloc(&client->dev, sizeof(*hym8563), GFP_KERNEL); + if (!hym8563) + return -ENOMEM; + + hym8563->client = client; + i2c_set_clientdata(client, hym8563); + + device_set_wakeup_capable(&client->dev, true); + + ret = hym8563_init_device(client); + if (ret) { + dev_err(&client->dev, "could not init device, %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, hym8563_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + client->name, hym8563); + if (ret < 0) { + dev_err(&client->dev, "irq %d request failed, %d\n", + client->irq, ret); + return ret; + } + + /* check state of calendar information */ + ret = i2c_smbus_read_byte_data(client, HYM8563_SEC); + if (ret < 0) + return ret; + + hym8563->valid = !(ret & HYM8563_SEC_VL); + dev_dbg(&client->dev, "rtc information is %s\n", + hym8563->valid ? "valid" : "invalid"); + + hym8563->rtc = devm_rtc_device_register(&client->dev, client->name, + &hym8563_rtc_ops, THIS_MODULE); + if (IS_ERR(hym8563->rtc)) + return PTR_ERR(hym8563->rtc); + + /* the hym8563 alarm only supports a minute accuracy */ + hym8563->rtc->uie_unsupported = 1; + +#ifdef CONFIG_COMMON_CLK + hym8563_clkout_register_clk(hym8563); +#endif + + return 0; +} + +static const struct i2c_device_id hym8563_id[] = { + { "hym8563", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, hym8563_id); + +static const struct of_device_id hym8563_dt_idtable[] = { + { .compatible = "haoyu,hym8563" }, + {}, +}; +MODULE_DEVICE_TABLE(of, hym8563_dt_idtable); + +static struct i2c_driver hym8563_driver = { + .driver = { + .name = "rtc-hym8563", + .owner = THIS_MODULE, + .pm = &hym8563_pm_ops, + .of_match_table = hym8563_dt_idtable, + }, + .probe = hym8563_probe, + .id_table = hym8563_id, +}; + +module_i2c_driver(hym8563_driver); + +MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); +MODULE_DESCRIPTION("HYM8563 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index d3a8c8e255d..cd741c77e08 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -375,24 +375,16 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) struct imxdi_dev *imxdi; int rc; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - imxdi = devm_kzalloc(&pdev->dev, sizeof(*imxdi), GFP_KERNEL); if (!imxdi) return -ENOMEM; imxdi->pdev = pdev; - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) - return -EBUSY; - - imxdi->ioaddr = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (imxdi->ioaddr == NULL) - return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + imxdi->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(imxdi->ioaddr)) + return PTR_ERR(imxdi->ioaddr); spin_lock_init(&imxdi->irq_lock); @@ -409,7 +401,9 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) imxdi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(imxdi->clk)) return PTR_ERR(imxdi->clk); - clk_prepare_enable(imxdi->clk); + rc = clk_prepare_enable(imxdi->clk); + if (rc) + return rc; /* * Initialize dryice hardware diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a1bbbb8de02..03b89112942 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -16,6 +16,7 @@ #include <linux/rtc.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/err.h> #define DRV_VERSION "0.1" @@ -267,15 +268,7 @@ static int isl12022_probe(struct i2c_client *client, isl12022->rtc = devm_rtc_device_register(&client->dev, isl12022_driver.driver.name, &isl12022_rtc_ops, THIS_MODULE); - if (IS_ERR(isl12022->rtc)) - return PTR_ERR(isl12022->rtc); - - return 0; -} - -static int isl12022_remove(struct i2c_client *client) -{ - return 0; + return PTR_ERR_OR_ZERO(isl12022->rtc); } static const struct i2c_device_id isl12022_id[] = { @@ -289,7 +282,6 @@ static struct i2c_driver isl12022_driver = { .name = "rtc-isl12022", }, .probe = isl12022_probe, - .remove = isl12022_remove, .id_table = isl12022_id, }; diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c new file mode 100644 index 00000000000..455b601d731 --- /dev/null +++ b/drivers/rtc/rtc-isl12057.c @@ -0,0 +1,306 @@ +/* + * rtc-isl12057 - Driver for Intersil ISL12057 I2C Real Time Clock + * + * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.org> + * + * This work is largely based on Intersil ISL1208 driver developed by + * Hebert Valerio Riedel <hvr@gnu.org>. + * + * Detailed datasheet on which this development is based is available here: + * + * http://natisbad.org/NAS2/refs/ISL12057.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/rtc.h> +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +#define DRV_NAME "rtc-isl12057" + +/* RTC section */ +#define ISL12057_REG_RTC_SC 0x00 /* Seconds */ +#define ISL12057_REG_RTC_MN 0x01 /* Minutes */ +#define ISL12057_REG_RTC_HR 0x02 /* Hours */ +#define ISL12057_REG_RTC_HR_PM BIT(5) /* AM/PM bit in 12h format */ +#define ISL12057_REG_RTC_HR_MIL BIT(6) /* 24h/12h format */ +#define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */ +#define ISL12057_REG_RTC_DT 0x04 /* Date */ +#define ISL12057_REG_RTC_MO 0x05 /* Month */ +#define ISL12057_REG_RTC_YR 0x06 /* Year */ +#define ISL12057_RTC_SEC_LEN 7 + +/* Alarm 1 section */ +#define ISL12057_REG_A1_SC 0x07 /* Alarm 1 Seconds */ +#define ISL12057_REG_A1_MN 0x08 /* Alarm 1 Minutes */ +#define ISL12057_REG_A1_HR 0x09 /* Alarm 1 Hours */ +#define ISL12057_REG_A1_HR_PM BIT(5) /* AM/PM bit in 12h format */ +#define ISL12057_REG_A1_HR_MIL BIT(6) /* 24h/12h format */ +#define ISL12057_REG_A1_DWDT 0x0A /* Alarm 1 Date / Day of the week */ +#define ISL12057_REG_A1_DWDT_B BIT(6) /* DW / DT selection bit */ +#define ISL12057_A1_SEC_LEN 4 + +/* Alarm 2 section */ +#define ISL12057_REG_A2_MN 0x0B /* Alarm 2 Minutes */ +#define ISL12057_REG_A2_HR 0x0C /* Alarm 2 Hours */ +#define ISL12057_REG_A2_DWDT 0x0D /* Alarm 2 Date / Day of the week */ +#define ISL12057_A2_SEC_LEN 3 + +/* Control/Status registers */ +#define ISL12057_REG_INT 0x0E +#define ISL12057_REG_INT_A1IE BIT(0) /* Alarm 1 interrupt enable bit */ +#define ISL12057_REG_INT_A2IE BIT(1) /* Alarm 2 interrupt enable bit */ +#define ISL12057_REG_INT_INTCN BIT(2) /* Interrupt control enable bit */ +#define ISL12057_REG_INT_RS1 BIT(3) /* Freq out control bit 1 */ +#define ISL12057_REG_INT_RS2 BIT(4) /* Freq out control bit 2 */ +#define ISL12057_REG_INT_EOSC BIT(7) /* Oscillator enable bit */ + +#define ISL12057_REG_SR 0x0F +#define ISL12057_REG_SR_A1F BIT(0) /* Alarm 1 interrupt bit */ +#define ISL12057_REG_SR_A2F BIT(1) /* Alarm 2 interrupt bit */ +#define ISL12057_REG_SR_OSF BIT(7) /* Oscillator failure bit */ + +/* Register memory map length */ +#define ISL12057_MEM_MAP_LEN 0x10 + +struct isl12057_rtc_data { + struct regmap *regmap; + struct mutex lock; +}; + +static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs) +{ + tm->tm_sec = bcd2bin(regs[ISL12057_REG_RTC_SC]); + tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]); + + if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */ + tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x0f); + if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM) + tm->tm_hour += 12; + } else { /* 24 hour mode */ + tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x3f); + } + + tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]); + tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */ + tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO]) - 1; /* starts at 1 */ + tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100; +} + +static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm) +{ + /* + * The clock has an 8 bit wide bcd-coded register for the year. + * tm_year is an offset from 1900 and we are interested in the + * 2000-2099 range, so any value less than 100 is invalid. + */ + if (tm->tm_year < 100) + return -EINVAL; + + regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec); + regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min); + regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */ + regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday); + regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1); + regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year - 100); + regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1); + + return 0; +} + +/* + * Try and match register bits w/ fixed null values to see whether we + * are dealing with an ISL12057. Note: this function is called early + * during init and hence does need mutex protection. + */ +static int isl12057_i2c_validate_chip(struct regmap *regmap) +{ + u8 regs[ISL12057_MEM_MAP_LEN]; + static const u8 mask[ISL12057_MEM_MAP_LEN] = { 0x80, 0x80, 0x80, 0xf8, + 0xc0, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x7c }; + int ret, i; + + ret = regmap_bulk_read(regmap, 0, regs, ISL12057_MEM_MAP_LEN); + if (ret) + return ret; + + for (i = 0; i < ISL12057_MEM_MAP_LEN; ++i) { + if (regs[i] & mask[i]) /* check if bits are cleared */ + return -ENODEV; + } + + return 0; +} + +static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct isl12057_rtc_data *data = dev_get_drvdata(dev); + u8 regs[ISL12057_RTC_SEC_LEN]; + int ret; + + mutex_lock(&data->lock); + ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs, + ISL12057_RTC_SEC_LEN); + mutex_unlock(&data->lock); + + if (ret) { + dev_err(dev, "%s: RTC read failed\n", __func__); + return ret; + } + + isl12057_rtc_regs_to_tm(tm, regs); + + return rtc_valid_tm(tm); +} + +static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct isl12057_rtc_data *data = dev_get_drvdata(dev); + u8 regs[ISL12057_RTC_SEC_LEN]; + int ret; + + ret = isl12057_rtc_tm_to_regs(regs, tm); + if (ret) + return ret; + + mutex_lock(&data->lock); + ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs, + ISL12057_RTC_SEC_LEN); + mutex_unlock(&data->lock); + + if (ret) + dev_err(dev, "%s: RTC write failed\n", __func__); + + return ret; +} + +/* + * Check current RTC status and enable/disable what needs to be. Return 0 if + * everything went ok and a negative value upon error. Note: this function + * is called early during init and hence does need mutex protection. + */ +static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) +{ + int ret; + + /* Enable oscillator if not already running */ + ret = regmap_update_bits(regmap, ISL12057_REG_INT, + ISL12057_REG_INT_EOSC, 0); + if (ret < 0) { + dev_err(dev, "Unable to enable oscillator\n"); + return ret; + } + + /* Clear oscillator failure bit if needed */ + ret = regmap_update_bits(regmap, ISL12057_REG_SR, + ISL12057_REG_SR_OSF, 0); + if (ret < 0) { + dev_err(dev, "Unable to clear oscillator failure bit\n"); + return ret; + } + + /* Clear alarm bit if needed */ + ret = regmap_update_bits(regmap, ISL12057_REG_SR, + ISL12057_REG_SR_A1F, 0); + if (ret < 0) { + dev_err(dev, "Unable to clear alarm bit\n"); + return ret; + } + + return 0; +} + +static const struct rtc_class_ops rtc_ops = { + .read_time = isl12057_rtc_read_time, + .set_time = isl12057_rtc_set_time, +}; + +static struct regmap_config isl12057_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int isl12057_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct isl12057_rtc_data *data; + struct rtc_device *rtc; + struct regmap *regmap; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; + + regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(dev, "regmap allocation failed: %d\n", ret); + return ret; + } + + ret = isl12057_i2c_validate_chip(regmap); + if (ret) + return ret; + + ret = isl12057_check_rtc_status(dev, regmap); + if (ret) + return ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + mutex_init(&data->lock); + data->regmap = regmap; + dev_set_drvdata(dev, data); + + rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops, THIS_MODULE); + return PTR_ERR_OR_ZERO(rtc); +} + +#ifdef CONFIG_OF +static const struct of_device_id isl12057_dt_match[] = { + { .compatible = "isl,isl12057" }, + { }, +}; +#endif + +static const struct i2c_device_id isl12057_id[] = { + { "isl12057", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, isl12057_id); + +static struct i2c_driver isl12057_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(isl12057_dt_match), + }, + .probe = isl12057_probe, + .id_table = isl12057_id, +}; +module_i2c_driver(isl12057_driver); + +MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>"); +MODULE_DESCRIPTION("Intersil ISL12057 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index c016ad81767..c3c549d511b 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -144,11 +144,7 @@ isl1208_i2c_validate_client(struct i2c_client *client) static int isl1208_i2c_get_sr(struct i2c_client *client) { - int sr = i2c_smbus_read_byte_data(client, ISL1208_REG_SR); - if (sr < 0) - return -EIO; - - return sr; + return i2c_smbus_read_byte_data(client, ISL1208_REG_SR); } static int @@ -647,10 +643,11 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) "chip found, driver version " DRV_VERSION "\n"); if (client->irq > 0) { - rc = request_threaded_irq(client->irq, NULL, - isl1208_rtc_interrupt, - IRQF_SHARED, - isl1208_driver.driver.name, client); + rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, + isl1208_rtc_interrupt, + IRQF_SHARED, + isl1208_driver.driver.name, + client); if (!rc) { device_init_wakeup(&client->dev, 1); enable_irq_wake(client->irq); @@ -662,20 +659,18 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) } } - rtc = rtc_device_register(isl1208_driver.driver.name, - &client->dev, &isl1208_rtc_ops, + rtc = devm_rtc_device_register(&client->dev, isl1208_driver.driver.name, + &isl1208_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - rc = PTR_ERR(rtc); - goto exit_free_irq; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); i2c_set_clientdata(client, rtc); rc = isl1208_i2c_get_sr(client); if (rc < 0) { dev_err(&client->dev, "reading status failed\n"); - goto exit_unregister; + return rc; } if (rc & ISL1208_REG_SR_RTCF) @@ -684,28 +679,15 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); if (rc) - goto exit_unregister; + return rc; return 0; - -exit_unregister: - rtc_device_unregister(rtc); -exit_free_irq: - if (client->irq) - free_irq(client->irq, client); - - return rc; } static int isl1208_remove(struct i2c_client *client) { - struct rtc_device *rtc = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); - rtc_device_unregister(rtc); - if (client->irq) - free_irq(client->irq, client); return 0; } diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 1e48686ca6d..08f5160fb6d 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -14,6 +14,7 @@ * */ +#include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -37,7 +38,6 @@ #define JZ_RTC_CTRL_ENABLE BIT(0) struct jz4740_rtc { - struct resource *mem; void __iomem *base; struct rtc_device *rtc; @@ -215,39 +215,22 @@ static int jz4740_rtc_probe(struct platform_device *pdev) int ret; struct jz4740_rtc *rtc; uint32_t scratchpad; + struct resource *mem; - rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; rtc->irq = platform_get_irq(pdev, 0); if (rtc->irq < 0) { - ret = -ENOENT; dev_err(&pdev->dev, "Failed to get platform irq\n"); - goto err_free; - } - - rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!rtc->mem) { - ret = -ENOENT; - dev_err(&pdev->dev, "Failed to get platform mmio memory\n"); - goto err_free; + return -ENOENT; } - rtc->mem = request_mem_region(rtc->mem->start, resource_size(rtc->mem), - pdev->name); - if (!rtc->mem) { - ret = -EBUSY; - dev_err(&pdev->dev, "Failed to request mmio memory region\n"); - goto err_free; - } - - rtc->base = ioremap_nocache(rtc->mem->start, resource_size(rtc->mem)); - if (!rtc->base) { - ret = -EBUSY; - dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); - goto err_release_mem_region; - } + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rtc->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(rtc->base)) + return PTR_ERR(rtc->base); spin_lock_init(&rtc->lock); @@ -255,19 +238,19 @@ static int jz4740_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops, - THIS_MODULE); + rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &jz4740_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc)) { ret = PTR_ERR(rtc->rtc); dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret); - goto err_iounmap; + return ret; } - ret = request_irq(rtc->irq, jz4740_rtc_irq, 0, + ret = devm_request_irq(&pdev->dev, rtc->irq, jz4740_rtc_irq, 0, pdev->name, rtc); if (ret) { dev_err(&pdev->dev, "Failed to request rtc irq: %d\n", ret); - goto err_unregister_rtc; + return ret; } scratchpad = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD); @@ -276,46 +259,13 @@ static int jz4740_rtc_probe(struct platform_device *pdev) ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0); if (ret) { dev_err(&pdev->dev, "Could not write write to RTC registers\n"); - goto err_free_irq; + return ret; } } return 0; - -err_free_irq: - free_irq(rtc->irq, rtc); -err_unregister_rtc: - rtc_device_unregister(rtc->rtc); -err_iounmap: - platform_set_drvdata(pdev, NULL); - iounmap(rtc->base); -err_release_mem_region: - release_mem_region(rtc->mem->start, resource_size(rtc->mem)); -err_free: - kfree(rtc); - - return ret; } -static int jz4740_rtc_remove(struct platform_device *pdev) -{ - struct jz4740_rtc *rtc = platform_get_drvdata(pdev); - - free_irq(rtc->irq, rtc); - - rtc_device_unregister(rtc->rtc); - - iounmap(rtc->base); - release_mem_region(rtc->mem->start, resource_size(rtc->mem)); - - kfree(rtc); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - - #ifdef CONFIG_PM static int jz4740_rtc_suspend(struct device *dev) { @@ -347,7 +297,6 @@ static const struct dev_pm_ops jz4740_pm_ops = { static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, - .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 index 9853ac15b29..4ff6c73253b 100644 --- a/drivers/rtc/rtc-lp8788.c +++ b/drivers/rtc/rtc-lp8788.c @@ -312,16 +312,8 @@ static int lp8788_rtc_probe(struct platform_device *pdev) return 0; } -static int lp8788_rtc_remove(struct platform_device *pdev) -{ - 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, diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index 787550d756e..f130c08c98f 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -201,16 +201,9 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev) { struct resource *res; struct lpc32xx_rtc *rtc; - resource_size_t size; int rtcirq; u32 tmp; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Can't get memory resource\n"); - return -ENOENT; - } - rtcirq = platform_get_irq(pdev, 0); if (rtcirq < 0 || rtcirq >= NR_IRQS) { dev_warn(&pdev->dev, "Can't get interrupt resource\n"); @@ -218,25 +211,15 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev) } rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); - if (unlikely(!rtc)) { - dev_err(&pdev->dev, "Can't allocate memory\n"); + if (unlikely(!rtc)) return -ENOMEM; - } - rtc->irq = rtcirq; - - size = resource_size(res); - if (!devm_request_mem_region(&pdev->dev, res->start, size, - pdev->name)) { - dev_err(&pdev->dev, "RTC registers are not free\n"); - return -EBUSY; - } + rtc->irq = rtcirq; - rtc->rtc_base = devm_ioremap(&pdev->dev, res->start, size); - if (!rtc->rtc_base) { - dev_err(&pdev->dev, "Can't map memory\n"); - return -ENOMEM; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rtc->rtc_base)) + return PTR_ERR(rtc->rtc_base); spin_lock_init(&rtc->lock); @@ -277,7 +260,6 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev) &lpc32xx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc)) { dev_err(&pdev->dev, "Can't get RTC\n"); - platform_set_drvdata(pdev, NULL); return PTR_ERR(rtc->rtc); } @@ -306,8 +288,6 @@ static int lpc32xx_rtc_remove(struct platform_device *pdev) if (rtc->irq >= 0) device_init_wakeup(&pdev->dev, 0); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c index db82f91f456..682ecb09483 100644 --- a/drivers/rtc/rtc-ls1x.c +++ b/drivers/rtc/rtc-ls1x.c @@ -185,19 +185,11 @@ err: return ret; } -static int ls1x_rtc_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - - return 0; -} - static struct platform_driver ls1x_rtc_driver = { .driver = { .name = "ls1x-rtc", .owner = THIS_MODULE, }, - .remove = ls1x_rtc_remove, .probe = ls1x_rtc_probe, }; diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 89674b5e6ef..7ff7427c2e6 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -66,8 +66,6 @@ #define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */ #define M41T80_FEATURE_SQ_ALT (1 << 4) /* RSx bits are in reg 4 */ -#define DRV_VERSION "0.05" - static DEFINE_MUTEX(m41t80_rtc_mutex); static const struct i2c_device_id m41t80_id[] = { { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, @@ -80,6 +78,7 @@ static const struct i2c_device_id m41t80_id[] = { { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ }, { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ }, { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ }, + { "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT }, { } }; MODULE_DEVICE_TABLE(i2c, m41t80_id); @@ -168,7 +167,7 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f); buf[M41T80_REG_HOUR] = - bin2bcd(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f) ; + bin2bcd(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f); buf[M41T80_REG_WDAY] = (tm->tm_wday & 0x07) | (buf[M41T80_REG_WDAY] & ~0x07); buf[M41T80_REG_DAY] = @@ -232,7 +231,7 @@ static ssize_t m41t80_sysfs_show_flags(struct device *dev, val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); if (val < 0) - return -EIO; + return val; return sprintf(buf, "%#x\n", val); } static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL); @@ -252,7 +251,7 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev, reg_sqw = M41T80_REG_WDAY; val = i2c_smbus_read_byte_data(client, reg_sqw); if (val < 0) - return -EIO; + return val; val = (val >> 4) & 0xf; switch (val) { case 0: @@ -271,7 +270,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct m41t80_data *clientdata = i2c_get_clientdata(client); - int almon, sqw, reg_sqw; + int almon, sqw, reg_sqw, rc; int val = simple_strtoul(buf, NULL, 0); if (!(clientdata->features & M41T80_FEATURE_SQ)) @@ -291,21 +290,30 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, /* disable SQW, set SQW frequency & re-enable */ almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); if (almon < 0) - return -EIO; + return almon; reg_sqw = M41T80_REG_SQW; if (clientdata->features & M41T80_FEATURE_SQ_ALT) reg_sqw = M41T80_REG_WDAY; sqw = i2c_smbus_read_byte_data(client, reg_sqw); if (sqw < 0) - return -EIO; + return sqw; sqw = (sqw & 0x0f) | (val << 4); - if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, - almon & ~M41T80_ALMON_SQWE) < 0 || - i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0) - return -EIO; - if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, - almon | M41T80_ALMON_SQWE) < 0) - return -EIO; + + rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, + almon & ~M41T80_ALMON_SQWE); + if (rc < 0) + return rc; + + if (val) { + rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw); + if (rc < 0) + return rc; + + rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, + almon | M41T80_ALMON_SQWE); + if (rc <0) + return rc; + } return count; } static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR, @@ -629,40 +637,28 @@ static int m41t80_probe(struct i2c_client *client, struct m41t80_data *clientdata = NULL; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C - | I2C_FUNC_SMBUS_BYTE_DATA)) { - rc = -ENODEV; - goto exit; - } - - dev_info(&client->dev, - "chip found, driver version " DRV_VERSION "\n"); + | I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata), GFP_KERNEL); - if (!clientdata) { - rc = -ENOMEM; - goto exit; - } + if (!clientdata) + return -ENOMEM; clientdata->features = id->driver_data; i2c_set_clientdata(client, clientdata); rtc = devm_rtc_device_register(&client->dev, client->name, &m41t80_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - rc = PTR_ERR(rtc); - rtc = NULL; - goto exit; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); clientdata->rtc = rtc; /* Make sure HT (Halt Update) bit is cleared */ rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); - if (rc < 0) - goto ht_err; - if (rc & M41T80_ALHOUR_HT) { + if (rc >= 0 && rc & M41T80_ALHOUR_HT) { if (clientdata->features & M41T80_FEATURE_HT) { m41t80_get_datetime(client, &tm); dev_info(&client->dev, "HT bit was set!\n"); @@ -673,53 +669,44 @@ static int m41t80_probe(struct i2c_client *client, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } - if (i2c_smbus_write_byte_data(client, - M41T80_REG_ALARM_HOUR, - rc & ~M41T80_ALHOUR_HT) < 0) - goto ht_err; + rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR, + rc & ~M41T80_ALHOUR_HT); + } + + if (rc < 0) { + dev_err(&client->dev, "Can't clear HT bit\n"); + return rc; } /* Make sure ST (stop) bit is cleared */ rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC); - if (rc < 0) - goto st_err; - if (rc & M41T80_SEC_ST) { - if (i2c_smbus_write_byte_data(client, M41T80_REG_SEC, - rc & ~M41T80_SEC_ST) < 0) - goto st_err; + if (rc >= 0 && rc & M41T80_SEC_ST) + rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, + rc & ~M41T80_SEC_ST); + if (rc < 0) { + dev_err(&client->dev, "Can't clear ST bit\n"); + return rc; } rc = m41t80_sysfs_register(&client->dev); if (rc) - goto exit; + return rc; #ifdef CONFIG_RTC_DRV_M41T80_WDT if (clientdata->features & M41T80_FEATURE_HT) { save_client = client; rc = misc_register(&wdt_dev); if (rc) - goto exit; + return rc; rc = register_reboot_notifier(&wdt_notifier); if (rc) { misc_deregister(&wdt_dev); - goto exit; + return rc; } } #endif return 0; - -st_err: - rc = -EIO; - dev_err(&client->dev, "Can't clear ST bit\n"); - goto exit; -ht_err: - rc = -EIO; - dev_err(&client->dev, "Can't clear HT bit\n"); - goto exit; - -exit: - return rc; } static int m41t80_remove(struct i2c_client *client) @@ -750,4 +737,3 @@ module_i2c_driver(m41t80_driver); MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>"); MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c index 9707d36e8b1..4698c7e344e 100644 --- a/drivers/rtc/rtc-m41t93.c +++ b/drivers/rtc/rtc-m41t93.c @@ -194,19 +194,12 @@ static int m41t93_probe(struct spi_device *spi) return 0; } - -static int m41t93_remove(struct spi_device *spi) -{ - return 0; -} - static struct spi_driver m41t93_driver = { .driver = { .name = "rtc-m41t93", .owner = THIS_MODULE, }, .probe = m41t93_probe, - .remove = m41t93_remove, }; module_spi_driver(m41t93_driver); diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c index 7454ef0a4cf..8d800b1bf87 100644 --- a/drivers/rtc/rtc-m41t94.c +++ b/drivers/rtc/rtc-m41t94.c @@ -134,18 +134,12 @@ static int m41t94_probe(struct spi_device *spi) return 0; } -static int m41t94_remove(struct spi_device *spi) -{ - return 0; -} - static struct spi_driver m41t94_driver = { .driver = { .name = "rtc-m41t94", .owner = THIS_MODULE, }, .probe = m41t94_probe, - .remove = m41t94_remove, }; module_spi_driver(m41t94_driver); diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index 37444246e5e..411adb3f86a 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -20,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/bcd.h> #include <linux/io.h> +#include <linux/err.h> #define DRV_VERSION "1.0" @@ -174,15 +175,7 @@ static int m48t35_probe(struct platform_device *pdev) priv->rtc = devm_rtc_device_register(&pdev->dev, "m48t35", &m48t35_ops, THIS_MODULE); - if (IS_ERR(priv->rtc)) - return PTR_ERR(priv->rtc); - - return 0; -} - -static int m48t35_remove(struct platform_device *pdev) -{ - return 0; + return PTR_ERR_OR_ZERO(priv->rtc); } static struct platform_driver m48t35_platform_driver = { @@ -191,7 +184,6 @@ static struct platform_driver m48t35_platform_driver = { .owner = THIS_MODULE, }, .probe = m48t35_probe, - .remove = m48t35_remove, }; module_platform_driver(m48t35_platform_driver); diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 130f29af386..11880c1e9da 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -68,7 +68,7 @@ m48t59_mem_readb(struct device *dev, u32 ofs) static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; u8 val; @@ -111,7 +111,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; u8 val = 0; @@ -158,7 +158,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); struct rtc_time *tm = &alrm->time; unsigned long flags; @@ -205,7 +205,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); struct rtc_time *tm = &alrm->time; u8 mday, hour, min, sec; @@ -266,7 +266,7 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; @@ -283,7 +283,7 @@ static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq) { struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); unsigned long flags; u8 val; @@ -304,7 +304,7 @@ static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id) { struct device *dev = (struct device *)dev_id; struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); u8 event; @@ -340,7 +340,7 @@ static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); ssize_t cnt = 0; unsigned long flags; @@ -360,7 +360,7 @@ static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct platform_device *pdev = to_platform_device(dev); - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = platform_get_drvdata(pdev); ssize_t cnt = 0; unsigned long flags; @@ -385,7 +385,7 @@ static struct bin_attribute m48t59_nvram_attr = { static int m48t59_rtc_probe(struct platform_device *pdev) { - struct m48t59_plat_data *pdata = pdev->dev.platform_data; + struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev); struct m48t59_private *m48t59 = NULL; struct resource *res; int ret = -ENOMEM; @@ -409,7 +409,8 @@ static int m48t59_rtc_probe(struct platform_device *pdev) } else if (res->flags & IORESOURCE_MEM) { /* we are memory-mapped */ if (!pdata) { - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), + GFP_KERNEL); if (!pdata) return -ENOMEM; /* Ensure we only kmalloc platform data once */ @@ -425,7 +426,7 @@ static int m48t59_rtc_probe(struct platform_device *pdev) pdata->read_byte = m48t59_mem_readb; } - m48t59 = kzalloc(sizeof(*m48t59), GFP_KERNEL); + m48t59 = devm_kzalloc(&pdev->dev, sizeof(*m48t59), GFP_KERNEL); if (!m48t59) return -ENOMEM; @@ -433,9 +434,10 @@ static int m48t59_rtc_probe(struct platform_device *pdev) if (!m48t59->ioaddr) { /* ioaddr not mapped externally */ - m48t59->ioaddr = ioremap(res->start, resource_size(res)); + m48t59->ioaddr = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (!m48t59->ioaddr) - goto out; + return ret; } /* Try to get irq number. We also can work in @@ -446,10 +448,11 @@ static int m48t59_rtc_probe(struct platform_device *pdev) m48t59->irq = NO_IRQ; if (m48t59->irq != NO_IRQ) { - ret = request_irq(m48t59->irq, m48t59_rtc_interrupt, - IRQF_SHARED, "rtc-m48t59", &pdev->dev); + ret = devm_request_irq(&pdev->dev, m48t59->irq, + m48t59_rtc_interrupt, IRQF_SHARED, + "rtc-m48t59", &pdev->dev); if (ret) - goto out; + return ret; } switch (pdata->type) { case M48T59RTC_TYPE_M48T59: @@ -469,52 +472,29 @@ static int m48t59_rtc_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "Unknown RTC type\n"); - ret = -ENODEV; - goto out; + return -ENODEV; } spin_lock_init(&m48t59->lock); platform_set_drvdata(pdev, m48t59); - m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); - if (IS_ERR(m48t59->rtc)) { - ret = PTR_ERR(m48t59->rtc); - goto out; - } + m48t59->rtc = devm_rtc_device_register(&pdev->dev, name, ops, + THIS_MODULE); + if (IS_ERR(m48t59->rtc)) + return PTR_ERR(m48t59->rtc); m48t59_nvram_attr.size = pdata->offset; ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); - if (ret) { - rtc_device_unregister(m48t59->rtc); - goto out; - } + if (ret) + return ret; return 0; - -out: - if (m48t59->irq != NO_IRQ) - free_irq(m48t59->irq, &pdev->dev); - if (m48t59->ioaddr) - iounmap(m48t59->ioaddr); - kfree(m48t59); - return ret; } 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; - sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); - if (!IS_ERR(m48t59->rtc)) - rtc_device_unregister(m48t59->rtc); - if (m48t59->ioaddr && !pdata->ioaddr) - iounmap(m48t59->ioaddr); - if (m48t59->irq != NO_IRQ) - free_irq(m48t59->irq, &pdev->dev); - platform_set_drvdata(pdev, NULL); - kfree(m48t59); return 0; } diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 33a91c48453..32f64c94262 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -46,7 +46,7 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); reg = ops->readbyte(M48T86_REG_B); @@ -84,7 +84,7 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); reg = ops->readbyte(M48T86_REG_B); @@ -123,7 +123,7 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) { unsigned char reg; struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = pdev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); reg = ops->readbyte(M48T86_REG_B); @@ -147,7 +147,7 @@ static const struct rtc_class_ops m48t86_rtc_ops = { static int m48t86_rtc_probe(struct platform_device *dev) { unsigned char reg; - struct m48t86_ops *ops = dev->dev.platform_data; + struct m48t86_ops *ops = dev_get_platdata(&dev->dev); struct rtc_device *rtc; rtc = devm_rtc_device_register(&dev->dev, "m48t86", @@ -166,20 +166,12 @@ static int m48t86_rtc_probe(struct platform_device *dev) return 0; } -static int m48t86_rtc_remove(struct platform_device *dev) -{ - platform_set_drvdata(dev, NULL); - - return 0; -} - static struct platform_driver m48t86_rtc_platform_driver = { .driver = { .name = "rtc-m48t86", .owner = THIS_MODULE, }, .probe = m48t86_rtc_probe, - .remove = m48t86_rtc_remove, }; module_platform_driver(m48t86_rtc_platform_driver); diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index 8669d6d09a0..4804985b876 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -164,14 +164,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) static int max6900_i2c_clear_write_protect(struct i2c_client *client) { - int rc; - rc = i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0); - if (rc < 0) { - dev_err(&client->dev, "%s: control register write failed\n", - __func__); - return -EIO; - } - return 0; + return i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0); } static int @@ -212,11 +205,6 @@ static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm) return max6900_i2c_set_time(to_i2c_client(dev), tm); } -static int max6900_remove(struct i2c_client *client) -{ - return 0; -} - static const struct rtc_class_ops max6900_rtc_ops = { .read_time = max6900_rtc_read_time, .set_time = max6900_rtc_set_time, @@ -252,7 +240,6 @@ static struct i2c_driver max6900_driver = { .name = "rtc-max6900", }, .probe = max6900_probe, - .remove = max6900_remove, .id_table = max6900_id, }; diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index e3aea00c314..ac3f4191864 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -143,23 +143,17 @@ static int max6902_probe(struct spi_device *spi) return 0; } -static int max6902_remove(struct spi_device *spi) -{ - return 0; -} - static struct spi_driver max6902_driver = { .driver = { .name = "rtc-max6902", .owner = THIS_MODULE, }, .probe = max6902_probe, - .remove = max6902_remove, }; module_spi_driver(max6902_driver); -MODULE_DESCRIPTION ("max6902 spi RTC driver"); -MODULE_AUTHOR ("Raphael Assenat"); -MODULE_LICENSE ("GPL"); +MODULE_DESCRIPTION("max6902 spi RTC driver"); +MODULE_AUTHOR("Raphael Assenat"); +MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:rtc-max6902"); diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 771812d62e6..9efe118a28b 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -119,7 +119,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) 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 ; + 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." @@ -240,9 +240,9 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) } alrm->pending = 0; - ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS1, &val); + ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val); if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n", + dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n", __func__, __LINE__, ret); goto out; } @@ -567,11 +567,6 @@ err_rtc: return ret; } -static int max77686_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static void max77686_rtc_shutdown(struct platform_device *pdev) { #ifdef MAX77686_RTC_WTSR_SMPL @@ -610,7 +605,6 @@ static struct platform_driver max77686_rtc_driver = { .owner = THIS_MODULE, }, .probe = max77686_rtc_probe, - .remove = max77686_rtc_remove, .shutdown = max77686_rtc_shutdown, .id_table = rtc_id, }; diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index 86afb797125..3032178bd9e 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -51,7 +51,7 @@ static irqreturn_t max8907_irq_handler(int irq, void *data) { struct max8907_rtc *rtc = data; - regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); + regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0); rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); @@ -64,7 +64,7 @@ static void regs_to_tm(u8 *regs, struct rtc_time *tm) bcd2bin(regs[RTC_YEAR1]) - 1900; tm->tm_mon = bcd2bin(regs[RTC_MONTH] & 0x1f) - 1; tm->tm_mday = bcd2bin(regs[RTC_DATE] & 0x3f); - tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07) - 1; + tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07); if (regs[RTC_HOUR] & HOUR_12) { tm->tm_hour = bcd2bin(regs[RTC_HOUR] & 0x01f); if (tm->tm_hour == 12) @@ -88,7 +88,7 @@ static void tm_to_regs(struct rtc_time *tm, u8 *regs) regs[RTC_YEAR1] = bin2bcd(low); regs[RTC_MONTH] = bin2bcd(tm->tm_mon + 1); regs[RTC_DATE] = bin2bcd(tm->tm_mday); - regs[RTC_WEEKDAY] = tm->tm_wday + 1; + regs[RTC_WEEKDAY] = tm->tm_wday; regs[RTC_HOUR] = bin2bcd(tm->tm_hour); regs[RTC_MIN] = bin2bcd(tm->tm_min); regs[RTC_SEC] = bin2bcd(tm->tm_sec); @@ -153,7 +153,7 @@ static int max8907_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) tm_to_regs(&alrm->time, regs); /* Disable alarm while we update the target time */ - ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); + ret = regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0); if (ret < 0) return ret; @@ -163,8 +163,7 @@ static int max8907_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; if (alrm->enabled) - ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, - 0x7f, 0x7f); + ret = regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x77); return ret; } @@ -213,18 +212,12 @@ static int max8907_rtc_probe(struct platform_device *pdev) return ret; } -static int max8907_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver max8907_rtc_driver = { .driver = { .name = "max8907-rtc", .owner = THIS_MODULE, }, .probe = max8907_rtc_probe, - .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 7c90f4e45e2..951d1a78e19 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -268,7 +268,7 @@ static int max8925_rtc_probe(struct platform_device *pdev) if (ret < 0) { dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", info->irq, ret); - goto err; + return ret; } dev_set_drvdata(&pdev->dev, info); @@ -282,18 +282,10 @@ static int max8925_rtc_probe(struct platform_device *pdev) ret = PTR_ERR(info->rtc_dev); if (IS_ERR(info->rtc_dev)) { dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); - goto err; + return ret; } return 0; -err: - platform_set_drvdata(pdev, NULL); - return ret; -} - -static int max8925_rtc_remove(struct platform_device *pdev) -{ - return 0; } #ifdef CONFIG_PM_SLEEP @@ -326,7 +318,6 @@ static struct platform_driver max8925_rtc_driver = { .pm = &max8925_rtc_pm_ops, }, .probe = max8925_rtc_probe, - .remove = max8925_rtc_remove, }; module_platform_driver(max8925_rtc_driver); diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index dacf48db792..0777c01b58e 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -104,7 +104,7 @@ static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data) 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 ; + 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." @@ -507,11 +507,6 @@ err_out: return ret; } -static int max8997_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static void max8997_rtc_shutdown(struct platform_device *pdev) { struct max8997_rtc_info *info = platform_get_drvdata(pdev); @@ -531,7 +526,6 @@ static struct platform_driver max8997_rtc_driver = { .owner = THIS_MODULE, }, .probe = max8997_rtc_probe, - .remove = max8997_rtc_remove, .shutdown = max8997_rtc_shutdown, .id_table = rtc_id, }; diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index d5af7baa48b..f098ad8382d 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -16,6 +16,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/bcd.h> +#include <linux/irqdomain.h> #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/mfd/max8998.h> @@ -252,7 +253,7 @@ static const struct rtc_class_ops max8998_rtc_ops = { 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); + struct max8998_platform_data *pdata = max8998->pdata; struct max8998_rtc_info *info; int ret; @@ -264,7 +265,6 @@ static int max8998_rtc_probe(struct platform_device *pdev) info->dev = &pdev->dev; info->max8998 = max8998; info->rtc = max8998->rtc; - info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; platform_set_drvdata(pdev, info); @@ -274,7 +274,16 @@ static int max8998_rtc_probe(struct platform_device *pdev) if (IS_ERR(info->rtc_dev)) { ret = PTR_ERR(info->rtc_dev); dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); - goto out_rtc; + return ret; + } + + if (!max8998->irq_domain) + goto no_irq; + + info->irq = irq_create_mapping(max8998->irq_domain, MAX8998_IRQ_ALARM0); + if (!info->irq) { + dev_warn(&pdev->dev, "Failed to map alarm IRQ\n"); + goto no_irq; } ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, @@ -284,6 +293,7 @@ static int max8998_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", info->irq, ret); +no_irq: dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name); if (pdata && pdata->rtc_delay) { info->lp3974_bug_workaround = true; @@ -292,15 +302,6 @@ static int max8998_rtc_probe(struct platform_device *pdev) } return 0; - -out_rtc: - platform_set_drvdata(pdev, NULL); - return ret; -} - -static int max8998_rtc_remove(struct platform_device *pdev) -{ - return 0; } static const struct platform_device_id max8998_rtc_id[] = { @@ -315,7 +316,6 @@ static struct platform_driver max8998_rtc_driver = { .owner = THIS_MODULE, }, .probe = max8998_rtc_probe, - .remove = max8998_rtc_remove, .id_table = max8998_rtc_id, }; diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 7a8ed27a5f2..0765606a2d1 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -23,6 +23,8 @@ #define MC13XXX_RTCDAY 22 #define MC13XXX_RTCDAYA 23 +#define SEC_PER_DAY (24 * 60 * 60) + struct mc13xxx_rtc { struct rtc_device *rtc; struct mc13xxx *mc13xxx; @@ -42,15 +44,15 @@ static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev, return func(priv->mc13xxx, irq); } -static int mc13xxx_rtc_irq_enable(struct device *dev, - unsigned int enabled, int irq) +static int mc13xxx_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) { struct mc13xxx_rtc *priv = dev_get_drvdata(dev); int ret; mc13xxx_lock(priv->mc13xxx); - ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq); + ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, MC13XXX_IRQ_TODA); mc13xxx_unlock(priv->mc13xxx); @@ -61,44 +63,27 @@ static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct mc13xxx_rtc *priv = dev_get_drvdata(dev); unsigned int seconds, days1, days2; - unsigned long s1970; - int ret; - - mc13xxx_lock(priv->mc13xxx); - if (!priv->valid) { - ret = -ENODATA; - goto out; - } - - ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1); - if (unlikely(ret)) - goto out; - - ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds); - if (unlikely(ret)) - goto out; - - ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2); -out: - mc13xxx_unlock(priv->mc13xxx); + if (!priv->valid) + return -ENODATA; - if (ret) - return ret; + do { + int ret; - if (days2 == days1 + 1) { - if (seconds >= 86400 / 2) - days2 = days1; - else - days1 = days2; - } + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1); + if (ret) + return ret; - if (days1 != days2) - return -EIO; + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds); + if (ret) + return ret; - s1970 = days1 * 86400 + seconds; + ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2); + if (ret) + return ret; + } while (days1 != days2); - rtc_time_to_tm(s1970, tm); + rtc_time_to_tm(days1 * SEC_PER_DAY + seconds, tm); return rtc_valid_tm(tm); } @@ -110,8 +95,8 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs) unsigned int alarmseconds; int ret; - seconds = secs % 86400; - days = secs / 86400; + seconds = secs % SEC_PER_DAY; + days = secs / SEC_PER_DAY; mc13xxx_lock(priv->mc13xxx); @@ -123,7 +108,7 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs) if (unlikely(ret)) goto out; - if (alarmseconds < 86400) { + if (alarmseconds < SEC_PER_DAY) { ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, 0x1ffff); if (unlikely(ret)) @@ -147,18 +132,21 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs) goto out; /* restore alarm */ - if (alarmseconds < 86400) { + if (alarmseconds < SEC_PER_DAY) { ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, alarmseconds); if (unlikely(ret)) goto out; } - ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST); - if (unlikely(ret)) - goto out; + if (!priv->valid) { + ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST); + if (unlikely(ret)) + goto out; + + ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST); + } - ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST); out: priv->valid = !ret; @@ -180,7 +168,7 @@ static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds); if (unlikely(ret)) goto out; - if (seconds >= 86400) { + if (seconds >= SEC_PER_DAY) { ret = -ENODATA; goto out; } @@ -201,7 +189,7 @@ out: alarm->enabled = enabled; alarm->pending = pending; - s1970 = days * 86400 + seconds; + s1970 = days * SEC_PER_DAY + seconds; rtc_time_to_tm(s1970, &alarm->time); dev_dbg(dev, "%s: %lu\n", __func__, s1970); @@ -239,8 +227,8 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) if (unlikely(ret)) goto out; - seconds = s1970 % 86400; - days = s1970 / 86400; + seconds = s1970 % SEC_PER_DAY; + days = s1970 / SEC_PER_DAY; ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days); if (unlikely(ret)) @@ -259,8 +247,6 @@ static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev) struct mc13xxx_rtc *priv = dev; struct mc13xxx *mc13xxx = priv->mc13xxx; - dev_dbg(&priv->rtc->dev, "Alarm\n"); - rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); mc13xxx_irq_ack(mc13xxx, irq); @@ -273,8 +259,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev) struct mc13xxx_rtc *priv = dev; struct mc13xxx *mc13xxx = priv->mc13xxx; - dev_dbg(&priv->rtc->dev, "1HZ\n"); - rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); mc13xxx_irq_ack(mc13xxx, irq); @@ -282,12 +266,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev) return IRQ_HANDLED; } -static int mc13xxx_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) -{ - return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA); -} - static const struct rtc_class_ops mc13xxx_rtc_ops = { .read_time = mc13xxx_rtc_read_time, .set_mmss = mc13xxx_rtc_set_mmss, @@ -301,7 +279,6 @@ static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev) struct mc13xxx_rtc *priv = dev; struct mc13xxx *mc13xxx = priv->mc13xxx; - dev_dbg(&priv->rtc->dev, "RTCRST\n"); priv->valid = 0; mc13xxx_irq_mask(mc13xxx, irq); @@ -314,7 +291,6 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev) int ret; struct mc13xxx_rtc *priv; struct mc13xxx *mc13xxx; - int rtcrst_pending; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -322,62 +298,47 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev) mc13xxx = dev_get_drvdata(pdev->dev.parent); priv->mc13xxx = mc13xxx; + priv->valid = 1; platform_set_drvdata(pdev, priv); mc13xxx_lock(mc13xxx); + mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST); + ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST, mc13xxx_rtc_reset_handler, DRIVER_NAME, priv); if (ret) - goto err_reset_irq_request; - - ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST, - NULL, &rtcrst_pending); - if (ret) - goto err_reset_irq_status; + goto err_irq_request; - priv->valid = !rtcrst_pending; - - ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ, + ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_1HZ, mc13xxx_rtc_update_handler, DRIVER_NAME, priv); if (ret) - goto err_update_irq_request; + goto err_irq_request; ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA, mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv); if (ret) - goto err_alarm_irq_request; + goto err_irq_request; mc13xxx_unlock(mc13xxx); priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &mc13xxx_rtc_ops, THIS_MODULE); - if (IS_ERR(priv->rtc)) { - ret = PTR_ERR(priv->rtc); - - mc13xxx_lock(mc13xxx); - - mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); -err_alarm_irq_request: + &mc13xxx_rtc_ops, THIS_MODULE); - mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv); -err_update_irq_request: - -err_reset_irq_status: - - mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); -err_reset_irq_request: + return 0; - mc13xxx_unlock(mc13xxx); +err_irq_request: + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv); + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); - platform_set_drvdata(pdev, NULL); - } + mc13xxx_unlock(mc13xxx); return ret; } -static int __exit mc13xxx_rtc_remove(struct platform_device *pdev) +static int mc13xxx_rtc_remove(struct platform_device *pdev) { struct mc13xxx_rtc *priv = platform_get_drvdata(pdev); @@ -389,8 +350,6 @@ static int __exit mc13xxx_rtc_remove(struct platform_device *pdev) mc13xxx_unlock(priv->mc13xxx); - platform_set_drvdata(pdev, NULL); - return 0; } @@ -408,7 +367,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable); static struct platform_driver mc13xxx_rtc_driver = { .id_table = mc13xxx_rtc_idtable, - .remove = __exit_p(mc13xxx_rtc_remove), + .remove = mc13xxx_rtc_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c new file mode 100644 index 00000000000..34295bf0041 --- /dev/null +++ b/drivers/rtc/rtc-mcp795.c @@ -0,0 +1,199 @@ +/* + * SPI Driver for Microchip MCP795 RTC + * + * Copyright (C) Josef Gajdusek <atx@atx.name> + * + * based on other Linux RTC drivers + * + * Device datasheet: + * http://ww1.microchip.com/downloads/en/DeviceDoc/22280A.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/printk.h> +#include <linux/spi/spi.h> +#include <linux/rtc.h> + +/* MCP795 Instructions, see datasheet table 3-1 */ +#define MCP795_EEREAD 0x03 +#define MCP795_EEWRITE 0x02 +#define MCP795_EEWRDI 0x04 +#define MCP795_EEWREN 0x06 +#define MCP795_SRREAD 0x05 +#define MCP795_SRWRITE 0x01 +#define MCP795_READ 0x13 +#define MCP795_WRITE 0x12 +#define MCP795_UNLOCK 0x14 +#define MCP795_IDWRITE 0x32 +#define MCP795_IDREAD 0x33 +#define MCP795_CLRWDT 0x44 +#define MCP795_CLRRAM 0x54 + +#define MCP795_ST_BIT 0x80 +#define MCP795_24_BIT 0x40 + +static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count) +{ + struct spi_device *spi = to_spi_device(dev); + int ret; + u8 tx[2]; + + tx[0] = MCP795_READ; + tx[1] = addr; + ret = spi_write_then_read(spi, tx, sizeof(tx), buf, count); + + if (ret) + dev_err(dev, "Failed reading %d bytes from address %x.\n", + count, addr); + + return ret; +} + +static int mcp795_rtcc_write(struct device *dev, u8 addr, u8 *data, u8 count) +{ + struct spi_device *spi = to_spi_device(dev); + int ret; + u8 tx[2 + count]; + + tx[0] = MCP795_WRITE; + tx[1] = addr; + memcpy(&tx[2], data, count); + + ret = spi_write(spi, tx, 2 + count); + + if (ret) + dev_err(dev, "Failed to write %d bytes to address %x.\n", + count, addr); + + return ret; +} + +static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state) +{ + int ret; + u8 tmp; + + ret = mcp795_rtcc_read(dev, addr, &tmp, 1); + if (ret) + return ret; + + if ((tmp & mask) != state) { + tmp = (tmp & ~mask) | state; + ret = mcp795_rtcc_write(dev, addr, &tmp, 1); + } + + return ret; +} + +static int mcp795_set_time(struct device *dev, struct rtc_time *tim) +{ + int ret; + u8 data[7]; + + /* Read first, so we can leave config bits untouched */ + ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + + if (ret) + return ret; + + data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10); + data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10); + data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10); + data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10); + data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10); + + if (tim->tm_year > 100) + tim->tm_year -= 100; + + data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10); + + ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data)); + + if (ret) + return ret; + + dev_dbg(dev, "Set mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", + tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, + tim->tm_hour, tim->tm_min, tim->tm_sec); + + return 0; +} + +static int mcp795_read_time(struct device *dev, struct rtc_time *tim) +{ + int ret; + u8 data[7]; + + ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + + if (ret) + return ret; + + tim->tm_sec = ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f); + tim->tm_min = ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f); + tim->tm_hour = ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f); + tim->tm_mday = ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f); + tim->tm_mon = ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f); + tim->tm_year = ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */ + + dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", + tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, + tim->tm_hour, tim->tm_min, tim->tm_sec); + + return rtc_valid_tm(tim); +} + +static struct rtc_class_ops mcp795_rtc_ops = { + .read_time = mcp795_read_time, + .set_time = mcp795_set_time +}; + +static int mcp795_probe(struct spi_device *spi) +{ + struct rtc_device *rtc; + int ret; + + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + ret = spi_setup(spi); + if (ret) { + dev_err(&spi->dev, "Unable to setup SPI\n"); + return ret; + } + + /* Start the oscillator */ + mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT); + /* Clear the 12 hour mode flag*/ + mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0); + + rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795", + &mcp795_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + spi_set_drvdata(spi, rtc); + + return 0; +} + +static struct spi_driver mcp795_driver = { + .driver = { + .name = "rtc-mcp795", + .owner = THIS_MODULE, + }, + .probe = mcp795_probe, +}; + +module_spi_driver(mcp795_driver); + +MODULE_DESCRIPTION("MCP795 RTC SPI Driver"); +MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:mcp795"); diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c new file mode 100644 index 00000000000..c3184623887 --- /dev/null +++ b/drivers/rtc/rtc-moxart.c @@ -0,0 +1,328 @@ +/* + * MOXA ART RTC driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen <jonas.jensen@gmail.com> + * + * Based on code from + * Moxa Technology Co., Ltd. <www.moxa.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> + +#define GPIO_RTC_RESERVED 0x0C +#define GPIO_RTC_DATA_SET 0x10 +#define GPIO_RTC_DATA_CLEAR 0x14 +#define GPIO_RTC_PIN_PULL_ENABLE 0x18 +#define GPIO_RTC_PIN_PULL_TYPE 0x1C +#define GPIO_RTC_INT_ENABLE 0x20 +#define GPIO_RTC_INT_RAW_STATE 0x24 +#define GPIO_RTC_INT_MASKED_STATE 0x28 +#define GPIO_RTC_INT_MASK 0x2C +#define GPIO_RTC_INT_CLEAR 0x30 +#define GPIO_RTC_INT_TRIGGER 0x34 +#define GPIO_RTC_INT_BOTH 0x38 +#define GPIO_RTC_INT_RISE_NEG 0x3C +#define GPIO_RTC_BOUNCE_ENABLE 0x40 +#define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 +#define GPIO_RTC_PROTECT_W 0x8E +#define GPIO_RTC_PROTECT_R 0x8F +#define GPIO_RTC_YEAR_W 0x8C +#define GPIO_RTC_YEAR_R 0x8D +#define GPIO_RTC_DAY_W 0x8A +#define GPIO_RTC_DAY_R 0x8B +#define GPIO_RTC_MONTH_W 0x88 +#define GPIO_RTC_MONTH_R 0x89 +#define GPIO_RTC_DATE_W 0x86 +#define GPIO_RTC_DATE_R 0x87 +#define GPIO_RTC_HOURS_W 0x84 +#define GPIO_RTC_HOURS_R 0x85 +#define GPIO_RTC_MINUTES_W 0x82 +#define GPIO_RTC_MINUTES_R 0x83 +#define GPIO_RTC_SECONDS_W 0x80 +#define GPIO_RTC_SECONDS_R 0x81 +#define GPIO_RTC_DELAY_TIME 8 + +struct moxart_rtc { + struct rtc_device *rtc; + spinlock_t rtc_lock; + int gpio_data, gpio_sclk, gpio_reset; +}; + +static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + +static void moxart_rtc_write_byte(struct device *dev, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < 8; i++, data >>= 1) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + } +} + +static u8 moxart_rtc_read_byte(struct device *dev) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + u8 data = 0; + + for (i = 0; i < 8; i++) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + if (gpio_get_value(moxart_rtc->gpio_data)) + data |= (1 << i); + udelay(GPIO_RTC_DELAY_TIME); + } + return data; +} + +static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + u8 data; + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + gpio_direction_input(moxart_rtc->gpio_data); + udelay(GPIO_RTC_DELAY_TIME); + data = moxart_rtc_read_byte(dev); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); + + return data; +} + +static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + moxart_rtc_write_byte(dev, data); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); +} + +static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&moxart_rtc->rtc_lock); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0); + moxart_rtc_write_register(dev, GPIO_RTC_YEAR_W, + (((tm->tm_year - 100) / 10) << 4) | + ((tm->tm_year - 100) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MONTH_W, + (((tm->tm_mon + 1) / 10) << 4) | + ((tm->tm_mon + 1) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_DATE_W, + ((tm->tm_mday / 10) << 4) | + (tm->tm_mday % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_HOURS_W, + ((tm->tm_hour / 10) << 4) | + (tm->tm_hour % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MINUTES_W, + ((tm->tm_min / 10) << 4) | + (tm->tm_min % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_SECONDS_W, + ((tm->tm_sec / 10) << 4) | + (tm->tm_sec % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" + "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned char v; + + spin_lock_irq(&moxart_rtc->rtc_lock); + + v = moxart_rtc_read_register(dev, GPIO_RTC_SECONDS_R); + tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MINUTES_R); + tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_HOURS_R); + if (v & 0x80) { /* 12-hour mode */ + tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if (v & 0x20) { /* PM mode */ + tm->tm_hour += 12; + if (tm->tm_hour >= 24) + tm->tm_hour = 0; + } + } else { /* 24-hour mode */ + tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + + v = moxart_rtc_read_register(dev, GPIO_RTC_DATE_R); + tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MONTH_R); + tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + tm->tm_mon--; + + v = moxart_rtc_read_register(dev, GPIO_RTC_YEAR_R); + tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + tm->tm_year += 100; + if (tm->tm_year <= 69) + tm->tm_year += 100; + + v = moxart_rtc_read_register(dev, GPIO_RTC_DAY_R); + tm->tm_wday = (v & 0x0f) - 1; + tm->tm_yday = day_of_year[tm->tm_mon]; + tm->tm_yday += (tm->tm_mday - 1); + if (tm->tm_mon >= 2) { + if (!(tm->tm_year % 4) && (tm->tm_year % 100)) + tm->tm_yday++; + } + + tm->tm_isdst = 0; + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + return 0; +} + +static const struct rtc_class_ops moxart_rtc_ops = { + .read_time = moxart_rtc_read_time, + .set_time = moxart_rtc_set_time, +}; + +static int moxart_rtc_probe(struct platform_device *pdev) +{ + struct moxart_rtc *moxart_rtc; + int ret = 0; + + moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL); + if (!moxart_rtc) + return -ENOMEM; + + moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-data", 0); + if (!gpio_is_valid(moxart_rtc->gpio_data)) { + dev_err(&pdev->dev, "invalid gpio (data): %d\n", + moxart_rtc->gpio_data); + return moxart_rtc->gpio_data; + } + + moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-sclk", 0); + if (!gpio_is_valid(moxart_rtc->gpio_sclk)) { + dev_err(&pdev->dev, "invalid gpio (sclk): %d\n", + moxart_rtc->gpio_sclk); + return moxart_rtc->gpio_sclk; + } + + moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-reset", 0); + if (!gpio_is_valid(moxart_rtc->gpio_reset)) { + dev_err(&pdev->dev, "invalid gpio (reset): %d\n", + moxart_rtc->gpio_reset); + return moxart_rtc->gpio_reset; + } + + spin_lock_init(&moxart_rtc->rtc_lock); + platform_set_drvdata(pdev, moxart_rtc); + + ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_data gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk, + GPIOF_DIR_OUT, "rtc_sclk"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_sclk gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset, + GPIOF_DIR_OUT, "rtc_reset"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_reset gpio\n"); + return ret; + } + + moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &moxart_rtc_ops, + THIS_MODULE); + if (IS_ERR(moxart_rtc->rtc)) { + dev_err(&pdev->dev, "devm_rtc_device_register failed\n"); + return PTR_ERR(moxart_rtc->rtc); + } + + return 0; +} + +static const struct of_device_id moxart_rtc_match[] = { + { .compatible = "moxa,moxart-rtc" }, + { }, +}; + +static struct platform_driver moxart_rtc_driver = { + .probe = moxart_rtc_probe, + .driver = { + .name = "moxart-rtc", + .owner = THIS_MODULE, + .of_match_table = moxart_rtc_match, + }, +}; +module_platform_driver(moxart_rtc_driver); + +MODULE_DESCRIPTION("MOXART RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index bdcc60830ae..dc4f14255cc 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -14,7 +14,9 @@ #include <linux/module.h> #include <linux/rtc.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/io.h> #include <linux/slab.h> @@ -68,7 +70,7 @@ struct mpc5121_rtc_regs { u32 target_time; /* RTC + 0x20 */ /* * actual_time: - * readonly time since VBAT_RTC was last connected + * readonly time since VBAT_RTC was last connected */ u32 actual_time; /* RTC + 0x24 */ u32 keep_alive; /* RTC + 0x28 */ @@ -312,20 +314,19 @@ static int mpc5121_rtc_probe(struct platform_device *op) struct mpc5121_rtc_data *rtc; int err = 0; - rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + rtc = devm_kzalloc(&op->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; rtc->regs = of_iomap(op->dev.of_node, 0); if (!rtc->regs) { dev_err(&op->dev, "%s: couldn't map io space\n", __func__); - err = -ENOSYS; - goto out_free; + return -ENOSYS; } device_init_wakeup(&op->dev, 1); - dev_set_drvdata(&op->dev, rtc); + platform_set_drvdata(op, rtc); rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1); err = request_irq(rtc->irq, mpc5121_rtc_handler, 0, @@ -354,10 +355,10 @@ static int mpc5121_rtc_probe(struct platform_device *op) out_be32(&rtc->regs->keep_alive, ka); } - rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev, + rtc->rtc = devm_rtc_device_register(&op->dev, "mpc5121-rtc", &mpc5121_rtc_ops, THIS_MODULE); } else { - rtc->rtc = rtc_device_register("mpc5200-rtc", &op->dev, + rtc->rtc = devm_rtc_device_register(&op->dev, "mpc5200-rtc", &mpc5200_rtc_ops, THIS_MODULE); } @@ -377,29 +378,24 @@ out_dispose2: out_dispose: irq_dispose_mapping(rtc->irq); iounmap(rtc->regs); -out_free: - kfree(rtc); return err; } static int mpc5121_rtc_remove(struct platform_device *op) { - struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev); + struct mpc5121_rtc_data *rtc = platform_get_drvdata(op); struct mpc5121_rtc_regs __iomem *regs = rtc->regs; /* disable interrupt, so there are no nasty surprises */ out_8(®s->alm_enable, 0); out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1); - rtc_device_unregister(rtc->rtc); iounmap(rtc->regs); free_irq(rtc->irq, &op->dev); free_irq(rtc->irq_periodic, &op->dev); irq_dispose_mapping(rtc->irq); irq_dispose_mapping(rtc->irq_periodic); - dev_set_drvdata(&op->dev, NULL); - kfree(rtc); return 0; } diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index 578baf9d972..e2436d14017 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -38,8 +38,8 @@ #include <asm-generic/rtc.h> #include <asm/intel_scu_ipc.h> -#include <asm/mrst.h> -#include <asm/mrst-vrtc.h> +#include <asm/intel-mid.h> +#include <asm/intel_mid_vrtc.h> struct mrst_rtc { struct rtc_device *rtc; @@ -380,7 +380,6 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, cleanup1: rtc_device_unregister(mrst_rtc.rtc); cleanup0: - dev_set_drvdata(dev, NULL); mrst_rtc.dev = NULL; release_mem_region(iomem->start, resource_size(iomem)); dev_err(dev, "rtc-mrst: unable to initialise\n"); @@ -412,7 +411,6 @@ static void rtc_mrst_do_remove(struct device *dev) mrst->iomem = NULL; mrst->dev = NULL; - dev_set_drvdata(dev, NULL); } #ifdef CONFIG_PM diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index 771f86a05d1..426cb5189da 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -111,8 +111,8 @@ static void msm6242_lock(struct msm6242_priv *priv) } if (!cnt) - pr_warning("msm6242: timed out waiting for RTC (0x%x)\n", - msm6242_read(priv, MSM6242_CD)); + pr_warn("msm6242: timed out waiting for RTC (0x%x)\n", + msm6242_read(priv, MSM6242_CD)); } static void msm6242_unlock(struct msm6242_priv *priv) @@ -199,7 +199,6 @@ static int __init msm6242_rtc_probe(struct platform_device *pdev) struct resource *res; struct msm6242_priv *priv; struct rtc_device *rtc; - int error; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -216,22 +215,11 @@ static int __init msm6242_rtc_probe(struct platform_device *pdev) rtc = devm_rtc_device_register(&pdev->dev, "rtc-msm6242", &msm6242_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - error = PTR_ERR(rtc); - goto out_unmap; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); priv->rtc = rtc; return 0; - -out_unmap: - platform_set_drvdata(pdev, NULL); - return error; -} - -static int __exit msm6242_rtc_remove(struct platform_device *pdev) -{ - return 0; } static struct platform_driver msm6242_rtc_driver = { @@ -239,7 +227,6 @@ static struct platform_driver msm6242_rtc_driver = { .name = "rtc-msm6242", .owner = THIS_MODULE, }, - .remove = __exit_p(msm6242_rtc_remove), }; module_platform_driver_probe(msm6242_rtc_driver, msm6242_rtc_probe); diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index baab802f215..6aaec2fc7c0 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -221,26 +221,18 @@ static int __init mv_rtc_probe(struct platform_device *pdev) { struct resource *res; struct rtc_plat_data *pdata; - resource_size_t size; u32 rtc_time; + u32 rtc_date; int ret = 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - size = resource_size(res); - if (!devm_request_mem_region(&pdev->dev, res->start, size, - pdev->name)) - return -EBUSY; - - pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, size); - if (!pdata->ioaddr) - return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->ioaddr)) + return PTR_ERR(pdata->ioaddr); pdata->clk = devm_clk_get(&pdev->dev, NULL); /* Not all SoCs require a clock.*/ @@ -266,6 +258,17 @@ static int __init mv_rtc_probe(struct platform_device *pdev) } } + /* + * A date after January 19th, 2038 does not fit on 32 bits and + * will confuse the kernel and userspace. Reset to a sane date + * (January 1st, 2013) if we're after 2038. + */ + rtc_date = readl(pdata->ioaddr + RTC_DATE_REG_OFFS); + if (bcd2bin((rtc_date >> RTC_YEAR_OFFS) & 0xff) >= 38) { + dev_info(&pdev->dev, "invalid RTC date, resetting to January 1st, 2013\n"); + writel(0x130101, pdata->ioaddr + RTC_DATE_REG_OFFS); + } + pdata->irq = platform_get_irq(pdev, 0); platform_set_drvdata(pdev, pdata); @@ -316,7 +319,7 @@ static int __exit mv_rtc_remove(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id rtc_mv_of_match_table[] = { +static const struct of_device_id rtc_mv_of_match_table[] = { { .compatible = "marvell,orion-rtc", }, {} }; diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 9a3895bc4f4..419874fefa4 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -377,31 +377,27 @@ static int mxc_rtc_probe(struct platform_device *pdev) unsigned long rate; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; pdata->devtype = pdev->id_entry->driver_data; - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) - return -EBUSY; - - pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->ioaddr)) + return PTR_ERR(pdata->ioaddr); pdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pdata->clk)) { dev_err(&pdev->dev, "unable to get clock!\n"); - ret = PTR_ERR(pdata->clk); - goto exit_free_pdata; + return PTR_ERR(pdata->clk); } - clk_prepare_enable(pdata->clk); + ret = clk_prepare_enable(pdata->clk); + if (ret) + return ret; + rate = clk_get_rate(pdata->clk); if (rate == 32768) @@ -436,27 +432,23 @@ static int mxc_rtc_probe(struct platform_device *pdev) pdata->irq = -1; } - if (pdata->irq >=0) + if (pdata->irq >= 0) device_init_wakeup(&pdev->dev, 1); rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { ret = PTR_ERR(rtc); - goto exit_clr_drvdata; + goto exit_put_clk; } pdata->rtc = rtc; return 0; -exit_clr_drvdata: - platform_set_drvdata(pdev, NULL); exit_put_clk: clk_disable_unprepare(pdata->clk); -exit_free_pdata: - return ret; } @@ -465,7 +457,6 @@ static int mxc_rtc_remove(struct platform_device *pdev) struct rtc_plat_data *pdata = platform_get_drvdata(pdev); clk_disable_unprepare(pdata->clk); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index d592e2fe43f..a53da0958e9 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -99,7 +99,7 @@ static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) if (!timeout) return ERR_PTR(-EPERM); - return 0; + return NULL; } static int nuc900_rtc_bcd2bin(unsigned int timereg, @@ -229,10 +229,9 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev) nuc900_rtc = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_rtc), GFP_KERNEL); - if (!nuc900_rtc) { - dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n"); + if (!nuc900_rtc) return -ENOMEM; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(nuc900_rtc->rtc_reg)) @@ -260,15 +259,7 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit nuc900_rtc_remove(struct platform_device *pdev) -{ - platform_set_drvdata(pdev, NULL); - - return 0; -} - static struct platform_driver nuc900_rtc_driver = { - .remove = __exit_p(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 b0ba3fc991e..21142e6574a 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -23,9 +23,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> - -#include <asm/io.h> - +#include <linux/io.h> /* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock * with century-range alarm matching, driven by the 32kHz clock. @@ -72,35 +70,55 @@ #define OMAP_RTC_KICK0_REG 0x6c #define OMAP_RTC_KICK1_REG 0x70 +#define OMAP_RTC_IRQWAKEEN 0x7c + /* OMAP_RTC_CTRL_REG bit fields: */ -#define OMAP_RTC_CTRL_SPLIT (1<<7) -#define OMAP_RTC_CTRL_DISABLE (1<<6) -#define OMAP_RTC_CTRL_SET_32_COUNTER (1<<5) -#define OMAP_RTC_CTRL_TEST (1<<4) -#define OMAP_RTC_CTRL_MODE_12_24 (1<<3) -#define OMAP_RTC_CTRL_AUTO_COMP (1<<2) -#define OMAP_RTC_CTRL_ROUND_30S (1<<1) -#define OMAP_RTC_CTRL_STOP (1<<0) +#define OMAP_RTC_CTRL_SPLIT BIT(7) +#define OMAP_RTC_CTRL_DISABLE BIT(6) +#define OMAP_RTC_CTRL_SET_32_COUNTER BIT(5) +#define OMAP_RTC_CTRL_TEST BIT(4) +#define OMAP_RTC_CTRL_MODE_12_24 BIT(3) +#define OMAP_RTC_CTRL_AUTO_COMP BIT(2) +#define OMAP_RTC_CTRL_ROUND_30S BIT(1) +#define OMAP_RTC_CTRL_STOP BIT(0) /* OMAP_RTC_STATUS_REG bit fields: */ -#define OMAP_RTC_STATUS_POWER_UP (1<<7) -#define OMAP_RTC_STATUS_ALARM (1<<6) -#define OMAP_RTC_STATUS_1D_EVENT (1<<5) -#define OMAP_RTC_STATUS_1H_EVENT (1<<4) -#define OMAP_RTC_STATUS_1M_EVENT (1<<3) -#define OMAP_RTC_STATUS_1S_EVENT (1<<2) -#define OMAP_RTC_STATUS_RUN (1<<1) -#define OMAP_RTC_STATUS_BUSY (1<<0) +#define OMAP_RTC_STATUS_POWER_UP BIT(7) +#define OMAP_RTC_STATUS_ALARM BIT(6) +#define OMAP_RTC_STATUS_1D_EVENT BIT(5) +#define OMAP_RTC_STATUS_1H_EVENT BIT(4) +#define OMAP_RTC_STATUS_1M_EVENT BIT(3) +#define OMAP_RTC_STATUS_1S_EVENT BIT(2) +#define OMAP_RTC_STATUS_RUN BIT(1) +#define OMAP_RTC_STATUS_BUSY BIT(0) /* OMAP_RTC_INTERRUPTS_REG bit fields: */ -#define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) -#define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) +#define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3) +#define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2) + +/* OMAP_RTC_OSC_REG bit fields: */ +#define OMAP_RTC_OSC_32KCLK_EN BIT(6) + +/* OMAP_RTC_IRQWAKEEN bit fields: */ +#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1) /* OMAP_RTC_KICKER values */ #define KICK0_VALUE 0x83e70b13 #define KICK1_VALUE 0x95a4f1e0 -#define OMAP_RTC_HAS_KICKER 0x1 +#define OMAP_RTC_HAS_KICKER BIT(0) + +/* + * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup + * generation for event Alarm. + */ +#define OMAP_RTC_HAS_IRQWAKEEN BIT(1) + +/* + * Some RTC IP revisions (like those in AM335x and DRA7x) need + * the 32KHz clock to be explicitly enabled. + */ +#define OMAP_RTC_HAS_32KCLK_EN BIT(2) static void __iomem *rtc_base; @@ -153,17 +171,28 @@ static irqreturn_t rtc_irq(int irq, void *rtc) static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - u8 reg; + u8 reg, irqwake_reg = 0; + struct platform_device *pdev = to_platform_device(dev); + const struct platform_device_id *id_entry = + platform_get_device_id(pdev); local_irq_disable(); rtc_wait_not_busy(); reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); - if (enabled) + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) + irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + + if (enabled) { reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; - else + irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; + } else { reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; + irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; + } rtc_wait_not_busy(); rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) + rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN); local_irq_enable(); return 0; @@ -263,7 +292,10 @@ static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { - u8 reg; + u8 reg, irqwake_reg = 0; + struct platform_device *pdev = to_platform_device(dev); + const struct platform_device_id *id_entry = + platform_get_device_id(pdev); if (tm2bcd(&alm->time) < 0) return -EINVAL; @@ -279,11 +311,19 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG); reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); - if (alm->enabled) + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) + irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + + if (alm->enabled) { reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; - else + irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; + } else { reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; + irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; + } rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) + rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN); local_irq_enable(); @@ -301,12 +341,19 @@ 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 +#define OMAP_RTC_DATA_AM3352_IDX 1 +#define OMAP_RTC_DATA_DA830_IDX 2 static struct platform_device_id omap_rtc_devtype[] = { { .name = DRIVER_NAME, - }, { + }, + [OMAP_RTC_DATA_AM3352_IDX] = { + .name = "am3352-rtc", + .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN | + OMAP_RTC_HAS_32KCLK_EN, + }, + [OMAP_RTC_DATA_DA830_IDX] = { .name = "da830-rtc", .driver_data = OMAP_RTC_HAS_KICKER, }, @@ -318,6 +365,9 @@ static const struct of_device_id omap_rtc_of_match[] = { { .compatible = "ti,da830-rtc", .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], }, + { .compatible = "ti,am3352-rtc", + .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX], + }, {}, }; MODULE_DEVICE_TABLE(of, omap_rtc_of_match); @@ -334,6 +384,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev) if (of_id) pdev->id_entry = of_id->data; + id_entry = platform_get_device_id(pdev); + if (!id_entry) { + dev_err(&pdev->dev, "no matching device entry\n"); + return -ENODEV; + } + omap_rtc_timer = platform_get_irq(pdev, 0); if (omap_rtc_timer <= 0) { pr_debug("%s: no update irq?\n", pdev->name); @@ -355,8 +411,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) 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)) { + if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) { rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG); rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG); } @@ -375,6 +430,10 @@ static int __init omap_rtc_probe(struct platform_device *pdev) */ rtc_write(0, OMAP_RTC_INTERRUPTS_REG); + /* enable RTC functional clock */ + if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN) + rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG); + /* clear old status */ reg = rtc_read(OMAP_RTC_STATUS_REG); if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) { @@ -423,6 +482,8 @@ static int __init omap_rtc_probe(struct platform_device *pdev) * is write-only, and always reads as zero...) */ + device_init_wakeup(&pdev->dev, true); + if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT) pr_info("%s: split power mode\n", pdev->name); @@ -432,7 +493,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) return 0; fail0: - if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) + if (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); @@ -449,7 +510,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) /* leave rtc running, but disable irqs */ rtc_write(0, OMAP_RTC_INTERRUPTS_REG); - if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) + if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) rtc_writel(0, OMAP_RTC_KICK0_REG); /* Disable the clock/module */ @@ -467,8 +528,8 @@ static int omap_rtc_suspend(struct device *dev) irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); /* FIXME the RTC alarm is not currently acting as a wakeup event - * source, and in fact this enable() call is just saving a flag - * that's never used... + * source on some platforms, and in fact this enable() call is just + * saving a flag that's never used... */ if (device_may_wakeup(dev)) enable_irq_wake(omap_rtc_alarm); @@ -490,6 +551,7 @@ static int omap_rtc_resume(struct device *dev) disable_irq_wake(omap_rtc_alarm); else rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); + return 0; } #endif @@ -509,7 +571,7 @@ static struct platform_driver omap_rtc_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &omap_rtc_pm_ops, - .of_match_table = of_match_ptr(omap_rtc_of_match), + .of_match_table = omap_rtc_of_match, }, .id_table = omap_rtc_devtype, }; diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index 50204d474eb..4dfe2d793fa 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -238,6 +238,15 @@ 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; + bool enable_bb_charging = false; + bool high_bb_charging; + + if (pdev->dev.of_node) { + enable_bb_charging = of_property_read_bool(pdev->dev.of_node, + "ti,backup-battery-chargeable"); + high_bb_charging = of_property_read_bool(pdev->dev.of_node, + "ti,backup-battery-charge-high-current"); + } palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc), GFP_KERNEL); @@ -254,6 +263,32 @@ static int palmas_rtc_probe(struct platform_device *pdev) palmas_rtc->dev = &pdev->dev; platform_set_drvdata(pdev, palmas_rtc); + if (enable_bb_charging) { + unsigned reg = PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG; + + if (high_bb_charging) + reg = 0; + + ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, + PALMAS_BACKUP_BATTERY_CTRL, + PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG, reg); + if (ret < 0) { + dev_err(&pdev->dev, + "BACKUP_BATTERY_CTRL update failed, %d\n", ret); + return ret; + } + + ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, + PALMAS_BACKUP_BATTERY_CTRL, + PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN, + PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN); + if (ret < 0) { + dev_err(&pdev->dev, + "BACKUP_BATTERY_CTRL update failed, %d\n", ret); + return ret; + } + } + /* Start RTC */ ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG, PALMAS_RTC_CTRL_REG_STOP_RTC, @@ -265,6 +300,7 @@ static int palmas_rtc_probe(struct platform_device *pdev) palmas_rtc->irq = platform_get_irq(pdev, 0); + device_init_wakeup(&pdev->dev, 1); palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &palmas_rtc_ops, THIS_MODULE); if (IS_ERR(palmas_rtc->rtc)) { @@ -283,7 +319,6 @@ static int palmas_rtc_probe(struct platform_device *pdev) return ret; } - device_set_wakeup_capable(&pdev->dev, 1); return 0; } @@ -313,12 +348,11 @@ static int palmas_rtc_resume(struct device *dev) } #endif -static const struct dev_pm_ops palmas_rtc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume) -}; +static SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend, + palmas_rtc_resume); #ifdef CONFIG_OF -static struct of_device_id of_palmas_rtc_match[] = { +static const struct of_device_id of_palmas_rtc_match[] = { { .compatible = "ti,palmas-rtc"}, { }, }; diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index 539a90b98bc..40b5c630bc7 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -156,10 +156,8 @@ static int __init pcap_rtc_probe(struct platform_device *pdev) pcap_rtc->rtc = devm_rtc_device_register(&pdev->dev, "pcap", &pcap_rtc_ops, THIS_MODULE); - if (IS_ERR(pcap_rtc->rtc)) { - err = PTR_ERR(pcap_rtc->rtc); - goto fail; - } + if (IS_ERR(pcap_rtc->rtc)) + return PTR_ERR(pcap_rtc->rtc); timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); @@ -167,17 +165,14 @@ static int __init pcap_rtc_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, timer_irq, pcap_rtc_irq, 0, "RTC Timer", pcap_rtc); if (err) - goto fail; + return err; err = devm_request_irq(&pdev->dev, alarm_irq, pcap_rtc_irq, 0, "RTC Alarm", pcap_rtc); if (err) - goto fail; + return err; return 0; -fail: - platform_set_drvdata(pdev, NULL); - return err; } static int __exit pcap_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 796a6c5067d..d1953bb244c 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -18,11 +18,11 @@ * should look something like: * * static struct spi_board_info ek_spi_devices[] = { - * ... - * { - * .modalias = "rtc-pcf2123", - * .chip_select = 1, - * .controller_data = (void *)AT91_PIN_PA10, + * ... + * { + * .modalias = "rtc-pcf2123", + * .chip_select = 1, + * .controller_data = (void *)AT91_PIN_PA10, * .max_speed_hz = 1000 * 1000, * .mode = SPI_CS_HIGH, * .bus_num = 0, @@ -94,8 +94,9 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, r = container_of(attr, struct pcf2123_sysfs_reg, attr); - if (strict_strtoul(r->name, 16, ®)) - return -EINVAL; + ret = kstrtoul(r->name, 16, ®); + if (ret) + return ret; txbuf[0] = PCF2123_READ | reg; ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1); @@ -117,9 +118,13 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, r = container_of(attr, struct pcf2123_sysfs_reg, attr); - if (strict_strtoul(r->name, 16, ®) - || strict_strtoul(buffer, 10, &val)) - return -EINVAL; + ret = kstrtoul(r->name, 16, ®); + if (ret) + return ret; + + ret = kstrtoul(buffer, 10, &val); + if (ret) + return ret; txbuf[0] = PCF2123_WRITE | reg; txbuf[1] = val; @@ -322,7 +327,7 @@ kfree_exit: static int pcf2123_remove(struct spi_device *spi) { - struct pcf2123_plat_data *pdata = spi->dev.platform_data; + struct pcf2123_plat_data *pdata = dev_get_platdata(&spi->dev); int i; if (pdata) { diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c new file mode 100644 index 00000000000..9bd842e9774 --- /dev/null +++ b/drivers/rtc/rtc-pcf2127.c @@ -0,0 +1,232 @@ +/* + * An I2C driver for the NXP PCF2127 RTC + * Copyright 2013 Til-Technologies + * + * Author: Renaud Cerrato <r.cerrato@til-technologies.fr> + * + * based on the other drivers in this same directory. + * + * http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/rtc.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/of.h> + +#define DRV_VERSION "0.0.1" + +#define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */ +#define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */ +#define PCF2127_REG_CTRL3 (0x02) /* Control Register 3 */ +#define PCF2127_REG_SC (0x03) /* datetime */ +#define PCF2127_REG_MN (0x04) +#define PCF2127_REG_HR (0x05) +#define PCF2127_REG_DM (0x06) +#define PCF2127_REG_DW (0x07) +#define PCF2127_REG_MO (0x08) +#define PCF2127_REG_YR (0x09) + +static struct i2c_driver pcf2127_driver; + +struct pcf2127 { + struct rtc_device *rtc; + int voltage_low; /* indicates if a low_voltage was detected */ +}; + +/* + * In the routines that deal directly with the pcf2127 hardware, we use + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. + */ +static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + struct pcf2127 *pcf2127 = i2c_get_clientdata(client); + unsigned char buf[10] = { PCF2127_REG_CTRL1 }; + + /* read registers */ + if (i2c_master_send(client, buf, 1) != 1 || + i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) { + dev_err(&client->dev, "%s: read error\n", __func__); + return -EIO; + } + + if (buf[PCF2127_REG_CTRL3] & 0x04) { + pcf2127->voltage_low = 1; + dev_info(&client->dev, + "low voltage detected, date/time is not reliable.\n"); + } + + dev_dbg(&client->dev, + "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, " + "sec=%02x, min=%02x, hr=%02x, " + "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", + __func__, + buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], + buf[6], buf[7], buf[8], buf[9]); + + + tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); + tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); + tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */ + tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F); + tm->tm_wday = buf[PCF2127_REG_DW] & 0x07; + tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]); + if (tm->tm_year < 70) + tm->tm_year += 100; /* assume we are in 1970...2069 */ + + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + /* the clock can give out invalid datetime, but we cannot return + * -EINVAL otherwise hwclock will refuse to set the time on bootup. + */ + if (rtc_valid_tm(tm) < 0) + dev_err(&client->dev, "retrieved date/time is not valid.\n"); + + return 0; +} + +static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + unsigned char buf[8]; + int i = 0, err; + + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + + /* start register address */ + buf[i++] = PCF2127_REG_SC; + + /* hours, minutes and seconds */ + buf[i++] = bin2bcd(tm->tm_sec); + buf[i++] = bin2bcd(tm->tm_min); + buf[i++] = bin2bcd(tm->tm_hour); + buf[i++] = bin2bcd(tm->tm_mday); + buf[i++] = tm->tm_wday & 0x07; + + /* month, 1 - 12 */ + buf[i++] = bin2bcd(tm->tm_mon + 1); + + /* year */ + buf[i++] = bin2bcd(tm->tm_year % 100); + + /* write register's data */ + err = i2c_master_send(client, buf, i); + if (err != i) { + dev_err(&client->dev, + "%s: err=%d", __func__, err); + return -EIO; + } + + return 0; +} + +#ifdef CONFIG_RTC_INTF_DEV +static int pcf2127_rtc_ioctl(struct device *dev, + unsigned int cmd, unsigned long arg) +{ + struct pcf2127 *pcf2127 = i2c_get_clientdata(to_i2c_client(dev)); + + switch (cmd) { + case RTC_VL_READ: + if (pcf2127->voltage_low) + dev_info(dev, "low voltage detected, date/time is not reliable.\n"); + + if (copy_to_user((void __user *)arg, &pcf2127->voltage_low, + sizeof(int))) + return -EFAULT; + return 0; + default: + return -ENOIOCTLCMD; + } +} +#else +#define pcf2127_rtc_ioctl NULL +#endif + +static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + return pcf2127_get_datetime(to_i2c_client(dev), tm); +} + +static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + return pcf2127_set_datetime(to_i2c_client(dev), tm); +} + +static const struct rtc_class_ops pcf2127_rtc_ops = { + .ioctl = pcf2127_rtc_ioctl, + .read_time = pcf2127_rtc_read_time, + .set_time = pcf2127_rtc_set_time, +}; + +static int pcf2127_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pcf2127 *pcf2127; + + dev_dbg(&client->dev, "%s\n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127), + GFP_KERNEL); + if (!pcf2127) + return -ENOMEM; + + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + + i2c_set_clientdata(client, pcf2127); + + pcf2127->rtc = devm_rtc_device_register(&client->dev, + pcf2127_driver.driver.name, + &pcf2127_rtc_ops, THIS_MODULE); + + return PTR_ERR_OR_ZERO(pcf2127->rtc); +} + +static const struct i2c_device_id pcf2127_id[] = { + { "pcf2127", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf2127_id); + +#ifdef CONFIG_OF +static const struct of_device_id pcf2127_of_match[] = { + { .compatible = "nxp,pcf2127" }, + {} +}; +MODULE_DEVICE_TABLE(of, pcf2127_of_match); +#endif + +static struct i2c_driver pcf2127_driver = { + .driver = { + .name = "rtc-pcf2127", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pcf2127_of_match), + }, + .probe = pcf2127_probe, + .id_table = pcf2127_id, +}; + +module_i2c_driver(pcf2127_driver); + +MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>"); +MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 305c9515e5b..4cdb64be061 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -206,7 +206,7 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) 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_mon = bcd2bin(regs[5] & 0x1f) - 1; tm->tm_year = bcd2bin(regs[6]) + 100; return rtc_valid_tm(tm); @@ -229,7 +229,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) regs[3] = bin2bcd(tm->tm_hour); regs[4] = bin2bcd(tm->tm_mday); regs[5] = tm->tm_wday; - regs[6] = bin2bcd(tm->tm_mon); + regs[6] = bin2bcd(tm->tm_mon + 1); regs[7] = bin2bcd(tm->tm_year - 100); msg.addr = client->addr; @@ -317,11 +317,6 @@ static int pcf8523_probe(struct i2c_client *client, return 0; } -static int pcf8523_remove(struct i2c_client *client) -{ - return 0; -} - static const struct i2c_device_id pcf8523_id[] = { { "pcf8523", 0 }, { } @@ -343,7 +338,6 @@ static struct i2c_driver pcf8523_driver = { .of_match_table = of_match_ptr(pcf8523_of_match), }, .probe = pcf8523_probe, - .remove = pcf8523_remove, .id_table = pcf8523_id, }; module_i2c_driver(pcf8523_driver); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 97b354a26a4..63b558c4819 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/err.h> #define DRV_VERSION "0.4.3" @@ -263,15 +264,7 @@ static int pcf8563_probe(struct i2c_client *client, pcf8563_driver.driver.name, &pcf8563_rtc_ops, THIS_MODULE); - if (IS_ERR(pcf8563->rtc)) - return PTR_ERR(pcf8563->rtc); - - return 0; -} - -static int pcf8563_remove(struct i2c_client *client) -{ - return 0; + return PTR_ERR_OR_ZERO(pcf8563->rtc); } static const struct i2c_device_id pcf8563_id[] = { @@ -296,7 +289,6 @@ static struct i2c_driver pcf8563_driver = { .of_match_table = of_match_ptr(pcf8563_of_match), }, .probe = pcf8563_probe, - .remove = pcf8563_remove, .id_table = pcf8563_id, }; diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 95886dcf4a3..c2639845186 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/rtc.h> #include <linux/init.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/bcd.h> @@ -188,7 +189,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_warn(dev, "resetting control %02x -> %02x\n", ctrl, new_ctrl); - if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0) + err = pcf8583_set_ctrl(client, &new_ctrl); + if (err < 0) return err; } @@ -283,15 +285,7 @@ static int pcf8583_probe(struct i2c_client *client, pcf8583_driver.driver.name, &pcf8583_rtc_ops, THIS_MODULE); - if (IS_ERR(pcf8583->rtc)) - return PTR_ERR(pcf8583->rtc); - - return 0; -} - -static int pcf8583_remove(struct i2c_client *client) -{ - return 0; + return PTR_ERR_OR_ZERO(pcf8583->rtc); } static const struct i2c_device_id pcf8583_id[] = { @@ -306,7 +300,6 @@ static struct i2c_driver pcf8583_driver = { .owner = THIS_MODULE, }, .probe = pcf8583_probe, - .remove = pcf8583_remove, .id_table = pcf8583_id, }; diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index 22bacdbf913..f85a1a93e66 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -106,7 +106,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id) if (ret) goto err_req; - rtc = kmalloc(sizeof(*rtc), GFP_KERNEL); + rtc = devm_kzalloc(&dev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) { ret = -ENOMEM; goto err_rtc; @@ -115,7 +115,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id) rtc->base = ioremap(dev->res.start, resource_size(&dev->res)); if (!rtc->base) { ret = -ENOMEM; - goto err_map; + goto err_rtc; } __raw_writel(0, rtc->base + RTC_CR); @@ -141,8 +141,6 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id) free_irq(dev->irq[0], rtc); err_irq: iounmap(rtc->base); - err_map: - kfree(rtc); err_rtc: amba_release_regions(dev); err_req: @@ -153,14 +151,11 @@ static int pl030_remove(struct amba_device *dev) { struct pl030_rtc *rtc = amba_get_drvdata(dev); - amba_set_drvdata(dev, NULL); - writel(0, rtc->base + RTC_CR); free_irq(dev->irq[0], rtc); rtc_device_unregister(rtc->rtc); iounmap(rtc->base); - kfree(rtc); amba_release_regions(dev); return 0; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 0f0609b1aa2..99181fff88f 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -305,7 +305,6 @@ static int pl031_remove(struct amba_device *adev) { struct pl031_local *ldata = dev_get_drvdata(&adev->dev); - amba_set_drvdata(adev, NULL); free_irq(adev->irq[0], ldata); rtc_device_unregister(ldata->rtc); iounmap(ldata->base); @@ -371,6 +370,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) } } + device_init_wakeup(&adev->dev, 1); ldata->rtc = rtc_device_register("pl031", &adev->dev, ops, THIS_MODULE); if (IS_ERR(ldata->rtc)) { @@ -384,15 +384,12 @@ 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: rtc_device_unregister(ldata->rtc); out_no_rtc: iounmap(ldata->base); - amba_set_drvdata(adev, NULL); out_no_remap: kfree(ldata); out: diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index f1a6557261f..197699f358c 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -9,18 +9,16 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ - +#include <linux/of.h> #include <linux/module.h> #include <linux/init.h> #include <linux/rtc.h> +#include <linux/platform_device.h> #include <linux/pm.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/mfd/pm8xxx/core.h> -#include <linux/mfd/pm8xxx/rtc.h> - - /* RTC Register offsets from RTC CTRL REG */ #define PM8XXX_ALARM_CTRL_OFFSET 0x01 #define PM8XXX_RTC_WRITE_OFFSET 0x02 @@ -37,6 +35,8 @@ /** * struct pm8xxx_rtc - rtc driver internal structure * @rtc: rtc device for this driver. + * @regmap: regmap used to access RTC registers + * @allow_set_time: indicates whether writing to the RTC is allowed * @rtc_alarm_irq: rtc alarm irq number. * @rtc_base: address of rtc control register. * @rtc_read_base: base address of read registers. @@ -48,55 +48,19 @@ */ struct pm8xxx_rtc { struct rtc_device *rtc; + struct regmap *regmap; + bool allow_set_time; int rtc_alarm_irq; int rtc_base; int rtc_read_base; int rtc_write_base; int alarm_rw_base; - u8 ctrl_reg; + u8 ctrl_reg; struct device *rtc_dev; spinlock_t ctrl_reg_lock; }; /* - * The RTC registers need to be read/written one byte at a time. This is a - * hardware limitation. - */ -static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val, - int base, int count) -{ - int i, rc; - struct device *parent = rtc_dd->rtc_dev->parent; - - for (i = 0; i < count; i++) { - rc = pm8xxx_readb(parent, base + i, &rtc_val[i]); - if (rc < 0) { - dev_err(rtc_dd->rtc_dev, "PMIC read failed\n"); - return rc; - } - } - - return 0; -} - -static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val, - int base, int count) -{ - int i, rc; - struct device *parent = rtc_dd->rtc_dev->parent; - - for (i = 0; i < count; i++) { - rc = pm8xxx_writeb(parent, base + i, rtc_val[i]); - if (rc < 0) { - dev_err(rtc_dd->rtc_dev, "PMIC write failed\n"); - return rc; - } - } - - return 0; -} - -/* * Steps to write the RTC registers. * 1. Disable alarm if enabled. * 2. Write 0x00 to LSB. @@ -107,9 +71,12 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) { int rc, i; unsigned long secs, irq_flags; - u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg; + u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, ctrl_reg; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); + if (!rtc_dd->allow_set_time) + return -EACCES; + rtc_tm_to_time(tm, &secs); for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { @@ -125,47 +92,43 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) { alarm_enabled = 1; ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; - rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, - 1); - if (rc < 0) { - dev_err(dev, "Write to RTC control register " - "failed\n"); + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); + if (rc) { + dev_err(dev, "Write to RTC control register failed\n"); goto rtc_rw_fail; } rtc_dd->ctrl_reg = ctrl_reg; - } else + } else { spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); + } /* Write 0 to Byte[0] */ - reg = 0; - rc = pm8xxx_write_wrapper(rtc_dd, ®, rtc_dd->rtc_write_base, 1); - if (rc < 0) { + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, 0); + if (rc) { dev_err(dev, "Write to RTC write data register failed\n"); goto rtc_rw_fail; } /* Write Byte[1], Byte[2], Byte[3] */ - rc = pm8xxx_write_wrapper(rtc_dd, value + 1, - rtc_dd->rtc_write_base + 1, 3); - if (rc < 0) { + rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->rtc_write_base + 1, + &value[1], sizeof(value) - 1); + if (rc) { dev_err(dev, "Write to RTC write data register failed\n"); goto rtc_rw_fail; } /* Write Byte[0] */ - rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1); - if (rc < 0) { + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, value[0]); + if (rc) { dev_err(dev, "Write to RTC write data register failed\n"); goto rtc_rw_fail; } if (alarm_enabled) { ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE; - rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, - 1); - if (rc < 0) { - dev_err(dev, "Write to RTC control register " - "failed\n"); + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); + if (rc) { + dev_err(dev, "Write to RTC control register failed\n"); goto rtc_rw_fail; } rtc_dd->ctrl_reg = ctrl_reg; @@ -181,13 +144,14 @@ rtc_rw_fail: static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) { int rc; - u8 value[NUM_8_BIT_RTC_REGS], reg; + u8 value[NUM_8_BIT_RTC_REGS]; unsigned long secs; + unsigned int reg; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); - rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base, - NUM_8_BIT_RTC_REGS); - if (rc < 0) { + rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base, + value, sizeof(value)); + if (rc) { dev_err(dev, "RTC read data register failed\n"); return rc; } @@ -196,16 +160,16 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) * Read the LSB again and check if there has been a carry over. * If there is, redo the read operation. */ - rc = pm8xxx_read_wrapper(rtc_dd, ®, rtc_dd->rtc_read_base, 1); + rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_read_base, ®); if (rc < 0) { dev_err(dev, "RTC read data register failed\n"); return rc; } if (unlikely(reg < value[0])) { - rc = pm8xxx_read_wrapper(rtc_dd, value, - rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS); - if (rc < 0) { + rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base, + value, sizeof(value)); + if (rc) { dev_err(dev, "RTC read data register failed\n"); return rc; } @@ -222,8 +186,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) } dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n", - secs, tm->tm_hour, tm->tm_min, tm->tm_sec, - tm->tm_mday, tm->tm_mon, tm->tm_year); + secs, tm->tm_hour, tm->tm_min, tm->tm_sec, + tm->tm_mday, tm->tm_mon, tm->tm_year); return 0; } @@ -244,19 +208,22 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); - rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base, - NUM_8_BIT_RTC_REGS); - if (rc < 0) { + rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->alarm_rw_base, value, + sizeof(value)); + if (rc) { dev_err(dev, "Write to RTC ALARM register failed\n"); goto rtc_rw_fail; } ctrl_reg = rtc_dd->ctrl_reg; - ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) : - (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE); - rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); - if (rc < 0) { + if (alarm->enabled) + ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE; + else + ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; + + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); + if (rc) { dev_err(dev, "Write to RTC control register failed\n"); goto rtc_rw_fail; } @@ -264,9 +231,9 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) rtc_dd->ctrl_reg = ctrl_reg; dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", - alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec, alarm->time.tm_mday, - alarm->time.tm_mon, alarm->time.tm_year); + alarm->time.tm_hour, alarm->time.tm_min, + alarm->time.tm_sec, alarm->time.tm_mday, + alarm->time.tm_mon, alarm->time.tm_year); rtc_rw_fail: spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); return rc; @@ -279,9 +246,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) unsigned long secs; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); - rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base, - NUM_8_BIT_RTC_REGS); - if (rc < 0) { + rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->alarm_rw_base, value, + sizeof(value)); + if (rc) { dev_err(dev, "RTC alarm time read failed\n"); return rc; } @@ -297,9 +264,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) } dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", - alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec, alarm->time.tm_mday, - alarm->time.tm_mon, alarm->time.tm_year); + alarm->time.tm_hour, alarm->time.tm_min, + alarm->time.tm_sec, alarm->time.tm_mday, + alarm->time.tm_mon, alarm->time.tm_year); return 0; } @@ -312,12 +279,16 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) u8 ctrl_reg; spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); + ctrl_reg = rtc_dd->ctrl_reg; - ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) : - (ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE); - rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); - if (rc < 0) { + if (enable) + ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE; + else + ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; + + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); + if (rc) { dev_err(dev, "Write to RTC control register failed\n"); goto rtc_rw_fail; } @@ -329,8 +300,9 @@ rtc_rw_fail: return rc; } -static struct rtc_class_ops pm8xxx_rtc_ops = { +static const struct rtc_class_ops pm8xxx_rtc_ops = { .read_time = pm8xxx_rtc_read_time, + .set_time = pm8xxx_rtc_set_time, .set_alarm = pm8xxx_rtc_set_alarm, .read_alarm = pm8xxx_rtc_read_alarm, .alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable, @@ -339,7 +311,7 @@ static struct rtc_class_ops pm8xxx_rtc_ops = { static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) { struct pm8xxx_rtc *rtc_dd = dev_id; - u8 ctrl_reg; + unsigned int ctrl_reg; int rc; unsigned long irq_flags; @@ -351,11 +323,11 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) ctrl_reg = rtc_dd->ctrl_reg; ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; - rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); - if (rc < 0) { + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); + if (rc) { spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); - dev_err(rtc_dd->rtc_dev, "Write to RTC control register " - "failed\n"); + dev_err(rtc_dd->rtc_dev, + "Write to RTC control register failed\n"); goto rtc_alarm_handled; } @@ -363,63 +335,71 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); /* Clear RTC alarm register */ - rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base + - PM8XXX_ALARM_CTRL_OFFSET, 1); - if (rc < 0) { - dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read " - "failed\n"); + rc = regmap_read(rtc_dd->regmap, + rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET, + &ctrl_reg); + if (rc) { + dev_err(rtc_dd->rtc_dev, + "RTC Alarm control register read failed\n"); goto rtc_alarm_handled; } ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR; - rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base + - PM8XXX_ALARM_CTRL_OFFSET, 1); - if (rc < 0) - dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register" - " failed\n"); + rc = regmap_write(rtc_dd->regmap, + rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET, + ctrl_reg); + if (rc) + dev_err(rtc_dd->rtc_dev, + "Write to RTC Alarm control register failed\n"); rtc_alarm_handled: return IRQ_HANDLED; } +/* + * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out + */ +static const struct of_device_id pm8xxx_id_table[] = { + { .compatible = "qcom,pm8921-rtc", .data = (void *) 0x11D }, + { .compatible = "qcom,pm8058-rtc", .data = (void *) 0x1E8 }, + { }, +}; +MODULE_DEVICE_TABLE(of, pm8xxx_id_table); + static int pm8xxx_rtc_probe(struct platform_device *pdev) { int rc; - u8 ctrl_reg; - bool rtc_write_enable = false; + unsigned int ctrl_reg; struct pm8xxx_rtc *rtc_dd; - struct resource *rtc_resource; - const struct pm8xxx_rtc_platform_data *pdata = - dev_get_platdata(&pdev->dev); + const struct of_device_id *match; - if (pdata != NULL) - rtc_write_enable = pdata->rtc_write_enable; + match = of_match_node(pm8xxx_id_table, pdev->dev.of_node); + if (!match) + return -ENXIO; - rtc_dd = kzalloc(sizeof(*rtc_dd), GFP_KERNEL); - if (rtc_dd == NULL) { - dev_err(&pdev->dev, "Unable to allocate memory!\n"); + rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL); + if (rtc_dd == NULL) return -ENOMEM; - } /* Initialise spinlock to protect RTC control register */ spin_lock_init(&rtc_dd->ctrl_reg_lock); + rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!rtc_dd->regmap) { + dev_err(&pdev->dev, "Parent regmap unavailable.\n"); + return -ENXIO; + } + rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0); if (rtc_dd->rtc_alarm_irq < 0) { dev_err(&pdev->dev, "Alarm IRQ resource absent!\n"); - rc = -ENXIO; - goto fail_rtc_enable; + return -ENXIO; } - rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO, - "pmic_rtc_base"); - if (!(rtc_resource && rtc_resource->start)) { - dev_err(&pdev->dev, "RTC IO resource absent!\n"); - rc = -ENXIO; - goto fail_rtc_enable; - } + rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node, + "allow-set-time"); - rtc_dd->rtc_base = rtc_resource->start; + rtc_dd->rtc_base = (long) match->data; /* Setup RTC register addresses */ rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET; @@ -429,73 +409,50 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) rtc_dd->rtc_dev = &pdev->dev; /* Check if the RTC is on, else turn it on */ - rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); - if (rc < 0) { + rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_base, &ctrl_reg); + if (rc) { dev_err(&pdev->dev, "RTC control register read failed!\n"); - goto fail_rtc_enable; + return rc; } if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) { ctrl_reg |= PM8xxx_RTC_ENABLE; - rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, - 1); - if (rc < 0) { - dev_err(&pdev->dev, "Write to RTC control register " - "failed\n"); - goto fail_rtc_enable; + rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); + if (rc) { + dev_err(&pdev->dev, + "Write to RTC control register failed\n"); + return rc; } } rtc_dd->ctrl_reg = ctrl_reg; - if (rtc_write_enable == true) - pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time; platform_set_drvdata(pdev, rtc_dd); + device_init_wakeup(&pdev->dev, 1); + /* Register the RTC device */ - rtc_dd->rtc = rtc_device_register("pm8xxx_rtc", &pdev->dev, - &pm8xxx_rtc_ops, THIS_MODULE); + rtc_dd->rtc = devm_rtc_device_register(&pdev->dev, "pm8xxx_rtc", + &pm8xxx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc_dd->rtc)) { dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n", - __func__, PTR_ERR(rtc_dd->rtc)); - rc = PTR_ERR(rtc_dd->rtc); - goto fail_rtc_enable; + __func__, PTR_ERR(rtc_dd->rtc)); + return PTR_ERR(rtc_dd->rtc); } /* Request the alarm IRQ */ - rc = request_any_context_irq(rtc_dd->rtc_alarm_irq, - pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING, - "pm8xxx_rtc_alarm", rtc_dd); + rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq, + pm8xxx_alarm_trigger, + IRQF_TRIGGER_RISING, + "pm8xxx_rtc_alarm", rtc_dd); if (rc < 0) { dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc); - goto fail_req_irq; + return rc; } - device_init_wakeup(&pdev->dev, 1); - dev_dbg(&pdev->dev, "Probe success !!\n"); return 0; - -fail_req_irq: - rtc_device_unregister(rtc_dd->rtc); -fail_rtc_enable: - platform_set_drvdata(pdev, NULL); - kfree(rtc_dd); - return rc; -} - -static int pm8xxx_rtc_remove(struct platform_device *pdev) -{ - struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev); - - device_init_wakeup(&pdev->dev, 0); - free_irq(rtc_dd->rtc_alarm_irq, rtc_dd); - rtc_device_unregister(rtc_dd->rtc); - platform_set_drvdata(pdev, NULL); - kfree(rtc_dd); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -520,15 +477,17 @@ static int pm8xxx_rtc_suspend(struct device *dev) } #endif -static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume); +static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, + pm8xxx_rtc_suspend, + pm8xxx_rtc_resume); static struct platform_driver pm8xxx_rtc_driver = { .probe = pm8xxx_rtc_probe, - .remove = pm8xxx_rtc_remove, .driver = { - .name = PM8XXX_RTC_DEV_NAME, - .owner = THIS_MODULE, - .pm = &pm8xxx_rtc_pm_ops, + .name = "rtc-pm8xxx", + .owner = THIS_MODULE, + .pm = &pm8xxx_rtc_pm_ops, + .of_match_table = pm8xxx_id_table, }, }; diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c index 4bb825bb580..554ada5e9b7 100644 --- a/drivers/rtc/rtc-ps3.c +++ b/drivers/rtc/rtc-ps3.c @@ -71,17 +71,11 @@ static int __init ps3_rtc_probe(struct platform_device *dev) return 0; } -static int __exit ps3_rtc_remove(struct platform_device *dev) -{ - return 0; -} - static struct platform_driver ps3_rtc_driver = { .driver = { .name = "rtc-ps3", .owner = THIS_MODULE, }, - .remove = __exit_p(ps3_rtc_remove), }; module_platform_driver_probe(ps3_rtc_driver, ps3_rtc_probe); diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 72f437170d2..1cff2a21db6 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -53,11 +53,11 @@ static irqreturn_t puv3_rtc_tickirq(int irq, void *id) } /* Update control registers */ -static void puv3_rtc_setaie(int to) +static void puv3_rtc_setaie(struct device *dev, int to) { unsigned int tmp; - pr_debug("%s: aie=%d\n", __func__, to); + dev_dbg(dev, "%s: aie=%d\n", __func__, to); tmp = readl(RTC_RTSR) & ~RTC_RTSR_ALE; @@ -71,7 +71,7 @@ static int puv3_rtc_setpie(struct device *dev, int enabled) { unsigned int tmp; - pr_debug("%s: pie=%d\n", __func__, enabled); + dev_dbg(dev, "%s: pie=%d\n", __func__, enabled); spin_lock_irq(&puv3_rtc_pie_lock); tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE; @@ -90,7 +90,7 @@ static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); - pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", + dev_dbg(dev, "read time %02x.%02x.%02x %02x/%02x/%02x\n", rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); @@ -101,7 +101,7 @@ static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long rtc_count = 0; - pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", + dev_dbg(dev, "set time %02d.%02d.%02d %02d/%02d/%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -119,7 +119,7 @@ static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; - pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", + dev_dbg(dev, "read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", alrm->enabled, alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); @@ -132,7 +132,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; unsigned long rtcalarm_count = 0; - pr_debug("puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", + dev_dbg(dev, "puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", alrm->enabled, tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); @@ -140,7 +140,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) rtc_tm_to_time(tm, &rtcalarm_count); writel(rtcalarm_count, RTC_RTAR); - puv3_rtc_setaie(alrm->enabled); + puv3_rtc_setaie(dev, alrm->enabled); if (alrm->enabled) enable_irq_wake(puv3_rtc_alarmno); @@ -224,11 +224,10 @@ static int puv3_rtc_remove(struct platform_device *dev) { struct rtc_device *rtc = platform_get_drvdata(dev); - platform_set_drvdata(dev, NULL); rtc_device_unregister(rtc); puv3_rtc_setpie(&dev->dev, 0); - puv3_rtc_setaie(0); + puv3_rtc_setaie(&dev->dev, 0); release_resource(puv3_rtc_mem); kfree(puv3_rtc_mem); @@ -242,7 +241,7 @@ static int puv3_rtc_probe(struct platform_device *pdev) struct resource *res; int ret; - pr_debug("%s: probe=%p\n", __func__, pdev); + dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev); /* find the IRQs */ puv3_rtc_tickno = platform_get_irq(pdev, 1); @@ -257,7 +256,7 @@ static int puv3_rtc_probe(struct platform_device *pdev) return -ENOENT; } - pr_debug("PKUnity_rtc: tick irq %d, alarm irq %d\n", + dev_dbg(&pdev->dev, "PKUnity_rtc: tick irq %d, alarm irq %d\n", puv3_rtc_tickno, puv3_rtc_alarmno); /* get the memory region */ diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index ed037ae91c5..4561f375327 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -32,7 +32,6 @@ #include <mach/hardware.h> -#define TIMER_FREQ CLOCK_TICK_RATE #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 #define MAXFREQ_PERIODIC 1000 @@ -324,37 +323,35 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) int ret; u32 rttr; - pxa_rtc = kzalloc(sizeof(struct pxa_rtc), GFP_KERNEL); + pxa_rtc = devm_kzalloc(dev, sizeof(*pxa_rtc), GFP_KERNEL); if (!pxa_rtc) return -ENOMEM; spin_lock_init(&pxa_rtc->lock); platform_set_drvdata(pdev, pxa_rtc); - ret = -ENXIO; pxa_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!pxa_rtc->ress) { dev_err(dev, "No I/O memory resource defined\n"); - goto err_ress; + return -ENXIO; } pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0); if (pxa_rtc->irq_1Hz < 0) { dev_err(dev, "No 1Hz IRQ resource defined\n"); - goto err_ress; + return -ENXIO; } pxa_rtc->irq_Alrm = platform_get_irq(pdev, 1); if (pxa_rtc->irq_Alrm < 0) { dev_err(dev, "No alarm IRQ resource defined\n"); - goto err_ress; + return -ENXIO; } pxa_rtc_open(dev); - ret = -ENOMEM; - pxa_rtc->base = ioremap(pxa_rtc->ress->start, + pxa_rtc->base = devm_ioremap(dev, pxa_rtc->ress->start, resource_size(pxa_rtc->ress)); if (!pxa_rtc->base) { - dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n"); - goto err_map; + dev_err(dev, "Unable to map pxa RTC I/O memory\n"); + return -ENOMEM; } /* @@ -370,46 +367,29 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); - pxa_rtc->rtc = rtc_device_register("pxa-rtc", &pdev->dev, &pxa_rtc_ops, - THIS_MODULE); - ret = PTR_ERR(pxa_rtc->rtc); + pxa_rtc->rtc = devm_rtc_device_register(&pdev->dev, "pxa-rtc", + &pxa_rtc_ops, THIS_MODULE); if (IS_ERR(pxa_rtc->rtc)) { + ret = PTR_ERR(pxa_rtc->rtc); dev_err(dev, "Failed to register RTC device -> %d\n", ret); - goto err_rtc_reg; + return ret; } device_init_wakeup(dev, 1); return 0; - -err_rtc_reg: - iounmap(pxa_rtc->base); -err_ress: -err_map: - kfree(pxa_rtc); - return ret; } static int __exit pxa_rtc_remove(struct platform_device *pdev) { - struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - pxa_rtc_release(dev); - - rtc_device_unregister(pxa_rtc->rtc); - - spin_lock_irq(&pxa_rtc->lock); - iounmap(pxa_rtc->base); - spin_unlock_irq(&pxa_rtc->lock); - - kfree(pxa_rtc); + pxa_rtc_release(dev); return 0; } #ifdef CONFIG_OF -static struct of_device_id pxa_rtc_dt_ids[] = { +static const struct of_device_id pxa_rtc_dt_ids[] = { { .compatible = "marvell,pxa-rtc" }, {} }; diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c index 8eabcf51b35..e53e9b1c69b 100644 --- a/drivers/rtc/rtc-rc5t583.c +++ b/drivers/rtc/rtc-rc5t583.c @@ -273,7 +273,7 @@ static int rc5t583_rtc_probe(struct platform_device *pdev) */ static int rc5t583_rtc_remove(struct platform_device *pdev) { - struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(&pdev->dev); + struct rc5t583_rtc *rc5t583_rtc = platform_get_drvdata(pdev); rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0); return 0; diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 873c689f01c..89d07367926 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -251,21 +251,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) rtc = devm_rtc_device_register(&dev->dev, "rtc-rp5c01", &rp5c01_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - error = PTR_ERR(rtc); - goto out; - } + if (IS_ERR(rtc)) + return PTR_ERR(rtc); priv->rtc = rtc; error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); if (error) - goto out; + return error; return 0; - -out: - platform_set_drvdata(dev, NULL); - return error; } static int __exit rp5c01_rtc_remove(struct platform_device *dev) diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index 8089fc63e40..68f7856422f 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -47,10 +47,10 @@ #include <linux/platform_device.h> #include <linux/bcd.h> #include <linux/delay.h> -#include <asm/io.h> +#include <linux/io.h> #define DRV_NAME "rs5c313" -#define DRV_VERSION "1.13" +#define DRV_VERSION "1.13" #ifdef CONFIG_SH_LANDISK /*****************************************************/ @@ -301,7 +301,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4)); data = bin2bcd(tm->tm_min); - rs5c313_write_reg(RS5C313_ADDR_MIN, data ); + rs5c313_write_reg(RS5C313_ADDR_MIN, data); rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4)); data = bin2bcd(tm->tm_hour); @@ -310,7 +310,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) data = bin2bcd(tm->tm_mday); rs5c313_write_reg(RS5C313_ADDR_DAY, data); - rs5c313_write_reg(RS5C313_ADDR_DAY10, (data>> 4)); + rs5c313_write_reg(RS5C313_ADDR_DAY10, (data >> 4)); data = bin2bcd(tm->tm_mon + 1); rs5c313_write_reg(RS5C313_ADDR_MON, data); @@ -349,9 +349,9 @@ static void rs5c313_check_xstp_bit(void) } memset(&tm, 0, sizeof(struct rtc_time)); - tm.tm_mday = 1; - tm.tm_mon = 1 - 1; - tm.tm_year = 2000 - 1900; + tm.tm_mday = 1; + tm.tm_mon = 1 - 1; + tm.tm_year = 2000 - 1900; rs5c313_rtc_set_time(NULL, &tm); pr_err("invalid value, resetting to 1 Jan 2000\n"); @@ -378,18 +378,12 @@ static int rs5c313_rtc_probe(struct platform_device *pdev) return 0; } -static int rs5c313_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver rs5c313_rtc_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, - .probe = rs5c313_rtc_probe, - .remove = rs5c313_rtc_remove, + .probe = rs5c313_rtc_probe, }; static int __init rs5c313_rtc_init(void) @@ -408,7 +402,7 @@ static int __init rs5c313_rtc_init(void) static void __exit rs5c313_rtc_exit(void) { - platform_driver_unregister( &rs5c313_rtc_platform_driver ); + platform_driver_unregister(&rs5c313_rtc_platform_driver); } module_init(rs5c313_rtc_init); diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index 2c37df3586c..090a101c1c8 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -64,7 +64,7 @@ static int rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct spi_device *spi = to_spi_device(dev); - struct rs5c348_plat_data *pdata = spi->dev.platform_data; + struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev); u8 txbuf[5+7], *txp; int ret; @@ -100,7 +100,7 @@ static int rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct spi_device *spi = to_spi_device(dev); - struct rs5c348_plat_data *pdata = spi->dev.platform_data; + struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev); u8 txbuf[5], rxbuf[7]; int ret; @@ -218,18 +218,12 @@ static int rs5c348_probe(struct spi_device *spi) return ret; } -static int rs5c348_remove(struct spi_device *spi) -{ - return 0; -} - static struct spi_driver rs5c348_driver = { .driver = { .name = "rtc-rs5c348", .owner = THIS_MODULE, }, .probe = rs5c348_probe, - .remove = rs5c348_remove, }; module_spi_driver(rs5c348_driver); diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 5032c24ec15..e9ac5a43be1 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -310,7 +310,7 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, dev_dbg(&client->dev, "alarm IRQ armed\n"); } else { /* disable AIE irq */ - ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1); + ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 0); if (ret) return ret; @@ -395,6 +395,12 @@ static int rv3029c2_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL)) return -ENODEV; + rc = rv3029c2_i2c_get_sr(client, buf); + if (rc < 0) { + dev_err(&client->dev, "reading status failed\n"); + return rc; + } + rtc = devm_rtc_device_register(&client->dev, client->name, &rv3029c2_rtc_ops, THIS_MODULE); @@ -403,17 +409,6 @@ static int rv3029c2_probe(struct i2c_client *client, i2c_set_clientdata(client, rtc); - rc = rv3029c2_i2c_get_sr(client, buf); - if (rc < 0) { - dev_err(&client->dev, "reading status failed\n"); - return rc; - } - - return 0; -} - -static int rv3029c2_remove(struct i2c_client *client) -{ return 0; } @@ -422,7 +417,6 @@ static struct i2c_driver rv3029c2_driver = { .name = "rtc-rv3029c2", }, .probe = rv3029c2_probe, - .remove = rv3029c2_remove, .id_table = rv3029c2_id, }; diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c index 84eb08d65d3..6889222f9ed 100644 --- a/drivers/rtc/rtc-rx4581.c +++ b/drivers/rtc/rtc-rx4581.c @@ -282,11 +282,6 @@ static int rx4581_probe(struct spi_device *spi) return 0; } -static int rx4581_remove(struct spi_device *spi) -{ - return 0; -} - static const struct spi_device_id rx4581_id[] = { { "rx4581", 0 }, { } @@ -299,7 +294,6 @@ static struct spi_driver rx4581_driver = { .owner = THIS_MODULE, }, .probe = rx4581_probe, - .remove = rx4581_remove, .id_table = rx4581_id, }; diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 0722d36b9c9..e6298e02b40 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -549,9 +549,8 @@ static int rx8025_probe(struct i2c_client *client, goto errout; } - rx8025 = kzalloc(sizeof(*rx8025), GFP_KERNEL); + rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL); if (!rx8025) { - dev_err(&adapter->dev, "failed to alloc memory\n"); err = -ENOMEM; goto errout; } @@ -562,7 +561,7 @@ static int rx8025_probe(struct i2c_client *client, err = rx8025_init_client(client, &need_reset); if (err) - goto errout_free; + goto errout; if (need_reset) { struct rtc_time tm; @@ -572,12 +571,12 @@ static int rx8025_probe(struct i2c_client *client, rx8025_set_time(&client->dev, &tm); } - rx8025->rtc = rtc_device_register(client->name, &client->dev, + rx8025->rtc = devm_rtc_device_register(&client->dev, client->name, &rx8025_rtc_ops, THIS_MODULE); if (IS_ERR(rx8025->rtc)) { err = PTR_ERR(rx8025->rtc); dev_err(&client->dev, "unable to register the class device\n"); - goto errout_free; + goto errout; } if (client->irq > 0) { @@ -586,7 +585,7 @@ static int rx8025_probe(struct i2c_client *client, 0, "rx8025", client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); - goto errout_reg; + goto errout; } } @@ -603,12 +602,6 @@ errout_irq: if (client->irq > 0) free_irq(client->irq, client); -errout_reg: - rtc_device_unregister(rx8025->rtc); - -errout_free: - kfree(rx8025); - errout: dev_err(&adapter->dev, "probing for rx8025 failed\n"); return err; @@ -629,8 +622,6 @@ static int rx8025_remove(struct i2c_client *client) } rx8025_sysfs_unregister(&client->dev); - rtc_device_unregister(rx8025->rtc); - kfree(rx8025); return 0; } diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 07f3037b18f..de8d9c42778 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -52,8 +52,45 @@ #define RX8581_CTRL_STOP 0x02 /* STOP bit */ #define RX8581_CTRL_RESET 0x01 /* RESET bit */ +struct rx8581 { + struct i2c_client *client; + struct rtc_device *rtc; + s32 (*read_block_data)(const struct i2c_client *client, u8 command, + u8 length, u8 *values); + s32 (*write_block_data)(const struct i2c_client *client, u8 command, + u8 length, const u8 *values); +}; + static struct i2c_driver rx8581_driver; +static int rx8581_read_block_data(const struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + s32 i, data; + + for (i = 0; i < length; i++) { + data = i2c_smbus_read_byte_data(client, command + i); + if (data < 0) + return data; + values[i] = data; + } + return i; +} + +static int rx8581_write_block_data(const struct i2c_client *client, u8 command, + u8 length, const u8 *values) +{ + s32 i, ret; + + for (i = 0; i < length; i++) { + ret = i2c_smbus_write_byte_data(client, command + i, + values[i]); + if (ret < 0) + return ret; + } + return length; +} + /* * In the routines that deal directly with the rx8581 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. @@ -62,6 +99,7 @@ static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm) { unsigned char date[7]; int data, err; + struct rx8581 *rx8581 = i2c_get_clientdata(client); /* 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 @@ -80,14 +118,13 @@ static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm) err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG, (data & ~RX8581_FLAG_UF)); if (err != 0) { - dev_err(&client->dev, "Unable to write device " - "flags\n"); + dev_err(&client->dev, "Unable to write device flags\n"); return -EIO; } } /* Now read time and date */ - err = i2c_smbus_read_i2c_block_data(client, RX8581_REG_SC, + err = rx8581->read_block_data(client, RX8581_REG_SC, 7, date); if (err < 0) { dev_err(&client->dev, "Unable to read date\n"); @@ -140,6 +177,7 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm) { int data, err; unsigned char buf[7]; + struct rx8581 *rx8581 = i2c_get_clientdata(client); dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", @@ -176,7 +214,7 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm) } /* write register's data */ - err = i2c_smbus_write_i2c_block_data(client, RX8581_REG_SC, 7, buf); + err = rx8581->write_block_data(client, RX8581_REG_SC, 7, buf); if (err < 0) { dev_err(&client->dev, "Unable to write to date registers\n"); return -EIO; @@ -231,28 +269,40 @@ static const struct rtc_class_ops rx8581_rtc_ops = { static int rx8581_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct rtc_device *rtc; + struct rx8581 *rx8581; dev_dbg(&client->dev, "%s\n", __func__); - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA) + && !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -EIO; - dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL); + if (!rx8581) + return -ENOMEM; - rtc = devm_rtc_device_register(&client->dev, rx8581_driver.driver.name, - &rx8581_rtc_ops, THIS_MODULE); + i2c_set_clientdata(client, rx8581); + rx8581->client = client; + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + rx8581->read_block_data = i2c_smbus_read_i2c_block_data; + rx8581->write_block_data = i2c_smbus_write_i2c_block_data; + } else { + rx8581->read_block_data = rx8581_read_block_data; + rx8581->write_block_data = rx8581_write_block_data; + } - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - i2c_set_clientdata(client, rtc); + rx8581->rtc = devm_rtc_device_register(&client->dev, + rx8581_driver.driver.name, &rx8581_rtc_ops, THIS_MODULE); - return 0; -} + if (IS_ERR(rx8581->rtc)) { + dev_err(&client->dev, + "unable to register the class device\n"); + return PTR_ERR(rx8581->rtc); + } -static int rx8581_remove(struct i2c_client *client) -{ return 0; } @@ -268,7 +318,6 @@ static struct i2c_driver rx8581_driver = { .owner = THIS_MODULE, }, .probe = rx8581_probe, - .remove = rx8581_remove, .id_table = rx8581_id, }; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 0b495e8b8e6..4958a363b2c 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -48,8 +48,8 @@ struct s3c_rtc_drv_data { static struct clk *rtc_clk; static void __iomem *s3c_rtc_base; -static int s3c_rtc_alarmno = NO_IRQ; -static int s3c_rtc_tickno = NO_IRQ; +static int s3c_rtc_alarmno; +static int s3c_rtc_tickno; static enum s3c_cpu_type s3c_rtc_cpu_type; static DEFINE_SPINLOCK(s3c_rtc_pie_lock); @@ -421,8 +421,6 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) static int s3c_rtc_remove(struct platform_device *dev) { - platform_set_drvdata(dev, NULL); - s3c_rtc_setaie(&dev->dev, 0); clk_unprepare(rtc_clk); @@ -549,23 +547,20 @@ static int s3c_rtc_probe(struct platform_device *pdev) 0, "s3c2410-rtc alarm", rtc); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret); - goto err_alarm_irq; + goto err_nortc; } 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); - goto err_alarm_irq; + goto err_nortc; } clk_disable(rtc_clk); return 0; - err_alarm_irq: - platform_set_drvdata(pdev, NULL); - err_nortc: s3c_rtc_enable(pdev, 0); clk_disable_unprepare(rtc_clk); @@ -585,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev) clk_enable(rtc_clk); /* save TICNT for anyone using periodic interrupts */ - ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt_en_save &= S3C64XX_RTCCON_TICEN; + ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT); + } else { + ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); } s3c_rtc_enable(pdev, 0); @@ -610,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev) clk_enable(rtc_clk); s3c_rtc_enable(pdev, 1); - writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); - if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { - tmp = readw(s3c_rtc_base + S3C2410_RTCCON); - writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); + if (s3c_rtc_cpu_type == TYPE_S3C64XX) { + writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT); + if (ticnt_en_save) { + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); + writew(tmp | ticnt_en_save, + s3c_rtc_base + S3C2410_RTCCON); + } + } else { + writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); } if (device_may_wakeup(dev) && wake_en) { diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c new file mode 100644 index 00000000000..8f06250a038 --- /dev/null +++ b/drivers/rtc/rtc-s5m.c @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd + * http://www.samsung.com + * + * Copyright (C) 2013 Google, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/irq.h> +#include <linux/mfd/samsung/rtc.h> +#include <linux/mfd/samsung/s2mps14.h> + +/* + * Maximum number of retries for checking changes in UDR field + * of S5M_RTC_UDR_CON register (to limit possible endless loop). + * + * After writing to RTC registers (setting time or alarm) read the UDR field + * in S5M_RTC_UDR_CON register. UDR is auto-cleared when data have + * been transferred. + */ +#define UDR_READ_RETRY_CNT 5 + +/* Registers used by the driver which are different between chipsets. */ +struct s5m_rtc_reg_config { + /* Number of registers used for setting time/alarm0/alarm1 */ + unsigned int regs_count; + /* First register for time, seconds */ + unsigned int time; + /* RTC control register */ + unsigned int ctrl; + /* First register for alarm 0, seconds */ + unsigned int alarm0; + /* First register for alarm 1, seconds */ + unsigned int alarm1; + /* SMPL/WTSR register */ + unsigned int smpl_wtsr; + /* + * Register for update flag (UDR). Typically setting UDR field to 1 + * will enable update of time or alarm register. Then it will be + * auto-cleared after successful update. + */ + unsigned int rtc_udr_update; + /* Mask for UDR field in 'rtc_udr_update' register */ + unsigned int rtc_udr_mask; +}; + +/* Register map for S5M8763 and S5M8767 */ +static const struct s5m_rtc_reg_config s5m_rtc_regs = { + .regs_count = 8, + .time = S5M_RTC_SEC, + .ctrl = S5M_ALARM1_CONF, + .alarm0 = S5M_ALARM0_SEC, + .alarm1 = S5M_ALARM1_SEC, + .smpl_wtsr = S5M_WTSR_SMPL_CNTL, + .rtc_udr_update = S5M_RTC_UDR_CON, + .rtc_udr_mask = S5M_RTC_UDR_MASK, +}; + +/* + * Register map for S2MPS14. + * It may be also suitable for S2MPS11 but this was not tested. + */ +static const struct s5m_rtc_reg_config s2mps_rtc_regs = { + .regs_count = 7, + .time = S2MPS_RTC_SEC, + .ctrl = S2MPS_RTC_CTRL, + .alarm0 = S2MPS_ALARM0_SEC, + .alarm1 = S2MPS_ALARM1_SEC, + .smpl_wtsr = S2MPS_WTSR_SMPL_CNTL, + .rtc_udr_update = S2MPS_RTC_UDR_CON, + .rtc_udr_mask = S2MPS_RTC_WUDR_MASK, +}; + +struct s5m_rtc_info { + struct device *dev; + struct i2c_client *i2c; + struct sec_pmic_dev *s5m87xx; + struct regmap *regmap; + struct rtc_device *rtc_dev; + int irq; + int device_type; + int rtc_24hr_mode; + bool wtsr_smpl; + const struct s5m_rtc_reg_config *regs; +}; + +static const struct regmap_config s5m_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S5M_RTC_REG_MAX, +}; + +static const struct regmap_config s2mps14_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS_RTC_REG_MAX, +}; + +static void s5m8767_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 = ffs(data[RTC_WEEKDAY] & 0x7f); + tm->tm_mday = data[RTC_DATE] & 0x1f; + tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; + tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100; + tm->tm_yday = 0; + tm->tm_isdst = 0; +} + +static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = tm->tm_sec; + data[RTC_MIN] = tm->tm_min; + + if (tm->tm_hour >= 12) + data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK; + else + data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK; + + data[RTC_WEEKDAY] = 1 << tm->tm_wday; + data[RTC_DATE] = tm->tm_mday; + data[RTC_MONTH] = tm->tm_mon + 1; + data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; + + if (tm->tm_year < 100) { + pr_err("s5m8767 RTC cannot handle the year %d.\n", + 1900 + tm->tm_year); + return -EINVAL; + } else { + return 0; + } +} + +/* + * Read RTC_UDR_CON register and wait till UDR field is cleared. + * This indicates that time/alarm update ended. + */ +static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) +{ + int ret, retry = UDR_READ_RETRY_CNT; + unsigned int data; + + do { + ret = regmap_read(info->regmap, info->regs->rtc_udr_update, + &data); + } while (--retry && (data & info->regs->rtc_udr_mask) && !ret); + + if (!retry) + dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); + + return ret; +} + +static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, + struct rtc_wkalrm *alarm) +{ + int ret; + unsigned int val; + + switch (info->device_type) { + case S5M8767X: + case S5M8763X: + ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); + val &= S5M_ALARM0_STATUS; + break; + case S2MPS14X: + ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, + &val); + val &= S2MPS_ALARM0_STATUS; + break; + default: + return -EINVAL; + } + if (ret < 0) + return ret; + + if (val) + alarm->pending = 1; + else + alarm->pending = 0; + + return 0; +} + +static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) +{ + int ret; + unsigned int data; + + ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); + if (ret < 0) { + dev_err(info->dev, "failed to read update reg(%d)\n", ret); + return ret; + } + + data |= info->regs->rtc_udr_mask; + if (info->device_type == S5M8763X || info->device_type == S5M8767X) + data |= S5M_RTC_TIME_EN_MASK; + + ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); + if (ret < 0) { + dev_err(info->dev, "failed to write update reg(%d)\n", ret); + return ret; + } + + ret = s5m8767_wait_for_udr_update(info); + + return ret; +} + +static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) +{ + int ret; + unsigned int data; + + ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to read update reg(%d)\n", + __func__, ret); + return ret; + } + + data |= info->regs->rtc_udr_mask; + switch (info->device_type) { + case S5M8763X: + case S5M8767X: + data &= ~S5M_RTC_TIME_EN_MASK; + break; + case S2MPS14X: + data |= S2MPS_RTC_RUDR_MASK; + break; + default: + return -EINVAL; + } + + ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); + if (ret < 0) { + dev_err(info->dev, "%s: fail to write update reg(%d)\n", + __func__, ret); + return ret; + } + + ret = s5m8767_wait_for_udr_update(info); + + return ret; +} + +static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(data[RTC_SEC]); + tm->tm_min = bcd2bin(data[RTC_MIN]); + + if (data[RTC_HOUR] & HOUR_12) { + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); + if (data[RTC_HOUR] & HOUR_PM) + tm->tm_hour += 12; + } else { + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); + } + + tm->tm_wday = data[RTC_WEEKDAY] & 0x07; + tm->tm_mday = bcd2bin(data[RTC_DATE]); + tm->tm_mon = bcd2bin(data[RTC_MONTH]); + tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; + tm->tm_year -= 1900; +} + +static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data) +{ + data[RTC_SEC] = bin2bcd(tm->tm_sec); + data[RTC_MIN] = bin2bcd(tm->tm_min); + data[RTC_HOUR] = bin2bcd(tm->tm_hour); + data[RTC_WEEKDAY] = tm->tm_wday; + data[RTC_DATE] = bin2bcd(tm->tm_mday); + data[RTC_MONTH] = bin2bcd(tm->tm_mon); + data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); + data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); +} + +static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[info->regs->regs_count]; + int ret; + + if (info->device_type == S2MPS14X) { + ret = regmap_update_bits(info->regmap, + info->regs->rtc_udr_update, + S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); + if (ret) { + dev_err(dev, + "Failed to prepare registers for time reading: %d\n", + ret); + return ret; + } + } + ret = regmap_bulk_read(info->regmap, info->regs->time, data, + info->regs->regs_count); + if (ret < 0) + return ret; + + switch (info->device_type) { + case S5M8763X: + s5m8763_data_to_tm(data, tm); + break; + + case S5M8767X: + case S2MPS14X: + s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); + break; + + default: + return -EINVAL; + } + + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + + return rtc_valid_tm(tm); +} + +static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[info->regs->regs_count]; + int ret = 0; + + switch (info->device_type) { + case S5M8763X: + s5m8763_tm_to_data(tm, data); + break; + case S5M8767X: + case S2MPS14X: + ret = s5m8767_tm_to_data(tm, data); + break; + default: + return -EINVAL; + } + + if (ret < 0) + return ret; + + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + + ret = regmap_raw_write(info->regmap, info->regs->time, data, + info->regs->regs_count); + if (ret < 0) + return ret; + + ret = s5m8767_rtc_set_time_reg(info); + + return ret; +} + +static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[info->regs->regs_count]; + unsigned int val; + int ret, i; + + ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); + if (ret < 0) + return ret; + + switch (info->device_type) { + case S5M8763X: + s5m8763_data_to_tm(data, &alrm->time); + ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val); + if (ret < 0) + return ret; + + alrm->enabled = !!val; + break; + + case S5M8767X: + case S2MPS14X: + s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + alrm->enabled = 0; + for (i = 0; i < info->regs->regs_count; i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } + } + break; + + default: + return -EINVAL; + } + + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, + alrm->time.tm_mday, alrm->time.tm_hour, + alrm->time.tm_min, alrm->time.tm_sec, + alrm->time.tm_wday); + + ret = s5m_check_peding_alarm_interrupt(info, alrm); + + return 0; +} + +static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) +{ + u8 data[info->regs->regs_count]; + int ret, i; + struct rtc_time tm; + + ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); + if (ret < 0) + return ret; + + s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); + dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + + switch (info->device_type) { + case S5M8763X: + ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0); + break; + + case S5M8767X: + case S2MPS14X: + for (i = 0; i < info->regs->regs_count; i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); + if (ret < 0) + return ret; + + ret = s5m8767_rtc_set_alarm_reg(info); + + break; + + default: + return -EINVAL; + } + + return ret; +} + +static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) +{ + int ret; + u8 data[info->regs->regs_count]; + u8 alarm0_conf; + struct rtc_time tm; + + ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); + if (ret < 0) + return ret; + + s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); + dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + + switch (info->device_type) { + case S5M8763X: + alarm0_conf = 0x77; + ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf); + break; + + case S5M8767X: + case S2MPS14X: + data[RTC_SEC] |= ALARM_ENABLE_MASK; + data[RTC_MIN] |= ALARM_ENABLE_MASK; + data[RTC_HOUR] |= ALARM_ENABLE_MASK; + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= ALARM_ENABLE_MASK; + if (data[RTC_YEAR1] & 0x7f) + data[RTC_YEAR1] |= ALARM_ENABLE_MASK; + + ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); + if (ret < 0) + return ret; + ret = s5m8767_rtc_set_alarm_reg(info); + + break; + + default: + return -EINVAL; + } + + return ret; +} + +static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + u8 data[info->regs->regs_count]; + int ret; + + switch (info->device_type) { + case S5M8763X: + s5m8763_tm_to_data(&alrm->time, data); + break; + + case S5M8767X: + case S2MPS14X: + s5m8767_tm_to_data(&alrm->time, data); + break; + + default: + return -EINVAL; + } + + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, + alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min, + alrm->time.tm_sec, alrm->time.tm_wday); + + ret = s5m_rtc_stop_alarm(info); + if (ret < 0) + return ret; + + ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); + if (ret < 0) + return ret; + + ret = s5m8767_rtc_set_alarm_reg(info); + if (ret < 0) + return ret; + + if (alrm->enabled) + ret = s5m_rtc_start_alarm(info); + + return ret; +} + +static int s5m_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + + if (enabled) + return s5m_rtc_start_alarm(info); + else + return s5m_rtc_stop_alarm(info); +} + +static irqreturn_t s5m_rtc_alarm_irq(int irq, void *data) +{ + struct s5m_rtc_info *info = data; + + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops s5m_rtc_ops = { + .read_time = s5m_rtc_read_time, + .set_time = s5m_rtc_set_time, + .read_alarm = s5m_rtc_read_alarm, + .set_alarm = s5m_rtc_set_alarm, + .alarm_irq_enable = s5m_rtc_alarm_irq_enable, +}; + +static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) +{ + int ret; + ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, + WTSR_ENABLE_MASK, + enable ? WTSR_ENABLE_MASK : 0); + if (ret < 0) + dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", + __func__, ret); +} + +static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) +{ + int ret; + ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, + SMPL_ENABLE_MASK, + enable ? SMPL_ENABLE_MASK : 0); + if (ret < 0) + dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", + __func__, ret); +} + +static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) +{ + u8 data[2]; + int ret; + + switch (info->device_type) { + case S5M8763X: + case S5M8767X: + /* UDR update time. Default of 7.32 ms is too long. */ + ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON, + S5M_RTC_UDR_T_MASK, S5M_RTC_UDR_T_450_US); + if (ret < 0) + dev_err(info->dev, "%s: fail to change UDR time: %d\n", + __func__, ret); + + /* Set RTC control register : Binary mode, 24hour mode */ + data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + + ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2); + break; + + case S2MPS14X: + data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); + break; + + default: + return -EINVAL; + } + + info->rtc_24hr_mode = 1; + if (ret < 0) { + dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", + __func__, ret); + return ret; + } + + return ret; +} + +static int s5m_rtc_probe(struct platform_device *pdev) +{ + struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent); + struct sec_platform_data *pdata = s5m87xx->pdata; + struct s5m_rtc_info *info; + const struct regmap_config *regmap_cfg; + int ret, alarm_irq; + + if (!pdata) { + dev_err(pdev->dev.parent, "Platform data not supplied\n"); + return -ENODEV; + } + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + switch (pdata->device_type) { + case S2MPS14X: + regmap_cfg = &s2mps14_rtc_regmap_config; + info->regs = &s2mps_rtc_regs; + alarm_irq = S2MPS14_IRQ_RTCA0; + break; + case S5M8763X: + regmap_cfg = &s5m_rtc_regmap_config; + info->regs = &s5m_rtc_regs; + alarm_irq = S5M8763_IRQ_ALARM0; + break; + case S5M8767X: + regmap_cfg = &s5m_rtc_regmap_config; + info->regs = &s5m_rtc_regs; + alarm_irq = S5M8767_IRQ_RTCA1; + break; + default: + dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); + return -ENODEV; + } + + info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR); + if (!info->i2c) { + dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n"); + return -ENODEV; + } + + info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg); + if (IS_ERR(info->regmap)) { + ret = PTR_ERR(info->regmap); + dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n", + ret); + goto err; + } + + info->dev = &pdev->dev; + info->s5m87xx = s5m87xx; + info->device_type = s5m87xx->device_type; + info->wtsr_smpl = s5m87xx->wtsr_smpl; + + info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq); + if (info->irq <= 0) { + ret = -EINVAL; + dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n", + alarm_irq); + goto err; + } + + platform_set_drvdata(pdev, info); + + ret = s5m8767_rtc_init_reg(info); + + if (info->wtsr_smpl) { + s5m_rtc_enable_wtsr(info, true); + s5m_rtc_enable_smpl(info, true); + } + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", + &s5m_rtc_ops, THIS_MODULE); + + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + goto err; + } + + ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, + s5m_rtc_alarm_irq, 0, "rtc-alarm0", + info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->irq, ret); + goto err; + } + + return 0; + +err: + i2c_unregister_device(info->i2c); + + return ret; +} + +static void s5m_rtc_shutdown(struct platform_device *pdev) +{ + struct s5m_rtc_info *info = platform_get_drvdata(pdev); + int i; + unsigned int val = 0; + if (info->wtsr_smpl) { + for (i = 0; i < 3; i++) { + s5m_rtc_enable_wtsr(info, false); + regmap_read(info->regmap, info->regs->smpl_wtsr, &val); + pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); + if (val & WTSR_ENABLE_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 */ + s5m_rtc_enable_smpl(info, false); +} + +static int s5m_rtc_remove(struct platform_device *pdev) +{ + struct s5m_rtc_info *info = platform_get_drvdata(pdev); + + /* Perform also all shutdown steps when removing */ + s5m_rtc_shutdown(pdev); + i2c_unregister_device(info->i2c); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int s5m_rtc_resume(struct device *dev) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + int ret = 0; + + if (device_may_wakeup(dev)) + ret = disable_irq_wake(info->irq); + + return ret; +} + +static int s5m_rtc_suspend(struct device *dev) +{ + struct s5m_rtc_info *info = dev_get_drvdata(dev); + int ret = 0; + + if (device_may_wakeup(dev)) + ret = enable_irq_wake(info->irq); + + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); + +static const struct platform_device_id s5m_rtc_id[] = { + { "s5m-rtc", S5M8767X }, + { "s2mps14-rtc", S2MPS14X }, +}; + +static struct platform_driver s5m_rtc_driver = { + .driver = { + .name = "s5m-rtc", + .owner = THIS_MODULE, + .pm = &s5m_rtc_pm_ops, + }, + .probe = s5m_rtc_probe, + .remove = s5m_rtc_remove, + .shutdown = s5m_rtc_shutdown, + .id_table = s5m_rtc_id, +}; + +module_platform_driver(s5m_rtc_driver); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s5m-rtc"); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 00605601dbf..b6e1ca08c2c 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -249,7 +249,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev) ret = clk_prepare_enable(info->clk); if (ret) - goto err_enable_clk; + return ret; /* * 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. @@ -303,8 +303,6 @@ 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); return ret; } @@ -312,10 +310,8 @@ static int sa1100_rtc_remove(struct platform_device *pdev) { struct sa1100_rtc *info = platform_get_drvdata(pdev); - if (info) { + if (info) clk_disable_unprepare(info->clk); - platform_set_drvdata(pdev, NULL); - } return 0; } @@ -342,7 +338,7 @@ static SIMPLE_DEV_PM_OPS(sa1100_rtc_pm_ops, sa1100_rtc_suspend, sa1100_rtc_resume); #ifdef CONFIG_OF -static struct of_device_id sa1100_rtc_dt_ids[] = { +static const struct of_device_id sa1100_rtc_dt_ids[] = { { .compatible = "mrvl,sa1100-rtc", }, { .compatible = "mrvl,mmp-rtc", }, {} diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 8d5bd2e3677..d0d2b047658 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -593,7 +593,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev) char clk_name[6]; int clk_id, ret; - rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (unlikely(!rtc)) return -ENOMEM; @@ -602,9 +602,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev) /* get periodic/carry/alarm irqs */ ret = platform_get_irq(pdev, 0); if (unlikely(ret <= 0)) { - ret = -ENOENT; dev_err(&pdev->dev, "No IRQ resource\n"); - goto err_badres; + return -ENOENT; } rtc->periodic_irq = ret; @@ -613,24 +612,21 @@ static int __init sh_rtc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (unlikely(res == NULL)) { - ret = -ENOENT; dev_err(&pdev->dev, "No IO resource\n"); - goto err_badres; + return -ENOENT; } rtc->regsize = resource_size(res); - rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name); - if (unlikely(!rtc->res)) { - ret = -EBUSY; - goto err_badres; - } + rtc->res = devm_request_mem_region(&pdev->dev, res->start, + rtc->regsize, pdev->name); + if (unlikely(!rtc->res)) + return -EBUSY; - rtc->regbase = ioremap_nocache(rtc->res->start, rtc->regsize); - if (unlikely(!rtc->regbase)) { - ret = -EINVAL; - goto err_badmap; - } + rtc->regbase = devm_ioremap_nocache(&pdev->dev, rtc->res->start, + rtc->regsize); + if (unlikely(!rtc->regbase)) + return -EINVAL; clk_id = pdev->id; /* With a single device, the clock id is still "rtc0" */ @@ -639,7 +635,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev) snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id); - rtc->clk = clk_get(&pdev->dev, clk_name); + rtc->clk = devm_clk_get(&pdev->dev, clk_name); if (IS_ERR(rtc->clk)) { /* * No error handling for rtc->clk intentionally, not all @@ -653,8 +649,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev) clk_enable(rtc->clk); rtc->capabilities = RTC_DEF_CAPABILITIES; - if (pdev->dev.platform_data) { - struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; + if (dev_get_platdata(&pdev->dev)) { + struct sh_rtc_platform_info *pinfo = + dev_get_platdata(&pdev->dev); /* * Some CPUs have special capabilities in addition to the @@ -665,8 +662,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev) if (rtc->carry_irq <= 0) { /* register shared periodic/carry/alarm irq */ - ret = request_irq(rtc->periodic_irq, sh_rtc_shared, - 0, "sh-rtc", rtc); + ret = devm_request_irq(&pdev->dev, rtc->periodic_irq, + sh_rtc_shared, 0, "sh-rtc", rtc); if (unlikely(ret)) { dev_err(&pdev->dev, "request IRQ failed with %d, IRQ %d\n", ret, @@ -675,8 +672,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev) } } else { /* register periodic/carry/alarm irqs */ - ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, - 0, "sh-rtc period", rtc); + ret = devm_request_irq(&pdev->dev, rtc->periodic_irq, + sh_rtc_periodic, 0, "sh-rtc period", rtc); if (unlikely(ret)) { dev_err(&pdev->dev, "request period IRQ failed with %d, IRQ %d\n", @@ -684,24 +681,21 @@ static int __init sh_rtc_probe(struct platform_device *pdev) goto err_unmap; } - ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, - 0, "sh-rtc carry", rtc); + ret = devm_request_irq(&pdev->dev, rtc->carry_irq, + sh_rtc_interrupt, 0, "sh-rtc carry", rtc); if (unlikely(ret)) { dev_err(&pdev->dev, "request carry IRQ failed with %d, IRQ %d\n", ret, rtc->carry_irq); - free_irq(rtc->periodic_irq, rtc); goto err_unmap; } - ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, - 0, "sh-rtc alarm", rtc); + ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, + sh_rtc_alarm, 0, "sh-rtc alarm", rtc); if (unlikely(ret)) { dev_err(&pdev->dev, "request alarm IRQ failed with %d, IRQ %d\n", ret, rtc->alarm_irq); - free_irq(rtc->carry_irq, rtc); - free_irq(rtc->periodic_irq, rtc); goto err_unmap; } } @@ -714,13 +708,10 @@ static int __init sh_rtc_probe(struct platform_device *pdev) sh_rtc_setaie(&pdev->dev, 0); sh_rtc_setcie(&pdev->dev, 0); - rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, + rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "sh", &sh_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc_dev)) { ret = PTR_ERR(rtc->rtc_dev); - free_irq(rtc->periodic_irq, rtc); - free_irq(rtc->carry_irq, rtc); - free_irq(rtc->alarm_irq, rtc); goto err_unmap; } @@ -737,12 +728,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) err_unmap: clk_disable(rtc->clk); - clk_put(rtc->clk); - iounmap(rtc->regbase); -err_badmap: - release_mem_region(rtc->res->start, rtc->regsize); -err_badres: - kfree(rtc); return ret; } @@ -751,28 +736,12 @@ static int __exit sh_rtc_remove(struct platform_device *pdev) { struct sh_rtc *rtc = platform_get_drvdata(pdev); - rtc_device_unregister(rtc->rtc_dev); sh_rtc_irq_set_state(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); sh_rtc_setcie(&pdev->dev, 0); - free_irq(rtc->periodic_irq, rtc); - - if (rtc->carry_irq > 0) { - free_irq(rtc->carry_irq, rtc); - free_irq(rtc->alarm_irq, rtc); - } - - iounmap(rtc->regbase); - release_mem_region(rtc->res->start, rtc->regsize); - clk_disable(rtc->clk); - clk_put(rtc->clk); - - platform_set_drvdata(pdev, NULL); - - kfree(rtc); return 0; } diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c new file mode 100644 index 00000000000..76e38007ba9 --- /dev/null +++ b/drivers/rtc/rtc-sirfsoc.c @@ -0,0 +1,423 @@ +/* + * SiRFSoC Real Time Clock interface for Linux + * + * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/rtc/sirfsoc_rtciobrg.h> + + +#define RTC_CN 0x00 +#define RTC_ALARM0 0x04 +#define RTC_ALARM1 0x18 +#define RTC_STATUS 0x08 +#define RTC_SW_VALUE 0x40 +#define SIRFSOC_RTC_AL1E (1<<6) +#define SIRFSOC_RTC_AL1 (1<<4) +#define SIRFSOC_RTC_HZE (1<<3) +#define SIRFSOC_RTC_AL0E (1<<2) +#define SIRFSOC_RTC_HZ (1<<1) +#define SIRFSOC_RTC_AL0 (1<<0) +#define RTC_DIV 0x0c +#define RTC_DEEP_CTRL 0x14 +#define RTC_CLOCK_SWITCH 0x1c +#define SIRFSOC_RTC_CLK 0x03 /* others are reserved */ + +/* Refer to RTC DIV switch */ +#define RTC_HZ 16 + +/* This macro is also defined in arch/arm/plat-sirfsoc/cpu.c */ +#define RTC_SHIFT 4 + +#define INTR_SYSRTC_CN 0x48 + +struct sirfsoc_rtc_drv { + struct rtc_device *rtc; + u32 rtc_base; + u32 irq; + unsigned irq_wake; + /* Overflow for every 8 years extra time */ + u32 overflow_rtc; +#ifdef CONFIG_PM + u32 saved_counter; + u32 saved_overflow_rtc; +#endif +}; + +static int sirfsoc_rtc_read_alarm(struct device *dev, + struct rtc_wkalrm *alrm) +{ + unsigned long rtc_alarm, rtc_count; + struct sirfsoc_rtc_drv *rtcdrv; + + rtcdrv = dev_get_drvdata(dev); + + local_irq_disable(); + + rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + + rtc_alarm = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_ALARM0); + memset(alrm, 0, sizeof(struct rtc_wkalrm)); + + /* + * assume alarm interval not beyond one round counter overflow_rtc: + * 0->0xffffffff + */ + /* if alarm is in next overflow cycle */ + if (rtc_count > rtc_alarm) + rtc_time_to_tm((rtcdrv->overflow_rtc + 1) + << (BITS_PER_LONG - RTC_SHIFT) + | rtc_alarm >> RTC_SHIFT, &(alrm->time)); + else + rtc_time_to_tm(rtcdrv->overflow_rtc + << (BITS_PER_LONG - RTC_SHIFT) + | rtc_alarm >> RTC_SHIFT, &(alrm->time)); + if (sirfsoc_rtc_iobrg_readl( + rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E) + alrm->enabled = 1; + local_irq_enable(); + + return 0; +} + +static int sirfsoc_rtc_set_alarm(struct device *dev, + struct rtc_wkalrm *alrm) +{ + unsigned long rtc_status_reg, rtc_alarm; + struct sirfsoc_rtc_drv *rtcdrv; + rtcdrv = dev_get_drvdata(dev); + + if (alrm->enabled) { + rtc_tm_to_time(&(alrm->time), &rtc_alarm); + + local_irq_disable(); + + rtc_status_reg = sirfsoc_rtc_iobrg_readl( + rtcdrv->rtc_base + RTC_STATUS); + if (rtc_status_reg & SIRFSOC_RTC_AL0E) { + /* + * An ongoing alarm in progress - ingore it and not + * to return EBUSY + */ + dev_info(dev, "An old alarm was set, will be replaced by a new one\n"); + } + + sirfsoc_rtc_iobrg_writel( + rtc_alarm << RTC_SHIFT, rtcdrv->rtc_base + RTC_ALARM0); + rtc_status_reg &= ~0x07; /* mask out the lower status bits */ + /* + * This bit RTC_AL sets it as a wake-up source for Sleep Mode + * Writing 1 into this bit will clear it + */ + rtc_status_reg |= SIRFSOC_RTC_AL0; + /* enable the RTC alarm interrupt */ + rtc_status_reg |= SIRFSOC_RTC_AL0E; + sirfsoc_rtc_iobrg_writel( + rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + local_irq_enable(); + } else { + /* + * if this function was called with enabled=0 + * then it could mean that the application is + * trying to cancel an ongoing alarm + */ + local_irq_disable(); + + rtc_status_reg = sirfsoc_rtc_iobrg_readl( + rtcdrv->rtc_base + RTC_STATUS); + if (rtc_status_reg & SIRFSOC_RTC_AL0E) { + /* clear the RTC status register's alarm bit */ + rtc_status_reg &= ~0x07; + /* write 1 into SIRFSOC_RTC_AL0 to force a clear */ + rtc_status_reg |= (SIRFSOC_RTC_AL0); + /* Clear the Alarm enable bit */ + rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); + + sirfsoc_rtc_iobrg_writel(rtc_status_reg, + rtcdrv->rtc_base + RTC_STATUS); + } + + local_irq_enable(); + } + + return 0; +} + +static int sirfsoc_rtc_read_time(struct device *dev, + struct rtc_time *tm) +{ + unsigned long tmp_rtc = 0; + struct sirfsoc_rtc_drv *rtcdrv; + rtcdrv = dev_get_drvdata(dev); + /* + * This patch is taken from WinCE - Need to validate this for + * correctness. To work around sirfsoc RTC counter double sync logic + * fail, read several times to make sure get stable value. + */ + do { + tmp_rtc = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + cpu_relax(); + } while (tmp_rtc != sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN)); + + rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | + tmp_rtc >> RTC_SHIFT, tm); + return 0; +} + +static int sirfsoc_rtc_set_time(struct device *dev, + struct rtc_time *tm) +{ + unsigned long rtc_time; + struct sirfsoc_rtc_drv *rtcdrv; + rtcdrv = dev_get_drvdata(dev); + + rtc_tm_to_time(tm, &rtc_time); + + rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT); + + sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, + rtcdrv->rtc_base + RTC_SW_VALUE); + sirfsoc_rtc_iobrg_writel( + rtc_time << RTC_SHIFT, rtcdrv->rtc_base + RTC_CN); + + return 0; +} + +static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case RTC_PIE_ON: + case RTC_PIE_OFF: + case RTC_UIE_ON: + case RTC_UIE_OFF: + case RTC_AIE_ON: + case RTC_AIE_OFF: + return 0; + + default: + return -ENOIOCTLCMD; + } +} + +static const struct rtc_class_ops sirfsoc_rtc_ops = { + .read_time = sirfsoc_rtc_read_time, + .set_time = sirfsoc_rtc_set_time, + .read_alarm = sirfsoc_rtc_read_alarm, + .set_alarm = sirfsoc_rtc_set_alarm, + .ioctl = sirfsoc_rtc_ioctl +}; + +static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) +{ + struct sirfsoc_rtc_drv *rtcdrv = pdata; + unsigned long rtc_status_reg = 0x0; + unsigned long events = 0x0; + + rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS); + /* this bit will be set ONLY if an alarm was active + * and it expired NOW + * So this is being used as an ASSERT + */ + if (rtc_status_reg & SIRFSOC_RTC_AL0) { + /* + * clear the RTC status register's alarm bit + * mask out the lower status bits + */ + rtc_status_reg &= ~0x07; + /* write 1 into SIRFSOC_RTC_AL0 to ACK the alarm interrupt */ + rtc_status_reg |= (SIRFSOC_RTC_AL0); + /* Clear the Alarm enable bit */ + rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); + } + sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + /* this should wake up any apps polling/waiting on the read + * after setting the alarm + */ + events |= RTC_IRQF | RTC_AF; + rtc_update_irq(rtcdrv->rtc, 1, events); + + return IRQ_HANDLED; +} + +static const struct of_device_id sirfsoc_rtc_of_match[] = { + { .compatible = "sirf,prima2-sysrtc"}, + {}, +}; +MODULE_DEVICE_TABLE(of, sirfsoc_rtc_of_match); + +static int sirfsoc_rtc_probe(struct platform_device *pdev) +{ + int err; + unsigned long rtc_div; + struct sirfsoc_rtc_drv *rtcdrv; + struct device_node *np = pdev->dev.of_node; + + rtcdrv = devm_kzalloc(&pdev->dev, + sizeof(struct sirfsoc_rtc_drv), GFP_KERNEL); + if (rtcdrv == NULL) + return -ENOMEM; + + err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base); + if (err) { + dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n"); + return err; + } + + platform_set_drvdata(pdev, rtcdrv); + + /* Register rtc alarm as a wakeup source */ + device_init_wakeup(&pdev->dev, 1); + + /* + * Set SYS_RTC counter in RTC_HZ HZ Units + * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 + * If 16HZ, therefore RTC_DIV = 1023; + */ + rtc_div = ((32768 / RTC_HZ) / 2) - 1; + sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); + + rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &sirfsoc_rtc_ops, THIS_MODULE); + if (IS_ERR(rtcdrv->rtc)) { + err = PTR_ERR(rtcdrv->rtc); + dev_err(&pdev->dev, "can't register RTC device\n"); + return err; + } + + /* 0x3 -> RTC_CLK */ + sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, + rtcdrv->rtc_base + RTC_CLOCK_SWITCH); + + /* reset SYS RTC ALARM0 */ + sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0); + + /* reset SYS RTC ALARM1 */ + sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1); + + /* Restore RTC Overflow From Register After Command Reboot */ + rtcdrv->overflow_rtc = + sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); + + rtcdrv->irq = platform_get_irq(pdev, 0); + err = devm_request_irq( + &pdev->dev, + rtcdrv->irq, + sirfsoc_rtc_irq_handler, + IRQF_SHARED, + pdev->name, + rtcdrv); + if (err) { + dev_err(&pdev->dev, "Unable to register for the SiRF SOC RTC IRQ\n"); + return err; + } + + return 0; +} + +static int sirfsoc_rtc_remove(struct platform_device *pdev) +{ + device_init_wakeup(&pdev->dev, 0); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int sirfsoc_rtc_suspend(struct device *dev) +{ + struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); + rtcdrv->overflow_rtc = + sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); + + rtcdrv->saved_counter = + sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; + if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq)) + rtcdrv->irq_wake = 1; + + return 0; +} + +static int sirfsoc_rtc_resume(struct device *dev) +{ + u32 tmp; + struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); + + /* + * if resume from snapshot and the rtc power is lost, + * restroe the rtc settings + */ + if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl( + rtcdrv->rtc_base + RTC_CLOCK_SWITCH)) { + u32 rtc_div; + /* 0x3 -> RTC_CLK */ + sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, + rtcdrv->rtc_base + RTC_CLOCK_SWITCH); + /* + * Set SYS_RTC counter in RTC_HZ HZ Units + * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 + * If 16HZ, therefore RTC_DIV = 1023; + */ + rtc_div = ((32768 / RTC_HZ) / 2) - 1; + + sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); + + /* reset SYS RTC ALARM0 */ + sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0); + + /* reset SYS RTC ALARM1 */ + sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1); + } + rtcdrv->overflow_rtc = rtcdrv->saved_overflow_rtc; + + /* + * if current counter is small than previous, + * it means overflow in sleep + */ + tmp = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + if (tmp <= rtcdrv->saved_counter) + rtcdrv->overflow_rtc++; + /* + *PWRC Value Be Changed When Suspend, Restore Overflow + * In Memory To Register + */ + sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, + rtcdrv->rtc_base + RTC_SW_VALUE); + + if (device_may_wakeup(dev) && rtcdrv->irq_wake) { + disable_irq_wake(rtcdrv->irq); + rtcdrv->irq_wake = 0; + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops, + sirfsoc_rtc_suspend, sirfsoc_rtc_resume); + +static struct platform_driver sirfsoc_rtc_driver = { + .driver = { + .name = "sirfsoc-rtc", + .owner = THIS_MODULE, + .pm = &sirfsoc_rtc_pm_ops, + .of_match_table = sirfsoc_rtc_of_match, + }, + .probe = sirfsoc_rtc_probe, + .remove = sirfsoc_rtc_remove, +}; +module_platform_driver(sirfsoc_rtc_driver); + +MODULE_DESCRIPTION("SiRF SoC rtc driver"); +MODULE_AUTHOR("Xianglong Du <Xianglong.Du@csr.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sirfsoc-rtc"); diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index b04f09a1df2..fa384fe2898 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -294,11 +294,6 @@ static int snvs_rtc_probe(struct platform_device *pdev) return 0; } -static int snvs_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - #ifdef CONFIG_PM_SLEEP static int snvs_rtc_suspend(struct device *dev) { @@ -334,10 +329,9 @@ static struct platform_driver snvs_rtc_driver = { .name = "snvs_rtc", .owner = THIS_MODULE, .pm = &snvs_rtc_pm_ops, - .of_match_table = of_match_ptr(snvs_dt_ids), + .of_match_table = snvs_dt_ids, }, .probe = snvs_rtc_probe, - .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 574359c48f6..d2cdb9823a1 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -365,10 +365,8 @@ static int spear_rtc_probe(struct platform_device *pdev) } config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); - if (!config) { - dev_err(&pdev->dev, "out of memory\n"); + if (!config) return -ENOMEM; - } /* alarm irqs */ irq = platform_get_irq(pdev, 0); @@ -417,7 +415,6 @@ static int spear_rtc_probe(struct platform_device *pdev) return 0; err_disable_clock: - platform_set_drvdata(pdev, NULL); clk_disable_unprepare(config->clk); return status; diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c index 987b5ec0ae5..f7d8a6db807 100644 --- a/drivers/rtc/rtc-starfire.c +++ b/drivers/rtc/rtc-starfire.c @@ -51,17 +51,11 @@ static int __init starfire_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit starfire_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver starfire_rtc_driver = { .driver = { .name = "rtc-starfire", .owner = THIS_MODULE, }, - .remove = __exit_p(starfire_rtc_remove), }; module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe); diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index af5e97e3f27..35ed49ea1f8 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -214,8 +214,7 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id) events |= RTC_UF; else events |= RTC_AF; - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); + rtc_update_irq(pdata->rtc, 1, events); } spin_unlock(&pdata->lock); return events ? IRQ_HANDLED : IRQ_NONE; @@ -294,19 +293,14 @@ static int stk17ta8_rtc_probe(struct platform_device *pdev) void __iomem *ioaddr; int ret = 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, - pdev->name)) - return -EBUSY; - ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); - if (!ioaddr) - return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ioaddr)) + return PTR_ERR(ioaddr); pdata->ioaddr = ioaddr; pdata->irq = platform_get_irq(pdev, 0); diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 483ce086990..ea96492357b 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/delay.h> #include <linux/rtc.h> #include <linux/slab.h> #include <linux/of_device.h> @@ -119,24 +120,39 @@ 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) +static int stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) { + int timeout = 5000; /* 3ms according to i.MX28 Ref Manual */ /* - * The datasheet doesn't say which way round the - * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, - * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS + * The i.MX28 Applications Processor Reference Manual, Rev. 1, 2010 + * states: + * | The order in which registers are updated is + * | Persistent 0, 1, 2, 3, 4, 5, Alarm, Seconds. + * | (This list is in bitfield order, from LSB to MSB, as they would + * | appear in the STALE_REGS and NEW_REGS bitfields of the HW_RTC_STAT + * | register. For example, the Seconds register corresponds to + * | STALE_REGS or NEW_REGS containing 0x80.) */ - while (readl(rtc_data->io + STMP3XXX_RTC_STAT) & - (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) - cpu_relax(); + do { + if (!(readl(rtc_data->io + STMP3XXX_RTC_STAT) & + (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT))) + return 0; + udelay(1); + } while (--timeout > 0); + return (readl(rtc_data->io + STMP3XXX_RTC_STAT) & + (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) ? -ETIME : 0; } /* Time read/write */ static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { + int ret; struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - stmp3xxx_wait_time(rtc_data); + ret = stmp3xxx_wait_time(rtc_data); + if (ret) + return ret; + rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm); return 0; } @@ -146,8 +162,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); - stmp3xxx_wait_time(rtc_data); - return 0; + return stmp3xxx_wait_time(rtc_data); } /* interrupt(s) handler */ @@ -225,7 +240,6 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, rtc_data->io + STMP3XXX_RTC_CTRL_CLR); - platform_set_drvdata(pdev, NULL); return 0; } @@ -262,7 +276,12 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc_data); - stmp_reset_block(rtc_data->io); + err = stmp_reset_block(rtc_data->io); + if (err) { + dev_err(&pdev->dev, "stmp_reset_block failed: %d\n", err); + return err; + } + writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, @@ -274,25 +293,19 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) rtc_data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &stmp3xxx_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc_data->rtc)) { - err = PTR_ERR(rtc_data->rtc); - goto out; - } + if (IS_ERR(rtc_data->rtc)) + return PTR_ERR(rtc_data->rtc); err = devm_request_irq(&pdev->dev, rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, 0, "RTC alarm", &pdev->dev); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ%d\n", rtc_data->irq_alarm); - goto out; + return err; } stmp3xxx_wdt_register(pdev); return 0; - -out: - platform_set_drvdata(pdev, NULL); - return err; } #ifdef CONFIG_PM_SLEEP @@ -330,7 +343,7 @@ static struct platform_driver stmp3xxx_rtcdrv = { .name = "stmp3xxx-rtc", .owner = THIS_MODULE, .pm = &stmp3xxx_rtc_pm_ops, - .of_match_table = of_match_ptr(rtc_dt_ids), + .of_match_table = rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c index ce42e5fa9e0..bc97ff91341 100644 --- a/drivers/rtc/rtc-sun4v.c +++ b/drivers/rtc/rtc-sun4v.c @@ -92,17 +92,11 @@ static int __init sun4v_rtc_probe(struct platform_device *pdev) return 0; } -static int __exit sun4v_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver sun4v_rtc_driver = { .driver = { .name = "rtc-sun4v", .owner = THIS_MODULE, }, - .remove = __exit_p(sun4v_rtc_remove), }; module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe); diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c new file mode 100644 index 00000000000..b6f21f73d50 --- /dev/null +++ b/drivers/rtc/rtc-sunxi.c @@ -0,0 +1,523 @@ +/* + * An RTC driver for Allwinner A10/A20 + * + * Copyright (c) 2013, Carlo Caione <carlo.caione@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/types.h> + +#define SUNXI_LOSC_CTRL 0x0000 +#define SUNXI_LOSC_CTRL_RTC_HMS_ACC BIT(8) +#define SUNXI_LOSC_CTRL_RTC_YMD_ACC BIT(7) + +#define SUNXI_RTC_YMD 0x0004 + +#define SUNXI_RTC_HMS 0x0008 + +#define SUNXI_ALRM_DHMS 0x000c + +#define SUNXI_ALRM_EN 0x0014 +#define SUNXI_ALRM_EN_CNT_EN BIT(8) + +#define SUNXI_ALRM_IRQ_EN 0x0018 +#define SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN BIT(0) + +#define SUNXI_ALRM_IRQ_STA 0x001c +#define SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND BIT(0) + +#define SUNXI_MASK_DH 0x0000001f +#define SUNXI_MASK_SM 0x0000003f +#define SUNXI_MASK_M 0x0000000f +#define SUNXI_MASK_LY 0x00000001 +#define SUNXI_MASK_D 0x00000ffe +#define SUNXI_MASK_M 0x0000000f + +#define SUNXI_GET(x, mask, shift) (((x) & ((mask) << (shift))) \ + >> (shift)) + +#define SUNXI_SET(x, mask, shift) (((x) & (mask)) << (shift)) + +/* + * Get date values + */ +#define SUNXI_DATE_GET_DAY_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 0) +#define SUNXI_DATE_GET_MON_VALUE(x) SUNXI_GET(x, SUNXI_MASK_M, 8) +#define SUNXI_DATE_GET_YEAR_VALUE(x, mask) SUNXI_GET(x, mask, 16) + +/* + * Get time values + */ +#define SUNXI_TIME_GET_SEC_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 0) +#define SUNXI_TIME_GET_MIN_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 8) +#define SUNXI_TIME_GET_HOUR_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 16) + +/* + * Get alarm values + */ +#define SUNXI_ALRM_GET_SEC_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 0) +#define SUNXI_ALRM_GET_MIN_VALUE(x) SUNXI_GET(x, SUNXI_MASK_SM, 8) +#define SUNXI_ALRM_GET_HOUR_VALUE(x) SUNXI_GET(x, SUNXI_MASK_DH, 16) + +/* + * Set date values + */ +#define SUNXI_DATE_SET_DAY_VALUE(x) SUNXI_DATE_GET_DAY_VALUE(x) +#define SUNXI_DATE_SET_MON_VALUE(x) SUNXI_SET(x, SUNXI_MASK_M, 8) +#define SUNXI_DATE_SET_YEAR_VALUE(x, mask) SUNXI_SET(x, mask, 16) +#define SUNXI_LEAP_SET_VALUE(x, shift) SUNXI_SET(x, SUNXI_MASK_LY, shift) + +/* + * Set time values + */ +#define SUNXI_TIME_SET_SEC_VALUE(x) SUNXI_TIME_GET_SEC_VALUE(x) +#define SUNXI_TIME_SET_MIN_VALUE(x) SUNXI_SET(x, SUNXI_MASK_SM, 8) +#define SUNXI_TIME_SET_HOUR_VALUE(x) SUNXI_SET(x, SUNXI_MASK_DH, 16) + +/* + * Set alarm values + */ +#define SUNXI_ALRM_SET_SEC_VALUE(x) SUNXI_ALRM_GET_SEC_VALUE(x) +#define SUNXI_ALRM_SET_MIN_VALUE(x) SUNXI_SET(x, SUNXI_MASK_SM, 8) +#define SUNXI_ALRM_SET_HOUR_VALUE(x) SUNXI_SET(x, SUNXI_MASK_DH, 16) +#define SUNXI_ALRM_SET_DAY_VALUE(x) SUNXI_SET(x, SUNXI_MASK_D, 21) + +/* + * Time unit conversions + */ +#define SEC_IN_MIN 60 +#define SEC_IN_HOUR (60 * SEC_IN_MIN) +#define SEC_IN_DAY (24 * SEC_IN_HOUR) + +/* + * The year parameter passed to the driver is usually an offset relative to + * the year 1900. This macro is used to convert this offset to another one + * relative to the minimum year allowed by the hardware. + */ +#define SUNXI_YEAR_OFF(x) ((x)->min - 1900) + +/* + * min and max year are arbitrary set considering the limited range of the + * hardware register field + */ +struct sunxi_rtc_data_year { + unsigned int min; /* min year allowed */ + unsigned int max; /* max year allowed */ + unsigned int mask; /* mask for the year field */ + unsigned char leap_shift; /* bit shift to get the leap year */ +}; + +static struct sunxi_rtc_data_year data_year_param[] = { + [0] = { + .min = 2010, + .max = 2073, + .mask = 0x3f, + .leap_shift = 22, + }, + [1] = { + .min = 1970, + .max = 2225, + .mask = 0xff, + .leap_shift = 24, + }, +}; + +struct sunxi_rtc_dev { + struct rtc_device *rtc; + struct device *dev; + struct sunxi_rtc_data_year *data_year; + void __iomem *base; + int irq; +}; + +static irqreturn_t sunxi_rtc_alarmirq(int irq, void *id) +{ + struct sunxi_rtc_dev *chip = (struct sunxi_rtc_dev *) id; + u32 val; + + val = readl(chip->base + SUNXI_ALRM_IRQ_STA); + + if (val & SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND) { + val |= SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND; + writel(val, chip->base + SUNXI_ALRM_IRQ_STA); + + rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static void sunxi_rtc_setaie(int to, struct sunxi_rtc_dev *chip) +{ + u32 alrm_val = 0; + u32 alrm_irq_val = 0; + + if (to) { + alrm_val = readl(chip->base + SUNXI_ALRM_EN); + alrm_val |= SUNXI_ALRM_EN_CNT_EN; + + alrm_irq_val = readl(chip->base + SUNXI_ALRM_IRQ_EN); + alrm_irq_val |= SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN; + } else { + writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, + chip->base + SUNXI_ALRM_IRQ_STA); + } + + writel(alrm_val, chip->base + SUNXI_ALRM_EN); + writel(alrm_irq_val, chip->base + SUNXI_ALRM_IRQ_EN); +} + +static int sunxi_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); + struct rtc_time *alrm_tm = &wkalrm->time; + u32 alrm; + u32 alrm_en; + u32 date; + + alrm = readl(chip->base + SUNXI_ALRM_DHMS); + date = readl(chip->base + SUNXI_RTC_YMD); + + alrm_tm->tm_sec = SUNXI_ALRM_GET_SEC_VALUE(alrm); + alrm_tm->tm_min = SUNXI_ALRM_GET_MIN_VALUE(alrm); + alrm_tm->tm_hour = SUNXI_ALRM_GET_HOUR_VALUE(alrm); + + alrm_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); + alrm_tm->tm_mon = SUNXI_DATE_GET_MON_VALUE(date); + alrm_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, + chip->data_year->mask); + + alrm_tm->tm_mon -= 1; + + /* + * switch from (data_year->min)-relative offset to + * a (1900)-relative one + */ + alrm_tm->tm_year += SUNXI_YEAR_OFF(chip->data_year); + + alrm_en = readl(chip->base + SUNXI_ALRM_IRQ_EN); + if (alrm_en & SUNXI_ALRM_EN_CNT_EN) + wkalrm->enabled = 1; + + return 0; +} + +static int sunxi_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +{ + struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); + u32 date, time; + + /* + * read again in case it changes + */ + do { + date = readl(chip->base + SUNXI_RTC_YMD); + time = readl(chip->base + SUNXI_RTC_HMS); + } while ((date != readl(chip->base + SUNXI_RTC_YMD)) || + (time != readl(chip->base + SUNXI_RTC_HMS))); + + rtc_tm->tm_sec = SUNXI_TIME_GET_SEC_VALUE(time); + rtc_tm->tm_min = SUNXI_TIME_GET_MIN_VALUE(time); + rtc_tm->tm_hour = SUNXI_TIME_GET_HOUR_VALUE(time); + + rtc_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); + rtc_tm->tm_mon = SUNXI_DATE_GET_MON_VALUE(date); + rtc_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, + chip->data_year->mask); + + rtc_tm->tm_mon -= 1; + + /* + * switch from (data_year->min)-relative offset to + * a (1900)-relative one + */ + rtc_tm->tm_year += SUNXI_YEAR_OFF(chip->data_year); + + return rtc_valid_tm(rtc_tm); +} + +static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); + struct rtc_time *alrm_tm = &wkalrm->time; + struct rtc_time tm_now; + u32 alrm = 0; + unsigned long time_now = 0; + unsigned long time_set = 0; + unsigned long time_gap = 0; + unsigned long time_gap_day = 0; + unsigned long time_gap_hour = 0; + unsigned long time_gap_min = 0; + int ret = 0; + + ret = sunxi_rtc_gettime(dev, &tm_now); + if (ret < 0) { + dev_err(dev, "Error in getting time\n"); + return -EINVAL; + } + + rtc_tm_to_time(alrm_tm, &time_set); + rtc_tm_to_time(&tm_now, &time_now); + if (time_set <= time_now) { + dev_err(dev, "Date to set in the past\n"); + return -EINVAL; + } + + time_gap = time_set - time_now; + time_gap_day = time_gap / SEC_IN_DAY; + time_gap -= time_gap_day * SEC_IN_DAY; + time_gap_hour = time_gap / SEC_IN_HOUR; + time_gap -= time_gap_hour * SEC_IN_HOUR; + time_gap_min = time_gap / SEC_IN_MIN; + time_gap -= time_gap_min * SEC_IN_MIN; + + if (time_gap_day > 255) { + dev_err(dev, "Day must be in the range 0 - 255\n"); + return -EINVAL; + } + + sunxi_rtc_setaie(0, chip); + writel(0, chip->base + SUNXI_ALRM_DHMS); + usleep_range(100, 300); + + alrm = SUNXI_ALRM_SET_SEC_VALUE(time_gap) | + SUNXI_ALRM_SET_MIN_VALUE(time_gap_min) | + SUNXI_ALRM_SET_HOUR_VALUE(time_gap_hour) | + SUNXI_ALRM_SET_DAY_VALUE(time_gap_day); + writel(alrm, chip->base + SUNXI_ALRM_DHMS); + + writel(0, chip->base + SUNXI_ALRM_IRQ_EN); + writel(SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN, chip->base + SUNXI_ALRM_IRQ_EN); + + sunxi_rtc_setaie(wkalrm->enabled, chip); + + return 0; +} + +static int sunxi_rtc_wait(struct sunxi_rtc_dev *chip, int offset, + unsigned int mask, unsigned int ms_timeout) +{ + const unsigned long timeout = jiffies + msecs_to_jiffies(ms_timeout); + u32 reg; + + do { + reg = readl(chip->base + offset); + reg &= mask; + + if (reg == mask) + return 0; + + } while (time_before(jiffies, timeout)); + + return -ETIMEDOUT; +} + +static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) +{ + struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); + u32 date = 0; + u32 time = 0; + int year; + + /* + * the input rtc_tm->tm_year is the offset relative to 1900. We use + * the SUNXI_YEAR_OFF macro to rebase it with respect to the min year + * allowed by the hardware + */ + + year = rtc_tm->tm_year + 1900; + if (year < chip->data_year->min || year > chip->data_year->max) { + dev_err(dev, "rtc only supports year in range %d - %d\n", + chip->data_year->min, chip->data_year->max); + return -EINVAL; + } + + rtc_tm->tm_year -= SUNXI_YEAR_OFF(chip->data_year); + rtc_tm->tm_mon += 1; + + date = SUNXI_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | + SUNXI_DATE_SET_MON_VALUE(rtc_tm->tm_mon) | + SUNXI_DATE_SET_YEAR_VALUE(rtc_tm->tm_year, + chip->data_year->mask); + + if (is_leap_year(year)) + date |= SUNXI_LEAP_SET_VALUE(1, chip->data_year->leap_shift); + + time = SUNXI_TIME_SET_SEC_VALUE(rtc_tm->tm_sec) | + SUNXI_TIME_SET_MIN_VALUE(rtc_tm->tm_min) | + SUNXI_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); + + writel(0, chip->base + SUNXI_RTC_HMS); + writel(0, chip->base + SUNXI_RTC_YMD); + + writel(time, chip->base + SUNXI_RTC_HMS); + + /* + * After writing the RTC HH-MM-SS register, the + * SUNXI_LOSC_CTRL_RTC_HMS_ACC bit is set and it will not + * be cleared until the real writing operation is finished + */ + + if (sunxi_rtc_wait(chip, SUNXI_LOSC_CTRL, + SUNXI_LOSC_CTRL_RTC_HMS_ACC, 50)) { + dev_err(dev, "Failed to set rtc time.\n"); + return -1; + } + + writel(date, chip->base + SUNXI_RTC_YMD); + + /* + * After writing the RTC YY-MM-DD register, the + * SUNXI_LOSC_CTRL_RTC_YMD_ACC bit is set and it will not + * be cleared until the real writing operation is finished + */ + + if (sunxi_rtc_wait(chip, SUNXI_LOSC_CTRL, + SUNXI_LOSC_CTRL_RTC_YMD_ACC, 50)) { + dev_err(dev, "Failed to set rtc time.\n"); + return -1; + } + + return 0; +} + +static int sunxi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); + + if (!enabled) + sunxi_rtc_setaie(enabled, chip); + + return 0; +} + +static const struct rtc_class_ops sunxi_rtc_ops = { + .read_time = sunxi_rtc_gettime, + .set_time = sunxi_rtc_settime, + .read_alarm = sunxi_rtc_getalarm, + .set_alarm = sunxi_rtc_setalarm, + .alarm_irq_enable = sunxi_rtc_alarm_irq_enable +}; + +static const struct of_device_id sunxi_rtc_dt_ids[] = { + { .compatible = "allwinner,sun4i-a10-rtc", .data = &data_year_param[0] }, + { .compatible = "allwinner,sun7i-a20-rtc", .data = &data_year_param[1] }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, sunxi_rtc_dt_ids); + +static int sunxi_rtc_probe(struct platform_device *pdev) +{ + struct sunxi_rtc_dev *chip; + struct resource *res; + const struct of_device_id *of_id; + int ret; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + platform_set_drvdata(pdev, chip); + chip->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + + chip->irq = platform_get_irq(pdev, 0); + if (chip->irq < 0) { + dev_err(&pdev->dev, "No IRQ resource\n"); + return chip->irq; + } + ret = devm_request_irq(&pdev->dev, chip->irq, sunxi_rtc_alarmirq, + 0, dev_name(&pdev->dev), chip); + if (ret) { + dev_err(&pdev->dev, "Could not request IRQ\n"); + return ret; + } + + of_id = of_match_device(sunxi_rtc_dt_ids, &pdev->dev); + if (!of_id) { + dev_err(&pdev->dev, "Unable to setup RTC data\n"); + return -ENODEV; + } + chip->data_year = (struct sunxi_rtc_data_year *) of_id->data; + + /* clear the alarm count value */ + writel(0, chip->base + SUNXI_ALRM_DHMS); + + /* disable alarm, not generate irq pending */ + writel(0, chip->base + SUNXI_ALRM_EN); + + /* disable alarm week/cnt irq, unset to cpu */ + writel(0, chip->base + SUNXI_ALRM_IRQ_EN); + + /* clear alarm week/cnt irq pending */ + writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, chip->base + + SUNXI_ALRM_IRQ_STA); + + chip->rtc = rtc_device_register("rtc-sunxi", &pdev->dev, + &sunxi_rtc_ops, THIS_MODULE); + if (IS_ERR(chip->rtc)) { + dev_err(&pdev->dev, "unable to register device\n"); + return PTR_ERR(chip->rtc); + } + + dev_info(&pdev->dev, "RTC enabled\n"); + + return 0; +} + +static int sunxi_rtc_remove(struct platform_device *pdev) +{ + struct sunxi_rtc_dev *chip = platform_get_drvdata(pdev); + + rtc_device_unregister(chip->rtc); + + return 0; +} + +static struct platform_driver sunxi_rtc_driver = { + .probe = sunxi_rtc_probe, + .remove = sunxi_rtc_remove, + .driver = { + .name = "sunxi-rtc", + .owner = THIS_MODULE, + .of_match_table = sunxi_rtc_dt_ids, + }, +}; + +module_platform_driver(sunxi_rtc_driver); + +MODULE_DESCRIPTION("sunxi RTC driver"); +MODULE_AUTHOR("Carlo Caione <carlo.caione@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index b70e2bb6364..babd43bf3dd 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -25,15 +25,14 @@ */ static ssize_t -rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr, - char *buf) +name_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", to_rtc_device(dev)->name); } +static DEVICE_ATTR_RO(name); static ssize_t -rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr, - char *buf) +date_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; struct rtc_time tm; @@ -46,10 +45,10 @@ rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr, return retval; } +static DEVICE_ATTR_RO(date); static ssize_t -rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr, - char *buf) +time_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; struct rtc_time tm; @@ -62,10 +61,10 @@ rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr, return retval; } +static DEVICE_ATTR_RO(time); static ssize_t -rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr, - char *buf) +since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; struct rtc_time tm; @@ -79,16 +78,16 @@ rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr, return retval; } +static DEVICE_ATTR_RO(since_epoch); static ssize_t -rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr, - char *buf) +max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); } static ssize_t -rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, +max_user_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { struct rtc_device *rtc = to_rtc_device(dev); @@ -101,6 +100,7 @@ rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, return n; } +static DEVICE_ATTR_RW(max_user_freq); /** * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time @@ -109,8 +109,7 @@ rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, * boot or resume event. */ static ssize_t -rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, - char *buf) +hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) { #ifdef CONFIG_RTC_HCTOSYS_DEVICE if (rtc_hctosys_ret == 0 && @@ -121,17 +120,18 @@ rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, #endif return sprintf(buf, "0\n"); } - -static struct device_attribute rtc_attrs[] = { - __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), - __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), - __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL), - __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), - __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, - rtc_sysfs_set_max_user_freq), - __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL), - { }, +static DEVICE_ATTR_RO(hctosys); + +static struct attribute *rtc_attrs[] = { + &dev_attr_name.attr, + &dev_attr_date.attr, + &dev_attr_time.attr, + &dev_attr_since_epoch.attr, + &dev_attr_max_user_freq.attr, + &dev_attr_hctosys.attr, + NULL, }; +ATTRIBUTE_GROUPS(rtc); static ssize_t rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, @@ -164,6 +164,7 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, { ssize_t retval; unsigned long now, alarm; + unsigned long push = 0; struct rtc_wkalrm alm; struct rtc_device *rtc = to_rtc_device(dev); char *buf_ptr; @@ -180,13 +181,17 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, buf_ptr = (char *)buf; if (*buf_ptr == '+') { buf_ptr++; - adjust = 1; + if (*buf_ptr == '=') { + buf_ptr++; + push = 1; + } else + adjust = 1; } alarm = simple_strtoul(buf_ptr, NULL, 0); if (adjust) { alarm += now; } - if (alarm > now) { + if (alarm > now || push) { /* Avoid accidentally clobbering active alarms; we can't * entirely prevent that here, without even the minimal * locking from the /dev/rtcN api. @@ -194,9 +199,14 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, retval = rtc_read_alarm(rtc, &alm); if (retval < 0) return retval; - if (alm.enabled) - return -EBUSY; - + if (alm.enabled) { + if (push) { + rtc_tm_to_time(&alm.time, &push); + alarm += push; + } else + return -EBUSY; + } else if (push) + return -EINVAL; alm.enabled = 1; } else { alm.enabled = 0; @@ -251,5 +261,5 @@ void rtc_sysfs_del_device(struct rtc_device *rtc) void __init rtc_sysfs_init(struct class *rtc_class) { - rtc_class->dev_attrs = rtc_attrs; + rtc_class->dev_groups = rtc_groups; } diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 7746e65b93f..6599c20bc45 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -104,20 +104,17 @@ static int test_probe(struct platform_device *plat_dev) rtc = devm_rtc_device_register(&plat_dev->dev, "test", &test_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { - err = PTR_ERR(rtc); - return err; + return PTR_ERR(rtc); } err = device_create_file(&plat_dev->dev, &dev_attr_irq); if (err) - goto err; + dev_err(&plat_dev->dev, "Unable to create sysfs entry: %s\n", + dev_attr_irq.attr.name); platform_set_drvdata(plat_dev, rtc); return 0; - -err: - return err; } static int test_remove(struct platform_device *plat_dev) diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c index fc3dee95f16..ff9632eb79f 100644 --- a/drivers/rtc/rtc-tile.c +++ b/drivers/rtc/rtc-tile.c @@ -91,23 +91,12 @@ static int tile_rtc_probe(struct platform_device *dev) return 0; } -/* - * Device cleanup routine. - */ -static int tile_rtc_remove(struct platform_device *dev) -{ - platform_set_drvdata(dev, NULL); - - return 0; -} - static struct platform_driver tile_rtc_platform_driver = { .driver = { .name = "rtc-tile", .owner = THIS_MODULE, }, .probe = tile_rtc_probe, - .remove = tile_rtc_remove, }; /* diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index a9caf043b0c..7af00208d63 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -22,7 +22,6 @@ #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> diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 72662eafb93..3e400dce2d0 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -298,11 +298,6 @@ static int tps80031_rtc_probe(struct platform_device *pdev) return 0; } -static int tps80031_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - #ifdef CONFIG_PM_SLEEP static int tps80031_rtc_suspend(struct device *dev) { @@ -333,7 +328,6 @@ static struct platform_driver tps80031_rtc_driver = { .pm = &tps80031_pm_ops, }, .probe = tps80031_rtc_probe, - .remove = tps80031_rtc_remove, }; module_platform_driver(tps80031_rtc_driver); diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index b2eab34f38d..1915464e4cd 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -213,12 +213,24 @@ static int mask_rtc_irq_bit(unsigned char bit) static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) { + struct platform_device *pdev = to_platform_device(dev); + int irq = platform_get_irq(pdev, 0); + static bool twl_rtc_wake_enabled; int ret; - if (enabled) + if (enabled) { ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - else + if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) { + enable_irq_wake(irq); + twl_rtc_wake_enabled = true; + } + } else { ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + if (twl_rtc_wake_enabled) { + disable_irq_wake(irq); + twl_rtc_wake_enabled = false; + } + } return ret; } @@ -467,11 +479,17 @@ static int twl_rtc_probe(struct platform_device *pdev) u8 rd_reg; if (irq <= 0) - goto out1; + return ret; + + /* Initialize the register map */ + if (twl_class_is_4030()) + rtc_reg_map = (u8 *)twl4030_rtc_reg_map; + else + rtc_reg_map = (u8 *)twl6030_rtc_reg_map; ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); if (ret < 0) - goto out1; + return ret; if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) dev_warn(&pdev->dev, "Power up reset detected.\n"); @@ -482,7 +500,7 @@ static int twl_rtc_probe(struct platform_device *pdev) /* Clear RTC Power up reset and pending alarm interrupts */ ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); if (ret < 0) - goto out1; + return ret; if (twl_class_is_6030()) { twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, @@ -494,7 +512,7 @@ static int twl_rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Enabling TWL-RTC\n"); ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG); if (ret < 0) - goto out1; + return ret; /* ensure interrupts are disabled, bootloaders can be strange */ ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); @@ -504,33 +522,29 @@ static int twl_rtc_probe(struct platform_device *pdev) /* init cached IRQ enable bits */ ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); if (ret < 0) - goto out1; + return ret; + + device_init_wakeup(&pdev->dev, 1); - rtc = rtc_device_register(pdev->name, - &pdev->dev, &twl_rtc_ops, THIS_MODULE); + rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &twl_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); dev_err(&pdev->dev, "can't register RTC device, err %ld\n", PTR_ERR(rtc)); - goto out1; + return PTR_ERR(rtc); } - ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - dev_name(&rtc->dev), rtc); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + twl_rtc_interrupt, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + dev_name(&rtc->dev), rtc); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); - goto out2; + return ret; } platform_set_drvdata(pdev, rtc); - device_init_wakeup(&pdev->dev, 1); return 0; - -out2: - rtc_device_unregister(rtc); -out1: - return ret; } /* @@ -540,9 +554,6 @@ out1: static int twl_rtc_remove(struct platform_device *pdev) { /* leave rtc running, but disable irqs */ - struct rtc_device *rtc = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); if (twl_class_is_6030()) { @@ -552,11 +563,6 @@ static int twl_rtc_remove(struct platform_device *pdev) REG_INT_MSK_STS_A); } - - free_irq(irq, rtc); - - rtc_device_unregister(rtc); - platform_set_drvdata(pdev, NULL); return 0; } @@ -609,22 +615,7 @@ static struct platform_driver twl4030rtc_driver = { }, }; -static int __init twl_rtc_init(void) -{ - if (twl_class_is_4030()) - rtc_reg_map = (u8 *) twl4030_rtc_reg_map; - else - rtc_reg_map = (u8 *) twl6030_rtc_reg_map; - - return platform_driver_register(&twl4030rtc_driver); -} -module_init(twl_rtc_init); - -static void __exit twl_rtc_exit(void) -{ - platform_driver_unregister(&twl4030rtc_driver); -} -module_exit(twl_rtc_exit); +module_platform_driver(twl4030rtc_driver); MODULE_AUTHOR("Texas Instruments, MontaVista Software"); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index f9a0677e4e3..2e678c681b1 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -176,8 +176,8 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id) tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP); } spin_unlock(&pdata->lock); - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); + rtc_update_irq(pdata->rtc, 1, events); + return IRQ_HANDLED; } @@ -244,9 +244,6 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) struct resource *res; int irq, ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; irq = platform_get_irq(pdev, 0); if (irq < 0) return -ENODEV; @@ -255,13 +252,10 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, pdata); - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) - return -EBUSY; - pdata->rtcreg = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!pdata->rtcreg) - return -EBUSY; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->rtcreg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->rtcreg)) + return PTR_ERR(pdata->rtcreg); spin_lock_init(&pdata->lock); tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 6e0cba8f47d..25222cdccdc 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -16,7 +16,7 @@ * - Use the generic rtc class * * ??-???-2004: Someone at Compulab - * - Initial driver creation. + * - Initial driver creation. * */ #include <linux/platform_device.h> @@ -278,13 +278,13 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt) dev_dbg(dev, "tm_year: %i\n", dt->tm_year); /* Write all the values to ram... */ - v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec)); - v3020_set_reg(chip, V3020_MINUTES, bin2bcd(dt->tm_min)); - v3020_set_reg(chip, V3020_HOURS, bin2bcd(dt->tm_hour)); + v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec)); + v3020_set_reg(chip, V3020_MINUTES, bin2bcd(dt->tm_min)); + v3020_set_reg(chip, V3020_HOURS, bin2bcd(dt->tm_hour)); v3020_set_reg(chip, V3020_MONTH_DAY, bin2bcd(dt->tm_mday)); - v3020_set_reg(chip, V3020_MONTH, bin2bcd(dt->tm_mon + 1)); - v3020_set_reg(chip, V3020_WEEK_DAY, bin2bcd(dt->tm_wday)); - v3020_set_reg(chip, V3020_YEAR, bin2bcd(dt->tm_year % 100)); + v3020_set_reg(chip, V3020_MONTH, bin2bcd(dt->tm_mon + 1)); + v3020_set_reg(chip, V3020_WEEK_DAY, bin2bcd(dt->tm_wday)); + v3020_set_reg(chip, V3020_YEAR, bin2bcd(dt->tm_year % 100)); /* ...and set the clock. */ v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0); @@ -303,7 +303,7 @@ static const struct rtc_class_ops v3020_rtc_ops = { static int rtc_probe(struct platform_device *pdev) { - struct v3020_platform_data *pdata = pdev->dev.platform_data; + struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev); struct v3020 *chip; int retval = -EBUSY; int i; @@ -320,7 +320,7 @@ static int rtc_probe(struct platform_device *pdev) retval = chip->ops->map_io(chip, pdev, pdata); if (retval) - goto err_chip; + return retval; /* Make sure the v3020 expects a communication cycle * by reading 8 times */ @@ -364,7 +364,7 @@ static int rtc_probe(struct platform_device *pdev) err_io: chip->ops->unmap_io(chip); -err_chip: + return retval; } diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index f91be04b905..88c9c92e89f 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -20,6 +20,7 @@ #include <linux/err.h> #include <linux/fs.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -27,11 +28,10 @@ #include <linux/rtc.h> #include <linux/spinlock.h> #include <linux/types.h> +#include <linux/uaccess.h> #include <linux/log2.h> #include <asm/div64.h> -#include <asm/io.h> -#include <asm/uaccess.h> MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); @@ -103,7 +103,7 @@ static inline unsigned long read_elapsed_second(void) second_mid = rtc1_read(ETIMEMREG); second_high = rtc1_read(ETIMEHREG); } while (first_low != second_low || first_mid != second_mid || - first_high != second_high); + first_high != second_high); return (first_high << 17) | (first_mid << 1) | (first_low >> 15); } @@ -154,7 +154,7 @@ static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time) epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, - time->tm_hour, time->tm_min, time->tm_sec); + time->tm_hour, time->tm_min, time->tm_sec); write_elapsed_second(current_sec - epoch_sec); @@ -186,7 +186,7 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) struct rtc_time *time = &wkalrm->time; alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, - time->tm_hour, time->tm_min, time->tm_sec); + time->tm_hour, time->tm_min, time->tm_sec); spin_lock_irq(&rtc_lock); @@ -293,7 +293,7 @@ static int rtc_probe(struct platform_device *pdev) if (!res) return -EBUSY; - rtc1_base = ioremap(res->start, resource_size(res)); + rtc1_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!rtc1_base) return -EBUSY; @@ -303,13 +303,14 @@ static int rtc_probe(struct platform_device *pdev) goto err_rtc1_iounmap; } - rtc2_base = ioremap(res->start, resource_size(res)); + rtc2_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!rtc2_base) { retval = -EBUSY; goto err_rtc1_iounmap; } - rtc = rtc_device_register(rtc_name, &pdev->dev, &vr41xx_rtc_ops, THIS_MODULE); + rtc = devm_rtc_device_register(&pdev->dev, rtc_name, &vr41xx_rtc_ops, + THIS_MODULE); if (IS_ERR(rtc)) { retval = PTR_ERR(rtc); goto err_iounmap_all; @@ -330,22 +331,24 @@ static int rtc_probe(struct platform_device *pdev) aie_irq = platform_get_irq(pdev, 0); if (aie_irq <= 0) { retval = -EBUSY; - goto err_device_unregister; + goto err_iounmap_all; } - retval = request_irq(aie_irq, elapsedtime_interrupt, 0, - "elapsed_time", pdev); + retval = devm_request_irq(&pdev->dev, aie_irq, elapsedtime_interrupt, 0, + "elapsed_time", pdev); if (retval < 0) - goto err_device_unregister; + goto err_iounmap_all; pie_irq = platform_get_irq(pdev, 1); - if (pie_irq <= 0) - goto err_free_irq; + if (pie_irq <= 0) { + retval = -EBUSY; + goto err_iounmap_all; + } - retval = request_irq(pie_irq, rtclong1_interrupt, 0, - "rtclong1", pdev); + retval = devm_request_irq(&pdev->dev, pie_irq, rtclong1_interrupt, 0, + "rtclong1", pdev); if (retval < 0) - goto err_free_irq; + goto err_iounmap_all; platform_set_drvdata(pdev, rtc); @@ -356,49 +359,20 @@ static int rtc_probe(struct platform_device *pdev) return 0; -err_free_irq: - free_irq(aie_irq, pdev); - -err_device_unregister: - rtc_device_unregister(rtc); - err_iounmap_all: - iounmap(rtc2_base); rtc2_base = NULL; err_rtc1_iounmap: - iounmap(rtc1_base); rtc1_base = NULL; return retval; } -static int rtc_remove(struct platform_device *pdev) -{ - struct rtc_device *rtc; - - rtc = platform_get_drvdata(pdev); - if (rtc) - rtc_device_unregister(rtc); - - platform_set_drvdata(pdev, NULL); - - free_irq(aie_irq, pdev); - free_irq(pie_irq, pdev); - if (rtc1_base) - iounmap(rtc1_base); - if (rtc2_base) - iounmap(rtc2_base); - - return 0; -} - /* work with hotplug and coldplug */ MODULE_ALIAS("platform:RTC"); static struct platform_driver rtc_platform_driver = { .probe = rtc_probe, - .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 d89efee6d29..051da968da6 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -79,7 +79,6 @@ struct vt8500_rtc { void __iomem *regbase; - struct resource *res; int irq_alarm; struct rtc_device *rtc; spinlock_t lock; /* Protects this structure */ @@ -209,6 +208,7 @@ static const struct rtc_class_ops vt8500_rtc_ops = { static int vt8500_rtc_probe(struct platform_device *pdev) { struct vt8500_rtc *vt8500_rtc; + struct resource *res; int ret; vt8500_rtc = devm_kzalloc(&pdev->dev, @@ -219,34 +219,16 @@ static int vt8500_rtc_probe(struct platform_device *pdev) spin_lock_init(&vt8500_rtc->lock); platform_set_drvdata(pdev, vt8500_rtc); - vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!vt8500_rtc->res) { - dev_err(&pdev->dev, "No I/O memory resource defined\n"); - 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"); - return -ENXIO; + return vt8500_rtc->irq_alarm; } - 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"); - return -EBUSY; - } - - 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_return; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + vt8500_rtc->regbase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(vt8500_rtc->regbase)) + return PTR_ERR(vt8500_rtc->regbase); /* Enable RTC and set it to 24-hour mode */ writel(VT8500_RTC_CR_ENABLE, @@ -282,8 +264,6 @@ static int vt8500_rtc_remove(struct platform_device *pdev) /* Disable alarm matching */ writel(0, vt8500_rtc->regbase + VT8500_RTC_IS); - platform_set_drvdata(pdev, NULL); - return 0; } @@ -298,7 +278,7 @@ static struct platform_driver vt8500_rtc_driver = { .driver = { .name = "vt8500-rtc", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(wmt_dt_ids), + .of_match_table = wmt_dt_ids, }, }; diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 8d65b94e5a7..75aea4c4d33 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -460,11 +460,6 @@ err: return ret; } -static int wm831x_rtc_remove(struct platform_device *pdev) -{ - return 0; -} - static const struct dev_pm_ops wm831x_rtc_pm_ops = { .suspend = wm831x_rtc_suspend, .resume = wm831x_rtc_resume, @@ -478,7 +473,6 @@ static const struct dev_pm_ops wm831x_rtc_pm_ops = { static struct platform_driver wm831x_rtc_driver = { .probe = wm831x_rtc_probe, - .remove = wm831x_rtc_remove, .driver = { .name = "wm831x-rtc", .pm = &wm831x_rtc_pm_ops, diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index fa9b0679fb6..b1de58e0b3d 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -4,7 +4,7 @@ * Copyright 2005 Alessandro Zummo * * please send all reports to: - * Karen Spearel <kas111 at gmail dot com> + * Karen Spearel <kas111 at gmail dot com> * Alessandro Zummo <a.zummo@towertech.it> * * based on a lot of other RTC drivers. @@ -215,12 +215,14 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, buf[i] |= 0x80; /* this sequence is required to unlock the chip */ - if ((xfer = i2c_master_send(client, wel, 3)) != 3) { + xfer = i2c_master_send(client, wel, 3); + if (xfer != 3) { dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); return -EIO; } - if ((xfer = i2c_master_send(client, rwel, 3)) != 3) { + xfer = i2c_master_send(client, rwel, 3); + if (xfer != 3) { dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer); return -EIO; } @@ -269,7 +271,8 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, } /* disable further writes */ - if ((xfer = i2c_master_send(client, diswe, 3)) != 3) { + xfer = i2c_master_send(client, diswe, 3); + if (xfer != 3) { dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer); return -EIO; } @@ -375,8 +378,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) return 0; } -struct x1205_limit -{ +struct x1205_limit { unsigned char reg, mask, min, max; }; @@ -430,7 +432,8 @@ static int x1205_validate_client(struct i2c_client *client) }, }; - if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { + xfer = i2c_transfer(client->adapter, msgs, 2); + if (xfer != 2) { dev_err(&client->dev, "%s: could not read register %x\n", __func__, probe_zero_pattern[i]); @@ -467,7 +470,8 @@ static int x1205_validate_client(struct i2c_client *client) }, }; - if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { + xfer = i2c_transfer(client->adapter, msgs, 2); + if (xfer != 2) { dev_err(&client->dev, "%s: could not read register %x\n", __func__, probe_limits_pattern[i].reg); @@ -548,10 +552,12 @@ static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) { int err, dtrim, atrim; - if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0) + err = x1205_get_dtrim(to_i2c_client(dev), &dtrim); + if (!err) seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim); - if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0) + err = x1205_get_atrim(to_i2c_client(dev), &atrim); + if (!err) seq_printf(seq, "analog_trim\t: %d.%02d pF\n", atrim / 1000, atrim % 1000); return 0; @@ -639,7 +645,8 @@ static int x1205_probe(struct i2c_client *client, i2c_set_clientdata(client, rtc); /* Check for power failures and eventually enable the osc */ - if ((err = x1205_get_status(client, &sr)) == 0) { + err = x1205_get_status(client, &sr); + if (!err) { if (sr & X1205_SR_RTCF) { dev_err(&client->dev, "power failure detected, " @@ -647,13 +654,13 @@ static int x1205_probe(struct i2c_client *client, udelay(50); x1205_fix_osc(client); } - } - else + } else { dev_err(&client->dev, "couldn't read status\n"); + } err = x1205_sysfs_register(&client->dev); if (err) - return err; + dev_err(&client->dev, "Unable to create sysfs entries\n"); return 0; } diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c new file mode 100644 index 00000000000..14129cc85bd --- /dev/null +++ b/drivers/rtc/rtc-xgene.c @@ -0,0 +1,278 @@ +/* + * APM X-Gene SoC Real Time Clock Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Rameshwar Prasad Sahu <rsahu@apm.com> + * Loc Ho <lho@apm.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/rtc.h> + +/* RTC CSR Registers */ +#define RTC_CCVR 0x00 +#define RTC_CMR 0x04 +#define RTC_CLR 0x08 +#define RTC_CCR 0x0C +#define RTC_CCR_IE BIT(0) +#define RTC_CCR_MASK BIT(1) +#define RTC_CCR_EN BIT(2) +#define RTC_CCR_WEN BIT(3) +#define RTC_STAT 0x10 +#define RTC_STAT_BIT BIT(0) +#define RTC_RSTAT 0x14 +#define RTC_EOI 0x18 +#define RTC_VER 0x1C + +struct xgene_rtc_dev { + struct rtc_device *rtc; + struct device *dev; + unsigned long alarm_time; + void __iomem *csr_base; + struct clk *clk; + unsigned int irq_wake; +}; + +static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + + rtc_time_to_tm(readl(pdata->csr_base + RTC_CCVR), tm); + return rtc_valid_tm(tm); +} + +static int xgene_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + + /* + * NOTE: After the following write, the RTC_CCVR is only reflected + * after the update cycle of 1 seconds. + */ + writel((u32) secs, pdata->csr_base + RTC_CLR); + readl(pdata->csr_base + RTC_CLR); /* Force a barrier */ + + return 0; +} + +static int xgene_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + + rtc_time_to_tm(pdata->alarm_time, &alrm->time); + alrm->enabled = readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE; + + return 0; +} + +static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled) +{ + struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + u32 ccr; + + ccr = readl(pdata->csr_base + RTC_CCR); + if (enabled) { + ccr &= ~RTC_CCR_MASK; + ccr |= RTC_CCR_IE; + } else { + ccr &= ~RTC_CCR_IE; + ccr |= RTC_CCR_MASK; + } + writel(ccr, pdata->csr_base + RTC_CCR); + + return 0; +} + +static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + unsigned long rtc_time; + unsigned long alarm_time; + + rtc_time = readl(pdata->csr_base + RTC_CCVR); + rtc_tm_to_time(&alrm->time, &alarm_time); + + pdata->alarm_time = alarm_time; + writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR); + + xgene_rtc_alarm_irq_enable(dev, alrm->enabled); + + return 0; +} + +static const struct rtc_class_ops xgene_rtc_ops = { + .read_time = xgene_rtc_read_time, + .set_mmss = xgene_rtc_set_mmss, + .read_alarm = xgene_rtc_read_alarm, + .set_alarm = xgene_rtc_set_alarm, + .alarm_irq_enable = xgene_rtc_alarm_irq_enable, +}; + +static irqreturn_t xgene_rtc_interrupt(int irq, void *id) +{ + struct xgene_rtc_dev *pdata = (struct xgene_rtc_dev *) id; + + /* Check if interrupt asserted */ + if (!(readl(pdata->csr_base + RTC_STAT) & RTC_STAT_BIT)) + return IRQ_NONE; + + /* Clear interrupt */ + readl(pdata->csr_base + RTC_EOI); + + rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int xgene_rtc_probe(struct platform_device *pdev) +{ + struct xgene_rtc_dev *pdata; + struct resource *res; + int ret; + int irq; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + platform_set_drvdata(pdev, pdata); + pdata->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->csr_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->csr_base)) + return PTR_ERR(pdata->csr_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No IRQ resource\n"); + return irq; + } + ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0, + dev_name(&pdev->dev), pdata); + if (ret) { + dev_err(&pdev->dev, "Could not request IRQ\n"); + return ret; + } + + pdata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pdata->clk)) { + dev_err(&pdev->dev, "Couldn't get the clock for RTC\n"); + return -ENODEV; + } + clk_prepare_enable(pdata->clk); + + /* Turn on the clock and the crystal */ + writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR); + + device_init_wakeup(&pdev->dev, 1); + + pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &xgene_rtc_ops, THIS_MODULE); + if (IS_ERR(pdata->rtc)) { + clk_disable_unprepare(pdata->clk); + return PTR_ERR(pdata->rtc); + } + + /* HW does not support update faster than 1 seconds */ + pdata->rtc->uie_unsupported = 1; + + return 0; +} + +static int xgene_rtc_remove(struct platform_device *pdev) +{ + struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); + + xgene_rtc_alarm_irq_enable(&pdev->dev, 0); + device_init_wakeup(&pdev->dev, 0); + clk_disable_unprepare(pdata->clk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int xgene_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); + int irq; + + irq = platform_get_irq(pdev, 0); + if (device_may_wakeup(&pdev->dev)) { + if (!enable_irq_wake(irq)) + pdata->irq_wake = 1; + } else { + xgene_rtc_alarm_irq_enable(dev, 0); + clk_disable(pdata->clk); + } + + return 0; +} + +static int xgene_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); + int irq; + + irq = platform_get_irq(pdev, 0); + if (device_may_wakeup(&pdev->dev)) { + if (pdata->irq_wake) { + disable_irq_wake(irq); + pdata->irq_wake = 0; + } + } else { + clk_enable(pdata->clk); + xgene_rtc_alarm_irq_enable(dev, 1); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume); + +#ifdef CONFIG_OF +static const struct of_device_id xgene_rtc_of_match[] = { + {.compatible = "apm,xgene-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, xgene_rtc_of_match); +#endif + +static struct platform_driver xgene_rtc_driver = { + .probe = xgene_rtc_probe, + .remove = xgene_rtc_remove, + .driver = { + .owner = THIS_MODULE, + .name = "xgene-rtc", + .pm = &xgene_rtc_pm_ops, + .of_match_table = of_match_ptr(xgene_rtc_of_match), + }, +}; + +module_platform_driver(xgene_rtc_driver); + +MODULE_DESCRIPTION("APM X-Gene SoC RTC driver"); +MODULE_AUTHOR("Rameshwar Sahu <rsahu@apm.com>"); +MODULE_LICENSE("GPL"); |
