diff options
Diffstat (limited to 'drivers/rtc')
167 files changed, 3747 insertions, 3279 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index f933c06bff4f..1adf9f815652 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # RTC class/drivers configuration # @@ -372,12 +373,23 @@ config RTC_DRV_MAX77686 This driver can also be built as a module. If so, the module will be called rtc-max77686. +config RTC_DRV_MESON_VRTC + tristate "Amlogic Meson Virtual RTC" + depends on ARCH_MESON || COMPILE_TEST + default m if ARCH_MESON + help + If you say yes here you will get support for the + Virtual RTC of Amlogic SoCs. + + This driver can also be built as a module. If so, the module + will be called rtc-meson-vrtc. + config RTC_DRV_RK808 - tristate "Rockchip RK805/RK808/RK818 RTC" + tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC" depends on MFD_RK808 help If you say yes here you will get support for the - RTC of RK805, RK808 and RK818 PMIC. + RTC of RK805, RK809 and RK817, RK808 and RK818 PMIC. This driver can also be built as a module. If so, the module will be called rk808-rtc. @@ -439,6 +451,7 @@ config RTC_DRV_PCF8523 config RTC_DRV_PCF85063 tristate "NXP PCF85063" + select REGMAP_I2C help If you say yes here you get support for the PCF85063 RTC chip @@ -447,7 +460,6 @@ config RTC_DRV_PCF85063 config RTC_DRV_PCF85363 tristate "NXP PCF85363" - depends on I2C select REGMAP_I2C help If you say yes here you get support for the PCF85363 RTC chip. @@ -497,6 +509,15 @@ config RTC_DRV_M41T80_WDT help If you say Y here you will get support for the watchdog timer in the ST M41T60 and M41T80 RTC chips series. +config RTC_DRV_BD70528 + tristate "ROHM BD70528 PMIC RTC" + depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG) + help + If you say Y here you will get support for the RTC + on ROHM BD70528 Power Management IC. + + This driver can also be built as a module. If so, the module + will be called rtc-bd70528. config RTC_DRV_BQ32K tristate "TI BQ32000" @@ -553,7 +574,7 @@ config RTC_DRV_TPS6586X config RTC_DRV_TPS65910 tristate "TI TPS65910 RTC driver" - depends on RTC_CLASS && MFD_TPS65910 + depends on MFD_TPS65910 help If you say yes here you get support for the RTC on the TPS65910 chips. @@ -602,7 +623,6 @@ config RTC_DRV_FM3130 config RTC_DRV_RX8010 tristate "Epson RX8010SJ" - depends on I2C help If you say yes here you get support for the Epson RX8010SJ RTC chip. @@ -812,6 +832,7 @@ config RTC_DRV_MAX6902 config RTC_DRV_PCF2123 tristate "NXP PCF2123" + select REGMAP_SPI help If you say yes here you get support for the NXP PCF2123 RTC chip. @@ -865,9 +886,15 @@ config RTC_DRV_DS3232_HWMON config RTC_DRV_PCF2127 tristate "NXP PCF2127" depends on RTC_I2C_AND_SPI + select WATCHDOG_CORE if WATCHDOG help If you say yes here you get support for the NXP PCF2127/29 RTC - chips. + chips with integrated quartz crystal for industrial applications. + Both chips also have watchdog timer and tamper switch detection + features. + + PCF2127 has an additional feature of 512 bytes battery backed + memory that's accessible using nvmem interface. This driver can also be built as a module. If so, the module will be called rtc-pcf2127. @@ -1238,13 +1265,6 @@ config RTC_DRV_AB8500 Select this to enable the ST-Ericsson AB8500 power management IC RTC support. This chip contains a battery- and capacitor-backed RTC. -config RTC_DRV_NUC900 - tristate "NUC910/NUC920 RTC driver" - depends on ARCH_W90X900 || COMPILE_TEST - help - If you say yes here you get support for the RTC subsystem of the - NUC910/NUC920 used in embedded systems. - config RTC_DRV_OPAL tristate "IBM OPAL RTC driver" depends on PPC_POWERNV @@ -1265,7 +1285,7 @@ config RTC_DRV_ZYNQMP config RTC_DRV_CROS_EC tristate "Chrome OS EC RTC driver" - depends on MFD_CROS_EC + depends on CROS_EC help If you say yes here you will get support for the Chrome OS Embedded Controller's RTC. @@ -1314,6 +1334,21 @@ config RTC_DRV_IMXDI This driver can also be built as a module, if so, the module will be called "rtc-imxdi". +config RTC_DRV_FSL_FTM_ALARM + tristate "Freescale FlexTimer alarm timer" + depends on ARCH_LAYERSCAPE || SOC_LS1021A + select FSL_RCPM + default y + help + For the FlexTimer in LS1012A, LS1021A, LS1028A, LS1043A, LS1046A, + LS1088A, LS208xA, we can use FTM as the wakeup source. + + Say y here to enable FTM alarm support. The FTM alarm provides + alarm functions for wakeup system from deep sleep. + + This driver can also be built as a module, if so, the module + will be called "rtc-fsl-ftm-alarm". + config RTC_DRV_MESON tristate "Amlogic Meson RTC" depends on (ARM && ARCH_MESON) || COMPILE_TEST @@ -1432,7 +1467,7 @@ config RTC_DRV_AT91RM9200 config RTC_DRV_AT91SAM9 tristate "AT91SAM9 RTT as RTC" depends on ARCH_AT91 || COMPILE_TEST - depends on HAS_IOMEM + depends on OF && HAS_IOMEM select MFD_SYSCON help Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which @@ -1841,6 +1876,17 @@ config RTC_DRV_RTD119X If you say yes here, you get support for the RTD1295 SoC Real Time Clock. +config RTC_DRV_ASPEED + tristate "ASPEED RTC" + depends on OF + depends on ARCH_ASPEED || COMPILE_TEST + help + If you say yes here you get support for the ASPEED BMC SoC real time + clocks. + + This driver can also be built as a module, if so, the module + will be called "rtc-aspeed". + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME @@ -1857,7 +1903,8 @@ config RTC_DRV_HID_SENSOR_TIME config RTC_DRV_GOLDFISH tristate "Goldfish Real Time Clock" - depends on MIPS && (GOLDFISH || COMPILE_TEST) + depends on OF && HAS_IOMEM + depends on GOLDFISH || COMPILE_TEST help Say yes to enable RTC driver for the Goldfish based virtual platform. diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index fe3962496685..4ac8f19fb631 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -34,9 +34,11 @@ obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o +obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o +obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o @@ -71,6 +73,7 @@ obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o +obj-$(CONFIG_RTC_DRV_FSL_FTM_ALARM) += rtc-fsl-ftm-alarm.o obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o @@ -100,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o +obj-$(CONFIG_RTC_DRV_MESON_VRTC)+= rtc-meson-vrtc.o obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o @@ -111,7 +115,6 @@ obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o -obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index ac93b76f2b11..9458e6d6686a 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * RTC subsystem, base class * @@ -5,11 +6,7 @@ * Author: Alessandro Zummo <a.zummo@towertech.it> * * class skeleton from drivers/hwmon/hwmon.c - * - * 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. -*/ + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -23,13 +20,13 @@ #include "rtc-core.h" - static DEFINE_IDA(rtc_ida); struct class *rtc_class; static void rtc_device_release(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); + ida_simple_remove(&rtc_ida, rtc->id); kfree(rtc); } @@ -47,7 +44,6 @@ int rtc_hctosys_ret = -ENODEV; static struct timespec64 old_rtc, old_system, old_delta; - static int rtc_suspend(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); @@ -71,7 +67,6 @@ static int rtc_suspend(struct device *dev) ktime_get_real_ts64(&old_system); old_rtc.tv_sec = rtc_tm_to_time64(&tm); - /* * To avoid drift caused by repeated suspend/resumes, * which each can add ~1 second drift error, @@ -83,7 +78,7 @@ static int rtc_suspend(struct device *dev) if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) { /* * if delta_delta is too large, assume time correction - * has occured and set old_delta to the current delta. + * has occurred and set old_delta to the current delta. */ old_delta = delta; } else { @@ -136,7 +131,7 @@ static int rtc_resume(struct device *dev) * to keep things accurate. */ sleep_time = timespec64_sub(sleep_time, - timespec64_sub(new_system, old_system)); + timespec64_sub(new_system, old_system)); if (sleep_time.tv_sec >= 0) timekeeping_inject_sleeptime64(&sleep_time); @@ -351,8 +346,10 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc) struct rtc_wkalrm alrm; int err; - if (!rtc->ops) + if (!rtc->ops) { + dev_dbg(&rtc->dev, "no ops set\n"); return -EINVAL; + } rtc->owner = owner; rtc_device_get_offset(rtc); @@ -397,9 +394,9 @@ EXPORT_SYMBOL_GPL(__rtc_register_device); * rtc_register_device instead */ struct rtc_device *devm_rtc_device_register(struct device *dev, - const char *name, - const struct rtc_class_ops *ops, - struct module *owner) + const char *name, + const struct rtc_class_ops *ops, + struct module *owner) { struct rtc_device *rtc; int err; diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index 1d006ef4bb57..5b8ebe86124a 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * RTC subsystem, dev interface * @@ -5,14 +6,11 @@ * Author: Alessandro Zummo <a.zummo@towertech.it> * * based on arch/arm/common/rtctime.c - * - * 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. -*/ + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/compat.h> #include <linux/module.h> #include <linux/rtc.h> #include <linux/sched/signal.h> @@ -60,7 +58,7 @@ static void rtc_uie_task(struct work_struct *work) } else if (rtc->oldsecs != tm.tm_sec) { num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; rtc->oldsecs = tm.tm_sec; - rtc->uie_timer.expires = jiffies + HZ - (HZ/10); + rtc->uie_timer.expires = jiffies + HZ - (HZ / 10); rtc->uie_timer_active = 1; rtc->uie_task_active = 0; add_timer(&rtc->uie_timer); @@ -71,6 +69,7 @@ static void rtc_uie_task(struct work_struct *work) if (num) rtc_handle_legacy_irq(rtc, num, RTC_UF); } + static void rtc_uie_timer(struct timer_list *t) { struct rtc_device *rtc = from_timer(rtc, t, uie_timer); @@ -202,14 +201,14 @@ static __poll_t rtc_dev_poll(struct file *file, poll_table *wait) } static long rtc_dev_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { int err = 0; struct rtc_device *rtc = file->private_data; const struct rtc_class_ops *ops = rtc->ops; struct rtc_time tm; struct rtc_wkalrm alarm; - void __user *uarg = (void __user *) arg; + void __user *uarg = (void __user *)arg; err = mutex_lock_interruptible(&rtc->ops_lock); if (err) @@ -233,7 +232,7 @@ static long rtc_dev_ioctl(struct file *file, case RTC_PIE_ON: if (rtc->irq_freq > rtc->max_user_freq && - !capable(CAP_SYS_RESOURCE)) + !capable(CAP_SYS_RESOURCE)) err = -EACCES; break; } @@ -362,7 +361,6 @@ static long rtc_dev_ioctl(struct file *file, case RTC_IRQP_SET: err = rtc_irq_set_freq(rtc, arg); break; - case RTC_IRQP_READ: err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); break; @@ -390,8 +388,9 @@ static long rtc_dev_ioctl(struct file *file, err = ops->ioctl(rtc->dev.parent, cmd, arg); if (err == -ENOIOCTLCMD) err = -ENOTTY; - } else + } else { err = -ENOTTY; + } break; } @@ -400,9 +399,38 @@ done: return err; } +#ifdef CONFIG_COMPAT +#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32) +#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32) +#define RTC_EPOCH_SET32 _IOW('p', 0x0e, __u32) + +static long rtc_dev_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct rtc_device *rtc = file->private_data; + void __user *uarg = compat_ptr(arg); + + switch (cmd) { + case RTC_IRQP_READ32: + return put_user(rtc->irq_freq, (__u32 __user *)uarg); + + case RTC_IRQP_SET32: + /* arg is a plain integer, not pointer */ + return rtc_dev_ioctl(file, RTC_IRQP_SET, arg); + + case RTC_EPOCH_SET32: + /* arg is a plain integer, not pointer */ + return rtc_dev_ioctl(file, RTC_EPOCH_SET, arg); + } + + return rtc_dev_ioctl(file, cmd, (unsigned long)uarg); +} +#endif + static int rtc_dev_fasync(int fd, struct file *file, int on) { struct rtc_device *rtc = file->private_data; + return fasync_helper(fd, file, on, &rtc->async_queue); } @@ -434,6 +462,9 @@ static const struct file_operations rtc_dev_fops = { .read = rtc_dev_read, .poll = rtc_dev_poll, .unlocked_ioctl = rtc_dev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = rtc_dev_compat_ioctl, +#endif .open = rtc_dev_open, .release = rtc_dev_release, .fasync = rtc_dev_fasync, diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index ff2092a0d38c..a74d0d890600 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * RTC subsystem, initialize system time on startup * * Copyright (C) 2005 Tower Technologies * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -33,7 +30,7 @@ static int __init rtc_hctosys(void) }; struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); - if (rtc == NULL) { + if (!rtc) { pr_info("unable to open rtc device (%s)\n", CONFIG_RTC_HCTOSYS_DEVICE); goto err_open; @@ -44,7 +41,6 @@ static int __init rtc_hctosys(void) dev_err(rtc->dev.parent, "hctosys: unable to read the hardware clock\n"); goto err_read; - } tv64.tv_sec = rtc_tm_to_time64(&tm); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 98d9c87b0d1b..c93ef33b01d3 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * RTC subsystem, interface functions * @@ -5,11 +6,7 @@ * Author: Alessandro Zummo <a.zummo@towertech.it> * * based on arch/arm/common/rtctime.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ + */ #include <linux/rtc.h> #include <linux/sched.h> @@ -87,11 +84,12 @@ static int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm) static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) { int err; - if (!rtc->ops) + + if (!rtc->ops) { err = -ENODEV; - else if (!rtc->ops->read_time) + } else if (!rtc->ops->read_time) { err = -EINVAL; - else { + } else { memset(tm, 0, sizeof(struct rtc_time)); err = rtc->ops->read_time(rtc->dev.parent, tm); if (err < 0) { @@ -147,14 +145,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) err = -ENODEV; else if (rtc->ops->set_time) err = rtc->ops->set_time(rtc->dev.parent, tm); - else if (rtc->ops->set_mmss64) { - time64_t secs64 = rtc_tm_to_time64(tm); - - err = rtc->ops->set_mmss64(rtc->dev.parent, secs64); - } else if (rtc->ops->set_mmss) { - time64_t secs64 = rtc_tm_to_time64(tm); - err = rtc->ops->set_mmss(rtc->dev.parent, secs64); - } else + else err = -EINVAL; pm_stay_awake(rtc->dev.parent); @@ -167,7 +158,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) } EXPORT_SYMBOL_GPL(rtc_set_time); -static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +static int rtc_read_alarm_internal(struct rtc_device *rtc, + struct rtc_wkalrm *alarm) { int err; @@ -175,11 +167,11 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al if (err) return err; - if (rtc->ops == NULL) + if (!rtc->ops) { err = -ENODEV; - else if (!rtc->ops->read_alarm) + } else if (!rtc->ops->read_alarm) { err = -EINVAL; - else { + } else { alarm->enabled = 0; alarm->pending = 0; alarm->time.tm_sec = -1; @@ -207,7 +199,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) int first_time = 1; time64_t t_now, t_alm; enum { none, day, month, year } missing = none; - unsigned days; + unsigned int days; /* The lower level RTC driver may return -1 in some fields, * creating invalid alarm->time values, for reasons like: @@ -276,10 +268,10 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) return err; /* note that tm_sec is a "don't care" value here: */ - } while ( before.tm_min != now.tm_min - || before.tm_hour != now.tm_hour - || before.tm_mon != now.tm_mon - || before.tm_year != now.tm_year); + } while (before.tm_min != now.tm_min || + before.tm_hour != now.tm_hour || + before.tm_mon != now.tm_mon || + before.tm_year != now.tm_year); /* Fill in the missing alarm fields using the timestamp; we * know there's at least one since alarm->time is invalid. @@ -296,7 +288,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) alarm->time.tm_mday = now.tm_mday; missing = day; } - if ((unsigned)alarm->time.tm_mon >= 12) { + if ((unsigned int)alarm->time.tm_mon >= 12) { alarm->time.tm_mon = now.tm_mon; if (missing == none) missing = month; @@ -321,7 +313,6 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) goto done; switch (missing) { - /* 24 hour rollover ... if it's now 10am Monday, an alarm that * that will trigger at 5am will do so at 5am Tuesday, which * could also be in the next month or year. This is a common @@ -341,14 +332,14 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) case month: dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month"); do { - if (alarm->time.tm_mon < 11) + if (alarm->time.tm_mon < 11) { alarm->time.tm_mon++; - else { + } else { alarm->time.tm_mon = 0; alarm->time.tm_year++; } days = rtc_month_days(alarm->time.tm_mon, - alarm->time.tm_year); + alarm->time.tm_year); } while (days < alarm->time.tm_mday); break; @@ -357,8 +348,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 (!is_leap_year(alarm->time.tm_year + 1900) - && rtc_valid_tm(&alarm->time) != 0); + } while (!is_leap_year(alarm->time.tm_year + 1900) && + rtc_valid_tm(&alarm->time) != 0); break; default: @@ -369,7 +360,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) done: if (err) - dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", &alarm->time); + dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", + &alarm->time); return err; } @@ -381,11 +373,11 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; - if (rtc->ops == NULL) + if (!rtc->ops) { err = -ENODEV; - else if (!rtc->ops->read_alarm) + } else if (!rtc->ops->read_alarm) { err = -EINVAL; - else { + } else { memset(alarm, 0, sizeof(struct rtc_wkalrm)); alarm->enabled = rtc->aie_timer.enabled; alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires); @@ -494,7 +486,6 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) /* Alarm has to be enabled & in the future for us to enqueue it */ if (alarm->enabled && (rtc_tm_to_ktime(now) < rtc->aie_timer.node.expires)) { - rtc->aie_timer.enabled = 1; timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); trace_rtc_timer_enqueue(&rtc->aie_timer); @@ -506,7 +497,9 @@ EXPORT_SYMBOL_GPL(rtc_initialize_alarm); int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) { - int err = mutex_lock_interruptible(&rtc->ops_lock); + int err; + + err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; @@ -535,7 +528,9 @@ EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) { - int err = mutex_lock_interruptible(&rtc->ops_lock); + int err; + + err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; @@ -564,27 +559,25 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); rtc->uie_rtctimer.period = ktime_set(1, 0); err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); - } else + } else { rtc_timer_remove(rtc, &rtc->uie_rtctimer); + } out: mutex_unlock(&rtc->ops_lock); #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL /* - * Enable emulation if the driver did not provide - * the update_irq_enable function pointer or if returned - * -EINVAL to signal that it has been configured without - * interrupts or that are not available at the moment. + * Enable emulation if the driver returned -EINVAL to signal that it has + * been configured without interrupts or they are not available at the + * moment. */ if (err == -EINVAL) err = rtc_dev_update_irq_enable_emul(rtc, enabled); #endif return err; - } EXPORT_SYMBOL_GPL(rtc_update_irq_enable); - /** * rtc_handle_legacy_irq - AIE, UIE and PIE event hook * @rtc: pointer to the rtc device @@ -599,14 +592,13 @@ void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) /* mark one irq of the appropriate mode */ spin_lock_irqsave(&rtc->irq_lock, flags); - rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); + rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF | mode); spin_unlock_irqrestore(&rtc->irq_lock, flags); wake_up_interruptible(&rtc->irq_queue); kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); } - /** * rtc_aie_update_irq - AIE mode rtctimer hook * @rtc: pointer to the rtc_device @@ -618,7 +610,6 @@ void rtc_aie_update_irq(struct rtc_device *rtc) rtc_handle_legacy_irq(rtc, 1, RTC_AF); } - /** * rtc_uie_update_irq - UIE mode rtctimer hook * @rtc: pointer to the rtc_device @@ -630,7 +621,6 @@ void rtc_uie_update_irq(struct rtc_device *rtc) rtc_handle_legacy_irq(rtc, 1, RTC_UF); } - /** * rtc_pie_update_irq - PIE mode hrtimer hook * @timer: pointer to the pie mode hrtimer @@ -643,7 +633,8 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) { struct rtc_device *rtc; ktime_t period; - int count; + u64 count; + rtc = container_of(timer, struct rtc_device, pie_timer); period = NSEC_PER_SEC / rtc->irq_freq; @@ -662,7 +653,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) * Context: any */ void rtc_update_irq(struct rtc_device *rtc, - unsigned long num, unsigned long events) + unsigned long num, unsigned long events) { if (IS_ERR_OR_NULL(rtc)) return; @@ -672,21 +663,12 @@ void rtc_update_irq(struct rtc_device *rtc, } EXPORT_SYMBOL_GPL(rtc_update_irq); -static int __rtc_match(struct device *dev, const void *data) -{ - const char *name = data; - - if (strcmp(dev_name(dev), name) == 0) - return 1; - return 0; -} - struct rtc_device *rtc_class_open(const char *name) { struct device *dev; struct rtc_device *rtc = NULL; - dev = class_find_device(rtc_class, NULL, name, __rtc_match); + dev = class_find_device_by_name(rtc_class, name); if (dev) rtc = to_rtc_device(dev); @@ -811,6 +793,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) if (!next || ktime_before(timer->node.expires, next->expires)) { struct rtc_wkalrm alarm; int err; + alarm.time = rtc_ktime_to_tm(timer->node.expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); @@ -851,12 +834,14 @@ static void rtc_alarm_disable(struct rtc_device *rtc) static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) { struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); + timerqueue_del(&rtc->timerqueue, &timer->node); trace_rtc_timer_dequeue(timer); timer->enabled = 0; if (next == &timer->node) { struct rtc_wkalrm alarm; int err; + next = timerqueue_getnext(&rtc->timerqueue); if (!next) { rtc_alarm_disable(rtc); @@ -929,9 +914,9 @@ again: alarm.enabled = 1; reprogram: err = __rtc_set_alarm(rtc, &alarm); - if (err == -ETIME) + if (err == -ETIME) { goto again; - else if (err) { + } else if (err) { if (retry-- > 0) goto reprogram; @@ -942,14 +927,14 @@ reprogram: dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err); goto again; } - } else + } else { rtc_alarm_disable(rtc); + } pm_relax(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); } - /* rtc_timer_init - Initializes an rtc_timer * @timer: timer to be intiialized * @f: function pointer to be called when timer fires @@ -975,9 +960,10 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r), * Kernel interface to set an rtc_timer */ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, - ktime_t expires, ktime_t period) + ktime_t expires, ktime_t period) { int ret = 0; + mutex_lock(&rtc->ops_lock); if (timer->enabled) rtc_timer_remove(rtc, timer); diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c index 9714cb3d1e29..23284580df97 100644 --- a/drivers/rtc/lib.c +++ b/drivers/rtc/lib.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * rtc and date/time utility functions * @@ -5,11 +6,7 @@ * Author: Alessandro Zummo <a.zummo@towertech.it> * * based on arch/arm/common/rtctime.c and other bits - * - * 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/export.h> #include <linux/rtc.h> @@ -25,7 +22,7 @@ static const unsigned short rtc_ydays[2][13] = { { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; -#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) +#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) /* * The number of days in the month. @@ -41,11 +38,10 @@ EXPORT_SYMBOL(rtc_month_days); */ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) { - return rtc_ydays[is_leap_year(year)][month] + day-1; + return rtc_ydays[is_leap_year(year)][month] + day - 1; } EXPORT_SYMBOL(rtc_year_days); - /* * rtc_time64_to_tm - Converts time64_t to rtc_time. * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. @@ -97,13 +93,15 @@ EXPORT_SYMBOL(rtc_time64_to_tm); */ int rtc_valid_tm(struct rtc_time *tm) { - if (tm->tm_year < 70 - || ((unsigned)tm->tm_mon) >= 12 - || tm->tm_mday < 1 - || tm->tm_mday > rtc_month_days(tm->tm_mon, ((unsigned)tm->tm_year + 1900)) - || ((unsigned)tm->tm_hour) >= 24 - || ((unsigned)tm->tm_min) >= 60 - || ((unsigned)tm->tm_sec) >= 60) + if (tm->tm_year < 70 || + tm->tm_year > (INT_MAX - 1900) || + ((unsigned int)tm->tm_mon) >= 12 || + tm->tm_mday < 1 || + tm->tm_mday > rtc_month_days(tm->tm_mon, + ((unsigned int)tm->tm_year + 1900)) || + ((unsigned int)tm->tm_hour) >= 24 || + ((unsigned int)tm->tm_min) >= 60 || + ((unsigned int)tm->tm_sec) >= 60) return -EINVAL; return 0; @@ -116,7 +114,7 @@ EXPORT_SYMBOL(rtc_valid_tm); */ time64_t rtc_tm_to_time64(struct rtc_time *tm) { - return mktime64(((unsigned)tm->tm_year + 1900), tm->tm_mon + 1, + return mktime64(((unsigned int)tm->tm_year + 1900), tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } EXPORT_SYMBOL(rtc_tm_to_time64); diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c index dce518d5e50e..4312096c7738 100644 --- a/drivers/rtc/nvmem.c +++ b/drivers/rtc/nvmem.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * RTC subsystem, nvmem interface * * Copyright (C) 2017 Alexandre Belloni - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> @@ -46,7 +43,7 @@ static int rtc_nvram_register(struct rtc_device *rtc, { int err; - rtc->nvram = kzalloc(sizeof(struct bin_attribute), GFP_KERNEL); + rtc->nvram = kzalloc(sizeof(*rtc->nvram), GFP_KERNEL); if (!rtc->nvram) return -ENOMEM; diff --git a/drivers/rtc/proc.c b/drivers/rtc/proc.c index 4d74e4f4ff30..73344598fc1b 100644 --- a/drivers/rtc/proc.c +++ b/drivers/rtc/proc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * RTC subsystem, proc interface * @@ -5,11 +6,7 @@ * Author: Alessandro Zummo <a.zummo@towertech.it> * * based on arch/arm/common/rtctime.c - * - * 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/rtc.h> @@ -60,17 +57,17 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) seq_printf(seq, "alrm_time\t: %ptRt\n", &alrm.time); seq_printf(seq, "alrm_date\t: %ptRd\n", &alrm.time); seq_printf(seq, "alarm_IRQ\t: %s\n", - alrm.enabled ? "yes" : "no"); + alrm.enabled ? "yes" : "no"); seq_printf(seq, "alrm_pending\t: %s\n", - alrm.pending ? "yes" : "no"); + alrm.pending ? "yes" : "no"); seq_printf(seq, "update IRQ enabled\t: %s\n", - (rtc->uie_rtctimer.enabled) ? "yes" : "no"); + (rtc->uie_rtctimer.enabled) ? "yes" : "no"); seq_printf(seq, "periodic IRQ enabled\t: %s\n", - (rtc->pie_enabled) ? "yes" : "no"); + (rtc->pie_enabled) ? "yes" : "no"); seq_printf(seq, "periodic IRQ frequency\t: %d\n", - rtc->irq_freq); + rtc->irq_freq); seq_printf(seq, "max user IRQ frequency\t: %d\n", - rtc->max_user_freq); + rtc->max_user_freq); } seq_printf(seq, "24hr\t\t: yes\n"); @@ -85,7 +82,7 @@ void rtc_proc_add_device(struct rtc_device *rtc) { if (is_rtc_hctosys(rtc)) proc_create_single_data("driver/rtc", 0, NULL, rtc_proc_show, - rtc); + rtc); } void rtc_proc_del_device(struct rtc_device *rtc) diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 1fc48ebd3cd0..75779e8501a3 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Real Time Clock driver for Marvell 88PM80x PMIC * * Copyright (c) 2012 Marvell International Ltd. * Wenzeng Chen<wzch@marvell.com> * Qiao Zhou <zhouqiao@marvell.com> - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file "COPYING" in the main directory of this - * archive for more details. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/kernel.h> @@ -276,7 +264,6 @@ static int pm80x_rtc_probe(struct platform_device *pdev) return -ENOMEM; info->irq = platform_get_irq(pdev, 0); if (info->irq < 0) { - dev_err(&pdev->dev, "No IRQ resource!\n"); ret = -EINVAL; goto out; } @@ -308,10 +295,9 @@ static int pm80x_rtc_probe(struct platform_device *pdev) info->rtc_dev->range_max = U32_MAX; ret = rtc_register_device(info->rtc_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + if (ret) goto out_rtc; - } + /* * enable internal XO instead of internal 3.25MHz clock since it can * free running in PMIC power-down state. diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index d25282b4a7dd..4743b16a8d84 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Real Time Clock driver for Marvell 88PM860x PMIC * * Copyright (c) 2010 Marvell International Ltd. * Author: Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> @@ -331,10 +328,8 @@ static int pm860x_rtc_probe(struct platform_device *pdev) if (!info) return -ENOMEM; info->irq = platform_get_irq(pdev, 0); - if (info->irq < 0) { - dev_err(&pdev->dev, "No IRQ resource!\n"); + if (info->irq < 0) return info->irq; - } info->chip = chip; info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; @@ -421,7 +416,7 @@ static int pm860x_rtc_remove(struct platform_device *pdev) struct pm860x_rtc_info *info = platform_get_drvdata(pdev); #ifdef VRTC_CALIBRATION - flush_scheduled_work(); + cancel_delayed_work_sync(&info->calib_work); /* disable measurement */ pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); #endif /* VRTC_CALIBRATION */ diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c index 2233601761ac..cdad6f00debf 100644 --- a/drivers/rtc/rtc-ab-b5ze-s3.c +++ b/drivers/rtc/rtc-ab-b5ze-s3.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * rtc-ab-b5ze-s3 - Driver for Abracon AB-RTCMC-32.768Khz-B5ZE-S3 * I2C RTC / Alarm chip @@ -10,19 +11,9 @@ * * This work is based on ISL12057 driver (drivers/rtc/rtc-isl12057.c). * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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> @@ -128,7 +119,6 @@ struct abb5zes3_rtc_data { struct rtc_device *rtc; struct regmap *regmap; - struct mutex lock; int irq; @@ -138,8 +128,7 @@ struct abb5zes3_rtc_data { /* * Try and match register bits w/ fixed null values to see whether we - * are dealing with an ABB5ZES3. Note: this function is called early - * during init and hence does need mutex protection. + * are dealing with an ABB5ZES3. */ static int abb5zes3_i2c_validate_chip(struct regmap *regmap) { @@ -230,14 +219,12 @@ static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ret) { dev_err(dev, "%s: reading RTC time failed (%d)\n", __func__, ret); - goto err; + return ret; } /* If clock integrity is not guaranteed, do not return a time value */ - if (regs[ABB5ZES3_REG_RTC_SC] & ABB5ZES3_REG_RTC_SC_OSC) { - ret = -ENODATA; - goto err; - } + if (regs[ABB5ZES3_REG_RTC_SC] & ABB5ZES3_REG_RTC_SC_OSC) + return -ENODATA; tm->tm_sec = bcd2bin(regs[ABB5ZES3_REG_RTC_SC] & 0x7F); tm->tm_min = bcd2bin(regs[ABB5ZES3_REG_RTC_MN]); @@ -255,7 +242,6 @@ static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mon = bcd2bin(regs[ABB5ZES3_REG_RTC_MO]) - 1; /* starts at 1 */ tm->tm_year = bcd2bin(regs[ABB5ZES3_REG_RTC_YR]) + 100; -err: return ret; } @@ -273,12 +259,9 @@ static int abb5zes3_rtc_set_time(struct device *dev, struct rtc_time *tm) regs[ABB5ZES3_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1); regs[ABB5ZES3_REG_RTC_YR] = bin2bcd(tm->tm_year - 100); - mutex_lock(&data->lock); ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_RTC_SC, regs + ABB5ZES3_REG_RTC_SC, ABB5ZES3_RTC_SEC_LEN); - mutex_unlock(&data->lock); - return ret; } @@ -332,38 +315,35 @@ static int _abb5zes3_rtc_read_timer(struct device *dev, if (ret) { dev_err(dev, "%s: reading Timer A section failed (%d)\n", __func__, ret); - goto err; + return ret; } /* get current time ... */ ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); if (ret) - goto err; + return ret; /* ... convert to seconds ... */ - ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); - if (ret) - goto err; + rtc_secs = rtc_tm_to_time64(&rtc_tm); /* ... add remaining timer A time ... */ ret = sec_from_timer_a(&timer_secs, regs[1], regs[2]); if (ret) - goto err; + return ret; /* ... and convert back. */ - rtc_time_to_tm(rtc_secs + timer_secs, alarm_tm); + rtc_time64_to_tm(rtc_secs + timer_secs, alarm_tm); ret = regmap_read(data->regmap, ABB5ZES3_REG_CTRL2, ®); if (ret) { dev_err(dev, "%s: reading ctrl reg failed (%d)\n", __func__, ret); - goto err; + return ret; } alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL2_WTAIE); -err: - return ret; + return 0; } /* Read alarm currently configured via a RTC alarm registers. */ @@ -382,7 +362,7 @@ static int _abb5zes3_rtc_read_alarm(struct device *dev, if (ret) { dev_err(dev, "%s: reading alarm section failed (%d)\n", __func__, ret); - goto err; + return ret; } alarm_tm->tm_sec = 0; @@ -398,18 +378,13 @@ static int _abb5zes3_rtc_read_alarm(struct device *dev, */ ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); if (ret) - goto err; + return ret; alarm_tm->tm_year = rtc_tm.tm_year; alarm_tm->tm_mon = rtc_tm.tm_mon; - ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); - if (ret) - goto err; - - ret = rtc_tm_to_time(alarm_tm, &alarm_secs); - if (ret) - goto err; + rtc_secs = rtc_tm_to_time64(&rtc_tm); + alarm_secs = rtc_tm_to_time64(alarm_tm); if (alarm_secs < rtc_secs) { if (alarm_tm->tm_mon == 11) { @@ -424,13 +399,12 @@ static int _abb5zes3_rtc_read_alarm(struct device *dev, if (ret) { dev_err(dev, "%s: reading ctrl reg failed (%d)\n", __func__, ret); - goto err; + return ret; } alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL1_AIE); -err: - return ret; + return 0; } /* @@ -447,12 +421,10 @@ static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); int ret; - mutex_lock(&data->lock); if (data->timer_alarm) ret = _abb5zes3_rtc_read_timer(dev, alarm); else ret = _abb5zes3_rtc_read_alarm(dev, alarm); - mutex_unlock(&data->lock); return ret; } @@ -466,33 +438,25 @@ static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); struct rtc_time *alarm_tm = &alarm->time; - unsigned long rtc_secs, alarm_secs; u8 regs[ABB5ZES3_ALRM_SEC_LEN]; struct rtc_time rtc_tm; int ret, enable = 1; - ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); - if (ret) - goto err; - - ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); - if (ret) - goto err; - - ret = rtc_tm_to_time(alarm_tm, &alarm_secs); - if (ret) - goto err; - - /* If alarm time is before current time, disable the alarm */ - if (!alarm->enabled || alarm_secs <= rtc_secs) { + if (!alarm->enabled) { enable = 0; } else { + unsigned long rtc_secs, alarm_secs; + /* * Chip only support alarms up to one month in the future. Let's * return an error if we get something after that limit. * Comparison is done by incrementing rtc_tm month field by one * and checking alarm value is still below. */ + ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); + if (ret) + return ret; + if (rtc_tm.tm_mon == 11) { /* handle year wrapping */ rtc_tm.tm_mon = 0; rtc_tm.tm_year += 1; @@ -500,15 +464,13 @@ static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) rtc_tm.tm_mon += 1; } - ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); - if (ret) - goto err; + rtc_secs = rtc_tm_to_time64(&rtc_tm); + alarm_secs = rtc_tm_to_time64(alarm_tm); if (alarm_secs > rtc_secs) { - dev_err(dev, "%s: alarm maximum is one month in the " - "future (%d)\n", __func__, ret); - ret = -EINVAL; - goto err; + dev_err(dev, "%s: alarm maximum is one month in the future (%d)\n", + __func__, ret); + return -EINVAL; } } @@ -526,17 +488,14 @@ static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) if (ret < 0) { dev_err(dev, "%s: writing ALARM section failed (%d)\n", __func__, ret); - goto err; + return ret; } /* Record currently configured alarm is not a timer */ data->timer_alarm = 0; /* Enable or disable alarm interrupt generation */ - ret = _abb5zes3_rtc_update_alarm(dev, enable); - -err: - return ret; + return _abb5zes3_rtc_update_alarm(dev, enable); } /* @@ -557,7 +516,7 @@ static int _abb5zes3_rtc_set_timer(struct device *dev, struct rtc_wkalrm *alarm, ABB5ZES3_TIMA_SEC_LEN); if (ret < 0) { dev_err(dev, "%s: writing timer section failed\n", __func__); - goto err; + return ret; } /* Configure Timer A as a watchdog timer */ @@ -570,10 +529,7 @@ static int _abb5zes3_rtc_set_timer(struct device *dev, struct rtc_wkalrm *alarm, data->timer_alarm = 1; /* Enable or disable timer interrupt generation */ - ret = _abb5zes3_rtc_update_timer(dev, alarm->enabled); - -err: - return ret; + return _abb5zes3_rtc_update_timer(dev, alarm->enabled); } /* @@ -590,31 +546,25 @@ static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) struct rtc_time rtc_tm; int ret; - mutex_lock(&data->lock); ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); if (ret) - goto err; + return ret; - ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); - if (ret) - goto err; - - ret = rtc_tm_to_time(alarm_tm, &alarm_secs); - if (ret) - goto err; + rtc_secs = rtc_tm_to_time64(&rtc_tm); + alarm_secs = rtc_tm_to_time64(alarm_tm); /* Let's first disable both the alarm and the timer interrupts */ ret = _abb5zes3_rtc_update_alarm(dev, false); if (ret < 0) { dev_err(dev, "%s: unable to disable alarm (%d)\n", __func__, ret); - goto err; + return ret; } ret = _abb5zes3_rtc_update_timer(dev, false); if (ret < 0) { dev_err(dev, "%s: unable to disable timer (%d)\n", __func__, ret); - goto err; + return ret; } data->timer_alarm = 0; @@ -629,9 +579,6 @@ static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) else ret = _abb5zes3_rtc_set_alarm(dev, alarm); - err: - mutex_unlock(&data->lock); - if (ret) dev_err(dev, "%s: unable to configure alarm (%d)\n", __func__, ret); @@ -650,8 +597,7 @@ static inline int _abb5zes3_rtc_battery_low_irq_enable(struct regmap *regmap, /* * 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. + * everything went ok and a negative value upon error. */ static int abb5zes3_rtc_check_setup(struct device *dev) { @@ -675,8 +621,9 @@ static int abb5zes3_rtc_check_setup(struct device *dev) ABB5ZES3_REG_TIM_CLK_COF1 | ABB5ZES3_REG_TIM_CLK_COF2 | ABB5ZES3_REG_TIM_CLK_TBM | ABB5ZES3_REG_TIM_CLK_TAM); ret = regmap_update_bits(regmap, ABB5ZES3_REG_TIM_CLK, mask, - ABB5ZES3_REG_TIM_CLK_COF0 | ABB5ZES3_REG_TIM_CLK_COF1 | - ABB5ZES3_REG_TIM_CLK_COF2); + ABB5ZES3_REG_TIM_CLK_COF0 | + ABB5ZES3_REG_TIM_CLK_COF1 | + ABB5ZES3_REG_TIM_CLK_COF2); if (ret < 0) { dev_err(dev, "%s: unable to initialize clkout register (%d)\n", __func__, ret); @@ -729,9 +676,9 @@ static int abb5zes3_rtc_check_setup(struct device *dev) * switchover flag but not battery low flag. The latter is checked * later below. */ - mask = (ABB5ZES3_REG_CTRL3_PM0 | ABB5ZES3_REG_CTRL3_PM1 | - ABB5ZES3_REG_CTRL3_PM2 | ABB5ZES3_REG_CTRL3_BLIE | - ABB5ZES3_REG_CTRL3_BSIE| ABB5ZES3_REG_CTRL3_BSF); + mask = (ABB5ZES3_REG_CTRL3_PM0 | ABB5ZES3_REG_CTRL3_PM1 | + ABB5ZES3_REG_CTRL3_PM2 | ABB5ZES3_REG_CTRL3_BLIE | + ABB5ZES3_REG_CTRL3_BSIE | ABB5ZES3_REG_CTRL3_BSF); ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL3, mask, 0); if (ret < 0) { dev_err(dev, "%s: unable to initialize CTRL3 register (%d)\n", @@ -748,10 +695,8 @@ static int abb5zes3_rtc_check_setup(struct device *dev) } if (reg & ABB5ZES3_REG_RTC_SC_OSC) { - dev_err(dev, "clock integrity not guaranteed. Osc. has stopped " - "or has been interrupted.\n"); - dev_err(dev, "change battery (if not already done) and " - "then set time to reset osc. failure flag.\n"); + dev_err(dev, "clock integrity not guaranteed. Osc. has stopped or has been interrupted.\n"); + dev_err(dev, "change battery (if not already done) and then set time to reset osc. failure flag.\n"); } /* @@ -769,13 +714,12 @@ static int abb5zes3_rtc_check_setup(struct device *dev) data->battery_low = reg & ABB5ZES3_REG_CTRL3_BLF; if (data->battery_low) { - dev_err(dev, "RTC battery is low; please, consider " - "changing it!\n"); + dev_err(dev, "RTC battery is low; please, consider changing it!\n"); ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, false); if (ret) - dev_err(dev, "%s: disabling battery low interrupt " - "generation failed (%d)\n", __func__, ret); + dev_err(dev, "%s: disabling battery low interrupt generation failed (%d)\n", + __func__, ret); } return ret; @@ -788,12 +732,10 @@ static int abb5zes3_rtc_alarm_irq_enable(struct device *dev, int ret = 0; if (rtc_data->irq) { - mutex_lock(&rtc_data->lock); if (rtc_data->timer_alarm) ret = _abb5zes3_rtc_update_timer(dev, enable); else ret = _abb5zes3_rtc_update_alarm(dev, enable); - mutex_unlock(&rtc_data->lock); } return ret; @@ -885,49 +827,44 @@ static int abb5zes3_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) { - ret = -ENODEV; - goto err; - } + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; regmap = devm_regmap_init_i2c(client, &abb5zes3_rtc_regmap_config); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); dev_err(dev, "%s: regmap allocation failed: %d\n", __func__, ret); - goto err; + return ret; } ret = abb5zes3_i2c_validate_chip(regmap); if (ret) - goto err; + return ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto err; - } + if (!data) + return -ENOMEM; - mutex_init(&data->lock); data->regmap = regmap; dev_set_drvdata(dev, data); ret = abb5zes3_rtc_check_setup(dev); if (ret) - goto err; + return ret; data->rtc = devm_rtc_allocate_device(dev); ret = PTR_ERR_OR_ZERO(data->rtc); if (ret) { dev_err(dev, "%s: unable to allocate RTC device (%d)\n", __func__, ret); - goto err; + return ret; } if (client->irq > 0) { ret = devm_request_threaded_irq(dev, client->irq, NULL, _abb5zes3_rtc_interrupt, - IRQF_SHARED|IRQF_ONESHOT, + IRQF_SHARED | IRQF_ONESHOT, DRV_NAME, client); if (!ret) { device_init_wakeup(dev, true); @@ -949,8 +886,8 @@ static int abb5zes3_probe(struct i2c_client *client, if (!data->battery_low && data->irq) { ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, true); if (ret) { - dev_err(dev, "%s: enabling battery low interrupt " - "generation failed (%d)\n", __func__, ret); + dev_err(dev, "%s: enabling battery low interrupt generation failed (%d)\n", + __func__, ret); goto err; } } @@ -958,7 +895,7 @@ static int abb5zes3_probe(struct i2c_client *client, ret = rtc_register_device(data->rtc); err: - if (ret && data && data->irq) + if (ret && data->irq) device_init_wakeup(dev, false); return ret; } diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c index e4f6e0061ccf..d690985caa4c 100644 --- a/drivers/rtc/rtc-ab-eoz9.c +++ b/drivers/rtc/rtc-ab-eoz9.c @@ -390,35 +390,31 @@ static int abeoz9_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) { - ret = -ENODEV; - goto err; - } + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; regmap = devm_regmap_init_i2c(client, &abeoz9_rtc_regmap_config); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); dev_err(dev, "regmap allocation failed: %d\n", ret); - goto err; + return ret; } data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto err; - } + if (!data) + return -ENOMEM; data->regmap = regmap; dev_set_drvdata(dev, data); ret = abeoz9_rtc_setup(dev, client->dev.of_node); if (ret) - goto err; + return ret; data->rtc = devm_rtc_allocate_device(dev); ret = PTR_ERR_OR_ZERO(data->rtc); if (ret) - goto err; + return ret; data->rtc->ops = &rtc_ops; data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; @@ -426,14 +422,10 @@ static int abeoz9_probe(struct i2c_client *client, ret = rtc_register_device(data->rtc); if (ret) - goto err; + return ret; abeoz9_hwmon_register(dev, data); return 0; - -err: - dev_err(dev, "unable to register RTC device (%d)\n", ret); - return ret; } #ifdef CONFIG_OF diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c index 821ff52a2222..2ed6def90975 100644 --- a/drivers/rtc/rtc-ab3100.c +++ b/drivers/rtc/rtc-ab3100.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007-2009 ST-Ericsson AB - * License terms: GNU General Public License (GPL) version 2 * RTC clock driver for the AB3100 Analog Baseband Chip * Author: Linus Walleij <linus.walleij@stericsson.com> */ @@ -43,12 +43,12 @@ /* * RTC clock functions and device struct declaration */ -static int ab3100_rtc_set_mmss(struct device *dev, time64_t secs) +static int ab3100_rtc_set_time(struct device *dev, struct rtc_time *tm) { u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2, AB3100_TI3, AB3100_TI4, AB3100_TI5}; unsigned char buf[6]; - u64 hw_counter = secs * AB3100_RTC_CLOCK_RATE * 2; + u64 hw_counter = rtc_tm_to_time64(tm) * AB3100_RTC_CLOCK_RATE * 2; int err = 0; int i; @@ -192,7 +192,7 @@ static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled) static const struct rtc_class_ops ab3100_rtc_ops = { .read_time = ab3100_rtc_read_time, - .set_mmss64 = ab3100_rtc_set_mmss, + .set_time = ab3100_rtc_set_time, .read_alarm = ab3100_rtc_read_alarm, .set_alarm = ab3100_rtc_set_alarm, .alarm_irq_enable = ab3100_rtc_irq_enable, @@ -228,15 +228,17 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) /* Ignore any error on this write */ } - rtc = devm_rtc_device_register(&pdev->dev, "ab3100-rtc", - &ab3100_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - err = PTR_ERR(rtc); - return err; - } + rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + rtc->ops = &ab3100_rtc_ops; + /* 48bit counter at (AB3100_RTC_CLOCK_RATE * 2) */ + rtc->range_max = U32_MAX; + platform_set_drvdata(pdev, rtc); - return 0; + return rtc_register_device(rtc); } static struct platform_driver ab3100_rtc_driver = { diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 1f0cbd51ba06..8492ffed4ca6 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) ST-Ericsson SA 2010 * - * License terms: GNU General Public License (GPL) version 2 * Author: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com> * * RTC clock driver for the RTC part of the AB8500 Power management chip. diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 6ddcad642d1e..73830670a41f 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * A driver for the I2C members of the Abracon AB x8xx RTC family, * and compatible: AB 1805 and AB 0805 @@ -7,10 +8,6 @@ * Author: Philippe De Muyter <phdm@macqel.be> * Author: Alexandre Belloni <alexandre.belloni@bootlin.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/bcd.h> @@ -404,7 +401,7 @@ static ssize_t autocalibration_store(struct device *dev, return -EINVAL; } - retval = abx80x_rtc_set_autocalibration(dev, autocalibration); + retval = abx80x_rtc_set_autocalibration(dev->parent, autocalibration); return retval ? retval : count; } @@ -414,7 +411,7 @@ static ssize_t autocalibration_show(struct device *dev, { int autocalibration = 0; - autocalibration = abx80x_rtc_get_autocalibration(dev); + autocalibration = abx80x_rtc_get_autocalibration(dev->parent); if (autocalibration < 0) { dev_err(dev, "Failed to read RTC autocalibration\n"); sprintf(buf, "0\n"); @@ -430,7 +427,7 @@ static ssize_t oscillator_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev->parent); int retval, flags, rc_mode = 0; if (strncmp(buf, "rc", 2) == 0) { @@ -472,7 +469,7 @@ static ssize_t oscillator_show(struct device *dev, struct device_attribute *attr, char *buf) { int rc_mode = 0; - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev->parent); rc_mode = abx80x_is_rc_mode(client); @@ -592,13 +589,6 @@ static int abx80x_dt_trickle_cfg(struct device_node *np) return (trickle_cfg | i); } -static void rtc_calib_remove_sysfs_group(void *_dev) -{ - struct device *dev = _dev; - - sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group); -} - #ifdef CONFIG_WATCHDOG static inline u8 timeout_bits(unsigned int timeout) @@ -851,32 +841,14 @@ static int abx80x_probe(struct i2c_client *client, } } - /* Export sysfs entries */ - err = sysfs_create_group(&(&client->dev)->kobj, &rtc_calib_attr_group); + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); if (err) { dev_err(&client->dev, "Failed to create sysfs group: %d\n", err); return err; } - err = devm_add_action_or_reset(&client->dev, - rtc_calib_remove_sysfs_group, - &client->dev); - if (err) { - dev_err(&client->dev, - "Failed to add sysfs cleanup action: %d\n", - err); - return err; - } - - err = rtc_register_device(priv->rtc); - - return err; -} - -static int abx80x_remove(struct i2c_client *client) -{ - return 0; + return rtc_register_device(priv->rtc); } static const struct i2c_device_id abx80x_id[] = { @@ -899,7 +871,6 @@ static struct i2c_driver abx80x_driver = { .name = "rtc-abx80x", }, .probe = abx80x_probe, - .remove = abx80x_remove, .id_table = abx80x_id, }; diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 784b676284bf..29223931aba7 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC Driver for X-Powers AC100 * * Copyright (c) 2016 Chen-Yu Tsai * * Chen-Yu Tsai <wens@csie.org> - * - * 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. - * - * 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> @@ -586,10 +578,8 @@ static int ac100_rtc_probe(struct platform_device *pdev) chip->regmap = ac100->regmap; chip->irq = platform_get_irq(pdev, 0); - if (chip->irq < 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); + if (chip->irq < 0) return chip->irq; - } chip->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(chip->rtc)) @@ -620,15 +610,7 @@ static int ac100_rtc_probe(struct platform_device *pdev) if (ret) return ret; - ret = rtc_register_device(chip->rtc); - if (ret) { - dev_err(&pdev->dev, "unable to register device\n"); - return ret; - } - - dev_info(&pdev->dev, "RTC enabled\n"); - - return 0; + return rtc_register_device(chip->rtc); } static int ac100_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 9e78f004670b..9351bd52477e 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * RTC driver for the Armada 38x Marvell SoCs * * Copyright (C) 2015 Marvell * * Gregory Clement <gregory.clement@free-electrons.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * */ #include <linux/delay.h> @@ -507,7 +502,6 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) struct resource *res; struct armada38x_rtc *rtc; const struct of_device_id *match; - int ret; match = of_match_device(armada38x_rtc_of_match_table, &pdev->dev); if (!match) @@ -535,11 +529,8 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtc->regs_soc); rtc->irq = platform_get_irq(pdev, 0); - - if (rtc->irq < 0) { - dev_err(&pdev->dev, "no irq\n"); + if (rtc->irq < 0) return rtc->irq; - } rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc_dev)) @@ -569,11 +560,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) rtc->rtc_dev->range_max = U32_MAX; - ret = rtc_register_device(rtc->rtc_dev); - if (ret) - dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); - - return ret; + return rtc_register_device(rtc->rtc_dev); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c index 6ef0c887e6ca..0f21af27f4cf 100644 --- a/drivers/rtc/rtc-as3722.c +++ b/drivers/rtc/rtc-as3722.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs * @@ -6,16 +7,6 @@ * * 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> diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c index d36534965635..10413d803caa 100644 --- a/drivers/rtc/rtc-asm9260.c +++ b/drivers/rtc/rtc-asm9260.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 Oleksij Rempel <linux@rempel-privat.de> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, - * or (at your option) any later version. */ #include <linux/clk.h> @@ -261,10 +257,8 @@ static int asm9260_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); irq_alarm = platform_get_irq(pdev, 0); - if (irq_alarm < 0) { - dev_err(dev, "No alarm IRQ resource defined\n"); + if (irq_alarm < 0) return irq_alarm; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->iobase = devm_ioremap_resource(dev, res); diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c new file mode 100644 index 000000000000..e351d35b29a3 --- /dev/null +++ b/drivers/rtc/rtc-aspeed.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2015 IBM Corp. + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/io.h> + +struct aspeed_rtc { + struct rtc_device *rtc_dev; + void __iomem *base; +}; + +#define RTC_TIME 0x00 +#define RTC_YEAR 0x04 +#define RTC_CTRL 0x10 + +#define RTC_UNLOCK BIT(1) +#define RTC_ENABLE BIT(0) + +static int aspeed_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct aspeed_rtc *rtc = dev_get_drvdata(dev); + unsigned int cent, year; + u32 reg1, reg2; + + if (!(readl(rtc->base + RTC_CTRL) & RTC_ENABLE)) { + dev_dbg(dev, "%s failing as rtc disabled\n", __func__); + return -EINVAL; + } + + do { + reg2 = readl(rtc->base + RTC_YEAR); + reg1 = readl(rtc->base + RTC_TIME); + } while (reg2 != readl(rtc->base + RTC_YEAR)); + + tm->tm_mday = (reg1 >> 24) & 0x1f; + tm->tm_hour = (reg1 >> 16) & 0x1f; + tm->tm_min = (reg1 >> 8) & 0x3f; + tm->tm_sec = (reg1 >> 0) & 0x3f; + + cent = (reg2 >> 16) & 0x1f; + year = (reg2 >> 8) & 0x7f; + tm->tm_mon = ((reg2 >> 0) & 0x0f) - 1; + tm->tm_year = year + (cent * 100) - 1900; + + dev_dbg(dev, "%s %ptR", __func__, tm); + + return 0; +} + +static int aspeed_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct aspeed_rtc *rtc = dev_get_drvdata(dev); + u32 reg1, reg2, ctrl; + int year, cent; + + cent = (tm->tm_year + 1900) / 100; + year = tm->tm_year % 100; + + reg1 = (tm->tm_mday << 24) | (tm->tm_hour << 16) | (tm->tm_min << 8) | + tm->tm_sec; + + reg2 = ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) | + ((tm->tm_mon + 1) & 0xf); + + ctrl = readl(rtc->base + RTC_CTRL); + writel(ctrl | RTC_UNLOCK, rtc->base + RTC_CTRL); + + writel(reg1, rtc->base + RTC_TIME); + writel(reg2, rtc->base + RTC_YEAR); + + /* Re-lock and ensure enable is set now that a time is programmed */ + writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL); + + return 0; +} + +static const struct rtc_class_ops aspeed_rtc_ops = { + .read_time = aspeed_rtc_read_time, + .set_time = aspeed_rtc_set_time, +}; + +static int aspeed_rtc_probe(struct platform_device *pdev) +{ + struct aspeed_rtc *rtc; + struct resource *res; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rtc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rtc->base)) + return PTR_ERR(rtc->base); + + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + + platform_set_drvdata(pdev, rtc); + + rtc->rtc_dev->ops = &aspeed_rtc_ops; + rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900; + rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */ + + return rtc_register_device(rtc->rtc_dev); +} + +static const struct of_device_id aspeed_rtc_match[] = { + { .compatible = "aspeed,ast2400-rtc", }, + { .compatible = "aspeed,ast2500-rtc", }, + { .compatible = "aspeed,ast2600-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, aspeed_rtc_match); + +static struct platform_driver aspeed_rtc_driver = { + .driver = { + .name = "aspeed-rtc", + .of_match_table = of_match_ptr(aspeed_rtc_match), + }, +}; + +module_platform_driver_probe(aspeed_rtc_driver, aspeed_rtc_probe); + +MODULE_DESCRIPTION("ASPEED RTC driver"); +MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 862b993c3142..d119c6e6353e 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Real Time Clock interface for Linux on Atmel AT91RM9200 * @@ -10,12 +11,6 @@ * * Based on sa1100-rtc.c by Nils Faerber * Based on rtc.c by Paul Gortmaker - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * */ #include <linux/bcd.h> @@ -383,10 +378,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource defined\n"); + if (irq < 0) return -ENXIO; - } at91_rtc_regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); diff --git a/drivers/rtc/rtc-at91rm9200.h b/drivers/rtc/rtc-at91rm9200.h index da1945e5f714..8be5289da8e2 100644 --- a/drivers/rtc/rtc-at91rm9200.h +++ b/drivers/rtc/rtc-at91rm9200.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * arch/arm/mach-at91/include/mach/at91_rtc.h * @@ -6,11 +7,6 @@ * * Real Time Clock (RTC) - System peripheral registers. * Based on AT91RM9200 datasheet revision E. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #ifndef AT91_RTC_H diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 1d31c0ae6334..bb3ba7bfe6a5 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * "RTT as Real Time Clock" driver for AT91SAM9 SoC family * * (C) 2007 Michel Benoit * * Based on rtc-at91rm9200.c by Rick Bronson - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/clk.h> @@ -47,21 +43,21 @@ * registers available, likewise usable for more than "RTC" support. */ -#define AT91_RTT_MR 0x00 /* Real-time Mode Register */ -#define AT91_RTT_RTPRES (0xffff << 0) /* Real-time Timer Prescaler Value */ -#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */ -#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */ -#define AT91_RTT_RTTRST (1 << 18) /* Real Time Timer Restart */ +#define AT91_RTT_MR 0x00 /* Real-time Mode Register */ +#define AT91_RTT_RTPRES (0xffff << 0) /* Timer Prescaler Value */ +#define AT91_RTT_ALMIEN BIT(16) /* Alarm Interrupt Enable */ +#define AT91_RTT_RTTINCIEN BIT(17) /* Increment Interrupt Enable */ +#define AT91_RTT_RTTRST BIT(18) /* Timer Restart */ -#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */ -#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */ +#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */ +#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */ -#define AT91_RTT_VR 0x08 /* Real-time Value Register */ -#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */ +#define AT91_RTT_VR 0x08 /* Real-time Value Register */ +#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */ -#define AT91_RTT_SR 0x0c /* Real-time Status Register */ -#define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */ -#define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */ +#define AT91_RTT_SR 0x0c /* Real-time Status Register */ +#define AT91_RTT_ALMS BIT(0) /* Alarm Status */ +#define AT91_RTT_RTTINC BIT(1) /* Timer Increment */ /* * We store ALARM_DISABLED in ALMV to record that no alarm is set. @@ -69,14 +65,13 @@ */ #define ALARM_DISABLED ((u32)~0) - struct sam9_rtc { void __iomem *rtt; struct rtc_device *rtcdev; u32 imr; struct regmap *gpbr; unsigned int gpbr_offset; - int irq; + int irq; struct clk *sclk; bool suspended; unsigned long events; @@ -122,7 +117,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) if (secs != secs2) secs = rtt_readl(rtc, VR); - rtc_time_to_tm(offset + secs, tm); + rtc_time64_to_tm(offset + secs, tm); dev_dbg(dev, "%s: %ptR\n", __func__, tm); @@ -135,15 +130,12 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) { struct sam9_rtc *rtc = dev_get_drvdata(dev); - int err; u32 offset, alarm, mr; unsigned long secs; dev_dbg(dev, "%s: %ptR\n", __func__, tm); - err = rtc_tm_to_time(tm, &secs); - if (err != 0) - return err; + secs = rtc_tm_to_time64(tm); mr = rtt_readl(rtc, MR); @@ -193,7 +185,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) memset(alrm, 0, sizeof(*alrm)); if (alarm != ALARM_DISABLED && offset != 0) { - rtc_time_to_tm(offset + alarm, tm); + rtc_time64_to_tm(offset + alarm, tm); dev_dbg(dev, "%s: %ptR\n", __func__, tm); @@ -211,11 +203,8 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned long secs; u32 offset; u32 mr; - int err; - err = rtc_tm_to_time(tm, &secs); - if (err != 0) - return err; + secs = rtc_tm_to_time64(tm); offset = gpbr_readl(rtc); if (offset == 0) { @@ -263,7 +252,7 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq) u32 mr = rtt_readl(rtc, MR); seq_printf(seq, "update_IRQ\t: %s\n", - (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no"); + (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no"); return 0; } @@ -299,7 +288,7 @@ static void at91_rtc_flush_events(struct sam9_rtc *rtc) rtc->events = 0; pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, - rtc->events >> 8, rtc->events & 0x000000FF); + rtc->events >> 8, rtc->events & 0x000000FF); } /* @@ -340,13 +329,6 @@ static const struct rtc_class_ops at91_rtc_ops = { .alarm_irq_enable = at91_rtc_alarm_irq_enable, }; -static const struct regmap_config gpbr_regmap_config = { - .name = "gpbr", - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, -}; - /* * Initialize and install RTC driver */ @@ -357,12 +339,11 @@ static int at91_rtc_probe(struct platform_device *pdev) int ret, irq; u32 mr; unsigned int sclk_rate; + struct of_phandle_args args; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get interrupt resource\n"); + if (irq < 0) return irq; - } rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) @@ -382,34 +363,14 @@ static int at91_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc->rtt)) return PTR_ERR(rtc->rtt); - if (!pdev->dev.of_node) { - /* - * TODO: Remove this code chunk when removing non DT board - * support. Remember to remove the gpbr_regmap_config - * variable too. - */ - void __iomem *gpbr; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 1); - gpbr = devm_ioremap_resource(&pdev->dev, r); - if (IS_ERR(gpbr)) - return PTR_ERR(gpbr); - - rtc->gpbr = regmap_init_mmio(NULL, gpbr, - &gpbr_regmap_config); - } else { - struct of_phandle_args args; - - ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "atmel,rtt-rtc-time-reg", 1, 0, - &args); - if (ret) - return ret; - - rtc->gpbr = syscon_node_to_regmap(args.np); - rtc->gpbr_offset = args.args[0]; - } + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "atmel,rtt-rtc-time-reg", 1, 0, + &args); + if (ret) + return ret; + rtc->gpbr = syscon_node_to_regmap(args.np); + rtc->gpbr_offset = args.args[0]; if (IS_ERR(rtc->gpbr)) { dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n"); return -ENOMEM; @@ -444,13 +405,15 @@ static int at91_rtc_probe(struct platform_device *pdev) mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); rtt_writel(rtc, MR, mr); - rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name, - &at91_rtc_ops, THIS_MODULE); + rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtcdev)) { ret = PTR_ERR(rtc->rtcdev); goto err_clk; } + rtc->rtcdev->ops = &at91_rtc_ops; + rtc->rtcdev->range_max = U32_MAX; + /* register irq handler after we know what name we'll use */ ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, IRQF_SHARED | IRQF_COND_SUSPEND, @@ -468,9 +431,9 @@ static int at91_rtc_probe(struct platform_device *pdev) if (gpbr_readl(rtc) == 0) dev_warn(&pdev->dev, "%s: SET TIME!\n", - dev_name(&rtc->rtcdev->dev)); + dev_name(&rtc->rtcdev->dev)); - return 0; + return rtc_register_device(rtc->rtcdev); err_clk: clk_disable_unprepare(rtc->sclk); @@ -528,8 +491,9 @@ static int at91_rtc_suspend(struct device *dev) /* don't let RTTINC cause wakeups */ if (mr & AT91_RTT_RTTINCIEN) rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); - } else + } else { rtt_writel(rtc, MR, mr & ~rtc->imr); + } } return 0; @@ -561,13 +525,11 @@ static int at91_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); -#ifdef CONFIG_OF static const struct of_device_id at91_rtc_dt_ids[] = { { .compatible = "atmel,at91sam9260-rtt" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); -#endif static struct platform_driver at91_rtc_driver = { .probe = at91_rtc_probe, diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c new file mode 100644 index 000000000000..7744333b0f40 --- /dev/null +++ b/drivers/rtc/rtc-bd70528.c @@ -0,0 +1,493 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Copyright (C) 2018 ROHM Semiconductors +// +// RTC driver for ROHM BD70528 PMIC + +#include <linux/bcd.h> +#include <linux/mfd/rohm-bd70528.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/rtc.h> + +/* + * We read regs RTC_SEC => RTC_YEAR + * this struct is ordered according to chip registers. + * Keep it u8 only to avoid padding issues. + */ +struct bd70528_rtc_day { + u8 sec; + u8 min; + u8 hour; +} __packed; + +struct bd70528_rtc_data { + struct bd70528_rtc_day time; + u8 week; + u8 day; + u8 month; + u8 year; +} __packed; + +struct bd70528_rtc_wake { + struct bd70528_rtc_day time; + u8 ctrl; +} __packed; + +struct bd70528_rtc_alm { + struct bd70528_rtc_data data; + u8 alm_mask; + u8 alm_repeat; +} __packed; + +struct bd70528_rtc { + struct rohm_regmap_dev *mfd; + struct device *dev; +}; + +static int bd70528_set_wake(struct rohm_regmap_dev *bd70528, + int enable, int *old_state) +{ + int ret; + unsigned int ctrl_reg; + + ret = regmap_read(bd70528->regmap, BD70528_REG_WAKE_EN, &ctrl_reg); + if (ret) + return ret; + + if (old_state) { + if (ctrl_reg & BD70528_MASK_WAKE_EN) + *old_state |= BD70528_WAKE_STATE_BIT; + else + *old_state &= ~BD70528_WAKE_STATE_BIT; + + if (!enable == !(*old_state & BD70528_WAKE_STATE_BIT)) + return 0; + } + + if (enable) + ctrl_reg |= BD70528_MASK_WAKE_EN; + else + ctrl_reg &= ~BD70528_MASK_WAKE_EN; + + return regmap_write(bd70528->regmap, BD70528_REG_WAKE_EN, + ctrl_reg); +} + +static int bd70528_set_elapsed_tmr(struct rohm_regmap_dev *bd70528, + int enable, int *old_state) +{ + int ret; + unsigned int ctrl_reg; + + /* + * TBD + * What is the purpose of elapsed timer ? + * Is the timeout registers counting down, or is the disable - re-enable + * going to restart the elapsed-time counting? If counting is restarted + * the timeout should be decreased by the amount of time that has + * elapsed since starting the timer. Maybe we should store the monotonic + * clock value when timer is started so that if RTC is set while timer + * is armed we could do the compensation. This is a hack if RTC/system + * clk are drifting. OTOH, RTC controlled via I2C is in any case + * inaccurate... + */ + ret = regmap_read(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN, + &ctrl_reg); + if (ret) + return ret; + + if (old_state) { + if (ctrl_reg & BD70528_MASK_ELAPSED_TIMER_EN) + *old_state |= BD70528_ELAPSED_STATE_BIT; + else + *old_state &= ~BD70528_ELAPSED_STATE_BIT; + + if ((!enable) == (!(*old_state & BD70528_ELAPSED_STATE_BIT))) + return 0; + } + + if (enable) + ctrl_reg |= BD70528_MASK_ELAPSED_TIMER_EN; + else + ctrl_reg &= ~BD70528_MASK_ELAPSED_TIMER_EN; + + return regmap_write(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN, + ctrl_reg); +} + +static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, + int *old_state) +{ + int ret; + + ret = bd70528_wdt_set(r->mfd, new_state & BD70528_WDT_STATE_BIT, + old_state); + if (ret) { + dev_err(r->dev, + "Failed to disable WDG for RTC setting (%d)\n", ret); + return ret; + } + ret = bd70528_set_elapsed_tmr(r->mfd, + new_state & BD70528_ELAPSED_STATE_BIT, + old_state); + if (ret) { + dev_err(r->dev, + "Failed to disable 'elapsed timer' for RTC setting\n"); + return ret; + } + ret = bd70528_set_wake(r->mfd, new_state & BD70528_WAKE_STATE_BIT, + old_state); + if (ret) { + dev_err(r->dev, + "Failed to disable 'wake timer' for RTC setting\n"); + return ret; + } + + return ret; +} + +static int bd70528_re_enable_rtc_based_timers(struct bd70528_rtc *r, + int old_state) +{ + return bd70528_set_rtc_based_timers(r, old_state, NULL); +} + +static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r, + int *old_state) +{ + return bd70528_set_rtc_based_timers(r, 0, old_state); +} + +static inline void tmday2rtc(struct rtc_time *t, struct bd70528_rtc_day *d) +{ + d->sec &= ~BD70528_MASK_RTC_SEC; + d->min &= ~BD70528_MASK_RTC_MINUTE; + d->hour &= ~BD70528_MASK_RTC_HOUR; + d->sec |= bin2bcd(t->tm_sec); + d->min |= bin2bcd(t->tm_min); + d->hour |= bin2bcd(t->tm_hour); +} + +static inline void tm2rtc(struct rtc_time *t, struct bd70528_rtc_data *r) +{ + r->day &= ~BD70528_MASK_RTC_DAY; + r->week &= ~BD70528_MASK_RTC_WEEK; + r->month &= ~BD70528_MASK_RTC_MONTH; + /* + * PM and 24H bits are not used by Wake - thus we clear them + * here and not in tmday2rtc() which is also used by wake. + */ + r->time.hour &= ~(BD70528_MASK_RTC_HOUR_PM | BD70528_MASK_RTC_HOUR_24H); + + tmday2rtc(t, &r->time); + /* + * We do always set time in 24H mode. + */ + r->time.hour |= BD70528_MASK_RTC_HOUR_24H; + r->day |= bin2bcd(t->tm_mday); + r->week |= bin2bcd(t->tm_wday); + r->month |= bin2bcd(t->tm_mon + 1); + r->year = bin2bcd(t->tm_year - 100); +} + +static inline void rtc2tm(struct bd70528_rtc_data *r, struct rtc_time *t) +{ + t->tm_sec = bcd2bin(r->time.sec & BD70528_MASK_RTC_SEC); + t->tm_min = bcd2bin(r->time.min & BD70528_MASK_RTC_MINUTE); + t->tm_hour = bcd2bin(r->time.hour & BD70528_MASK_RTC_HOUR); + /* + * If RTC is in 12H mode, then bit BD70528_MASK_RTC_HOUR_PM + * is not BCD value but tells whether it is AM or PM + */ + if (!(r->time.hour & BD70528_MASK_RTC_HOUR_24H)) { + t->tm_hour %= 12; + if (r->time.hour & BD70528_MASK_RTC_HOUR_PM) + t->tm_hour += 12; + } + t->tm_mday = bcd2bin(r->day & BD70528_MASK_RTC_DAY); + t->tm_mon = bcd2bin(r->month & BD70528_MASK_RTC_MONTH) - 1; + t->tm_year = 100 + bcd2bin(r->year & BD70528_MASK_RTC_YEAR); + t->tm_wday = bcd2bin(r->week & BD70528_MASK_RTC_WEEK); +} + +static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) +{ + struct bd70528_rtc_wake wake; + struct bd70528_rtc_alm alm; + int ret; + struct bd70528_rtc *r = dev_get_drvdata(dev); + struct rohm_regmap_dev *bd70528 = r->mfd; + + ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_WAKE_START, + &wake, sizeof(wake)); + if (ret) { + dev_err(dev, "Failed to read wake regs\n"); + return ret; + } + + ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START, + &alm, sizeof(alm)); + if (ret) { + dev_err(dev, "Failed to read alarm regs\n"); + return ret; + } + + tm2rtc(&a->time, &alm.data); + tmday2rtc(&a->time, &wake.time); + + if (a->enabled) { + alm.alm_mask &= ~BD70528_MASK_ALM_EN; + wake.ctrl |= BD70528_MASK_WAKE_EN; + } else { + alm.alm_mask |= BD70528_MASK_ALM_EN; + wake.ctrl &= ~BD70528_MASK_WAKE_EN; + } + + ret = regmap_bulk_write(bd70528->regmap, + BD70528_REG_RTC_WAKE_START, &wake, + sizeof(wake)); + if (ret) { + dev_err(dev, "Failed to set wake time\n"); + return ret; + } + ret = regmap_bulk_write(bd70528->regmap, BD70528_REG_RTC_ALM_START, + &alm, sizeof(alm)); + if (ret) + dev_err(dev, "Failed to set alarm time\n"); + + return ret; +} + +static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a) +{ + struct bd70528_rtc_alm alm; + int ret; + struct bd70528_rtc *r = dev_get_drvdata(dev); + struct rohm_regmap_dev *bd70528 = r->mfd; + + ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START, + &alm, sizeof(alm)); + if (ret) { + dev_err(dev, "Failed to read alarm regs\n"); + return ret; + } + + rtc2tm(&alm.data, &a->time); + a->time.tm_mday = -1; + a->time.tm_mon = -1; + a->time.tm_year = -1; + a->enabled = !(alm.alm_mask & BD70528_MASK_ALM_EN); + a->pending = 0; + + return 0; +} + +static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) +{ + int ret, tmpret, old_states; + struct bd70528_rtc_data rtc_data; + struct bd70528_rtc *r = dev_get_drvdata(dev); + struct rohm_regmap_dev *bd70528 = r->mfd; + + ret = bd70528_disable_rtc_based_timers(r, &old_states); + if (ret) + return ret; + + tmpret = regmap_bulk_read(bd70528->regmap, + BD70528_REG_RTC_START, &rtc_data, + sizeof(rtc_data)); + if (tmpret) { + dev_err(dev, "Failed to read RTC time registers\n"); + goto renable_out; + } + tm2rtc(t, &rtc_data); + + tmpret = regmap_bulk_write(bd70528->regmap, + BD70528_REG_RTC_START, &rtc_data, + sizeof(rtc_data)); + if (tmpret) { + dev_err(dev, "Failed to set RTC time\n"); + goto renable_out; + } + +renable_out: + ret = bd70528_re_enable_rtc_based_timers(r, old_states); + if (tmpret) + ret = tmpret; + + return ret; +} + +static int bd70528_set_time(struct device *dev, struct rtc_time *t) +{ + int ret; + struct bd70528_rtc *r = dev_get_drvdata(dev); + + bd70528_wdt_lock(r->mfd); + ret = bd70528_set_time_locked(dev, t); + bd70528_wdt_unlock(r->mfd); + return ret; +} + +static int bd70528_get_time(struct device *dev, struct rtc_time *t) +{ + struct bd70528_rtc *r = dev_get_drvdata(dev); + struct rohm_regmap_dev *bd70528 = r->mfd; + struct bd70528_rtc_data rtc_data; + int ret; + + /* read the RTC date and time registers all at once */ + ret = regmap_bulk_read(bd70528->regmap, + BD70528_REG_RTC_START, &rtc_data, + sizeof(rtc_data)); + if (ret) { + dev_err(dev, "Failed to read RTC time (err %d)\n", ret); + return ret; + } + + rtc2tm(&rtc_data, t); + + return 0; +} + +static int bd70528_alm_enable(struct device *dev, unsigned int enabled) +{ + int ret; + unsigned int enableval = BD70528_MASK_ALM_EN; + struct bd70528_rtc *r = dev_get_drvdata(dev); + + if (enabled) + enableval = 0; + + bd70528_wdt_lock(r->mfd); + ret = bd70528_set_wake(r->mfd, enabled, NULL); + if (ret) { + dev_err(dev, "Failed to change wake state\n"); + goto out_unlock; + } + ret = regmap_update_bits(r->mfd->regmap, BD70528_REG_RTC_ALM_MASK, + BD70528_MASK_ALM_EN, enableval); + if (ret) + dev_err(dev, "Failed to change alarm state\n"); + +out_unlock: + bd70528_wdt_unlock(r->mfd); + return ret; +} + +static const struct rtc_class_ops bd70528_rtc_ops = { + .read_time = bd70528_get_time, + .set_time = bd70528_set_time, + .read_alarm = bd70528_read_alarm, + .set_alarm = bd70528_set_alarm, + .alarm_irq_enable = bd70528_alm_enable, +}; + +static irqreturn_t alm_hndlr(int irq, void *data) +{ + struct rtc_device *rtc = data; + + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF | RTC_PF); + return IRQ_HANDLED; +} + +static int bd70528_probe(struct platform_device *pdev) +{ + struct bd70528_rtc *bd_rtc; + struct rohm_regmap_dev *mfd; + int ret; + struct rtc_device *rtc; + int irq; + unsigned int hr; + + mfd = dev_get_drvdata(pdev->dev.parent); + if (!mfd) { + dev_err(&pdev->dev, "No MFD driver data\n"); + return -EINVAL; + } + bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL); + if (!bd_rtc) + return -ENOMEM; + + bd_rtc->mfd = mfd; + bd_rtc->dev = &pdev->dev; + + irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm"); + if (irq < 0) + return irq; + + platform_set_drvdata(pdev, bd_rtc); + + ret = regmap_read(mfd->regmap, BD70528_REG_RTC_HOUR, &hr); + + if (ret) { + dev_err(&pdev->dev, "Failed to reag RTC clock\n"); + return ret; + } + + if (!(hr & BD70528_MASK_RTC_HOUR_24H)) { + struct rtc_time t; + + ret = bd70528_get_time(&pdev->dev, &t); + + if (!ret) + ret = bd70528_set_time(&pdev->dev, &t); + + if (ret) { + dev_err(&pdev->dev, + "Setting 24H clock for RTC failed\n"); + return ret; + } + } + + device_set_wakeup_capable(&pdev->dev, true); + device_wakeup_enable(&pdev->dev); + + rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc)) { + dev_err(&pdev->dev, "RTC device creation failed\n"); + return PTR_ERR(rtc); + } + + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2099; + rtc->ops = &bd70528_rtc_ops; + + /* Request alarm IRQ prior to registerig the RTC */ + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, &alm_hndlr, + IRQF_ONESHOT, "bd70528-rtc", rtc); + if (ret) + return ret; + + /* + * BD70528 irq controller is not touching the main mask register. + * So enable the RTC block interrupts at main level. We can just + * leave them enabled as irq-controller should disable irqs + * from sub-registers when IRQ is disabled or freed. + */ + ret = regmap_update_bits(mfd->regmap, + BD70528_REG_INT_MAIN_MASK, + BD70528_INT_RTC_MASK, 0); + if (ret) { + dev_err(&pdev->dev, "Failed to enable RTC interrupts\n"); + return ret; + } + + return rtc_register_device(rtc); +} + +static struct platform_driver bd70528_rtc = { + .driver = { + .name = "bd70528-rtc" + }, + .probe = bd70528_probe, +}; + +module_platform_driver(bd70528_rtc); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("BD70528 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index ef52741000a8..4a63f0cd2321 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for TI BQ32000 RTC. * * Copyright (C) 2009 Semihalf. * Copyright (C) 2014 Pavel Machek <pavel@denx.de> * - * 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. - * * You can get hardware description at * http://www.ti.com/lit/ds/symlink/bq32000.pdf */ diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index 113493b52149..472e75668917 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* rtc-bq4802.c: TI BQ4802 RTC driver. * * Copyright (C) 2008 David S. Miller <davem@davemloft.net> diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index f4010a75f2be..3e9800f9878a 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2014-2017 Broadcom - * - * 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. - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -132,7 +124,7 @@ static int brcmstb_waketmr_gettime(struct device *dev, wktmr_read(timer, &now); - rtc_time_to_tm(now.sec, tm); + rtc_time64_to_tm(now.sec, tm); return 0; } @@ -263,10 +255,8 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) timer->rtc->range_max = U32_MAX; ret = rtc_register_device(timer->rtc); - if (ret) { - dev_err(dev, "unable to register device\n"); + if (ret) goto err_notifier; - } dev_info(dev, "registered, with irq %d\n", timer->irq); diff --git a/drivers/rtc/rtc-cadence.c b/drivers/rtc/rtc-cadence.c index 3b7d643c8a63..592aae23cbaf 100644 --- a/drivers/rtc/rtc-cadence.c +++ b/drivers/rtc/rtc-cadence.c @@ -289,12 +289,8 @@ static int cdns_rtc_probe(struct platform_device *pdev) } crtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); - if (IS_ERR(crtc->rtc_dev)) { - ret = PTR_ERR(crtc->rtc_dev); - dev_err(&pdev->dev, - "Failed to allocate the RTC device, %d\n", ret); - return ret; - } + if (IS_ERR(crtc->rtc_dev)) + return PTR_ERR(crtc->rtc_dev); platform_set_drvdata(pdev, crtc); @@ -343,11 +339,8 @@ static int cdns_rtc_probe(struct platform_device *pdev) writel(CDNS_RTC_KRTCR_KRTC, crtc->regs + CDNS_RTC_KRTCR); ret = rtc_register_device(crtc->rtc_dev); - if (ret) { - dev_err(&pdev->dev, - "Failed to register the RTC device, %d\n", ret); + if (ret) goto err_disable_wakeup; - } return 0; diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index a5a19ff10535..033303708c8b 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * RTC class driver for "CMOS RTC": PCs, ACPI, etc * * Copyright (C) 1996 Paul Gortmaker (drivers/char/rtc.c) * Copyright (C) 2006 David Brownell (convert to new framework) - * - * 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. */ /* diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 0b232c84f674..4ac850837153 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2007-2009 ST-Ericsson AB - * License terms: GNU General Public License (GPL) version 2 * Real Time Clock interface for ST-Ericsson AB COH 901 331 RTC. * Author: Linus Walleij <linus.walleij@stericsson.com> * Based on rtc-pl031.c by Deepak Saxena <dsaxena@plexity.net> @@ -80,21 +80,22 @@ static int coh901331_read_time(struct device *dev, struct rtc_time *tm) clk_enable(rtap->clk); /* Check if the time is valid */ - if (readl(rtap->virtbase + COH901331_VALID)) { - rtc_time_to_tm(readl(rtap->virtbase + COH901331_CUR_TIME), tm); + if (!readl(rtap->virtbase + COH901331_VALID)) { clk_disable(rtap->clk); - return 0; + return -EINVAL; } + + rtc_time64_to_tm(readl(rtap->virtbase + COH901331_CUR_TIME), tm); clk_disable(rtap->clk); - return -EINVAL; + return 0; } -static int coh901331_set_mmss(struct device *dev, unsigned long secs) +static int coh901331_set_time(struct device *dev, struct rtc_time *tm) { struct coh901331_port *rtap = dev_get_drvdata(dev); clk_enable(rtap->clk); - writel(secs, rtap->virtbase + COH901331_SET_TIME); + writel(rtc_tm_to_time64(tm), rtap->virtbase + COH901331_SET_TIME); clk_disable(rtap->clk); return 0; @@ -105,7 +106,7 @@ static int coh901331_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) struct coh901331_port *rtap = dev_get_drvdata(dev); clk_enable(rtap->clk); - rtc_time_to_tm(readl(rtap->virtbase + COH901331_ALARM), &alarm->time); + rtc_time64_to_tm(readl(rtap->virtbase + COH901331_ALARM), &alarm->time); alarm->pending = readl(rtap->virtbase + COH901331_IRQ_EVENT) & 1U; alarm->enabled = readl(rtap->virtbase + COH901331_IRQ_MASK) & 1U; clk_disable(rtap->clk); @@ -116,9 +117,8 @@ static int coh901331_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int coh901331_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct coh901331_port *rtap = dev_get_drvdata(dev); - unsigned long time; + unsigned long time = rtc_tm_to_time64(&alarm->time); - rtc_tm_to_time(&alarm->time, &time); clk_enable(rtap->clk); writel(time, rtap->virtbase + COH901331_ALARM); writel(alarm->enabled, rtap->virtbase + COH901331_IRQ_MASK); @@ -143,7 +143,7 @@ static int coh901331_alarm_irq_enable(struct device *dev, unsigned int enabled) static const struct rtc_class_ops coh901331_ops = { .read_time = coh901331_read_time, - .set_mmss = coh901331_set_mmss, + .set_time = coh901331_set_time, .read_alarm = coh901331_read_alarm, .set_alarm = coh901331_set_alarm, .alarm_irq_enable = coh901331_alarm_irq_enable, @@ -188,6 +188,13 @@ static int __init coh901331_probe(struct platform_device *pdev) return ret; } + rtap->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtap->rtc)) + return PTR_ERR(rtap->rtc); + + rtap->rtc->ops = &coh901331_ops; + rtap->rtc->range_max = U32_MAX; + /* We enable/disable the clock only to assure it works */ ret = clk_prepare_enable(rtap->clk); if (ret) { @@ -197,12 +204,10 @@ static int __init coh901331_probe(struct platform_device *pdev) clk_disable(rtap->clk); platform_set_drvdata(pdev, rtap); - rtap->rtc = devm_rtc_device_register(&pdev->dev, "coh901331", - &coh901331_ops, THIS_MODULE); - if (IS_ERR(rtap->rtc)) { - ret = PTR_ERR(rtap->rtc); + + ret = rtc_register_device(rtap->rtc); + if (ret) goto out_no_rtc; - } return 0; diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c index 6b477174a82f..6a3b70fd7e1f 100644 --- a/drivers/rtc/rtc-cpcap.c +++ b/drivers/rtc/rtc-cpcap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Motorola CPCAP PMIC RTC driver * @@ -12,15 +13,6 @@ * - remove custom "secure clock daemon" helpers * * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org> - * - * 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. - * - * 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/kernel.h> #include <linux/module.h> diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c index 4d6bf9304ceb..6909e01936d9 100644 --- a/drivers/rtc/rtc-cros-ec.c +++ b/drivers/rtc/rtc-cros-ec.c @@ -6,8 +6,9 @@ #include <linux/kernel.h> #include <linux/mfd/cros_ec.h> -#include <linux/mfd/cros_ec_commands.h> #include <linux/module.h> +#include <linux/platform_data/cros_ec_commands.h> +#include <linux/platform_data/cros_ec_proto.h> #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/slab.h> diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 03044e1bc497..204eb7cf1aa4 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Real time clock driver for DA9052 * * Copyright(c) 2012 Dialog Semiconductor Ltd. * * Author: Dajun Dajun Chen <dajun.chen@diasemi.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c index e08cd8130c23..844168fcae1e 100644 --- a/drivers/rtc/rtc-da9055.c +++ b/drivers/rtc/rtc-da9055.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Real time clock driver for DA9055 * * Copyright(c) 2012 Dialog Semiconductor Ltd. * * Author: Dajun Dajun Chen <dajun.chen@diasemi.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 69b54e5556c0..15908d51b1cb 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -1,15 +1,7 @@ -/* rtc-da9063.c - Real time clock device driver for DA9063 +// SPDX-License-Identifier: GPL-2.0+ +/* + * Real time clock device driver for DA9063 * Copyright (C) 2013-2015 Dialog Semiconductor Ltd. - * - * 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/delay.h> @@ -247,8 +239,8 @@ static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) da9063_data_to_tm(data, tm, rtc); - rtc_tm_to_time(tm, &tm_secs); - rtc_tm_to_time(&rtc->alarm_time, &al_secs); + tm_secs = rtc_tm_to_time64(tm); + al_secs = rtc_tm_to_time64(&rtc->alarm_time); /* handle the rtc synchronisation delay */ if (rtc->rtc_sync == true && al_secs - tm_secs == 1) @@ -472,11 +464,14 @@ static int da9063_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); - rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, - &da9063_rtc_ops, THIS_MODULE); + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); + rtc->rtc_dev->ops = &da9063_rtc_ops; + rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->rtc_dev->range_max = RTC_TIMESTAMP_END_2063; + da9063_data_to_tm(data, &rtc->alarm_time, rtc); rtc->rtc_sync = false; @@ -496,7 +491,7 @@ static int da9063_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", irq_alarm, ret); - return ret; + return rtc_register_device(rtc->rtc_dev); } static struct platform_driver da9063_rtc_driver = { diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index caf35567e14c..d8e0db2e7fc6 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * DaVinci Power Management and Real Time Clock Driver for TI platforms * * Copyright (C) 2009 Texas Instruments, Inc * * Author: Miguel Aguilar <miguel.aguilar@ridgerun.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/kernel.h> #include <linux/init.h> @@ -490,10 +477,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) return -ENOMEM; davinci_rtc->irq = platform_get_irq(pdev, 0); - if (davinci_rtc->irq < 0) { - dev_err(dev, "no RTC irq\n"); + if (davinci_rtc->irq < 0) return davinci_rtc->irq; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); davinci_rtc->base = devm_ioremap_resource(dev, res); diff --git a/drivers/rtc/rtc-digicolor.c b/drivers/rtc/rtc-digicolor.c index b253bf1b3531..0aecc3f8e721 100644 --- a/drivers/rtc/rtc-digicolor.c +++ b/drivers/rtc/rtc-digicolor.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Real Time Clock driver for Conexant Digicolor * * Copyright (C) 2015 Paradox Innovation Ltd. * * Author: Baruch Siach <baruch@tkos.co.il> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/io.h> @@ -106,11 +102,11 @@ static int dc_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } -static int dc_rtc_set_mmss(struct device *dev, unsigned long secs) +static int dc_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct dc_rtc *rtc = dev_get_drvdata(dev); - return dc_rtc_write(rtc, secs); + return dc_rtc_write(rtc, rtc_tm_to_time64(tm)); } static int dc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) @@ -161,7 +157,7 @@ static int dc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) static const struct rtc_class_ops dc_rtc_ops = { .read_time = dc_rtc_read_time, - .set_mmss = dc_rtc_set_mmss, + .set_time = dc_rtc_set_time, .read_alarm = dc_rtc_read_alarm, .set_alarm = dc_rtc_set_alarm, .alarm_irq_enable = dc_rtc_alarm_irq_enable, @@ -192,6 +188,10 @@ static int __init dc_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc->regs)) return PTR_ERR(rtc->regs); + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -200,12 +200,11 @@ static int __init dc_rtc_probe(struct platform_device *pdev) return ret; platform_set_drvdata(pdev, rtc); - rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, - &dc_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc_dev)) - return PTR_ERR(rtc->rtc_dev); - return 0; + rtc->rtc_dev->ops = &dc_rtc_ops; + rtc->rtc_dev->range_max = U32_MAX; + + return rtc_register_device(rtc->rtc_dev); } static const struct of_device_id dc_dt_ids[] = { diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c index 97d8259b9494..cd947a20843b 100644 --- a/drivers/rtc/rtc-dm355evm.c +++ b/drivers/rtc/rtc-dm355evm.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * rtc-dm355evm.c - access battery-backed counter in MSP430 firmware * * Copyright (c) 2008 by David Brownell - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/kernel.h> #include <linux/init.h> @@ -78,7 +74,7 @@ static int dm355evm_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_dbg(dev, "read timestamp %08x\n", time.value); - rtc_time_to_tm(le32_to_cpu(time.value), tm); + rtc_time64_to_tm(le32_to_cpu(time.value), tm); return 0; } @@ -88,7 +84,7 @@ static int dm355evm_rtc_set_time(struct device *dev, struct rtc_time *tm) unsigned long value; int status; - rtc_tm_to_time(tm, &value); + value = rtc_tm_to_time64(tm); time.value = cpu_to_le32(value); dev_dbg(dev, "write timestamp %08x\n", time.value); @@ -127,16 +123,16 @@ static int dm355evm_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &dm355evm_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - dev_err(&pdev->dev, "can't register RTC device, err %ld\n", - PTR_ERR(rtc)); + rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc)) return PTR_ERR(rtc); - } + platform_set_drvdata(pdev, rtc); - return 0; + rtc->ops = &dm355evm_rtc_ops; + rtc->range_max = U32_MAX; + + return rtc_register_device(rtc); } /* diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c index 50fabe1cd286..b225bcfef50b 100644 --- a/drivers/rtc/rtc-ds1216.c +++ b/drivers/rtc/rtc-ds1216.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Dallas DS1216 RTC driver * diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 0744916b79c5..a06508b6c404 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * DS1286 Real Time Clock interface for Linux * @@ -5,11 +6,6 @@ * Copyright (C) 2008 Thomas Bogendoerfer * * Based on code written by Paul Gortmaker. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 2a881150d51c..4faa24c88af5 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Dallas DS1302 RTC Support * * Copyright (C) 2002 David McCullough * Copyright (C) 2003 - 2007 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License version 2. See the file "COPYING" in the main directory of - * this archive for more details. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 2d502fc85698..4420fbf2f8fe 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1305.c -- driver for DS1305 and DS1306 SPI RTC chips * * Copyright (C) 2008 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> #include <linux/init.h> @@ -694,19 +690,16 @@ static int ds1305_probe(struct spi_device *spi) /* register RTC ... from here on, ds1305->ctrl needs locking */ ds1305->rtc = devm_rtc_allocate_device(&spi->dev); - if (IS_ERR(ds1305->rtc)) { + if (IS_ERR(ds1305->rtc)) return PTR_ERR(ds1305->rtc); - } ds1305->rtc->ops = &ds1305_ops; ds1305_nvmem_cfg.priv = ds1305; ds1305->rtc->nvram_old_abi = true; status = rtc_register_device(ds1305->rtc); - if (status) { - dev_dbg(&spi->dev, "register rtc --> %d\n", status); + if (status) return status; - } rtc_nvmem_register(ds1305->rtc, &ds1305_nvmem_cfg); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 07530fe1da2a..1f7e8aefc1eb 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips. * @@ -5,10 +6,6 @@ * Copyright (C) 2006 David Brownell * Copyright (C) 2009 Matthias Fuchs (rx8025 support) * Copyright (C) 2012 Bertrand Achard (nvram access fixes) - * - * 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/acpi.h> @@ -225,6 +222,45 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) return -EINVAL; } + tmp = regs[DS1307_REG_SECS]; + switch (ds1307->type) { + case ds_1307: + case m41t0: + case m41t00: + case m41t11: + if (tmp & DS1307_BIT_CH) + return -EINVAL; + break; + case ds_1308: + case ds_1338: + if (tmp & DS1307_BIT_CH) + return -EINVAL; + + ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &tmp); + if (ret) + return ret; + if (tmp & DS1338_BIT_OSF) + return -EINVAL; + break; + case ds_1340: + if (tmp & DS1340_BIT_nEOSC) + return -EINVAL; + + ret = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp); + if (ret) + return ret; + if (tmp & DS1340_BIT_OSF) + return -EINVAL; + break; + case mcp794xx: + if (!(tmp & MCP794XX_BIT_ST)) + return -EINVAL; + + break; + default: + break; + } + t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f); t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f); tmp = regs[DS1307_REG_HOUR] & 0x3f; @@ -289,7 +325,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) if (t->tm_year > 199 && chip->century_bit) regs[chip->century_reg] |= chip->century_bit; - if (ds1307->type == mcp794xx) { + switch (ds1307->type) { + case ds_1308: + case ds_1338: + regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL, + DS1338_BIT_OSF, 0); + break; + case ds_1340: + regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG, + DS1340_BIT_OSF, 0); + break; + case mcp794xx: /* * these bits were cleared when preparing the date/time * values and need to be set again before writing the @@ -297,6 +343,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) */ regs[DS1307_REG_SECS] |= MCP794XX_BIT_ST; regs[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN; + break; + default: + break; } dev_dbg(dev, "%s: %7ph\n", "write", regs); @@ -1705,7 +1754,6 @@ static int ds1307_probe(struct i2c_client *client, break; } -read_rtc: /* read RTC registers */ err = regmap_bulk_read(ds1307->regmap, chip->offset, regs, sizeof(regs)); @@ -1714,75 +1762,11 @@ read_rtc: goto exit; } - /* - * minimal sanity checking; some chips (like DS1340) don't - * specify the extra bits as must-be-zero, but there are - * still a few values that are clearly out-of-range. - */ - tmp = regs[DS1307_REG_SECS]; - switch (ds1307->type) { - case ds_1307: - case m41t0: - case m41t00: - case m41t11: - /* clock halted? turn it on, so clock can tick. */ - if (tmp & DS1307_BIT_CH) { - regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); - dev_warn(ds1307->dev, "SET TIME!\n"); - goto read_rtc; - } - break; - case ds_1308: - case ds_1338: - /* clock halted? turn it on, so clock can tick. */ - if (tmp & DS1307_BIT_CH) - regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); - - /* oscillator fault? clear flag, and warn */ - if (regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) { - regmap_write(ds1307->regmap, DS1307_REG_CONTROL, - regs[DS1307_REG_CONTROL] & - ~DS1338_BIT_OSF); - dev_warn(ds1307->dev, "SET TIME!\n"); - goto read_rtc; - } - break; - case ds_1340: - /* clock halted? turn it on, so clock can tick. */ - if (tmp & DS1340_BIT_nEOSC) - regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); - - err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp); - if (err) { - dev_dbg(ds1307->dev, "read error %d\n", err); - goto exit; - } - - /* oscillator fault? clear flag, and warn */ - if (tmp & DS1340_BIT_OSF) { - regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0); - dev_warn(ds1307->dev, "SET TIME!\n"); - } - break; - case mcp794xx: - /* make sure that the backup battery is enabled */ - if (!(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) { - regmap_write(ds1307->regmap, DS1307_REG_WDAY, - regs[DS1307_REG_WDAY] | - MCP794XX_BIT_VBATEN); - } - - /* clock halted? turn it on, so clock can tick. */ - if (!(tmp & MCP794XX_BIT_ST)) { - regmap_write(ds1307->regmap, DS1307_REG_SECS, - MCP794XX_BIT_ST); - dev_warn(ds1307->dev, "SET TIME!\n"); - goto read_rtc; - } - - break; - default: - break; + if (ds1307->type == mcp794xx && + !(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) { + regmap_write(ds1307->regmap, DS1307_REG_WDAY, + regs[DS1307_REG_WDAY] | + MCP794XX_BIT_VBATEN); } tmp = regs[DS1307_REG_HOUR]; diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c index 5208da4cf94a..fa6de31d5793 100644 --- a/drivers/rtc/rtc-ds1343.c +++ b/drivers/rtc/rtc-ds1343.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* rtc-ds1343.c * * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible @@ -5,11 +6,6 @@ * * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> * Ankur Srivastava <sankurece@gmail.com> : DS1343 Nvram Support - * - * 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> diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c index 938512c676ee..d392a7bfdd1c 100644 --- a/drivers/rtc/rtc-ds1347.c +++ b/drivers/rtc/rtc-ds1347.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* 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> diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 38a2e9e684df..6e96916c41ff 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -14,7 +14,7 @@ */ /* * It would be more efficient to use i2c msgs/i2c_transfer directly but, as - * recommened in .../Documentation/i2c/writing-clients section + * recommended in .../Documentation/i2c/writing-clients.rst section * "Sending and receiving", using SMBus level communication is preferred. */ @@ -467,7 +467,7 @@ static int ds1374_wdt_open(struct inode *inode, struct file *file) */ wdt_is_open = 1; mutex_unlock(&ds1374->mutex); - return nonseekable_open(inode, file); + return stream_open(inode, file); } return -ENODEV; } @@ -586,6 +586,7 @@ static const struct file_operations ds1374_wdt_fops = { .owner = THIS_MODULE, .read = ds1374_wdt_read, .unlocked_ioctl = ds1374_wdt_unlocked_ioctl, + .compat_ioctl = compat_ptr_ioctl, .write = ds1374_wdt_write, .open = ds1374_wdt_open, .release = ds1374_wdt_release, diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 3b095401f848..66fc8617d07e 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1390.c -- driver for the Dallas/Maxim DS1390/93/94 SPI RTC * * Copyright (C) 2008 Mercury IMC Ltd * Written by Mark Jackson <mpfj@mimc.co.uk> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * NOTE: Currently this driver only supports the bare minimum for read * and write the RTC. The extra features provided by the chip family * (alarms, trickle charger, different control registers) are unavailable. diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index b8b6e51c0461..b6a477519280 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas DS1511 * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> * Copyright (C) 2007 Andrew Sharp <andy.sharp@lsi.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. - * * Real time clock driver for the Dallas 1511 chip, which also * contains a watchdog timer. There is a tiny amount of code that * platform code could use to mess with the watchdog device a little diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 34af7a802f43..219d6b520a69 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas DS1553 * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index b1ebca099b0d..9da84df9f152 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * An rtc/i2c driver for the Dallas DS1672 * Copyright 2005-06 Tower Technologies * * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> @@ -21,17 +18,16 @@ #define DS1672_REG_CONTROL_EOSC 0x80 -static struct i2c_driver ds1672_driver; - /* * In the routines that deal directly with the ds1672 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch - * Epoch is initialized as 2000. Time is set to UTC. + * Time is set to UTC. */ -static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) +static int ds1672_read_time(struct device *dev, struct rtc_time *tm) { + struct i2c_client *client = to_i2c_client(dev); unsigned long time; - unsigned char addr = DS1672_REG_CNT_BASE; + unsigned char addr = DS1672_REG_CONTROL; unsigned char buf[4]; struct i2c_msg msgs[] = { @@ -43,11 +39,25 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) {/* read date */ .addr = client->addr, .flags = I2C_M_RD, - .len = 4, + .len = 1, .buf = buf }, }; + /* read control register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_warn(&client->dev, "Unable to read the control register\n"); + return -EIO; + } + + if (buf[0] & DS1672_REG_CONTROL_EOSC) { + dev_warn(&client->dev, "Oscillator not enabled. Set time to enable.\n"); + return -EINVAL; + } + + addr = DS1672_REG_CNT_BASE; + msgs[1].len = 4; + /* read date registers */ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { dev_err(&client->dev, "%s: read error\n", __func__); @@ -61,20 +71,19 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) time = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; - rtc_time_to_tm(time, tm); + rtc_time64_to_tm(time, tm); - 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); + dev_dbg(&client->dev, "%s: tm is %ptR\n", __func__, tm); return 0; } -static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) +static int ds1672_set_time(struct device *dev, struct rtc_time *tm) { + struct i2c_client *client = to_i2c_client(dev); int xfer; unsigned char buf[6]; + unsigned long secs = rtc_tm_to_time64(tm); buf[0] = DS1672_REG_CNT_BASE; buf[1] = secs & 0x000000FF; @@ -92,71 +101,15 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) return 0; } -static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - return ds1672_get_datetime(to_i2c_client(dev), tm); -} - -static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs) -{ - return ds1672_set_mmss(to_i2c_client(dev), secs); -} - -static int ds1672_get_control(struct i2c_client *client, u8 *status) -{ - unsigned char addr = DS1672_REG_CONTROL; - - struct i2c_msg msgs[] = { - {/* setup read ptr */ - .addr = client->addr, - .len = 1, - .buf = &addr - }, - {/* read control */ - .addr = client->addr, - .flags = I2C_M_RD, - .len = 1, - .buf = status - }, - }; - - /* read control register */ - if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __func__); - return -EIO; - } - - return 0; -} - -/* following are the sysfs callback functions */ -static ssize_t show_control(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - u8 control; - int err; - - err = ds1672_get_control(client, &control); - if (err) - return err; - - return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC) - ? "disabled" : "enabled"); -} - -static DEVICE_ATTR(control, S_IRUGO, show_control, NULL); - static const struct rtc_class_ops ds1672_rtc_ops = { - .read_time = ds1672_rtc_read_time, - .set_mmss = ds1672_rtc_set_mmss, + .read_time = ds1672_read_time, + .set_time = ds1672_set_time, }; static int ds1672_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err = 0; - u8 control; struct rtc_device *rtc; dev_dbg(&client->dev, "%s\n", __func__); @@ -164,29 +117,18 @@ static int ds1672_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - rtc = devm_rtc_device_register(&client->dev, ds1672_driver.driver.name, - &ds1672_rtc_ops, THIS_MODULE); - + rtc = devm_rtc_allocate_device(&client->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); - i2c_set_clientdata(client, rtc); - - /* read control register */ - err = ds1672_get_control(client, &control); - 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. " - "Set time to enable.\n"); + rtc->ops = &ds1672_rtc_ops; + rtc->range_max = U32_MAX; - /* Register sysfs hooks */ - err = device_create_file(&client->dev, &dev_attr_control); + err = rtc_register_device(rtc); if (err) - dev_err(&client->dev, "Unable to create sysfs entry: %s\n", - dev_attr_control.attr.name); + return err; + + i2c_set_clientdata(client, rtc); return 0; } diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 2710f2594c42..184e4a3e2bef 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time * chips. @@ -10,10 +11,6 @@ * DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10. * DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105. * Application Note 90, Using the Multiplex Bus RTC Extended Features. - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -192,42 +189,6 @@ ds1685_rtc_end_data_access(struct ds1685_priv *rtc) } /** - * ds1685_rtc_begin_ctrl_access - prepare the rtc for ctrl access. - * @rtc: pointer to the ds1685 rtc structure. - * @flags: irq flags variable for spin_lock_irqsave. - * - * This takes several steps to prepare the rtc for access to read just the - * control registers: - * - Sets a spinlock on the rtc IRQ. - * - Switches the rtc to bank 1. This allows access to the two extended - * control registers. - * - * Only use this where you are certain another lock will not be held. - */ -static inline void -ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long *flags) -{ - spin_lock_irqsave(&rtc->lock, *flags); - ds1685_rtc_switch_to_bank1(rtc); -} - -/** - * ds1685_rtc_end_ctrl_access - end ctrl access on the rtc. - * @rtc: pointer to the ds1685 rtc structure. - * @flags: irq flags variable for spin_unlock_irqrestore. - * - * This ends what was started by ds1685_rtc_begin_ctrl_access: - * - Switches the rtc back to bank 0. - * - Unsets the spinlock on the rtc IRQ. - */ -static inline void -ds1685_rtc_end_ctrl_access(struct ds1685_priv *rtc, unsigned long flags) -{ - ds1685_rtc_switch_to_bank0(rtc); - spin_unlock_irqrestore(&rtc->lock, flags); -} - -/** * ds1685_rtc_get_ssn - retrieve the silicon serial number. * @rtc: pointer to the ds1685 rtc structure. * @ssn: u8 array to hold the bits of the silicon serial number. @@ -546,10 +507,6 @@ static int ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct ds1685_priv *rtc = dev_get_drvdata(dev); - unsigned long flags = 0; - - /* Enable/disable the Alarm IRQ-Enable flag. */ - spin_lock_irqsave(&rtc->lock, flags); /* Flip the requisite interrupt-enable bit. */ if (enabled) @@ -561,7 +518,6 @@ ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) /* Read Control C to clear all the flag bits. */ rtc->read(rtc, RTC_CTRL_C); - spin_unlock_irqrestore(&rtc->lock, flags); return 0; } @@ -569,98 +525,18 @@ ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) /* ----------------------------------------------------------------------- */ -/* IRQ handler & workqueue. */ - -/** - * ds1685_rtc_irq_handler - IRQ handler. - * @irq: IRQ number. - * @dev_id: platform device pointer. - */ -static irqreturn_t -ds1685_rtc_irq_handler(int irq, void *dev_id) -{ - struct platform_device *pdev = dev_id; - struct ds1685_priv *rtc = platform_get_drvdata(pdev); - u8 ctrlb, ctrlc; - unsigned long events = 0; - u8 num_irqs = 0; - - /* Abort early if the device isn't ready yet (i.e., DEBUG_SHIRQ). */ - if (unlikely(!rtc)) - return IRQ_HANDLED; - - /* Ctrlb holds the interrupt-enable bits and ctrlc the flag bits. */ - spin_lock(&rtc->lock); - ctrlb = rtc->read(rtc, RTC_CTRL_B); - ctrlc = rtc->read(rtc, RTC_CTRL_C); - - /* Is the IRQF bit set? */ - if (likely(ctrlc & RTC_CTRL_C_IRQF)) { - /* - * We need to determine if it was one of the standard - * events: PF, AF, or UF. If so, we handle them and - * update the RTC core. - */ - if (likely(ctrlc & RTC_CTRL_B_PAU_MASK)) { - events = RTC_IRQF; - - /* Check for a periodic interrupt. */ - if ((ctrlb & RTC_CTRL_B_PIE) && - (ctrlc & RTC_CTRL_C_PF)) { - events |= RTC_PF; - num_irqs++; - } - - /* Check for an alarm interrupt. */ - if ((ctrlb & RTC_CTRL_B_AIE) && - (ctrlc & RTC_CTRL_C_AF)) { - events |= RTC_AF; - num_irqs++; - } - - /* Check for an update interrupt. */ - if ((ctrlb & RTC_CTRL_B_UIE) && - (ctrlc & RTC_CTRL_C_UF)) { - events |= RTC_UF; - num_irqs++; - } - - rtc_update_irq(rtc->dev, num_irqs, events); - } else { - /* - * One of the "extended" interrupts was received that - * is not recognized by the RTC core. These need to - * be handled in task context as they can call other - * functions and the time spent in irq context needs - * to be minimized. Schedule them into a workqueue - * and inform the RTC core that the IRQs were handled. - */ - spin_unlock(&rtc->lock); - schedule_work(&rtc->work); - rtc_update_irq(rtc->dev, 0, 0); - return IRQ_HANDLED; - } - } - spin_unlock(&rtc->lock); - - return events ? IRQ_HANDLED : IRQ_NONE; -} +/* IRQ handler */ /** - * ds1685_rtc_work_queue - work queue handler. - * @work: work_struct containing data to work on in task context. + * ds1685_rtc_extended_irq - take care of extended interrupts + * @rtc: pointer to the ds1685 rtc structure. + * @pdev: platform device pointer. */ static void -ds1685_rtc_work_queue(struct work_struct *work) +ds1685_rtc_extended_irq(struct ds1685_priv *rtc, struct platform_device *pdev) { - struct ds1685_priv *rtc = container_of(work, - struct ds1685_priv, work); - struct platform_device *pdev = to_platform_device(&rtc->dev->dev); - struct mutex *rtc_mutex = &rtc->dev->ops_lock; u8 ctrl4a, ctrl4b; - mutex_lock(rtc_mutex); - ds1685_rtc_switch_to_bank1(rtc); ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A); ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B); @@ -739,8 +615,76 @@ ds1685_rtc_work_queue(struct work_struct *work) "RAM-Clear IRQ just occurred!\n"); } ds1685_rtc_switch_to_bank0(rtc); +} + +/** + * ds1685_rtc_irq_handler - IRQ handler. + * @irq: IRQ number. + * @dev_id: platform device pointer. + */ +static irqreturn_t +ds1685_rtc_irq_handler(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct ds1685_priv *rtc = platform_get_drvdata(pdev); + struct mutex *rtc_mutex; + u8 ctrlb, ctrlc; + unsigned long events = 0; + u8 num_irqs = 0; + + /* Abort early if the device isn't ready yet (i.e., DEBUG_SHIRQ). */ + if (unlikely(!rtc)) + return IRQ_HANDLED; + + rtc_mutex = &rtc->dev->ops_lock; + mutex_lock(rtc_mutex); + + /* Ctrlb holds the interrupt-enable bits and ctrlc the flag bits. */ + ctrlb = rtc->read(rtc, RTC_CTRL_B); + ctrlc = rtc->read(rtc, RTC_CTRL_C); + + /* Is the IRQF bit set? */ + if (likely(ctrlc & RTC_CTRL_C_IRQF)) { + /* + * We need to determine if it was one of the standard + * events: PF, AF, or UF. If so, we handle them and + * update the RTC core. + */ + if (likely(ctrlc & RTC_CTRL_B_PAU_MASK)) { + events = RTC_IRQF; + + /* Check for a periodic interrupt. */ + if ((ctrlb & RTC_CTRL_B_PIE) && + (ctrlc & RTC_CTRL_C_PF)) { + events |= RTC_PF; + num_irqs++; + } + /* Check for an alarm interrupt. */ + if ((ctrlb & RTC_CTRL_B_AIE) && + (ctrlc & RTC_CTRL_C_AF)) { + events |= RTC_AF; + num_irqs++; + } + + /* Check for an update interrupt. */ + if ((ctrlb & RTC_CTRL_B_UIE) && + (ctrlc & RTC_CTRL_C_UF)) { + events |= RTC_UF; + num_irqs++; + } + } else { + /* + * One of the "extended" interrupts was received that + * is not recognized by the RTC core. + */ + ds1685_rtc_extended_irq(rtc, pdev); + } + } + rtc_update_irq(rtc->dev, num_irqs, events); mutex_unlock(rtc_mutex); + + return events ? IRQ_HANDLED : IRQ_NONE; } /* ----------------------------------------------------------------------- */ @@ -869,11 +813,15 @@ static int ds1685_nvram_read(void *priv, unsigned int pos, void *val, size_t size) { struct ds1685_priv *rtc = priv; + struct mutex *rtc_mutex = &rtc->dev->ops_lock; ssize_t count; - unsigned long flags = 0; u8 *buf = val; + int err; + + err = mutex_lock_interruptible(rtc_mutex); + if (err) + return err; - spin_lock_irqsave(&rtc->lock, flags); ds1685_rtc_switch_to_bank0(rtc); /* Read NVRAM in time and bank0 registers. */ @@ -923,7 +871,7 @@ static int ds1685_nvram_read(void *priv, unsigned int pos, void *val, ds1685_rtc_switch_to_bank0(rtc); } #endif /* !CONFIG_RTC_DRV_DS1689 */ - spin_unlock_irqrestore(&rtc->lock, flags); + mutex_unlock(rtc_mutex); return 0; } @@ -932,11 +880,15 @@ static int ds1685_nvram_write(void *priv, unsigned int pos, void *val, size_t size) { struct ds1685_priv *rtc = priv; + struct mutex *rtc_mutex = &rtc->dev->ops_lock; ssize_t count; - unsigned long flags = 0; u8 *buf = val; + int err; + + err = mutex_lock_interruptible(rtc_mutex); + if (err) + return err; - spin_lock_irqsave(&rtc->lock, flags); ds1685_rtc_switch_to_bank0(rtc); /* Write NVRAM in time and bank0 registers. */ @@ -986,7 +938,7 @@ static int ds1685_nvram_write(void *priv, unsigned int pos, void *val, ds1685_rtc_switch_to_bank0(rtc); } #endif /* !CONFIG_RTC_DRV_DS1689 */ - spin_unlock_irqrestore(&rtc->lock, flags); + mutex_unlock(rtc_mutex); return 0; } @@ -1004,7 +956,7 @@ static ssize_t ds1685_rtc_sysfs_battery_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct ds1685_priv *rtc = dev_get_drvdata(dev); + struct ds1685_priv *rtc = dev_get_drvdata(dev->parent); u8 ctrld; ctrld = rtc->read(rtc, RTC_CTRL_D); @@ -1024,7 +976,7 @@ static ssize_t ds1685_rtc_sysfs_auxbatt_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct ds1685_priv *rtc = dev_get_drvdata(dev); + struct ds1685_priv *rtc = dev_get_drvdata(dev->parent); u8 ctrl4a; ds1685_rtc_switch_to_bank1(rtc); @@ -1046,7 +998,7 @@ static ssize_t ds1685_rtc_sysfs_serial_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct ds1685_priv *rtc = dev_get_drvdata(dev); + struct ds1685_priv *rtc = dev_get_drvdata(dev->parent); u8 ssn[8]; ds1685_rtc_switch_to_bank1(rtc); @@ -1177,9 +1129,7 @@ ds1685_rtc_probe(struct platform_device *pdev) if (pdata->plat_post_ram_clear) rtc->post_ram_clear = pdata->plat_post_ram_clear; - /* Init the spinlock, workqueue, & set the driver data. */ - spin_lock_init(&rtc->lock); - INIT_WORK(&rtc->work, ds1685_rtc_work_queue); + /* set the driver data. */ platform_set_drvdata(pdev, rtc); /* Turn the oscillator on if is not already on (DV1 = 1). */ @@ -1335,22 +1285,23 @@ ds1685_rtc_probe(struct platform_device *pdev) */ if (!pdata->no_irq) { ret = platform_get_irq(pdev, 0); - if (ret > 0) { - rtc->irq_num = ret; - - /* Request an IRQ. */ - ret = devm_request_irq(&pdev->dev, rtc->irq_num, - ds1685_rtc_irq_handler, - IRQF_SHARED, pdev->name, pdev); - - /* Check to see if something came back. */ - if (unlikely(ret)) { - dev_warn(&pdev->dev, - "RTC interrupt not available\n"); - rtc->irq_num = 0; - } - } else + if (ret <= 0) return ret; + + rtc->irq_num = ret; + + /* Request an IRQ. */ + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_num, + NULL, ds1685_rtc_irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + pdev->name, pdev); + + /* Check to see if something came back. */ + if (unlikely(ret)) { + dev_warn(&pdev->dev, + "RTC interrupt not available\n"); + rtc->irq_num = 0; + } } rtc->no_irq = pdata->no_irq; @@ -1397,8 +1348,6 @@ ds1685_rtc_remove(struct platform_device *pdev) (rtc->read(rtc, RTC_EXT_CTRL_4A) & ~(RTC_CTRL_4A_RWK_MASK))); - cancel_work_sync(&rtc->work); - return 0; } diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 5a4c2c5e86fe..2b949f0dbaa9 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas DS1742 * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> * - * 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. - * * Copyright (C) 2006 Torsten Ertbjerg Rasmussen <tr@newtec.dk> * - nvram size determined from resource * - this ds1742 driver now supports ds1743. diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index b886b6a5c178..9df0c44512b8 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -1,11 +1,5 @@ -/* - * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org> - * - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2012 Sven Schnelle <svens@stackframe.org> #include <linux/platform_device.h> #include <linux/module.h> @@ -29,14 +23,6 @@ #define DS2404_COPY_SCRATCHPAD_CMD 0x55 #define DS2404_READ_MEMORY_CMD 0xf0 -struct ds2404; - -struct ds2404_chip_ops { - int (*map_io)(struct ds2404 *chip, struct platform_device *pdev, - struct ds2404_platform_data *pdata); - void (*unmap_io)(struct ds2404 *chip); -}; - #define DS2404_RST 0 #define DS2404_CLK 1 #define DS2404_DQ 2 @@ -48,7 +34,6 @@ struct ds2404_gpio { struct ds2404 { struct ds2404_gpio *gpio; - const struct ds2404_chip_ops *ops; struct rtc_device *rtc; }; @@ -87,7 +72,7 @@ err_request: return err; } -static void ds2404_gpio_unmap(struct ds2404 *chip) +static void ds2404_gpio_unmap(void *data) { int i; @@ -95,11 +80,6 @@ static void ds2404_gpio_unmap(struct ds2404 *chip) gpio_free(ds2404_gpio[i].gpio); } -static const struct ds2404_chip_ops ds2404_gpio_ops = { - .map_io = ds2404_gpio_map, - .unmap_io = ds2404_gpio_unmap, -}; - static void ds2404_reset(struct device *dev) { gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0); @@ -202,24 +182,25 @@ static void ds2404_enable_osc(struct device *dev) static int ds2404_read_time(struct device *dev, struct rtc_time *dt) { unsigned long time = 0; + __le32 hw_time = 0; - ds2404_read_memory(dev, 0x203, 4, (u8 *)&time); - time = le32_to_cpu(time); + ds2404_read_memory(dev, 0x203, 4, (u8 *)&hw_time); + time = le32_to_cpu(hw_time); - rtc_time_to_tm(time, dt); + rtc_time64_to_tm(time, dt); return 0; } -static int ds2404_set_mmss(struct device *dev, unsigned long secs) +static int ds2404_set_time(struct device *dev, struct rtc_time *dt) { - u32 time = cpu_to_le32(secs); + u32 time = cpu_to_le32(rtc_tm_to_time64(dt)); ds2404_write_memory(dev, 0x203, 4, (u8 *)&time); return 0; } static const struct rtc_class_ops ds2404_rtc_ops = { .read_time = ds2404_read_time, - .set_mmss = ds2404_set_mmss, + .set_time = ds2404_set_time, }; static int rtc_probe(struct platform_device *pdev) @@ -232,11 +213,17 @@ static int rtc_probe(struct platform_device *pdev) if (!chip) return -ENOMEM; - chip->ops = &ds2404_gpio_ops; + chip->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(chip->rtc)) + return PTR_ERR(chip->rtc); - retval = chip->ops->map_io(chip, pdev, pdata); + retval = ds2404_gpio_map(chip, pdev, pdata); if (retval) - goto err_chip; + return retval; + + retval = devm_add_action_or_reset(&pdev->dev, ds2404_gpio_unmap, chip); + if (retval) + return retval; dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n", chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio, @@ -244,34 +231,19 @@ static int rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, chip); - chip->rtc = devm_rtc_device_register(&pdev->dev, "ds2404", - &ds2404_rtc_ops, THIS_MODULE); - if (IS_ERR(chip->rtc)) { - retval = PTR_ERR(chip->rtc); - goto err_io; - } + chip->rtc->ops = &ds2404_rtc_ops; + chip->rtc->range_max = U32_MAX; - ds2404_enable_osc(&pdev->dev); - return 0; - -err_io: - chip->ops->unmap_io(chip); -err_chip: - return retval; -} - -static int rtc_remove(struct platform_device *dev) -{ - struct ds2404 *chip = platform_get_drvdata(dev); - - chip->ops->unmap_io(chip); + retval = rtc_register_device(chip->rtc); + if (retval) + return retval; + ds2404_enable_osc(&pdev->dev); return 0; } static struct platform_driver rtc_device_driver = { .probe = rtc_probe, - .remove = rtc_remove, .driver = { .name = "ds2404", }, diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 7184e5145f12..69c37ab64352 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * RTC client/driver for the Maxim/Dallas DS3232/DS3234 Real-Time Clock * * Copyright (C) 2009-2011 Freescale Semiconductor. * Author: Jack Lan <jack.lan@freescale.com> * Copyright (C) 2008 MIMOMax Wireless Ltd. - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -48,6 +44,10 @@ # define DS3232_REG_SR_A1F 0x01 #define DS3232_REG_TEMPERATURE 0x11 +#define DS3232_REG_SRAM_START 0x14 +#define DS3232_REG_SRAM_END 0xFF + +#define DS3232_REG_SRAM_SIZE 236 struct ds3232 { struct device *dev; @@ -461,11 +461,39 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .alarm_irq_enable = ds3232_alarm_irq_enable, }; +static int ds3232_nvmem_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct regmap *ds3232_regmap = (struct regmap *)priv; + + return regmap_bulk_read(ds3232_regmap, DS3232_REG_SRAM_START + offset, + val, bytes); +} + +static int ds3232_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct regmap *ds3232_regmap = (struct regmap *)priv; + + return regmap_bulk_write(ds3232_regmap, DS3232_REG_SRAM_START + offset, + val, bytes); +} + static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { struct ds3232 *ds3232; int ret; + struct nvmem_config nvmem_cfg = { + .name = "ds3232_sram", + .stride = 1, + .size = DS3232_REG_SRAM_SIZE, + .word_size = 1, + .reg_read = ds3232_nvmem_read, + .reg_write = ds3232_nvmem_write, + .priv = regmap, + .type = NVMEM_TYPE_BATTERY_BACKED + }; ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL); if (!ds3232) @@ -490,6 +518,10 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, if (IS_ERR(ds3232->rtc)) return PTR_ERR(ds3232->rtc); + ret = rtc_nvmem_register(ds3232->rtc, &nvmem_cfg); + if(ret) + return ret; + if (ds3232->irq > 0) { ret = devm_request_threaded_irq(dev, ds3232->irq, NULL, ds3232_irq, @@ -542,7 +574,7 @@ static int ds3232_i2c_probe(struct i2c_client *client, static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, }; regmap = devm_regmap_init_i2c(client, &config); @@ -609,7 +641,7 @@ static int ds3234_probe(struct spi_device *spi) static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, .write_flag_mask = 0x80, }; struct regmap *regmap; diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 3454e7814524..edb64debd173 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * rtc-efi: RTC Class Driver for EFI-based systems * @@ -5,12 +6,6 @@ * * Author: dann frazier <dannf@dannf.org> * Based on efirtc.c by Stephane Eranian - * - * 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. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c index b0ef8cfe742d..77cca1392253 100644 --- a/drivers/rtc/rtc-em3027.c +++ b/drivers/rtc/rtc-em3027.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An rtc/i2c driver for the EM Microelectronic EM3027 * Copyright 2011 CompuLab, Ltd. @@ -5,10 +6,6 @@ * Author: Mike Rapoport <mike@compulab.co.il> * * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 1932a4f861d1..1766496385fe 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * A driver for the RTC embedded in the Cirrus Logic EP93XX processors * Copyright (c) 2006 Tower Technologies * * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -18,27 +15,23 @@ #define EP93XX_RTC_DATA 0x000 #define EP93XX_RTC_MATCH 0x004 #define EP93XX_RTC_STATUS 0x008 -#define EP93XX_RTC_STATUS_INTR (1<<0) +#define EP93XX_RTC_STATUS_INTR BIT(0) #define EP93XX_RTC_LOAD 0x00C #define EP93XX_RTC_CONTROL 0x010 -#define EP93XX_RTC_CONTROL_MIE (1<<0) +#define EP93XX_RTC_CONTROL_MIE BIT(0) #define EP93XX_RTC_SWCOMP 0x108 #define EP93XX_RTC_SWCOMP_DEL_MASK 0x001f0000 #define EP93XX_RTC_SWCOMP_DEL_SHIFT 16 #define EP93XX_RTC_SWCOMP_INT_MASK 0x0000ffff #define EP93XX_RTC_SWCOMP_INT_SHIFT 0 -/* - * struct device dev.platform_data is used to store our private data - * because struct rtc_device does not have a variable to hold it. - */ struct ep93xx_rtc { void __iomem *mmio_base; struct rtc_device *rtc; }; static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload, - unsigned short *delete) + unsigned short *delete) { struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); unsigned long comp; @@ -63,13 +56,14 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); - rtc_time_to_tm(time, tm); + rtc_time64_to_tm(time, tm); return 0; } -static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) +static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); + unsigned long secs = rtc_tm_to_time64(tm); writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD); return 0; @@ -89,31 +83,31 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) static const struct rtc_class_ops ep93xx_rtc_ops = { .read_time = ep93xx_rtc_read_time, - .set_mmss = ep93xx_rtc_set_mmss, + .set_time = ep93xx_rtc_set_time, .proc = ep93xx_rtc_proc, }; -static ssize_t ep93xx_rtc_show_comp_preload(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t comp_preload_show(struct device *dev, + struct device_attribute *attr, char *buf) { unsigned short preload; - ep93xx_rtc_get_swcomp(dev, &preload, NULL); + ep93xx_rtc_get_swcomp(dev->parent, &preload, NULL); return sprintf(buf, "%d\n", preload); } -static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_rtc_show_comp_preload, NULL); +static DEVICE_ATTR_RO(comp_preload); -static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t comp_delete_show(struct device *dev, + struct device_attribute *attr, char *buf) { unsigned short delete; - ep93xx_rtc_get_swcomp(dev, NULL, &delete); + ep93xx_rtc_get_swcomp(dev->parent, NULL, &delete); return sprintf(buf, "%d\n", delete); } -static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL); +static DEVICE_ATTR_RO(comp_delete); static struct attribute *ep93xx_rtc_attrs[] = { &dev_attr_comp_preload.attr, @@ -140,33 +134,20 @@ static int ep93xx_rtc_probe(struct platform_device *pdev) 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); - ep93xx_rtc->rtc = devm_rtc_device_register(&pdev->dev, - pdev->name, &ep93xx_rtc_ops, THIS_MODULE); - if (IS_ERR(ep93xx_rtc->rtc)) { - err = PTR_ERR(ep93xx_rtc->rtc); - goto exit; - } + ep93xx_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(ep93xx_rtc->rtc)) + return PTR_ERR(ep93xx_rtc->rtc); - err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); - if (err) - goto exit; - - return 0; + ep93xx_rtc->rtc->ops = &ep93xx_rtc_ops; + ep93xx_rtc->rtc->range_max = U32_MAX; -exit: - pdev->dev.platform_data = NULL; - return err; -} - -static int ep93xx_rtc_remove(struct platform_device *pdev) -{ - sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); - pdev->dev.platform_data = NULL; + err = rtc_add_group(ep93xx_rtc->rtc, &ep93xx_rtc_sysfs_files); + if (err) + return err; - return 0; + return rtc_register_device(ep93xx_rtc->rtc); } static struct platform_driver ep93xx_rtc_driver = { @@ -174,7 +155,6 @@ static struct platform_driver ep93xx_rtc_driver = { .name = "ep93xx-rtc", }, .probe = ep93xx_rtc_probe, - .remove = ep93xx_rtc_remove, }; module_platform_driver(ep93xx_rtc_driver); diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index e1137670d4d2..677ec2da13d8 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip. * * Copyright (C) 2008 Sergey Lapin * Based on ds1307 driver by James Chapman and David Brownell - * - * 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> @@ -107,8 +104,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t) fm3130_rtc_mode(dev, FM3130_MODE_READ); /* read the RTC date and time registers all at once */ - tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), - fm3130->msg, 2); + tmp = i2c_transfer(fm3130->client->adapter, fm3130->msg, 2); if (tmp != 2) { dev_err(dev, "%s error %d\n", "read", tmp); return -EIO; @@ -200,8 +196,7 @@ static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) } /* read the RTC alarm registers all at once */ - tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), - &fm3130->msg[2], 2); + tmp = i2c_transfer(fm3130->client->adapter, &fm3130->msg[2], 2); if (tmp != 2) { dev_err(dev, "%s error %d\n", "read", tmp); return -EIO; @@ -351,7 +346,7 @@ static int fm3130_probe(struct i2c_client *client, struct fm3130 *fm3130; int err = -ENODEV; int tmp; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c new file mode 100644 index 000000000000..8df2075af9a2 --- /dev/null +++ b/drivers/rtc/rtc-fsl-ftm-alarm.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Freescale FlexTimer Module (FTM) alarm device driver. + * + * Copyright 2014 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + * + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/module.h> +#include <linux/fsl/ftm.h> +#include <linux/rtc.h> +#include <linux/time.h> + +#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT) + +/* + * Select Fixed frequency clock (32KHz) as clock source + * of FlexTimer Module + */ +#define FTM_SC_CLKS_FIXED_FREQ 0x02 +#define FIXED_FREQ_CLK 32000 + +/* Select 128 (2^7) as divider factor */ +#define MAX_FREQ_DIV (1 << FTM_SC_PS_MASK) + +/* Maximum counter value in FlexTimer's CNT registers */ +#define MAX_COUNT_VAL 0xffff + +struct ftm_rtc { + struct rtc_device *rtc_dev; + void __iomem *base; + bool big_endian; + u32 alarm_freq; +}; + +static inline u32 rtc_readl(struct ftm_rtc *dev, u32 reg) +{ + if (dev->big_endian) + return ioread32be(dev->base + reg); + else + return ioread32(dev->base + reg); +} + +static inline void rtc_writel(struct ftm_rtc *dev, u32 reg, u32 val) +{ + if (dev->big_endian) + iowrite32be(val, dev->base + reg); + else + iowrite32(val, dev->base + reg); +} + +static inline void ftm_counter_enable(struct ftm_rtc *rtc) +{ + u32 val; + + /* select and enable counter clock source */ + val = rtc_readl(rtc, FTM_SC); + val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK); + val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ)); + rtc_writel(rtc, FTM_SC, val); +} + +static inline void ftm_counter_disable(struct ftm_rtc *rtc) +{ + u32 val; + + /* disable counter clock source */ + val = rtc_readl(rtc, FTM_SC); + val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK); + rtc_writel(rtc, FTM_SC, val); +} + +static inline void ftm_irq_acknowledge(struct ftm_rtc *rtc) +{ + unsigned int timeout = 100; + + /* + *Fix errata A-007728 for flextimer + * If the FTM counter reaches the FTM_MOD value between + * the reading of the TOF bit and the writing of 0 to + * the TOF bit, the process of clearing the TOF bit + * does not work as expected when FTMx_CONF[NUMTOF] != 0 + * and the current TOF count is less than FTMx_CONF[NUMTOF]. + * If the above condition is met, the TOF bit remains set. + * If the TOF interrupt is enabled (FTMx_SC[TOIE] = 1),the + * TOF interrupt also remains asserted. + * + * Above is the errata discription + * + * In one word: software clearing TOF bit not works when + * FTMx_CONF[NUMTOF] was seted as nonzero and FTM counter + * reaches the FTM_MOD value. + * + * The workaround is clearing TOF bit until it works + * (FTM counter doesn't always reache the FTM_MOD anyway), + * which may cost some cycles. + */ + while ((FTM_SC_TOF & rtc_readl(rtc, FTM_SC)) && timeout--) + rtc_writel(rtc, FTM_SC, rtc_readl(rtc, FTM_SC) & (~FTM_SC_TOF)); +} + +static inline void ftm_irq_enable(struct ftm_rtc *rtc) +{ + u32 val; + + val = rtc_readl(rtc, FTM_SC); + val |= FTM_SC_TOIE; + rtc_writel(rtc, FTM_SC, val); +} + +static inline void ftm_irq_disable(struct ftm_rtc *rtc) +{ + u32 val; + + val = rtc_readl(rtc, FTM_SC); + val &= ~FTM_SC_TOIE; + rtc_writel(rtc, FTM_SC, val); +} + +static inline void ftm_reset_counter(struct ftm_rtc *rtc) +{ + /* + * The CNT register contains the FTM counter value. + * Reset clears the CNT register. Writing any value to COUNT + * updates the counter with its initial value, CNTIN. + */ + rtc_writel(rtc, FTM_CNT, 0x00); +} + +static void ftm_clean_alarm(struct ftm_rtc *rtc) +{ + ftm_counter_disable(rtc); + + rtc_writel(rtc, FTM_CNTIN, 0x00); + rtc_writel(rtc, FTM_MOD, ~0U); + + ftm_reset_counter(rtc); +} + +static irqreturn_t ftm_rtc_alarm_interrupt(int irq, void *dev) +{ + struct ftm_rtc *rtc = dev; + + ftm_irq_acknowledge(rtc); + ftm_irq_disable(rtc); + ftm_clean_alarm(rtc); + + return IRQ_HANDLED; +} + +static int ftm_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct ftm_rtc *rtc = dev_get_drvdata(dev); + + if (enabled) + ftm_irq_enable(rtc); + else + ftm_irq_disable(rtc); + + return 0; +} + +/* + * Note: + * The function is not really getting time from the RTC + * since FlexTimer is not a RTC device, but we need to + * get time to setup alarm, so we are using system time + * for now. + */ +static int ftm_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct timespec64 ts64; + + ktime_get_real_ts64(&ts64); + rtc_time_to_tm(ts64.tv_sec, tm); + + return 0; +} + +static int ftm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + return 0; +} + +/* + * 1. Select fixed frequency clock (32KHz) as clock source; + * 2. Select 128 (2^7) as divider factor; + * So clock is 250 Hz (32KHz/128). + * + * 3. FlexTimer's CNT register is a 32bit register, + * but the register's 16 bit as counter value,it's other 16 bit + * is reserved.So minimum counter value is 0x0,maximum counter + * value is 0xffff. + * So max alarm value is 262 (65536 / 250) seconds + */ +static int ftm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct rtc_time tm; + unsigned long now, alm_time, cycle; + struct ftm_rtc *rtc = dev_get_drvdata(dev); + + ftm_rtc_read_time(dev, &tm); + rtc_tm_to_time(&tm, &now); + rtc_tm_to_time(&alm->time, &alm_time); + + ftm_clean_alarm(rtc); + cycle = (alm_time - now) * rtc->alarm_freq; + if (cycle > MAX_COUNT_VAL) { + pr_err("Out of alarm range {0~262} seconds.\n"); + return -ERANGE; + } + + ftm_irq_disable(rtc); + + /* + * The counter increments until the value of MOD is reached, + * at which point the counter is reloaded with the value of CNTIN. + * The TOF (the overflow flag) bit is set when the FTM counter + * changes from MOD to CNTIN. So we should using the cycle - 1. + */ + rtc_writel(rtc, FTM_MOD, cycle - 1); + + ftm_counter_enable(rtc); + ftm_irq_enable(rtc); + + return 0; + +} + +static const struct rtc_class_ops ftm_rtc_ops = { + .read_time = ftm_rtc_read_time, + .read_alarm = ftm_rtc_read_alarm, + .set_alarm = ftm_rtc_set_alarm, + .alarm_irq_enable = ftm_rtc_alarm_irq_enable, +}; + +static int ftm_rtc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *r; + int irq; + int ret; + struct ftm_rtc *rtc; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (unlikely(!rtc)) { + dev_err(&pdev->dev, "cannot alloc memory for rtc\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, rtc); + + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "cannot get resource for rtc\n"); + return -ENODEV; + } + + rtc->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(rtc->base)) { + dev_err(&pdev->dev, "cannot ioremap resource for rtc\n"); + return PTR_ERR(rtc->base); + } + + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "unable to get IRQ from DT, %d\n", irq); + return -EINVAL; + } + + ret = devm_request_irq(&pdev->dev, irq, ftm_rtc_alarm_interrupt, + IRQF_NO_SUSPEND, dev_name(&pdev->dev), rtc); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request irq\n"); + return ret; + } + + rtc->big_endian = of_property_read_bool(np, "big-endian"); + rtc->alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV; + rtc->rtc_dev->ops = &ftm_rtc_ops; + + device_init_wakeup(&pdev->dev, true); + + ret = rtc_register_device(rtc->rtc_dev); + if (ret) { + dev_err(&pdev->dev, "can't register rtc device\n"); + return ret; + } + + return 0; +} + +static const struct of_device_id ftm_rtc_match[] = { + { .compatible = "fsl,ls1012a-ftm-alarm", }, + { .compatible = "fsl,ls1021a-ftm-alarm", }, + { .compatible = "fsl,ls1028a-ftm-alarm", }, + { .compatible = "fsl,ls1043a-ftm-alarm", }, + { .compatible = "fsl,ls1046a-ftm-alarm", }, + { .compatible = "fsl,ls1088a-ftm-alarm", }, + { .compatible = "fsl,ls208xa-ftm-alarm", }, + { .compatible = "fsl,lx2160a-ftm-alarm", }, + { }, +}; + +static struct platform_driver ftm_rtc_driver = { + .probe = ftm_rtc_probe, + .driver = { + .name = "ftm-alarm", + .of_match_table = ftm_rtc_match, + }, +}; + +static int __init ftm_alarm_init(void) +{ + return platform_driver_register(&ftm_rtc_driver); +} + +device_initcall(ftm_alarm_init); + +MODULE_DESCRIPTION("NXP/Freescale FlexTimer alarm driver"); +MODULE_AUTHOR("Biwen Li <biwen.li@nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c index 8f1dd88fa827..0919f7dc94a3 100644 --- a/drivers/rtc/rtc-ftrtc010.c +++ b/drivers/rtc/rtc-ftrtc010.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Faraday Technology FTRTC010 driver * * Copyright (C) 2009 Janos Laube <janos.dev@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. - * * Original code for older kernel 2.6.15 are from Stormlinksemi * first update from Janos Laube for > 2.6.29 kernels * diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c index 1bf5d2347928..89ae78e93b83 100644 --- a/drivers/rtc/rtc-generic.c +++ b/drivers/rtc/rtc-generic.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* rtc-generic: RTC driver using the generic RTC abstraction * * Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca> diff --git a/drivers/rtc/rtc-goldfish.c b/drivers/rtc/rtc-goldfish.c index a1c44d0c8557..1a3420ee6a4d 100644 --- a/drivers/rtc/rtc-goldfish.c +++ b/drivers/rtc/rtc-goldfish.c @@ -1,23 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 /* drivers/rtc/rtc-goldfish.c * * Copyright (C) 2007 Google, Inc. * Copyright (C) 2017 Imagination Technologies Ltd. - * - * 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/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/rtc.h> -#include <linux/io.h> #define TIMER_TIME_LOW 0x00 /* get low bits of current time */ /* and update TIMER_TIME_HIGH */ @@ -56,7 +48,7 @@ static int goldfish_rtc_read_alarm(struct device *dev, do_div(rtc_alarm, NSEC_PER_SEC); memset(alrm, 0, sizeof(struct rtc_wkalrm)); - rtc_time_to_tm(rtc_alarm, &alrm->time); + rtc_time64_to_tm(rtc_alarm, &alrm->time); if (readl(base + TIMER_ALARM_STATUS)) alrm->enabled = 1; @@ -70,21 +62,15 @@ static int goldfish_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct goldfish_rtc *rtcdrv; - unsigned long rtc_alarm; u64 rtc_alarm64; u64 rtc_status_reg; void __iomem *base; - int ret = 0; rtcdrv = dev_get_drvdata(dev); base = rtcdrv->base; if (alrm->enabled) { - ret = rtc_tm_to_time(&alrm->time, &rtc_alarm); - if (ret != 0) - return ret; - - rtc_alarm64 = rtc_alarm * NSEC_PER_SEC; + rtc_alarm64 = rtc_tm_to_time64(&alrm->time) * NSEC_PER_SEC; writel((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH); writel(rtc_alarm64, base + TIMER_ALARM_LOW); } else { @@ -98,7 +84,7 @@ static int goldfish_rtc_set_alarm(struct device *dev, writel(1, base + TIMER_CLEAR_ALARM); } - return ret; + return 0; } static int goldfish_rtc_alarm_irq_enable(struct device *dev, @@ -147,7 +133,7 @@ static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm) do_div(time, NSEC_PER_SEC); - rtc_time_to_tm(time, tm); + rtc_time64_to_tm(time, tm); return 0; } @@ -156,21 +142,16 @@ static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct goldfish_rtc *rtcdrv; void __iomem *base; - unsigned long now; u64 now64; - int ret; rtcdrv = dev_get_drvdata(dev); base = rtcdrv->base; - ret = rtc_tm_to_time(tm, &now); - if (ret == 0) { - now64 = now * NSEC_PER_SEC; - writel((now64 >> 32), base + TIMER_TIME_HIGH); - writel(now64, base + TIMER_TIME_LOW); - } + now64 = rtc_tm_to_time64(tm) * NSEC_PER_SEC; + writel((now64 >> 32), base + TIMER_TIME_HIGH); + writel(now64, base + TIMER_TIME_LOW); - return ret; + return 0; } static const struct rtc_class_ops goldfish_rtc_ops = { @@ -205,19 +186,20 @@ static int goldfish_rtc_probe(struct platform_device *pdev) if (rtcdrv->irq < 0) return -ENODEV; - rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &goldfish_rtc_ops, - THIS_MODULE); + rtcdrv->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtcdrv->rtc)) return PTR_ERR(rtcdrv->rtc); + rtcdrv->rtc->ops = &goldfish_rtc_ops; + rtcdrv->rtc->range_max = U64_MAX / NSEC_PER_SEC; + err = devm_request_irq(&pdev->dev, rtcdrv->irq, goldfish_rtc_interrupt, 0, pdev->name, rtcdrv); if (err) return err; - return 0; + return rtc_register_device(rtcdrv->rtc); } static const struct of_device_id goldfish_rtc_of_match[] = { diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 3e1abb455472..1b42ee0758d2 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HID Sensor Time Driver * Copyright (c) 2012, Alexander Holler. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <linux/device.h> #include <linux/platform_device.h> @@ -205,8 +192,7 @@ static int hid_time_parse_report(struct platform_device *pdev, static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) { unsigned long flags; - struct hid_time_state *time_state = - platform_get_drvdata(to_platform_device(dev)); + struct hid_time_state *time_state = dev_get_drvdata(dev); int ret; reinit_completion(&time_state->comp_last_time); diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index d03f5d212eea..443f6d05ce29 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Haoyu HYM8563 RTC driver * @@ -6,15 +7,6 @@ * * 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> diff --git a/drivers/rtc/rtc-imx-sc.c b/drivers/rtc/rtc-imx-sc.c index 19642bfd913a..cf2c12107f2b 100644 --- a/drivers/rtc/rtc-imx-sc.c +++ b/drivers/rtc/rtc-imx-sc.c @@ -3,6 +3,7 @@ * Copyright 2018 NXP. */ +#include <dt-bindings/firmware/imx/rsrc.h> #include <linux/arm-smccc.h> #include <linux/firmware/imx/sci.h> #include <linux/module.h> @@ -11,11 +12,15 @@ #include <linux/rtc.h> #define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9 +#define IMX_SC_TIMER_FUNC_SET_RTC_ALARM 8 #define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6 #define IMX_SIP_SRTC 0xC2000002 #define IMX_SIP_SRTC_SET_TIME 0x0 +#define SC_IRQ_GROUP_RTC 2 +#define SC_IRQ_RTC 1 + static struct imx_sc_ipc *rtc_ipc_handle; static struct rtc_device *imx_sc_rtc; @@ -24,6 +29,16 @@ struct imx_sc_msg_timer_get_rtc_time { u32 time; } __packed; +struct imx_sc_msg_timer_rtc_set_alarm { + struct imx_sc_rpc_msg hdr; + u16 year; + u8 mon; + u8 day; + u8 hour; + u8 min; + u8 sec; +} __packed; + static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct imx_sc_msg_timer_get_rtc_time msg; @@ -60,9 +75,77 @@ static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm) return res.a0; } +static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + return imx_scu_irq_group_enable(SC_IRQ_GROUP_RTC, SC_IRQ_RTC, enable); +} + +static int imx_sc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + /* + * SCU firmware does NOT provide read alarm API, but .read_alarm + * callback is required by RTC framework to support alarm function, + * so just return here. + */ + return 0; +} + +static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct imx_sc_msg_timer_rtc_set_alarm msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + struct rtc_time *alrm_tm = &alrm->time; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_TIMER; + hdr->func = IMX_SC_TIMER_FUNC_SET_RTC_ALARM; + hdr->size = 3; + + msg.year = alrm_tm->tm_year + 1900; + msg.mon = alrm_tm->tm_mon + 1; + msg.day = alrm_tm->tm_mday; + msg.hour = alrm_tm->tm_hour; + msg.min = alrm_tm->tm_min; + msg.sec = alrm_tm->tm_sec; + + ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true); + if (ret) { + dev_err(dev, "set rtc alarm failed, ret %d\n", ret); + return ret; + } + + ret = imx_sc_rtc_alarm_irq_enable(dev, alrm->enabled); + if (ret) { + dev_err(dev, "enable rtc alarm failed, ret %d\n", ret); + return ret; + } + + return 0; +} + static const struct rtc_class_ops imx_sc_rtc_ops = { .read_time = imx_sc_rtc_read_time, .set_time = imx_sc_rtc_set_time, + .read_alarm = imx_sc_rtc_read_alarm, + .set_alarm = imx_sc_rtc_set_alarm, + .alarm_irq_enable = imx_sc_rtc_alarm_irq_enable, +}; + +static int imx_sc_rtc_alarm_notify(struct notifier_block *nb, + unsigned long event, void *group) +{ + /* ignore non-rtc irq */ + if (!((event & SC_IRQ_RTC) && (*(u8 *)group == SC_IRQ_GROUP_RTC))) + return 0; + + rtc_update_irq(imx_sc_rtc, 1, RTC_IRQF | RTC_AF); + + return 0; +} + +static struct notifier_block imx_sc_rtc_alarm_sc_notifier = { + .notifier_call = imx_sc_rtc_alarm_notify, }; static int imx_sc_rtc_probe(struct platform_device *pdev) @@ -73,6 +156,8 @@ static int imx_sc_rtc_probe(struct platform_device *pdev) if (ret) return ret; + device_init_wakeup(&pdev->dev, true); + imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(imx_sc_rtc)) return PTR_ERR(imx_sc_rtc); @@ -82,10 +167,10 @@ static int imx_sc_rtc_probe(struct platform_device *pdev) imx_sc_rtc->range_max = U32_MAX; ret = rtc_register_device(imx_sc_rtc); - if (ret) { - dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); + if (ret) return ret; - } + + imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier); return 0; } diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 80931114c899..f21dc6b16d88 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2010 Orex Computed Radiography */ /* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -/* based on rtc-mc13892.c */ - -/* * This driver uses the 47-bit 32 kHz counter in the Freescale DryIce block * to implement a Linux RTC. Times and alarms are truncated to seconds. * Since the RTC framework performs API locking via rtc->ops_lock the @@ -552,7 +542,7 @@ static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm) unsigned long now; now = readl(imxdi->ioaddr + DTCMR); - rtc_time_to_tm(now, tm); + rtc_time64_to_tm(now, tm); return 0; } @@ -561,7 +551,7 @@ static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm) * set the seconds portion of dryice time counter and clear the * fractional part. */ -static int dryice_rtc_set_mmss(struct device *dev, unsigned long secs) +static int dryice_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct imxdi_dev *imxdi = dev_get_drvdata(dev); u32 dcr, dsr; @@ -588,7 +578,7 @@ static int dryice_rtc_set_mmss(struct device *dev, unsigned long secs) if (rc != 0) return rc; - rc = di_write_wait(imxdi, secs, DTCMR); + rc = di_write_wait(imxdi, rtc_tm_to_time64(tm), DTCMR); if (rc != 0) return rc; @@ -618,7 +608,7 @@ static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) u32 dcamr; dcamr = readl(imxdi->ioaddr + DCAMR); - rtc_time_to_tm(dcamr, &alarm->time); + rtc_time64_to_tm(dcamr, &alarm->time); /* alarm is enabled if the interrupt is enabled */ alarm->enabled = (readl(imxdi->ioaddr + DIER) & DIER_CAIE) != 0; @@ -640,21 +630,10 @@ static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct imxdi_dev *imxdi = dev_get_drvdata(dev); - unsigned long now; - unsigned long alarm_time; int rc; - rc = rtc_tm_to_time(&alarm->time, &alarm_time); - if (rc) - return rc; - - /* don't allow setting alarm in the past */ - now = readl(imxdi->ioaddr + DTCMR); - if (alarm_time < now) - return -EINVAL; - /* write the new alarm time */ - rc = di_write_wait(imxdi, (u32)alarm_time, DCAMR); + rc = di_write_wait(imxdi, rtc_tm_to_time64(&alarm->time), DCAMR); if (rc) return rc; @@ -668,7 +647,7 @@ static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) static const struct rtc_class_ops dryice_rtc_ops = { .read_time = dryice_rtc_read_time, - .set_mmss = dryice_rtc_set_mmss, + .set_time = dryice_rtc_set_time, .alarm_irq_enable = dryice_rtc_alarm_irq_enable, .read_alarm = dryice_rtc_read_alarm, .set_alarm = dryice_rtc_set_alarm, @@ -761,7 +740,6 @@ static void dryice_work(struct work_struct *work) */ static int __init dryice_rtc_probe(struct platform_device *pdev) { - struct resource *res; struct imxdi_dev *imxdi; int norm_irq, sec_irq; int rc; @@ -772,8 +750,7 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) imxdi->pdev = pdev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - imxdi->ioaddr = devm_ioremap_resource(&pdev->dev, res); + imxdi->ioaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(imxdi->ioaddr)) return PTR_ERR(imxdi->ioaddr); @@ -796,6 +773,10 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) mutex_init(&imxdi->write_mutex); + imxdi->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(imxdi->rtc)) + return PTR_ERR(imxdi->rtc); + imxdi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(imxdi->clk)) return PTR_ERR(imxdi->clk); @@ -829,12 +810,13 @@ static int __init dryice_rtc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, imxdi); - imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &dryice_rtc_ops, THIS_MODULE); - if (IS_ERR(imxdi->rtc)) { - rc = PTR_ERR(imxdi->rtc); + + imxdi->rtc->ops = &dryice_rtc_ops; + imxdi->rtc->range_max = U32_MAX; + + rc = rtc_register_device(imxdi->rtc); + if (rc) goto err; - } return 0; diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 890ccfc9e5aa..961bd5d1d109 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for the Intersil ISL 12022 * @@ -5,10 +6,6 @@ * * Based on the Philips PCF8563 RTC * by Alessandro Zummo <a.zummo@towertech.it>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. */ #include <linux/i2c.h> diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 97f594f9667c..5b6b17fb6d62 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -454,9 +454,9 @@ static int isl12026_probe_new(struct i2c_client *client) isl12026_force_power_modes(client); - priv->nvm_client = i2c_new_dummy(client->adapter, ISL12026_EEPROM_ADDR); - if (!priv->nvm_client) - return -ENOMEM; + priv->nvm_client = i2c_new_dummy_device(client->adapter, ISL12026_EEPROM_ADDR); + if (IS_ERR(priv->nvm_client)) + return PTR_ERR(priv->nvm_client); priv->rtc = devm_rtc_allocate_device(&client->dev); ret = PTR_ERR_OR_ZERO(priv->rtc); diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 471e395b20db..ebb691fa48a6 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -1,13 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Intersil ISL1208 rtc class driver * * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index d0a891777f44..3089645e0ce8 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> * Copyright (C) 2010, Paul Cercueil <paul@crapouillou.net> * JZ4740 SoC RTC driver - * - * 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. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * */ #include <linux/clk.h> @@ -20,6 +11,7 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/reboot.h> #include <linux/rtc.h> #include <linux/slab.h> @@ -156,6 +148,9 @@ static int jz4740_rtc_read_time(struct device *dev, struct rtc_time *time) uint32_t secs, secs2; int timeout = 5; + if (jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD) != 0x12345678) + return -EINVAL; + /* If the seconds register is read while it is updated, it can contain a * bogus value. This can be avoided by making sure that two consecutive * reads have the same value. @@ -171,16 +166,21 @@ static int jz4740_rtc_read_time(struct device *dev, struct rtc_time *time) if (timeout == 0) return -EIO; - rtc_time_to_tm(secs, time); + rtc_time64_to_tm(secs, time); return 0; } -static int jz4740_rtc_set_mmss(struct device *dev, unsigned long secs) +static int jz4740_rtc_set_time(struct device *dev, struct rtc_time *time) { struct jz4740_rtc *rtc = dev_get_drvdata(dev); + int ret; + + ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, rtc_tm_to_time64(time)); + if (ret) + return ret; - return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, secs); + return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678); } static int jz4740_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -196,18 +196,16 @@ static int jz4740_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = !!(ctrl & JZ_RTC_CTRL_AE); alrm->pending = !!(ctrl & JZ_RTC_CTRL_AF); - rtc_time_to_tm(secs, &alrm->time); + rtc_time64_to_tm(secs, &alrm->time); - return rtc_valid_tm(&alrm->time); + return 0; } static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { int ret; struct jz4740_rtc *rtc = dev_get_drvdata(dev); - unsigned long secs; - - rtc_tm_to_time(&alrm->time, &secs); + uint32_t secs = lower_32_bits(rtc_tm_to_time64(&alrm->time)); ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, secs); if (!ret) @@ -225,7 +223,7 @@ static int jz4740_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) static const struct rtc_class_ops jz4740_rtc_ops = { .read_time = jz4740_rtc_read_time, - .set_mmss = jz4740_rtc_set_mmss, + .set_time = jz4740_rtc_set_time, .read_alarm = jz4740_rtc_read_alarm, .set_alarm = jz4740_rtc_set_alarm, .alarm_irq_enable = jz4740_rtc_alarm_irq_enable, @@ -309,7 +307,6 @@ static int jz4740_rtc_probe(struct platform_device *pdev) { int ret; struct jz4740_rtc *rtc; - uint32_t scratchpad; struct resource *mem; const struct platform_device_id *id = platform_get_device_id(pdev); const struct of_device_id *of_id = of_match_device( @@ -326,10 +323,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev) rtc->type = id->driver_data; rtc->irq = platform_get_irq(pdev, 0); - if (rtc->irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq\n"); + if (rtc->irq < 0) return -ENOENT; - } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); rtc->base = devm_ioremap_resource(&pdev->dev, mem); @@ -348,14 +343,26 @@ static int jz4740_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &jz4740_rtc_ops, THIS_MODULE); + ret = dev_pm_set_wake_irq(&pdev->dev, rtc->irq); + if (ret) { + dev_err(&pdev->dev, "Failed to set wake irq: %d\n", ret); + return ret; + } + + rtc->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc)) { ret = PTR_ERR(rtc->rtc); - dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret); + dev_err(&pdev->dev, "Failed to allocate rtc device: %d\n", ret); return ret; } + rtc->rtc->ops = &jz4740_rtc_ops; + rtc->rtc->range_max = U32_MAX; + + ret = rtc_register_device(rtc->rtc); + if (ret) + return ret; + ret = devm_request_irq(&pdev->dev, rtc->irq, jz4740_rtc_irq, 0, pdev->name, rtc); if (ret) { @@ -363,16 +370,6 @@ static int jz4740_rtc_probe(struct platform_device *pdev) return ret; } - scratchpad = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD); - if (scratchpad != 0x12345678) { - ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678); - ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0); - if (ret) { - dev_err(&pdev->dev, "Could not write to RTC registers\n"); - return ret; - } - } - if (np && of_device_is_system_power_controller(np)) { if (!pm_power_off) { /* Default: 60ms */ @@ -397,35 +394,6 @@ static int jz4740_rtc_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int jz4740_rtc_suspend(struct device *dev) -{ - struct jz4740_rtc *rtc = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(rtc->irq); - return 0; -} - -static int jz4740_rtc_resume(struct device *dev) -{ - struct jz4740_rtc *rtc = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(rtc->irq); - return 0; -} - -static const struct dev_pm_ops jz4740_pm_ops = { - .suspend = jz4740_rtc_suspend, - .resume = jz4740_rtc_resume, -}; -#define JZ4740_RTC_PM_OPS (&jz4740_pm_ops) - -#else -#define JZ4740_RTC_PM_OPS NULL -#endif /* CONFIG_PM */ - static const struct platform_device_id jz4740_rtc_ids[] = { { "jz4740-rtc", ID_JZ4740 }, { "jz4780-rtc", ID_JZ4780 }, @@ -437,7 +405,6 @@ static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, .driver = { .name = "jz4740-rtc", - .pm = JZ4740_RTC_PM_OPS, .of_match_table = of_match_ptr(jz4740_rtc_of_match), }, .id_table = jz4740_rtc_ids, diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c index e20e7bd822e0..c0b8fbce1082 100644 --- a/drivers/rtc/rtc-lp8788.c +++ b/drivers/rtc/rtc-lp8788.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI LP8788 MFD - rtc driver * * Copyright 2012 Texas Instruments * * Author: Milo(Woogyom) Kim <milo.kim@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/err.h> diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c index 14dc7b04fae0..a8bb15606ec8 100644 --- a/drivers/rtc/rtc-lpc24xx.c +++ b/drivers/rtc/rtc-lpc24xx.c @@ -1,14 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * RTC driver for NXP LPC178x/18xx/43xx Real-Time Clock (RTC) * * Copyright (C) 2011 NXP Semiconductors * Copyright (C) 2015 Joachim Eastwood <manabian@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. - * */ #include <linux/clk.h> diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index 910e600275b9..ac393230e592 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2010 NXP Semiconductors - * - * 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. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> @@ -47,8 +39,6 @@ #define LPC32XX_RTC_KEY_ONSW_LOADVAL 0xB5C13F27 -#define RTC_NAME "rtc-lpc32xx" - #define rtc_readl(dev, reg) \ __raw_readl((dev)->rtc_base + (reg)) #define rtc_writel(dev, reg, val) \ @@ -68,14 +58,15 @@ static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time) struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT); - rtc_time_to_tm(elapsed_sec, time); + rtc_time64_to_tm(elapsed_sec, time); return 0; } -static int lpc32xx_rtc_set_mmss(struct device *dev, unsigned long secs) +static int lpc32xx_rtc_set_time(struct device *dev, struct rtc_time *time) { struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); + u32 secs = rtc_tm_to_time64(time); u32 tmp; spin_lock_irq(&rtc->lock); @@ -97,7 +88,7 @@ static int lpc32xx_rtc_read_alarm(struct device *dev, { struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); - rtc_time_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time); + rtc_time64_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time); wkalrm->enabled = rtc->alarm_enabled; wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) & LPC32XX_RTC_INTSTAT_MATCH0); @@ -111,13 +102,8 @@ static int lpc32xx_rtc_set_alarm(struct device *dev, struct lpc32xx_rtc *rtc = dev_get_drvdata(dev); unsigned long alarmsecs; u32 tmp; - int ret; - ret = rtc_tm_to_time(&wkalrm->time, &alarmsecs); - if (ret < 0) { - dev_warn(dev, "Failed to convert time: %d\n", ret); - return ret; - } + alarmsecs = rtc_tm_to_time64(&wkalrm->time); spin_lock_irq(&rtc->lock); @@ -191,7 +177,7 @@ static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev) static const struct rtc_class_ops lpc32xx_rtc_ops = { .read_time = lpc32xx_rtc_read_time, - .set_mmss = lpc32xx_rtc_set_mmss, + .set_time = lpc32xx_rtc_set_time, .read_alarm = lpc32xx_rtc_read_alarm, .set_alarm = lpc32xx_rtc_set_alarm, .alarm_irq_enable = lpc32xx_rtc_alarm_irq_enable, @@ -201,21 +187,13 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev) { struct resource *res; struct lpc32xx_rtc *rtc; - int rtcirq; + int err; u32 tmp; - rtcirq = platform_get_irq(pdev, 0); - if (rtcirq < 0) { - dev_warn(&pdev->dev, "Can't get interrupt resource\n"); - rtcirq = -1; - } - rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (unlikely(!rtc)) return -ENOMEM; - rtc->irq = rtcirq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(rtc->rtc_base)) @@ -256,18 +234,25 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); - rtc->rtc = devm_rtc_device_register(&pdev->dev, RTC_NAME, - &lpc32xx_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc)) { - dev_err(&pdev->dev, "Can't get RTC\n"); + rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc)) return PTR_ERR(rtc->rtc); - } + + rtc->rtc->ops = &lpc32xx_rtc_ops; + rtc->rtc->range_max = U32_MAX; + + err = rtc_register_device(rtc->rtc); + if (err) + return err; /* * IRQ is enabled after device registration in case alarm IRQ * is pending upon suspend exit. */ - if (rtc->irq >= 0) { + rtc->irq = platform_get_irq(pdev, 0); + if (rtc->irq < 0) { + dev_warn(&pdev->dev, "Can't get interrupt resource\n"); + } else { if (devm_request_irq(&pdev->dev, rtc->irq, lpc32xx_rtc_alarm_interrupt, 0, pdev->name, rtc) < 0) { @@ -374,7 +359,7 @@ static struct platform_driver lpc32xx_rtc_driver = { .probe = lpc32xx_rtc_probe, .remove = lpc32xx_rtc_remove, .driver = { - .name = RTC_NAME, + .name = "rtc-lpc32xx", .pm = LPC32XX_RTC_PM_OPS, .of_match_table = of_match_ptr(lpc32xx_rtc_match), }, diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c index f4c248655edd..8bd34056fea0 100644 --- a/drivers/rtc/rtc-ls1x.c +++ b/drivers/rtc/rtc-ls1x.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2011 Zhao Zhang <zhzhl555@gmail.com> * * Derived from driver/rtc/rtc-au1xxx.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index ebf50b1540f2..f9fa4f068de3 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C client/driver for the ST M41T80 family of i2c rtc chips. * @@ -6,11 +7,6 @@ * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com> * * 2006 (c) mycable GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -802,7 +798,7 @@ static int wdt_open(struct inode *inode, struct file *file) */ wdt_is_open = 1; mutex_unlock(&m41t80_rtc_mutex); - return nonseekable_open(inode, file); + return stream_open(inode, file); } return -ENODEV; } @@ -844,6 +840,7 @@ static const struct file_operations wdt_fops = { .owner = THIS_MODULE, .read = wdt_read, .unlocked_ioctl = wdt_unlocked_ioctl, + .compat_ioctl = compat_ptr_ioctl, .write = wdt_write, .open = wdt_open, .release = wdt_release, @@ -876,7 +873,7 @@ static struct notifier_block wdt_notifier = { static int m41t80_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int rc = 0; struct rtc_time tm; struct m41t80_data *m41t80_data = NULL; diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c index 4a08a9dabc82..9444cb5f5190 100644 --- a/drivers/rtc/rtc-m41t93.c +++ b/drivers/rtc/rtc-m41t93.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * * Driver for ST M41T93 SPI RTC * * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c index bab82b4be356..6803b0273302 100644 --- a/drivers/rtc/rtc-m41t94.c +++ b/drivers/rtc/rtc-m41t94.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for ST M41T94 SPI RTC * * Copyright (C) 2008 Kim B. Heino - * - * 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> diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index 0cf6507de3c7..d3a75d447fce 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip * @@ -7,11 +8,6 @@ * Copyright (C) 2008 Thomas Bogendoerfer * * Based on code written by Paul Gortmaker. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 3c8ad1cdfd7c..67e218758a8b 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST M48T59 RTC driver * * Copyright (c) 2007 Wind River Systems, Inc. * * Author: Mark Zhan <rongkai.zhan@windriver.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/kernel.h> diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index a9533535c3b7..59b54ed9b841 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ST M48T86 / Dallas DS12887 RTC driver * Copyright (c) 2006 Tower Technologies * * Author: Alessandro Zummo <a.zummo@towertech.it> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * This drivers only supports the clock running in BCD and 24H mode. * If it will be ever adapted to binary and 12H mode, care must be taken * to not introduce bugs. diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 745827463367..daaeb6fb6c2d 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-max6902.c * * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for MAX6902 spi RTC - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-max6916.c b/drivers/rtc/rtc-max6916.c index 9d4b407cc4b8..e72e768ab8ff 100644 --- a/drivers/rtc/rtc-max6916.c +++ b/drivers/rtc/rtc-max6916.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* rtc-max6916.c * * Driver for MAXIM max6916 Low Current, SPI Compatible * Real Time Clock * * Author : Venkat Prashanth B U <venkat.prashanth2498@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> diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 4aff349ae301..d5a0e27dd0a0 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -673,11 +673,8 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) struct platform_device *pdev = to_platform_device(info->dev); info->rtc_irq = platform_get_irq(pdev, 0); - if (info->rtc_irq < 0) { - dev_err(info->dev, "Failed to get rtc interrupts: %d\n", - info->rtc_irq); + if (info->rtc_irq < 0) return info->rtc_irq; - } } else { info->rtc_irq = parent_i2c->irq; } @@ -693,11 +690,11 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) goto add_rtc_irq; } - info->rtc = i2c_new_dummy(parent_i2c->adapter, - info->drv_data->rtc_i2c_addr); - if (!info->rtc) { + info->rtc = devm_i2c_new_dummy_device(info->dev, parent_i2c->adapter, + info->drv_data->rtc_i2c_addr); + if (IS_ERR(info->rtc)) { dev_err(info->dev, "Failed to allocate I2C device for RTC\n"); - return -ENODEV; + return PTR_ERR(info->rtc); } info->rtc_regmap = devm_regmap_init_i2c(info->rtc, @@ -705,7 +702,7 @@ static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) if (IS_ERR(info->rtc_regmap)) { ret = PTR_ERR(info->rtc_regmap); dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret); - goto err_unregister_i2c; + return ret; } add_rtc_irq: @@ -715,15 +712,10 @@ add_rtc_irq: &info->rtc_irq_data); if (ret < 0) { dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret); - goto err_unregister_i2c; + return ret; } return 0; - -err_unregister_i2c: - if (info->rtc) - i2c_unregister_device(info->rtc); - return ret; } static int max77686_rtc_probe(struct platform_device *pdev) @@ -786,8 +778,6 @@ static int max77686_rtc_probe(struct platform_device *pdev) err_rtc: regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data); - if (info->rtc) - i2c_unregister_device(info->rtc); return ret; } @@ -798,8 +788,6 @@ static int max77686_rtc_remove(struct platform_device *pdev) free_irq(info->virq, info); regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data); - if (info->rtc) - i2c_unregister_device(info->rtc); return 0; } diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index 19c29b72598d..db3495d10274 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC driver for Maxim MAX8907 * @@ -5,10 +6,6 @@ * * Based on drivers/rtc/rtc-max8925.c, * Copyright (C) 2009-2010 Marvell International Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 67d6fc2d23e6..64bb8ac6ef62 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC driver for Maxim MAX8925 * * Copyright (C) 2009-2010 Marvell International Ltd. * Haojian Zhuang <haojian.zhuang@marvell.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 0fa33708fc49..afce2c0b4bd6 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Real Time Clock driver for Freescale MC13XXX PMIC * * (C) 2009 Sascha Hauer, Pengutronix * (C) 2009 Uwe Kleine-Koenig, Pengutronix - * - * 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/mfd/mc13xxx.h> @@ -89,14 +86,14 @@ static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } -static int mc13xxx_rtc_set_mmss(struct device *dev, time64_t secs) +static int mc13xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct mc13xxx_rtc *priv = dev_get_drvdata(dev); unsigned int seconds, days; unsigned int alarmseconds; int ret; - days = div_s64_rem(secs, SEC_PER_DAY, &seconds); + days = div_s64_rem(rtc_tm_to_time64(tm), SEC_PER_DAY, &seconds); mc13xxx_lock(priv->mc13xxx); @@ -158,7 +155,7 @@ out: static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct mc13xxx_rtc *priv = dev_get_drvdata(dev); - unsigned seconds, days; + unsigned int seconds, days; time64_t s1970; int enabled, pending; int ret; @@ -253,7 +250,7 @@ static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev) static const struct rtc_class_ops mc13xxx_rtc_ops = { .read_time = mc13xxx_rtc_read_time, - .set_mmss64 = mc13xxx_rtc_set_mmss, + .set_time = mc13xxx_rtc_set_time, .read_alarm = mc13xxx_rtc_read_alarm, .set_alarm = mc13xxx_rtc_set_alarm, .alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable, @@ -285,8 +282,15 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev) priv->mc13xxx = mc13xxx; priv->valid = 1; + priv->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(priv->rtc)) + return PTR_ERR(priv->rtc); platform_set_drvdata(pdev, priv); + priv->rtc->ops = &mc13xxx_rtc_ops; + /* 15bit days + hours, minutes, seconds */ + priv->rtc->range_max = (timeu64_t)(1 << 15) * SEC_PER_DAY - 1; + mc13xxx_lock(mc13xxx); mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST); @@ -303,8 +307,9 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev) mc13xxx_unlock(mc13xxx); - priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &mc13xxx_rtc_ops, THIS_MODULE); + ret = rtc_register_device(priv->rtc); + if (ret) + goto err_irq_request; return 0; diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index 18a6f15e313d..2ecd8752b088 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only #include <linux/bcd.h> #include <linux/delay.h> #include <linux/export.h> diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index f22a945a3794..1660d5e79582 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI Driver for Microchip MCP795 RTC * @@ -7,11 +8,6 @@ * * 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> diff --git a/drivers/rtc/rtc-meson-vrtc.c b/drivers/rtc/rtc-meson-vrtc.c new file mode 100644 index 000000000000..89e5ba0dae69 --- /dev/null +++ b/drivers/rtc/rtc-meson-vrtc.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/time64.h> + +struct meson_vrtc_data { + void __iomem *io_alarm; + struct rtc_device *rtc; + unsigned long alarm_time; + bool enabled; +}; + +static int meson_vrtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct timespec64 time; + + dev_dbg(dev, "%s\n", __func__); + ktime_get_raw_ts64(&time); + rtc_time64_to_tm(time.tv_sec, tm); + + return 0; +} + +static void meson_vrtc_set_wakeup_time(struct meson_vrtc_data *vrtc, + unsigned long time) +{ + writel_relaxed(time, vrtc->io_alarm); +} + +static int meson_vrtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct meson_vrtc_data *vrtc = dev_get_drvdata(dev); + + dev_dbg(dev, "%s: alarm->enabled=%d\n", __func__, alarm->enabled); + if (alarm->enabled) + vrtc->alarm_time = rtc_tm_to_time64(&alarm->time); + else + vrtc->alarm_time = 0; + + return 0; +} + +static int meson_vrtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct meson_vrtc_data *vrtc = dev_get_drvdata(dev); + + vrtc->enabled = enabled; + return 0; +} + +static const struct rtc_class_ops meson_vrtc_ops = { + .read_time = meson_vrtc_read_time, + .set_alarm = meson_vrtc_set_alarm, + .alarm_irq_enable = meson_vrtc_alarm_irq_enable, +}; + +static int meson_vrtc_probe(struct platform_device *pdev) +{ + struct meson_vrtc_data *vrtc; + int ret; + + vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL); + if (!vrtc) + return -ENOMEM; + + vrtc->io_alarm = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(vrtc->io_alarm)) + return PTR_ERR(vrtc->io_alarm); + + device_init_wakeup(&pdev->dev, 1); + + platform_set_drvdata(pdev, vrtc); + + vrtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(vrtc->rtc)) + return PTR_ERR(vrtc->rtc); + + vrtc->rtc->ops = &meson_vrtc_ops; + ret = rtc_register_device(vrtc->rtc); + if (ret) + return ret; + + return 0; +} + +static int __maybe_unused meson_vrtc_suspend(struct device *dev) +{ + struct meson_vrtc_data *vrtc = dev_get_drvdata(dev); + + dev_dbg(dev, "%s\n", __func__); + if (vrtc->alarm_time) { + unsigned long local_time; + long alarm_secs; + struct timespec64 time; + + ktime_get_raw_ts64(&time); + local_time = time.tv_sec; + + dev_dbg(dev, "alarm_time = %lus, local_time=%lus\n", + vrtc->alarm_time, local_time); + alarm_secs = vrtc->alarm_time - local_time; + if (alarm_secs > 0) { + meson_vrtc_set_wakeup_time(vrtc, alarm_secs); + dev_dbg(dev, "system will wakeup in %lds.\n", + alarm_secs); + } else { + dev_err(dev, "alarm time already passed: %lds.\n", + alarm_secs); + } + } + + return 0; +} + +static int __maybe_unused meson_vrtc_resume(struct device *dev) +{ + struct meson_vrtc_data *vrtc = dev_get_drvdata(dev); + + dev_dbg(dev, "%s\n", __func__); + + vrtc->alarm_time = 0; + meson_vrtc_set_wakeup_time(vrtc, 0); + return 0; +} + +static SIMPLE_DEV_PM_OPS(meson_vrtc_pm_ops, + meson_vrtc_suspend, meson_vrtc_resume); + +static const struct of_device_id meson_vrtc_dt_match[] = { + { .compatible = "amlogic,meson-vrtc"}, + {}, +}; +MODULE_DEVICE_TABLE(of, meson_vrtc_dt_match); + +static struct platform_driver meson_vrtc_driver = { + .probe = meson_vrtc_probe, + .driver = { + .name = "meson-vrtc", + .of_match_table = meson_vrtc_dt_match, + .pm = &meson_vrtc_pm_ops, + }, +}; + +module_platform_driver(meson_vrtc_driver); + +MODULE_DESCRIPTION("Amlogic Virtual Wakeup RTC Timer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index dd0364293bc0..15a9d0278778 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Real-time clock driver for MPC5121 * * Copyright 2007, Domen Puncer <domen.puncer@telargo.com> * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved. * Copyright 2011, Dmitry Eremin-Solenikov - * - * 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> diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index daf354a6a853..17bf5394e1e5 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-mrst.c: Driver for Moorestown virtual RTC * @@ -5,11 +6,6 @@ * Author: Jacob Pan (jacob.jun.pan@intel.com) * Feng Tang (feng.tang@intel.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - * * Note: * VRTC is emulated by system controller firmware, the real HW * RTC is located in the PMIC device. SCU FW shadows PMIC RTC diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index 0c72a2e8ec67..1c2d3c4a4963 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Oki MSM6242 RTC Driver * diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index e9a25ec4d434..5249fc99fd5f 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -1,80 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014-2015 MediaTek Inc. * Author: Tianping.Fang <tianping.fang@mediatek.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. -* -* 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/delay.h> -#include <linux/init.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/mfd/mt6397/core.h> #include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/rtc.h> -#include <linux/irqdomain.h> -#include <linux/platform_device.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/io.h> -#include <linux/mfd/mt6397/core.h> - -#define RTC_BBPU 0x0000 -#define RTC_BBPU_CBUSY BIT(6) - -#define RTC_WRTGR 0x003c - -#define RTC_IRQ_STA 0x0002 -#define RTC_IRQ_STA_AL BIT(0) -#define RTC_IRQ_STA_LP BIT(3) - -#define RTC_IRQ_EN 0x0004 -#define RTC_IRQ_EN_AL BIT(0) -#define RTC_IRQ_EN_ONESHOT BIT(2) -#define RTC_IRQ_EN_LP BIT(3) -#define RTC_IRQ_EN_ONESHOT_AL (RTC_IRQ_EN_ONESHOT | RTC_IRQ_EN_AL) - -#define RTC_AL_MASK 0x0008 -#define RTC_AL_MASK_DOW BIT(4) - -#define RTC_TC_SEC 0x000a -/* Min, Hour, Dom... register offset to RTC_TC_SEC */ -#define RTC_OFFSET_SEC 0 -#define RTC_OFFSET_MIN 1 -#define RTC_OFFSET_HOUR 2 -#define RTC_OFFSET_DOM 3 -#define RTC_OFFSET_DOW 4 -#define RTC_OFFSET_MTH 5 -#define RTC_OFFSET_YEAR 6 -#define RTC_OFFSET_COUNT 7 - -#define RTC_AL_SEC 0x0018 - -#define RTC_PDN2 0x002e -#define RTC_PDN2_PWRON_ALARM BIT(4) - -#define RTC_MIN_YEAR 1968 -#define RTC_BASE_YEAR 1900 -#define RTC_NUM_YEARS 128 -#define RTC_MIN_YEAR_OFFSET (RTC_MIN_YEAR - RTC_BASE_YEAR) - -struct mt6397_rtc { - struct device *dev; - struct rtc_device *rtc_dev; - struct mutex lock; - struct regmap *regmap; - int irq; - u32 addr_base; -}; +#include <linux/mfd/mt6397/rtc.h> +#include <linux/mod_devicetable.h> static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc) { - unsigned long timeout = jiffies + HZ; int ret; u32 data; @@ -82,19 +24,13 @@ static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc) if (ret < 0) return ret; - while (1) { - ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_BBPU, - &data); - if (ret < 0) - break; - if (!(data & RTC_BBPU_CBUSY)) - break; - if (time_after(jiffies, timeout)) { - ret = -ETIMEDOUT; - break; - } - cpu_relax(); - } + ret = regmap_read_poll_timeout(rtc->regmap, + rtc->addr_base + RTC_BBPU, data, + !(data & RTC_BBPU_CBUSY), + MTK_RTC_POLL_DELAY_US, + MTK_RTC_POLL_TIMEOUT); + if (ret < 0) + dev_err(rtc->dev, "failed to write WRTGE: %d\n", ret); return ret; } @@ -327,23 +263,23 @@ static int mtk_rtc_probe(struct platform_device *pdev) return rtc->irq; rtc->regmap = mt6397_chip->regmap; - rtc->dev = &pdev->dev; mutex_init(&rtc->lock); platform_set_drvdata(pdev, rtc); - rtc->rtc_dev = devm_rtc_allocate_device(rtc->dev); + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); - ret = request_threaded_irq(rtc->irq, NULL, - mtk_rtc_irq_handler_thread, - IRQF_ONESHOT | IRQF_TRIGGER_HIGH, - "mt6397-rtc", rtc); + ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, + mtk_rtc_irq_handler_thread, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + "mt6397-rtc", rtc); + if (ret) { dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", rtc->irq, ret); - goto out_dispose_irq; + return ret; } device_init_wakeup(&pdev->dev, 1); @@ -351,30 +287,16 @@ static int mtk_rtc_probe(struct platform_device *pdev) rtc->rtc_dev->ops = &mtk_rtc_ops; ret = rtc_register_device(rtc->rtc_dev); - if (ret) { - dev_err(&pdev->dev, "register rtc device failed\n"); + if (ret) goto out_free_irq; - } return 0; out_free_irq: - free_irq(rtc->irq, rtc->rtc_dev); -out_dispose_irq: - irq_dispose_mapping(rtc->irq); + free_irq(rtc->irq, rtc); return ret; } -static int mtk_rtc_remove(struct platform_device *pdev) -{ - struct mt6397_rtc *rtc = platform_get_drvdata(pdev); - - free_irq(rtc->irq, rtc->rtc_dev); - irq_dispose_mapping(rtc->irq); - - return 0; -} - #ifdef CONFIG_PM_SLEEP static int mt6397_rtc_suspend(struct device *dev) { @@ -401,6 +323,7 @@ static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_rtc_suspend, mt6397_rtc_resume); static const struct of_device_id mt6397_rtc_of_match[] = { + { .compatible = "mediatek,mt6323-rtc", }, { .compatible = "mediatek,mt6397-rtc", }, { } }; @@ -413,7 +336,6 @@ static struct platform_driver mtk_rtc_driver = { .pm = &mt6397_pm_ops, }, .probe = mtk_rtc_probe, - .remove = mtk_rtc_remove, }; module_platform_driver(mtk_rtc_driver); diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c index fd0cea722286..16bd26b5aa6f 100644 --- a/drivers/rtc/rtc-mt7622.c +++ b/drivers/rtc/rtc-mt7622.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for MediaTek SoC based RTC * * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.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/clk.h> @@ -338,7 +329,6 @@ static int mtk_rtc_probe(struct platform_device *pdev) hw->irq = platform_get_irq(pdev, 0); if (hw->irq < 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); ret = hw->irq; goto err; } diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index e7f14bd12fe3..ab9db57a6834 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the RTC in Marvell SoCs. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/init.h> @@ -60,7 +57,7 @@ static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc_reg = (bin2bcd(tm->tm_mday) << RTC_MDAY_OFFS) | (bin2bcd(tm->tm_mon + 1) << RTC_MONTH_OFFS) | - (bin2bcd(tm->tm_year % 100) << RTC_YEAR_OFFS); + (bin2bcd(tm->tm_year - 100) << RTC_YEAR_OFFS); writel(rtc_reg, ioaddr + RTC_DATE_REG_OFFS); return 0; @@ -159,7 +156,7 @@ static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) << RTC_MONTH_OFFS; if (alm->time.tm_year >= 0) - rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_year % 100)) + rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_year - 100)) << RTC_YEAR_OFFS; writel(rtc_reg, ioaddr + RTC_ALARM_DATE_REG_OFFS); @@ -257,15 +254,7 @@ static int __init mv_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pdata); - if (pdata->irq >= 0) { - device_init_wakeup(&pdev->dev, 1); - pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &mv_rtc_alarm_ops, - THIS_MODULE); - } else { - pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &mv_rtc_ops, THIS_MODULE); - } + pdata->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(pdata->rtc)) { ret = PTR_ERR(pdata->rtc); goto out; @@ -281,7 +270,19 @@ static int __init mv_rtc_probe(struct platform_device *pdev) } } - return 0; + if (pdata->irq >= 0) { + device_init_wakeup(&pdev->dev, 1); + pdata->rtc->ops = &mv_rtc_alarm_ops; + } else { + pdata->rtc->ops = &mv_rtc_ops; + } + + pdata->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + pdata->rtc->range_max = RTC_TIMESTAMP_END_2099; + + ret = rtc_register_device(pdata->rtc); + if (!ret) + return 0; out: if (!IS_ERR(pdata->clk)) clk_disable_unprepare(pdata->clk); diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 878c6ee82901..902d57dcd0d4 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -8,6 +8,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/clk.h> #include <linux/of.h> #include <linux/of_device.h> @@ -183,8 +184,9 @@ static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit, struct rtc_plat_data *pdata = dev_get_drvdata(dev); void __iomem *ioaddr = pdata->ioaddr; u32 reg; + unsigned long flags; - spin_lock_irq(&pdata->rtc->irq_lock); + spin_lock_irqsave(&pdata->rtc->irq_lock, flags); reg = readw(ioaddr + RTC_RTCIENR); if (enabled) @@ -193,7 +195,7 @@ static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit, reg &= ~bit; writew(reg, ioaddr + RTC_RTCIENR); - spin_unlock_irq(&pdata->rtc->irq_lock); + spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); } /* This function is the RTC interrupt service routine. */ @@ -253,20 +255,9 @@ static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm) /* * This function sets the internal RTC time based on tm in Gregorian date. */ -static int mxc_rtc_set_mmss(struct device *dev, time64_t time) +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct rtc_plat_data *pdata = dev_get_drvdata(dev); - - /* - * TTC_DAYR register is 9-bit in MX1 SoC, save time and day of year only - */ - if (is_imx1_rtc(pdata)) { - struct rtc_time tm; - - rtc_time64_to_tm(time, &tm); - tm.tm_year = 70; - time = rtc_tm_to_time64(&tm); - } + time64_t time = rtc_tm_to_time64(tm); /* Avoid roll-over from reading the different registers */ do { @@ -310,7 +301,7 @@ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) /* RTC layer */ static const struct rtc_class_ops mxc_rtc_ops = { .read_time = mxc_rtc_read_time, - .set_mmss64 = mxc_rtc_set_mmss, + .set_time = mxc_rtc_set_time, .read_alarm = mxc_rtc_read_alarm, .set_alarm = mxc_rtc_set_alarm, .alarm_irq_enable = mxc_rtc_alarm_irq_enable, @@ -318,7 +309,6 @@ static const struct rtc_class_ops mxc_rtc_ops = { static int mxc_rtc_probe(struct platform_device *pdev) { - struct resource *res; struct rtc_device *rtc; struct rtc_plat_data *pdata = NULL; u32 reg; @@ -336,11 +326,34 @@ static int mxc_rtc_probe(struct platform_device *pdev) else pdata->devtype = pdev->id_entry->driver_data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); + pdata->ioaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pdata->ioaddr)) return PTR_ERR(pdata->ioaddr); + rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + pdata->rtc = rtc; + rtc->ops = &mxc_rtc_ops; + if (is_imx1_rtc(pdata)) { + struct rtc_time tm; + + /* 9bit days + hours minutes seconds */ + rtc->range_max = (1 << 9) * 86400 - 1; + + /* + * Set the start date as beginning of the current year. This can + * be overridden using device tree. + */ + rtc_time64_to_tm(ktime_get_real_seconds(), &tm); + rtc->start_secs = mktime64(tm.tm_year, 1, 1, 0, 0, 0); + rtc->set_start_time = true; + } else { + /* 16bit days + hours minutes seconds */ + rtc->range_max = (1 << 16) * 86400ULL - 1; + } + pdata->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(pdata->clk_ipg)) { dev_err(&pdev->dev, "unable to get ipg clock!\n"); @@ -396,17 +409,16 @@ 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_put_clk_ref; + ret = dev_pm_set_wake_irq(&pdev->dev, pdata->irq); + if (ret) + dev_err(&pdev->dev, "failed to enable irq wake\n"); } - pdata->rtc = rtc; + ret = rtc_register_device(rtc); + if (ret) + goto exit_put_clk_ref; return 0; @@ -428,35 +440,10 @@ static int mxc_rtc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int mxc_rtc_suspend(struct device *dev) -{ - struct rtc_plat_data *pdata = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(pdata->irq); - - return 0; -} - -static int mxc_rtc_resume(struct device *dev) -{ - struct rtc_plat_data *pdata = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(pdata->irq); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(mxc_rtc_pm_ops, mxc_rtc_suspend, mxc_rtc_resume); - static struct platform_driver mxc_rtc_driver = { .driver = { .name = "mxc_rtc", .of_match_table = of_match_ptr(imx_rtc_dt_ids), - .pm = &mxc_rtc_pm_ops, }, .id_table = imx_rtc_devtype, .probe = mxc_rtc_probe, diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index 007879a5042d..91534560fe2a 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/rtc.h> #define SRTC_LPPDR_INIT 0x41736166 /* init for glitch detect */ @@ -278,7 +279,6 @@ static int mxc_rtc_wait_for_flag(void __iomem *ioaddr, int flag) static int mxc_rtc_probe(struct platform_device *pdev) { struct mxc_rtc_data *pdata; - struct resource *res; void __iomem *ioaddr; int ret = 0; @@ -286,8 +286,7 @@ static int mxc_rtc_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); + pdata->ioaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pdata->ioaddr)) return PTR_ERR(pdata->ioaddr); @@ -305,6 +304,9 @@ static int mxc_rtc_probe(struct platform_device *pdev) return pdata->irq; device_init_wakeup(&pdev->dev, 1); + ret = dev_pm_set_wake_irq(&pdev->dev, pdata->irq); + if (ret) + dev_err(&pdev->dev, "failed to enable irq wake\n"); ret = clk_prepare_enable(pdata->clk); if (ret) @@ -367,30 +369,6 @@ static int mxc_rtc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int mxc_rtc_suspend(struct device *dev) -{ - struct mxc_rtc_data *pdata = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(pdata->irq); - - return 0; -} - -static int mxc_rtc_resume(struct device *dev) -{ - struct mxc_rtc_data *pdata = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(pdata->irq); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(mxc_rtc_pm_ops, mxc_rtc_suspend, mxc_rtc_resume); - static const struct of_device_id mxc_ids[] = { { .compatible = "fsl,imx53-rtc", }, {} @@ -400,7 +378,6 @@ static struct platform_driver mxc_rtc_driver = { .driver = { .name = "mxc_rtc_v2", .of_match_table = mxc_ids, - .pm = &mxc_rtc_pm_ops, }, .probe = mxc_rtc_probe, .remove = mxc_rtc_remove, diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c deleted file mode 100644 index 7da664a77181..000000000000 --- a/drivers/rtc/rtc-nuc900.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2008-2009 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@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;version 2 of the License. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/rtc.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/bcd.h> - -/* RTC Control Registers */ -#define REG_RTC_INIR 0x00 -#define REG_RTC_AER 0x04 -#define REG_RTC_FCR 0x08 -#define REG_RTC_TLR 0x0C -#define REG_RTC_CLR 0x10 -#define REG_RTC_TSSR 0x14 -#define REG_RTC_DWR 0x18 -#define REG_RTC_TAR 0x1C -#define REG_RTC_CAR 0x20 -#define REG_RTC_LIR 0x24 -#define REG_RTC_RIER 0x28 -#define REG_RTC_RIIR 0x2C -#define REG_RTC_TTR 0x30 - -#define RTCSET 0x01 -#define AERRWENB 0x10000 -#define INIRRESET 0xa5eb1357 -#define AERPOWERON 0xA965 -#define AERPOWEROFF 0x0000 -#define LEAPYEAR 0x0001 -#define TICKENB 0x80 -#define TICKINTENB 0x0002 -#define ALARMINTENB 0x0001 -#define MODE24 0x0001 - -struct nuc900_rtc { - int irq_num; - void __iomem *rtc_reg; - struct rtc_device *rtcdev; -}; - -struct nuc900_bcd_time { - int bcd_sec; - int bcd_min; - int bcd_hour; - int bcd_mday; - int bcd_mon; - int bcd_year; -}; - -static irqreturn_t nuc900_rtc_interrupt(int irq, void *_rtc) -{ - struct nuc900_rtc *rtc = _rtc; - unsigned long events = 0, rtc_irq; - - rtc_irq = __raw_readl(rtc->rtc_reg + REG_RTC_RIIR); - - if (rtc_irq & ALARMINTENB) { - rtc_irq &= ~ALARMINTENB; - __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); - events |= RTC_AF | RTC_IRQF; - } - - if (rtc_irq & TICKINTENB) { - rtc_irq &= ~TICKINTENB; - __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); - events |= RTC_UF | RTC_IRQF; - } - - rtc_update_irq(rtc->rtcdev, 1, events); - - return IRQ_HANDLED; -} - -static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) -{ - unsigned int timeout = 0x1000; - __raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR); - - mdelay(10); - - __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER); - - while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) - && --timeout) - mdelay(1); - - if (!timeout) - return ERR_PTR(-EPERM); - - return NULL; -} - -static void nuc900_rtc_bcd2bin(unsigned int timereg, - unsigned int calreg, struct rtc_time *tm) -{ - tm->tm_mday = bcd2bin(calreg >> 0); - tm->tm_mon = bcd2bin(calreg >> 8); - tm->tm_year = bcd2bin(calreg >> 16) + 100; - - tm->tm_sec = bcd2bin(timereg >> 0); - tm->tm_min = bcd2bin(timereg >> 8); - tm->tm_hour = bcd2bin(timereg >> 16); -} - -static void nuc900_rtc_bin2bcd(struct device *dev, struct rtc_time *settm, - struct nuc900_bcd_time *gettm) -{ - gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0; - gettm->bcd_mon = bin2bcd(settm->tm_mon) << 8; - - if (settm->tm_year < 100) { - dev_warn(dev, "The year will be between 1970-1999, right?\n"); - gettm->bcd_year = bin2bcd(settm->tm_year) << 16; - } else { - gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16; - } - - gettm->bcd_sec = bin2bcd(settm->tm_sec) << 0; - gettm->bcd_min = bin2bcd(settm->tm_min) << 8; - gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16; -} - -static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - - if (enabled) - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| - (ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); - else - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& - (~ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); - - return 0; -} - -static int nuc900_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - unsigned int timeval, clrval; - - timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR); - clrval = __raw_readl(rtc->rtc_reg + REG_RTC_CLR); - - nuc900_rtc_bcd2bin(timeval, clrval, tm); - - return 0; -} - -static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - struct nuc900_bcd_time gettm; - unsigned long val; - int *err; - - nuc900_rtc_bin2bcd(dev, tm, &gettm); - - err = check_rtc_access_enable(rtc); - if (IS_ERR(err)) - return PTR_ERR(err); - - val = gettm.bcd_mday | gettm.bcd_mon | gettm.bcd_year; - __raw_writel(val, rtc->rtc_reg + REG_RTC_CLR); - - val = gettm.bcd_sec | gettm.bcd_min | gettm.bcd_hour; - __raw_writel(val, rtc->rtc_reg + REG_RTC_TLR); - - return 0; -} - -static int nuc900_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - unsigned int timeval, carval; - - timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR); - carval = __raw_readl(rtc->rtc_reg + REG_RTC_CAR); - - nuc900_rtc_bcd2bin(timeval, carval, &alrm->time); - - return rtc_valid_tm(&alrm->time); -} - -static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - struct nuc900_bcd_time tm; - unsigned long val; - int *err; - - nuc900_rtc_bin2bcd(dev, &alrm->time, &tm); - - err = check_rtc_access_enable(rtc); - if (IS_ERR(err)) - return PTR_ERR(err); - - val = tm.bcd_mday | tm.bcd_mon | tm.bcd_year; - __raw_writel(val, rtc->rtc_reg + REG_RTC_CAR); - - val = tm.bcd_sec | tm.bcd_min | tm.bcd_hour; - __raw_writel(val, rtc->rtc_reg + REG_RTC_TAR); - - return 0; -} - -static const struct rtc_class_ops nuc900_rtc_ops = { - .read_time = nuc900_rtc_read_time, - .set_time = nuc900_rtc_set_time, - .read_alarm = nuc900_rtc_read_alarm, - .set_alarm = nuc900_rtc_set_alarm, - .alarm_irq_enable = nuc900_alarm_irq_enable, -}; - -static int __init nuc900_rtc_probe(struct platform_device *pdev) -{ - struct resource *res; - struct nuc900_rtc *nuc900_rtc; - - nuc900_rtc = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_rtc), - GFP_KERNEL); - 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)) - return PTR_ERR(nuc900_rtc->rtc_reg); - - platform_set_drvdata(pdev, nuc900_rtc); - - nuc900_rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name, - &nuc900_rtc_ops, THIS_MODULE); - if (IS_ERR(nuc900_rtc->rtcdev)) { - dev_err(&pdev->dev, "rtc device register failed\n"); - return PTR_ERR(nuc900_rtc->rtcdev); - } - - __raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24, - nuc900_rtc->rtc_reg + REG_RTC_TSSR); - - nuc900_rtc->irq_num = platform_get_irq(pdev, 0); - if (devm_request_irq(&pdev->dev, nuc900_rtc->irq_num, - nuc900_rtc_interrupt, 0, "nuc900rtc", nuc900_rtc)) { - dev_err(&pdev->dev, "NUC900 RTC request irq failed\n"); - return -EBUSY; - } - - return 0; -} - -static struct platform_driver nuc900_rtc_driver = { - .driver = { - .name = "nuc900-rtc", - }, -}; - -module_platform_driver_probe(nuc900_rtc_driver, nuc900_rtc_probe); - -MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("nuc910/nuc920 RTC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-rtc"); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index bbff0e2deb84..a2941c875a06 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * TI OMAP Real Time Clock interface for Linux * @@ -6,11 +7,6 @@ * * Copyright (C) 2006 David Brownell (new RTC framework) * Copyright (C) 2014 Johan Hovold <johan@kernel.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <dt-bindings/gpio/gpio.h> @@ -271,7 +267,7 @@ static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) } /* this hardware doesn't support "don't care" alarm fields */ -static int tm2bcd(struct rtc_time *tm) +static void tm2bcd(struct rtc_time *tm) { tm->tm_sec = bin2bcd(tm->tm_sec); tm->tm_min = bin2bcd(tm->tm_min); @@ -279,13 +275,7 @@ static int tm2bcd(struct rtc_time *tm) tm->tm_mday = bin2bcd(tm->tm_mday); tm->tm_mon = bin2bcd(tm->tm_mon + 1); - - /* epoch == 1900 */ - if (tm->tm_year < 100 || tm->tm_year > 199) - return -EINVAL; tm->tm_year = bin2bcd(tm->tm_year - 100); - - return 0; } static void bcd2tm(struct rtc_time *tm) @@ -328,8 +318,7 @@ static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct omap_rtc *rtc = dev_get_drvdata(dev); - if (tm2bcd(tm) < 0) - return -EINVAL; + tm2bcd(tm); local_irq_disable(); rtc_wait_not_busy(rtc); @@ -378,8 +367,7 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) struct omap_rtc *rtc = dev_get_drvdata(dev); u8 reg, irqwake_reg = 0; - if (tm2bcd(&alm->time) < 0) - return -EINVAL; + tm2bcd(&alm->time); local_irq_disable(); rtc_wait_not_busy(rtc); @@ -415,15 +403,12 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) static struct omap_rtc *omap_rtc_power_off_rtc; -/* - * omap_rtc_poweroff: RTC-controlled power off - * - * The RTC can be used to control an external PMIC via the pmic_power_en pin, - * which can be configured to transition to OFF on ALARM2 events. - * - * Called with local interrupts disabled. +/** + * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC + * generates pmic_pwr_enable control, which can be used to control an external + * PMIC. */ -static void omap_rtc_power_off(void) +int omap_rtc_power_off_program(struct device *dev) { struct omap_rtc *rtc = omap_rtc_power_off_rtc; struct rtc_time tm; @@ -437,18 +422,17 @@ static void omap_rtc_power_off(void) rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); again: + /* Clear any existing ALARM2 event */ + rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2); + /* set alarm one second from now */ omap_rtc_read_time_raw(rtc, &tm); seconds = tm.tm_sec; bcd2tm(&tm); - rtc_tm_to_time(&tm, &now); - rtc_time_to_tm(now + 1, &tm); + now = rtc_tm_to_time64(&tm); + rtc_time64_to_tm(now + 1, &tm); - if (tm2bcd(&tm) < 0) { - dev_err(&rtc->rtc->dev, "power off failed\n"); - rtc->type->lock(rtc); - return; - } + tm2bcd(&tm); rtc_wait_not_busy(rtc); @@ -477,6 +461,39 @@ again: rtc->type->lock(rtc); + return 0; +} +EXPORT_SYMBOL(omap_rtc_power_off_program); + +/* + * omap_rtc_poweroff: RTC-controlled power off + * + * The RTC can be used to control an external PMIC via the pmic_power_en pin, + * which can be configured to transition to OFF on ALARM2 events. + * + * Notes: + * The one-second alarm offset is the shortest offset possible as the alarm + * registers must be set before the next timer update and the offset + * calculation is too heavy for everything to be done within a single access + * period (~15 us). + * + * Called with local interrupts disabled. + */ +static void omap_rtc_power_off(void) +{ + struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc; + u32 val; + + omap_rtc_power_off_program(rtc->dev.parent); + + /* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */ + omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc); + val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG); + val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) | + OMAP_RTC_PMIC_EXT_WKUP_EN(0); + rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val); + omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc); + /* * Wait for alarm to trigger (within one second) and external PMIC to * power off the system. Add a 500 ms margin for external latencies @@ -845,6 +862,8 @@ static int omap_rtc_probe(struct platform_device *pdev) } rtc->rtc->ops = &omap_rtc_ops; + rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->rtc->range_max = RTC_TIMESTAMP_END_2099; omap_rtc_nvmem_config.priv = rtc; /* handle periodic and alarm irqs */ diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 60f2250fd96b..7b9f8bcf86fe 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * IBM OPAL RTC driver * Copyright (C) 2014 IBM - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -224,7 +212,7 @@ exit: return rc; } -int opal_tpo_alarm_irq_enable(struct device *dev, unsigned int enabled) +static int opal_tpo_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct rtc_wkalrm alarm = { .enabled = 0 }; diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index f176cb9d0dbc..178bfb1dea21 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * pcap rtc code for Motorola EZX phones * @@ -5,11 +6,6 @@ * Copyright (c) 2009 Daniel Ribeiro <drwyrm@gmail.com> * * Based on Motorola's rtc.c Copyright (c) 2003-2005 Motorola - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/kernel.h> @@ -55,7 +51,7 @@ static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAYA, &days); secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY; - rtc_time_to_tm(secs, tm); + rtc_time64_to_tm(secs, tm); return 0; } @@ -63,12 +59,9 @@ static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev); - struct rtc_time *tm = &alrm->time; - unsigned long secs; + unsigned long secs = rtc_tm_to_time64(&alrm->time); u32 tod, days; - rtc_tm_to_time(tm, &secs); - tod = secs % SEC_PER_DAY; ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_TODA, tod); @@ -90,14 +83,15 @@ static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm) ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAY, &days); secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY; - rtc_time_to_tm(secs, tm); + rtc_time64_to_tm(secs, tm); return 0; } -static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs) +static int pcap_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev); + unsigned long secs = rtc_tm_to_time64(tm); u32 tod, days; tod = secs % SEC_PER_DAY; @@ -128,9 +122,9 @@ static int pcap_rtc_alarm_irq_enable(struct device *dev, unsigned int en) static const struct rtc_class_ops pcap_rtc_ops = { .read_time = pcap_rtc_read_time, + .set_time = pcap_rtc_set_time, .read_alarm = pcap_rtc_read_alarm, .set_alarm = pcap_rtc_set_alarm, - .set_mmss = pcap_rtc_set_mmss, .alarm_irq_enable = pcap_rtc_alarm_irq_enable, }; @@ -149,11 +143,13 @@ static int __init pcap_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcap_rtc); - pcap_rtc->rtc = devm_rtc_device_register(&pdev->dev, "pcap", - &pcap_rtc_ops, THIS_MODULE); + pcap_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(pcap_rtc->rtc)) return PTR_ERR(pcap_rtc->rtc); + pcap_rtc->rtc->ops = &pcap_rtc_ops; + pcap_rtc->rtc->range_max = (1 << 14) * 86400ULL - 1; + timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); @@ -167,7 +163,7 @@ static int __init pcap_rtc_probe(struct platform_device *pdev) if (err) return err; - return 0; + return rtc_register_device(pcap_rtc->rtc); } 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 39da8b214275..c3691fa4210e 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An SPI driver for the Philips PCF2123 RTC * Copyright 2009 Cyber Switching, Inc. @@ -10,10 +11,6 @@ * Thanks to Christian Pellegrin <chripell@fsfe.org> for * the sysfs contributions to this driver. * - * 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. - * * Please note that the CS is active high, so platform data * should look something like: * @@ -29,7 +26,6 @@ * }, * ... *}; - * */ #include <linux/bcd.h> @@ -44,7 +40,7 @@ #include <linux/rtc.h> #include <linux/spi/spi.h> #include <linux/module.h> -#include <linux/sysfs.h> +#include <linux/regmap.h> /* REGISTERS */ #define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */ @@ -86,7 +82,7 @@ #define OSC_HAS_STOPPED BIT(7) /* Clock has been stopped */ /* PCF2123_REG_ALRM_XX BITS */ -#define ALRM_ENABLE BIT(7) /* MN, HR, DM, or DW alarm enable */ +#define ALRM_DISABLE BIT(7) /* MN, HR, DM, or DW alarm matching */ /* PCF2123_REG_TMR_CLKOUT BITS */ #define CD_TMR_4096KHZ (0) /* 4096 KHz countdown timer */ @@ -99,6 +95,7 @@ #define OFFSET_SIGN_BIT 6 /* 2's complement sign bit */ #define OFFSET_COARSE BIT(7) /* Coarse mode offset */ #define OFFSET_STEP (2170) /* Offset step in parts per billion */ +#define OFFSET_MASK GENMASK(6, 0) /* Offset value */ /* READ/WRITE ADDRESS BITS */ #define PCF2123_WRITE BIT(4) @@ -107,120 +104,35 @@ static struct spi_driver pcf2123_driver; -struct pcf2123_sysfs_reg { - struct device_attribute attr; - char name[2]; -}; - -struct pcf2123_plat_data { +struct pcf2123_data { struct rtc_device *rtc; - struct pcf2123_sysfs_reg regs[16]; + struct regmap *map; }; -/* - * Causes a 30 nanosecond delay to ensure that the PCF2123 chip select - * is released properly after an SPI write. This function should be - * called after EVERY read/write call over SPI. - */ -static inline void pcf2123_delay_trec(void) -{ - ndelay(30); -} - -static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size) -{ - struct spi_device *spi = to_spi_device(dev); - int ret; - - reg |= PCF2123_READ; - ret = spi_write_then_read(spi, ®, 1, rxbuf, size); - pcf2123_delay_trec(); - - return ret; -} - -static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size) -{ - struct spi_device *spi = to_spi_device(dev); - int ret; - - txbuf[0] |= PCF2123_WRITE; - ret = spi_write(spi, txbuf, size); - pcf2123_delay_trec(); - - return ret; -} - -static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val) -{ - u8 txbuf[2]; - - txbuf[0] = reg; - txbuf[1] = val; - return pcf2123_write(dev, txbuf, sizeof(txbuf)); -} - -static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, - char *buffer) -{ - struct pcf2123_sysfs_reg *r; - u8 rxbuf[1]; - unsigned long reg; - int ret; - - r = container_of(attr, struct pcf2123_sysfs_reg, attr); - - ret = kstrtoul(r->name, 16, ®); - if (ret) - return ret; - - ret = pcf2123_read(dev, reg, rxbuf, 1); - if (ret < 0) - return -EIO; - - return sprintf(buffer, "0x%x\n", rxbuf[0]); -} +static const struct regmap_config pcf2123_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = PCF2123_READ, + .write_flag_mask = PCF2123_WRITE, + .max_register = PCF2123_REG_CTDWN_TMR, +}; -static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, - const char *buffer, size_t count) +static int pcf2123_read_offset(struct device *dev, long *offset) { - struct pcf2123_sysfs_reg *r; - unsigned long reg; - unsigned long val; - - int ret; + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); + int ret, val; + unsigned int reg; - r = container_of(attr, struct pcf2123_sysfs_reg, attr); - - ret = kstrtoul(r->name, 16, ®); - if (ret) - return ret; - - ret = kstrtoul(buffer, 10, &val); + ret = regmap_read(pcf2123->map, PCF2123_REG_OFFSET, ®); if (ret) return ret; - ret = pcf2123_write_reg(dev, reg, val); - if (ret < 0) - return -EIO; - return count; -} - -static int pcf2123_read_offset(struct device *dev, long *offset) -{ - int ret; - s8 reg; - - ret = pcf2123_read(dev, PCF2123_REG_OFFSET, ®, 1); - if (ret < 0) - return ret; + val = sign_extend32((reg & OFFSET_MASK), OFFSET_SIGN_BIT); if (reg & OFFSET_COARSE) - reg <<= 1; /* multiply by 2 and sign extend */ - else - reg = sign_extend32(reg, OFFSET_SIGN_BIT); + val *= 2; - *offset = ((long)reg) * OFFSET_STEP; + *offset = ((long)val) * OFFSET_STEP; return 0; } @@ -237,6 +149,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset) */ static int pcf2123_set_offset(struct device *dev, long offset) { + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); s8 reg; if (offset > OFFSET_STEP * 127) @@ -244,7 +157,7 @@ static int pcf2123_set_offset(struct device *dev, long offset) else if (offset < OFFSET_STEP * -128) reg = -128; else - reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP); + reg = DIV_ROUND_CLOSEST(offset, OFFSET_STEP); /* choose fine offset only for odd values in the normal range */ if (reg & 1 && reg <= 63 && reg >= -64) { @@ -256,16 +169,18 @@ static int pcf2123_set_offset(struct device *dev, long offset) reg |= OFFSET_COARSE; } - return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg); + return regmap_write(pcf2123->map, PCF2123_REG_OFFSET, (unsigned int)reg); } static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) { + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); u8 rxbuf[7]; int ret; - ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf)); - if (ret < 0) + ret = regmap_bulk_read(pcf2123->map, PCF2123_REG_SC, rxbuf, + sizeof(rxbuf)); + if (ret) return ret; if (rxbuf[0] & OSC_HAS_STOPPED) { @@ -279,86 +194,170 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mday = bcd2bin(rxbuf[3] & 0x3F); tm->tm_wday = rxbuf[4] & 0x07; tm->tm_mon = bcd2bin(rxbuf[5] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = bcd2bin(rxbuf[6]); - if (tm->tm_year < 70) - tm->tm_year += 100; /* assume we are in 1970...2069 */ + tm->tm_year = bcd2bin(rxbuf[6]) + 100; - dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm); return 0; } static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) { - u8 txbuf[8]; + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); + u8 txbuf[7]; int ret; - dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + dev_dbg(dev, "%s: tm is %ptR\n", __func__, tm); /* Stop the counter first */ - ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP); - if (ret < 0) + ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_STOP); + if (ret) return ret; /* Set the new time */ - txbuf[0] = PCF2123_REG_SC; - txbuf[1] = bin2bcd(tm->tm_sec & 0x7F); - txbuf[2] = bin2bcd(tm->tm_min & 0x7F); - txbuf[3] = bin2bcd(tm->tm_hour & 0x3F); - txbuf[4] = bin2bcd(tm->tm_mday & 0x3F); - txbuf[5] = tm->tm_wday & 0x07; - txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */ - txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100); - - ret = pcf2123_write(dev, txbuf, sizeof(txbuf)); - if (ret < 0) + txbuf[0] = bin2bcd(tm->tm_sec & 0x7F); + txbuf[1] = bin2bcd(tm->tm_min & 0x7F); + txbuf[2] = bin2bcd(tm->tm_hour & 0x3F); + txbuf[3] = bin2bcd(tm->tm_mday & 0x3F); + txbuf[4] = tm->tm_wday & 0x07; + txbuf[5] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */ + txbuf[6] = bin2bcd(tm->tm_year - 100); + + ret = regmap_bulk_write(pcf2123->map, PCF2123_REG_SC, txbuf, + sizeof(txbuf)); + if (ret) return ret; /* Start the counter */ - ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); - if (ret < 0) + ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_CLEAR); + if (ret) return ret; return 0; } +static int pcf2123_rtc_alarm_irq_enable(struct device *dev, unsigned int en) +{ + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); + + return regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AIE, + en ? CTRL2_AIE : 0); +} + +static int pcf2123_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); + u8 rxbuf[4]; + int ret; + unsigned int val = 0; + + ret = regmap_bulk_read(pcf2123->map, PCF2123_REG_ALRM_MN, rxbuf, + sizeof(rxbuf)); + if (ret) + return ret; + + alm->time.tm_min = bcd2bin(rxbuf[0] & 0x7F); + alm->time.tm_hour = bcd2bin(rxbuf[1] & 0x3F); + alm->time.tm_mday = bcd2bin(rxbuf[2] & 0x3F); + alm->time.tm_wday = bcd2bin(rxbuf[3] & 0x07); + + dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time); + + ret = regmap_read(pcf2123->map, PCF2123_REG_CTRL2, &val); + if (ret) + return ret; + + alm->enabled = !!(val & CTRL2_AIE); + + return 0; +} + +static int pcf2123_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); + u8 txbuf[4]; + int ret; + + dev_dbg(dev, "%s: alm is %ptR\n", __func__, &alm->time); + + /* Disable alarm interrupt */ + ret = regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AIE, 0); + if (ret) + return ret; + + /* Ensure alarm flag is clear */ + ret = regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AF, 0); + if (ret) + return ret; + + /* Set new alarm */ + txbuf[0] = bin2bcd(alm->time.tm_min & 0x7F); + txbuf[1] = bin2bcd(alm->time.tm_hour & 0x3F); + txbuf[2] = bin2bcd(alm->time.tm_mday & 0x3F); + txbuf[3] = ALRM_DISABLE; + + ret = regmap_bulk_write(pcf2123->map, PCF2123_REG_ALRM_MN, txbuf, + sizeof(txbuf)); + if (ret) + return ret; + + return pcf2123_rtc_alarm_irq_enable(dev, alm->enabled); +} + +static irqreturn_t pcf2123_rtc_irq(int irq, void *dev) +{ + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); + struct mutex *lock = &pcf2123->rtc->ops_lock; + unsigned int val = 0; + int ret = IRQ_NONE; + + mutex_lock(lock); + regmap_read(pcf2123->map, PCF2123_REG_CTRL2, &val); + + /* Alarm? */ + if (val & CTRL2_AF) { + ret = IRQ_HANDLED; + + /* Clear alarm flag */ + regmap_update_bits(pcf2123->map, PCF2123_REG_CTRL2, CTRL2_AF, 0); + + rtc_update_irq(pcf2123->rtc, 1, RTC_IRQF | RTC_AF); + } + + mutex_unlock(lock); + + return ret; +} + static int pcf2123_reset(struct device *dev) { + struct pcf2123_data *pcf2123 = dev_get_drvdata(dev); int ret; - u8 rxbuf[2]; + unsigned int val = 0; - ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET); - if (ret < 0) + ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_SW_RESET); + if (ret) return ret; /* Stop the counter */ dev_dbg(dev, "stopping RTC\n"); - ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP); - if (ret < 0) + ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_STOP); + if (ret) return ret; /* See if the counter was actually stopped */ dev_dbg(dev, "checking for presence of RTC\n"); - ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf)); - if (ret < 0) + ret = regmap_read(pcf2123->map, PCF2123_REG_CTRL1, &val); + if (ret) return ret; - dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n", - rxbuf[0], rxbuf[1]); - if (!(rxbuf[0] & CTRL1_STOP)) + dev_dbg(dev, "received data from RTC (0x%08X)\n", val); + if (!(val & CTRL1_STOP)) return -ENODEV; /* Start the counter */ - ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); - if (ret < 0) + ret = regmap_write(pcf2123->map, PCF2123_REG_CTRL1, CTRL1_CLEAR); + if (ret) return ret; return 0; @@ -369,28 +368,37 @@ static const struct rtc_class_ops pcf2123_rtc_ops = { .set_time = pcf2123_rtc_set_time, .read_offset = pcf2123_read_offset, .set_offset = pcf2123_set_offset, - + .read_alarm = pcf2123_rtc_read_alarm, + .set_alarm = pcf2123_rtc_set_alarm, + .alarm_irq_enable = pcf2123_rtc_alarm_irq_enable, }; static int pcf2123_probe(struct spi_device *spi) { struct rtc_device *rtc; struct rtc_time tm; - struct pcf2123_plat_data *pdata; - int ret, i; + struct pcf2123_data *pcf2123; + int ret = 0; - pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data), + pcf2123 = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_data), GFP_KERNEL); - if (!pdata) + if (!pcf2123) return -ENOMEM; - spi->dev.platform_data = pdata; + + dev_set_drvdata(&spi->dev, pcf2123); + + pcf2123->map = devm_regmap_init_spi(spi, &pcf2123_regmap_config); + if (IS_ERR(pcf2123->map)) { + dev_err(&spi->dev, "regmap init failed.\n"); + return PTR_ERR(pcf2123->map); + } ret = pcf2123_rtc_read_time(&spi->dev, &tm); if (ret < 0) { ret = pcf2123_reset(&spi->dev); if (ret < 0) { dev_err(&spi->dev, "chip not found\n"); - goto kfree_exit; + return ret; } } @@ -398,62 +406,47 @@ static int pcf2123_probe(struct spi_device *spi) (spi->max_speed_hz + 500) / 1000); /* Finalize the initialization */ - rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name, - &pcf2123_rtc_ops, THIS_MODULE); - - if (IS_ERR(rtc)) { - dev_err(&spi->dev, "failed to register.\n"); - ret = PTR_ERR(rtc); - goto kfree_exit; + rtc = devm_rtc_allocate_device(&spi->dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + pcf2123->rtc = rtc; + + /* Register alarm irq */ + if (spi->irq > 0) { + ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, + pcf2123_rtc_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + pcf2123_driver.driver.name, &spi->dev); + if (!ret) + device_init_wakeup(&spi->dev, true); + else + dev_err(&spi->dev, "could not request irq.\n"); } - pdata->rtc = rtc; - - for (i = 0; i < 16; i++) { - sysfs_attr_init(&pdata->regs[i].attr.attr); - sprintf(pdata->regs[i].name, "%1x", i); - pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR; - pdata->regs[i].attr.attr.name = pdata->regs[i].name; - pdata->regs[i].attr.show = pcf2123_show; - pdata->regs[i].attr.store = pcf2123_store; - ret = device_create_file(&spi->dev, &pdata->regs[i].attr); - if (ret) { - dev_err(&spi->dev, "Unable to create sysfs %s\n", - pdata->regs[i].name); - goto sysfs_exit; - } - } - - return 0; - -sysfs_exit: - for (i--; i >= 0; i--) - device_remove_file(&spi->dev, &pdata->regs[i].attr); - -kfree_exit: - spi->dev.platform_data = NULL; - return ret; -} - -static int pcf2123_remove(struct spi_device *spi) -{ - struct pcf2123_plat_data *pdata = dev_get_platdata(&spi->dev); - int i; - - if (pdata) { - for (i = 0; i < 16; i++) - if (pdata->regs[i].name[0]) - device_remove_file(&spi->dev, - &pdata->regs[i].attr); - } + /* The PCF2123's alarm only has minute accuracy. Must add timer + * support to this driver to generate interrupts more than once + * per minute. + */ + rtc->uie_unsupported = 1; + rtc->ops = &pcf2123_rtc_ops; + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2099; + rtc->set_start_time = true; + + ret = rtc_register_device(rtc); + if (ret) + return ret; return 0; } #ifdef CONFIG_OF static const struct of_device_id pcf2123_dt_ids[] = { - { .compatible = "nxp,rtc-pcf2123", }, + { .compatible = "nxp,pcf2123", }, { .compatible = "microcrystal,rv2123", }, + /* Deprecated, do not use */ + { .compatible = "nxp,rtc-pcf2123", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, pcf2123_dt_ids); @@ -465,7 +458,6 @@ static struct spi_driver pcf2123_driver = { .of_match_table = of_match_ptr(pcf2123_dt_ids), }, .probe = pcf2123_probe, - .remove = pcf2123_remove, }; module_spi_driver(pcf2123_driver); diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 7cb786d76e3c..02b069caffd5 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,16 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C and SPI driver for the NXP PCF2127/29 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato <r.cerrato@til-technologies.fr> * + * Watchdog and tamper functions + * Author: Bruno Thomsen <bruno.thomsen@gmail.com> + * * based on the other drivers in this same directory. * * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.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> @@ -21,30 +21,67 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/regmap.h> +#include <linux/watchdog.h> + +/* Control register 1 */ +#define PCF2127_REG_CTRL1 0x00 +#define PCF2127_BIT_CTRL1_TSF1 BIT(4) +/* Control register 2 */ +#define PCF2127_REG_CTRL2 0x01 +#define PCF2127_BIT_CTRL2_TSIE BIT(2) +#define PCF2127_BIT_CTRL2_TSF2 BIT(5) +/* Control register 3 */ +#define PCF2127_REG_CTRL3 0x02 +#define PCF2127_BIT_CTRL3_BLIE BIT(0) +#define PCF2127_BIT_CTRL3_BIE BIT(1) +#define PCF2127_BIT_CTRL3_BLF BIT(2) +#define PCF2127_BIT_CTRL3_BF BIT(3) +#define PCF2127_BIT_CTRL3_BTSE BIT(4) +/* Time and date registers */ +#define PCF2127_REG_SC 0x03 +#define PCF2127_BIT_SC_OSF BIT(7) +#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 +/* Watchdog registers */ +#define PCF2127_REG_WD_CTL 0x10 +#define PCF2127_BIT_WD_CTL_TF0 BIT(0) +#define PCF2127_BIT_WD_CTL_TF1 BIT(1) +#define PCF2127_BIT_WD_CTL_CD0 BIT(6) +#define PCF2127_BIT_WD_CTL_CD1 BIT(7) +#define PCF2127_REG_WD_VAL 0x11 +/* Tamper timestamp registers */ +#define PCF2127_REG_TS_CTRL 0x12 +#define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) +#define PCF2127_BIT_TS_CTRL_TSM BIT(7) +#define PCF2127_REG_TS_SC 0x13 +#define PCF2127_REG_TS_MN 0x14 +#define PCF2127_REG_TS_HR 0x15 +#define PCF2127_REG_TS_DM 0x16 +#define PCF2127_REG_TS_MO 0x17 +#define PCF2127_REG_TS_YR 0x18 +/* + * RAM registers + * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is + * battery backed and can survive a power outage. + * PCF2129 doesn't have this feature. + */ +#define PCF2127_REG_RAM_ADDR_MSB 0x1A +#define PCF2127_REG_RAM_WRT_CMD 0x1C +#define PCF2127_REG_RAM_RD_CMD 0x1D -#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_CTRL3_BLF BIT(2) - -#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) - -/* the pcf2127 has 512 bytes nvmem, pcf2129 doesn't */ -#define PCF2127_REG_RAM_addr_MSB 0x1a -#define PCF2127_REG_RAM_wrt_cmd 0x1c -#define PCF2127_REG_RAM_rd_cmd 0x1d - -#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ +/* Watchdog timer value constants */ +#define PCF2127_WD_VAL_STOP 0 +#define PCF2127_WD_VAL_MIN 2 +#define PCF2127_WD_VAL_MAX 255 +#define PCF2127_WD_VAL_DEFAULT 60 struct pcf2127 { struct rtc_device *rtc; + struct watchdog_device wdd; struct regmap *regmap; }; @@ -57,30 +94,25 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) struct pcf2127 *pcf2127 = dev_get_drvdata(dev); unsigned char buf[10]; int ret; - int i; - - for (i = 0; i <= PCF2127_REG_CTRL3; i++) { - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1 + i, - (unsigned int *)(buf + i)); - if (ret) { - dev_err(dev, "%s: read error\n", __func__); - return ret; - } - } - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC, - (buf + PCF2127_REG_SC), - ARRAY_SIZE(buf) - PCF2127_REG_SC); + /* + * Avoid reading CTRL2 register as it causes WD_VAL register + * value to reset to 0 which means watchdog is stopped. + */ + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3, + (buf + PCF2127_REG_CTRL3), + ARRAY_SIZE(buf) - PCF2127_REG_CTRL3); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; } - if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF) + if (buf[PCF2127_REG_CTRL3] & PCF2127_BIT_CTRL3_BLF) dev_info(dev, "low voltage detected, check/replace RTC battery.\n"); - if (buf[PCF2127_REG_SC] & PCF2127_OSF) { + /* Clock integrity is not guaranteed when OSF flag is set. */ + if (buf[PCF2127_REG_SC] & PCF2127_BIT_SC_OSF) { /* * no need clear the flag here, * it will be cleared once the new date is saved @@ -91,14 +123,12 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) } dev_dbg(dev, - "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, " - "sec=%02x, min=%02x, hr=%02x, " + "%s: raw data is 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]); - + __func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC], + buf[PCF2127_REG_MN], buf[PCF2127_REG_HR], + buf[PCF2127_REG_DM], buf[PCF2127_REG_DW], + buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]); tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); @@ -169,7 +199,7 @@ static int pcf2127_rtc_ioctl(struct device *dev, if (ret) return ret; - touser = touser & PCF2127_REG_CTRL3_BLF ? 1 : 0; + touser = touser & PCF2127_BIT_CTRL3_BLF ? 1 : 0; if (copy_to_user((void __user *)arg, &touser, sizeof(int))) return -EFAULT; @@ -195,12 +225,12 @@ static int pcf2127_nvmem_read(void *priv, unsigned int offset, int ret; unsigned char offsetbuf[] = { offset >> 8, offset }; - ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_ADDR_MSB, offsetbuf, 2); if (ret) return ret; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_rd_cmd, + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_RD_CMD, val, bytes); return ret ?: bytes; @@ -213,17 +243,176 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset, int ret; unsigned char offsetbuf[] = { offset >> 8, offset }; - ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_ADDR_MSB, offsetbuf, 2); if (ret) return ret; - ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_wrt_cmd, + ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_WRT_CMD, val, bytes); return ret ?: bytes; } +/* watchdog driver */ + +static int pcf2127_wdt_ping(struct watchdog_device *wdd) +{ + struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); + + return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, wdd->timeout); +} + +/* + * Restart watchdog timer if feature is active. + * + * Note: Reading CTRL2 register causes watchdog to stop which is unfortunate, + * since register also contain control/status flags for other features. + * Always call this function after reading CTRL2 register. + */ +static int pcf2127_wdt_active_ping(struct watchdog_device *wdd) +{ + int ret = 0; + + if (watchdog_active(wdd)) { + ret = pcf2127_wdt_ping(wdd); + if (ret) + dev_err(wdd->parent, + "%s: watchdog restart failed, ret=%d\n", + __func__, ret); + } + + return ret; +} + +static int pcf2127_wdt_start(struct watchdog_device *wdd) +{ + return pcf2127_wdt_ping(wdd); +} + +static int pcf2127_wdt_stop(struct watchdog_device *wdd) +{ + struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); + + return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, + PCF2127_WD_VAL_STOP); +} + +static int pcf2127_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int new_timeout) +{ + dev_dbg(wdd->parent, "new watchdog timeout: %is (old: %is)\n", + new_timeout, wdd->timeout); + + wdd->timeout = new_timeout; + + return pcf2127_wdt_active_ping(wdd); +} + +static const struct watchdog_info pcf2127_wdt_info = { + .identity = "NXP PCF2127/PCF2129 Watchdog", + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, +}; + +static const struct watchdog_ops pcf2127_watchdog_ops = { + .owner = THIS_MODULE, + .start = pcf2127_wdt_start, + .stop = pcf2127_wdt_stop, + .ping = pcf2127_wdt_ping, + .set_timeout = pcf2127_wdt_set_timeout, +}; + +/* sysfs interface */ + +static ssize_t timestamp0_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); + int ret; + + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_TSF1, 0); + if (ret) { + dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret); + return ret; + } + + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, + PCF2127_BIT_CTRL2_TSF2, 0); + if (ret) { + dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); + return ret; + } + + ret = pcf2127_wdt_active_ping(&pcf2127->wdd); + if (ret) + return ret; + + return count; +}; + +static ssize_t timestamp0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); + struct rtc_time tm; + int ret; + unsigned char data[25]; + + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, + sizeof(data)); + if (ret) { + dev_err(dev, "%s: read error ret=%d\n", __func__, ret); + return ret; + } + + dev_dbg(dev, + "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, " + "ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", + __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], + data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC], + data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], + data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], + data[PCF2127_REG_TS_YR]); + + ret = pcf2127_wdt_active_ping(&pcf2127->wdd); + if (ret) + return ret; + + if (!(data[PCF2127_REG_CTRL1] & PCF2127_BIT_CTRL1_TSF1) && + !(data[PCF2127_REG_CTRL2] & PCF2127_BIT_CTRL2_TSF2)) + return 0; + + tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F); + tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F); + tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F); + tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F); + /* TS_MO register (month) value range: 1-12 */ + tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; + tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); + if (tm.tm_year < 70) + tm.tm_year += 100; /* assume we are in 1970...2069 */ + + ret = rtc_valid_tm(&tm); + if (ret) + return ret; + + return sprintf(buf, "%llu\n", + (unsigned long long)rtc_tm_to_time64(&tm)); +}; + +static DEVICE_ATTR_RW(timestamp0); + +static struct attribute *pcf2127_attrs[] = { + &dev_attr_timestamp0.attr, + NULL +}; + +static const struct attribute_group pcf2127_attr_group = { + .attrs = pcf2127_attrs, +}; + static int pcf2127_probe(struct device *dev, struct regmap *regmap, const char *name, bool has_nvmem) { @@ -240,11 +429,22 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, dev_set_drvdata(dev, pcf2127); - pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops, - THIS_MODULE); + pcf2127->rtc = devm_rtc_allocate_device(dev); if (IS_ERR(pcf2127->rtc)) return PTR_ERR(pcf2127->rtc); + pcf2127->rtc->ops = &pcf2127_rtc_ops; + + pcf2127->wdd.parent = dev; + pcf2127->wdd.info = &pcf2127_wdt_info; + pcf2127->wdd.ops = &pcf2127_watchdog_ops; + pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN; + pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX; + pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT; + pcf2127->wdd.min_hw_heartbeat_ms = 500; + + watchdog_set_drvdata(&pcf2127->wdd, pcf2127); + if (has_nvmem) { struct nvmem_config nvmem_cfg = { .priv = pcf2127, @@ -256,7 +456,84 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); } - return ret; + /* + * Watchdog timer enabled and reset pin /RST activated when timed out. + * Select 1Hz clock source for watchdog timer. + * Timer is not started until WD_VAL is loaded with a valid value. + * Note: Countdown timer disabled and not available. + */ + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL, + PCF2127_BIT_WD_CTL_CD1 | + PCF2127_BIT_WD_CTL_CD0 | + PCF2127_BIT_WD_CTL_TF1 | + PCF2127_BIT_WD_CTL_TF0, + PCF2127_BIT_WD_CTL_CD1 | + PCF2127_BIT_WD_CTL_CD0 | + PCF2127_BIT_WD_CTL_TF1); + if (ret) { + dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__); + return ret; + } + +#ifdef CONFIG_WATCHDOG + ret = devm_watchdog_register_device(dev, &pcf2127->wdd); + if (ret) + return ret; +#endif /* CONFIG_WATCHDOG */ + + /* + * Disable battery low/switch-over timestamp and interrupts. + * Clear battery interrupt flags which can block new trigger events. + * Note: This is the default chip behaviour but added to ensure + * correct tamper timestamp and interrupt function. + */ + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL3, + PCF2127_BIT_CTRL3_BTSE | + PCF2127_BIT_CTRL3_BF | + PCF2127_BIT_CTRL3_BIE | + PCF2127_BIT_CTRL3_BLIE, 0); + if (ret) { + dev_err(dev, "%s: interrupt config (ctrl3) failed\n", + __func__); + return ret; + } + + /* + * Enable timestamp function and store timestamp of first trigger + * event until TSF1 and TFS2 interrupt flags are cleared. + */ + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL, + PCF2127_BIT_TS_CTRL_TSOFF | + PCF2127_BIT_TS_CTRL_TSM, + PCF2127_BIT_TS_CTRL_TSM); + if (ret) { + dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n", + __func__); + return ret; + } + + /* + * Enable interrupt generation when TSF1 or TSF2 timestamp flags + * are set. Interrupt signal is an open-drain output and can be + * left floating if unused. + */ + ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, + PCF2127_BIT_CTRL2_TSIE, + PCF2127_BIT_CTRL2_TSIE); + if (ret) { + dev_err(dev, "%s: tamper detection config (ctrl2) failed\n", + __func__); + return ret; + } + + ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group); + if (ret) { + dev_err(dev, "%s: tamper sysfs registering failed\n", + __func__); + return ret; + } + + return rtc_register_device(pcf2127->rtc); } #ifdef CONFIG_OF diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index 0eb05b1d0b94..48951a16d65d 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* NXP PCF50633 RTC Driver * * (C) 2006-2008 by Openmoko, Inc. @@ -6,12 +7,6 @@ * * Broken down from monstrous PCF50633 driver mainly by * Harald Welte, Andy Green and Werner Almesberger - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/kernel.h> diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index f6ce63c443a0..1afa6d9fa9fb 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * An I2C driver for the PCF85063 RTC * Copyright 2014 Rose Technology @@ -5,16 +6,16 @@ * Author: Søren Andersen <san@rosetechnology.dk> * Maintainers: http://www.nslu2-linux.org/ * - * based on the other drivers in this same directory. - * - * 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. + * Copyright (C) 2019 Micro Crystal AG + * Author: Alexandre Belloni <alexandre.belloni@bootlin.com> */ #include <linux/i2c.h> #include <linux/bcd.h> #include <linux/rtc.h> #include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_wakeirq.h> +#include <linux/regmap.h> /* * Information for this driver was pulled from the following datasheets. @@ -24,61 +25,47 @@ * * PCF85063A -- Rev. 6 — 18 November 2015 * PCF85063TP -- Rev. 4 — 6 May 2015 -*/ + * + * https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8263-C7_App-Manual.pdf + * RV8263 -- Rev. 1.0 — January 2019 + */ #define PCF85063_REG_CTRL1 0x00 /* status */ #define PCF85063_REG_CTRL1_CAP_SEL BIT(0) #define PCF85063_REG_CTRL1_STOP BIT(5) -#define PCF85063_REG_SC 0x04 /* datetime */ -#define PCF85063_REG_SC_OS 0x80 - -static struct i2c_driver pcf85063_driver; - -static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) -{ - int rc; - u8 reg; +#define PCF85063_REG_CTRL2 0x01 +#define PCF85063_CTRL2_AF BIT(6) +#define PCF85063_CTRL2_AIE BIT(7) - rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); - if (rc < 0) { - dev_err(&client->dev, "Failing to stop the clock\n"); - return -EIO; - } +#define PCF85063_REG_OFFSET 0x02 +#define PCF85063_OFFSET_SIGN_BIT 6 /* 2's complement sign bit */ +#define PCF85063_OFFSET_MODE BIT(7) +#define PCF85063_OFFSET_STEP0 4340 +#define PCF85063_OFFSET_STEP1 4069 - /* stop the clock */ - reg = rc | PCF85063_REG_CTRL1_STOP; +#define PCF85063_REG_RAM 0x03 - rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg); - if (rc < 0) { - dev_err(&client->dev, "Failing to stop the clock\n"); - return -EIO; - } - - *ctrl1 = reg; - - return 0; -} - -static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1) -{ - int rc; +#define PCF85063_REG_SC 0x04 /* datetime */ +#define PCF85063_REG_SC_OS 0x80 - /* start the clock */ - ctrl1 &= ~PCF85063_REG_CTRL1_STOP; +#define PCF85063_REG_ALM_S 0x0b +#define PCF85063_AEN BIT(7) - rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1); - if (rc < 0) { - dev_err(&client->dev, "Failing to start the clock\n"); - return -EIO; - } +struct pcf85063_config { + struct regmap_config regmap; + unsigned has_alarms:1; + unsigned force_cap_7000:1; +}; - return 0; -} +struct pcf85063 { + struct rtc_device *rtc; + struct regmap *regmap; +}; static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); int rc; u8 regs[7]; @@ -88,16 +75,14 @@ static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm) * event, the access must be finished within one second. So, read all * time/date registers in one turn. */ - rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC, - sizeof(regs), regs); - if (rc != sizeof(regs)) { - dev_err(&client->dev, "date/time register read error\n"); - return -EIO; - } + rc = regmap_bulk_read(pcf85063->regmap, PCF85063_REG_SC, regs, + sizeof(regs)); + if (rc) + return rc; /* if the clock has lost its power it makes no sense to use its time */ if (regs[0] & PCF85063_REG_SC_OS) { - dev_warn(&client->dev, "Power loss detected, invalid time\n"); + dev_warn(&pcf85063->rtc->dev, "Power loss detected, invalid time\n"); return -EINVAL; } @@ -115,20 +100,18 @@ static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); int rc; u8 regs[7]; - u8 ctrl1; - - if ((tm->tm_year < 100) || (tm->tm_year > 199)) - return -EINVAL; /* * to accurately set the time, reset the divider chain and keep it in * reset state until all time/date registers are written */ - rc = pcf85063_stop_clock(client, &ctrl1); - if (rc != 0) + rc = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1, + PCF85063_REG_CTRL1_STOP, + PCF85063_REG_CTRL1_STOP); + if (rc) return rc; /* hours, minutes and seconds */ @@ -150,101 +133,351 @@ static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm) regs[6] = bin2bcd(tm->tm_year - 100); /* write all registers at once */ - rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC, - sizeof(regs), regs); - if (rc < 0) { - dev_err(&client->dev, "date/time register write error\n"); + rc = regmap_bulk_write(pcf85063->regmap, PCF85063_REG_SC, + regs, sizeof(regs)); + if (rc) return rc; - } /* * Write the control register as a separate action since the size of * the register space is different between the PCF85063TP and * PCF85063A devices. The rollover point can not be used. */ - rc = pcf85063_start_clock(client, ctrl1); - if (rc != 0) - return rc; + return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1, + PCF85063_REG_CTRL1_STOP, 0); +} + +static int pcf85063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); + u8 buf[4]; + unsigned int val; + int ret; + + ret = regmap_bulk_read(pcf85063->regmap, PCF85063_REG_ALM_S, + buf, sizeof(buf)); + if (ret) + return ret; + + alrm->time.tm_sec = bcd2bin(buf[0]); + alrm->time.tm_min = bcd2bin(buf[1]); + alrm->time.tm_hour = bcd2bin(buf[2]); + alrm->time.tm_mday = bcd2bin(buf[3]); + + ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &val); + if (ret) + return ret; + + alrm->enabled = !!(val & PCF85063_CTRL2_AIE); return 0; } +static int pcf85063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); + u8 buf[5]; + int ret; + + buf[0] = bin2bcd(alrm->time.tm_sec); + buf[1] = bin2bcd(alrm->time.tm_min); + buf[2] = bin2bcd(alrm->time.tm_hour); + buf[3] = bin2bcd(alrm->time.tm_mday); + buf[4] = PCF85063_AEN; /* Do not match on week day */ + + ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2, + PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF, 0); + if (ret) + return ret; + + ret = regmap_bulk_write(pcf85063->regmap, PCF85063_REG_ALM_S, + buf, sizeof(buf)); + if (ret) + return ret; + + return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2, + PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF, + alrm->enabled ? PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF : PCF85063_CTRL2_AF); +} + +static int pcf85063_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); + + return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2, + PCF85063_CTRL2_AIE, + enabled ? PCF85063_CTRL2_AIE : 0); +} + +static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id) +{ + struct pcf85063 *pcf85063 = dev_id; + unsigned int val; + int err; + + err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &val); + if (err) + return IRQ_NONE; + + if (val & PCF85063_CTRL2_AF) { + rtc_update_irq(pcf85063->rtc, 1, RTC_IRQF | RTC_AF); + regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2, + PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF, + 0); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int pcf85063_read_offset(struct device *dev, long *offset) +{ + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); + long val; + u32 reg; + int ret; + + ret = regmap_read(pcf85063->regmap, PCF85063_REG_OFFSET, ®); + if (ret < 0) + return ret; + + val = sign_extend32(reg & ~PCF85063_OFFSET_MODE, + PCF85063_OFFSET_SIGN_BIT); + + if (reg & PCF85063_OFFSET_MODE) + *offset = val * PCF85063_OFFSET_STEP1; + else + *offset = val * PCF85063_OFFSET_STEP0; + + return 0; +} + +static int pcf85063_set_offset(struct device *dev, long offset) +{ + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); + s8 mode0, mode1, reg; + unsigned int error0, error1; + + if (offset > PCF85063_OFFSET_STEP0 * 63) + return -ERANGE; + if (offset < PCF85063_OFFSET_STEP0 * -64) + return -ERANGE; + + mode0 = DIV_ROUND_CLOSEST(offset, PCF85063_OFFSET_STEP0); + mode1 = DIV_ROUND_CLOSEST(offset, PCF85063_OFFSET_STEP1); + + error0 = abs(offset - (mode0 * PCF85063_OFFSET_STEP0)); + error1 = abs(offset - (mode1 * PCF85063_OFFSET_STEP1)); + if (mode1 > 63 || mode1 < -64 || error0 < error1) + reg = mode0 & ~PCF85063_OFFSET_MODE; + else + reg = mode1 | PCF85063_OFFSET_MODE; + + return regmap_write(pcf85063->regmap, PCF85063_REG_OFFSET, reg); +} + +static int pcf85063_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct pcf85063 *pcf85063 = dev_get_drvdata(dev); + int status, ret = 0; + + switch (cmd) { + case RTC_VL_READ: + ret = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &status); + if (ret < 0) + return ret; + + if (status & PCF85063_REG_SC_OS) + dev_warn(&pcf85063->rtc->dev, "Voltage low, data loss detected.\n"); + + status &= PCF85063_REG_SC_OS; + + if (copy_to_user((void __user *)arg, &status, sizeof(int))) + return -EFAULT; + + return 0; + + case RTC_VL_CLR: + ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_SC, + PCF85063_REG_SC_OS, 0); + + return ret; + + default: + return -ENOIOCTLCMD; + } +} + static const struct rtc_class_ops pcf85063_rtc_ops = { .read_time = pcf85063_rtc_read_time, - .set_time = pcf85063_rtc_set_time + .set_time = pcf85063_rtc_set_time, + .read_offset = pcf85063_read_offset, + .set_offset = pcf85063_set_offset, + .ioctl = pcf85063_ioctl, +}; + +static const struct rtc_class_ops pcf85063_rtc_ops_alarm = { + .read_time = pcf85063_rtc_read_time, + .set_time = pcf85063_rtc_set_time, + .read_offset = pcf85063_read_offset, + .set_offset = pcf85063_set_offset, + .read_alarm = pcf85063_rtc_read_alarm, + .set_alarm = pcf85063_rtc_set_alarm, + .alarm_irq_enable = pcf85063_rtc_alarm_irq_enable, + .ioctl = pcf85063_ioctl, }; -static int pcf85063_load_capacitance(struct i2c_client *client) +static int pcf85063_nvmem_read(void *priv, unsigned int offset, + void *val, size_t bytes) { - u32 load; - int rc; - u8 reg; + return regmap_read(priv, PCF85063_REG_RAM, val); +} - rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); - if (rc < 0) - return rc; +static int pcf85063_nvmem_write(void *priv, unsigned int offset, + void *val, size_t bytes) +{ + return regmap_write(priv, PCF85063_REG_RAM, *(u8 *)val); +} - reg = rc; - load = 7000; - of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads", - &load); +static int pcf85063_load_capacitance(struct pcf85063 *pcf85063, + const struct device_node *np, + unsigned int force_cap) +{ + u32 load = 7000; + u8 reg = 0; + + if (force_cap) + load = force_cap; + else + of_property_read_u32(np, "quartz-load-femtofarads", &load); switch (load) { default: - dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000", + dev_warn(&pcf85063->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000", load); /* fall through */ case 7000: - reg &= ~PCF85063_REG_CTRL1_CAP_SEL; break; case 12500: - reg |= PCF85063_REG_CTRL1_CAP_SEL; + reg = PCF85063_REG_CTRL1_CAP_SEL; break; } - rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg); - - return rc; + return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1, + PCF85063_REG_CTRL1_CAP_SEL, reg); } -static int pcf85063_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct pcf85063_config pcf85063a_config = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, + }, + .has_alarms = 1, +}; + +static const struct pcf85063_config pcf85063tp_config = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0a, + }, +}; + +static const struct pcf85063_config rv8263_config = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, + }, + .has_alarms = 1, + .force_cap_7000 = 1, +}; + +static int pcf85063_probe(struct i2c_client *client) { - struct rtc_device *rtc; + struct pcf85063 *pcf85063; + unsigned int tmp; int err; + const struct pcf85063_config *config = &pcf85063tp_config; + const void *data = of_device_get_match_data(&client->dev); + struct nvmem_config nvmem_cfg = { + .name = "pcf85063_nvram", + .reg_read = pcf85063_nvmem_read, + .reg_write = pcf85063_nvmem_write, + .type = NVMEM_TYPE_BATTERY_BACKED, + .size = 1, + }; dev_dbg(&client->dev, "%s\n", __func__); - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; + pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063), + GFP_KERNEL); + if (!pcf85063) + return -ENOMEM; + + if (data) + config = data; + + pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap); + if (IS_ERR(pcf85063->regmap)) + return PTR_ERR(pcf85063->regmap); - err = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); - if (err < 0) { + i2c_set_clientdata(client, pcf85063); + + err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp); + if (err) { dev_err(&client->dev, "RTC chip is not present\n"); return err; } - err = pcf85063_load_capacitance(client); + pcf85063->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(pcf85063->rtc)) + return PTR_ERR(pcf85063->rtc); + + err = pcf85063_load_capacitance(pcf85063, client->dev.of_node, + config->force_cap_7000 ? 7000 : 0); if (err < 0) dev_warn(&client->dev, "failed to set xtal load capacitance: %d", err); - rtc = devm_rtc_device_register(&client->dev, - pcf85063_driver.driver.name, - &pcf85063_rtc_ops, THIS_MODULE); + pcf85063->rtc->ops = &pcf85063_rtc_ops; + pcf85063->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + pcf85063->rtc->range_max = RTC_TIMESTAMP_END_2099; + pcf85063->rtc->uie_unsupported = 1; + + if (config->has_alarms && client->irq > 0) { + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, pcf85063_rtc_handle_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "pcf85063", pcf85063); + if (err) { + dev_warn(&pcf85063->rtc->dev, + "unable to request IRQ, alarms disabled\n"); + } else { + pcf85063->rtc->ops = &pcf85063_rtc_ops_alarm; + device_init_wakeup(&client->dev, true); + err = dev_pm_set_wake_irq(&client->dev, client->irq); + if (err) + dev_err(&pcf85063->rtc->dev, + "failed to enable irq wake\n"); + } + } + + nvmem_cfg.priv = pcf85063->regmap; + rtc_nvmem_register(pcf85063->rtc, &nvmem_cfg); - return PTR_ERR_OR_ZERO(rtc); + return rtc_register_device(pcf85063->rtc); } -static const struct i2c_device_id pcf85063_id[] = { - { "pcf85063", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pcf85063_id); - #ifdef CONFIG_OF static const struct of_device_id pcf85063_of_match[] = { - { .compatible = "nxp,pcf85063" }, + { .compatible = "nxp,pcf85063", .data = &pcf85063tp_config }, + { .compatible = "nxp,pcf85063tp", .data = &pcf85063tp_config }, + { .compatible = "nxp,pcf85063a", .data = &pcf85063a_config }, + { .compatible = "microcrystal,rv8263", .data = &rv8263_config }, {} }; MODULE_DEVICE_TABLE(of, pcf85063_of_match); @@ -255,8 +488,7 @@ static struct i2c_driver pcf85063_driver = { .name = "rtc-pcf85063", .of_match_table = of_match_ptr(pcf85063_of_match), }, - .probe = pcf85063_probe, - .id_table = pcf85063_id, + .probe_new = pcf85063_probe, }; module_i2c_driver(pcf85063_driver); diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index b5c61a70b5df..2f435e533b10 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 Avionic Design GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index a3988079f60a..3450d615974d 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -1,15 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/rtc/rtc-pcf85363.c * * Driver for NXP PCF85363 real-time clock. * * Copyright (C) 2017 Eric Nelson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Based loosely on rtc-8583 by Russell King, Wolfram Sang and Juergen Beisert */ #include <linux/module.h> #include <linux/i2c.h> @@ -112,10 +107,7 @@ #define NVRAM_SIZE 0x40 -static struct i2c_driver pcf85363_driver; - struct pcf85363 { - struct device *dev; struct rtc_device *rtc; struct regmap *regmap; }; @@ -174,7 +166,12 @@ static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[DT_YEARS] = bin2bcd(tm->tm_year % 100); ret = regmap_bulk_write(pcf85363->regmap, CTRL_STOP_EN, - tmp, sizeof(tmp)); + tmp, 2); + if (ret) + return ret; + + ret = regmap_bulk_write(pcf85363->regmap, DT_100THS, + buf, sizeof(tmp) - 2); if (ret) return ret; @@ -386,9 +383,6 @@ static int pcf85363_probe(struct i2c_client *client, if (data) config = data; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; - pcf85363 = devm_kzalloc(&client->dev, sizeof(struct pcf85363), GFP_KERNEL); if (!pcf85363) @@ -400,20 +394,21 @@ static int pcf85363_probe(struct i2c_client *client, return PTR_ERR(pcf85363->regmap); } - pcf85363->dev = &client->dev; i2c_set_clientdata(client, pcf85363); - pcf85363->rtc = devm_rtc_allocate_device(pcf85363->dev); + pcf85363->rtc = devm_rtc_allocate_device(&client->dev); if (IS_ERR(pcf85363->rtc)) return PTR_ERR(pcf85363->rtc); pcf85363->rtc->ops = &rtc_ops; + pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; if (client->irq > 0) { regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, PIN_IO_INTA_OUT, PIN_IO_INTAPM); - ret = devm_request_threaded_irq(pcf85363->dev, client->irq, + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf85363_rtc_handle_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "pcf85363", client); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 3efc86c25d27..24baa4767b11 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for the Philips PCF8563 RTC * Copyright 2005-06 Tower Technologies @@ -8,10 +9,6 @@ * based on the other drivers in this same directory. * * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.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/clk-provider.h> @@ -199,8 +196,9 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id) * In the routines that deal directly with the pcf8563 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. */ -static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) +static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) { + struct i2c_client *client = to_i2c_client(dev); struct pcf8563 *pcf8563 = i2c_get_clientdata(client); unsigned char buf[9]; int err; @@ -231,9 +229,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F); tm->tm_wday = buf[PCF8563_REG_DW] & 0x07; tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]); - if (tm->tm_year < 70) - tm->tm_year += 100; /* assume we are in 1970...2069 */ + tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]) + 100; /* detect the polarity heuristically. see note above. */ pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ? (tm->tm_year >= 100) : (tm->tm_year < 100); @@ -247,8 +243,9 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) return 0; } -static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) +static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) { + struct i2c_client *client = to_i2c_client(dev); struct pcf8563 *pcf8563 = i2c_get_clientdata(client); unsigned char buf[9]; @@ -269,7 +266,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1); /* year and century */ - buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100); + buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year - 100); if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100)) buf[PCF8563_REG_MO] |= PCF8563_MO_C; @@ -302,8 +299,8 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long * because of the cached voltage_low value but do it * anyway for consistency. */ - if (pcf8563_get_datetime(to_i2c_client(dev), &tm)) - pcf8563_set_datetime(to_i2c_client(dev), &tm); + if (pcf8563_rtc_read_time(dev, &tm)) + pcf8563_rtc_set_time(dev, &tm); /* Clear the cached value. */ pcf8563->voltage_low = 0; @@ -317,16 +314,6 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long #define pcf8563_rtc_ioctl NULL #endif -static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - return pcf8563_get_datetime(to_i2c_client(dev), tm); -} - -static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - return pcf8563_set_datetime(to_i2c_client(dev), tm); -} - static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) { struct i2c_client *client = to_i2c_client(dev); @@ -563,7 +550,6 @@ static int pcf8563_probe(struct i2c_client *client, struct pcf8563 *pcf8563; int err; unsigned char buf; - unsigned char alm_pending; dev_dbg(&client->dev, "%s\n", __func__); @@ -587,42 +573,46 @@ static int pcf8563_probe(struct i2c_client *client, return err; } - err = pcf8563_get_alarm_mode(client, NULL, &alm_pending); - if (err) { - dev_err(&client->dev, "%s: read error\n", __func__); + /* Clear flags and disable interrupts */ + buf = 0; + err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); + if (err < 0) { + dev_err(&client->dev, "%s: write error\n", __func__); return err; } - if (alm_pending) - pcf8563_set_alarm_mode(client, 0); - - pcf8563->rtc = devm_rtc_device_register(&client->dev, - pcf8563_driver.driver.name, - &pcf8563_rtc_ops, THIS_MODULE); + pcf8563->rtc = devm_rtc_allocate_device(&client->dev); if (IS_ERR(pcf8563->rtc)) return PTR_ERR(pcf8563->rtc); + pcf8563->rtc->ops = &pcf8563_rtc_ops; + /* the pcf8563 alarm only supports a minute accuracy */ + pcf8563->rtc->uie_unsupported = 1; + pcf8563->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + pcf8563->rtc->range_max = RTC_TIMESTAMP_END_2099; + pcf8563->rtc->set_start_time = true; + if (client->irq > 0) { err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8563_irq, - IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING, + IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, pcf8563_driver.driver.name, client); if (err) { dev_err(&client->dev, "unable to request IRQ %d\n", client->irq); return err; } - } + err = rtc_register_device(pcf8563->rtc); + if (err) + return err; + #ifdef CONFIG_COMMON_CLK /* register clk in common clk framework */ pcf8563_clkout_register_clk(pcf8563); #endif - /* the pcf8563 alarm only supports a minute accuracy */ - pcf8563->rtc->uie_unsupported = 1; - return 0; } @@ -636,6 +626,8 @@ MODULE_DEVICE_TABLE(i2c, pcf8563_id); #ifdef CONFIG_OF static const struct of_device_id pcf8563_of_match[] = { { .compatible = "nxp,pcf8563" }, + { .compatible = "epson,rtc8564" }, + { .compatible = "microcrystal,rv8564" }, {} }; MODULE_DEVICE_TABLE(of, pcf8563_of_match); diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 7ca9e8871d77..c80ca20e5d8d 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/rtc/rtc-pcf8583.c * * Copyright (C) 2000 Russell King * Copyright (C) 2008 Wolfram Sang & Juergen Beisert, Pengutronix * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for PCF8583 RTC & RAM chip * * Converted to the generic RTC susbsystem by G. Liakhovetski (2006) diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c index 1c4de6e90da0..17653ed52ebb 100644 --- a/drivers/rtc/rtc-pic32.c +++ b/drivers/rtc/rtc-pic32.c @@ -308,10 +308,8 @@ static int pic32_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pdata); pdata->alarm_irq = platform_get_irq(pdev, 0); - if (pdata->alarm_irq < 0) { - dev_err(&pdev->dev, "no irq for alarm\n"); + if (pdata->alarm_irq < 0) return pdata->alarm_irq; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pdata->reg_base = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index 343bb6ed1783..d4a5f8afafbc 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/rtc/rtc-pl030.c * * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 30943d200c5e..180caebbd355 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * drivers/rtc/rtc-pl031.c * @@ -9,11 +10,6 @@ * * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> * Copyright 2010 (c) ST-Ericsson AB - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/module.h> #include <linux/rtc.h> diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index cda020700744..f5a30e0f16c2 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -1,13 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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/of.h> #include <linux/module.h> @@ -476,10 +468,8 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) } 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"); + if (rtc_dd->rtc_alarm_irq < 0) return -ENXIO; - } rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node, "allow-set-time"); diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c index 347288bff438..f0336d691e6c 100644 --- a/drivers/rtc/rtc-ps3.c +++ b/drivers/rtc/rtc-ps3.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * PS3 RTC Driver * * Copyright 2009 Sony Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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/kernel.h> @@ -40,16 +28,13 @@ static u64 read_rtc(void) static int ps3_get_time(struct device *dev, struct rtc_time *tm) { - rtc_time_to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm); + rtc_time64_to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm); return 0; } static int ps3_set_time(struct device *dev, struct rtc_time *tm) { - unsigned long now; - - rtc_tm_to_time(tm, &now); - ps3_os_area_set_rtc_diff(now - read_rtc()); + ps3_os_area_set_rtc_diff(rtc_tm_to_time64(tm) - read_rtc()); return 0; } @@ -62,13 +47,16 @@ static int __init ps3_rtc_probe(struct platform_device *dev) { struct rtc_device *rtc; - rtc = devm_rtc_device_register(&dev->dev, "rtc-ps3", &ps3_rtc_ops, - THIS_MODULE); + rtc = devm_rtc_allocate_device(&dev->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); + rtc->ops = &ps3_rtc_ops; + rtc->range_max = U64_MAX; + platform_set_drvdata(dev, rtc); - return 0; + + return rtc_register_device(rtc); } static struct platform_driver ps3_rtc_driver = { diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index f77ef282f013..89ff713163dd 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC driver code specific to PKUnity SoC and UniCore ISA * * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> * Copyright (C) 2001-2010 Guan Xuetao - * - * 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> @@ -189,16 +186,12 @@ static int puv3_rtc_probe(struct platform_device *pdev) /* find the IRQs */ puv3_rtc_tickno = platform_get_irq(pdev, 1); - if (puv3_rtc_tickno < 0) { - dev_err(&pdev->dev, "no irq for rtc tick\n"); + if (puv3_rtc_tickno < 0) return -ENOENT; - } puv3_rtc_alarmno = platform_get_irq(pdev, 0); - if (puv3_rtc_alarmno < 0) { - dev_err(&pdev->dev, "no irq for alarm\n"); + if (puv3_rtc_alarmno < 0) return -ENOENT; - } dev_dbg(&pdev->dev, "PKUnity_rtc: tick irq %d, alarm irq %d\n", puv3_rtc_tickno, puv3_rtc_alarmno); @@ -242,10 +235,8 @@ static int puv3_rtc_probe(struct platform_device *pdev) /* register RTC and exit */ rtc->ops = &puv3_rtcops; ret = rtc_register_device(rtc); - if (ret) { - dev_err(&pdev->dev, "cannot attach rtc\n"); + if (ret) goto err_nortc; - } /* platform setup code should have handled this; sigh */ if (!device_can_wakeup(&pdev->dev)) diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index e1887b86fdc7..d2f1d8f754bf 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -1,22 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Real Time Clock interface for XScale PXA27x and PXA3xx * * Copyright (C) 2008 Robert Jarzmik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <linux/init.h> @@ -145,8 +131,7 @@ static void rtsr_set_bits(struct pxa_rtc *pxa_rtc, u32 mask) static irqreturn_t pxa_rtc_irq(int irq, void *dev_id) { - struct platform_device *pdev = to_platform_device(dev_id); - struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); + struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev_id); u32 rtsr; unsigned long events = 0; @@ -339,15 +324,11 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) } sa1100_rtc->irq_1hz = platform_get_irq(pdev, 0); - if (sa1100_rtc->irq_1hz < 0) { - dev_err(dev, "No 1Hz IRQ resource defined\n"); + if (sa1100_rtc->irq_1hz < 0) return -ENXIO; - } sa1100_rtc->irq_alarm = platform_get_irq(pdev, 1); - if (sa1100_rtc->irq_alarm < 0) { - dev_err(dev, "No alarm IRQ resource defined\n"); + if (sa1100_rtc->irq_alarm < 0) return -ENXIO; - } pxa_rtc->base = devm_ioremap(dev, pxa_rtc->ress->start, resource_size(pxa_rtc->ress)); diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c index 1943c8151152..2498278853af 100644 --- a/drivers/rtc/rtc-r7301.c +++ b/drivers/rtc/rtc-r7301.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EPSON TOYOCOM RTC-7301SF/DG Driver * diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index a39ccd1cf6e8..84f0d25259ae 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Epson RTC-9701JE * @@ -7,10 +8,6 @@ * * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c index 68ce77414bdc..18684a7026c4 100644 --- a/drivers/rtc/rtc-rc5t583.c +++ b/drivers/rtc/rtc-rc5t583.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-rc5t583.c -- RICOH RC5T583 Real Time Clock * * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * Author: Venu Byravarasu <vbyravarasu@nvidia.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + */ #include <linux/kernel.h> #include <linux/errno.h> diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c index 1fb864d4ef83..c0334c602e88 100644 --- a/drivers/rtc/rtc-rk808.c +++ b/drivers/rtc/rtc-rk808.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RTC driver for Rockchip RK808 * @@ -5,15 +6,6 @@ * * Author: Chris Zhong <zyw@rock-chips.com> * Author: Zhang Qing <zhangqing@rock-chips.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include <linux/module.h> @@ -50,9 +42,18 @@ #define NUM_TIME_REGS (RK808_WEEKS_REG - RK808_SECONDS_REG + 1) #define NUM_ALARM_REGS (RK808_ALARM_YEARS_REG - RK808_ALARM_SECONDS_REG + 1) +struct rk_rtc_compat_reg { + unsigned int ctrl_reg; + unsigned int status_reg; + unsigned int alarm_seconds_reg; + unsigned int int_reg; + unsigned int seconds_reg; +}; + struct rk808_rtc { struct rk808 *rk808; struct rtc_device *rtc; + struct rk_rtc_compat_reg *creg; int irq; }; @@ -101,7 +102,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) int ret; /* Force an update of the shadowed registers right now */ - ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG, + ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg, BIT_RTC_CTRL_REG_RTC_GET_TIME, BIT_RTC_CTRL_REG_RTC_GET_TIME); if (ret) { @@ -115,7 +116,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) * 32khz. If we clear the GET_TIME bit here, the time of i2c transfer * certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency. */ - ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG, + ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg, BIT_RTC_CTRL_REG_RTC_GET_TIME, 0); if (ret) { @@ -123,7 +124,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) return ret; } - ret = regmap_bulk_read(rk808->regmap, RK808_SECONDS_REG, + ret = regmap_bulk_read(rk808->regmap, rk808_rtc->creg->seconds_reg, rtc_data, NUM_TIME_REGS); if (ret) { dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret); @@ -162,7 +163,7 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc_data[6] = bin2bcd(tm->tm_wday); /* Stop RTC while updating the RTC registers */ - ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG, + ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg, BIT_RTC_CTRL_REG_STOP_RTC_M, BIT_RTC_CTRL_REG_STOP_RTC_M); if (ret) { @@ -170,14 +171,14 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) return ret; } - ret = regmap_bulk_write(rk808->regmap, RK808_SECONDS_REG, + ret = regmap_bulk_write(rk808->regmap, rk808_rtc->creg->seconds_reg, rtc_data, NUM_TIME_REGS); if (ret) { dev_err(dev, "Failed to bull write rtc_data: %d\n", ret); return ret; } /* Start RTC again */ - ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG, + ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg, BIT_RTC_CTRL_REG_STOP_RTC_M, 0); if (ret) { dev_err(dev, "Failed to update RTC control: %d\n", ret); @@ -195,8 +196,13 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) uint32_t int_reg; int ret; - ret = regmap_bulk_read(rk808->regmap, RK808_ALARM_SECONDS_REG, + ret = regmap_bulk_read(rk808->regmap, + rk808_rtc->creg->alarm_seconds_reg, alrm_data, NUM_ALARM_REGS); + if (ret) { + dev_err(dev, "Failed to read RTC alarm date REG: %d\n", ret); + return ret; + } alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK); alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK); @@ -206,7 +212,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100; rockchip_to_gregorian(&alrm->time); - ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg); + ret = regmap_read(rk808->regmap, rk808_rtc->creg->int_reg, &int_reg); if (ret) { dev_err(dev, "Failed to read RTC INT REG: %d\n", ret); return ret; @@ -225,7 +231,7 @@ static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc) struct rk808 *rk808 = rk808_rtc->rk808; int ret; - ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG, + ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, 0); return ret; @@ -236,7 +242,7 @@ static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc) struct rk808 *rk808 = rk808_rtc->rk808; int ret; - ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG, + ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); @@ -266,7 +272,8 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1); alrm_data[5] = bin2bcd(alrm->time.tm_year - 100); - ret = regmap_bulk_write(rk808->regmap, RK808_ALARM_SECONDS_REG, + ret = regmap_bulk_write(rk808->regmap, + rk808_rtc->creg->alarm_seconds_reg, alrm_data, NUM_ALARM_REGS); if (ret) { dev_err(dev, "Failed to bulk write: %d\n", ret); @@ -310,7 +317,7 @@ static irqreturn_t rk808_alarm_irq(int irq, void *data) struct i2c_client *client = rk808->i2c; int ret; - ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG, + ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg, RTC_STATUS_MASK); if (ret) { dev_err(&client->dev, @@ -336,8 +343,7 @@ static const struct rtc_class_ops rk808_rtc_ops = { /* Turn off the alarm if it should not be a wake source. */ static int rk808_rtc_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct rk808_rtc *rk808_rtc = dev_get_drvdata(&pdev->dev); + struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) enable_irq_wake(rk808_rtc->irq); @@ -350,8 +356,7 @@ static int rk808_rtc_suspend(struct device *dev) */ static int rk808_rtc_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct rk808_rtc *rk808_rtc = dev_get_drvdata(&pdev->dev); + struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) disable_irq_wake(rk808_rtc->irq); @@ -363,6 +368,22 @@ static int rk808_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(rk808_rtc_pm_ops, rk808_rtc_suspend, rk808_rtc_resume); +static struct rk_rtc_compat_reg rk808_creg = { + .ctrl_reg = RK808_RTC_CTRL_REG, + .status_reg = RK808_RTC_STATUS_REG, + .alarm_seconds_reg = RK808_ALARM_SECONDS_REG, + .int_reg = RK808_RTC_INT_REG, + .seconds_reg = RK808_SECONDS_REG, +}; + +static struct rk_rtc_compat_reg rk817_creg = { + .ctrl_reg = RK817_RTC_CTRL_REG, + .status_reg = RK817_RTC_STATUS_REG, + .alarm_seconds_reg = RK817_ALARM_SECONDS_REG, + .int_reg = RK817_RTC_INT_REG, + .seconds_reg = RK817_SECONDS_REG, +}; + static int rk808_rtc_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); @@ -373,11 +394,20 @@ static int rk808_rtc_probe(struct platform_device *pdev) if (rk808_rtc == NULL) return -ENOMEM; + switch (rk808->variant) { + case RK809_ID: + case RK817_ID: + rk808_rtc->creg = &rk817_creg; + break; + default: + rk808_rtc->creg = &rk808_creg; + break; + } platform_set_drvdata(pdev, rk808_rtc); rk808_rtc->rk808 = rk808; /* start rtc running by default, and use shadowed timer. */ - ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG, + ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg, BIT_RTC_CTRL_REG_STOP_RTC_M | BIT_RTC_CTRL_REG_RTC_READSEL_M, BIT_RTC_CTRL_REG_RTC_READSEL_M); @@ -387,7 +417,7 @@ static int rk808_rtc_probe(struct platform_device *pdev) return ret; } - ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG, + ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg, RTC_STATUS_MASK); if (ret) { dev_err(&pdev->dev, @@ -404,12 +434,8 @@ static int rk808_rtc_probe(struct platform_device *pdev) rk808_rtc->rtc->ops = &rk808_rtc_ops; rk808_rtc->irq = platform_get_irq(pdev, 0); - if (rk808_rtc->irq < 0) { - if (rk808_rtc->irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "Wake up is not possible as irq = %d\n", - rk808_rtc->irq); + if (rk808_rtc->irq < 0) return rk808_rtc->irq; - } /* request alarm irq of rk808 */ ret = devm_request_threaded_irq(&pdev->dev, rk808_rtc->irq, NULL, diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index f1c160fe7d37..8776eadbdd3a 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Ricoh RP5C01 RTC Driver * diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index 6582be707bd0..47c13678449e 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * A SPI driver for the Ricoh RS5C348 RTC * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> * - * 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. - * * The board specific init code should provide characteristics of this * device: * Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 66a473a3c3fe..3bd6eaa0dcf6 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs * * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> * Copyright (C) 2006 Tower Technologies * Copyright (C) 2008 Paul Mundt - * - * 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> diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 06884ebb7a61..2b316661a578 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -639,9 +639,8 @@ static int rv3028_probe(struct i2c_client *client) dev_warn(&client->dev, "An alarm may have been missed.\n"); rv3028->rtc = devm_rtc_allocate_device(&client->dev); - if (IS_ERR(rv3028->rtc)) { + if (IS_ERR(rv3028->rtc)) return PTR_ERR(rv3028->rtc); - } if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 3d6174eb32f6..4cdf6588e1d9 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Micro Crystal RV-3029 / RV-3049 rtc class driver * @@ -5,11 +6,6 @@ * Michael Buesch <m@bues.ch> * * based on previously existing rtc class drivers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/module.h> @@ -282,13 +278,13 @@ static int rv3029_eeprom_read(struct device *dev, u8 reg, static int rv3029_eeprom_write(struct device *dev, u8 reg, u8 const buf[], size_t len) { - int ret; + int ret, err; size_t i; u8 tmp; - ret = rv3029_eeprom_enter(dev); - if (ret < 0) - return ret; + err = rv3029_eeprom_enter(dev); + if (err < 0) + return err; for (i = 0; i < len; i++, reg++) { ret = rv3029_read_regs(dev, reg, &tmp, 1); @@ -304,11 +300,11 @@ static int rv3029_eeprom_write(struct device *dev, u8 reg, break; } - ret = rv3029_eeprom_exit(dev); - if (ret < 0) - return ret; + err = rv3029_eeprom_exit(dev); + if (err < 0) + return err; - return 0; + return ret; } static int rv3029_eeprom_update_bits(struct device *dev, diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 0b102c3cf5a4..4960f0a2b249 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -517,7 +517,7 @@ static int rx8900_trickle_charger_init(struct rv8803_data *rv8803) static int rv8803_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct rv8803_data *rv8803; int err, flags; struct nvmem_config nvmem_cfg = { @@ -564,9 +564,8 @@ static int rv8803_probe(struct i2c_client *client, dev_warn(&client->dev, "An alarm maybe have been missed.\n"); rv8803->rtc = devm_rtc_allocate_device(&client->dev); - if (IS_ERR(rv8803->rtc)) { + if (IS_ERR(rv8803->rtc)) return PTR_ERR(rv8803->rtc); - } if (client->irq > 0) { err = devm_request_threaded_irq(&client->dev, client->irq, diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c index c59a218bdd87..c092e0452347 100644 --- a/drivers/rtc/rtc-rx4581.c +++ b/drivers/rtc/rtc-rx4581.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-rx4581.c * * written by Torben Hohn <torbenh@linutronix.de> @@ -8,10 +9,6 @@ * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for MAX6902 spi RTC * * and based on: @@ -22,13 +19,8 @@ * Author: Martyn Welch <martyn.welch@ge.com> * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) * Copyright 2005-06 Tower Technologies - * */ #include <linux/module.h> diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 5899ca368d59..71e20a6bd387 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -21,6 +21,8 @@ #include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/rtc.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/spi/spi.h> /* RX-6110 Register definitions */ @@ -379,9 +381,16 @@ static const struct spi_device_id rx6110_id[] = { }; MODULE_DEVICE_TABLE(spi, rx6110_id); +static const struct of_device_id rx6110_spi_of_match[] = { + { .compatible = "epson,rx6110" }, + { }, +}; +MODULE_DEVICE_TABLE(of, rx6110_spi_of_match); + static struct spi_driver rx6110_driver = { .driver = { .name = RX6110_DRIVER_NAME, + .of_match_table = of_match_ptr(rx6110_spi_of_match), }, .probe = rx6110_probe, .remove = rx6110_remove, diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 7ddc22eb5b0f..8102469e27c0 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for the Epson RTC module RX-8010 SJ * * Copyright(C) Timesys Corporation 2015 * Copyright(C) General Electric Company 2015 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/bcd.h> @@ -437,7 +433,7 @@ static struct rtc_class_ops rx8010_rtc_ops = { static int rx8010_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct rx8010_data *rx8010; int err = 0; diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 41de38acc570..b9bda10589e0 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for Epson's RTC module RX-8025 SA/NB * @@ -13,10 +14,6 @@ * Code cleanup by Sergei Poselenov, <sposelenov@emcraft.com> * Converted to new style by Wolfgang Grandegger <wg@grandegger.com> * Alarm and periodic interrupt added by Dmitry Rakhchev <rda@emcraft.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/bcd.h> #include <linux/bitops.h> @@ -311,7 +308,7 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12 + (ald[1] & 0x20 ? 12 : 0); - dev_dbg(dev, "%s: date: %ptRr\n", __func__, t); + dev_dbg(dev, "%s: date: %ptRr\n", __func__, &t->time); t->enabled = !!(rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE); t->pending = (ctrl2 & RX8025_BIT_CTRL2_DAFG) && t->enabled; @@ -504,7 +501,7 @@ static void rx8025_sysfs_unregister(struct device *dev) static int rx8025_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct rx8025_data *rx8025; int err = 0; diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 776e3a2b89e8..490f70f57636 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An I2C driver for the Epson RX8581 RTC * * Author: Martyn Welch <martyn.welch@ge.com> * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) * Copyright 2005-06 Tower Technologies */ diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index 3c64dbb08109..da34cfd70f95 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Seiko Instruments S-35390A RTC Driver * * Copyright (c) 2007 Byron Bradley - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/module.h> @@ -36,21 +32,22 @@ #define S35390A_ALRM_BYTE_MINS 2 /* flags for STATUS1 */ -#define S35390A_FLAG_POC 0x01 -#define S35390A_FLAG_BLD 0x02 -#define S35390A_FLAG_INT2 0x04 -#define S35390A_FLAG_24H 0x40 -#define S35390A_FLAG_RESET 0x80 +#define S35390A_FLAG_POC BIT(0) +#define S35390A_FLAG_BLD BIT(1) +#define S35390A_FLAG_INT2 BIT(2) +#define S35390A_FLAG_24H BIT(6) +#define S35390A_FLAG_RESET BIT(7) /* flag for STATUS2 */ -#define S35390A_FLAG_TEST 0x01 - -#define S35390A_INT2_MODE_MASK 0xF0 +#define S35390A_FLAG_TEST BIT(0) +/* INT2 pin output mode */ +#define S35390A_INT2_MODE_MASK 0x0E #define S35390A_INT2_MODE_NOINTR 0x00 -#define S35390A_INT2_MODE_FREQ 0x10 -#define S35390A_INT2_MODE_ALARM 0x40 -#define S35390A_INT2_MODE_PMIN_EDG 0x20 +#define S35390A_INT2_MODE_ALARM BIT(1) /* INT2AE */ +#define S35390A_INT2_MODE_PMIN_EDG BIT(2) /* INT2ME */ +#define S35390A_INT2_MODE_FREQ BIT(3) /* INT2FE */ +#define S35390A_INT2_MODE_PMIN (BIT(3) | BIT(2)) /* INT2FE | INT2ME */ static const struct i2c_device_id s35390a_id[] = { { "s35390a", 0 }, @@ -288,6 +285,9 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday, alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday); + if (alm->time.tm_sec != 0) + dev_warn(&client->dev, "Alarms are only supported on a per minute basis!\n"); + /* disable interrupt (which deasserts the irq line) */ err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); if (err < 0) @@ -303,9 +303,6 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) else sts = S35390A_INT2_MODE_NOINTR; - /* This chip expects the bits of each byte to be in reverse order */ - sts = bitrev8(sts); - /* set interupt mode*/ err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); if (err < 0) @@ -343,7 +340,7 @@ static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) if (err < 0) return err; - if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) { + if ((sts & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) { /* * When the alarm isn't enabled, the register to configure * the alarm time isn't accessible. @@ -435,39 +432,34 @@ static int s35390a_probe(struct i2c_client *client, unsigned int i; struct s35390a *s35390a; char buf, status1; + struct device *dev = &client->dev; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - err = -ENODEV; - goto exit; - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; - s35390a = devm_kzalloc(&client->dev, sizeof(struct s35390a), - GFP_KERNEL); - if (!s35390a) { - err = -ENOMEM; - goto exit; - } + s35390a = devm_kzalloc(dev, sizeof(struct s35390a), GFP_KERNEL); + if (!s35390a) + return -ENOMEM; s35390a->client[0] = client; i2c_set_clientdata(client, s35390a); /* This chip uses multiple addresses, use dummy devices for them */ for (i = 1; i < 8; ++i) { - s35390a->client[i] = i2c_new_dummy(client->adapter, - client->addr + i); - if (!s35390a->client[i]) { - dev_err(&client->dev, "Address %02x unavailable\n", - client->addr + i); - err = -EBUSY; - goto exit_dummy; + s35390a->client[i] = devm_i2c_new_dummy_device(dev, + client->adapter, + client->addr + i); + if (IS_ERR(s35390a->client[i])) { + dev_err(dev, "Address %02x unavailable\n", + client->addr + i); + return PTR_ERR(s35390a->client[i]); } } err_read = s35390a_read_status(s35390a, &status1); if (err_read < 0) { - err = err_read; - dev_err(&client->dev, "error resetting chip\n"); - goto exit_dummy; + dev_err(dev, "error resetting chip\n"); + return err_read; } if (status1 & S35390A_FLAG_24H) @@ -480,52 +472,32 @@ static int s35390a_probe(struct i2c_client *client, buf = 0; err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1); if (err < 0) { - dev_err(&client->dev, "error disabling alarm"); - goto exit_dummy; + dev_err(dev, "error disabling alarm"); + return err; } } else { err = s35390a_disable_test_mode(s35390a); if (err < 0) { - dev_err(&client->dev, "error disabling test mode\n"); - goto exit_dummy; + dev_err(dev, "error disabling test mode\n"); + return err; } } - device_set_wakeup_capable(&client->dev, 1); + device_set_wakeup_capable(dev, 1); - s35390a->rtc = devm_rtc_device_register(&client->dev, - s35390a_driver.driver.name, - &s35390a_rtc_ops, THIS_MODULE); + s35390a->rtc = devm_rtc_device_register(dev, s35390a_driver.driver.name, + &s35390a_rtc_ops, THIS_MODULE); - if (IS_ERR(s35390a->rtc)) { - err = PTR_ERR(s35390a->rtc); - goto exit_dummy; - } + if (IS_ERR(s35390a->rtc)) + return PTR_ERR(s35390a->rtc); + + /* supports per-minute alarms only, therefore set uie_unsupported */ + s35390a->rtc->uie_unsupported = 1; if (status1 & S35390A_FLAG_INT2) rtc_update_irq(s35390a->rtc, 1, RTC_AF); return 0; - -exit_dummy: - for (i = 1; i < 8; ++i) - if (s35390a->client[i]) - i2c_unregister_device(s35390a->client[i]); - -exit: - return err; -} - -static int s35390a_remove(struct i2c_client *client) -{ - unsigned int i; - struct s35390a *s35390a = i2c_get_clientdata(client); - - for (i = 1; i < 8; ++i) - if (s35390a->client[i]) - i2c_unregister_device(s35390a->client[i]); - - return 0; } static struct i2c_driver s35390a_driver = { @@ -534,7 +506,6 @@ static struct i2c_driver s35390a_driver = { .of_match_table = of_match_ptr(s35390a_of_match), }, .probe = s35390a_probe, - .remove = s35390a_remove, .id_table = s35390a_id, }; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e81a2b22a5c3..7801249c254b 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-s3c.c * * Copyright (c) 2010 Samsung Electronics Co., Ltd. @@ -7,10 +8,6 @@ * Ben Dooks, <ben@simtec.co.uk> * http://armlinux.simtec.co.uk/ * - * 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. - * * S3C2410/S3C2440/S3C24XX Internal RTC Driver */ @@ -456,10 +453,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) /* find the IRQs */ info->irq_tick = platform_get_irq(pdev, 1); - if (info->irq_tick < 0) { - dev_err(&pdev->dev, "no irq for rtc tick\n"); + if (info->irq_tick < 0) return info->irq_tick; - } info->dev = &pdev->dev; info->data = of_device_get_match_data(&pdev->dev); @@ -473,10 +468,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, info); info->irq_alarm = platform_get_irq(pdev, 0); - if (info->irq_alarm < 0) { - dev_err(&pdev->dev, "no irq for alarm\n"); + if (info->irq_alarm < 0) return info->irq_alarm; - } dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n", info->irq_tick, info->irq_alarm); diff --git a/drivers/rtc/rtc-s3c.h b/drivers/rtc/rtc-s3c.h index 004b61a8343f..3552914aa611 100644 --- a/drivers/rtc/rtc-s3c.h +++ b/drivers/rtc/rtc-s3c.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> * http://www.simtec.co.uk/products/SWLINUX/ * - * 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. - * * S3C2410 Internal RTC register definition */ diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index c7f1bf823ea0..eb9dde4095a9 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -760,10 +760,10 @@ static int s5m_rtc_probe(struct platform_device *pdev) return -ENODEV; } - info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR); - if (!info->i2c) { + info->i2c = i2c_new_dummy_device(s5m87xx->i2c->adapter, RTC_I2C_ADDR); + if (IS_ERR(info->i2c)) { dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n"); - return -ENODEV; + return PTR_ERR(info->i2c); } info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 304d905cb23f..86fa723b3b76 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx * @@ -14,11 +15,6 @@ * * Converted to the RTC subsystem and Driver Model * by Richard Purdie <rpurdie@rpsys.net> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/platform_device.h> diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c index b4eb3b3c6c2c..b95676899750 100644 --- a/drivers/rtc/rtc-sc27xx.c +++ b/drivers/rtc/rtc-sc27xx.c @@ -138,7 +138,7 @@ static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock) if (ret) return ret; - val &= ~(SPRD_RTC_ALMLOCK_MASK | SPRD_RTC_POWEROFF_ALM_FLAG); + val &= ~SPRD_RTC_ALMLOCK_MASK; if (lock) val |= SPRD_RTC_ALM_LOCK; else @@ -614,10 +614,8 @@ static int sprd_rtc_probe(struct platform_device *pdev) } rtc->irq = platform_get_irq(pdev, 0); - if (rtc->irq < 0) { - dev_err(&pdev->dev, "failed to get RTC irq number\n"); + if (rtc->irq < 0) return rtc->irq; - } rtc->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc)) @@ -656,7 +654,6 @@ static int sprd_rtc_probe(struct platform_device *pdev) rtc->rtc->range_max = 5662310399LL; ret = rtc_register_device(rtc->rtc); if (ret) { - dev_err(&pdev->dev, "failed to register rtc device\n"); device_init_wakeup(&pdev->dev, 0); return ret; } diff --git a/drivers/rtc/rtc-sd3078.c b/drivers/rtc/rtc-sd3078.c index 42cb90db7f94..a7aa943c1183 100644 --- a/drivers/rtc/rtc-sd3078.c +++ b/drivers/rtc/rtc-sd3078.c @@ -193,10 +193,8 @@ static int sd3078_probe(struct i2c_client *client, sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099; ret = rtc_register_device(sd3078->rtc); - if (ret) { - dev_err(&client->dev, "failed to register rtc device\n"); + if (ret) return ret; - } sd3078_enable_reg_write(sd3078); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 1d3de2a3d1a4..579b3ff5c644 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -276,6 +276,9 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) struct sh_rtc *rtc = dev_get_drvdata(dev); unsigned int sec128, sec2, yr, yr100, cf_bit; + if (!(readb(rtc->regbase + RCR2) & RCR2_RTCEN)) + return -EINVAL; + do { unsigned int tmp; @@ -466,7 +469,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev) { struct sh_rtc *rtc; struct resource *res; - struct rtc_time r; char clk_name[6]; int clk_id, ret; @@ -528,6 +530,10 @@ static int __init sh_rtc_probe(struct platform_device *pdev) rtc->clk = NULL; } + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc->rtc_dev)) + return PTR_ERR(rtc->rtc_dev); + clk_enable(rtc->clk); rtc->capabilities = RTC_DEF_CAPABILITIES; @@ -591,21 +597,21 @@ 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 = devm_rtc_device_register(&pdev->dev, "sh", - &sh_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc_dev)) { - ret = PTR_ERR(rtc->rtc_dev); - goto err_unmap; - } - + rtc->rtc_dev->ops = &sh_rtc_ops; rtc->rtc_dev->max_user_freq = 256; - /* reset rtc to epoch 0 if time is invalid */ - if (rtc_read_time(rtc->rtc_dev, &r) < 0) { - rtc_time_to_tm(0, &r); - rtc_set_time(rtc->rtc_dev, &r); + if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { + rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900; + rtc->rtc_dev->range_max = RTC_TIMESTAMP_END_9999; + } else { + rtc->rtc_dev->range_min = mktime64(1999, 1, 1, 0, 0, 0); + rtc->rtc_dev->range_max = mktime64(2098, 12, 31, 23, 59, 59); } + ret = rtc_register_device(rtc->rtc_dev); + if (ret) + goto err_unmap; + device_init_wakeup(&pdev->dev, 1); return 0; diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index 2a9e151cae99..c759c55359a1 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * 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> @@ -279,7 +278,7 @@ static const struct of_device_id sirfsoc_rtc_of_match[] = { {}, }; -const struct regmap_config sysrtc_regmap_config = { +static const struct regmap_config sysrtc_regmap_config = { .reg_bits = 32, .val_bits = 32, .fast_io = true, diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 0b9eff19149b..757f4daa7181 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -9,6 +9,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/rtc.h> #include <linux/clk.h> #include <linux/mfd/syscon.h> @@ -150,7 +151,7 @@ static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) struct snvs_rtc_data *data = dev_get_drvdata(dev); unsigned long time = rtc_read_lp_counter(data); - rtc_time_to_tm(time, tm); + rtc_time64_to_tm(time, tm); return 0; } @@ -158,11 +159,9 @@ static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); - unsigned long time; + unsigned long time = rtc_tm_to_time64(tm); int ret; - rtc_tm_to_time(tm, &time); - /* Disable RTC first */ ret = snvs_rtc_enable(data, false); if (ret) @@ -184,7 +183,7 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) u32 lptar, lpsr; regmap_read(data->regmap, data->offset + SNVS_LPTAR, &lptar); - rtc_time_to_tm(lptar, &alrm->time); + rtc_time64_to_tm(lptar, &alrm->time); regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0; @@ -206,12 +205,9 @@ static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); - struct rtc_time *alrm_tm = &alrm->time; - unsigned long time; + unsigned long time = rtc_tm_to_time64(&alrm->time); int ret; - rtc_tm_to_time(alrm_tm, &time); - regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); ret = rtc_write_sync_lp(data); if (ret) @@ -271,7 +267,6 @@ static const struct regmap_config snvs_rtc_config = { static int snvs_rtc_probe(struct platform_device *pdev) { struct snvs_rtc_data *data; - struct resource *res; int ret; void __iomem *mmio; @@ -279,13 +274,16 @@ static int snvs_rtc_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + data->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(data->rtc)) + return PTR_ERR(data->rtc); + data->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap"); if (IS_ERR(data->regmap)) { dev_warn(&pdev->dev, "snvs rtc: you use old dts file, please update it\n"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio = devm_ioremap_resource(&pdev->dev, res); + mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mmio)) return PTR_ERR(mmio); @@ -332,6 +330,9 @@ static int snvs_rtc_probe(struct platform_device *pdev) } device_init_wakeup(&pdev->dev, true); + ret = dev_pm_set_wake_irq(&pdev->dev, data->irq); + if (ret) + dev_err(&pdev->dev, "failed to enable irq wake\n"); ret = devm_request_irq(&pdev->dev, data->irq, snvs_rtc_irq_handler, IRQF_SHARED, "rtc alarm", &pdev->dev); @@ -341,10 +342,10 @@ static int snvs_rtc_probe(struct platform_device *pdev) goto error_rtc_device_register; } - data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &snvs_rtc_ops, THIS_MODULE); - if (IS_ERR(data->rtc)) { - ret = PTR_ERR(data->rtc); + data->rtc->ops = &snvs_rtc_ops; + data->rtc->range_max = U32_MAX; + ret = rtc_register_device(data->rtc); + if (ret) { dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); goto error_rtc_device_register; } @@ -358,18 +359,7 @@ error_rtc_device_register: return ret; } -#ifdef CONFIG_PM_SLEEP -static int snvs_rtc_suspend(struct device *dev) -{ - struct snvs_rtc_data *data = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - return enable_irq_wake(data->irq); - - return 0; -} - -static int snvs_rtc_suspend_noirq(struct device *dev) +static int __maybe_unused snvs_rtc_suspend_noirq(struct device *dev) { struct snvs_rtc_data *data = dev_get_drvdata(dev); @@ -379,17 +369,7 @@ static int snvs_rtc_suspend_noirq(struct device *dev) return 0; } -static int snvs_rtc_resume(struct device *dev) -{ - struct snvs_rtc_data *data = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - return disable_irq_wake(data->irq); - - return 0; -} - -static int snvs_rtc_resume_noirq(struct device *dev) +static int __maybe_unused snvs_rtc_resume_noirq(struct device *dev) { struct snvs_rtc_data *data = dev_get_drvdata(dev); @@ -400,20 +380,9 @@ static int snvs_rtc_resume_noirq(struct device *dev) } static const struct dev_pm_ops snvs_rtc_pm_ops = { - .suspend = snvs_rtc_suspend, - .suspend_noirq = snvs_rtc_suspend_noirq, - .resume = snvs_rtc_resume, - .resume_noirq = snvs_rtc_resume_noirq, + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(snvs_rtc_suspend_noirq, snvs_rtc_resume_noirq) }; -#define SNVS_RTC_PM_OPS (&snvs_rtc_pm_ops) - -#else - -#define SNVS_RTC_PM_OPS NULL - -#endif - static const struct of_device_id snvs_dt_ids[] = { { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, { /* sentinel */ } @@ -423,7 +392,7 @@ MODULE_DEVICE_TABLE(of, snvs_dt_ids); static struct platform_driver snvs_rtc_driver = { .driver = { .name = "snvs_rtc", - .pm = SNVS_RTC_PM_OPS, + .pm = &snvs_rtc_pm_ops, .of_match_table = snvs_dt_ids, }, .probe = snvs_rtc_probe, diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index 0567944fd4f8..9f23b24f466c 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -358,10 +358,8 @@ static int spear_rtc_probe(struct platform_device *pdev) /* alarm irqs */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no update irq?\n"); + if (irq < 0) return irq; - } status = devm_request_irq(&pdev->dev, irq, spear_rtc_irq, 0, pdev->name, config); diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c index bee75ca7ff79..49474a31c66d 100644 --- a/drivers/rtc/rtc-st-lpc.c +++ b/drivers/rtc/rtc-st-lpc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * rtc-st-lpc.c - ST's LPC RTC, powered by the Low Power Timer * @@ -7,11 +8,6 @@ * Lee Jones <lee.jones@linaro.org> for STMicroelectronics * * Based on the original driver written by Stuart Menefy. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #include <linux/clk.h> @@ -166,10 +162,6 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) now_secs = rtc_tm_to_time64(&now); alarm_secs = rtc_tm_to_time64(&t->time); - /* Invalid alarm time */ - if (now_secs > alarm_secs) - return -EINVAL; - memcpy(&rtc->alarm, t, sizeof(struct rtc_wkalrm)); /* Now many secs to fire */ diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index fccbecbb2c98..a833ebc4ecb9 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * A RTC driver for the Simtek STK17TA8 * @@ -5,10 +6,6 @@ * * Based on the DS1553 driver from * Atsushi Nemoto <anemo@mba.ocn.ne.jp> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/bcd.h> diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index c5908cfea234..2999e33a7e37 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -519,11 +519,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) /* Write to Alarm register */ writel_relaxed(alrmar, rtc->base + regs->alrmar); - if (alrm->enabled) - stm32_rtc_alarm_irq_enable(dev, 1); - else - stm32_rtc_alarm_irq_enable(dev, 0); - + stm32_rtc_alarm_irq_enable(dev, alrm->enabled); end: stm32_rtc_wpr_lock(rtc); @@ -780,7 +776,6 @@ static int stm32_rtc_probe(struct platform_device *pdev) rtc->irq_alarm = platform_get_irq(pdev, 0); if (rtc->irq_alarm <= 0) { - dev_err(&pdev->dev, "no alarm irq\n"); ret = rtc->irq_alarm; goto err; } @@ -788,11 +783,14 @@ static int stm32_rtc_probe(struct platform_device *pdev) ret = device_init_wakeup(&pdev->dev, true); if (rtc->data->has_wakeirq) { rtc->wakeirq_alarm = platform_get_irq(pdev, 1); - if (rtc->wakeirq_alarm <= 0) - ret = rtc->wakeirq_alarm; - else + if (rtc->wakeirq_alarm > 0) { ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, rtc->wakeirq_alarm); + } else { + ret = rtc->wakeirq_alarm; + if (rtc->wakeirq_alarm == -EPROBE_DEFER) + goto err; + } } if (ret) dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret); diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index b76318fd5bb0..ff6488be385f 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale STMP37XX/STMP378X Real Time Clock driver * @@ -8,15 +9,6 @@ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. * Copyright 2011 Wolfram Sang, Pengutronix e.K. */ - -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/io.h> @@ -160,15 +152,15 @@ static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) if (ret) return ret; - rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm); + rtc_time64_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm); return 0; } -static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) +static int stmp3xxx_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); + writel(rtc_tm_to_time64(rtc_tm), rtc_data->io + STMP3XXX_RTC_SECONDS); return stmp3xxx_wait_time(rtc_data); } @@ -214,17 +206,15 @@ static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_ALARM), &alm->time); + rtc_time64_to_tm(readl(rtc_data->io + STMP3XXX_RTC_ALARM), &alm->time); return 0; } static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { - unsigned long t; struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - rtc_tm_to_time(&alm->time, &t); - writel(t, rtc_data->io + STMP3XXX_RTC_ALARM); + writel(rtc_tm_to_time64(&alm->time), rtc_data->io + STMP3XXX_RTC_ALARM); stmp3xxx_alarm_irq_enable(dev, alm->enabled); @@ -235,7 +225,7 @@ static const struct rtc_class_ops stmp3xxx_rtc_ops = { .alarm_irq_enable = stmp3xxx_alarm_irq_enable, .read_time = stmp3xxx_rtc_gettime, - .set_mmss = stmp3xxx_rtc_set_mmss, + .set_time = stmp3xxx_rtc_settime, .read_alarm = stmp3xxx_rtc_read_alarm, .set_alarm = stmp3xxx_rtc_set_alarm, }; @@ -361,8 +351,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); - rtc_data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &stmp3xxx_rtc_ops, THIS_MODULE); + rtc_data->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc_data->rtc)) return PTR_ERR(rtc_data->rtc); @@ -374,6 +363,13 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) return err; } + rtc_data->rtc->ops = &stmp3xxx_rtc_ops; + rtc_data->rtc->range_max = U32_MAX; + + err = rtc_register_device(rtc_data->rtc); + if (err) + return err; + stmp3xxx_wdt_register(pdev); return 0; } diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c index 11bc562eba5d..036463dfa103 100644 --- a/drivers/rtc/rtc-sun4v.c +++ b/drivers/rtc/rtc-sun4v.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems. * * Author: David S. Miller - * License: GPL * * Copyright (C) 2008 David S. Miller <davem@davemloft.net> */ @@ -39,7 +39,7 @@ retry: static int sun4v_read_time(struct device *dev, struct rtc_time *tm) { - rtc_time_to_tm(hypervisor_get_time(), tm); + rtc_time64_to_tm(hypervisor_get_time(), tm); return 0; } @@ -66,14 +66,7 @@ retry: static int sun4v_set_time(struct device *dev, struct rtc_time *tm) { - unsigned long secs; - int err; - - err = rtc_tm_to_time(tm, &secs); - if (err) - return err; - - return hypervisor_set_time(secs); + return hypervisor_set_time(rtc_tm_to_time64(tm)); } static const struct rtc_class_ops sun4v_rtc_ops = { @@ -85,13 +78,15 @@ static int __init sun4v_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; - rtc = devm_rtc_device_register(&pdev->dev, "sun4v", - &sun4v_rtc_ops, THIS_MODULE); + rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); + rtc->ops = &sun4v_rtc_ops; + rtc->range_max = U64_MAX; platform_set_drvdata(pdev, rtc); - return 0; + + return rtc_register_device(rtc); } static struct platform_driver sun4v_rtc_driver = { diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 11f56de52179..5e2bd9f1d01e 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * An RTC driver for Allwinner A31/A23 * @@ -8,16 +9,6 @@ * 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. */ #include <linux/clk.h> @@ -41,9 +32,11 @@ /* Control register */ #define SUN6I_LOSC_CTRL 0x0000 #define SUN6I_LOSC_CTRL_KEY (0x16aa << 16) +#define SUN6I_LOSC_CTRL_AUTO_SWT_BYPASS BIT(15) #define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9) #define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8) #define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7) +#define SUN6I_LOSC_CTRL_EXT_LOSC_EN BIT(4) #define SUN6I_LOSC_CTRL_EXT_OSC BIT(0) #define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7) @@ -137,6 +130,8 @@ struct sun6i_rtc_clk_data { unsigned int has_prescaler : 1; unsigned int has_out_clk : 1; unsigned int export_iosc : 1; + unsigned int has_losc_en : 1; + unsigned int has_auto_swt : 1; }; struct sun6i_rtc_dev { @@ -199,6 +194,10 @@ static int sun6i_rtc_osc_set_parent(struct clk_hw *hw, u8 index) val &= ~SUN6I_LOSC_CTRL_EXT_OSC; val |= SUN6I_LOSC_CTRL_KEY; val |= index ? SUN6I_LOSC_CTRL_EXT_OSC : 0; + if (rtc->data->has_losc_en) { + val &= ~SUN6I_LOSC_CTRL_EXT_LOSC_EN; + val |= index ? SUN6I_LOSC_CTRL_EXT_LOSC_EN : 0; + } writel(val, rtc->base + SUN6I_LOSC_CTRL); spin_unlock_irqrestore(&rtc->lock, flags); @@ -224,6 +223,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, const char *iosc_name = "rtc-int-osc"; const char *clkout_name = "osc32k-out"; const char *parents[2]; + u32 reg; rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); if (!rtc) @@ -244,9 +244,18 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, goto err; } + reg = SUN6I_LOSC_CTRL_KEY; + if (rtc->data->has_auto_swt) { + /* Bypass auto-switch to int osc, on ext losc failure */ + reg |= SUN6I_LOSC_CTRL_AUTO_SWT_BYPASS; + writel(reg, rtc->base + SUN6I_LOSC_CTRL); + } + /* Switch to the external, more precise, oscillator */ - writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC, - rtc->base + SUN6I_LOSC_CTRL); + reg |= SUN6I_LOSC_CTRL_EXT_OSC; + if (rtc->data->has_losc_en) + reg |= SUN6I_LOSC_CTRL_EXT_LOSC_EN; + writel(reg, rtc->base + SUN6I_LOSC_CTRL); /* Yes, I know, this is ugly. */ sun6i_rtc = rtc; @@ -288,7 +297,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, of_property_read_string_index(node, "clock-output-names", 1, &clkout_name); - rtc->ext_losc = clk_register_gate(NULL, clkout_name, rtc->hw.init->name, + rtc->ext_losc = clk_register_gate(NULL, clkout_name, init.name, 0, rtc->base + SUN6I_LOSC_OUT_GATING, SUN6I_LOSC_OUT_GATING_EN_OFFSET, 0, &rtc->lock); @@ -354,6 +363,23 @@ CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc", CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc", sun8i_h3_rtc_clk_init); +static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = { + .rc_osc_rate = 16000000, + .fixed_prescaler = 32, + .has_prescaler = 1, + .has_out_clk = 1, + .export_iosc = 1, + .has_losc_en = 1, + .has_auto_swt = 1, +}; + +static void __init sun50i_h6_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun50i_h6_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun50i_h6_rtc_clk, "allwinner,sun50i-h6-rtc", + sun50i_h6_rtc_clk_init); + static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = { .rc_osc_rate = 32000, .has_out_clk = 1, @@ -607,6 +633,33 @@ static const struct rtc_class_ops sun6i_rtc_ops = { .alarm_irq_enable = sun6i_rtc_alarm_irq_enable }; +#ifdef CONFIG_PM_SLEEP +/* Enable IRQ wake on suspend, to wake up from RTC. */ +static int sun6i_rtc_suspend(struct device *dev) +{ + struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(chip->irq); + + return 0; +} + +/* Disable IRQ wake on resume. */ +static int sun6i_rtc_resume(struct device *dev) +{ + struct sun6i_rtc_dev *chip = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(chip->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(sun6i_rtc_pm_ops, + sun6i_rtc_suspend, sun6i_rtc_resume); + static int sun6i_rtc_probe(struct platform_device *pdev) { struct sun6i_rtc_dev *chip = sun6i_rtc; @@ -619,10 +672,8 @@ static int sun6i_rtc_probe(struct platform_device *pdev) chip->dev = &pdev->dev; chip->irq = platform_get_irq(pdev, 0); - if (chip->irq < 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); + if (chip->irq < 0) return chip->irq; - } ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq, 0, dev_name(&pdev->dev), chip); @@ -659,6 +710,8 @@ static int sun6i_rtc_probe(struct platform_device *pdev) clk_prepare_enable(chip->losc); + device_init_wakeup(&pdev->dev, 1); + chip->rtc = devm_rtc_device_register(&pdev->dev, "rtc-sun6i", &sun6i_rtc_ops, THIS_MODULE); if (IS_ERR(chip->rtc)) { @@ -681,8 +734,10 @@ static const struct of_device_id sun6i_rtc_dt_ids[] = { { .compatible = "allwinner,sun6i-a31-rtc" }, { .compatible = "allwinner,sun8i-a23-rtc" }, { .compatible = "allwinner,sun8i-h3-rtc" }, + { .compatible = "allwinner,sun8i-r40-rtc" }, { .compatible = "allwinner,sun8i-v3-rtc" }, { .compatible = "allwinner,sun50i-h5-rtc" }, + { .compatible = "allwinner,sun50i-h6-rtc" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids); @@ -692,6 +747,7 @@ static struct platform_driver sun6i_rtc_driver = { .driver = { .name = "sun6i-rtc", .of_match_table = sun6i_rtc_dt_ids, + .pm = &sun6i_rtc_pm_ops, }, }; builtin_platform_driver(sun6i_rtc_driver); diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 21865d3d8fe8..9b6f2483c1c6 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * 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> @@ -455,10 +442,8 @@ static int sunxi_rtc_probe(struct platform_device *pdev) return PTR_ERR(chip->base); chip->irq = platform_get_irq(pdev, 0); - if (chip->irq < 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); + if (chip->irq < 0) return chip->irq; - } ret = devm_request_irq(&pdev->dev, chip->irq, sunxi_rtc_alarmirq, 0, dev_name(&pdev->dev), chip); if (ret) { @@ -487,15 +472,7 @@ static int sunxi_rtc_probe(struct platform_device *pdev) chip->rtc->ops = &sunxi_rtc_ops; - ret = rtc_register_device(chip->rtc); - if (ret) { - dev_err(&pdev->dev, "unable to register device\n"); - return ret; - } - - dev_info(&pdev->dev, "RTC enabled\n"); - - return 0; + return rtc_register_device(chip->rtc); } static struct platform_driver sunxi_rtc_driver = { diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index c6b0a99aa3a9..69d695bf9500 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * An RTC driver for the NVIDIA Tegra 200 series internal RTC. * - * Copyright (c) 2010, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Copyright (c) 2010-2019, NVIDIA Corporation. */ #include <linux/clk.h> @@ -31,10 +18,10 @@ #include <linux/rtc.h> #include <linux/slab.h> -/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */ +/* Set to 1 = busy every eight 32 kHz clocks during copy of sec+msec to AHB. */ #define TEGRA_RTC_REG_BUSY 0x004 #define TEGRA_RTC_REG_SECONDS 0x008 -/* when msec is read, the seconds are buffered into shadow seconds. */ +/* When msec is read, the seconds are buffered into shadow seconds. */ #define TEGRA_RTC_REG_SHADOW_SECONDS 0x00c #define TEGRA_RTC_REG_MILLI_SECONDS 0x010 #define TEGRA_RTC_REG_SECONDS_ALARM0 0x014 @@ -59,44 +46,48 @@ #define TEGRA_RTC_INTR_STATUS_SEC_ALARM0 (1<<0) struct tegra_rtc_info { - struct platform_device *pdev; - struct rtc_device *rtc_dev; - void __iomem *rtc_base; /* NULL if not initialized. */ - struct clk *clk; - int tegra_rtc_irq; /* alarm and periodic irq */ - spinlock_t tegra_rtc_lock; + struct platform_device *pdev; + struct rtc_device *rtc; + void __iomem *base; /* NULL if not initialized */ + struct clk *clk; + int irq; /* alarm and periodic IRQ */ + spinlock_t lock; }; -/* RTC hardware is busy when it is updating its values over AHB once - * every eight 32kHz clocks (~250uS). - * outside of these updates the CPU is free to write. - * CPU is always free to read. +/* + * RTC hardware is busy when it is updating its values over AHB once every + * eight 32 kHz clocks (~250 us). Outside of these updates the CPU is free to + * write. CPU is always free to read. */ static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info) { - return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1; + return readl(info->base + TEGRA_RTC_REG_BUSY) & 1; } -/* Wait for hardware to be ready for writing. - * This function tries to maximize the amount of time before the next update. - * It does this by waiting for the RTC to become busy with its periodic update, - * then returning once the RTC first becomes not busy. +/* + * Wait for hardware to be ready for writing. This function tries to maximize + * the amount of time before the next update. It does this by waiting for the + * RTC to become busy with its periodic update, then returning once the RTC + * first becomes not busy. + * * This periodic update (where the seconds and milliseconds are copied to the - * AHB side) occurs every eight 32kHz clocks (~250uS). - * The behavior of this function allows us to make some assumptions without - * introducing a race, because 250uS is plenty of time to read/write a value. + * AHB side) occurs every eight 32 kHz clocks (~250 us). The behavior of this + * function allows us to make some assumptions without introducing a race, + * because 250 us is plenty of time to read/write a value. */ static int tegra_rtc_wait_while_busy(struct device *dev) { struct tegra_rtc_info *info = dev_get_drvdata(dev); + int retries = 500; /* ~490 us is the worst case, ~250 us is best */ - int retries = 500; /* ~490 us is the worst case, ~250 us is best. */ - - /* first wait for the RTC to become busy. this is when it - * posts its updated seconds+msec registers to AHB side. */ + /* + * First wait for the RTC to become busy. This is when it posts its + * updated seconds+msec registers to AHB side. + */ while (tegra_rtc_check_busy(info)) { if (!retries--) goto retry_failed; + udelay(1); } @@ -104,28 +95,30 @@ static int tegra_rtc_wait_while_busy(struct device *dev) return 0; retry_failed: - dev_err(dev, "write failed:retry count exceeded.\n"); + dev_err(dev, "write failed: retry count exceeded\n"); return -ETIMEDOUT; } static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct tegra_rtc_info *info = dev_get_drvdata(dev); - unsigned long sec, msec; - unsigned long sl_irq_flags; + unsigned long flags; + u32 sec, msec; - /* RTC hardware copies seconds to shadow seconds when a read - * of milliseconds occurs. use a lock to keep other threads out. */ - spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + /* + * RTC hardware copies seconds to shadow seconds when a read of + * milliseconds occurs. use a lock to keep other threads out. + */ + spin_lock_irqsave(&info->lock, flags); - msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS); - sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS); + msec = readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS); + sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS); - spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + spin_unlock_irqrestore(&info->lock, flags); - rtc_time_to_tm(sec, tm); + rtc_time64_to_tm(sec, tm); - dev_vdbg(dev, "time read as %lu. %ptR\n", sec, tm); + dev_vdbg(dev, "time read as %u, %ptR\n", sec, tm); return 0; } @@ -133,21 +126,21 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct tegra_rtc_info *info = dev_get_drvdata(dev); - unsigned long sec; + u32 sec; int ret; - /* convert tm to seconds. */ - rtc_tm_to_time(tm, &sec); + /* convert tm to seconds */ + sec = rtc_tm_to_time64(tm); - dev_vdbg(dev, "time set to %lu. %ptR\n", sec, tm); + dev_vdbg(dev, "time set to %u, %ptR\n", sec, tm); - /* seconds only written if wait succeeded. */ + /* seconds only written if wait succeeded */ ret = tegra_rtc_wait_while_busy(dev); if (!ret) - writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS); + writel(sec, info->base + TEGRA_RTC_REG_SECONDS); dev_vdbg(dev, "time read back as %d\n", - readl(info->rtc_base + TEGRA_RTC_REG_SECONDS)); + readl(info->base + TEGRA_RTC_REG_SECONDS)); return ret; } @@ -155,22 +148,21 @@ static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct tegra_rtc_info *info = dev_get_drvdata(dev); - unsigned long sec; - unsigned tmp; + u32 sec, value; - sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + sec = readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0); if (sec == 0) { - /* alarm is disabled. */ + /* alarm is disabled */ alarm->enabled = 0; } else { - /* alarm is enabled. */ + /* alarm is enabled */ alarm->enabled = 1; - rtc_time_to_tm(sec, &alarm->time); + rtc_time64_to_tm(sec, &alarm->time); } - tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); - alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0; + value = readl(info->base + TEGRA_RTC_REG_INTR_STATUS); + alarm->pending = (value & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0; return 0; } @@ -178,22 +170,22 @@ static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct tegra_rtc_info *info = dev_get_drvdata(dev); - unsigned status; - unsigned long sl_irq_flags; + unsigned long flags; + u32 status; tegra_rtc_wait_while_busy(dev); - spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + spin_lock_irqsave(&info->lock, flags); - /* read the original value, and OR in the flag. */ - status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + /* read the original value, and OR in the flag */ + status = readl(info->base + TEGRA_RTC_REG_INTR_MASK); if (enabled) status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */ else status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */ - writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + writel(status, info->base + TEGRA_RTC_REG_INTR_MASK); - spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + spin_unlock_irqrestore(&info->lock, flags); return 0; } @@ -201,24 +193,24 @@ static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct tegra_rtc_info *info = dev_get_drvdata(dev); - unsigned long sec; + u32 sec; if (alarm->enabled) - rtc_tm_to_time(&alarm->time, &sec); + sec = rtc_tm_to_time64(&alarm->time); else sec = 0; tegra_rtc_wait_while_busy(dev); - writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + writel(sec, info->base + TEGRA_RTC_REG_SECONDS_ALARM0); dev_vdbg(dev, "alarm read back as %d\n", - readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); + readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0)); /* if successfully written and alarm is enabled ... */ if (sec) { tegra_rtc_alarm_irq_enable(dev, 1); - dev_vdbg(dev, "alarm set as %lu. %ptR\n", sec, &alarm->time); + dev_vdbg(dev, "alarm set as %u, %ptR\n", sec, &alarm->time); } else { - /* disable alarm if 0 or write error. */ + /* disable alarm if 0 or write error */ dev_vdbg(dev, "alarm disabled\n"); tegra_rtc_alarm_irq_enable(dev, 0); } @@ -240,39 +232,39 @@ static irqreturn_t tegra_rtc_irq_handler(int irq, void *data) { struct device *dev = data; struct tegra_rtc_info *info = dev_get_drvdata(dev); - unsigned long events = 0; - unsigned status; - unsigned long sl_irq_flags; + unsigned long events = 0, flags; + u32 status; - status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + status = readl(info->base + TEGRA_RTC_REG_INTR_STATUS); if (status) { - /* clear the interrupt masks and status on any irq. */ + /* clear the interrupt masks and status on any IRQ */ tegra_rtc_wait_while_busy(dev); - spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); - writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); - writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); - spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + + spin_lock_irqsave(&info->lock, flags); + writel(0, info->base + TEGRA_RTC_REG_INTR_MASK); + writel(status, info->base + TEGRA_RTC_REG_INTR_STATUS); + spin_unlock_irqrestore(&info->lock, flags); } - /* check if Alarm */ - if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)) + /* check if alarm */ + if (status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) events |= RTC_IRQF | RTC_AF; - /* check if Periodic */ - if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)) + /* check if periodic */ + if (status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM) events |= RTC_IRQF | RTC_PF; - rtc_update_irq(info->rtc_dev, 1, events); + rtc_update_irq(info->rtc, 1, events); return IRQ_HANDLED; } static const struct rtc_class_ops tegra_rtc_ops = { - .read_time = tegra_rtc_read_time, - .set_time = tegra_rtc_set_time, - .read_alarm = tegra_rtc_read_alarm, - .set_alarm = tegra_rtc_set_alarm, - .proc = tegra_rtc_proc, + .read_time = tegra_rtc_read_time, + .set_time = tegra_rtc_set_time, + .read_alarm = tegra_rtc_read_alarm, + .set_alarm = tegra_rtc_set_alarm, + .proc = tegra_rtc_proc, .alarm_irq_enable = tegra_rtc_alarm_irq_enable, }; @@ -282,29 +274,33 @@ static const struct of_device_id tegra_rtc_dt_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match); -static int __init tegra_rtc_probe(struct platform_device *pdev) +static int tegra_rtc_probe(struct platform_device *pdev) { struct tegra_rtc_info *info; struct resource *res; int ret; - info = devm_kzalloc(&pdev->dev, sizeof(struct tegra_rtc_info), - GFP_KERNEL); + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->rtc_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(info->rtc_base)) - return PTR_ERR(info->rtc_base); + info->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->base)) + return PTR_ERR(info->base); ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - dev_err(&pdev->dev, "failed to get platform IRQ: %d\n", ret); + if (ret <= 0) return ret; - } - info->tegra_rtc_irq = ret; + info->irq = ret; + + info->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(info->rtc)) + return PTR_ERR(info->rtc); + + info->rtc->ops = &tegra_rtc_ops; + info->rtc->range_max = U32_MAX; info->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) @@ -314,38 +310,30 @@ static int __init tegra_rtc_probe(struct platform_device *pdev) if (ret < 0) return ret; - /* set context info. */ + /* set context info */ info->pdev = pdev; - spin_lock_init(&info->tegra_rtc_lock); + spin_lock_init(&info->lock); platform_set_drvdata(pdev, info); - /* clear out the hardware. */ - writel(0, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); - writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); - writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + /* clear out the hardware */ + writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0); + writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS); + writel(0, info->base + TEGRA_RTC_REG_INTR_MASK); device_init_wakeup(&pdev->dev, 1); - info->rtc_dev = devm_rtc_device_register(&pdev->dev, - dev_name(&pdev->dev), &tegra_rtc_ops, - THIS_MODULE); - if (IS_ERR(info->rtc_dev)) { - ret = PTR_ERR(info->rtc_dev); - dev_err(&pdev->dev, "Unable to register device (err=%d).\n", - ret); + ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler, + IRQF_TRIGGER_HIGH, dev_name(&pdev->dev), + &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret); goto disable_clk; } - ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq, - tegra_rtc_irq_handler, IRQF_TRIGGER_HIGH, - dev_name(&pdev->dev), &pdev->dev); - if (ret) { - dev_err(&pdev->dev, - "Unable to request interrupt for device (err=%d).\n", - ret); + ret = rtc_register_device(info->rtc); + if (ret) goto disable_clk; - } dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); @@ -372,20 +360,20 @@ static int tegra_rtc_suspend(struct device *dev) tegra_rtc_wait_while_busy(dev); - /* only use ALARM0 as a wake source. */ - writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + /* only use ALARM0 as a wake source */ + writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS); writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0, - info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + info->base + TEGRA_RTC_REG_INTR_MASK); dev_vdbg(dev, "alarm sec = %d\n", - readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); + readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0)); - dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n", - device_may_wakeup(dev), info->tegra_rtc_irq); + dev_vdbg(dev, "Suspend (device_may_wakeup=%d) IRQ:%d\n", + device_may_wakeup(dev), info->irq); - /* leave the alarms on as a wake source. */ + /* leave the alarms on as a wake source */ if (device_may_wakeup(dev)) - enable_irq_wake(info->tegra_rtc_irq); + enable_irq_wake(info->irq); return 0; } @@ -395,10 +383,11 @@ static int tegra_rtc_resume(struct device *dev) struct tegra_rtc_info *info = dev_get_drvdata(dev); dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n", - device_may_wakeup(dev)); - /* alarms were left on as a wake source, turn them off. */ + device_may_wakeup(dev)); + + /* alarms were left on as a wake source, turn them off */ if (device_may_wakeup(dev)) - disable_irq_wake(info->tegra_rtc_irq); + disable_irq_wake(info->irq); return 0; } @@ -408,22 +397,21 @@ static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume); static void tegra_rtc_shutdown(struct platform_device *pdev) { - dev_vdbg(&pdev->dev, "disabling interrupts.\n"); + dev_vdbg(&pdev->dev, "disabling interrupts\n"); tegra_rtc_alarm_irq_enable(&pdev->dev, 0); } -MODULE_ALIAS("platform:tegra_rtc"); static struct platform_driver tegra_rtc_driver = { - .remove = tegra_rtc_remove, - .shutdown = tegra_rtc_shutdown, - .driver = { - .name = "tegra_rtc", + .probe = tegra_rtc_probe, + .remove = tegra_rtc_remove, + .shutdown = tegra_rtc_shutdown, + .driver = { + .name = "tegra_rtc", .of_match_table = tegra_rtc_dt_match, - .pm = &tegra_rtc_pm_ops, + .pm = &tegra_rtc_pm_ops, }, }; - -module_platform_driver_probe(tegra_rtc_driver, tegra_rtc_probe); +module_platform_driver(tegra_rtc_driver); MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>"); MODULE_DESCRIPTION("driver for Tegra internal RTC"); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 6c5f09c815e8..74b3a0603b73 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -70,11 +70,11 @@ static int test_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } -static int test_rtc_set_mmss64(struct device *dev, time64_t secs) +static int test_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct rtc_test_data *rtd = dev_get_drvdata(dev); - rtd->offset = secs - ktime_get_real_seconds(); + rtd->offset = rtc_tm_to_time64(tm) - ktime_get_real_seconds(); return 0; } @@ -94,15 +94,15 @@ static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) static const struct rtc_class_ops test_rtc_ops_noalm = { .read_time = test_rtc_read_time, - .set_mmss64 = test_rtc_set_mmss64, + .set_time = test_rtc_set_time, .alarm_irq_enable = test_rtc_alarm_irq_enable, }; static const struct rtc_class_ops test_rtc_ops = { .read_time = test_rtc_read_time, + .set_time = test_rtc_set_time, .read_alarm = test_rtc_read_alarm, .set_alarm = test_rtc_set_alarm, - .set_mmss64 = test_rtc_set_mmss64, .alarm_irq_enable = test_rtc_alarm_irq_enable, }; @@ -133,6 +133,7 @@ static int test_probe(struct platform_device *plat_dev) break; default: rtd->rtc->ops = &test_rtc_ops; + device_init_wakeup(&plat_dev->dev, 1); } timer_setup(&rtd->alarm, test_rtc_alarm_handler, 0); @@ -152,7 +153,8 @@ static int __init test_init(void) { int i, err; - if ((err = platform_driver_register(&test_driver))) + err = platform_driver_register(&test_driver); + if (err) return err; err = -ENOMEM; diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index d6434e514a52..859d901fa6cb 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -259,7 +259,6 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) rtc->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc->rtc)) { ret = PTR_ERR(rtc->rtc); - dev_err(&pdev->dev, "RTC allocate device: ret %d\n", ret); goto fail_rtc_register; } @@ -280,10 +279,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) disable_irq(rtc->irq); ret = rtc_register_device(rtc->rtc); - if (ret) { - dev_err(&pdev->dev, "RTC device register: ret %d\n", ret); + if (ret) goto fail_rtc_register; - } return 0; diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index a9bbd022aeef..2c0467a9e717 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * rtc-tps65910.c -- TPS65910 Real Time Clock interface * @@ -7,11 +8,6 @@ * Based on original TI driver rtc-twl.c * Copyright (C) 2007 MontaVista Software, Inc * Author: Alexandre Rusev <source@mvista.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/kernel.h> @@ -147,7 +143,7 @@ static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) struct tps65910 *tps = dev_get_drvdata(dev->parent); int ret; - ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, alarm_data, + ret = regmap_bulk_read(tps->regmap, TPS65910_ALARM_SECONDS, alarm_data, NUM_TIME_REGS); if (ret < 0) { dev_err(dev, "rtc_read_alarm error %d\n", ret); @@ -429,13 +425,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev) tps_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; tps_rtc->rtc->range_max = RTC_TIMESTAMP_END_2099; - ret = rtc_register_device(tps_rtc->rtc); - if (ret) { - dev_err(&pdev->dev, "RTC device register: err %d\n", ret); - return ret; - } - - return 0; + return rtc_register_device(tps_rtc->rtc); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 3472e79f2b17..c24d1e18f56c 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * rtc-twl.c -- TWL Real Time Clock interface * @@ -11,11 +12,6 @@ * Copyright (C) 2003 MontaVista Software, Inc. * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com> * Copyright (C) 2006 David Brownell - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 2d24babc4057..5a29915a06ec 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -42,11 +42,6 @@ struct tx4939rtc_plat_data { spinlock_t lock; }; -static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) -{ - return platform_get_drvdata(to_platform_device(dev)); -} - static int tx4939_rtc_cmd(struct tx4939_rtc_reg __iomem *rtcreg, int cmd) { int i = 0; @@ -64,7 +59,7 @@ static int tx4939_rtc_cmd(struct tx4939_rtc_reg __iomem *rtcreg, int cmd) static int tx4939_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939rtc_plat_data *pdata = dev_get_drvdata(dev); struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; unsigned long secs = rtc_tm_to_time64(tm); int i, ret; @@ -89,7 +84,7 @@ static int tx4939_rtc_set_time(struct device *dev, struct rtc_time *tm) static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939rtc_plat_data *pdata = dev_get_drvdata(dev); struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; int i, ret; unsigned long sec; @@ -115,7 +110,7 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939rtc_plat_data *pdata = dev_get_drvdata(dev); struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; int i, ret; unsigned long sec; @@ -140,7 +135,7 @@ static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939rtc_plat_data *pdata = dev_get_drvdata(dev); struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; int i, ret; unsigned long sec; @@ -170,7 +165,7 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); + struct tx4939rtc_plat_data *pdata = dev_get_drvdata(dev); spin_lock_irq(&pdata->lock); tx4939_rtc_cmd(pdata->rtcreg, @@ -182,7 +177,7 @@ static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id) { - struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev_id); + struct tx4939rtc_plat_data *pdata = dev_get_drvdata(dev_id); struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; unsigned long events = RTC_IRQF; diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 1f3117b5a83c..63ffba21397b 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* drivers/rtc/rtc-v3020.c * * Copyright (C) 2006 8D Technologies inc. * Copyright (C) 2004 Compulab Ltd. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Driver for the V3020 RTC * * Changelog: @@ -17,7 +14,6 @@ * * ??-???-2004: Someone at Compulab * - Initial driver creation. - * */ #include <linux/platform_device.h> #include <linux/module.h> diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index e66d0f63cee2..c3671043ace7 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for NEC VR4100 series Real Time Clock unit. * * Copyright (C) 2003-2008 Yoichi Yuasa <yuasa@linux-mips.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/compat.h> #include <linux/err.h> #include <linux/fs.h> #include <linux/init.h> @@ -79,6 +67,9 @@ static void __iomem *rtc2_base; #define rtc2_read(offset) readw(rtc2_base + (offset)) #define rtc2_write(offset, value) writew((value), rtc2_base + (offset)) +/* 32-bit compat for ioctls that nobody else uses */ +#define RTC_EPOCH_READ32 _IOR('p', 0x0d, __u32) + static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ static DEFINE_SPINLOCK(rtc_lock); @@ -192,6 +183,10 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long switch (cmd) { case RTC_EPOCH_READ: return put_user(epoch, (unsigned long __user *)arg); +#ifdef CONFIG_64BIT + case RTC_EPOCH_READ32: + return put_user(epoch, (unsigned int __user *)arg); +#endif case RTC_EPOCH_SET: /* Doesn't support before 1900 */ if (arg < 1900) diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 27e896995e9b..d5d14cf86e0d 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * drivers/rtc/rtc-vt8500.c * * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> * * Based on rtc-pxa.c - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> @@ -220,10 +212,8 @@ static int vt8500_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vt8500_rtc); 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"); + if (vt8500_rtc->irq_alarm < 0) return vt8500_rtc->irq_alarm; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); vt8500_rtc->regbase = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/rtc/rtc-wilco-ec.c b/drivers/rtc/rtc-wilco-ec.c index e62bda0cb53e..8ad4c4e6d557 100644 --- a/drivers/rtc/rtc-wilco-ec.c +++ b/drivers/rtc/rtc-wilco-ec.c @@ -21,8 +21,20 @@ #define EC_CMOS_TOD_WRITE 0x02 #define EC_CMOS_TOD_READ 0x08 +/* Message sent to the EC to request the current time. */ +struct ec_rtc_read_request { + u8 command; + u8 reserved; + u8 param; +} __packed; +static struct ec_rtc_read_request read_rq = { + .command = EC_COMMAND_CMOS, + .param = EC_CMOS_TOD_READ, +}; + /** - * struct ec_rtc_read - Format of RTC returned by EC. + * struct ec_rtc_read_response - Format of RTC returned by EC. + * @reserved: Unused byte * @second: Second value (0..59) * @minute: Minute value (0..59) * @hour: Hour value (0..23) @@ -33,7 +45,8 @@ * * All values are presented in binary (not BCD). */ -struct ec_rtc_read { +struct ec_rtc_read_response { + u8 reserved; u8 second; u8 minute; u8 hour; @@ -44,8 +57,10 @@ struct ec_rtc_read { } __packed; /** - * struct ec_rtc_write - Format of RTC sent to the EC. - * @param: EC_CMOS_TOD_WRITE + * struct ec_rtc_write_request - Format of RTC sent to the EC. + * @command: Always EC_COMMAND_CMOS + * @reserved: Unused byte + * @param: Always EC_CMOS_TOD_WRITE * @century: Century value (full year / 100) * @year: Year value (full year % 100) * @month: Month value (1..12) @@ -57,7 +72,9 @@ struct ec_rtc_read { * * All values are presented in BCD. */ -struct ec_rtc_write { +struct ec_rtc_write_request { + u8 command; + u8 reserved; u8 param; u8 century; u8 year; @@ -72,19 +89,17 @@ struct ec_rtc_write { static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm) { struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); - u8 param = EC_CMOS_TOD_READ; - struct ec_rtc_read rtc; - struct wilco_ec_message msg = { - .type = WILCO_EC_MSG_LEGACY, - .flags = WILCO_EC_FLAG_RAW_RESPONSE, - .command = EC_COMMAND_CMOS, - .request_data = ¶m, - .request_size = sizeof(param), - .response_data = &rtc, - .response_size = sizeof(rtc), - }; + struct ec_rtc_read_response rtc; + struct wilco_ec_message msg; int ret; + memset(&msg, 0, sizeof(msg)); + msg.type = WILCO_EC_MSG_LEGACY; + msg.request_data = &read_rq; + msg.request_size = sizeof(read_rq); + msg.response_data = &rtc; + msg.response_size = sizeof(rtc); + ret = wilco_ec_mailbox(ec, &msg); if (ret < 0) return ret; @@ -106,14 +121,8 @@ static int wilco_ec_rtc_read(struct device *dev, struct rtc_time *tm) static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm) { struct wilco_ec_device *ec = dev_get_drvdata(dev->parent); - struct ec_rtc_write rtc; - struct wilco_ec_message msg = { - .type = WILCO_EC_MSG_LEGACY, - .flags = WILCO_EC_FLAG_RAW_RESPONSE, - .command = EC_COMMAND_CMOS, - .request_data = &rtc, - .request_size = sizeof(rtc), - }; + struct ec_rtc_write_request rtc; + struct wilco_ec_message msg; int year = tm->tm_year + 1900; /* * Convert from 0=Sunday to 0=Saturday for the EC @@ -123,6 +132,7 @@ static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm) int wday = tm->tm_wday == 6 ? 0 : tm->tm_wday + 1; int ret; + rtc.command = EC_COMMAND_CMOS; rtc.param = EC_CMOS_TOD_WRITE; rtc.century = bin2bcd(year / 100); rtc.year = bin2bcd(year % 100); @@ -133,6 +143,11 @@ static int wilco_ec_rtc_write(struct device *dev, struct rtc_time *tm) rtc.second = bin2bcd(tm->tm_sec); rtc.weekday = bin2bcd(wday); + memset(&msg, 0, sizeof(msg)); + msg.type = WILCO_EC_MSG_LEGACY; + msg.request_data = &rtc; + msg.request_size = sizeof(rtc); + ret = wilco_ec_mailbox(ec, &msg); if (ret < 0) return ret; diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 7b824dabf104..ccef887d2690 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Real Time Clock driver for Wolfson Microelectronics WM831x * @@ -5,11 +6,6 @@ * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/module.h> @@ -155,7 +151,7 @@ static int wm831x_rtc_readtime(struct device *dev, struct rtc_time *tm) if (memcmp(time1, time2, sizeof(time1)) == 0) { u32 time = (time1[0] << 16) | time1[1]; - rtc_time_to_tm(time, tm); + rtc_time64_to_tm(time, tm); return 0; } @@ -169,15 +165,17 @@ static int wm831x_rtc_readtime(struct device *dev, struct rtc_time *tm) /* * Set current time and date in RTC */ -static int wm831x_rtc_set_mmss(struct device *dev, unsigned long time) +static int wm831x_rtc_settime(struct device *dev, struct rtc_time *tm) { struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); struct wm831x *wm831x = wm831x_rtc->wm831x; struct rtc_time new_tm; - unsigned long new_time; + unsigned long time, new_time; int ret; int count = 0; + time = rtc_tm_to_time64(tm); + ret = wm831x_reg_write(wm831x, WM831X_RTC_TIME_1, (time >> 16) & 0xffff); if (ret < 0) { @@ -215,11 +213,7 @@ static int wm831x_rtc_set_mmss(struct device *dev, unsigned long time) if (ret < 0) return ret; - ret = rtc_tm_to_time(&new_tm, &new_time); - if (ret < 0) { - dev_err(dev, "Failed to convert time: %d\n", ret); - return ret; - } + new_time = rtc_tm_to_time64(&new_tm); /* Allow a second of change in case of tick */ if (new_time - time > 1) { @@ -249,7 +243,7 @@ static int wm831x_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) time = (data[0] << 16) | data[1]; - rtc_time_to_tm(time, &alrm->time); + rtc_time64_to_tm(time, &alrm->time); ret = wm831x_reg_read(wm831x_rtc->wm831x, WM831X_RTC_CONTROL); if (ret < 0) { @@ -288,11 +282,7 @@ static int wm831x_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) int ret; unsigned long time; - ret = rtc_tm_to_time(&alrm->time, &time); - if (ret < 0) { - dev_err(dev, "Failed to convert time: %d\n", ret); - return ret; - } + time = rtc_tm_to_time64(&alrm->time); ret = wm831x_rtc_stop_alarm(wm831x_rtc); if (ret < 0) { @@ -346,7 +336,7 @@ static irqreturn_t wm831x_alm_irq(int irq, void *data) static const struct rtc_class_ops wm831x_rtc_ops = { .read_time = wm831x_rtc_readtime, - .set_mmss = wm831x_rtc_set_mmss, + .set_time = wm831x_rtc_settime, .read_alarm = wm831x_rtc_readalarm, .set_alarm = wm831x_rtc_setalarm, .alarm_irq_enable = wm831x_rtc_alarm_irq_enable, @@ -356,11 +346,10 @@ static const struct rtc_class_ops wm831x_rtc_ops = { /* Turn off the alarm if it should not be a wake source. */ static int wm831x_rtc_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); int ret, enable; - if (wm831x_rtc->alarm_enabled && device_may_wakeup(&pdev->dev)) + if (wm831x_rtc->alarm_enabled && device_may_wakeup(dev)) enable = WM831X_RTC_ALM_ENA; else enable = 0; @@ -368,7 +357,7 @@ static int wm831x_rtc_suspend(struct device *dev) ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, WM831X_RTC_ALM_ENA, enable); if (ret != 0) - dev_err(&pdev->dev, "Failed to update RTC alarm: %d\n", ret); + dev_err(dev, "Failed to update RTC alarm: %d\n", ret); return 0; } @@ -378,15 +367,13 @@ static int wm831x_rtc_suspend(struct device *dev) */ static int wm831x_rtc_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); int ret; if (wm831x_rtc->alarm_enabled) { ret = wm831x_rtc_start_alarm(wm831x_rtc); if (ret != 0) - dev_err(&pdev->dev, - "Failed to restart RTC alarm: %d\n", ret); + dev_err(dev, "Failed to restart RTC alarm: %d\n", ret); } return 0; @@ -395,14 +382,13 @@ static int wm831x_rtc_resume(struct device *dev) /* Unconditionally disable the alarm */ static int wm831x_rtc_freeze(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); int ret; ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, WM831X_RTC_ALM_ENA, 0); if (ret != 0) - dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", ret); + dev_err(dev, "Failed to stop RTC alarm: %d\n", ret); return 0; } @@ -429,23 +415,28 @@ static int wm831x_rtc_probe(struct platform_device *pdev) ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); if (ret < 0) { dev_err(&pdev->dev, "Failed to read RTC control: %d\n", ret); - goto err; + return ret; } if (ret & WM831X_RTC_ALM_ENA) wm831x_rtc->alarm_enabled = 1; device_init_wakeup(&pdev->dev, 1); - wm831x_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm831x", - &wm831x_rtc_ops, THIS_MODULE); - if (IS_ERR(wm831x_rtc->rtc)) { - ret = PTR_ERR(wm831x_rtc->rtc); - goto err; - } + wm831x_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(wm831x_rtc->rtc)) + return PTR_ERR(wm831x_rtc->rtc); + + wm831x_rtc->rtc->ops = &wm831x_rtc_ops; + wm831x_rtc->rtc->range_max = U32_MAX; + + ret = rtc_register_device(wm831x_rtc->rtc); + if (ret) + return ret; ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, wm831x_alm_irq, - IRQF_TRIGGER_RISING, "RTC alarm", + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "RTC alarm", wm831x_rtc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", @@ -455,9 +446,6 @@ static int wm831x_rtc_probe(struct platform_device *pdev) wm831x_rtc_add_randomness(wm831x); return 0; - -err: - return ret; } static const struct dev_pm_ops wm831x_rtc_pm_ops = { diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 483c7993516b..2018614f258f 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Real Time Clock driver for Wolfson Microelectronics WM8350 * @@ -5,12 +6,6 @@ * * Author: Liam Girdwood * linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include <linux/module.h> @@ -340,8 +335,7 @@ static const struct rtc_class_ops wm8350_rtc_ops = { #ifdef CONFIG_PM_SLEEP static int wm8350_rtc_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); + struct wm8350 *wm8350 = dev_get_drvdata(dev); int ret = 0; u16 reg; @@ -351,8 +345,7 @@ static int wm8350_rtc_suspend(struct device *dev) reg & WM8350_RTC_ALMSTS) { ret = wm8350_rtc_stop_alarm(wm8350); if (ret != 0) - dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", - ret); + dev_err(dev, "Failed to stop RTC alarm: %d\n", ret); } return ret; @@ -360,15 +353,13 @@ static int wm8350_rtc_suspend(struct device *dev) static int wm8350_rtc_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); + struct wm8350 *wm8350 = dev_get_drvdata(dev); int ret; if (wm8350->rtc.alarm_enabled) { ret = wm8350_rtc_start_alarm(wm8350); if (ret != 0) - dev_err(&pdev->dev, - "Failed to restart RTC alarm: %d\n", ret); + dev_err(dev, "Failed to restart RTC alarm: %d\n", ret); } return 0; diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index f08f18e4fcdf..d1d5a44d9122 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * An i2c driver for the Xicor/Intersil X1205 RTC * Copyright 2004 Karen Spearel @@ -11,10 +12,6 @@ * * Information and datasheet: * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html - * - * 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> @@ -673,9 +670,16 @@ static const struct i2c_device_id x1205_id[] = { }; MODULE_DEVICE_TABLE(i2c, x1205_id); +static const struct of_device_id x1205_dt_ids[] = { + { .compatible = "xircom,x1205", }, + {}, +}; +MODULE_DEVICE_TABLE(of, x1205_dt_ids); + static struct i2c_driver x1205_driver = { .driver = { .name = "rtc-x1205", + .of_match_table = x1205_dt_ids, }, .probe = x1205_probe, .remove = x1205_remove, diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c index 153820876a82..9683fbf7c78d 100644 --- a/drivers/rtc/rtc-xgene.c +++ b/drivers/rtc/rtc-xgene.c @@ -1,34 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * 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/clk.h> +#include <linux/delay.h> #include <linux/init.h> +#include <linux/io.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> +#include <linux/slab.h> /* RTC CSR Registers */ #define RTC_CCVR 0x00 @@ -48,7 +35,6 @@ 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; @@ -59,11 +45,11 @@ 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); + rtc_time64_to_tm(readl(pdata->csr_base + RTC_CCVR), tm); return 0; } -static int xgene_rtc_set_mmss(struct device *dev, unsigned long secs) +static int xgene_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); @@ -71,7 +57,7 @@ static int xgene_rtc_set_mmss(struct device *dev, unsigned long secs) * 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); + writel((u32)rtc_tm_to_time64(tm), pdata->csr_base + RTC_CLR); readl(pdata->csr_base + RTC_CLR); /* Force a barrier */ return 0; @@ -81,7 +67,8 @@ 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); + /* If possible, CMR should be read here */ + rtc_time64_to_tm(0, &alrm->time); alrm->enabled = readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE; return 0; @@ -115,11 +102,8 @@ static int xgene_rtc_alarm_irq_enabled(struct device *dev) static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); - unsigned long alarm_time; - rtc_tm_to_time(&alrm->time, &alarm_time); - pdata->alarm_time = alarm_time; - writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR); + writel((u32)rtc_tm_to_time64(&alrm->time), pdata->csr_base + RTC_CMR); xgene_rtc_alarm_irq_enable(dev, alrm->enabled); @@ -128,7 +112,7 @@ static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static const struct rtc_class_ops xgene_rtc_ops = { .read_time = xgene_rtc_read_time, - .set_mmss = xgene_rtc_set_mmss, + .set_time = xgene_rtc_set_time, .read_alarm = xgene_rtc_read_alarm, .set_alarm = xgene_rtc_set_alarm, .alarm_irq_enable = xgene_rtc_alarm_irq_enable, @@ -136,7 +120,7 @@ static const struct rtc_class_ops xgene_rtc_ops = { static irqreturn_t xgene_rtc_interrupt(int irq, void *id) { - struct xgene_rtc_dev *pdata = (struct xgene_rtc_dev *) id; + struct xgene_rtc_dev *pdata = id; /* Check if interrupt asserted */ if (!(readl(pdata->csr_base + RTC_STAT) & RTC_STAT_BIT)) @@ -168,11 +152,13 @@ static int xgene_rtc_probe(struct platform_device *pdev) if (IS_ERR(pdata->csr_base)) return PTR_ERR(pdata->csr_base); + pdata->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(pdata->rtc)) + return PTR_ERR(pdata->rtc); + irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0, dev_name(&pdev->dev), pdata); if (ret) { @@ -198,15 +184,16 @@ static int xgene_rtc_probe(struct platform_device *pdev) return ret; } - 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; + pdata->rtc->ops = &xgene_rtc_ops; + pdata->rtc->range_max = U32_MAX; + + ret = rtc_register_device(pdata->rtc); + if (ret) { + clk_disable_unprepare(pdata->clk); + return ret; + } return 0; } diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index bb950945ec7f..2c762757fb54 100644 --- a/drivers/rtc/rtc-zynqmp.c +++ b/drivers/rtc/rtc-zynqmp.c @@ -1,20 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Xilinx Zynq Ultrascale+ MPSoC Real Time Clock Driver * * Copyright (C) 2015 Xilinx, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - * */ #include <linux/delay.h> @@ -229,10 +218,8 @@ static int xlnx_rtc_probe(struct platform_device *pdev) return PTR_ERR(xrtcdev->reg_base); xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm"); - if (xrtcdev->alarm_irq < 0) { - dev_err(&pdev->dev, "no irq resource\n"); + if (xrtcdev->alarm_irq < 0) return xrtcdev->alarm_irq; - } ret = devm_request_irq(&pdev->dev, xrtcdev->alarm_irq, xlnx_rtc_interrupt, 0, dev_name(&pdev->dev), xrtcdev); @@ -242,10 +229,8 @@ static int xlnx_rtc_probe(struct platform_device *pdev) } xrtcdev->sec_irq = platform_get_irq_byname(pdev, "sec"); - if (xrtcdev->sec_irq < 0) { - dev_err(&pdev->dev, "no irq resource\n"); + if (xrtcdev->sec_irq < 0) return xrtcdev->sec_irq; - } ret = devm_request_irq(&pdev->dev, xrtcdev->sec_irq, xlnx_rtc_interrupt, 0, dev_name(&pdev->dev), xrtcdev); diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c index a8f22ee726bb..be3531e7f868 100644 --- a/drivers/rtc/sysfs.c +++ b/drivers/rtc/sysfs.c @@ -1,20 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* * RTC subsystem, sysfs interface * * Copyright (C) 2005 Tower Technologies * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ + */ #include <linux/module.h> #include <linux/rtc.h> #include "rtc-core.h" - /* device attributes */ /* @@ -86,7 +82,7 @@ max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t max_user_freq_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) + const char *buf, size_t n) { struct rtc_device *rtc = to_rtc_device(dev); unsigned long val; @@ -116,12 +112,11 @@ hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) { #ifdef CONFIG_RTC_HCTOSYS_DEVICE if (rtc_hctosys_ret == 0 && - strcmp(dev_name(&to_rtc_device(dev)->dev), - CONFIG_RTC_HCTOSYS_DEVICE) == 0) + strcmp(dev_name(&to_rtc_device(dev)->dev), + CONFIG_RTC_HCTOSYS_DEVICE) == 0) return sprintf(buf, "1\n"); - else #endif - return sprintf(buf, "0\n"); + return sprintf(buf, "0\n"); } static DEVICE_ATTR_RO(hctosys); @@ -175,15 +170,15 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, if (*buf_ptr == '=') { buf_ptr++; push = 1; - } else + } else { adjust = 1; + } } retval = kstrtos64(buf_ptr, 0, &alarm); if (retval) return retval; - if (adjust) { + if (adjust) alarm += now; - } if (alarm > now || push) { /* Avoid accidentally clobbering active alarms; we can't * entirely prevent that here, without even the minimal diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c index 718293d72426..8b70f0520e13 100644 --- a/drivers/rtc/systohc.c +++ b/drivers/rtc/systohc.c @@ -1,9 +1,4 @@ -/* - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0 #include <linux/rtc.h> #include <linux/time.h> @@ -35,8 +30,7 @@ int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec) if (!rtc) goto out_err; - if (!rtc->ops || (!rtc->ops->set_time && !rtc->ops->set_mmss64 && - !rtc->ops->set_mmss)) + if (!rtc->ops || !rtc->ops->set_time) goto out_close; /* Compute the value of tv_nsec we require the caller to supply in @@ -58,9 +52,6 @@ int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec) rtc_time64_to_tm(to_set.tv_sec, &tm); - /* rtc_hctosys exclusively uses UTC, so we call set_time here, not - * set_mmss. - */ err = rtc_set_time(rtc, &tm); out_close: |