From c50156526a2f7176b50134e3e5fb108ba09791b2 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 31 Oct 2018 17:55:02 -0700 Subject: rtc: omap: Use define directive for PIN_CONFIG_ACTIVE_HIGH Clang warns when one enumerated type is implicitly converted to another: drivers/rtc/rtc-omap.c:574:21: warning: implicit conversion from enumeration type 'enum rtc_pin_config_param' to different enumeration type 'enum pin_config_param' [-Wenum-conversion] {"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0}, ~ ^~~~~~~~~~~~~~~~~~~~~~ drivers/rtc/rtc-omap.c:579:12: warning: implicit conversion from enumeration type 'enum rtc_pin_config_param' to different enumeration type 'enum pin_config_param' [-Wenum-conversion] PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false), ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/pinctrl/pinconf-generic.h:163:11: note: expanded from macro 'PCONFDUMP' .param = a, .display = b, .format = c, .has_arg = d \ ^ 2 warnings generated. It is expected that pinctrl drivers can extend pin_config_param because of the gap between PIN_CONFIG_END and PIN_CONFIG_MAX so this conversion isn't an issue. Most drivers that take advantage of this define the PIN_CONFIG variables as constants, rather than enumerated values. Do the same thing here so that Clang no longer warns. Link: https://github.com/ClangBuiltLinux/linux/issues/144 Signed-off-by: Nathan Chancellor Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 320b4a520eb3..bbff0e2deb84 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -566,9 +566,7 @@ static const struct pinctrl_ops rtc_pinctrl_ops = { .dt_free_map = pinconf_generic_dt_free_map, }; -enum rtc_pin_config_param { - PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1, -}; +#define PIN_CONFIG_ACTIVE_HIGH (PIN_CONFIG_END + 1) static const struct pinconf_generic_params rtc_params[] = { {"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0}, -- cgit From 725412d9e07aad88767ad847dcc81d60b617af99 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 1 Nov 2018 14:53:52 +0000 Subject: rtc: clean up indentation issues, remove extraneous space, add missing tabs Trivial fix to clean up indentation issues, remove spaces, add missing tabs Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ep93xx.c | 2 +- drivers/rtc/rtc-max6916.c | 2 +- drivers/rtc/rtc-rk808.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 694038208745..1932a4f861d1 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -61,7 +61,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); unsigned long time; - time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); + time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); rtc_time_to_tm(time, tm); return 0; diff --git a/drivers/rtc/rtc-max6916.c b/drivers/rtc/rtc-max6916.c index 7e908a490cf6..9d4b407cc4b8 100644 --- a/drivers/rtc/rtc-max6916.c +++ b/drivers/rtc/rtc-max6916.c @@ -86,7 +86,7 @@ static int max6916_set_time(struct device *dev, struct rtc_time *dt) if (dt->tm_year < 100 || dt->tm_year > 199) { dev_err(&spi->dev, "Year must be between 2000 and 2099. It's %d.\n", dt->tm_year + 1900); - return -EINVAL; + return -EINVAL; } buf[0] = MAX6916_CLOCK_BURST & 0x7F; diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c index 739c0d42e835..b2f9e45e0298 100644 --- a/drivers/rtc/rtc-rk808.c +++ b/drivers/rtc/rtc-rk808.c @@ -400,7 +400,7 @@ static int rk808_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to write RTC status: %d\n", ret); - return ret; + return ret; } device_init_wakeup(&pdev->dev, 1); -- cgit From 4ff6f0249e213eab98828b2d19e896a143fc7e28 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Nov 2018 06:43:22 +0000 Subject: rtc: sh: convert to SPDX identifiers This patch updates license to use SPDX-License-Identifier instead of verbose license text. As original license mentioned, it is GPL-2.0 in SPDX. Then, MODULE_LICENSE() should be "GPL v2" instead of "GPL". See ${LINUX}/include/linux/module.h "GPL" [GNU Public License v2 or later] "GPL v2" [GNU Public License v2] Signed-off-by: Kuninori Morimoto Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sh.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 51ba414798a8..d417b203cbc5 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH On-Chip RTC Support * @@ -9,10 +10,6 @@ * * Copyright (C) 2000 Philipp Rumpf * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka - * - * 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. */ #include #include @@ -681,5 +678,5 @@ MODULE_DESCRIPTION("SuperH on-chip RTC driver"); MODULE_AUTHOR("Paul Mundt , " "Jamie Lenehan , " "Angelo Castello "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); -- cgit From 03f39f47dc86fc4defbf9b97f8417f192d1ccba6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 10 Nov 2018 21:25:44 +0100 Subject: rtc: class: remove devm_rtc_device_unregister devm_rtc_device_unregister is not used by any driver and should not be used by any new driver. Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 26 -------------------------- include/linux/rtc.h | 2 -- 2 files changed, 28 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 3b43787f154b..6d364085bd86 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -380,13 +380,6 @@ static void devm_rtc_device_release(struct device *dev, void *res) rtc_device_unregister(rtc); } -static int devm_rtc_device_match(struct device *dev, void *res, void *data) -{ - struct rtc **r = res; - - return *r == data; -} - /** * devm_rtc_device_register - resource managed rtc_device_register() * @dev: the device to register @@ -424,25 +417,6 @@ struct rtc_device *devm_rtc_device_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_rtc_device_register); -/** - * devm_rtc_device_unregister - resource managed devm_rtc_device_unregister() - * @dev: the device to unregister - * @rtc: the RTC class device to unregister - * - * Deallocated a rtc allocated with devm_rtc_device_register(). Normally this - * function will not need to be called and the resource management code will - * ensure that the resource is freed. - */ -void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc) -{ - int rc; - - rc = devres_release(dev, devm_rtc_device_release, - devm_rtc_device_match, rtc); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_rtc_device_unregister); - static void devm_rtc_release_device(struct device *dev, void *res) { struct rtc_device *rtc = *(struct rtc_device **)res; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index c8bb4a2b48c3..311375dbb673 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -173,8 +173,6 @@ extern struct rtc_device *devm_rtc_device_register(struct device *dev, struct module *owner); struct rtc_device *devm_rtc_allocate_device(struct device *dev); int __rtc_register_device(struct module *owner, struct rtc_device *rtc); -extern void devm_rtc_device_unregister(struct device *dev, - struct rtc_device *rtc); extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); -- cgit From 3cc9ffbb1f51eb4320575a48e4805a8f52e0e26b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 7 Nov 2018 02:39:13 +0000 Subject: rtc: m41t80: Correct alarm month range with RTC reads Add the missing adjustment of the month range on alarm reads from the RTC, correcting an issue coming from commit 9c6dfed92c3e ("rtc: m41t80: add alarm functionality"). The range is 1-12 for hardware and 0-11 for `struct rtc_time', and is already correctly handled on alarm writes to the RTC. It was correct up until commit 48e9766726eb ("drivers/rtc/rtc-m41t80.c: remove disabled alarm functionality") too, which removed the previous implementation of alarm support. Signed-off-by: Maciej W. Rozycki Fixes: 9c6dfed92c3e ("rtc: m41t80: add alarm functionality") References: 48e9766726eb ("drivers/rtc/rtc-m41t80.c: remove disabled alarm functionality") Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m41t80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index a3fb235fea0d..7431a795a624 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -393,7 +393,7 @@ static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_min = bcd2bin(alarmvals[3] & 0x7f); alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f); alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f); - alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f); + alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f) - 1; alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE); alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled; -- cgit From f1bd154d8838f9bddbe0f07292dd1c70a47c8b83 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 7 Nov 2018 02:39:51 +0000 Subject: rtc: m41t80: Complete error propagation from SMBus calls Complement commit 85d77047c4ea ("drivers/rtc/rtc-m41t80.c: propagate error value from smbus functions") and correct the remaining places that fail to propagate the error code from SMBus calls. Signed-off-by: Maciej W. Rozycki References: 85d77047c4ea ("drivers/rtc/rtc-m41t80.c: propagate error value from smbus functions") Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m41t80.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 7431a795a624..a39138932379 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -217,7 +217,7 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm) sizeof(buf), buf); if (err < 0) { dev_err(&client->dev, "Unable to read date\n"); - return -EIO; + return err; } tm->tm_sec = bcd2bin(buf[M41T80_REG_SEC] & 0x7f); @@ -274,10 +274,11 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) if (flags < 0) return flags; - if (i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, - flags & ~M41T80_FLAGS_OF)) { + err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, + flags & ~M41T80_FLAGS_OF); + if (err < 0) { dev_err(&client->dev, "Unable to write flags register\n"); - return -EIO; + return err; } return err; @@ -287,10 +288,12 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq) { struct i2c_client *client = to_i2c_client(dev); struct m41t80_data *clientdata = i2c_get_clientdata(client); - u8 reg; + int reg; if (clientdata->features & M41T80_FEATURE_BL) { reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); + if (reg < 0) + return reg; seq_printf(seq, "battery\t\t: %s\n", (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok"); } -- cgit From 50c8aec4212a966817e868056efc9bfbb73337c0 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 13 Nov 2018 12:32:50 +0100 Subject: rtc: s3c-rtc: Avoid using broken ALMYEAR register (RTC,ALM)YEAR registers of Exynos built-in RTC device contains 3 BCD characters. s3c-rtc driver uses only 2 lower of them and supports years from 2000..2099 range. The third BCD value is typically set to 0, but it looks that handling of it is broken in the hardware. It sometimes defaults to a random (even non-BCD) value. This is not an issue for handling RTCYEAR register, because bcd2bin() properly handles only 8bit values (2 BCD characters, the third one is skipped). The problem is however with ALMYEAR register and proper RTC alarm operation. When YEAREN bit is set for the configured alarm, RTC hardware triggers alarm only when ALMYEAR and RTCYEAR matches. This usually doesn't happen because of the random noise on the third BCD character. Fix this by simply skipping setting ALMYEAR register in alarm configuration. This workaround fixes broken alarm operation on Exynos built-in rtc device. My tests revealed that the issue happens on the following Exynos series: 3250, 4210, 4412, 5250 and 5410. Signed-off-by: Marek Szyprowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 75c8c5033e08..58e03ac3578b 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -327,7 +327,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; unsigned int alrm_en; int ret; - int year = tm->tm_year - 100; dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, @@ -356,11 +355,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR); } - if (year < 100 && year >= 0) { - alrm_en |= S3C2410_RTCALM_YEAREN; - writeb(bin2bcd(year), info->base + S3C2410_ALMYEAR); - } - if (tm->tm_mon < 12 && tm->tm_mon >= 0) { alrm_en |= S3C2410_RTCALM_MONEN; writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON); -- cgit From b28cc6cec3d814f5184cbebb2d1f987e769f534a Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 14 Nov 2018 00:36:45 +0100 Subject: rtc: max77686: Fix the returned value in case of error in 'max77686_rtc_read_time()' In case of error, we return 0. This is spurious and not consistent with the other functions of the driver. Commit e115a2bf1426 has modified more than what is said in the commit message. Reverse part of it znd return an error when needed, as it was previously. Fixes: e115a2bf1426 ("rtc: max77686: stop validating rtc_time in .read_time") Signed-off-by: Christophe JAILLET Reviewed-by: Chanwoo Choi Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-max77686.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 8a60900d6b8b..4aff349ae301 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -360,7 +360,7 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) out: mutex_unlock(&info->lock); - return 0; + return ret; } static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) -- cgit From 461e557b97277b693cd8008c32a9d01c7f8f453b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 10 Nov 2018 21:29:02 +0100 Subject: rtc: nvmem: use devm_nvmem_register() Use the resource managed variant of nvmem_register(). Signed-off-by: Alexandre Belloni --- drivers/rtc/nvmem.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c index 36ab183c42f1..2a7220d8b02d 100644 --- a/drivers/rtc/nvmem.c +++ b/drivers/rtc/nvmem.c @@ -93,7 +93,7 @@ int rtc_nvmem_register(struct rtc_device *rtc, nvmem_config->dev = rtc->dev.parent; nvmem_config->owner = rtc->owner; - rtc->nvmem = nvmem_register(nvmem_config); + rtc->nvmem = devm_nvmem_register(rtc->dev.parent, nvmem_config); if (IS_ERR(rtc->nvmem)) return PTR_ERR(rtc->nvmem); @@ -107,12 +107,7 @@ EXPORT_SYMBOL_GPL(rtc_nvmem_register); void rtc_nvmem_unregister(struct rtc_device *rtc) { - if (IS_ERR_OR_NULL(rtc->nvmem)) - return; - /* unregister the old ABI */ if (rtc->nvram) rtc_nvram_unregister(rtc); - - nvmem_unregister(rtc->nvmem); } -- cgit From 41c9e132c5cc3e5f28cf44032ff82f7614a42989 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 10 Nov 2018 21:29:03 +0100 Subject: rtc: nvmem: remove nvmem from struct rtc_device Using devm_nvmem_register allows to avoid tracking the nvmem pointer in the rtc_device structure. This ultimately allows to register multiple nvmem devices from an RTC driver. Signed-off-by: Alexandre Belloni --- drivers/rtc/nvmem.c | 24 ++++++++++-------------- include/linux/rtc.h | 1 - 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c index 2a7220d8b02d..ebdfe8e3a1a0 100644 --- a/drivers/rtc/nvmem.c +++ b/drivers/rtc/nvmem.c @@ -25,11 +25,9 @@ rtc_nvram_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct rtc_device *rtc = attr->private; - dev_warn_once(kobj_to_dev(kobj), nvram_warning); - return nvmem_device_read(rtc->nvmem, off, count, buf); + return nvmem_device_read(attr->private, off, count, buf); } static ssize_t @@ -37,14 +35,13 @@ rtc_nvram_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct rtc_device *rtc = attr->private; - dev_warn_once(kobj_to_dev(kobj), nvram_warning); - return nvmem_device_write(rtc->nvmem, off, count, buf); + return nvmem_device_write(attr->private, off, count, buf); } -static int rtc_nvram_register(struct rtc_device *rtc, size_t size) +static int rtc_nvram_register(struct rtc_device *rtc, + struct nvmem_device *nvmem, size_t size) { int err; @@ -56,7 +53,7 @@ static int rtc_nvram_register(struct rtc_device *rtc, size_t size) rtc->nvram->attr.name = "nvram"; rtc->nvram->attr.mode = 0644; - rtc->nvram->private = rtc; + rtc->nvram->private = nvmem; sysfs_bin_attr_init(rtc->nvram); @@ -85,21 +82,20 @@ static void rtc_nvram_unregister(struct rtc_device *rtc) int rtc_nvmem_register(struct rtc_device *rtc, struct nvmem_config *nvmem_config) { - if (!IS_ERR_OR_NULL(rtc->nvmem)) - return -EBUSY; + struct nvmem_device *nvmem; if (!nvmem_config) return -ENODEV; nvmem_config->dev = rtc->dev.parent; nvmem_config->owner = rtc->owner; - rtc->nvmem = devm_nvmem_register(rtc->dev.parent, nvmem_config); - if (IS_ERR(rtc->nvmem)) - return PTR_ERR(rtc->nvmem); + nvmem = devm_nvmem_register(rtc->dev.parent, nvmem_config); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); /* Register the old ABI */ if (rtc->nvram_old_abi) - rtc_nvram_register(rtc, nvmem_config->size); + rtc_nvram_register(rtc, nvmem, nvmem_config->size); return 0; } diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 311375dbb673..58147b057acd 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -138,7 +138,6 @@ struct rtc_device { bool registered; - struct nvmem_device *nvmem; /* Old ABI support */ bool nvram_old_abi; struct bin_attribute *nvram; -- cgit From 41ef3878203cd9218d92eaa07df4b85a2cb128fb Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 14 Nov 2018 18:19:51 +0100 Subject: rtc: max8997: Fix the returned value in case of error in 'max8997_rtc_read_alarm()' In case of error, we return 0. This is spurious and not consistent with the other functions of the driver. Propagate the error code instead. Signed-off-by: Christophe JAILLET Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-max8997.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index 08c661a332ec..20e50d9fdf88 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -215,7 +215,7 @@ static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) out: mutex_unlock(&info->lock); - return 0; + return ret; } static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info) -- cgit From facc23b8ff21e9fb328938baf15ae68a91af0cb9 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 15 Nov 2018 18:51:18 +0000 Subject: rtc: isl1208: Use i2c block read/write routines The Linux i2c layer has functions to execute common SMBUS/I2C transactions. The register access code here is identical to the I2C read/write block data routines. Cc: Alessandro Zummo Cc: Alexandre Belloni Signed-off-by: Trent Piepho Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index ec5ef518a09b..37ab3e1d25f5 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -84,29 +84,13 @@ static int isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], unsigned len) { - u8 reg_addr[1] = { reg }; - struct i2c_msg msgs[2] = { - { - .addr = client->addr, - .len = sizeof(reg_addr), - .buf = reg_addr - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf - } - }; int ret; WARN_ON(reg > ISL1219_REG_YRT); WARN_ON(reg + len > ISL1219_REG_YRT + 1); - ret = i2c_transfer(client->adapter, msgs, 2); - if (ret > 0) - ret = 0; - return ret; + ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf); + return (ret < 0) ? ret : 0; } /* block write */ @@ -114,26 +98,13 @@ static int isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], unsigned len) { - u8 i2c_buf[ISL1208_REG_USR2 + 2]; - struct i2c_msg msgs[1] = { - { - .addr = client->addr, - .len = len + 1, - .buf = i2c_buf - } - }; int ret; WARN_ON(reg > ISL1219_REG_YRT); WARN_ON(reg + len > ISL1219_REG_YRT + 1); - i2c_buf[0] = reg; - memcpy(&i2c_buf[1], &buf[0], len); - - ret = i2c_transfer(client->adapter, msgs, 1); - if (ret > 0) - ret = 0; - return ret; + ret = i2c_smbus_write_i2c_block_data(client, reg, len, buf); + return (ret < 0) ? ret : 0; } /* simple check to see whether we have a isl1208 */ -- cgit From 73852e56827f5cb5db9d6e8dd8191fc2f2e8f424 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 19 Nov 2018 14:34:02 +0200 Subject: rtc: dt-binding: abx80x: fix resistance scale The abracon,tc-resistor property value is in kOhm. Signed-off-by: Baruch Siach Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/abracon,abx80x.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt b/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt index be789685a1c2..18b892d010d8 100644 --- a/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt +++ b/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt @@ -27,4 +27,4 @@ and valid to enable charging: - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V) - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output - resistor, the other values are in ohm. + resistor, the other values are in kOhm. -- cgit From 9ca22651e134c5d33b8776b63bf7384f8686b5f6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:12 +0800 Subject: dt-bindings: rtc: sun6i-rtc: Rewrite clock outputs as a list The clock output section for this binding describes the two outputs in the descriptions for both the #clock-cells and clock-output-names properties. Instead of overlapping information that is hard to read, rewrite the clock outputs as a list of indices and descriptions. The properies can reference this list instead. This will also make it easier to add notes or conditions to the clocks, and also for adding new outputs. Acked-by: Maxime Ripard Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/sun6i-rtc.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt index 12c083c1140a..d3e96459fc66 100644 --- a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt @@ -10,10 +10,12 @@ Required properties: Required properties for new device trees - clocks : phandle to the 32kHz external oscillator -- clock-output-names : names of the LOSC and its external output clocks created -- #clock-cells : must be equals to 1. The RTC provides two clocks: the - LOSC and its external output, with index 0 and 1 - respectively. +- clock-output-names : names of the two clock outputs. See below. +- #clock-cells : must be equal to 1. + +The RTC provides the following clocks at the given indices: +- 0: LOSC +- 1: LOSC external output, known as X32KFOUT in the datasheet. Example: -- cgit From 347d3570300ee961a5b51a02473761262b06980f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:13 +0800 Subject: dt-bindings: rtc: sun6i-rtc: Add compatible strings for pre-H6 variants While doing Bluetooth enablement for various boards based on various Allwinner SoCs, minor differences in the RTC modules were found. These include a lack of an external clock output (A31), different internal oscillator frequencies (H3/H5/A64/V3/V3s), different regulator voltage settings (H5/H6), and the presence of miscellaneous registers unrelated to the RTC (A64/R40/H5/H6). The datasheet also describes different number of registers for non-volatile storage, though based on actual experiments the actual number is the same across the board. This patch adds a list of all pre-H6 variants, grouped by the internal oscillator's clock rate, regulator settings, and the presence of the external clock output. Combinations are introduced for the variants that have miscellaneous registers. The RTC block in the H6 also handles the 24 MHz DCXO. This will require more device tree binding changes and will be done later. Acked-by: Maxime Ripard Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/sun6i-rtc.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt index d3e96459fc66..b1eaa443347d 100644 --- a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt @@ -3,7 +3,21 @@ RTC controller for the Allwinner A31 Required properties: -- compatible : Should be "allwinner,sun6i-a31-rtc" +- compatible : Should be one of the following combinations: + - "allwinner,sun6i-a31-rtc" + - "allwinner,sun8i-a23-rtc" + - "allwinner,sun8i-h3-rtc" + - "allwinner,sun8i-r40-rtc", "allwinner,sun8i-h3-rtc" + - "allwinner,sun8i-v3-rtc" + - "allwinner,sun50i-a64-rtc", "allwinner,sun8i-h3-rtc" + - "allwinner,sun50i-h5-rtc" + + Where there are two or more compatible strings, this + denotes the hardware covered by the most specific one + is backward-compatible with the latter ones, and the + implementation for the latter ones can be used, albeit + with reduced functionality. + - reg : physical base address of the controller and length of memory mapped region. - interrupts : IRQ lines for the RTC alarm 0 and alarm 1, in that order. -- cgit From 5a0923aad7d466b683e52b766290dcdc02453e1b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:14 +0800 Subject: dt-bindings: rtc: sun6i-rtc: Deprecate external clock output for A31 The A31 does not have an external clock output directly from the RTC. Instead, it has four muxable clock outputs: three (A, B, C) are controlled from the CCU, and the last (D) is controlled from the PRCM. Deprecate the usage of the external clock output for the A31 compatible. Acked-by: Maxime Ripard Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/sun6i-rtc.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt index b1eaa443347d..dba4d32cfbad 100644 --- a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt @@ -24,12 +24,14 @@ Required properties: Required properties for new device trees - clocks : phandle to the 32kHz external oscillator -- clock-output-names : names of the two clock outputs. See below. +- clock-output-names : names of up to two clock outputs. See below. - #clock-cells : must be equal to 1. The RTC provides the following clocks at the given indices: - 0: LOSC - 1: LOSC external output, known as X32KFOUT in the datasheet. + This clock is not available on the A31 and is deprecated for old + device trees still using the "allwinner,sun6i-a31-rtc" compatible. Example: @@ -37,7 +39,7 @@ rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; reg = <0x01f00000 0x54>; interrupts = <0 40 4>, <0 41 4>; - clock-output-names = "osc32k", "osc32k-out"; + clock-output-names = "osc32k"; clocks = <&ext_osc32k>; #clock-cells = <1>; }; -- cgit From 9cd3558678385329709b6d52f639d1f918e04aae Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:15 +0800 Subject: dt-bindings: rtc: sun6i-rtc: Export internal RC oscillator Experiments showed that on at least the H3/H5/A64 the RTC's internal oscillator also feeds the CPUS mux in the PRCM. Export this clock through the device tree, instead of having to use a dummy fixed-clock device node, for the PRCM to consume. This will properly describe the relationship between the clocks. Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/sun6i-rtc.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt index dba4d32cfbad..ceb38abf1ea2 100644 --- a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt @@ -24,7 +24,7 @@ Required properties: Required properties for new device trees - clocks : phandle to the 32kHz external oscillator -- clock-output-names : names of up to two clock outputs. See below. +- clock-output-names : names of up to three clock outputs. See below. - #clock-cells : must be equal to 1. The RTC provides the following clocks at the given indices: @@ -32,6 +32,7 @@ The RTC provides the following clocks at the given indices: - 1: LOSC external output, known as X32KFOUT in the datasheet. This clock is not available on the A31 and is deprecated for old device trees still using the "allwinner,sun6i-a31-rtc" compatible. +- 2: InternalOSC, or internal RC oscillator (A64/H3/H5 only) Example: -- cgit From 459b6ea00acccaac9cd25ba12d55b5fe7d8583df Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:16 +0800 Subject: rtc: sun6i: Add default clock name for LOSC The RTC's main clock, used internally and exported to the rest of the SoC, is called "LOSC" (low speed oscillator) through the hardware documentation. This patch adds a default name for this clock, in case the device tree does not provide one. This shouldn't happen, but lets play it safe. Acked-by: Maxime Ripard Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index fe07310952df..8edd9e1ec007 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -191,6 +191,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) struct sun6i_rtc_dev *rtc; struct clk_init_data init = { .ops = &sun6i_rtc_osc_ops, + .name = "losc", }; const char *clkout_name = "osc32k-out"; const char *parents[2]; -- cgit From 403a3c3dd0ec93c2504b94667d16485729fc0393 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:17 +0800 Subject: rtc: sun6i: Add support for different variants Amongst the Allwinner SoCs that have seen some kind of coverage by the linux-sunxi community, whether it be mainline Linux or U-boot support, or just available datasheets, most newer chips use the RTC design first seen in the A31 (sun6i). Overall there have been some minor differences. This patch covers the following: - average clock rate of the internal RC oscillator + presence of fixed and adjustable prescaler for this clock - availability of an external (to the SoC) clock output One major difference regarding the H6 is the 24 MHz crystal is now routed through the RTC, as a digitally compensated oscillator (DCXO). This is not covered in this patch and will be supported later. Other differences are either unrelated to RTC or clock functionality, such as boot or crypto related registers, or the driver simply doesn't use the feature in question. One example of the latter is the calibration function for the RC oscillator. We consider this clock to be very bad and avoid using it. Acked-by: Maxime Ripard Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 8edd9e1ec007..d1866d90b9ef 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -118,9 +118,30 @@ #define SUN6I_YEAR_MAX 2033 #define SUN6I_YEAR_OFF (SUN6I_YEAR_MIN - 1900) +/* + * There are other differences between models, including: + * + * - number of GPIO pins that can be configured to hold a certain level + * - crypto-key related registers (H5, H6) + * - boot process related (super standby, secondary processor entry address) + * registers (R40, H6) + * - SYS power domain controls (R40) + * - DCXO controls (H6) + * - RC oscillator calibration (H6) + * + * These functions are not covered by this driver. + */ +struct sun6i_rtc_clk_data { + unsigned long rc_osc_rate; + unsigned int fixed_prescaler : 16; + unsigned int has_prescaler : 1; + unsigned int has_out_clk : 1; +}; + struct sun6i_rtc_dev { struct rtc_device *rtc; struct device *dev; + const struct sun6i_rtc_clk_data *data; void __iomem *base; int irq; unsigned long alarm; @@ -139,14 +160,19 @@ static unsigned long sun6i_rtc_osc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); - u32 val; + u32 val = 0; val = readl(rtc->base + SUN6I_LOSC_CTRL); if (val & SUN6I_LOSC_CTRL_EXT_OSC) return parent_rate; - val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL); - val &= GENMASK(4, 0); + if (rtc->data->fixed_prescaler) + parent_rate /= rtc->data->fixed_prescaler; + + if (rtc->data->has_prescaler) { + val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL); + val &= GENMASK(4, 0); + } return parent_rate / (val + 1); } @@ -185,7 +211,8 @@ static const struct clk_ops sun6i_rtc_osc_ops = { .set_parent = sun6i_rtc_osc_set_parent, }; -static void __init sun6i_rtc_clk_init(struct device_node *node) +static void __init sun6i_rtc_clk_init(struct device_node *node, + const struct sun6i_rtc_clk_data *data) { struct clk_hw_onecell_data *clk_data; struct sun6i_rtc_dev *rtc; @@ -200,6 +227,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) if (!rtc) return; + rtc->data = data; clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL); if (!clk_data) { kfree(rtc); @@ -228,7 +256,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, "rtc-int-osc", NULL, 0, - 667000, + rtc->data->rc_osc_rate, 300000000); if (IS_ERR(rtc->int_osc)) { pr_crit("Couldn't register the internal oscillator\n"); @@ -271,8 +299,18 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) err: kfree(clk_data); } -CLK_OF_DECLARE_DRIVER(sun6i_rtc_clk, "allwinner,sun6i-a31-rtc", - sun6i_rtc_clk_init); + +static const struct sun6i_rtc_clk_data sun6i_a31_rtc_data = { + .rc_osc_rate = 667000, /* datasheet says 600 ~ 700 KHz */ + .has_prescaler = 1, +}; + +static void __init sun6i_a31_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun6i_a31_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun6i_a31_rtc_clk, "allwinner,sun6i-a31-rtc", + sun6i_a31_rtc_clk_init); static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id) { @@ -579,6 +617,12 @@ static int sun6i_rtc_probe(struct platform_device *pdev) return 0; } +/* + * As far as RTC functionality goes, all models are the same. The + * datasheets claim that different models have different number of + * registers available for non-volatile storage, but experiments show + * that all SoCs have 16 registers available for this purpose. + */ static const struct of_device_id sun6i_rtc_dt_ids[] = { { .compatible = "allwinner,sun6i-a31-rtc" }, { /* sentinel */ }, -- cgit From 7cd1acaeea4e72e2926c23ac8db5ab376b2819a4 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:18 +0800 Subject: rtc: sun6i: Add support for all known pre-H6 variants There are different variants to the RTC hardware first seen on sun6i (A31). The differences we care about in this driver are the clock rate for the internal oscillator, prescalers, and the presence of an external clock output. This patch adds support for all the known pre-H6 base compatibles using the variants data structure previously introduced. Acked-by: Maxime Ripard Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index d1866d90b9ef..46609ae56ffd 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -312,6 +312,48 @@ static void __init sun6i_a31_rtc_clk_init(struct device_node *node) CLK_OF_DECLARE_DRIVER(sun6i_a31_rtc_clk, "allwinner,sun6i-a31-rtc", sun6i_a31_rtc_clk_init); +static const struct sun6i_rtc_clk_data sun8i_a23_rtc_data = { + .rc_osc_rate = 667000, /* datasheet says 600 ~ 700 KHz */ + .has_prescaler = 1, + .has_out_clk = 1, +}; + +static void __init sun8i_a23_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun8i_a23_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc", + sun8i_a23_rtc_clk_init); + +static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = { + .rc_osc_rate = 16000000, + .fixed_prescaler = 32, + .has_prescaler = 1, + .has_out_clk = 1, +}; + +static void __init sun8i_h3_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun8i_h3_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc", + sun8i_h3_rtc_clk_init); +/* As far as we are concerned, clocks for H5 are the same as H3 */ +CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc", + sun8i_h3_rtc_clk_init); + +static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = { + .rc_osc_rate = 32000, + .has_out_clk = 1, +}; + +static void __init sun8i_v3_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun8i_v3_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun8i_v3_rtc_clk, "allwinner,sun8i-v3-rtc", + sun8i_v3_rtc_clk_init); + static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id) { struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id; @@ -625,6 +667,10 @@ static int sun6i_rtc_probe(struct platform_device *pdev) */ 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-v3-rtc" }, + { .compatible = "allwinner,sun50i-h5-rtc" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids); -- cgit From c56afc1844d6a8a050d73eda1a59d286e1d5bc04 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 3 Dec 2018 22:58:19 +0800 Subject: rtc: sun6i: Expose internal oscillator through device tree The bindings have been updated to expose the RTC's internal oscillator, for some SoCs that have it directly feeding the PRCM block. The changes include the index 2 for the clock outputs, as well as the clock output names. This patch adds the internal oscillator to the list of clocks exposed through of_clk_add_hw_provider(), and also have the driver optionally fetch the name of the clock from the device tree if it's available. Tested-by: Corentin Labbe Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 46609ae56ffd..11f56de52179 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -136,6 +136,7 @@ struct sun6i_rtc_clk_data { unsigned int fixed_prescaler : 16; unsigned int has_prescaler : 1; unsigned int has_out_clk : 1; + unsigned int export_iosc : 1; }; struct sun6i_rtc_dev { @@ -220,6 +221,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, .ops = &sun6i_rtc_osc_ops, .name = "losc", }; + const char *iosc_name = "rtc-int-osc"; const char *clkout_name = "osc32k-out"; const char *parents[2]; @@ -228,7 +230,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, return; rtc->data = data; - clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, 3), GFP_KERNEL); if (!clk_data) { kfree(rtc); return; @@ -253,8 +255,13 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, if (!of_get_property(node, "clocks", NULL)) goto err; + /* Only read IOSC name from device tree if it is exported */ + if (rtc->data->export_iosc) + of_property_read_string_index(node, "clock-output-names", 2, + &iosc_name); + rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, - "rtc-int-osc", + iosc_name, NULL, 0, rtc->data->rc_osc_rate, 300000000); @@ -293,6 +300,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, clk_data->num = 2; clk_data->hws[0] = &rtc->hw; clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); + if (rtc->data->export_iosc) { + clk_data->hws[2] = rtc->int_osc; + clk_data->num = 3; + } of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); return; @@ -330,6 +341,7 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = { .fixed_prescaler = 32, .has_prescaler = 1, .has_out_clk = 1, + .export_iosc = 1, }; static void __init sun8i_h3_rtc_clk_init(struct device_node *node) -- cgit From 8c4cf161a8b42749e986a3503f6cd4f3b5682fe3 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Dec 2018 16:47:19 +0800 Subject: dt-bindings: rtc: sun6i-rtc: Fix register range in example The register range for the RTC extends beyond 0x54. Use the size from the user manual's memory map instead. Fixes: 9765d2d94309 ("rtc: sun6i: Add sun6i RTC driver") Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/sun6i-rtc.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt index ceb38abf1ea2..6b732c41392b 100644 --- a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt @@ -38,7 +38,7 @@ Example: rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; - reg = <0x01f00000 0x54>; + reg = <0x01f00000 0x400>; interrupts = <0 40 4>, <0 41 4>; clock-output-names = "osc32k"; clocks = <&ext_osc32k>; -- cgit From 4d42c44727a062e233e446c6c86da1c84d762d79 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:11 +0200 Subject: lib/vsprintf: Print time and date in human readable format via %pt There are users which print time and date represented by content of struct rtc_time in human readable format. Instead of open coding that each time introduce %ptR[dt][r] specifier. Cc: Arnd Bergmann Cc: Bartlomiej Zolnierkiewicz Cc: Dmitry Torokhov Cc: Geert Uytterhoeven Cc: Guan Xuetao Cc: Ingo Molnar Cc: Jason Wessel Cc: Jonathan Corbet Cc: Jonathan Hunter Cc: Krzysztof Kozlowski Cc: "Rafael J. Wysocki" Cc: Thierry Reding Cc: Petr Mladek Signed-off-by: Andy Shevchenko Reviewed-by: Petr Mladek Signed-off-by: Alexandre Belloni --- Documentation/core-api/printk-formats.rst | 18 ++++++ lib/test_printf.c | 61 +++++++++++++++++- lib/vsprintf.c | 100 ++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 3 deletions(-) diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index ff48b55040ef..a7fae4538946 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -412,6 +412,24 @@ Examples:: Passed by reference. +Time and date (struct rtc_time) +------------------------------- + +:: + + %ptR YYYY-mm-ddTHH:MM:SS + %ptRd YYYY-mm-dd + %ptRt HH:MM:SS + %ptR[dt][r] + +For printing date and time as represented by struct rtc_time structure in +human readable format. + +By default year will be incremented by 1900 and month by 1. Use %ptRr (raw) +to suppress this behaviour. + +Passed by reference. + struct clk ---------- diff --git a/lib/test_printf.c b/lib/test_printf.c index 53527ea822b5..659b6cc0d483 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -249,12 +250,11 @@ plain_format(void) #endif /* BITS_PER_LONG == 64 */ static int __init -plain_hash(void) +plain_hash_to_buffer(const void *p, char *buf, size_t len) { - char buf[PLAIN_BUF_SIZE]; int nchars; - nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); + nchars = snprintf(buf, len, "%p", p); if (nchars != PTR_WIDTH) return -1; @@ -265,6 +265,20 @@ plain_hash(void) return 0; } + return 0; +} + + +static int __init +plain_hash(void) +{ + char buf[PLAIN_BUF_SIZE]; + int ret; + + ret = plain_hash_to_buffer(PTR, buf, PLAIN_BUF_SIZE); + if (ret) + return ret; + if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0) return -1; @@ -294,6 +308,23 @@ plain(void) } } +static void __init +test_hashed(const char *fmt, const void *p) +{ + char buf[PLAIN_BUF_SIZE]; + int ret; + + /* + * No need to increase failed test counter since this is assumed + * to be called after plain(). + */ + ret = plain_hash_to_buffer(p, buf, PLAIN_BUF_SIZE); + if (ret) + return; + + test(buf, fmt, p); +} + static void __init symbol_ptr(void) { @@ -418,6 +449,29 @@ struct_va_format(void) { } +static void __init +struct_rtc_time(void) +{ + /* 1543210543 */ + const struct rtc_time tm = { + .tm_sec = 43, + .tm_min = 35, + .tm_hour = 5, + .tm_mday = 26, + .tm_mon = 10, + .tm_year = 118, + }; + + test_hashed("%pt", &tm); + + test("2018-11-26T05:35:43", "%ptR", &tm); + test("0118-10-26T05:35:43", "%ptRr", &tm); + test("05:35:43|2018-11-26", "%ptRt|%ptRd", &tm, &tm); + test("05:35:43|0118-10-26", "%ptRtr|%ptRdr", &tm, &tm); + test("05:35:43|2018-11-26", "%ptRttr|%ptRdtr", &tm, &tm); + test("05:35:43 tr|2018-11-26 tr", "%ptRt tr|%ptRd tr", &tm, &tm); +} + static void __init struct_clk(void) { @@ -529,6 +583,7 @@ test_pointer(void) uuid(); dentry(); struct_va_format(); + struct_rtc_time(); struct_clk(); bitmap(); netdev_features(); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 37a54a6dd594..3add92329bae 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -822,6 +823,20 @@ static const struct printf_spec default_dec_spec = { .precision = -1, }; +static const struct printf_spec default_dec02_spec = { + .base = 10, + .field_width = 2, + .precision = -1, + .flags = ZEROPAD, +}; + +static const struct printf_spec default_dec04_spec = { + .base = 10, + .field_width = 4, + .precision = -1, + .flags = ZEROPAD, +}; + static noinline_for_stack char *resource_string(char *buf, char *end, struct resource *res, struct printf_spec spec, const char *fmt) @@ -1549,6 +1564,87 @@ char *address_val(char *buf, char *end, const void *addr, const char *fmt) return special_hex_number(buf, end, num, size); } +static noinline_for_stack +char *date_str(char *buf, char *end, const struct rtc_time *tm, bool r) +{ + int year = tm->tm_year + (r ? 0 : 1900); + int mon = tm->tm_mon + (r ? 0 : 1); + + buf = number(buf, end, year, default_dec04_spec); + if (buf < end) + *buf = '-'; + buf++; + + buf = number(buf, end, mon, default_dec02_spec); + if (buf < end) + *buf = '-'; + buf++; + + return number(buf, end, tm->tm_mday, default_dec02_spec); +} + +static noinline_for_stack +char *time_str(char *buf, char *end, const struct rtc_time *tm, bool r) +{ + buf = number(buf, end, tm->tm_hour, default_dec02_spec); + if (buf < end) + *buf = ':'; + buf++; + + buf = number(buf, end, tm->tm_min, default_dec02_spec); + if (buf < end) + *buf = ':'; + buf++; + + return number(buf, end, tm->tm_sec, default_dec02_spec); +} + +static noinline_for_stack +char *rtc_str(char *buf, char *end, const struct rtc_time *tm, const char *fmt) +{ + bool have_t = true, have_d = true; + bool raw = false; + int count = 2; + + switch (fmt[count]) { + case 'd': + have_t = false; + count++; + break; + case 't': + have_d = false; + count++; + break; + } + + raw = fmt[count] == 'r'; + + if (have_d) + buf = date_str(buf, end, tm, raw); + if (have_d && have_t) { + /* Respect ISO 8601 */ + if (buf < end) + *buf = 'T'; + buf++; + } + if (have_t) + buf = time_str(buf, end, tm, raw); + + return buf; +} + +static noinline_for_stack +char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, + const char *fmt) +{ + switch (fmt[1]) { + case 'R': + return rtc_str(buf, end, (const struct rtc_time *)ptr, fmt); + default: + return ptr_to_id(buf, end, ptr, spec); + } +} + static noinline_for_stack char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, const char *fmt) @@ -1828,6 +1924,8 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, * - 'd[234]' For a dentry name (optionally 2-4 last components) * - 'D[234]' Same as 'd' but for a struct file * - 'g' For block_device name (gendisk + partition number) + * - 't[R][dt][r]' For time and date as represented: + * R struct rtc_time * - 'C' For a clock, it prints the name (Common Clock Framework) or address * (legacy clock framework) of the clock * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address @@ -1952,6 +2050,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, return address_val(buf, end, ptr, fmt); case 'd': return dentry_name(buf, end, ptr, spec, fmt); + case 't': + return time_and_date(buf, end, ptr, spec, fmt); case 'C': return clock(buf, end, ptr, spec, fmt); case 'D': -- cgit From 5548cbf7f148b9a039b19fa4697f1b9beaba2c78 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:12 +0200 Subject: rtc: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Note, we drop the validation option. This is only used in a deprecated ABI and is mostly wrong as many RTCs will still be valid after 2100. Cc: Arnd Bergmann Acked-by: Greg Kroah-Hartman Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/char/rtc.c | 7 +++---- drivers/rtc/hctosys.c | 8 ++------ drivers/rtc/interface.c | 8 ++------ drivers/rtc/rtc-proc.c | 36 +++++------------------------------- drivers/rtc/rtc-sysfs.c | 16 ++++++---------- 5 files changed, 18 insertions(+), 57 deletions(-) diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 4948c8bda6b1..0cde96822a87 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -1125,11 +1125,10 @@ static int rtc_proc_show(struct seq_file *seq, void *v) * time or for Universal Standard Time (GMT). Probably local though. */ seq_printf(seq, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n" "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + &tm, &tm, epoch); get_rtc_alm_time(&tm); diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index e79f2a181ad2..23efbe6949a3 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -56,12 +56,8 @@ static int __init rtc_hctosys(void) err = do_settimeofday64(&tv64); - dev_info(rtc->dev.parent, - "setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%lld)\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (long long) tv64.tv_sec); + dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n", + &tm, (long long)tv64.tv_sec); err_read: rtc_class_close(rtc); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 612a83d3ddcc..e8d77b1eaeb2 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -368,12 +368,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = rtc_valid_tm(&alarm->time); done: - if (err) { - dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n", - alarm->time.tm_year + 1900, alarm->time.tm_mon + 1, - alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec); - } + if (err) + dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", &alarm->time); return err; } diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index a9dd9218fae2..4d74e4f4ff30 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -50,41 +50,15 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) err = rtc_read_time(rtc, &tm); if (err == 0) { seq_printf(seq, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n", + &tm, &tm); } err = rtc_read_alarm(rtc, &alrm); if (err == 0) { - seq_printf(seq, "alrm_time\t: "); - if ((unsigned int)alrm.time.tm_hour <= 24) - seq_printf(seq, "%02d:", alrm.time.tm_hour); - else - seq_printf(seq, "**:"); - if ((unsigned int)alrm.time.tm_min <= 59) - seq_printf(seq, "%02d:", alrm.time.tm_min); - else - seq_printf(seq, "**:"); - if ((unsigned int)alrm.time.tm_sec <= 59) - seq_printf(seq, "%02d\n", alrm.time.tm_sec); - else - seq_printf(seq, "**\n"); - - seq_printf(seq, "alrm_date\t: "); - if ((unsigned int)alrm.time.tm_year <= 200) - seq_printf(seq, "%04d-", alrm.time.tm_year + 1900); - else - seq_printf(seq, "****-"); - if ((unsigned int)alrm.time.tm_mon <= 11) - seq_printf(seq, "%02d-", alrm.time.tm_mon + 1); - else - seq_printf(seq, "**-"); - if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31) - seq_printf(seq, "%02d\n", alrm.time.tm_mday); - else - seq_printf(seq, "**\n"); + 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"); seq_printf(seq, "alrm_pending\t: %s\n", diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 9746c32eee2e..a8f22ee726bb 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -39,12 +39,10 @@ date_show(struct device *dev, struct device_attribute *attr, char *buf) struct rtc_time tm; retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval == 0) { - retval = sprintf(buf, "%04d-%02d-%02d\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - } + if (retval) + return retval; - return retval; + return sprintf(buf, "%ptRd\n", &tm); } static DEVICE_ATTR_RO(date); @@ -55,12 +53,10 @@ time_show(struct device *dev, struct device_attribute *attr, char *buf) struct rtc_time tm; retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval == 0) { - retval = sprintf(buf, "%02d:%02d:%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec); - } + if (retval) + return retval; - return retval; + return sprintf(buf, "%ptRt\n", &tm); } static DEVICE_ATTR_RO(time); -- cgit From d422f8835d29e1d0f915fe11fbfa61875df3508f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:13 +0200 Subject: rtc: at91rm9200: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91rm9200.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index caa71d04e989..862b993c3142 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -147,9 +147,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = tm->tm_year - 1900; - dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s(): %ptR\n", __func__, tm); return 0; } @@ -161,9 +159,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long cr; - dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s(): %ptR\n", __func__, tm); wait_for_completion(&at91_rtc_upd_rdy); @@ -209,8 +205,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM) ? 1 : 0; - dev_dbg(dev, "%s(): %02d-%02d %02d:%02d:%02d %sabled\n", __func__, - tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + dev_dbg(dev, "%s(): %ptR %sabled\n", __func__, tm, alrm->enabled ? "en" : "dis"); return 0; @@ -247,9 +242,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) at91_rtc_write_ier(AT91_RTC_ALARM); } - dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, - tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec); + dev_dbg(dev, "%s(): %ptR\n", __func__, &tm); return 0; } -- cgit From 285166cb8c77a01c510f05003cb38efcd2a66740 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:14 +0200 Subject: rtc: at91sam9: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91sam9.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index ee71e647fd43..1d31c0ae6334 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -124,9 +124,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) rtc_time_to_tm(offset + secs, tm); - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); return 0; } @@ -141,9 +139,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) u32 offset, alarm, mr; unsigned long secs; - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); err = rtc_tm_to_time(tm, &secs); if (err != 0) @@ -199,9 +195,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alarm != ALARM_DISABLED && offset != 0) { rtc_time_to_tm(offset + alarm, tm); - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN) alrm->enabled = 1; @@ -242,9 +236,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alrm->enabled) rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm", - tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, - tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); return 0; } -- cgit From 22b844ae3318fa4bc097cf24d30b6512f198ebae Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:15 +0200 Subject: rtc: m41t80: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m41t80.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index a39138932379..ebf50b1540f2 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -942,11 +942,7 @@ static int m41t80_probe(struct i2c_client *client, if (m41t80_data->features & M41T80_FEATURE_HT) { m41t80_rtc_read_time(&client->dev, &tm); dev_info(&client->dev, "HT bit was set!\n"); - dev_info(&client->dev, - "Power Down at %04i-%02i-%02i %02i:%02i:%02i\n", - tm.tm_year + 1900, - tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec); + dev_info(&client->dev, "Power Down at %ptR\n", &tm); } rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR, rc & ~M41T80_ALHOUR_HT); -- cgit From ad78343e40cb03f3eb8d713ed67ca8a5941967da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:16 +0200 Subject: rtc: m48t59: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t59.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index ac9ca1042889..3c8ad1cdfd7c 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -99,9 +99,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); spin_unlock_irqrestore(&m48t59->lock, flags); - dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n", - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC read time %ptR\n", tm); return 0; } @@ -188,9 +186,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); spin_unlock_irqrestore(&m48t59->lock, flags); - dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n", - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC read alarm time %ptR\n", tm); return rtc_valid_tm(tm); } -- cgit From 1481376072460fee7f25f142f3e3dac81651dfb6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:17 +0200 Subject: rtc: mcp795: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 00e11c1b2186..f22a945a3794 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -233,9 +233,7 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim) if (ret) return ret; - dev_dbg(dev, "Set mcp795: %04d-%02d-%02d(%d) %02d:%02d:%02d\n", - tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, - tim->tm_wday, tim->tm_hour, tim->tm_min, tim->tm_sec); + dev_dbg(dev, "Set mcp795: %ptR\n", tim); return 0; } @@ -258,9 +256,7 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim) tim->tm_mon = bcd2bin(data[5] & 0x1F) - 1; tim->tm_year = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */ - dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d(%d) %02d:%02d:%02d\n", - tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, - tim->tm_wday, tim->tm_hour, tim->tm_min, tim->tm_sec); + dev_dbg(dev, "Read from mcp795: %ptR\n", tim); return 0; } @@ -319,9 +315,8 @@ static int mcp795_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return ret; dev_dbg(dev, "Alarm IRQ armed\n"); } - dev_dbg(dev, "Set alarm: %02d-%02d(%d) %02d:%02d:%02d\n", - alm->time.tm_mon, alm->time.tm_mday, alm->time.tm_wday, - alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec); + dev_dbg(dev, "Set alarm: %ptRdr(%d) %ptRt\n", + &alm->time, alm->time.tm_wday, &alm->time); return 0; } @@ -345,9 +340,8 @@ static int mcp795_read_alarm(struct device *dev, struct rtc_wkalrm *alm) alm->time.tm_isdst = -1; alm->time.tm_yday = -1; - dev_dbg(dev, "Read alarm: %02d-%02d(%d) %02d:%02d:%02d\n", - alm->time.tm_mon, alm->time.tm_mday, alm->time.tm_wday, - alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec); + dev_dbg(dev, "Read alarm: %ptRdr(%d) %ptRt\n", + &alm->time, alm->time.tm_wday, &alm->time); return 0; } -- cgit From 8d2e6b22bbc609d08f22d3a63541d978ad729c6d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:18 +0200 Subject: rtc: pcf50633: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf50633.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index ef72b0c389d7..0eb05b1d0b94 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -131,9 +131,7 @@ static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm) pcf2rtc_time(tm, &pcf_tm); - dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC_TIME: %ptRr\n", tm); return 0; } @@ -146,9 +144,7 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc = dev_get_drvdata(dev); - dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC_TIME: %ptRr\n", tm); rtc2pcf_time(&pcf_tm, tm); -- cgit From 93206f9315bba8a1c00fad5d9fe29bdb79938a5b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:19 +0200 Subject: rtc: pic32: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pic32.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c index 3c08eab4f1a8..d7ef0a6f8931 100644 --- a/drivers/rtc/rtc-pic32.c +++ b/drivers/rtc/rtc-pic32.c @@ -170,9 +170,7 @@ static int pic32_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_year += 100; - dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", - 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, - rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); + dev_dbg(dev, "read time %ptR\n", rtc_tm); clk_disable(pdata->clk); return 0; @@ -184,9 +182,7 @@ static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm) void __iomem *base = pdata->reg_base; int year = tm->tm_year - 100; - dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "set time %ptR\n", tm); if (year < 0 || year >= 100) { dev_err(dev, "rtc only supports 100 years\n"); @@ -224,10 +220,7 @@ static int pic32_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (alm_en & PIC32_RTCALRM_ALRMEN) ? 1 : 0; - dev_dbg(dev, "getalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", - alm_en, - 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, - alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); + dev_dbg(dev, "getalarm: %d, %ptR\n", alm_en, alm_tm); alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); alm_tm->tm_min = bcd2bin(alm_tm->tm_min); @@ -247,10 +240,7 @@ static int pic32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) void __iomem *base = pdata->reg_base; clk_enable(pdata->clk); - dev_dbg(dev, "setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", - alrm->enabled, - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "setalarm: %d, %ptR\n", alrm->enabled, tm); writel(0x00, base + PIC32_ALRMTIME); writel(0x00, base + PIC32_ALRMDATE); -- cgit From 4f5ef6eec475cbcef92dd905db195b551fba867d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:20 +0200 Subject: rtc: pm8xxx: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 29358a045925..1074e3dbfc1d 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -217,9 +217,7 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) rtc_time_to_tm(secs, tm); - dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n", - secs, tm->tm_hour, tm->tm_min, tm->tm_sec, - tm->tm_mday, tm->tm_mon, tm->tm_year); + dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm); return 0; } @@ -264,10 +262,8 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) goto rtc_rw_fail; } - dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", - alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec, alarm->time.tm_mday, - alarm->time.tm_mon, alarm->time.tm_year); + dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n", + &alarm->time, &alarm->time); rtc_rw_fail: spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); return rc; @@ -298,10 +294,8 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return rc; } - dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", - alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec, alarm->time.tm_mday, - alarm->time.tm_mon, alarm->time.tm_year); + dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n", + &alarm->time, &alarm->time); return 0; } -- cgit From b2db0a291ac66a3526a8d9592263d40791b72e50 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:21 +0200 Subject: rtc: puv3: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Cc: Guan Xuetao Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-puv3.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 9e83be32ff43..f77ef282f013 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -90,9 +90,7 @@ static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); - dev_dbg(dev, "read time %02x.%02x.%02x %02x/%02x/%02x\n", - rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, - rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); + dev_dbg(dev, "read time %ptRr\n", rtc_tm); return 0; } @@ -101,9 +99,7 @@ static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long rtc_count = 0; - dev_dbg(dev, "set time %02d.%02d.%02d %02d/%02d/%02d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "set time %ptRr\n", tm); rtc_tm_to_time(tm, &rtc_count); writel(rtc_count, RTC_RCNR); @@ -119,10 +115,7 @@ static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; - dev_dbg(dev, "read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", - alrm->enabled, - alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, - alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); + dev_dbg(dev, "read alarm: %d, %ptRr\n", alrm->enabled, alm_tm); return 0; } @@ -132,10 +125,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; unsigned long rtcalarm_count = 0; - dev_dbg(dev, "puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", - alrm->enabled, - tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, - tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); + dev_dbg(dev, "set alarm: %d, %ptRr\n", alrm->enabled, tm); rtc_tm_to_time(tm, &rtcalarm_count); writel(rtcalarm_count, RTC_RTAR); -- cgit From 0991e754b99cc262f7dfd5e33390404327446d51 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:22 +0200 Subject: rtc: rk808: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rk808.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c index b2f9e45e0298..1fb864d4ef83 100644 --- a/drivers/rtc/rtc-rk808.c +++ b/drivers/rtc/rtc-rk808.c @@ -138,9 +138,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100; tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK); rockchip_to_gregorian(tm); - dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC date/time %ptRd(%d) %ptRt\n", tm, tm->tm_wday, tm); return ret; } @@ -153,9 +151,7 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) u8 rtc_data[NUM_TIME_REGS]; int ret; - dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "set RTC date/time %ptRd(%d) %ptRt\n", tm, tm->tm_wday, tm); gregorian_to_rockchip(tm); rtc_data[0] = bin2bcd(tm->tm_sec); rtc_data[1] = bin2bcd(tm->tm_min); @@ -216,10 +212,8 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } - dev_dbg(dev, "alrm read RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, - alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, - alrm->time.tm_min, alrm->time.tm_sec); + dev_dbg(dev, "alrm read RTC date/time %ptRd(%d) %ptRt\n", + &alrm->time, alrm->time.tm_wday, &alrm->time); alrm->enabled = (int_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) ? 1 : 0; @@ -261,10 +255,8 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) dev_err(dev, "Failed to stop alarm: %d\n", ret); return ret; } - dev_dbg(dev, "alrm set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, - alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, - alrm->time.tm_min, alrm->time.tm_sec); + dev_dbg(dev, "alrm set RTC date/time %ptRd(%d) %ptRt\n", + &alrm->time, alrm->time.tm_wday, &alrm->time); gregorian_to_rockchip(&alrm->time); alrm_data[0] = bin2bcd(alrm->time.tm_sec); -- cgit From a3f60bb35fcad65ad1d727f93fcb19d6d932533b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:23 +0200 Subject: rtc: rx6110: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx6110.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 8e322d884cc2..5899ca368d59 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -114,9 +114,7 @@ struct rx6110_data { */ static int rx6110_rtc_tm_to_data(struct rtc_time *tm, u8 *data) { - pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year); + pr_debug("%s: date %ptRr\n", __func__, tm); /* * The year in the RTC is a value between 0 and 99. @@ -154,9 +152,7 @@ static int rx6110_data_to_rtc_tm(u8 *data, struct rtc_time *tm) tm->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1f) - 1; tm->tm_year = bcd2bin(data[RTC_YEAR]) + 100; - pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year); + pr_debug("%s: date %ptRr\n", __func__, tm); /* * The year in the RTC is a value between 0 and 99. @@ -248,9 +244,7 @@ static int rx6110_get_time(struct device *dev, struct rtc_time *tm) if (ret) return ret; - dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year); + dev_dbg(dev, "%s: date %ptRr\n", __func__, tm); return 0; } -- cgit From 1921cab117237bfe84e22ec3b525e0e075b420c8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:24 +0200 Subject: rtc: rx8025: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 41127adf5765..41de38acc570 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -193,10 +193,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) if (err) return err; - dev_dbg(dev, "%s: read 0x%02x 0x%02x " - "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, - date[0], date[1], date[2], date[3], date[4], - date[5], date[6]); + dev_dbg(dev, "%s: read %7ph\n", __func__, date); dt->tm_sec = bcd2bin(date[RX8025_REG_SEC] & 0x7f); dt->tm_min = bcd2bin(date[RX8025_REG_MIN] & 0x7f); @@ -210,9 +207,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100; - dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - dt->tm_sec, dt->tm_min, dt->tm_hour, - dt->tm_mday, dt->tm_mon, dt->tm_year); + dev_dbg(dev, "%s: date %ptRr\n", __func__, dt); return 0; } @@ -243,10 +238,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100); - dev_dbg(dev, - "%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", - __func__, - date[0], date[1], date[2], date[3], date[4], date[5], date[6]); + dev_dbg(dev, "%s: write %7ph\n", __func__, date); ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); if (ret < 0) @@ -319,10 +311,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: %ds %dm %dh %dmd %dm %dy\n", - __func__, - t->time.tm_sec, t->time.tm_min, t->time.tm_hour, - t->time.tm_mday, t->time.tm_mon, t->time.tm_year); + dev_dbg(dev, "%s: date: %ptRr\n", __func__, t); t->enabled = !!(rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE); t->pending = (ctrl2 & RX8025_BIT_CTRL2_DAFG) && t->enabled; -- cgit From 9a1bacf4239ec197fe6a04d04ce924a8e6e701ce Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:25 +0200 Subject: rtc: s3c: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 58e03ac3578b..04c68178c42d 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -225,13 +225,9 @@ retry_get_time: s3c_rtc_disable_clk(info); rtc_tm->tm_year += 100; - - dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", - 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, - rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); - rtc_tm->tm_mon -= 1; + dev_dbg(dev, "read time %ptR\n", rtc_tm); return 0; } @@ -241,9 +237,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) int year = tm->tm_year - 100; int ret; - dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "set time %ptR\n", tm); /* we get around y2k by simply not supporting it */ @@ -292,10 +286,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; - dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", - alm_en, - 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, - alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); + dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm); /* decode the alarm enable field */ if (alm_en & S3C2410_RTCALM_SECEN) @@ -328,10 +319,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned int alrm_en; int ret; - dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", - alrm->enabled, - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm); ret = s3c_rtc_enable_clk(info); if (ret) -- cgit From 5527842eab2331ed58abf69aa77f5c81e21025e4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:26 +0200 Subject: rtc: s5m: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Cc: Bartlomiej Zolnierkiewicz Reviewed-by: Krzysztof Kozlowski Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s5m.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 6495f84f7428..c7f1bf823ea0 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -406,9 +406,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) return -EINVAL; } - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); return 0; } @@ -436,9 +434,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) if (ret < 0) return ret; - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); ret = regmap_raw_write(info->regmap, info->regs->time, data, info->regs->regs_count); @@ -490,11 +486,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return -EINVAL; } - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, - alrm->time.tm_mday, alrm->time.tm_hour, - alrm->time.tm_min, alrm->time.tm_sec, - alrm->time.tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday); ret = s5m_check_peding_alarm_interrupt(info, alrm); @@ -513,9 +505,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); - dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8763X: @@ -558,9 +548,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); - dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8763X: @@ -620,10 +608,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return -EINVAL; } - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, - alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min, - alrm->time.tm_sec, alrm->time.tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday); ret = s5m_rtc_stop_alarm(info); if (ret < 0) -- cgit From d54fb4861666c8259933547841e1a0c04471c4da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:27 +0200 Subject: rtc: tegra: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Cc: Thierry Reding Cc: Jonathan Hunter Signed-off-by: Andy Shevchenko Acked-by: Thierry Reding Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-tegra.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index c9e77a83cd1b..c6b0a99aa3a9 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -125,15 +125,7 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) rtc_time_to_tm(sec, tm); - dev_vdbg(dev, "time read as %lu. %d/%d/%d %d:%02u:%02u\n", - sec, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec - ); + dev_vdbg(dev, "time read as %lu. %ptR\n", sec, tm); return 0; } @@ -147,15 +139,7 @@ static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) /* convert tm to seconds. */ rtc_tm_to_time(tm, &sec); - dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n", - sec, - tm->tm_mon+1, - tm->tm_mday, - tm->tm_year+1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec - ); + dev_vdbg(dev, "time set to %lu. %ptR\n", sec, tm); /* seconds only written if wait succeeded. */ ret = tegra_rtc_wait_while_busy(dev); @@ -232,15 +216,7 @@ static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) /* if successfully written and alarm is enabled ... */ if (sec) { tegra_rtc_alarm_irq_enable(dev, 1); - - dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n", - sec, - alarm->time.tm_mon+1, - alarm->time.tm_mday, - alarm->time.tm_year+1900, - alarm->time.tm_hour, - alarm->time.tm_min, - alarm->time.tm_sec); + dev_vdbg(dev, "alarm set as %lu. %ptR\n", sec, &alarm->time); } else { /* disable alarm if 0 or write error. */ dev_vdbg(dev, "alarm disabled\n"); -- cgit From 804cfcb98232ee8acfa187cc59d6aec39aa50bdb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:28 +0200 Subject: Input: hp_sdc_rtc - Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Cc: Dmitry Torokhov Signed-off-by: Andy Shevchenko Acked-by: Dmitry Torokhov Signed-off-by: Alexandre Belloni --- drivers/input/misc/hp_sdc_rtc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 47eb8ca729fe..abca895a6156 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -441,12 +441,10 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) seq_puts(m, "BBRTC\t\t: READ FAILED!\n"); } else { seq_printf(m, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n" "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, epoch); + &tm, &tm, epoch); } if (hp_sdc_rtc_read_rt(&tv)) { -- cgit From 906254441564f27ec360b72d487fbee314481c75 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:29 +0200 Subject: m68k/mac: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Cc: Geert Uytterhoeven Cc: linux-m68k Signed-off-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven Acked-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni --- arch/m68k/mac/misc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c index ebb3b6d169ea..71c4735a31ee 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -605,13 +605,9 @@ int mac_hwclk(int op, struct rtc_time *t) unmktime(now, 0, &t->tm_year, &t->tm_mon, &t->tm_mday, &t->tm_hour, &t->tm_min, &t->tm_sec); - pr_debug("%s: read %04d-%02d-%-2d %02d:%02d:%02d\n", - __func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); + pr_debug("%s: read %ptR\n", __func__, t); } else { /* write */ - pr_debug("%s: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n", - __func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); + pr_debug("%s: tried to write %ptR\n", __func__, t); switch (macintosh_config->adb_type) { case MAC_ADB_IOP: -- cgit From a07995be61e18a504f37db0169b50de4036fc02d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 4 Dec 2018 23:23:30 +0200 Subject: PM: Switch to use %ptR Use %ptR instead of open coded variant to print content of struct rtc_time in human readable format. Cc: linux-pm@vger.kernel.org Acked-by: Rafael J. Wysocki Signed-off-by: Andy Shevchenko Signed-off-by: Alexandre Belloni --- drivers/base/power/trace.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 1cda505d6a85..b11f47a1e819 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -118,9 +118,7 @@ static unsigned int read_magic_time(void) unsigned int val; mc146818_get_time(&time); - pr_info("RTC time: %2d:%02d:%02d, date: %02d/%02d/%02d\n", - time.tm_hour, time.tm_min, time.tm_sec, - time.tm_mon + 1, time.tm_mday, time.tm_year % 100); + pr_info("RTC time: %ptRt, date: %ptRd\n", &time, &time); val = time.tm_year; /* 100 years */ if (val > 100) val -= 100; -- cgit From 2cb5e4743ab52d3a43ef25f229f6770fd9ca0065 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 3 Dec 2018 12:47:36 +0100 Subject: dt-bindings: rtc: use a generic node name for ds1307 The example should follow the practice or using a generic node name instead of the precise programming model, as recommended by the DTSpec. Signed-off-by: Lubomir Rintel Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/rtc-ds1307.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt index eebfbe04207a..eaee19b60960 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt @@ -35,7 +35,7 @@ Optional properties: Should be given if internal trickle charger diode should be disabled Example: - rtc1: ds1339@68 { + ds1339: rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; interrupt-parent = <&gpio4>; -- cgit From ecb4a353d3afd45b9bb30c85d03ee113a0589079 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 5 Dec 2018 17:00:09 +0200 Subject: rtc: pcf8523: don't return invalid date when battery is low MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RTC_VL_READ ioctl reports the low battery condition. Still, pcf8523_rtc_read_time() happily returns invalid dates in this case. Check the battery health on pcf8523_rtc_read_time() to avoid that. Reported-by: Erik ÄŒuk Signed-off-by: Baruch Siach Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf8523.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 453615f8ac9a..3fcd2cbafc84 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -85,6 +85,18 @@ static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) return 0; } +static int pcf8523_voltage_low(struct i2c_client *client) +{ + u8 value; + int err; + + err = pcf8523_read(client, REG_CONTROL3, &value); + if (err < 0) + return err; + + return !!(value & REG_CONTROL3_BLF); +} + static int pcf8523_select_capacitance(struct i2c_client *client, bool high) { u8 value; @@ -167,6 +179,14 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) struct i2c_msg msgs[2]; int err; + err = pcf8523_voltage_low(client); + if (err < 0) { + return err; + } else if (err > 0) { + dev_err(dev, "low voltage detected, time is unreliable\n"); + return -EINVAL; + } + msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 1; @@ -251,17 +271,13 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct i2c_client *client = to_i2c_client(dev); - u8 value; - int ret = 0, err; + int ret; switch (cmd) { case RTC_VL_READ: - err = pcf8523_read(client, REG_CONTROL3, &value); - if (err < 0) - return err; - - if (value & REG_CONTROL3_BLF) - ret = 1; + ret = pcf8523_voltage_low(client); + if (ret < 0) + return ret; if (copy_to_user((void __user *)arg, &ret, sizeof(int))) return -EFAULT; -- cgit From bae5e94bea188e652d798eeb4b92b88a355591f6 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 7 Dec 2018 11:27:43 +0000 Subject: dt-bindings: rtc: pcf85363: Document pcf85263 real-time clock The pcf85263 RTC is compatible with the pcf85363 RTC. The difference between the pcf85263 and pcf85363 RTC is that the latter has 64 bytes more RAM. This renders them incompatible from a DT point of view. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Reviewed-by: Rob Herring Reviewed-by: Simon Horman Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/pcf85363.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/pcf85363.txt b/Documentation/devicetree/bindings/rtc/pcf85363.txt index 76fdabc59742..94adc1cf93d9 100644 --- a/Documentation/devicetree/bindings/rtc/pcf85363.txt +++ b/Documentation/devicetree/bindings/rtc/pcf85363.txt @@ -1,8 +1,8 @@ -NXP PCF85363 Real Time Clock +NXP PCF85263/PCF85363 Real Time Clock ============================ Required properties: -- compatible: Should contain "nxp,pcf85363". +- compatible: Should contain "nxp,pcf85263" or "nxp,pcf85363". - reg: I2C address for chip. Optional properties: -- cgit From fc979933bcf162595b6004d0de4effb64c323152 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 7 Dec 2018 11:27:44 +0000 Subject: rtc: pcf85363: Add support for NXP pcf85263 rtc Add support for NXP pcf85263 real-time clock. pcf85263 rtc is compatible with pcf85363,except that pcf85363 has additional 64 bytes of RAM. 1 byte of nvmem is supported and exposed in sysfs (# is the instance number,starting with 0): /sys/bus/nvmem/devices/pcf85x63-#/nvmem Signed-off-by: Biju Das Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85363.c | 94 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index c04a1edcd571..a3988079f60a 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -120,6 +120,11 @@ struct pcf85363 { struct regmap *regmap; }; +struct pcf85x63_config { + struct regmap_config regmap; + unsigned int num_nvram; +}; + static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf85363 *pcf85363 = dev_get_drvdata(dev); @@ -311,25 +316,75 @@ static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val, val, bytes); } -static const struct regmap_config regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x7f, +static int pcf85x63_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct pcf85363 *pcf85363 = priv; + unsigned int tmp_val; + int ret; + + ret = regmap_read(pcf85363->regmap, CTRL_RAMBYTE, &tmp_val); + (*(unsigned char *) val) = (unsigned char) tmp_val; + + return ret; +} + +static int pcf85x63_nvram_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct pcf85363 *pcf85363 = priv; + unsigned char tmp_val; + + tmp_val = *((unsigned char *)val); + return regmap_write(pcf85363->regmap, CTRL_RAMBYTE, + (unsigned int)tmp_val); +} + +static const struct pcf85x63_config pcf_85263_config = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x2f, + }, + .num_nvram = 1 +}; + +static const struct pcf85x63_config pcf_85363_config = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x7f, + }, + .num_nvram = 2 }; static int pcf85363_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pcf85363 *pcf85363; - struct nvmem_config nvmem_cfg = { - .name = "pcf85363-", - .word_size = 1, - .stride = 1, - .size = NVRAM_SIZE, - .reg_read = pcf85363_nvram_read, - .reg_write = pcf85363_nvram_write, + const struct pcf85x63_config *config = &pcf_85363_config; + const void *data = of_device_get_match_data(&client->dev); + static struct nvmem_config nvmem_cfg[] = { + { + .name = "pcf85x63-", + .word_size = 1, + .stride = 1, + .size = 1, + .reg_read = pcf85x63_nvram_read, + .reg_write = pcf85x63_nvram_write, + }, { + .name = "pcf85363-", + .word_size = 1, + .stride = 1, + .size = NVRAM_SIZE, + .reg_read = pcf85363_nvram_read, + .reg_write = pcf85363_nvram_write, + }, }; - int ret; + int ret, i; + + if (data) + config = data; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -339,7 +394,7 @@ static int pcf85363_probe(struct i2c_client *client, if (!pcf85363) return -ENOMEM; - pcf85363->regmap = devm_regmap_init_i2c(client, ®map_config); + pcf85363->regmap = devm_regmap_init_i2c(client, &config->regmap); if (IS_ERR(pcf85363->regmap)) { dev_err(&client->dev, "regmap allocation failed\n"); return PTR_ERR(pcf85363->regmap); @@ -370,15 +425,18 @@ static int pcf85363_probe(struct i2c_client *client, ret = rtc_register_device(pcf85363->rtc); - nvmem_cfg.priv = pcf85363; - rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg); + for (i = 0; i < config->num_nvram; i++) { + nvmem_cfg[i].priv = pcf85363; + rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg[i]); + } return ret; } static const struct of_device_id dev_ids[] = { - { .compatible = "nxp,pcf85363" }, - {} + { .compatible = "nxp,pcf85263", .data = &pcf_85263_config }, + { .compatible = "nxp,pcf85363", .data = &pcf_85363_config }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, dev_ids); @@ -393,5 +451,5 @@ static struct i2c_driver pcf85363_driver = { module_i2c_driver(pcf85363_driver); MODULE_AUTHOR("Eric Nelson"); -MODULE_DESCRIPTION("pcf85363 I2C RTC driver"); +MODULE_DESCRIPTION("pcf85263/pcf85363 I2C RTC driver"); MODULE_LICENSE("GPL"); -- cgit From ffe1c5a2d4271a0e04e2576ab0a53ac09a14e065 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 7 Dec 2018 18:40:53 +0100 Subject: rtc: abx80x: Implement RTC_VL_READ,CLR ioctls Implement standard ioctls for polling the battery status and clearing the battery low indication from userspace. Signed-off-by: Marek Vasut Cc: Alexandre Belloni Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index d8e94edcb0ba..4d24f7288ad7 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -38,6 +38,7 @@ #define ABX8XX_REG_STATUS 0x0f #define ABX8XX_STATUS_AF BIT(2) +#define ABX8XX_STATUS_BLF BIT(4) #define ABX8XX_STATUS_WDT BIT(6) #define ABX8XX_REG_CTRL1 0x10 @@ -507,12 +508,49 @@ static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled) return err; } +static int abx80x_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + int status, tmp; + + switch (cmd) { + case RTC_VL_READ: + status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); + if (status < 0) + return status; + + tmp = !!(status & ABX8XX_STATUS_BLF); + + if (copy_to_user((void __user *)arg, &tmp, sizeof(int))) + return -EFAULT; + + return 0; + + case RTC_VL_CLR: + status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); + if (status < 0) + return status; + + status &= ~ABX8XX_STATUS_BLF; + + tmp = i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0); + if (tmp < 0) + return tmp; + + return 0; + + default: + return -ENOIOCTLCMD; + } +} + static const struct rtc_class_ops abx80x_rtc_ops = { .read_time = abx80x_rtc_read_time, .set_time = abx80x_rtc_set_time, .read_alarm = abx80x_read_alarm, .set_alarm = abx80x_set_alarm, .alarm_irq_enable = abx80x_alarm_irq_enable, + .ioctl = abx80x_ioctl, }; static int abx80x_dt_trickle_cfg(struct device_node *np) -- cgit From 9a03201170d3de1da47c1b7e2d514e0b15477881 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 18 Dec 2018 22:11:26 +0100 Subject: rtc: enforce rtc_timer_init private_data type All the remaining users of rtc_timers are passing the rtc_device as private data. Enforce that and rename private_data to rtc. Suggested-by: Arnd Bergmann Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 4 ++-- drivers/rtc/interface.c | 19 +++++++++---------- include/linux/rtc.h | 14 ++++++++------ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 6d364085bd86..8d9b65d54f4f 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -178,9 +178,9 @@ static struct rtc_device *rtc_allocate_device(void) timerqueue_init_head(&rtc->timerqueue); INIT_WORK(&rtc->irqwork, rtc_timer_do_work); /* Init aie timer */ - rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc); + rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, rtc); /* Init uie timer */ - rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc); + rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, rtc); /* Init pie timer */ hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); rtc->pie_timer.function = rtc_pie_update_irq; diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index e8d77b1eaeb2..98d9c87b0d1b 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -609,26 +609,24 @@ void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) /** * rtc_aie_update_irq - AIE mode rtctimer hook - * @private: pointer to the rtc_device + * @rtc: pointer to the rtc_device * * This functions is called when the aie_timer expires. */ -void rtc_aie_update_irq(void *private) +void rtc_aie_update_irq(struct rtc_device *rtc) { - struct rtc_device *rtc = (struct rtc_device *)private; rtc_handle_legacy_irq(rtc, 1, RTC_AF); } /** * rtc_uie_update_irq - UIE mode rtctimer hook - * @private: pointer to the rtc_device + * @rtc: pointer to the rtc_device * * This functions is called when the uie_timer expires. */ -void rtc_uie_update_irq(void *private) +void rtc_uie_update_irq(struct rtc_device *rtc) { - struct rtc_device *rtc = (struct rtc_device *)private; rtc_handle_legacy_irq(rtc, 1, RTC_UF); } @@ -908,7 +906,7 @@ again: trace_rtc_timer_dequeue(timer); timer->enabled = 0; if (timer->func) - timer->func(timer->private_data); + timer->func(timer->rtc); trace_rtc_timer_fired(timer); /* Re-add/fwd periodic timers */ @@ -955,16 +953,17 @@ reprogram: /* rtc_timer_init - Initializes an rtc_timer * @timer: timer to be intiialized * @f: function pointer to be called when timer fires - * @data: private data passed to function pointer + * @rtc: pointer to the rtc_device * * Kernel interface to initializing an rtc_timer. */ -void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data) +void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r), + struct rtc_device *rtc) { timerqueue_init(&timer->node); timer->enabled = 0; timer->func = f; - timer->private_data = data; + timer->rtc = rtc; } /* rtc_timer_start - Sets an rtc_timer to fire in the future diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 58147b057acd..c1089fe5344a 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -87,15 +87,16 @@ struct rtc_class_ops { int (*set_offset)(struct device *, long offset); }; +struct rtc_device; + struct rtc_timer { struct timerqueue_node node; ktime_t period; - void (*func)(void *private_data); - void *private_data; + void (*func)(struct rtc_device *rtc); + struct rtc_device *rtc; int enabled; }; - /* flags */ #define RTC_DEV_BUSY 0 @@ -197,11 +198,12 @@ extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled); void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode); -void rtc_aie_update_irq(void *private); -void rtc_uie_update_irq(void *private); +void rtc_aie_update_irq(struct rtc_device *rtc); +void rtc_uie_update_irq(struct rtc_device *rtc); enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer); -void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data); +void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r), + struct rtc_device *rtc); int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, ktime_t expires, ktime_t period); void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer); -- cgit From a26944149374c19d92f785108b6980f2e54bb517 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 18 Dec 2018 22:15:58 +0100 Subject: rtc: class: reimplement devm_rtc_device_register Implement devm_rtc_device_register using devm_rtc_allocate_device and __rtc_register_device so there is only one path left to register rtc devices. Also mark it as deprecated so new drivers will hopefully use devm_rtc_allocate_device and rtc_register_device that are less race prone and allow avoiding the 2038, 2070, 2100 and 2106 bugs properly. Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 157 ++++++++++++---------------------------------------- 1 file changed, 36 insertions(+), 121 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 8d9b65d54f4f..ac93b76f2b11 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -277,82 +277,6 @@ static void rtc_device_get_offset(struct rtc_device *rtc) rtc->offset_secs = 0; } -/** - * rtc_device_register - register w/ RTC class - * @dev: the device to register - * - * rtc_device_unregister() must be called when the class device is no - * longer needed. - * - * Returns the pointer to the new struct class device. - */ -static struct rtc_device *rtc_device_register(const char *name, - struct device *dev, - const struct rtc_class_ops *ops, - struct module *owner) -{ - struct rtc_device *rtc; - struct rtc_wkalrm alrm; - int id, err; - - id = rtc_device_get_id(dev); - if (id < 0) { - err = id; - goto exit; - } - - rtc = rtc_allocate_device(); - if (!rtc) { - err = -ENOMEM; - goto exit_ida; - } - - rtc->id = id; - rtc->ops = ops; - rtc->owner = owner; - rtc->dev.parent = dev; - - dev_set_name(&rtc->dev, "rtc%d", id); - - rtc_device_get_offset(rtc); - - /* Check to see if there is an ALARM already set in hw */ - err = __rtc_read_alarm(rtc, &alrm); - - if (!err && !rtc_valid_tm(&alrm.time)) - rtc_initialize_alarm(rtc, &alrm); - - rtc_dev_prepare(rtc); - - err = cdev_device_add(&rtc->char_dev, &rtc->dev); - if (err) { - dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", - name, MAJOR(rtc->dev.devt), rtc->id); - - /* This will free both memory and the ID */ - put_device(&rtc->dev); - goto exit; - } else { - dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", name, - MAJOR(rtc->dev.devt), rtc->id); - } - - rtc_proc_add_device(rtc); - - dev_info(dev, "rtc core: registered %s as %s\n", - name, dev_name(&rtc->dev)); - - return rtc; - -exit_ida: - ida_simple_remove(&rtc_ida, id); - -exit: - dev_err(dev, "rtc core: unable to register %s, err = %d\n", - name, err); - return ERR_PTR(err); -} - /** * rtc_device_unregister - removes the previously registered RTC class device * @@ -372,51 +296,6 @@ static void rtc_device_unregister(struct rtc_device *rtc) put_device(&rtc->dev); } -static void devm_rtc_device_release(struct device *dev, void *res) -{ - struct rtc_device *rtc = *(struct rtc_device **)res; - - rtc_nvmem_unregister(rtc); - rtc_device_unregister(rtc); -} - -/** - * devm_rtc_device_register - resource managed rtc_device_register() - * @dev: the device to register - * @name: the name of the device - * @ops: the rtc operations structure - * @owner: the module owner - * - * @return a struct rtc on success, or an ERR_PTR on error - * - * Managed rtc_device_register(). The rtc_device returned from this function - * are automatically freed on driver detach. See rtc_device_register() - * for more information. - */ - -struct rtc_device *devm_rtc_device_register(struct device *dev, - const char *name, - const struct rtc_class_ops *ops, - struct module *owner) -{ - struct rtc_device **ptr, *rtc; - - ptr = devres_alloc(devm_rtc_device_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - rtc = rtc_device_register(name, dev, ops, owner); - if (!IS_ERR(rtc)) { - *ptr = rtc; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return rtc; -} -EXPORT_SYMBOL_GPL(devm_rtc_device_register); - static void devm_rtc_release_device(struct device *dev, void *res) { struct rtc_device *rtc = *(struct rtc_device **)res; @@ -503,6 +382,42 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc) } EXPORT_SYMBOL_GPL(__rtc_register_device); +/** + * devm_rtc_device_register - resource managed rtc_device_register() + * @dev: the device to register + * @name: the name of the device (unused) + * @ops: the rtc operations structure + * @owner: the module owner + * + * @return a struct rtc on success, or an ERR_PTR on error + * + * Managed rtc_device_register(). The rtc_device returned from this function + * are automatically freed on driver detach. + * This function is deprecated, use devm_rtc_allocate_device and + * 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) +{ + struct rtc_device *rtc; + int err; + + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return rtc; + + rtc->ops = ops; + + err = __rtc_register_device(owner, rtc); + if (err) + return ERR_PTR(err); + + return rtc; +} +EXPORT_SYMBOL_GPL(devm_rtc_device_register); + static int __init rtc_init(void) { rtc_class = class_create(THIS_MODULE, "rtc"); -- cgit From 3c3d71013c7655b9cc4043c9f8845f0c4402d71d Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 18 Dec 2018 22:42:23 +0100 Subject: rtc: pcf2123: Add Microcrystal rv2123 Add a compatible string for Microcrystal rv2123 as the reset procedure seem to be differing. However, the current driver works just fine. Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt | 1 + drivers/rtc/rtc-pcf2123.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt b/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt index 811124a36d16..1994f601800a 100644 --- a/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt +++ b/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt @@ -2,6 +2,7 @@ NXP PCF2123 SPI Real Time Clock Required properties: - compatible: should be: "nxp,rtc-pcf2123" + or "microcrystal,rv2123" - reg: should be the SPI slave chipselect address Optional properties: diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index e5222c5d8223..39da8b214275 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -453,6 +453,7 @@ static int pcf2123_remove(struct spi_device *spi) #ifdef CONFIG_OF static const struct of_device_id pcf2123_dt_ids[] = { { .compatible = "nxp,rtc-pcf2123", }, + { .compatible = "microcrystal,rv2123", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, pcf2123_dt_ids); -- cgit From 2ea44ca1ffccf89cfb9e6755156843e278ec9645 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 20 Dec 2018 08:56:07 +0000 Subject: dt-bindings: fsl: scu: add rtc binding NXP i.MX8QXP is an ARMv8 SoC with a Cortex-M4 core inside as system controller, the system controller is in charge of system power, clock and secure RTC etc. management, Linux kernel has to communicate with system controller via MU (message unit) IPC to do RTC operation, this patch adds binding doc for i.MX system controller RTC driver. Signed-off-by: Anson Huang Reviewed-by: Rob Herring Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt index 46d0af1f0872..0860346fc9eb 100644 --- a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt @@ -114,6 +114,12 @@ Required properties for Pinctrl sub nodes: [2] Documentation/devicetree/bindings/power/power_domain.txt [3] Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt +RTC bindings based on SCU Message Protocol +------------------------------------------------------------ + +Required properties: +- compatible: should be "fsl,imx8qxp-sc-rtc"; + Example (imx8qxp): ------------- lsio_mu1: mailbox@5d1c0000 { @@ -169,6 +175,10 @@ firmware { }; ... }; + + rtc: rtc { + compatible = "fsl,imx8qxp-sc-rtc"; + }; }; }; -- cgit From e01b5781958de08942af341ce26768d5e0fbcdf5 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 20 Dec 2018 08:56:16 +0000 Subject: rtc: add i.MX system controller RTC support i.MX8QXP is an ARMv8 SoC which has a Cortex-M4 system controller inside, the system controller is in charge of controlling power, clock and secure rtc etc.. This patch adds i.MX system controller RTC driver support, Linux kernel has to communicate with system controller via MU (message unit) IPC to set/get RTC time and other alarm functions, since the RTC set time needs to be done in secure EL3 mode (required by system controller firmware) and alarm functions needs to be done with general MU IRQ handle, these depend on other components which are NOT ready, so this patch ONLY enables the RTC time read. Signed-off-by: Anson Huang Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 7 ++++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-imx-sc.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 drivers/rtc/rtc-imx-sc.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a819ef07b7ec..225b0b8516f3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1677,6 +1677,13 @@ config RTC_DRV_SNVS This driver can also be built as a module, if so, the module will be called "rtc-snvs". +config RTC_DRV_IMX_SC + depends on IMX_SCU + tristate "NXP i.MX System Controller RTC support" + help + If you say yes here you get support for the NXP i.MX System + Controller RTC module. + config RTC_DRV_SIRFSOC tristate "SiRFSOC RTC" depends on ARCH_SIRF diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 290c1730fb0a..f97c05ef99db 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o +obj-$(CONFIG_RTC_DRV_IMX_SC) += rtc-imx-sc.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o diff --git a/drivers/rtc/rtc-imx-sc.c b/drivers/rtc/rtc-imx-sc.c new file mode 100644 index 000000000000..7ff08544532a --- /dev/null +++ b/drivers/rtc/rtc-imx-sc.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include +#include + +#define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9 +#define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6 + +static struct imx_sc_ipc *rtc_ipc_handle; +static struct rtc_device *imx_sc_rtc; + +struct imx_sc_msg_timer_get_rtc_time { + struct imx_sc_rpc_msg hdr; + u32 time; +} __packed; + +static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct imx_sc_msg_timer_get_rtc_time msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_TIMER; + hdr->func = IMX_SC_TIMER_FUNC_GET_RTC_SEC1970; + hdr->size = 1; + + ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true); + if (ret) { + dev_err(dev, "read rtc time failed, ret %d\n", ret); + return ret; + } + + rtc_time_to_tm(msg.time, tm); + + return 0; +} + +static const struct rtc_class_ops imx_sc_rtc_ops = { + .read_time = imx_sc_rtc_read_time, +}; + +static int imx_sc_rtc_probe(struct platform_device *pdev) +{ + int ret; + + ret = imx_scu_get_handle(&rtc_ipc_handle); + if (ret) + return ret; + + imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(imx_sc_rtc)) + return PTR_ERR(imx_sc_rtc); + + imx_sc_rtc->ops = &imx_sc_rtc_ops; + imx_sc_rtc->range_min = 0; + 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); + return ret; + } + + return 0; +} + +static const struct of_device_id imx_sc_dt_ids[] = { + { .compatible = "fsl,imx8qxp-sc-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, imx_sc_dt_ids); + +static struct platform_driver imx_sc_rtc_driver = { + .driver = { + .name = "imx-sc-rtc", + .of_match_table = imx_sc_dt_ids, + }, + .probe = imx_sc_rtc_probe, +}; +module_platform_driver(imx_sc_rtc_driver); + +MODULE_AUTHOR("Anson Huang "); +MODULE_DESCRIPTION("NXP i.MX System Controller RTC Driver"); +MODULE_LICENSE("GPL"); -- cgit From bba3d2daa8a9bc888902275401f15ef48fcdd378 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 31 Dec 2018 00:49:36 +0100 Subject: rtc: nvmem: fix possible use after free In cas of probe failure, devres may free the memory allocated for rtc->nvram before devm_rtc_release_device() is called. This leads to rtc_nvram_unregister using it after being freed which may lead to a crash. This has been shown to happen after commit 461e557b9727 ("rtc: nvmem: use devm_nvmem_register()") Reported-by: kernel test robot Signed-off-by: Alexandre Belloni --- drivers/rtc/nvmem.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c index ebdfe8e3a1a0..dce518d5e50e 100644 --- a/drivers/rtc/nvmem.c +++ b/drivers/rtc/nvmem.c @@ -12,6 +12,7 @@ #include #include #include +#include #include /* @@ -45,9 +46,7 @@ static int rtc_nvram_register(struct rtc_device *rtc, { int err; - rtc->nvram = devm_kzalloc(rtc->dev.parent, - sizeof(struct bin_attribute), - GFP_KERNEL); + rtc->nvram = kzalloc(sizeof(struct bin_attribute), GFP_KERNEL); if (!rtc->nvram) return -ENOMEM; @@ -64,7 +63,7 @@ static int rtc_nvram_register(struct rtc_device *rtc, err = sysfs_create_bin_file(&rtc->dev.parent->kobj, rtc->nvram); if (err) { - devm_kfree(rtc->dev.parent, rtc->nvram); + kfree(rtc->nvram); rtc->nvram = NULL; } @@ -74,6 +73,8 @@ static int rtc_nvram_register(struct rtc_device *rtc, static void rtc_nvram_unregister(struct rtc_device *rtc) { sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram); + kfree(rtc->nvram); + rtc->nvram = NULL; } /* -- cgit From 36e14f5fdfdf7cec8887b7ff69cd9bb5051ecf62 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 31 Dec 2018 11:36:16 +0100 Subject: rtc: rename core files Rename core files so there is a clearer separation between the RTC core and the RTC drivers. Signed-off-by: Alexandre Belloni --- drivers/rtc/Makefile | 8 +- drivers/rtc/dev.c | 483 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/rtc/lib.c | 148 +++++++++++++++ drivers/rtc/proc.c | 95 ++++++++++ drivers/rtc/rtc-dev.c | 483 ------------------------------------------------ drivers/rtc/rtc-lib.c | 148 --------------- drivers/rtc/rtc-proc.c | 95 ---------- drivers/rtc/rtc-sysfs.c | 358 ----------------------------------- drivers/rtc/sysfs.c | 358 +++++++++++++++++++++++++++++++++++ 9 files changed, 1088 insertions(+), 1088 deletions(-) create mode 100644 drivers/rtc/dev.c create mode 100644 drivers/rtc/lib.c create mode 100644 drivers/rtc/proc.c delete mode 100644 drivers/rtc/rtc-dev.c delete mode 100644 drivers/rtc/rtc-lib.c delete mode 100644 drivers/rtc/rtc-proc.c delete mode 100644 drivers/rtc/rtc-sysfs.c create mode 100644 drivers/rtc/sysfs.c diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index f97c05ef99db..df022d820bee 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -5,7 +5,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG -obj-$(CONFIG_RTC_LIB) += rtc-lib.o +obj-$(CONFIG_RTC_LIB) += lib.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o @@ -17,9 +17,9 @@ rtc-core-y += rtc-efi-platform.o endif rtc-core-$(CONFIG_RTC_NVMEM) += nvmem.o -rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o -rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o -rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o +rtc-core-$(CONFIG_RTC_INTF_DEV) += dev.o +rtc-core-$(CONFIG_RTC_INTF_PROC) += proc.o +rtc-core-$(CONFIG_RTC_INTF_SYSFS) += sysfs.o # Keep the list ordered. diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c new file mode 100644 index 000000000000..43d962a9c210 --- /dev/null +++ b/drivers/rtc/dev.c @@ -0,0 +1,483 @@ +/* + * RTC subsystem, dev interface + * + * Copyright (C) 2005 Tower Technologies + * Author: Alessandro Zummo + * + * 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 +#include +#include +#include "rtc-core.h" + +static dev_t rtc_devt; + +#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */ + +static int rtc_dev_open(struct inode *inode, struct file *file) +{ + struct rtc_device *rtc = container_of(inode->i_cdev, + struct rtc_device, char_dev); + + if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) + return -EBUSY; + + file->private_data = rtc; + + spin_lock_irq(&rtc->irq_lock); + rtc->irq_data = 0; + spin_unlock_irq(&rtc->irq_lock); + + return 0; +} + +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL +/* + * Routine to poll RTC seconds field for change as often as possible, + * after first RTC_UIE use timer to reduce polling + */ +static void rtc_uie_task(struct work_struct *work) +{ + struct rtc_device *rtc = + container_of(work, struct rtc_device, uie_task); + struct rtc_time tm; + int num = 0; + int err; + + err = rtc_read_time(rtc, &tm); + + spin_lock_irq(&rtc->irq_lock); + if (rtc->stop_uie_polling || err) { + rtc->uie_task_active = 0; + } 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_active = 1; + rtc->uie_task_active = 0; + add_timer(&rtc->uie_timer); + } else if (schedule_work(&rtc->uie_task) == 0) { + rtc->uie_task_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + 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); + unsigned long flags; + + spin_lock_irqsave(&rtc->irq_lock, flags); + rtc->uie_timer_active = 0; + rtc->uie_task_active = 1; + if ((schedule_work(&rtc->uie_task) == 0)) + rtc->uie_task_active = 0; + spin_unlock_irqrestore(&rtc->irq_lock, flags); +} + +static int clear_uie(struct rtc_device *rtc) +{ + spin_lock_irq(&rtc->irq_lock); + if (rtc->uie_irq_active) { + rtc->stop_uie_polling = 1; + if (rtc->uie_timer_active) { + spin_unlock_irq(&rtc->irq_lock); + del_timer_sync(&rtc->uie_timer); + spin_lock_irq(&rtc->irq_lock); + rtc->uie_timer_active = 0; + } + if (rtc->uie_task_active) { + spin_unlock_irq(&rtc->irq_lock); + flush_scheduled_work(); + spin_lock_irq(&rtc->irq_lock); + } + rtc->uie_irq_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +static int set_uie(struct rtc_device *rtc) +{ + struct rtc_time tm; + int err; + + err = rtc_read_time(rtc, &tm); + if (err) + return err; + spin_lock_irq(&rtc->irq_lock); + if (!rtc->uie_irq_active) { + rtc->uie_irq_active = 1; + rtc->stop_uie_polling = 0; + rtc->oldsecs = tm.tm_sec; + rtc->uie_task_active = 1; + if (schedule_work(&rtc->uie_task) == 0) + rtc->uie_task_active = 0; + } + rtc->irq_data = 0; + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) +{ + if (enabled) + return set_uie(rtc); + else + return clear_uie(rtc); +} +EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); + +#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ + +static ssize_t +rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct rtc_device *rtc = file->private_data; + + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t ret; + + if (count != sizeof(unsigned int) && count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&rtc->irq_queue, &wait); + do { + __set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irq(&rtc->irq_lock); + data = rtc->irq_data; + rtc->irq_data = 0; + spin_unlock_irq(&rtc->irq_lock); + + if (data != 0) { + ret = 0; + break; + } + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + } while (1); + set_current_state(TASK_RUNNING); + remove_wait_queue(&rtc->irq_queue, &wait); + + if (ret == 0) { + /* Check for any data updates */ + if (rtc->ops->read_callback) + data = rtc->ops->read_callback(rtc->dev.parent, + data); + + if (sizeof(int) != sizeof(long) && + count == sizeof(unsigned int)) + ret = put_user(data, (unsigned int __user *)buf) ?: + sizeof(unsigned int); + else + ret = put_user(data, (unsigned long __user *)buf) ?: + sizeof(unsigned long); + } + return ret; +} + +static __poll_t rtc_dev_poll(struct file *file, poll_table *wait) +{ + struct rtc_device *rtc = file->private_data; + unsigned long data; + + poll_wait(file, &rtc->irq_queue, wait); + + data = rtc->irq_data; + + return (data != 0) ? (EPOLLIN | EPOLLRDNORM) : 0; +} + +static long rtc_dev_ioctl(struct file *file, + 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; + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return err; + + /* check that the calling task has appropriate permissions + * for certain ioctls. doing this check here is useful + * to avoid duplicate code in each driver. + */ + switch (cmd) { + case RTC_EPOCH_SET: + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + err = -EACCES; + break; + + case RTC_IRQP_SET: + if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE)) + err = -EACCES; + break; + + case RTC_PIE_ON: + if (rtc->irq_freq > rtc->max_user_freq && + !capable(CAP_SYS_RESOURCE)) + err = -EACCES; + break; + } + + if (err) + goto done; + + /* + * Drivers *SHOULD NOT* provide ioctl implementations + * for these requests. Instead, provide methods to + * support the following code, so that the RTC's main + * features are accessible without using ioctls. + * + * RTC and alarm times will be in UTC, by preference, + * but dual-booting with MS-Windows implies RTCs must + * use the local wall clock time. + */ + + switch (cmd) { + case RTC_ALM_READ: + mutex_unlock(&rtc->ops_lock); + + err = rtc_read_alarm(rtc, &alarm); + if (err < 0) + return err; + + if (copy_to_user(uarg, &alarm.time, sizeof(tm))) + err = -EFAULT; + return err; + + case RTC_ALM_SET: + mutex_unlock(&rtc->ops_lock); + + if (copy_from_user(&alarm.time, uarg, sizeof(tm))) + return -EFAULT; + + alarm.enabled = 0; + alarm.pending = 0; + alarm.time.tm_wday = -1; + alarm.time.tm_yday = -1; + alarm.time.tm_isdst = -1; + + /* RTC_ALM_SET alarms may be up to 24 hours in the future. + * Rather than expecting every RTC to implement "don't care" + * for day/month/year fields, just force the alarm to have + * the right values for those fields. + * + * RTC_WKALM_SET should be used instead. Not only does it + * eliminate the need for a separate RTC_AIE_ON call, it + * doesn't have the "alarm 23:59:59 in the future" race. + * + * NOTE: some legacy code may have used invalid fields as + * wildcards, exposing hardware "periodic alarm" capabilities. + * Not supported here. + */ + { + time64_t now, then; + + err = rtc_read_time(rtc, &tm); + if (err < 0) + return err; + now = rtc_tm_to_time64(&tm); + + alarm.time.tm_mday = tm.tm_mday; + alarm.time.tm_mon = tm.tm_mon; + alarm.time.tm_year = tm.tm_year; + err = rtc_valid_tm(&alarm.time); + if (err < 0) + return err; + then = rtc_tm_to_time64(&alarm.time); + + /* alarm may need to wrap into tomorrow */ + if (then < now) { + rtc_time64_to_tm(now + 24 * 60 * 60, &tm); + alarm.time.tm_mday = tm.tm_mday; + alarm.time.tm_mon = tm.tm_mon; + alarm.time.tm_year = tm.tm_year; + } + } + + return rtc_set_alarm(rtc, &alarm); + + case RTC_RD_TIME: + mutex_unlock(&rtc->ops_lock); + + err = rtc_read_time(rtc, &tm); + if (err < 0) + return err; + + if (copy_to_user(uarg, &tm, sizeof(tm))) + err = -EFAULT; + return err; + + case RTC_SET_TIME: + mutex_unlock(&rtc->ops_lock); + + if (copy_from_user(&tm, uarg, sizeof(tm))) + return -EFAULT; + + return rtc_set_time(rtc, &tm); + + case RTC_PIE_ON: + err = rtc_irq_set_state(rtc, 1); + break; + + case RTC_PIE_OFF: + err = rtc_irq_set_state(rtc, 0); + break; + + case RTC_AIE_ON: + mutex_unlock(&rtc->ops_lock); + return rtc_alarm_irq_enable(rtc, 1); + + case RTC_AIE_OFF: + mutex_unlock(&rtc->ops_lock); + return rtc_alarm_irq_enable(rtc, 0); + + case RTC_UIE_ON: + mutex_unlock(&rtc->ops_lock); + return rtc_update_irq_enable(rtc, 1); + + case RTC_UIE_OFF: + mutex_unlock(&rtc->ops_lock); + return rtc_update_irq_enable(rtc, 0); + + case RTC_IRQP_SET: + err = rtc_irq_set_freq(rtc, arg); + break; + + case RTC_IRQP_READ: + err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); + break; + + case RTC_WKALM_SET: + mutex_unlock(&rtc->ops_lock); + if (copy_from_user(&alarm, uarg, sizeof(alarm))) + return -EFAULT; + + return rtc_set_alarm(rtc, &alarm); + + case RTC_WKALM_RD: + mutex_unlock(&rtc->ops_lock); + err = rtc_read_alarm(rtc, &alarm); + if (err < 0) + return err; + + if (copy_to_user(uarg, &alarm, sizeof(alarm))) + err = -EFAULT; + return err; + + default: + /* Finally try the driver's ioctl interface */ + if (ops->ioctl) { + err = ops->ioctl(rtc->dev.parent, cmd, arg); + if (err == -ENOIOCTLCMD) + err = -ENOTTY; + } else + err = -ENOTTY; + break; + } + +done: + mutex_unlock(&rtc->ops_lock); + return err; +} + +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); +} + +static int rtc_dev_release(struct inode *inode, struct file *file) +{ + struct rtc_device *rtc = file->private_data; + + /* We shut down the repeating IRQs that userspace enabled, + * since nothing is listening to them. + * - Update (UIE) ... currently only managed through ioctls + * - Periodic (PIE) ... also used through rtc_*() interface calls + * + * Leave the alarm alone; it may be set to trigger a system wakeup + * later, or be used by kernel code, and is a one-shot event anyway. + */ + + /* Keep ioctl until all drivers are converted */ + rtc_dev_ioctl(file, RTC_UIE_OFF, 0); + rtc_update_irq_enable(rtc, 0); + rtc_irq_set_state(rtc, 0); + + clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); + return 0; +} + +static const struct file_operations rtc_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = rtc_dev_read, + .poll = rtc_dev_poll, + .unlocked_ioctl = rtc_dev_ioctl, + .open = rtc_dev_open, + .release = rtc_dev_release, + .fasync = rtc_dev_fasync, +}; + +/* insertion/removal hooks */ + +void rtc_dev_prepare(struct rtc_device *rtc) +{ + if (!rtc_devt) + return; + + if (rtc->id >= RTC_DEV_MAX) { + dev_dbg(&rtc->dev, "too many RTC devices\n"); + return; + } + + rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); + +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + INIT_WORK(&rtc->uie_task, rtc_uie_task); + timer_setup(&rtc->uie_timer, rtc_uie_timer, 0); +#endif + + cdev_init(&rtc->char_dev, &rtc_dev_fops); + rtc->char_dev.owner = rtc->owner; +} + +void __init rtc_dev_init(void) +{ + int err; + + err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); + if (err < 0) + pr_err("failed to allocate char dev region\n"); +} + +void __exit rtc_dev_exit(void) +{ + if (rtc_devt) + unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); +} diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c new file mode 100644 index 000000000000..ef160da84220 --- /dev/null +++ b/drivers/rtc/lib.c @@ -0,0 +1,148 @@ +/* + * rtc and date/time utility functions + * + * Copyright (C) 2005-06 Tower Technologies + * Author: Alessandro Zummo + * + * 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 +#include + +static const unsigned char rtc_days_in_month[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static const unsigned short rtc_ydays[2][13] = { + /* Normal years */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years */ + { 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) + +/* + * The number of days in the month. + */ +int rtc_month_days(unsigned int month, unsigned int year) +{ + return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); +} +EXPORT_SYMBOL(rtc_month_days); + +/* + * The number of days since January 1. (0 to 365) + */ +int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) +{ + 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. + */ +void rtc_time64_to_tm(time64_t time, struct rtc_time *tm) +{ + unsigned int month, year, secs; + int days; + + /* time must be positive */ + days = div_s64_rem(time, 86400, &secs); + + /* day of the week, 1970-01-01 was a Thursday */ + tm->tm_wday = (days + 4) % 7; + + year = 1970 + days / 365; + days -= (year - 1970) * 365 + + LEAPS_THRU_END_OF(year - 1) + - LEAPS_THRU_END_OF(1970 - 1); + while (days < 0) { + year -= 1; + days += 365 + is_leap_year(year); + } + tm->tm_year = year - 1900; + tm->tm_yday = days + 1; + + for (month = 0; month < 11; month++) { + int newdays; + + newdays = days - rtc_month_days(month, year); + if (newdays < 0) + break; + days = newdays; + } + tm->tm_mon = month; + tm->tm_mday = days + 1; + + tm->tm_hour = secs / 3600; + secs -= tm->tm_hour * 3600; + tm->tm_min = secs / 60; + tm->tm_sec = secs - tm->tm_min * 60; + + tm->tm_isdst = 0; +} +EXPORT_SYMBOL(rtc_time64_to_tm); + +/* + * Does the rtc_time represent a valid date/time? + */ +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, tm->tm_year + 1900) + || ((unsigned)tm->tm_hour) >= 24 + || ((unsigned)tm->tm_min) >= 60 + || ((unsigned)tm->tm_sec) >= 60) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(rtc_valid_tm); + +/* + * rtc_tm_to_time64 - Converts rtc_time to time64_t. + * Convert Gregorian date to seconds since 01-01-1970 00:00:00. + */ +time64_t rtc_tm_to_time64(struct rtc_time *tm) +{ + return mktime64(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); + +/* + * Convert rtc_time to ktime + */ +ktime_t rtc_tm_to_ktime(struct rtc_time tm) +{ + return ktime_set(rtc_tm_to_time64(&tm), 0); +} +EXPORT_SYMBOL_GPL(rtc_tm_to_ktime); + +/* + * Convert ktime to rtc_time + */ +struct rtc_time rtc_ktime_to_tm(ktime_t kt) +{ + struct timespec64 ts; + struct rtc_time ret; + + ts = ktime_to_timespec64(kt); + /* Round up any ns */ + if (ts.tv_nsec) + ts.tv_sec++; + rtc_time64_to_tm(ts.tv_sec, &ret); + return ret; +} +EXPORT_SYMBOL_GPL(rtc_ktime_to_tm); diff --git a/drivers/rtc/proc.c b/drivers/rtc/proc.c new file mode 100644 index 000000000000..4d74e4f4ff30 --- /dev/null +++ b/drivers/rtc/proc.c @@ -0,0 +1,95 @@ +/* + * RTC subsystem, proc interface + * + * Copyright (C) 2005-06 Tower Technologies + * Author: Alessandro Zummo + * + * 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 +#include +#include +#include + +#include "rtc-core.h" + +#define NAME_SIZE 10 + +#if defined(CONFIG_RTC_HCTOSYS_DEVICE) +static bool is_rtc_hctosys(struct rtc_device *rtc) +{ + int size; + char name[NAME_SIZE]; + + size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); + if (size > NAME_SIZE) + return false; + + return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); +} +#else +static bool is_rtc_hctosys(struct rtc_device *rtc) +{ + return (rtc->id == 0); +} +#endif + +static int rtc_proc_show(struct seq_file *seq, void *offset) +{ + int err; + struct rtc_device *rtc = seq->private; + const struct rtc_class_ops *ops = rtc->ops; + struct rtc_wkalrm alrm; + struct rtc_time tm; + + err = rtc_read_time(rtc, &tm); + if (err == 0) { + seq_printf(seq, + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n", + &tm, &tm); + } + + err = rtc_read_alarm(rtc, &alrm); + if (err == 0) { + 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"); + seq_printf(seq, "alrm_pending\t: %s\n", + alrm.pending ? "yes" : "no"); + seq_printf(seq, "update IRQ enabled\t: %s\n", + (rtc->uie_rtctimer.enabled) ? "yes" : "no"); + seq_printf(seq, "periodic IRQ enabled\t: %s\n", + (rtc->pie_enabled) ? "yes" : "no"); + seq_printf(seq, "periodic IRQ frequency\t: %d\n", + rtc->irq_freq); + seq_printf(seq, "max user IRQ frequency\t: %d\n", + rtc->max_user_freq); + } + + seq_printf(seq, "24hr\t\t: yes\n"); + + if (ops->proc) + ops->proc(rtc->dev.parent, seq); + + return 0; +} + +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); +} + +void rtc_proc_del_device(struct rtc_device *rtc) +{ + if (is_rtc_hctosys(rtc)) + remove_proc_entry("driver/rtc", NULL); +} diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c deleted file mode 100644 index 43d962a9c210..000000000000 --- a/drivers/rtc/rtc-dev.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * RTC subsystem, dev interface - * - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo - * - * 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 -#include -#include -#include "rtc-core.h" - -static dev_t rtc_devt; - -#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */ - -static int rtc_dev_open(struct inode *inode, struct file *file) -{ - struct rtc_device *rtc = container_of(inode->i_cdev, - struct rtc_device, char_dev); - - if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) - return -EBUSY; - - file->private_data = rtc; - - spin_lock_irq(&rtc->irq_lock); - rtc->irq_data = 0; - spin_unlock_irq(&rtc->irq_lock); - - return 0; -} - -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL -/* - * Routine to poll RTC seconds field for change as often as possible, - * after first RTC_UIE use timer to reduce polling - */ -static void rtc_uie_task(struct work_struct *work) -{ - struct rtc_device *rtc = - container_of(work, struct rtc_device, uie_task); - struct rtc_time tm; - int num = 0; - int err; - - err = rtc_read_time(rtc, &tm); - - spin_lock_irq(&rtc->irq_lock); - if (rtc->stop_uie_polling || err) { - rtc->uie_task_active = 0; - } 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_active = 1; - rtc->uie_task_active = 0; - add_timer(&rtc->uie_timer); - } else if (schedule_work(&rtc->uie_task) == 0) { - rtc->uie_task_active = 0; - } - spin_unlock_irq(&rtc->irq_lock); - 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); - unsigned long flags; - - spin_lock_irqsave(&rtc->irq_lock, flags); - rtc->uie_timer_active = 0; - rtc->uie_task_active = 1; - if ((schedule_work(&rtc->uie_task) == 0)) - rtc->uie_task_active = 0; - spin_unlock_irqrestore(&rtc->irq_lock, flags); -} - -static int clear_uie(struct rtc_device *rtc) -{ - spin_lock_irq(&rtc->irq_lock); - if (rtc->uie_irq_active) { - rtc->stop_uie_polling = 1; - if (rtc->uie_timer_active) { - spin_unlock_irq(&rtc->irq_lock); - del_timer_sync(&rtc->uie_timer); - spin_lock_irq(&rtc->irq_lock); - rtc->uie_timer_active = 0; - } - if (rtc->uie_task_active) { - spin_unlock_irq(&rtc->irq_lock); - flush_scheduled_work(); - spin_lock_irq(&rtc->irq_lock); - } - rtc->uie_irq_active = 0; - } - spin_unlock_irq(&rtc->irq_lock); - return 0; -} - -static int set_uie(struct rtc_device *rtc) -{ - struct rtc_time tm; - int err; - - err = rtc_read_time(rtc, &tm); - if (err) - return err; - spin_lock_irq(&rtc->irq_lock); - if (!rtc->uie_irq_active) { - rtc->uie_irq_active = 1; - rtc->stop_uie_polling = 0; - rtc->oldsecs = tm.tm_sec; - rtc->uie_task_active = 1; - if (schedule_work(&rtc->uie_task) == 0) - rtc->uie_task_active = 0; - } - rtc->irq_data = 0; - spin_unlock_irq(&rtc->irq_lock); - return 0; -} - -int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) -{ - if (enabled) - return set_uie(rtc); - else - return clear_uie(rtc); -} -EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); - -#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ - -static ssize_t -rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - struct rtc_device *rtc = file->private_data; - - DECLARE_WAITQUEUE(wait, current); - unsigned long data; - ssize_t ret; - - if (count != sizeof(unsigned int) && count < sizeof(unsigned long)) - return -EINVAL; - - add_wait_queue(&rtc->irq_queue, &wait); - do { - __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irq(&rtc->irq_lock); - data = rtc->irq_data; - rtc->irq_data = 0; - spin_unlock_irq(&rtc->irq_lock); - - if (data != 0) { - ret = 0; - break; - } - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - schedule(); - } while (1); - set_current_state(TASK_RUNNING); - remove_wait_queue(&rtc->irq_queue, &wait); - - if (ret == 0) { - /* Check for any data updates */ - if (rtc->ops->read_callback) - data = rtc->ops->read_callback(rtc->dev.parent, - data); - - if (sizeof(int) != sizeof(long) && - count == sizeof(unsigned int)) - ret = put_user(data, (unsigned int __user *)buf) ?: - sizeof(unsigned int); - else - ret = put_user(data, (unsigned long __user *)buf) ?: - sizeof(unsigned long); - } - return ret; -} - -static __poll_t rtc_dev_poll(struct file *file, poll_table *wait) -{ - struct rtc_device *rtc = file->private_data; - unsigned long data; - - poll_wait(file, &rtc->irq_queue, wait); - - data = rtc->irq_data; - - return (data != 0) ? (EPOLLIN | EPOLLRDNORM) : 0; -} - -static long rtc_dev_ioctl(struct file *file, - 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; - - err = mutex_lock_interruptible(&rtc->ops_lock); - if (err) - return err; - - /* check that the calling task has appropriate permissions - * for certain ioctls. doing this check here is useful - * to avoid duplicate code in each driver. - */ - switch (cmd) { - case RTC_EPOCH_SET: - case RTC_SET_TIME: - if (!capable(CAP_SYS_TIME)) - err = -EACCES; - break; - - case RTC_IRQP_SET: - if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE)) - err = -EACCES; - break; - - case RTC_PIE_ON: - if (rtc->irq_freq > rtc->max_user_freq && - !capable(CAP_SYS_RESOURCE)) - err = -EACCES; - break; - } - - if (err) - goto done; - - /* - * Drivers *SHOULD NOT* provide ioctl implementations - * for these requests. Instead, provide methods to - * support the following code, so that the RTC's main - * features are accessible without using ioctls. - * - * RTC and alarm times will be in UTC, by preference, - * but dual-booting with MS-Windows implies RTCs must - * use the local wall clock time. - */ - - switch (cmd) { - case RTC_ALM_READ: - mutex_unlock(&rtc->ops_lock); - - err = rtc_read_alarm(rtc, &alarm); - if (err < 0) - return err; - - if (copy_to_user(uarg, &alarm.time, sizeof(tm))) - err = -EFAULT; - return err; - - case RTC_ALM_SET: - mutex_unlock(&rtc->ops_lock); - - if (copy_from_user(&alarm.time, uarg, sizeof(tm))) - return -EFAULT; - - alarm.enabled = 0; - alarm.pending = 0; - alarm.time.tm_wday = -1; - alarm.time.tm_yday = -1; - alarm.time.tm_isdst = -1; - - /* RTC_ALM_SET alarms may be up to 24 hours in the future. - * Rather than expecting every RTC to implement "don't care" - * for day/month/year fields, just force the alarm to have - * the right values for those fields. - * - * RTC_WKALM_SET should be used instead. Not only does it - * eliminate the need for a separate RTC_AIE_ON call, it - * doesn't have the "alarm 23:59:59 in the future" race. - * - * NOTE: some legacy code may have used invalid fields as - * wildcards, exposing hardware "periodic alarm" capabilities. - * Not supported here. - */ - { - time64_t now, then; - - err = rtc_read_time(rtc, &tm); - if (err < 0) - return err; - now = rtc_tm_to_time64(&tm); - - alarm.time.tm_mday = tm.tm_mday; - alarm.time.tm_mon = tm.tm_mon; - alarm.time.tm_year = tm.tm_year; - err = rtc_valid_tm(&alarm.time); - if (err < 0) - return err; - then = rtc_tm_to_time64(&alarm.time); - - /* alarm may need to wrap into tomorrow */ - if (then < now) { - rtc_time64_to_tm(now + 24 * 60 * 60, &tm); - alarm.time.tm_mday = tm.tm_mday; - alarm.time.tm_mon = tm.tm_mon; - alarm.time.tm_year = tm.tm_year; - } - } - - return rtc_set_alarm(rtc, &alarm); - - case RTC_RD_TIME: - mutex_unlock(&rtc->ops_lock); - - err = rtc_read_time(rtc, &tm); - if (err < 0) - return err; - - if (copy_to_user(uarg, &tm, sizeof(tm))) - err = -EFAULT; - return err; - - case RTC_SET_TIME: - mutex_unlock(&rtc->ops_lock); - - if (copy_from_user(&tm, uarg, sizeof(tm))) - return -EFAULT; - - return rtc_set_time(rtc, &tm); - - case RTC_PIE_ON: - err = rtc_irq_set_state(rtc, 1); - break; - - case RTC_PIE_OFF: - err = rtc_irq_set_state(rtc, 0); - break; - - case RTC_AIE_ON: - mutex_unlock(&rtc->ops_lock); - return rtc_alarm_irq_enable(rtc, 1); - - case RTC_AIE_OFF: - mutex_unlock(&rtc->ops_lock); - return rtc_alarm_irq_enable(rtc, 0); - - case RTC_UIE_ON: - mutex_unlock(&rtc->ops_lock); - return rtc_update_irq_enable(rtc, 1); - - case RTC_UIE_OFF: - mutex_unlock(&rtc->ops_lock); - return rtc_update_irq_enable(rtc, 0); - - case RTC_IRQP_SET: - err = rtc_irq_set_freq(rtc, arg); - break; - - case RTC_IRQP_READ: - err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); - break; - - case RTC_WKALM_SET: - mutex_unlock(&rtc->ops_lock); - if (copy_from_user(&alarm, uarg, sizeof(alarm))) - return -EFAULT; - - return rtc_set_alarm(rtc, &alarm); - - case RTC_WKALM_RD: - mutex_unlock(&rtc->ops_lock); - err = rtc_read_alarm(rtc, &alarm); - if (err < 0) - return err; - - if (copy_to_user(uarg, &alarm, sizeof(alarm))) - err = -EFAULT; - return err; - - default: - /* Finally try the driver's ioctl interface */ - if (ops->ioctl) { - err = ops->ioctl(rtc->dev.parent, cmd, arg); - if (err == -ENOIOCTLCMD) - err = -ENOTTY; - } else - err = -ENOTTY; - break; - } - -done: - mutex_unlock(&rtc->ops_lock); - return err; -} - -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); -} - -static int rtc_dev_release(struct inode *inode, struct file *file) -{ - struct rtc_device *rtc = file->private_data; - - /* We shut down the repeating IRQs that userspace enabled, - * since nothing is listening to them. - * - Update (UIE) ... currently only managed through ioctls - * - Periodic (PIE) ... also used through rtc_*() interface calls - * - * Leave the alarm alone; it may be set to trigger a system wakeup - * later, or be used by kernel code, and is a one-shot event anyway. - */ - - /* Keep ioctl until all drivers are converted */ - rtc_dev_ioctl(file, RTC_UIE_OFF, 0); - rtc_update_irq_enable(rtc, 0); - rtc_irq_set_state(rtc, 0); - - clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); - return 0; -} - -static const struct file_operations rtc_dev_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = rtc_dev_read, - .poll = rtc_dev_poll, - .unlocked_ioctl = rtc_dev_ioctl, - .open = rtc_dev_open, - .release = rtc_dev_release, - .fasync = rtc_dev_fasync, -}; - -/* insertion/removal hooks */ - -void rtc_dev_prepare(struct rtc_device *rtc) -{ - if (!rtc_devt) - return; - - if (rtc->id >= RTC_DEV_MAX) { - dev_dbg(&rtc->dev, "too many RTC devices\n"); - return; - } - - rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); - -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - INIT_WORK(&rtc->uie_task, rtc_uie_task); - timer_setup(&rtc->uie_timer, rtc_uie_timer, 0); -#endif - - cdev_init(&rtc->char_dev, &rtc_dev_fops); - rtc->char_dev.owner = rtc->owner; -} - -void __init rtc_dev_init(void) -{ - int err; - - err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); - if (err < 0) - pr_err("failed to allocate char dev region\n"); -} - -void __exit rtc_dev_exit(void) -{ - if (rtc_devt) - unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); -} diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c deleted file mode 100644 index ef160da84220..000000000000 --- a/drivers/rtc/rtc-lib.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * rtc and date/time utility functions - * - * Copyright (C) 2005-06 Tower Technologies - * Author: Alessandro Zummo - * - * 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 -#include - -static const unsigned char rtc_days_in_month[] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -static const unsigned short rtc_ydays[2][13] = { - /* Normal years */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years */ - { 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) - -/* - * The number of days in the month. - */ -int rtc_month_days(unsigned int month, unsigned int year) -{ - return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); -} -EXPORT_SYMBOL(rtc_month_days); - -/* - * The number of days since January 1. (0 to 365) - */ -int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) -{ - 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. - */ -void rtc_time64_to_tm(time64_t time, struct rtc_time *tm) -{ - unsigned int month, year, secs; - int days; - - /* time must be positive */ - days = div_s64_rem(time, 86400, &secs); - - /* day of the week, 1970-01-01 was a Thursday */ - tm->tm_wday = (days + 4) % 7; - - year = 1970 + days / 365; - days -= (year - 1970) * 365 - + LEAPS_THRU_END_OF(year - 1) - - LEAPS_THRU_END_OF(1970 - 1); - while (days < 0) { - year -= 1; - days += 365 + is_leap_year(year); - } - tm->tm_year = year - 1900; - tm->tm_yday = days + 1; - - for (month = 0; month < 11; month++) { - int newdays; - - newdays = days - rtc_month_days(month, year); - if (newdays < 0) - break; - days = newdays; - } - tm->tm_mon = month; - tm->tm_mday = days + 1; - - tm->tm_hour = secs / 3600; - secs -= tm->tm_hour * 3600; - tm->tm_min = secs / 60; - tm->tm_sec = secs - tm->tm_min * 60; - - tm->tm_isdst = 0; -} -EXPORT_SYMBOL(rtc_time64_to_tm); - -/* - * Does the rtc_time represent a valid date/time? - */ -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, tm->tm_year + 1900) - || ((unsigned)tm->tm_hour) >= 24 - || ((unsigned)tm->tm_min) >= 60 - || ((unsigned)tm->tm_sec) >= 60) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL(rtc_valid_tm); - -/* - * rtc_tm_to_time64 - Converts rtc_time to time64_t. - * Convert Gregorian date to seconds since 01-01-1970 00:00:00. - */ -time64_t rtc_tm_to_time64(struct rtc_time *tm) -{ - return mktime64(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); - -/* - * Convert rtc_time to ktime - */ -ktime_t rtc_tm_to_ktime(struct rtc_time tm) -{ - return ktime_set(rtc_tm_to_time64(&tm), 0); -} -EXPORT_SYMBOL_GPL(rtc_tm_to_ktime); - -/* - * Convert ktime to rtc_time - */ -struct rtc_time rtc_ktime_to_tm(ktime_t kt) -{ - struct timespec64 ts; - struct rtc_time ret; - - ts = ktime_to_timespec64(kt); - /* Round up any ns */ - if (ts.tv_nsec) - ts.tv_sec++; - rtc_time64_to_tm(ts.tv_sec, &ret); - return ret; -} -EXPORT_SYMBOL_GPL(rtc_ktime_to_tm); diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c deleted file mode 100644 index 4d74e4f4ff30..000000000000 --- a/drivers/rtc/rtc-proc.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * RTC subsystem, proc interface - * - * Copyright (C) 2005-06 Tower Technologies - * Author: Alessandro Zummo - * - * 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 -#include -#include -#include - -#include "rtc-core.h" - -#define NAME_SIZE 10 - -#if defined(CONFIG_RTC_HCTOSYS_DEVICE) -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - int size; - char name[NAME_SIZE]; - - size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); - if (size > NAME_SIZE) - return false; - - return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); -} -#else -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - return (rtc->id == 0); -} -#endif - -static int rtc_proc_show(struct seq_file *seq, void *offset) -{ - int err; - struct rtc_device *rtc = seq->private; - const struct rtc_class_ops *ops = rtc->ops; - struct rtc_wkalrm alrm; - struct rtc_time tm; - - err = rtc_read_time(rtc, &tm); - if (err == 0) { - seq_printf(seq, - "rtc_time\t: %ptRt\n" - "rtc_date\t: %ptRd\n", - &tm, &tm); - } - - err = rtc_read_alarm(rtc, &alrm); - if (err == 0) { - 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"); - seq_printf(seq, "alrm_pending\t: %s\n", - alrm.pending ? "yes" : "no"); - seq_printf(seq, "update IRQ enabled\t: %s\n", - (rtc->uie_rtctimer.enabled) ? "yes" : "no"); - seq_printf(seq, "periodic IRQ enabled\t: %s\n", - (rtc->pie_enabled) ? "yes" : "no"); - seq_printf(seq, "periodic IRQ frequency\t: %d\n", - rtc->irq_freq); - seq_printf(seq, "max user IRQ frequency\t: %d\n", - rtc->max_user_freq); - } - - seq_printf(seq, "24hr\t\t: yes\n"); - - if (ops->proc) - ops->proc(rtc->dev.parent, seq); - - return 0; -} - -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); -} - -void rtc_proc_del_device(struct rtc_device *rtc) -{ - if (is_rtc_hctosys(rtc)) - remove_proc_entry("driver/rtc", NULL); -} diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c deleted file mode 100644 index a8f22ee726bb..000000000000 --- a/drivers/rtc/rtc-sysfs.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * RTC subsystem, sysfs interface - * - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo - * - * 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 -#include - -#include "rtc-core.h" - - -/* device attributes */ - -/* - * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's - * ideally UTC. However, PCs that also boot to MS-Windows normally use - * the local time and change to match daylight savings time. That affects - * attributes including date, time, since_epoch, and wakealarm. - */ - -static ssize_t -name_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent), - dev_name(dev->parent)); -} -static DEVICE_ATTR_RO(name); - -static ssize_t -date_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct rtc_time tm; - - retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval) - return retval; - - return sprintf(buf, "%ptRd\n", &tm); -} -static DEVICE_ATTR_RO(date); - -static ssize_t -time_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct rtc_time tm; - - retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval) - return retval; - - return sprintf(buf, "%ptRt\n", &tm); -} -static DEVICE_ATTR_RO(time); - -static ssize_t -since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct rtc_time tm; - - retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval == 0) { - time64_t time; - - time = rtc_tm_to_time64(&tm); - retval = sprintf(buf, "%lld\n", time); - } - - return retval; -} -static DEVICE_ATTR_RO(since_epoch); - -static ssize_t -max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); -} - -static ssize_t -max_user_freq_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct rtc_device *rtc = to_rtc_device(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 0, &val); - if (err) - return err; - - if (val >= 4096 || val == 0) - return -EINVAL; - - rtc->max_user_freq = (int)val; - - return n; -} -static DEVICE_ATTR_RW(max_user_freq); - -/** - * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time - * - * Returns 1 if the system clock was set by this RTC at the last - * boot or resume event. - */ -static ssize_t -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) - return sprintf(buf, "1\n"); - else -#endif - return sprintf(buf, "0\n"); -} -static DEVICE_ATTR_RO(hctosys); - -static ssize_t -wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - time64_t alarm; - struct rtc_wkalrm alm; - - /* Don't show disabled alarms. For uniformity, RTC alarms are - * conceptually one-shot, even though some common RTCs (on PCs) - * don't actually work that way. - * - * NOTE: RTC implementations where the alarm doesn't match an - * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC - * alarms after they trigger, to ensure one-shot semantics. - */ - retval = rtc_read_alarm(to_rtc_device(dev), &alm); - if (retval == 0 && alm.enabled) { - alarm = rtc_tm_to_time64(&alm.time); - retval = sprintf(buf, "%lld\n", alarm); - } - - return retval; -} - -static ssize_t -wakealarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - ssize_t retval; - time64_t now, alarm; - time64_t push = 0; - struct rtc_wkalrm alm; - struct rtc_device *rtc = to_rtc_device(dev); - const char *buf_ptr; - int adjust = 0; - - /* Only request alarms that trigger in the future. Disable them - * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. - */ - retval = rtc_read_time(rtc, &alm.time); - if (retval < 0) - return retval; - now = rtc_tm_to_time64(&alm.time); - - buf_ptr = buf; - if (*buf_ptr == '+') { - buf_ptr++; - if (*buf_ptr == '=') { - buf_ptr++; - push = 1; - } else - adjust = 1; - } - retval = kstrtos64(buf_ptr, 0, &alarm); - if (retval) - return retval; - if (adjust) { - alarm += now; - } - if (alarm > now || push) { - /* Avoid accidentally clobbering active alarms; we can't - * entirely prevent that here, without even the minimal - * locking from the /dev/rtcN api. - */ - retval = rtc_read_alarm(rtc, &alm); - if (retval < 0) - return retval; - if (alm.enabled) { - if (push) { - push = rtc_tm_to_time64(&alm.time); - alarm += push; - } else - return -EBUSY; - } else if (push) - return -EINVAL; - alm.enabled = 1; - } else { - alm.enabled = 0; - - /* Provide a valid future alarm time. Linux isn't EFI, - * this time won't be ignored when disabling the alarm. - */ - alarm = now + 300; - } - rtc_time64_to_tm(alarm, &alm.time); - - retval = rtc_set_alarm(rtc, &alm); - return (retval < 0) ? retval : n; -} -static DEVICE_ATTR_RW(wakealarm); - -static ssize_t -offset_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - long offset; - - retval = rtc_read_offset(to_rtc_device(dev), &offset); - if (retval == 0) - retval = sprintf(buf, "%ld\n", offset); - - return retval; -} - -static ssize_t -offset_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - ssize_t retval; - long offset; - - retval = kstrtol(buf, 10, &offset); - if (retval == 0) - retval = rtc_set_offset(to_rtc_device(dev), offset); - - return (retval < 0) ? retval : n; -} -static DEVICE_ATTR_RW(offset); - -static ssize_t -range_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min, - to_rtc_device(dev)->range_max); -} -static DEVICE_ATTR_RO(range); - -static struct attribute *rtc_attrs[] = { - &dev_attr_name.attr, - &dev_attr_date.attr, - &dev_attr_time.attr, - &dev_attr_since_epoch.attr, - &dev_attr_max_user_freq.attr, - &dev_attr_hctosys.attr, - &dev_attr_wakealarm.attr, - &dev_attr_offset.attr, - &dev_attr_range.attr, - NULL, -}; - -/* The reason to trigger an alarm with no process watching it (via sysfs) - * is its side effect: waking from a system state like suspend-to-RAM or - * suspend-to-disk. So: no attribute unless that side effect is possible. - * (Userspace may disable that mechanism later.) - */ -static bool rtc_does_wakealarm(struct rtc_device *rtc) -{ - if (!device_can_wakeup(rtc->dev.parent)) - return false; - - return rtc->ops->set_alarm != NULL; -} - -static umode_t rtc_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int n) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct rtc_device *rtc = to_rtc_device(dev); - umode_t mode = attr->mode; - - if (attr == &dev_attr_wakealarm.attr) { - if (!rtc_does_wakealarm(rtc)) - mode = 0; - } else if (attr == &dev_attr_offset.attr) { - if (!rtc->ops->set_offset) - mode = 0; - } else if (attr == &dev_attr_range.attr) { - if (!(rtc->range_max - rtc->range_min)) - mode = 0; - } - - return mode; -} - -static struct attribute_group rtc_attr_group = { - .is_visible = rtc_attr_is_visible, - .attrs = rtc_attrs, -}; - -static const struct attribute_group *rtc_attr_groups[] = { - &rtc_attr_group, - NULL -}; - -const struct attribute_group **rtc_get_dev_attribute_groups(void) -{ - return rtc_attr_groups; -} - -int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) -{ - size_t old_cnt = 0, add_cnt = 0, new_cnt; - const struct attribute_group **groups, **old; - - if (rtc->registered) - return -EINVAL; - if (!grps) - return -EINVAL; - - groups = rtc->dev.groups; - if (groups) - for (; *groups; groups++) - old_cnt++; - - for (groups = grps; *groups; groups++) - add_cnt++; - - new_cnt = old_cnt + add_cnt + 1; - groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL); - if (!groups) - return -ENOMEM; - memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups)); - memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups)); - groups[old_cnt + add_cnt] = NULL; - - old = rtc->dev.groups; - rtc->dev.groups = groups; - if (old && old != rtc_attr_groups) - devm_kfree(&rtc->dev, old); - - return 0; -} -EXPORT_SYMBOL(rtc_add_groups); - -int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) -{ - const struct attribute_group *groups[] = { grp, NULL }; - - return rtc_add_groups(rtc, groups); -} -EXPORT_SYMBOL(rtc_add_group); diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c new file mode 100644 index 000000000000..a8f22ee726bb --- /dev/null +++ b/drivers/rtc/sysfs.c @@ -0,0 +1,358 @@ +/* + * RTC subsystem, sysfs interface + * + * Copyright (C) 2005 Tower Technologies + * Author: Alessandro Zummo + * + * 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 +#include + +#include "rtc-core.h" + + +/* device attributes */ + +/* + * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's + * ideally UTC. However, PCs that also boot to MS-Windows normally use + * the local time and change to match daylight savings time. That affects + * attributes including date, time, since_epoch, and wakealarm. + */ + +static ssize_t +name_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent), + dev_name(dev->parent)); +} +static DEVICE_ATTR_RO(name); + +static ssize_t +date_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct rtc_time tm; + + retval = rtc_read_time(to_rtc_device(dev), &tm); + if (retval) + return retval; + + return sprintf(buf, "%ptRd\n", &tm); +} +static DEVICE_ATTR_RO(date); + +static ssize_t +time_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct rtc_time tm; + + retval = rtc_read_time(to_rtc_device(dev), &tm); + if (retval) + return retval; + + return sprintf(buf, "%ptRt\n", &tm); +} +static DEVICE_ATTR_RO(time); + +static ssize_t +since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct rtc_time tm; + + retval = rtc_read_time(to_rtc_device(dev), &tm); + if (retval == 0) { + time64_t time; + + time = rtc_tm_to_time64(&tm); + retval = sprintf(buf, "%lld\n", time); + } + + return retval; +} +static DEVICE_ATTR_RO(since_epoch); + +static ssize_t +max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); +} + +static ssize_t +max_user_freq_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct rtc_device *rtc = to_rtc_device(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 0, &val); + if (err) + return err; + + if (val >= 4096 || val == 0) + return -EINVAL; + + rtc->max_user_freq = (int)val; + + return n; +} +static DEVICE_ATTR_RW(max_user_freq); + +/** + * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time + * + * Returns 1 if the system clock was set by this RTC at the last + * boot or resume event. + */ +static ssize_t +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) + return sprintf(buf, "1\n"); + else +#endif + return sprintf(buf, "0\n"); +} +static DEVICE_ATTR_RO(hctosys); + +static ssize_t +wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + time64_t alarm; + struct rtc_wkalrm alm; + + /* Don't show disabled alarms. For uniformity, RTC alarms are + * conceptually one-shot, even though some common RTCs (on PCs) + * don't actually work that way. + * + * NOTE: RTC implementations where the alarm doesn't match an + * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC + * alarms after they trigger, to ensure one-shot semantics. + */ + retval = rtc_read_alarm(to_rtc_device(dev), &alm); + if (retval == 0 && alm.enabled) { + alarm = rtc_tm_to_time64(&alm.time); + retval = sprintf(buf, "%lld\n", alarm); + } + + return retval; +} + +static ssize_t +wakealarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + ssize_t retval; + time64_t now, alarm; + time64_t push = 0; + struct rtc_wkalrm alm; + struct rtc_device *rtc = to_rtc_device(dev); + const char *buf_ptr; + int adjust = 0; + + /* Only request alarms that trigger in the future. Disable them + * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. + */ + retval = rtc_read_time(rtc, &alm.time); + if (retval < 0) + return retval; + now = rtc_tm_to_time64(&alm.time); + + buf_ptr = buf; + if (*buf_ptr == '+') { + buf_ptr++; + if (*buf_ptr == '=') { + buf_ptr++; + push = 1; + } else + adjust = 1; + } + retval = kstrtos64(buf_ptr, 0, &alarm); + if (retval) + return retval; + if (adjust) { + alarm += now; + } + if (alarm > now || push) { + /* Avoid accidentally clobbering active alarms; we can't + * entirely prevent that here, without even the minimal + * locking from the /dev/rtcN api. + */ + retval = rtc_read_alarm(rtc, &alm); + if (retval < 0) + return retval; + if (alm.enabled) { + if (push) { + push = rtc_tm_to_time64(&alm.time); + alarm += push; + } else + return -EBUSY; + } else if (push) + return -EINVAL; + alm.enabled = 1; + } else { + alm.enabled = 0; + + /* Provide a valid future alarm time. Linux isn't EFI, + * this time won't be ignored when disabling the alarm. + */ + alarm = now + 300; + } + rtc_time64_to_tm(alarm, &alm.time); + + retval = rtc_set_alarm(rtc, &alm); + return (retval < 0) ? retval : n; +} +static DEVICE_ATTR_RW(wakealarm); + +static ssize_t +offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + long offset; + + retval = rtc_read_offset(to_rtc_device(dev), &offset); + if (retval == 0) + retval = sprintf(buf, "%ld\n", offset); + + return retval; +} + +static ssize_t +offset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + ssize_t retval; + long offset; + + retval = kstrtol(buf, 10, &offset); + if (retval == 0) + retval = rtc_set_offset(to_rtc_device(dev), offset); + + return (retval < 0) ? retval : n; +} +static DEVICE_ATTR_RW(offset); + +static ssize_t +range_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min, + to_rtc_device(dev)->range_max); +} +static DEVICE_ATTR_RO(range); + +static struct attribute *rtc_attrs[] = { + &dev_attr_name.attr, + &dev_attr_date.attr, + &dev_attr_time.attr, + &dev_attr_since_epoch.attr, + &dev_attr_max_user_freq.attr, + &dev_attr_hctosys.attr, + &dev_attr_wakealarm.attr, + &dev_attr_offset.attr, + &dev_attr_range.attr, + NULL, +}; + +/* The reason to trigger an alarm with no process watching it (via sysfs) + * is its side effect: waking from a system state like suspend-to-RAM or + * suspend-to-disk. So: no attribute unless that side effect is possible. + * (Userspace may disable that mechanism later.) + */ +static bool rtc_does_wakealarm(struct rtc_device *rtc) +{ + if (!device_can_wakeup(rtc->dev.parent)) + return false; + + return rtc->ops->set_alarm != NULL; +} + +static umode_t rtc_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct rtc_device *rtc = to_rtc_device(dev); + umode_t mode = attr->mode; + + if (attr == &dev_attr_wakealarm.attr) { + if (!rtc_does_wakealarm(rtc)) + mode = 0; + } else if (attr == &dev_attr_offset.attr) { + if (!rtc->ops->set_offset) + mode = 0; + } else if (attr == &dev_attr_range.attr) { + if (!(rtc->range_max - rtc->range_min)) + mode = 0; + } + + return mode; +} + +static struct attribute_group rtc_attr_group = { + .is_visible = rtc_attr_is_visible, + .attrs = rtc_attrs, +}; + +static const struct attribute_group *rtc_attr_groups[] = { + &rtc_attr_group, + NULL +}; + +const struct attribute_group **rtc_get_dev_attribute_groups(void) +{ + return rtc_attr_groups; +} + +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) +{ + size_t old_cnt = 0, add_cnt = 0, new_cnt; + const struct attribute_group **groups, **old; + + if (rtc->registered) + return -EINVAL; + if (!grps) + return -EINVAL; + + groups = rtc->dev.groups; + if (groups) + for (; *groups; groups++) + old_cnt++; + + for (groups = grps; *groups; groups++) + add_cnt++; + + new_cnt = old_cnt + add_cnt + 1; + groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL); + if (!groups) + return -ENOMEM; + memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups)); + memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups)); + groups[old_cnt + add_cnt] = NULL; + + old = rtc->dev.groups; + rtc->dev.groups = groups; + if (old && old != rtc_attr_groups) + devm_kfree(&rtc->dev, old); + + return 0; +} +EXPORT_SYMBOL(rtc_add_groups); + +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) +{ + const struct attribute_group *groups[] = { grp, NULL }; + + return rtc_add_groups(rtc, groups); +} +EXPORT_SYMBOL(rtc_add_group); -- cgit