diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-13 21:15:06 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-13 21:15:06 +0200 |
commit | 3a00be19238ca330ce43abd33caac8eff343800c (patch) | |
tree | a19fd8bac6b20a6b7a5e742fb60adb629ce8c3e0 /drivers/rtc | |
parent | Merge tag 'for-linus-20170713' of git://git.infradead.org/linux-mtd (diff) | |
parent | rtc: Remove wrong deprecation comment (diff) | |
download | linux-3a00be19238ca330ce43abd33caac8eff343800c.tar.xz linux-3a00be19238ca330ce43abd33caac8eff343800c.zip |
Merge tag 'rtc-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni:
"Here is the pull-request for the RTC subsystem for 4.13.
Subsystem:
- expose non volatile RAM using nvmem instead of open coding in many
drivers. Unfortunately, this option has to be enabled by default to
not break existing users.
- rtctest can now test for cutoff dates, showing when an RTC will
start failing to properly save time and date.
- new RTC registration functions to remove race conditions in drivers
Newly supported RTCs:
- Broadcom STB wake-timer
- Epson RX8130CE
- Maxim IC DS1308
- STMicroelectronics STM32H7
Drivers:
- ds1307: use regmap, use nvmem, more cleanups
- ds3232: temperature reading support
- gemini: renamed to ftrtc010
- m41t80: use CCF to expose the clock
- rv8803: use nvmem
- s3c: many cleanups
- st-lpc: fix y2106 bug"
* tag 'rtc-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (51 commits)
rtc: Remove wrong deprecation comment
nvmem: include linux/err.h from header
rtc: st-lpc: make it robust against y2038/2106 bug
rtc: rtctest: add check for problematic dates
tools: timer: add rtctest_setdate
rtc: ds1307: remove ds1307_remove
rtc: ds1307: use generic nvmem
rtc: ds1307: switch to rtc_register_device
rtc: rv8803: remove rv8803_remove
rtc: rv8803: use generic nvmem support
rtc: rv8803: switch to rtc_register_device
rtc: add generic nvmem support
rtc: at91rm9200: remove race condition
rtc: introduce new registration method
rtc: class separate id allocation from registration
rtc: class separate device allocation from registration
rtc: stm32: add STM32H7 RTC support
dt-bindings: rtc: stm32: add support for STM32H7
rtc: ds1307: add ds1308 variant
rtc: ds3232: add temperature support
...
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 37 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 4 | ||||
-rw-r--r-- | drivers/rtc/class.c | 202 | ||||
-rw-r--r-- | drivers/rtc/interface.c | 9 | ||||
-rw-r--r-- | drivers/rtc/nvmem.c | 113 | ||||
-rw-r--r-- | drivers/rtc/rtc-at91rm9200.c | 14 | ||||
-rw-r--r-- | drivers/rtc/rtc-brcmstb-waketimer.c | 330 | ||||
-rw-r--r-- | drivers/rtc/rtc-core.h | 8 | ||||
-rw-r--r-- | drivers/rtc/rtc-dev.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 957 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds3232.c | 119 | ||||
-rw-r--r-- | drivers/rtc/rtc-ftrtc010.c (renamed from drivers/rtc/rtc-gemini.c) | 119 | ||||
-rw-r--r-- | drivers/rtc/rtc-m41t80.c | 251 | ||||
-rw-r--r-- | drivers/rtc/rtc-mxc.c | 11 | ||||
-rw-r--r-- | drivers/rtc/rtc-nuc900.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-opal.c | 32 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-rv8803.c | 72 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 147 | ||||
-rw-r--r-- | drivers/rtc/rtc-st-lpc.c | 19 | ||||
-rw-r--r-- | drivers/rtc/rtc-stm32.c | 82 | ||||
-rw-r--r-- | drivers/rtc/rtc-sysfs.c | 3 |
22 files changed, 1696 insertions, 839 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8d3b95728326..72419ac2c52a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -77,6 +77,14 @@ config RTC_DEBUG Say yes here to enable debugging support in the RTC framework and individual RTC drivers. +config RTC_NVMEM + bool "RTC non volatile storage support" + select NVMEM + default RTC_CLASS + help + Say yes here to add support for the non volatile (often battery + backed) storage present on RTCs. + comment "RTC interfaces" config RTC_INTF_SYSFS @@ -197,6 +205,17 @@ config RTC_DRV_AC100 This driver can also be built as a module. If so, the module will be called rtc-ac100. +config RTC_DRV_BRCMSTB + tristate "Broadcom STB wake-timer" + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST + default ARCH_BRCMSTB || BMIPS_GENERIC + help + If you say yes here you get support for the wake-timer found on + Broadcom STB SoCs (BCM7xxx). + + This driver can also be built as a module. If so, the module will + be called rtc-brcmstb-waketimer. + config RTC_DRV_AS3722 tristate "ams AS3722 RTC driver" depends on MFD_AS3722 @@ -791,6 +810,14 @@ config RTC_DRV_DS3232 This driver can also be built as a module. If so, the module will be called rtc-ds3232. +config RTC_DRV_DS3232_HWMON + bool "HWMON support for Dallas/Maxim DS3232/DS3234" + depends on RTC_DRV_DS3232 && HWMON && !(RTC_DRV_DS3232=y && HWMON=m) + default y + help + Say Y here if you want to expose temperature sensor data on + rtc-ds3232 + config RTC_DRV_PCF2127 tristate "NXP PCF2127" depends on RTC_I2C_AND_SPI @@ -1484,16 +1511,16 @@ config RTC_DRV_ARMADA38X This driver can also be built as a module. If so, the module will be called armada38x-rtc. -config RTC_DRV_GEMINI - tristate "Gemini SoC RTC" - depends on ARCH_GEMINI || COMPILE_TEST +config RTC_DRV_FTRTC010 + tristate "Faraday Technology FTRTC010 RTC" depends on HAS_IOMEM + default ARCH_GEMINI help If you say Y here you will get support for the - RTC found on Gemini SoC's. + Faraday Technolog FTRTC010 found on e.g. Gemini SoC's. This driver can also be built as a module. If so, the module - will be called rtc-gemini. + will be called rtc-ftrtc010. config RTC_DRV_PS3 tristate "PS3 RTC" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 13857d2fce09..acd366b41c85 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -15,6 +15,7 @@ ifdef CONFIG_RTC_DRV_EFI 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 @@ -36,6 +37,7 @@ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o +obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o @@ -67,7 +69,7 @@ obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o -obj-$(CONFIG_RTC_DRV_GEMINI) += rtc-gemini.o +obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 5fb439897fe1..2ed970d61da1 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -150,59 +150,19 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume); #define RTC_CLASS_DEV_PM_OPS NULL #endif - -/** - * 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. - */ -struct rtc_device *rtc_device_register(const char *name, struct device *dev, - const struct rtc_class_ops *ops, - struct module *owner) +/* Ensure the caller will set the id before releasing the device */ +static struct rtc_device *rtc_allocate_device(void) { struct rtc_device *rtc; - struct rtc_wkalrm alrm; - int of_id = -1, id = -1, err; - - if (dev->of_node) - of_id = of_alias_get_id(dev->of_node, "rtc"); - else if (dev->parent && dev->parent->of_node) - of_id = of_alias_get_id(dev->parent->of_node, "rtc"); - if (of_id >= 0) { - id = ida_simple_get(&rtc_ida, of_id, of_id + 1, - GFP_KERNEL); - if (id < 0) - dev_warn(dev, "/aliases ID %d not available\n", - of_id); - } - - if (id < 0) { - id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); - if (id < 0) { - err = id; - goto exit; - } - } - - rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); - if (rtc == NULL) { - err = -ENOMEM; - goto exit_ida; - } + rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return NULL; device_initialize(&rtc->dev); - rtc->id = id; - rtc->ops = ops; - rtc->owner = owner; rtc->irq_freq = 1; rtc->max_user_freq = 64; - rtc->dev.parent = dev; rtc->dev.class = rtc_class; rtc->dev.groups = rtc_get_dev_attribute_groups(); rtc->dev.release = rtc_device_release; @@ -224,7 +184,64 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; - strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); + return rtc; +} + +static int rtc_device_get_id(struct device *dev) +{ + int of_id = -1, id = -1; + + if (dev->of_node) + of_id = of_alias_get_id(dev->of_node, "rtc"); + else if (dev->parent && dev->parent->of_node) + of_id = of_alias_get_id(dev->parent->of_node, "rtc"); + + if (of_id >= 0) { + id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL); + if (id < 0) + dev_warn(dev, "/aliases ID %d not available\n", of_id); + } + + if (id < 0) + id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); + + return id; +} + +/** + * 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. + */ +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); /* Check to see if there is an ALARM already set in hw */ @@ -238,20 +255,20 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, err = cdev_device_add(&rtc->char_dev, &rtc->dev); if (err) { dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", - rtc->name, MAJOR(rtc->dev.devt), rtc->id); + 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", rtc->name, + 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", - rtc->name, dev_name(&rtc->dev)); + name, dev_name(&rtc->dev)); return rtc; @@ -273,6 +290,8 @@ EXPORT_SYMBOL_GPL(rtc_device_register); */ void rtc_device_unregister(struct rtc_device *rtc) { + rtc_nvmem_unregister(rtc); + mutex_lock(&rtc->ops_lock); /* * Remove innards of this RTC, then disable it, before @@ -356,6 +375,91 @@ void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc) } 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; + + if (rtc->registered) + rtc_device_unregister(rtc); + else + put_device(&rtc->dev); +} + +struct rtc_device *devm_rtc_allocate_device(struct device *dev) +{ + struct rtc_device **ptr, *rtc; + int id, err; + + id = rtc_device_get_id(dev); + if (id < 0) + return ERR_PTR(id); + + ptr = devres_alloc(devm_rtc_release_device, sizeof(*ptr), GFP_KERNEL); + if (!ptr) { + err = -ENOMEM; + goto exit_ida; + } + + rtc = rtc_allocate_device(); + if (!rtc) { + err = -ENOMEM; + goto exit_devres; + } + + *ptr = rtc; + devres_add(dev, ptr); + + rtc->id = id; + rtc->dev.parent = dev; + dev_set_name(&rtc->dev, "rtc%d", id); + + return rtc; + +exit_devres: + devres_free(ptr); +exit_ida: + ida_simple_remove(&rtc_ida, id); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(devm_rtc_allocate_device); + +int __rtc_register_device(struct module *owner, struct rtc_device *rtc) +{ + struct rtc_wkalrm alrm; + int err; + + if (!rtc->ops) + return -EINVAL; + + rtc->owner = owner; + + /* 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.parent, "failed to add char device %d:%d\n", + MAJOR(rtc->dev.devt), rtc->id); + else + dev_dbg(rtc->dev.parent, "char device (%d:%d)\n", + MAJOR(rtc->dev.devt), rtc->id); + + rtc_proc_add_device(rtc); + + rtc_nvmem_register(rtc); + + rtc->registered = true; + dev_info(rtc->dev.parent, "registered as %s\n", + dev_name(&rtc->dev)); + + return 0; +} +EXPORT_SYMBOL_GPL(__rtc_register_device); + static int __init rtc_init(void) { rtc_class = class_create(THIS_MODULE, "rtc"); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index fc0fa7577636..8cec9a02c0b8 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -227,6 +227,13 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) missing = year; } + /* Can't proceed if alarm is still invalid after replacing + * missing fields. + */ + err = rtc_valid_tm(&alarm->time); + if (err) + goto done; + /* with luck, no rollover is needed */ t_now = rtc_tm_to_time64(&now); t_alm = rtc_tm_to_time64(&alarm->time); @@ -278,9 +285,9 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) dev_warn(&rtc->dev, "alarm rollover not handled\n"); } -done: 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, diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c new file mode 100644 index 000000000000..8567b4ed9ac6 --- /dev/null +++ b/drivers/rtc/nvmem.c @@ -0,0 +1,113 @@ +/* + * RTC subsystem, nvmem interface + * + * Copyright (C) 2017 Alexandre Belloni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/types.h> +#include <linux/nvmem-consumer.h> +#include <linux/rtc.h> +#include <linux/sysfs.h> + +#include "rtc-core.h" + +/* + * Deprecated ABI compatibility, this should be removed at some point + */ + +static const char nvram_warning[] = "Deprecated ABI, please use nvmem"; + +static ssize_t +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); +} + +static ssize_t +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); +} + +static int rtc_nvram_register(struct rtc_device *rtc) +{ + int err; + + rtc->nvram = devm_kzalloc(rtc->dev.parent, + sizeof(struct bin_attribute), + GFP_KERNEL); + if (!rtc->nvram) + return -ENOMEM; + + rtc->nvram->attr.name = "nvram"; + rtc->nvram->attr.mode = 0644; + rtc->nvram->private = rtc; + + sysfs_bin_attr_init(rtc->nvram); + + rtc->nvram->read = rtc_nvram_read; + rtc->nvram->write = rtc_nvram_write; + rtc->nvram->size = rtc->nvmem_config->size; + + err = sysfs_create_bin_file(&rtc->dev.parent->kobj, + rtc->nvram); + if (err) { + devm_kfree(rtc->dev.parent, rtc->nvram); + rtc->nvram = NULL; + } + + return err; +} + +static void rtc_nvram_unregister(struct rtc_device *rtc) +{ + sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram); +} + +/* + * New ABI, uses nvmem + */ +void rtc_nvmem_register(struct rtc_device *rtc) +{ + if (!rtc->nvmem_config) + return; + + rtc->nvmem_config->dev = &rtc->dev; + rtc->nvmem_config->owner = rtc->owner; + rtc->nvmem = nvmem_register(rtc->nvmem_config); + if (IS_ERR_OR_NULL(rtc->nvmem)) + return; + + /* Register the old ABI */ + if (rtc->nvram_old_abi) + rtc_nvram_register(rtc); +} + +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); +} diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index b60fd477778f..e221b78b6f10 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -409,6 +409,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev) return -ENOMEM; } + rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + platform_set_drvdata(pdev, rtc); + sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(sclk)) return PTR_ERR(sclk); @@ -441,13 +446,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev) if (!device_can_wakeup(&pdev->dev)) device_init_wakeup(&pdev->dev, 1); - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); + rtc->ops = &at91_rtc_ops; + ret = rtc_register_device(rtc); + if (ret) goto err_clk; - } - platform_set_drvdata(pdev, rtc); /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy * completion. diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c new file mode 100644 index 000000000000..796ac792a381 --- /dev/null +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -0,0 +1,330 @@ +/* + * Copyright © 2014-2017 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqreturn.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_wakeup.h> +#include <linux/reboot.h> +#include <linux/rtc.h> +#include <linux/stat.h> +#include <linux/suspend.h> + +struct brcmstb_waketmr { + struct rtc_device *rtc; + struct device *dev; + void __iomem *base; + int irq; + struct notifier_block reboot_notifier; + struct clk *clk; + u32 rate; +}; + +#define BRCMSTB_WKTMR_EVENT 0x00 +#define BRCMSTB_WKTMR_COUNTER 0x04 +#define BRCMSTB_WKTMR_ALARM 0x08 +#define BRCMSTB_WKTMR_PRESCALER 0x0C +#define BRCMSTB_WKTMR_PRESCALER_VAL 0x10 + +#define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000 + +static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) +{ + writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT); + (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); +} + +static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer, + unsigned int secs) +{ + brcmstb_waketmr_clear_alarm(timer); + + writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM); +} + +static irqreturn_t brcmstb_waketmr_irq(int irq, void *data) +{ + struct brcmstb_waketmr *timer = data; + + pm_wakeup_event(timer->dev, 0); + + return IRQ_HANDLED; +} + +struct wktmr_time { + u32 sec; + u32 pre; +}; + +static void wktmr_read(struct brcmstb_waketmr *timer, + struct wktmr_time *t) +{ + u32 tmp; + + do { + t->sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); + tmp = readl_relaxed(timer->base + BRCMSTB_WKTMR_PRESCALER_VAL); + } while (tmp >= timer->rate); + + t->pre = timer->rate - tmp; +} + +static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer) +{ + struct device *dev = timer->dev; + int ret = 0; + + if (device_may_wakeup(dev)) { + ret = enable_irq_wake(timer->irq); + if (ret) { + dev_err(dev, "failed to enable wake-up interrupt\n"); + return ret; + } + } + + return ret; +} + +/* If enabled as a wakeup-source, arm the timer when powering off */ +static int brcmstb_waketmr_reboot(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct brcmstb_waketmr *timer; + + timer = container_of(nb, struct brcmstb_waketmr, reboot_notifier); + + /* Set timer for cold boot */ + if (action == SYS_POWER_OFF) + brcmstb_waketmr_prepare_suspend(timer); + + return NOTIFY_DONE; +} + +static int brcmstb_waketmr_gettime(struct device *dev, + struct rtc_time *tm) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + struct wktmr_time now; + + wktmr_read(timer, &now); + + rtc_time_to_tm(now.sec, tm); + + return 0; +} + +static int brcmstb_waketmr_settime(struct device *dev, + struct rtc_time *tm) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + time64_t sec; + + sec = rtc_tm_to_time64(tm); + + if (sec > U32_MAX || sec < 0) + return -EINVAL; + + writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER); + + return 0; +} + +static int brcmstb_waketmr_getalarm(struct device *dev, + struct rtc_wkalrm *alarm) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + time64_t sec; + u32 reg; + + sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM); + if (sec != 0) { + /* Alarm is enabled */ + alarm->enabled = 1; + rtc_time64_to_tm(sec, &alarm->time); + } + + reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); + alarm->pending = !!(reg & 1); + + return 0; +} + +static int brcmstb_waketmr_setalarm(struct device *dev, + struct rtc_wkalrm *alarm) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + time64_t sec; + + if (alarm->enabled) + sec = rtc_tm_to_time64(&alarm->time); + else + sec = 0; + + if (sec > U32_MAX || sec < 0) + return -EINVAL; + + brcmstb_waketmr_set_alarm(timer, sec); + + return 0; +} + +/* + * Does not do much but keep the RTC class happy. We always support + * alarms. + */ +static int brcmstb_waketmr_alarm_enable(struct device *dev, + unsigned int enabled) +{ + return 0; +} + +static const struct rtc_class_ops brcmstb_waketmr_ops = { + .read_time = brcmstb_waketmr_gettime, + .set_time = brcmstb_waketmr_settime, + .read_alarm = brcmstb_waketmr_getalarm, + .set_alarm = brcmstb_waketmr_setalarm, + .alarm_irq_enable = brcmstb_waketmr_alarm_enable, +}; + +static int brcmstb_waketmr_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct brcmstb_waketmr *timer; + struct resource *res; + int ret; + + timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL); + if (!timer) + return -ENOMEM; + + platform_set_drvdata(pdev, timer); + timer->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + timer->base = devm_ioremap_resource(dev, res); + if (IS_ERR(timer->base)) + return PTR_ERR(timer->base); + + /* + * Set wakeup capability before requesting wakeup interrupt, so we can + * process boot-time "wakeups" (e.g., from S5 soft-off) + */ + device_set_wakeup_capable(dev, true); + device_wakeup_enable(dev); + + timer->irq = platform_get_irq(pdev, 0); + if (timer->irq < 0) + return -ENODEV; + + timer->clk = devm_clk_get(dev, NULL); + if (!IS_ERR(timer->clk)) { + ret = clk_prepare_enable(timer->clk); + if (ret) + return ret; + timer->rate = clk_get_rate(timer->clk); + if (!timer->rate) + timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ; + } else { + timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ; + timer->clk = NULL; + } + + ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0, + "brcmstb-waketimer", timer); + if (ret < 0) + return ret; + + timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot; + register_reboot_notifier(&timer->reboot_notifier); + + timer->rtc = rtc_device_register("brcmstb-waketmr", dev, + &brcmstb_waketmr_ops, THIS_MODULE); + if (IS_ERR(timer->rtc)) { + dev_err(dev, "unable to register device\n"); + unregister_reboot_notifier(&timer->reboot_notifier); + return PTR_ERR(timer->rtc); + } + + dev_info(dev, "registered, with irq %d\n", timer->irq); + + return ret; +} + +static int brcmstb_waketmr_remove(struct platform_device *pdev) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev); + + unregister_reboot_notifier(&timer->reboot_notifier); + rtc_device_unregister(timer->rtc); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int brcmstb_waketmr_suspend(struct device *dev) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + + return brcmstb_waketmr_prepare_suspend(timer); +} + +static int brcmstb_waketmr_resume(struct device *dev) +{ + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + int ret; + + if (!device_may_wakeup(dev)) + return 0; + + ret = disable_irq_wake(timer->irq); + + brcmstb_waketmr_clear_alarm(timer); + + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops, + brcmstb_waketmr_suspend, brcmstb_waketmr_resume); + +static const struct of_device_id brcmstb_waketmr_of_match[] = { + { .compatible = "brcm,brcmstb-waketimer" }, + { /* sentinel */ }, +}; + +static struct platform_driver brcmstb_waketmr_driver = { + .probe = brcmstb_waketmr_probe, + .remove = brcmstb_waketmr_remove, + .driver = { + .name = "brcmstb-waketimer", + .pm = &brcmstb_waketmr_pm_ops, + .of_match_table = of_match_ptr(brcmstb_waketmr_of_match), + } +}; +module_platform_driver(brcmstb_waketmr_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Brian Norris"); +MODULE_AUTHOR("Markus Mayer"); +MODULE_DESCRIPTION("Wake-up timer driver for STB chips"); diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h index 7a4ed2f7c7d7..ecab76a3207c 100644 --- a/drivers/rtc/rtc-core.h +++ b/drivers/rtc/rtc-core.h @@ -45,3 +45,11 @@ static inline const struct attribute_group **rtc_get_dev_attribute_groups(void) return NULL; } #endif + +#ifdef CONFIG_RTC_NVMEM +void rtc_nvmem_register(struct rtc_device *rtc); +void rtc_nvmem_unregister(struct rtc_device *rtc); +#else +static inline void rtc_nvmem_register(struct rtc_device *rtc) {} +static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {} +#endif diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index e81a8711fea7..794bc4fa4937 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -464,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc) return; if (rtc->id >= RTC_DEV_MAX) { - dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name); + dev_dbg(&rtc->dev, "too many RTC devices\n"); return; } diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 77339b3d50a1..4fac49e55d47 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -24,6 +24,7 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/clk-provider.h> +#include <linux/regmap.h> /* * We can't determine type by probing, but if we expect pre-Linux code @@ -33,6 +34,7 @@ */ enum ds_type { ds_1307, + ds_1308, ds_1337, ds_1338, ds_1339, @@ -43,6 +45,7 @@ enum ds_type { m41t00, mcp794xx, rx_8025, + rx_8130, last_ds_type /* always last */ /* rs5c372 too? different address... */ }; @@ -115,17 +118,16 @@ struct ds1307 { u8 offset; /* register's offset */ u8 regs[11]; u16 nvram_offset; - struct bin_attribute *nvram; + struct nvmem_config nvmem_cfg; enum ds_type type; unsigned long flags; #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ #define HAS_ALARM 1 /* bit 1 == irq claimed */ - struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + const char *name; + int irq; struct rtc_device *rtc; - s32 (*read_block_data)(const struct i2c_client *client, u8 command, - u8 length, u8 *values); - s32 (*write_block_data)(const struct i2c_client *client, u8 command, - u8 length, const u8 *values); #ifdef CONFIG_COMMON_CLK struct clk_hw clks[2]; #endif @@ -135,21 +137,30 @@ struct chip_desc { unsigned alarm:1; u16 nvram_offset; u16 nvram_size; + u8 century_reg; + u8 century_enable_bit; + u8 century_bit; u16 trickle_charger_reg; u8 trickle_charger_setup; - u8 (*do_trickle_setup)(struct i2c_client *, uint32_t, bool); + u8 (*do_trickle_setup)(struct ds1307 *, uint32_t, + bool); }; -static u8 do_trickle_setup_ds1339(struct i2c_client *, - uint32_t ohms, bool diode); +static u8 do_trickle_setup_ds1339(struct ds1307 *, uint32_t ohms, bool diode); static struct chip_desc chips[last_ds_type] = { [ds_1307] = { .nvram_offset = 8, .nvram_size = 56, }, + [ds_1308] = { + .nvram_offset = 8, + .nvram_size = 56, + }, [ds_1337] = { .alarm = 1, + .century_reg = DS1307_REG_MONTH, + .century_bit = DS1337_BIT_CENTURY, }, [ds_1338] = { .nvram_offset = 8, @@ -157,10 +168,15 @@ static struct chip_desc chips[last_ds_type] = { }, [ds_1339] = { .alarm = 1, + .century_reg = DS1307_REG_MONTH, + .century_bit = DS1337_BIT_CENTURY, .trickle_charger_reg = 0x10, .do_trickle_setup = &do_trickle_setup_ds1339, }, [ds_1340] = { + .century_reg = DS1307_REG_HOUR, + .century_enable_bit = DS1340_BIT_CENTURY_EN, + .century_bit = DS1340_BIT_CENTURY, .trickle_charger_reg = 0x08, }, [ds_1388] = { @@ -168,6 +184,14 @@ static struct chip_desc chips[last_ds_type] = { }, [ds_3231] = { .alarm = 1, + .century_reg = DS1307_REG_MONTH, + .century_bit = DS1337_BIT_CENTURY, + }, + [rx_8130] = { + .alarm = 1, + /* this is battery backed SRAM */ + .nvram_offset = 0x20, + .nvram_size = 4, /* 32bit (4 word x 8 bit) */ }, [mcp794xx] = { .alarm = 1, @@ -179,6 +203,7 @@ static struct chip_desc chips[last_ds_type] = { static const struct i2c_device_id ds1307_id[] = { { "ds1307", ds_1307 }, + { "ds1308", ds_1308 }, { "ds1337", ds_1337 }, { "ds1338", ds_1338 }, { "ds1339", ds_1339 }, @@ -192,6 +217,7 @@ static const struct i2c_device_id ds1307_id[] = { { "pt7c4338", ds_1307 }, { "rx8025", rx_8025 }, { "isl12057", ds_1337 }, + { "rx8130", rx_8130 }, { } }; MODULE_DEVICE_TABLE(i2c, ds1307_id); @@ -203,6 +229,10 @@ static const struct of_device_id ds1307_of_match[] = { .data = (void *)ds_1307 }, { + .compatible = "dallas,ds1308", + .data = (void *)ds_1308 + }, + { .compatible = "dallas,ds1337", .data = (void *)ds_1337 }, @@ -262,6 +292,7 @@ MODULE_DEVICE_TABLE(of, ds1307_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id ds1307_acpi_ids[] = { { .id = "DS1307", .driver_data = ds_1307 }, + { .id = "DS1308", .driver_data = ds_1308 }, { .id = "DS1337", .driver_data = ds_1337 }, { .id = "DS1338", .driver_data = ds_1338 }, { .id = "DS1339", .driver_data = ds_1339 }, @@ -280,136 +311,6 @@ static const struct acpi_device_id ds1307_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids); #endif -/*----------------------------------------------------------------------*/ - -#define BLOCK_DATA_MAX_TRIES 10 - -static s32 ds1307_read_block_data_once(const struct i2c_client *client, - u8 command, u8 length, u8 *values) -{ - s32 i, data; - - for (i = 0; i < length; i++) { - data = i2c_smbus_read_byte_data(client, command + i); - if (data < 0) - return data; - values[i] = data; - } - return i; -} - -static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command, - u8 length, u8 *values) -{ - u8 oldvalues[255]; - s32 ret; - int tries = 0; - - dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length); - ret = ds1307_read_block_data_once(client, command, length, values); - if (ret < 0) - return ret; - do { - if (++tries > BLOCK_DATA_MAX_TRIES) { - dev_err(&client->dev, - "ds1307_read_block_data failed\n"); - return -EIO; - } - memcpy(oldvalues, values, length); - ret = ds1307_read_block_data_once(client, command, length, - values); - if (ret < 0) - return ret; - } while (memcmp(oldvalues, values, length)); - return length; -} - -static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command, - u8 length, const u8 *values) -{ - u8 currvalues[255]; - int tries = 0; - - dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); - do { - s32 i, ret; - - if (++tries > BLOCK_DATA_MAX_TRIES) { - dev_err(&client->dev, - "ds1307_write_block_data failed\n"); - return -EIO; - } - for (i = 0; i < length; i++) { - ret = i2c_smbus_write_byte_data(client, command + i, - values[i]); - if (ret < 0) - return ret; - } - ret = ds1307_read_block_data_once(client, command, length, - currvalues); - if (ret < 0) - return ret; - } while (memcmp(currvalues, values, length)); - return length; -} - -/*----------------------------------------------------------------------*/ - -/* These RTC devices are not designed to be connected to a SMbus adapter. - SMbus limits block operations length to 32 bytes, whereas it's not - limited on I2C buses. As a result, accesses may exceed 32 bytes; - in that case, split them into smaller blocks */ - -static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client, - u8 command, u8 length, const u8 *values) -{ - u8 suboffset = 0; - - if (length <= I2C_SMBUS_BLOCK_MAX) { - s32 retval = i2c_smbus_write_i2c_block_data(client, - command, length, values); - if (retval < 0) - return retval; - return length; - } - - while (suboffset < length) { - s32 retval = i2c_smbus_write_i2c_block_data(client, - command + suboffset, - min(I2C_SMBUS_BLOCK_MAX, length - suboffset), - values + suboffset); - if (retval < 0) - return retval; - - suboffset += I2C_SMBUS_BLOCK_MAX; - } - return length; -} - -static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client, - u8 command, u8 length, u8 *values) -{ - u8 suboffset = 0; - - if (length <= I2C_SMBUS_BLOCK_MAX) - return i2c_smbus_read_i2c_block_data(client, - command, length, values); - - while (suboffset < length) { - s32 retval = i2c_smbus_read_i2c_block_data(client, - command + suboffset, - min(I2C_SMBUS_BLOCK_MAX, length - suboffset), - values + suboffset); - if (retval < 0) - return retval; - - suboffset += I2C_SMBUS_BLOCK_MAX; - } - return length; -} - -/*----------------------------------------------------------------------*/ - /* * The ds1337 and ds1339 both have two alarms, but we only use the first * one (with a "seconds" field). For ds1337 we expect nINTA is our alarm @@ -417,27 +318,24 @@ static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client, */ static irqreturn_t ds1307_irq(int irq, void *dev_id) { - struct i2c_client *client = dev_id; - struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct ds1307 *ds1307 = dev_id; struct mutex *lock = &ds1307->rtc->ops_lock; - int stat, control; + int stat, ret; mutex_lock(lock); - stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); - if (stat < 0) + ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &stat); + if (ret) goto out; if (stat & DS1337_BIT_A1I) { stat &= ~DS1337_BIT_A1I; - i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, stat); + regmap_write(ds1307->regmap, DS1337_REG_STATUS, stat); - control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); - if (control < 0) + ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL, + DS1337_BIT_A1IE, 0); + if (ret) goto out; - control &= ~DS1337_BIT_A1IE; - i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control); - rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); } @@ -452,14 +350,14 @@ out: static int ds1307_get_time(struct device *dev, struct rtc_time *t) { struct ds1307 *ds1307 = dev_get_drvdata(dev); - int tmp; + int tmp, ret; + const struct chip_desc *chip = &chips[ds1307->type]; /* read the RTC date and time registers all at once */ - tmp = ds1307->read_block_data(ds1307->client, - ds1307->offset, 7, ds1307->regs); - if (tmp != 7) { - dev_err(dev, "%s error %d\n", "read", tmp); - return -EIO; + ret = regmap_bulk_read(ds1307->regmap, ds1307->offset, ds1307->regs, 7); + if (ret) { + dev_err(dev, "%s error %d\n", "read", ret); + return ret; } dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs); @@ -481,22 +379,9 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) t->tm_mon = bcd2bin(tmp) - 1; t->tm_year = bcd2bin(ds1307->regs[DS1307_REG_YEAR]) + 100; -#ifdef CONFIG_RTC_DRV_DS1307_CENTURY - switch (ds1307->type) { - case ds_1337: - case ds_1339: - case ds_3231: - if (ds1307->regs[DS1307_REG_MONTH] & DS1337_BIT_CENTURY) - t->tm_year += 100; - break; - case ds_1340: - if (ds1307->regs[DS1307_REG_HOUR] & DS1340_BIT_CENTURY) - t->tm_year += 100; - break; - default: - break; - } -#endif + if (ds1307->regs[chip->century_reg] & chip->century_bit && + IS_ENABLED(CONFIG_RTC_DRV_DS1307_CENTURY)) + t->tm_year += 100; dev_dbg(dev, "%s secs=%d, mins=%d, " "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", @@ -511,6 +396,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) static int ds1307_set_time(struct device *dev, struct rtc_time *t) { struct ds1307 *ds1307 = dev_get_drvdata(dev); + const struct chip_desc *chip = &chips[ds1307->type]; int result; int tmp; u8 *buf = ds1307->regs; @@ -521,24 +407,14 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) t->tm_hour, t->tm_mday, t->tm_mon, t->tm_year, t->tm_wday); -#ifdef CONFIG_RTC_DRV_DS1307_CENTURY if (t->tm_year < 100) return -EINVAL; - switch (ds1307->type) { - case ds_1337: - case ds_1339: - case ds_3231: - case ds_1340: - if (t->tm_year > 299) - return -EINVAL; - default: - if (t->tm_year > 199) - return -EINVAL; - break; - } +#ifdef CONFIG_RTC_DRV_DS1307_CENTURY + if (t->tm_year > (chip->century_bit ? 299 : 199)) + return -EINVAL; #else - if (t->tm_year < 100 || t->tm_year > 199) + if (t->tm_year > 199) return -EINVAL; #endif @@ -553,19 +429,12 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) tmp = t->tm_year - 100; buf[DS1307_REG_YEAR] = bin2bcd(tmp); - switch (ds1307->type) { - case ds_1337: - case ds_1339: - case ds_3231: - if (t->tm_year > 199) - buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; - break; - case ds_1340: - buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN; - if (t->tm_year > 199) - buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY; - break; - case mcp794xx: + if (chip->century_enable_bit) + buf[chip->century_reg] |= chip->century_enable_bit; + if (t->tm_year > 199 && chip->century_bit) + buf[chip->century_reg] |= chip->century_bit; + + if (ds1307->type == mcp794xx) { /* * these bits were cleared when preparing the date/time * values and need to be set again before writing the @@ -573,16 +442,12 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) */ buf[DS1307_REG_SECS] |= MCP794XX_BIT_ST; buf[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN; - break; - default: - break; } dev_dbg(dev, "%s: %7ph\n", "write", buf); - result = ds1307->write_block_data(ds1307->client, - ds1307->offset, 7, buf); - if (result < 0) { + result = regmap_bulk_write(ds1307->regmap, ds1307->offset, buf, 7); + if (result) { dev_err(dev, "%s error %d\n", "write", result); return result; } @@ -591,19 +456,18 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct ds1307 *ds1307 = dev_get_drvdata(dev); int ret; if (!test_bit(HAS_ALARM, &ds1307->flags)) return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ret = ds1307->read_block_data(client, - DS1339_REG_ALARM1_SECS, 9, ds1307->regs); - if (ret != 9) { + ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, + ds1307->regs, 9); + if (ret) { dev_err(dev, "%s error %d\n", "alarm read", ret); - return -EIO; + return ret; } dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read", @@ -633,8 +497,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct ds1307 *ds1307 = dev_get_drvdata(dev); unsigned char *buf = ds1307->regs; u8 control, status; int ret; @@ -649,11 +512,10 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled, t->pending); /* read current status of both alarms and the chip */ - ret = ds1307->read_block_data(client, - DS1339_REG_ALARM1_SECS, 9, buf); - if (ret != 9) { + ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, buf, 9); + if (ret) { dev_err(dev, "%s error %d\n", "alarm write", ret); - return -EIO; + return ret; } control = ds1307->regs[7]; status = ds1307->regs[8]; @@ -676,9 +538,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE); buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ret = ds1307->write_block_data(client, - DS1339_REG_ALARM1_SECS, 9, buf); - if (ret < 0) { + ret = regmap_bulk_write(ds1307->regmap, DS1339_REG_ALARM1_SECS, buf, 9); + if (ret) { dev_err(dev, "can't set alarm time\n"); return ret; } @@ -687,7 +548,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) if (t->enabled) { dev_dbg(dev, "alarm IRQ armed\n"); buf[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */ - i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, buf[7]); + regmap_write(ds1307->regmap, DS1337_REG_CONTROL, buf[7]); } return 0; @@ -695,35 +556,181 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1307 *ds1307 = i2c_get_clientdata(client); - int ret; + struct ds1307 *ds1307 = dev_get_drvdata(dev); if (!test_bit(HAS_ALARM, &ds1307->flags)) return -ENOTTY; - ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); + return regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL, + DS1337_BIT_A1IE, + enabled ? DS1337_BIT_A1IE : 0); +} + +static const struct rtc_class_ops ds13xx_rtc_ops = { + .read_time = ds1307_get_time, + .set_time = ds1307_set_time, + .read_alarm = ds1337_read_alarm, + .set_alarm = ds1337_set_alarm, + .alarm_irq_enable = ds1307_alarm_irq_enable, +}; + +/*----------------------------------------------------------------------*/ + +/* + * Alarm support for rx8130 devices. + */ + +#define RX8130_REG_ALARM_MIN 0x07 +#define RX8130_REG_ALARM_HOUR 0x08 +#define RX8130_REG_ALARM_WEEK_OR_DAY 0x09 +#define RX8130_REG_EXTENSION 0x0c +#define RX8130_REG_EXTENSION_WADA (1 << 3) +#define RX8130_REG_FLAG 0x0d +#define RX8130_REG_FLAG_AF (1 << 3) +#define RX8130_REG_CONTROL0 0x0e +#define RX8130_REG_CONTROL0_AIE (1 << 3) + +static irqreturn_t rx8130_irq(int irq, void *dev_id) +{ + struct ds1307 *ds1307 = dev_id; + struct mutex *lock = &ds1307->rtc->ops_lock; + u8 ctl[3]; + int ret; + + mutex_lock(lock); + + /* Read control registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3); if (ret < 0) - return ret; + goto out; + if (!(ctl[1] & RX8130_REG_FLAG_AF)) + goto out; + ctl[1] &= ~RX8130_REG_FLAG_AF; + ctl[2] &= ~RX8130_REG_CONTROL0_AIE; - if (enabled) - ret |= DS1337_BIT_A1IE; - else - ret &= ~DS1337_BIT_A1IE; + ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3); + if (ret < 0) + goto out; + + rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); + +out: + mutex_unlock(lock); + + return IRQ_HANDLED; +} - ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret); +static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + u8 ald[3], ctl[3]; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + /* Read alarm registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, 3); if (ret < 0) return ret; + /* Read control registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3); + if (ret < 0) + return ret; + + t->enabled = !!(ctl[2] & RX8130_REG_CONTROL0_AIE); + t->pending = !!(ctl[1] & RX8130_REG_FLAG_AF); + + /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ + t->time.tm_sec = -1; + t->time.tm_min = bcd2bin(ald[0] & 0x7f); + t->time.tm_hour = bcd2bin(ald[1] & 0x7f); + t->time.tm_wday = -1; + t->time.tm_mday = bcd2bin(ald[2] & 0x7f); + t->time.tm_mon = -1; + t->time.tm_year = -1; + t->time.tm_yday = -1; + t->time.tm_isdst = -1; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d enabled=%d\n", + __func__, t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled); + return 0; } -static const struct rtc_class_ops ds13xx_rtc_ops = { +static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + u8 ald[3], ctl[3]; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " + "enabled=%d pending=%d\n", __func__, + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, + t->enabled, t->pending); + + /* Read control registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3); + if (ret < 0) + return ret; + + ctl[0] &= ~RX8130_REG_EXTENSION_WADA; + ctl[1] |= RX8130_REG_FLAG_AF; + ctl[2] &= ~RX8130_REG_CONTROL0_AIE; + + ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3); + if (ret < 0) + return ret; + + /* Hardware alarm precision is 1 minute! */ + ald[0] = bin2bcd(t->time.tm_min); + ald[1] = bin2bcd(t->time.tm_hour); + ald[2] = bin2bcd(t->time.tm_mday); + + ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, 3); + if (ret < 0) + return ret; + + if (!t->enabled) + return 0; + + ctl[2] |= RX8130_REG_CONTROL0_AIE; + + return regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3); +} + +static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + int ret, reg; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + ret = regmap_read(ds1307->regmap, RX8130_REG_CONTROL0, ®); + if (ret < 0) + return ret; + + if (enabled) + reg |= RX8130_REG_CONTROL0_AIE; + else + reg &= ~RX8130_REG_CONTROL0_AIE; + + return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, reg); +} + +static const struct rtc_class_ops rx8130_rtc_ops = { .read_time = ds1307_get_time, .set_time = ds1307_set_time, - .read_alarm = ds1337_read_alarm, - .set_alarm = ds1337_set_alarm, - .alarm_irq_enable = ds1307_alarm_irq_enable, + .read_alarm = rx8130_read_alarm, + .set_alarm = rx8130_set_alarm, + .alarm_irq_enable = rx8130_alarm_irq_enable, }; /*----------------------------------------------------------------------*/ @@ -752,31 +759,27 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { static irqreturn_t mcp794xx_irq(int irq, void *dev_id) { - struct i2c_client *client = dev_id; - struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct ds1307 *ds1307 = dev_id; struct mutex *lock = &ds1307->rtc->ops_lock; int reg, ret; mutex_lock(lock); /* Check and clear alarm 0 interrupt flag. */ - reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL); - if (reg < 0) + ret = regmap_read(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, ®); + if (ret) goto out; if (!(reg & MCP794XX_BIT_ALMX_IF)) goto out; reg &= ~MCP794XX_BIT_ALMX_IF; - ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_ALARM0_CTRL, reg); - if (ret < 0) + ret = regmap_write(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, reg); + if (ret) goto out; /* Disable alarm 0. */ - reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL); - if (reg < 0) - goto out; - reg &= ~MCP794XX_BIT_ALM0_EN; - ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg); - if (ret < 0) + ret = regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL, + MCP794XX_BIT_ALM0_EN, 0); + if (ret) goto out; rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); @@ -789,8 +792,7 @@ out: static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct ds1307 *ds1307 = dev_get_drvdata(dev); u8 *regs = ds1307->regs; int ret; @@ -798,8 +800,8 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) return -EINVAL; /* Read control and alarm 0 registers. */ - ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs); - if (ret < 0) + ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10); + if (ret) return ret; t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN); @@ -828,8 +830,7 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct ds1307 *ds1307 = dev_get_drvdata(dev); unsigned char *regs = ds1307->regs; int ret; @@ -843,8 +844,8 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled, t->pending); /* Read control and alarm 0 registers. */ - ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs); - if (ret < 0) + ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10); + if (ret) return ret; /* Set alarm 0, using 24-hour and day-of-month modes. */ @@ -862,35 +863,26 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) /* Disable interrupt. We will not enable until completely programmed */ regs[0] &= ~MCP794XX_BIT_ALM0_EN; - ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs); - if (ret < 0) + ret = regmap_bulk_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10); + if (ret) return ret; if (!t->enabled) return 0; regs[0] |= MCP794XX_BIT_ALM0_EN; - return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, regs[0]); + return regmap_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs[0]); } static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1307 *ds1307 = i2c_get_clientdata(client); - int reg; + struct ds1307 *ds1307 = dev_get_drvdata(dev); if (!test_bit(HAS_ALARM, &ds1307->flags)) return -EINVAL; - reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL); - if (reg < 0) - return reg; - - if (enabled) - reg |= MCP794XX_BIT_ALM0_EN; - else - reg &= ~MCP794XX_BIT_ALM0_EN; - - return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg); + return regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL, + MCP794XX_BIT_ALM0_EN, + enabled ? MCP794XX_BIT_ALM0_EN : 0); } static const struct rtc_class_ops mcp794xx_rtc_ops = { @@ -903,50 +895,27 @@ static const struct rtc_class_ops mcp794xx_rtc_ops = { /*----------------------------------------------------------------------*/ -static ssize_t -ds1307_nvram_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) +static int ds1307_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) { - struct i2c_client *client; - struct ds1307 *ds1307; - int result; + struct ds1307 *ds1307 = priv; - client = kobj_to_i2c_client(kobj); - ds1307 = i2c_get_clientdata(client); - - result = ds1307->read_block_data(client, ds1307->nvram_offset + off, - count, buf); - if (result < 0) - dev_err(&client->dev, "%s error %d\n", "nvram read", result); - return result; + return regmap_bulk_read(ds1307->regmap, ds1307->nvram_offset + offset, + val, bytes); } -static ssize_t -ds1307_nvram_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) +static int ds1307_nvram_write(void *priv, unsigned int offset, void *val, + size_t bytes) { - struct i2c_client *client; - struct ds1307 *ds1307; - int result; + struct ds1307 *ds1307 = priv; - client = kobj_to_i2c_client(kobj); - ds1307 = i2c_get_clientdata(client); - - result = ds1307->write_block_data(client, ds1307->nvram_offset + off, - count, buf); - if (result < 0) { - dev_err(&client->dev, "%s error %d\n", "nvram write", result); - return result; - } - return count; + return regmap_bulk_write(ds1307->regmap, ds1307->nvram_offset + offset, + val, bytes); } - /*----------------------------------------------------------------------*/ -static u8 do_trickle_setup_ds1339(struct i2c_client *client, +static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307, uint32_t ohms, bool diode) { u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE : @@ -963,14 +932,14 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client, setup |= DS1307_TRICKLE_CHARGER_4K_OHM; break; default: - dev_warn(&client->dev, + dev_warn(ds1307->dev, "Unsupported ohm value %u in dt\n", ohms); return 0; } return setup; } -static void ds1307_trickle_init(struct i2c_client *client, +static void ds1307_trickle_init(struct ds1307 *ds1307, struct chip_desc *chip) { uint32_t ohms = 0; @@ -978,11 +947,12 @@ static void ds1307_trickle_init(struct i2c_client *client, if (!chip->do_trickle_setup) goto out; - if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms)) + if (device_property_read_u32(ds1307->dev, "trickle-resistor-ohms", + &ohms)) goto out; - if (device_property_read_bool(&client->dev, "trickle-diode-disable")) + if (device_property_read_bool(ds1307->dev, "trickle-diode-disable")) diode = false; - chip->trickle_charger_setup = chip->do_trickle_setup(client, + chip->trickle_charger_setup = chip->do_trickle_setup(ds1307, ohms, diode); out: return; @@ -1009,13 +979,10 @@ static int ds3231_hwmon_read_temp(struct device *dev, s32 *mC) s16 temp; int ret; - ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE, - sizeof(temp_buf), temp_buf); - if (ret < 0) + ret = regmap_bulk_read(ds1307->regmap, DS3231_REG_TEMPERATURE, + temp_buf, sizeof(temp_buf)); + if (ret) return ret; - if (ret != sizeof(temp_buf)) - return -EIO; - /* * Temperature is represented as a 10-bit code with a resolution of * 0.25 degree celsius and encoded in two's complement format. @@ -1055,12 +1022,11 @@ static void ds1307_hwmon_register(struct ds1307 *ds1307) if (ds1307->type != ds_3231) return; - dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev, - ds1307->client->name, + dev = devm_hwmon_device_register_with_groups(ds1307->dev, ds1307->name, ds1307, ds3231_hwmon_groups); if (IS_ERR(dev)) { - dev_warn(&ds1307->client->dev, - "unable to register hwmon device %ld\n", PTR_ERR(dev)); + dev_warn(ds1307->dev, "unable to register hwmon device %ld\n", + PTR_ERR(dev)); } } @@ -1099,24 +1065,12 @@ static int ds3231_clk_sqw_rates[] = { static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value) { - struct i2c_client *client = ds1307->client; struct mutex *lock = &ds1307->rtc->ops_lock; - int control; int ret; mutex_lock(lock); - - control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); - if (control < 0) { - ret = control; - goto out; - } - - control &= ~mask; - control |= value; - - ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control); -out: + ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL, + mask, value); mutex_unlock(lock); return ret; @@ -1126,12 +1080,12 @@ static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); - int control; + int control, ret; int rate_sel = 0; - control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL); - if (control < 0) - return control; + ret = regmap_read(ds1307->regmap, DS1337_REG_CONTROL, &control); + if (ret) + return ret; if (control & DS1337_BIT_RS1) rate_sel += 1; if (control & DS1337_BIT_RS2) @@ -1195,11 +1149,11 @@ static void ds3231_clk_sqw_unprepare(struct clk_hw *hw) static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw) { struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); - int control; + int control, ret; - control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL); - if (control < 0) - return control; + ret = regmap_read(ds1307->regmap, DS1337_REG_CONTROL, &control); + if (ret) + return ret; return !(control & DS1337_BIT_INTCN); } @@ -1221,26 +1175,13 @@ static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw, static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable) { - struct i2c_client *client = ds1307->client; struct mutex *lock = &ds1307->rtc->ops_lock; - int status; int ret; mutex_lock(lock); - - status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); - if (status < 0) { - ret = status; - goto out; - } - - if (enable) - status |= DS3231_BIT_EN32KHZ; - else - status &= ~DS3231_BIT_EN32KHZ; - - ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status); -out: + ret = regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS, + DS3231_BIT_EN32KHZ, + enable ? DS3231_BIT_EN32KHZ : 0); mutex_unlock(lock); return ret; @@ -1263,11 +1204,11 @@ static void ds3231_clk_32khz_unprepare(struct clk_hw *hw) static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw) { struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw); - int status; + int status, ret; - status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS); - if (status < 0) - return status; + ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &status); + if (ret) + return ret; return !!(status & DS3231_BIT_EN32KHZ); } @@ -1292,18 +1233,17 @@ static struct clk_init_data ds3231_clks_init[] = { static int ds3231_clks_register(struct ds1307 *ds1307) { - struct i2c_client *client = ds1307->client; - struct device_node *node = client->dev.of_node; + struct device_node *node = ds1307->dev->of_node; struct clk_onecell_data *onecell; int i; - onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL); + onecell = devm_kzalloc(ds1307->dev, sizeof(*onecell), GFP_KERNEL); if (!onecell) return -ENOMEM; onecell->clk_num = ARRAY_SIZE(ds3231_clks_init); - onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num, - sizeof(onecell->clks[0]), GFP_KERNEL); + onecell->clks = devm_kcalloc(ds1307->dev, onecell->clk_num, + sizeof(onecell->clks[0]), GFP_KERNEL); if (!onecell->clks) return -ENOMEM; @@ -1322,8 +1262,8 @@ static int ds3231_clks_register(struct ds1307 *ds1307) &init.name); ds1307->clks[i].init = &init; - onecell->clks[i] = devm_clk_register(&client->dev, - &ds1307->clks[i]); + onecell->clks[i] = devm_clk_register(ds1307->dev, + &ds1307->clks[i]); if (IS_ERR(onecell->clks[i])) return PTR_ERR(onecell->clks[i]); } @@ -1345,8 +1285,8 @@ static void ds1307_clks_register(struct ds1307 *ds1307) ret = ds3231_clks_register(ds1307); if (ret) { - dev_warn(&ds1307->client->dev, - "unable to register clock device %d\n", ret); + dev_warn(ds1307->dev, "unable to register clock device %d\n", + ret); } } @@ -1358,6 +1298,12 @@ static void ds1307_clks_register(struct ds1307 *ds1307) #endif /* CONFIG_COMMON_CLK */ +static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x12, +}; + static int ds1307_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1365,7 +1311,6 @@ static int ds1307_probe(struct i2c_client *client, int err = -ENODEV; int tmp, wday; struct chip_desc *chip; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); bool want_irq = false; bool ds1307_can_wakeup_device = false; unsigned char *buf; @@ -1382,17 +1327,22 @@ static int ds1307_probe(struct i2c_client *client, }; const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) - return -EIO; - ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL); if (!ds1307) return -ENOMEM; - i2c_set_clientdata(client, ds1307); + dev_set_drvdata(&client->dev, ds1307); + ds1307->dev = &client->dev; + ds1307->name = client->name; + ds1307->irq = client->irq; - ds1307->client = client; + ds1307->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(ds1307->regmap)) { + dev_err(ds1307->dev, "regmap allocation failed\n"); + return PTR_ERR(ds1307->regmap); + } + + i2c_set_clientdata(client, ds1307); if (client->dev.of_node) { ds1307->type = (enum ds_type) @@ -1405,7 +1355,7 @@ static int ds1307_probe(struct i2c_client *client, const struct acpi_device_id *acpi_id; acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids), - &client->dev); + ds1307->dev); if (!acpi_id) return -ENODEV; chip = &chips[acpi_id->driver_data]; @@ -1413,27 +1363,21 @@ static int ds1307_probe(struct i2c_client *client, } if (!pdata) - ds1307_trickle_init(client, chip); + ds1307_trickle_init(ds1307, chip); else if (pdata->trickle_charger_setup) chip->trickle_charger_setup = pdata->trickle_charger_setup; if (chip->trickle_charger_setup && chip->trickle_charger_reg) { - dev_dbg(&client->dev, "writing trickle charger info 0x%x to 0x%x\n", + dev_dbg(ds1307->dev, + "writing trickle charger info 0x%x to 0x%x\n", DS13XX_TRICKLE_CHARGER_MAGIC | chip->trickle_charger_setup, chip->trickle_charger_reg); - i2c_smbus_write_byte_data(client, chip->trickle_charger_reg, + regmap_write(ds1307->regmap, chip->trickle_charger_reg, DS13XX_TRICKLE_CHARGER_MAGIC | chip->trickle_charger_setup); } buf = ds1307->regs; - if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { - ds1307->read_block_data = ds1307_native_smbus_read_block_data; - ds1307->write_block_data = ds1307_native_smbus_write_block_data; - } else { - ds1307->read_block_data = ds1307_read_block_data; - ds1307->write_block_data = ds1307_write_block_data; - } #ifdef CONFIG_OF /* @@ -1459,11 +1403,10 @@ static int ds1307_probe(struct i2c_client *client, case ds_1339: case ds_3231: /* get registers that the "rtc" read below won't read... */ - tmp = ds1307->read_block_data(ds1307->client, - DS1337_REG_CONTROL, 2, buf); - if (tmp != 2) { - dev_dbg(&client->dev, "read error %d\n", tmp); - err = -EIO; + err = regmap_bulk_read(ds1307->regmap, DS1337_REG_CONTROL, + buf, 2); + if (err) { + dev_dbg(ds1307->dev, "read error %d\n", err); goto exit; } @@ -1477,8 +1420,8 @@ static int ds1307_probe(struct i2c_client *client, * For some variants, be sure alarms can trigger when we're * running on Vbackup (BBSQI/BBSQW) */ - if (chip->alarm && (ds1307->client->irq > 0 || - ds1307_can_wakeup_device)) { + if (chip->alarm && (ds1307->irq > 0 || + ds1307_can_wakeup_device)) { ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); @@ -1486,50 +1429,49 @@ static int ds1307_probe(struct i2c_client *client, want_irq = true; } - i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, - ds1307->regs[0]); + regmap_write(ds1307->regmap, DS1337_REG_CONTROL, + ds1307->regs[0]); /* oscillator fault? clear flag, and warn */ if (ds1307->regs[1] & DS1337_BIT_OSF) { - i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, - ds1307->regs[1] & ~DS1337_BIT_OSF); - dev_warn(&client->dev, "SET TIME!\n"); + regmap_write(ds1307->regmap, DS1337_REG_STATUS, + ds1307->regs[1] & ~DS1337_BIT_OSF); + dev_warn(ds1307->dev, "SET TIME!\n"); } break; case rx_8025: - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, - RX8025_REG_CTRL1 << 4 | 0x08, 2, buf); - if (tmp != 2) { - dev_dbg(&client->dev, "read error %d\n", tmp); - err = -EIO; + err = regmap_bulk_read(ds1307->regmap, + RX8025_REG_CTRL1 << 4 | 0x08, buf, 2); + if (err) { + dev_dbg(ds1307->dev, "read error %d\n", err); goto exit; } /* oscillator off? turn it on, so clock can tick. */ if (!(ds1307->regs[1] & RX8025_BIT_XST)) { ds1307->regs[1] |= RX8025_BIT_XST; - i2c_smbus_write_byte_data(client, - RX8025_REG_CTRL2 << 4 | 0x08, - ds1307->regs[1]); - dev_warn(&client->dev, + regmap_write(ds1307->regmap, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(ds1307->dev, "oscillator stop detected - SET TIME!\n"); } if (ds1307->regs[1] & RX8025_BIT_PON) { ds1307->regs[1] &= ~RX8025_BIT_PON; - i2c_smbus_write_byte_data(client, - RX8025_REG_CTRL2 << 4 | 0x08, - ds1307->regs[1]); - dev_warn(&client->dev, "power-on detected\n"); + regmap_write(ds1307->regmap, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(ds1307->dev, "power-on detected\n"); } if (ds1307->regs[1] & RX8025_BIT_VDET) { ds1307->regs[1] &= ~RX8025_BIT_VDET; - i2c_smbus_write_byte_data(client, - RX8025_REG_CTRL2 << 4 | 0x08, - ds1307->regs[1]); - dev_warn(&client->dev, "voltage drop detected\n"); + regmap_write(ds1307->regmap, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(ds1307->dev, "voltage drop detected\n"); } /* make sure we are running in 24hour mode */ @@ -1537,16 +1479,15 @@ static int ds1307_probe(struct i2c_client *client, u8 hour; /* switch to 24 hour mode */ - i2c_smbus_write_byte_data(client, - RX8025_REG_CTRL1 << 4 | 0x08, - ds1307->regs[0] | - RX8025_BIT_2412); - - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, - RX8025_REG_CTRL1 << 4 | 0x08, 2, buf); - if (tmp != 2) { - dev_dbg(&client->dev, "read error %d\n", tmp); - err = -EIO; + regmap_write(ds1307->regmap, + RX8025_REG_CTRL1 << 4 | 0x08, + ds1307->regs[0] | RX8025_BIT_2412); + + err = regmap_bulk_read(ds1307->regmap, + RX8025_REG_CTRL1 << 4 | 0x08, + buf, 2); + if (err) { + dev_dbg(ds1307->dev, "read error %d\n", err); goto exit; } @@ -1557,9 +1498,16 @@ static int ds1307_probe(struct i2c_client *client, if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM) hour += 12; - i2c_smbus_write_byte_data(client, - DS1307_REG_HOUR << 4 | 0x08, - hour); + regmap_write(ds1307->regmap, + DS1307_REG_HOUR << 4 | 0x08, hour); + } + break; + case rx_8130: + ds1307->offset = 0x10; /* Seconds starts at 0x10 */ + rtc_ops = &rx8130_rtc_ops; + if (chip->alarm && ds1307->irq > 0) { + irq_handler = rx8130_irq; + want_irq = true; } break; case ds_1388: @@ -1567,7 +1515,8 @@ static int ds1307_probe(struct i2c_client *client, break; case mcp794xx: rtc_ops = &mcp794xx_rtc_ops; - if (ds1307->client->irq > 0 && chip->alarm) { + if (chip->alarm && (ds1307->irq > 0 || + ds1307_can_wakeup_device)) { irq_handler = mcp794xx_irq; want_irq = true; } @@ -1578,10 +1527,9 @@ static int ds1307_probe(struct i2c_client *client, read_rtc: /* read RTC registers */ - tmp = ds1307->read_block_data(ds1307->client, ds1307->offset, 8, buf); - if (tmp != 8) { - dev_dbg(&client->dev, "read error %d\n", tmp); - err = -EIO; + err = regmap_bulk_read(ds1307->regmap, ds1307->offset, buf, 8); + if (err) { + dev_dbg(ds1307->dev, "read error %d\n", err); goto exit; } @@ -1597,56 +1545,56 @@ read_rtc: case m41t00: /* clock halted? turn it on, so clock can tick. */ if (tmp & DS1307_BIT_CH) { - i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); - dev_warn(&client->dev, "SET TIME!\n"); + regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); + dev_warn(ds1307->dev, "SET TIME!\n"); goto read_rtc; } break; + case ds_1308: case ds_1338: /* clock halted? turn it on, so clock can tick. */ if (tmp & DS1307_BIT_CH) - i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); + regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); /* oscillator fault? clear flag, and warn */ if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) { - i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL, - ds1307->regs[DS1307_REG_CONTROL] - & ~DS1338_BIT_OSF); - dev_warn(&client->dev, "SET TIME!\n"); + regmap_write(ds1307->regmap, DS1307_REG_CONTROL, + ds1307->regs[DS1307_REG_CONTROL] & + ~DS1338_BIT_OSF); + dev_warn(ds1307->dev, "SET TIME!\n"); goto read_rtc; } break; case ds_1340: /* clock halted? turn it on, so clock can tick. */ if (tmp & DS1340_BIT_nEOSC) - i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); + regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); - tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG); - if (tmp < 0) { - dev_dbg(&client->dev, "read error %d\n", tmp); - err = -EIO; + err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp); + if (err) { + dev_dbg(ds1307->dev, "read error %d\n", err); goto exit; } /* oscillator fault? clear flag, and warn */ if (tmp & DS1340_BIT_OSF) { - i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0); - dev_warn(&client->dev, "SET TIME!\n"); + regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0); + dev_warn(ds1307->dev, "SET TIME!\n"); } break; case mcp794xx: /* make sure that the backup battery is enabled */ if (!(ds1307->regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) { - i2c_smbus_write_byte_data(client, DS1307_REG_WDAY, - ds1307->regs[DS1307_REG_WDAY] - | MCP794XX_BIT_VBATEN); + regmap_write(ds1307->regmap, DS1307_REG_WDAY, + ds1307->regs[DS1307_REG_WDAY] | + MCP794XX_BIT_VBATEN); } /* clock halted? turn it on, so clock can tick. */ if (!(tmp & MCP794XX_BIT_ST)) { - i2c_smbus_write_byte_data(client, DS1307_REG_SECS, - MCP794XX_BIT_ST); - dev_warn(&client->dev, "SET TIME!\n"); + regmap_write(ds1307->regmap, DS1307_REG_SECS, + MCP794XX_BIT_ST); + dev_warn(ds1307->dev, "SET TIME!\n"); goto read_rtc; } @@ -1680,16 +1628,15 @@ read_rtc: tmp = 0; if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM) tmp += 12; - i2c_smbus_write_byte_data(client, - ds1307->offset + DS1307_REG_HOUR, - bin2bcd(tmp)); + regmap_write(ds1307->regmap, ds1307->offset + DS1307_REG_HOUR, + bin2bcd(tmp)); } /* * Some IPs have weekday reset value = 0x1 which might not correct * hence compute the wday using the current date/month/year values */ - ds1307_get_time(&client->dev, &tm); + ds1307_get_time(ds1307->dev, &tm); wday = tm.tm_wday; timestamp = rtc_tm_to_time64(&tm); rtc_time64_to_tm(timestamp, &tm); @@ -1699,78 +1646,63 @@ read_rtc: * If different then set the wday which we computed using * timestamp */ - if (wday != tm.tm_wday) { - wday = i2c_smbus_read_byte_data(client, MCP794XX_REG_WEEKDAY); - wday = wday & ~MCP794XX_REG_WEEKDAY_WDAY_MASK; - wday = wday | (tm.tm_wday + 1); - i2c_smbus_write_byte_data(client, MCP794XX_REG_WEEKDAY, wday); - } + if (wday != tm.tm_wday) + regmap_update_bits(ds1307->regmap, MCP794XX_REG_WEEKDAY, + MCP794XX_REG_WEEKDAY_WDAY_MASK, + tm.tm_wday + 1); if (want_irq) { - device_set_wakeup_capable(&client->dev, true); + device_set_wakeup_capable(ds1307->dev, true); set_bit(HAS_ALARM, &ds1307->flags); } - ds1307->rtc = devm_rtc_device_register(&client->dev, client->name, - rtc_ops, THIS_MODULE); + + ds1307->rtc = devm_rtc_allocate_device(ds1307->dev); if (IS_ERR(ds1307->rtc)) { return PTR_ERR(ds1307->rtc); } - if (ds1307_can_wakeup_device && ds1307->client->irq <= 0) { + if (ds1307_can_wakeup_device && ds1307->irq <= 0) { /* Disable request for an IRQ */ want_irq = false; - dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n"); + dev_info(ds1307->dev, + "'wakeup-source' is set, request for an IRQ is disabled!\n"); /* We cannot support UIE mode if we do not have an IRQ line */ ds1307->rtc->uie_unsupported = 1; } if (want_irq) { - err = devm_request_threaded_irq(&client->dev, - client->irq, NULL, irq_handler, + err = devm_request_threaded_irq(ds1307->dev, + ds1307->irq, NULL, irq_handler, IRQF_SHARED | IRQF_ONESHOT, - ds1307->rtc->name, client); + ds1307->name, ds1307); if (err) { client->irq = 0; - device_set_wakeup_capable(&client->dev, false); + device_set_wakeup_capable(ds1307->dev, false); clear_bit(HAS_ALARM, &ds1307->flags); - dev_err(&client->dev, "unable to request IRQ!\n"); + dev_err(ds1307->dev, "unable to request IRQ!\n"); } else - dev_dbg(&client->dev, "got IRQ %d\n", client->irq); + dev_dbg(ds1307->dev, "got IRQ %d\n", client->irq); } if (chip->nvram_size) { - - ds1307->nvram = devm_kzalloc(&client->dev, - sizeof(struct bin_attribute), - GFP_KERNEL); - if (!ds1307->nvram) { - dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n"); - } else { - - ds1307->nvram->attr.name = "nvram"; - ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; - - sysfs_bin_attr_init(ds1307->nvram); - - ds1307->nvram->read = ds1307_nvram_read; - ds1307->nvram->write = ds1307_nvram_write; - ds1307->nvram->size = chip->nvram_size; - ds1307->nvram_offset = chip->nvram_offset; - - err = sysfs_create_bin_file(&client->dev.kobj, - ds1307->nvram); - if (err) { - dev_err(&client->dev, - "unable to create sysfs file: %s\n", - ds1307->nvram->attr.name); - } else { - set_bit(HAS_NVRAM, &ds1307->flags); - dev_info(&client->dev, "%zu bytes nvram\n", - ds1307->nvram->size); - } - } + ds1307->nvmem_cfg.name = "ds1307_nvram"; + ds1307->nvmem_cfg.word_size = 1; + ds1307->nvmem_cfg.stride = 1; + ds1307->nvmem_cfg.size = chip->nvram_size; + ds1307->nvmem_cfg.reg_read = ds1307_nvram_read; + ds1307->nvmem_cfg.reg_write = ds1307_nvram_write; + ds1307->nvmem_cfg.priv = ds1307; + ds1307->nvram_offset = chip->nvram_offset; + + ds1307->rtc->nvmem_config = &ds1307->nvmem_cfg; + ds1307->rtc->nvram_old_abi = true; } + ds1307->rtc->ops = rtc_ops; + err = rtc_register_device(ds1307->rtc); + if (err) + return err; + ds1307_hwmon_register(ds1307); ds1307_clks_register(ds1307); @@ -1780,16 +1712,6 @@ exit: return err; } -static int ds1307_remove(struct i2c_client *client) -{ - struct ds1307 *ds1307 = i2c_get_clientdata(client); - - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) - sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); - - return 0; -} - static struct i2c_driver ds1307_driver = { .driver = { .name = "rtc-ds1307", @@ -1797,7 +1719,6 @@ static struct i2c_driver ds1307_driver = { .acpi_match_table = ACPI_PTR(ds1307_acpi_ids), }, .probe = ds1307_probe, - .remove = ds1307_remove, .id_table = ds1307_id, }; diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index deff431a37c4..0550f7ba464f 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -22,6 +22,7 @@ #include <linux/bcd.h> #include <linux/slab.h> #include <linux/regmap.h> +#include <linux/hwmon.h> #define DS3232_REG_SECONDS 0x00 #define DS3232_REG_MINUTES 0x01 @@ -46,6 +47,8 @@ # define DS3232_REG_SR_A2F 0x02 # define DS3232_REG_SR_A1F 0x01 +#define DS3232_REG_TEMPERATURE 0x11 + struct ds3232 { struct device *dev; struct regmap *regmap; @@ -275,6 +278,120 @@ static int ds3232_update_alarm(struct device *dev, unsigned int enabled) return ret; } +/* + * Temperature sensor support for ds3232/ds3234 devices. + * A user-initiated temperature conversion is not started by this function, + * so the temperature is updated once every 64 seconds. + */ +static int ds3232_hwmon_read_temp(struct device *dev, long int *mC) +{ + struct ds3232 *ds3232 = dev_get_drvdata(dev); + u8 temp_buf[2]; + s16 temp; + int ret; + + ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_TEMPERATURE, temp_buf, + sizeof(temp_buf)); + if (ret < 0) + return ret; + + /* + * Temperature is represented as a 10-bit code with a resolution of + * 0.25 degree celsius and encoded in two's complement format. + */ + temp = (temp_buf[0] << 8) | temp_buf[1]; + temp >>= 6; + *mC = temp * 250; + + return 0; +} + +static umode_t ds3232_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + return 0444; + default: + return 0; + } +} + +static int ds3232_hwmon_read(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, long *temp) +{ + int err; + + switch (attr) { + case hwmon_temp_input: + err = ds3232_hwmon_read_temp(dev, temp); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static u32 ds3232_hwmon_chip_config[] = { + HWMON_C_REGISTER_TZ, + 0 +}; + +static const struct hwmon_channel_info ds3232_hwmon_chip = { + .type = hwmon_chip, + .config = ds3232_hwmon_chip_config, +}; + +static u32 ds3232_hwmon_temp_config[] = { + HWMON_T_INPUT, + 0 +}; + +static const struct hwmon_channel_info ds3232_hwmon_temp = { + .type = hwmon_temp, + .config = ds3232_hwmon_temp_config, +}; + +static const struct hwmon_channel_info *ds3232_hwmon_info[] = { + &ds3232_hwmon_chip, + &ds3232_hwmon_temp, + NULL +}; + +static const struct hwmon_ops ds3232_hwmon_hwmon_ops = { + .is_visible = ds3232_hwmon_is_visible, + .read = ds3232_hwmon_read, +}; + +static const struct hwmon_chip_info ds3232_hwmon_chip_info = { + .ops = &ds3232_hwmon_hwmon_ops, + .info = ds3232_hwmon_info, +}; + +static void ds3232_hwmon_register(struct device *dev, const char *name) +{ + struct ds3232 *ds3232 = dev_get_drvdata(dev); + struct device *hwmon_dev; + + if (!IS_ENABLED(CONFIG_RTC_DRV_DS3232_HWMON)) + return; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, name, ds3232, + &ds3232_hwmon_chip_info, + NULL); + if (IS_ERR(hwmon_dev)) { + dev_err(dev, "unable to register hwmon device %ld\n", + PTR_ERR(hwmon_dev)); + } +} + static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct ds3232 *ds3232 = dev_get_drvdata(dev); @@ -366,6 +483,8 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, if (ds3232->irq > 0) device_init_wakeup(dev, 1); + ds3232_hwmon_register(dev, name); + ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops, THIS_MODULE); if (IS_ERR(ds3232->rtc)) diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-ftrtc010.c index 5279390bb42d..af8d6beae20c 100644 --- a/drivers/rtc/rtc-gemini.c +++ b/drivers/rtc/rtc-ftrtc010.c @@ -1,5 +1,5 @@ /* - * Gemini OnChip RTC + * Faraday Technology FTRTC010 driver * * Copyright (C) 2009 Janos Laube <janos.dev@gmail.com> * @@ -26,33 +26,36 @@ #include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/clk.h> -#define DRV_NAME "rtc-gemini" +#define DRV_NAME "rtc-ftrtc010" MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>"); MODULE_DESCRIPTION("RTC driver for Gemini SoC"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); -struct gemini_rtc { +struct ftrtc010_rtc { struct rtc_device *rtc_dev; void __iomem *rtc_base; int rtc_irq; + struct clk *pclk; + struct clk *extclk; }; -enum gemini_rtc_offsets { - GEMINI_RTC_SECOND = 0x00, - GEMINI_RTC_MINUTE = 0x04, - GEMINI_RTC_HOUR = 0x08, - GEMINI_RTC_DAYS = 0x0C, - GEMINI_RTC_ALARM_SECOND = 0x10, - GEMINI_RTC_ALARM_MINUTE = 0x14, - GEMINI_RTC_ALARM_HOUR = 0x18, - GEMINI_RTC_RECORD = 0x1C, - GEMINI_RTC_CR = 0x20 +enum ftrtc010_rtc_offsets { + FTRTC010_RTC_SECOND = 0x00, + FTRTC010_RTC_MINUTE = 0x04, + FTRTC010_RTC_HOUR = 0x08, + FTRTC010_RTC_DAYS = 0x0C, + FTRTC010_RTC_ALARM_SECOND = 0x10, + FTRTC010_RTC_ALARM_MINUTE = 0x14, + FTRTC010_RTC_ALARM_HOUR = 0x18, + FTRTC010_RTC_RECORD = 0x1C, + FTRTC010_RTC_CR = 0x20, }; -static irqreturn_t gemini_rtc_interrupt(int irq, void *dev) +static irqreturn_t ftrtc010_rtc_interrupt(int irq, void *dev) { return IRQ_HANDLED; } @@ -66,18 +69,18 @@ static irqreturn_t gemini_rtc_interrupt(int irq, void *dev) * the same thing, without the rtc-lib.c calls. */ -static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct gemini_rtc *rtc = dev_get_drvdata(dev); + struct ftrtc010_rtc *rtc = dev_get_drvdata(dev); unsigned int days, hour, min, sec; unsigned long offset, time; - sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND); - min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE); - hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR); - days = readl(rtc->rtc_base + GEMINI_RTC_DAYS); - offset = readl(rtc->rtc_base + GEMINI_RTC_RECORD); + sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND); + min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE); + hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR); + days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS); + offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD); time = offset + days * 86400 + hour * 3600 + min * 60 + sec; @@ -86,9 +89,9 @@ static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm) return 0; } -static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm) +static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct gemini_rtc *rtc = dev_get_drvdata(dev); + struct ftrtc010_rtc *rtc = dev_get_drvdata(dev); unsigned int sec, min, hour, day; unsigned long offset, time; @@ -97,27 +100,27 @@ static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc_tm_to_time(tm, &time); - sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND); - min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE); - hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR); - day = readl(rtc->rtc_base + GEMINI_RTC_DAYS); + sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND); + min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE); + hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR); + day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS); offset = time - (day * 86400 + hour * 3600 + min * 60 + sec); - writel(offset, rtc->rtc_base + GEMINI_RTC_RECORD); - writel(0x01, rtc->rtc_base + GEMINI_RTC_CR); + writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD); + writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR); return 0; } -static const struct rtc_class_ops gemini_rtc_ops = { - .read_time = gemini_rtc_read_time, - .set_time = gemini_rtc_set_time, +static const struct rtc_class_ops ftrtc010_rtc_ops = { + .read_time = ftrtc010_rtc_read_time, + .set_time = ftrtc010_rtc_set_time, }; -static int gemini_rtc_probe(struct platform_device *pdev) +static int ftrtc010_rtc_probe(struct platform_device *pdev) { - struct gemini_rtc *rtc; + struct ftrtc010_rtc *rtc; struct device *dev = &pdev->dev; struct resource *res; int ret; @@ -127,6 +130,27 @@ static int gemini_rtc_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, rtc); + rtc->pclk = devm_clk_get(dev, "PCLK"); + if (IS_ERR(rtc->pclk)) { + dev_err(dev, "could not get PCLK\n"); + } else { + ret = clk_prepare_enable(rtc->pclk); + if (ret) { + dev_err(dev, "failed to enable PCLK\n"); + return ret; + } + } + rtc->extclk = devm_clk_get(dev, "EXTCLK"); + if (IS_ERR(rtc->extclk)) { + dev_err(dev, "could not get EXTCLK\n"); + } else { + ret = clk_prepare_enable(rtc->extclk); + if (ret) { + dev_err(dev, "failed to enable EXTCLK\n"); + return ret; + } + } + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) return -ENODEV; @@ -142,38 +166,43 @@ static int gemini_rtc_probe(struct platform_device *pdev) if (!rtc->rtc_base) return -ENOMEM; - ret = devm_request_irq(dev, rtc->rtc_irq, gemini_rtc_interrupt, + ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt, IRQF_SHARED, pdev->name, dev); if (unlikely(ret)) return ret; rtc->rtc_dev = rtc_device_register(pdev->name, dev, - &gemini_rtc_ops, THIS_MODULE); + &ftrtc010_rtc_ops, THIS_MODULE); return PTR_ERR_OR_ZERO(rtc->rtc_dev); } -static int gemini_rtc_remove(struct platform_device *pdev) +static int ftrtc010_rtc_remove(struct platform_device *pdev) { - struct gemini_rtc *rtc = platform_get_drvdata(pdev); + struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev); + if (!IS_ERR(rtc->extclk)) + clk_disable_unprepare(rtc->extclk); + if (!IS_ERR(rtc->pclk)) + clk_disable_unprepare(rtc->pclk); rtc_device_unregister(rtc->rtc_dev); return 0; } -static const struct of_device_id gemini_rtc_dt_match[] = { +static const struct of_device_id ftrtc010_rtc_dt_match[] = { { .compatible = "cortina,gemini-rtc" }, + { .compatible = "faraday,ftrtc010" }, { } }; -MODULE_DEVICE_TABLE(of, gemini_rtc_dt_match); +MODULE_DEVICE_TABLE(of, ftrtc010_rtc_dt_match); -static struct platform_driver gemini_rtc_driver = { +static struct platform_driver ftrtc010_rtc_driver = { .driver = { .name = DRV_NAME, - .of_match_table = gemini_rtc_dt_match, + .of_match_table = ftrtc010_rtc_dt_match, }, - .probe = gemini_rtc_probe, - .remove = gemini_rtc_remove, + .probe = ftrtc010_rtc_probe, + .remove = ftrtc010_rtc_remove, }; -module_platform_driver_probe(gemini_rtc_driver, gemini_rtc_probe); +module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe); diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 5ec4653022ff..8940e9e43ea0 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -16,6 +16,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/bcd.h> +#include <linux/clk-provider.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> @@ -53,6 +54,8 @@ #define M41T80_ALARM_REG_SIZE \ (M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON) +#define M41T80_SQW_MAX_FREQ 32768 + #define M41T80_SEC_ST BIT(7) /* ST: Stop Bit */ #define M41T80_ALMON_AFE BIT(7) /* AFE: AF Enable Bit */ #define M41T80_ALMON_SQWE BIT(6) /* SQWE: SQW Enable Bit */ @@ -147,7 +150,11 @@ MODULE_DEVICE_TABLE(of, m41t80_of_match); struct m41t80_data { unsigned long features; + struct i2c_client *client; struct rtc_device *rtc; +#ifdef CONFIG_COMMON_CLK + struct clk_hw sqw; +#endif }; static irqreturn_t m41t80_handle_irq(int irq, void *dev_id) @@ -227,6 +234,7 @@ static int m41t80_get_datetime(struct i2c_client *client, /* Sets the given date and time to the real time clock. */ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct m41t80_data *clientdata = i2c_get_clientdata(client); unsigned char buf[8]; int err, flags; @@ -242,6 +250,17 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100); buf[M41T80_REG_WDAY] = tm->tm_wday; + /* If the square wave output is controlled in the weekday register */ + if (clientdata->features & M41T80_FEATURE_SQ_ALT) { + int val; + + val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY); + if (val < 0) + return val; + + buf[M41T80_REG_WDAY] |= (val & 0xf0); + } + err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC, sizeof(buf), buf); if (err < 0) { @@ -332,6 +351,9 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return err; } + /* Keep SQWE bit value */ + alarmvals[0] |= (ret & M41T80_ALMON_SQWE); + ret = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); if (ret < 0) return ret; @@ -431,103 +453,175 @@ static ssize_t flags_show(struct device *dev, } static DEVICE_ATTR_RO(flags); -static ssize_t sqwfreq_show(struct device *dev, - struct device_attribute *attr, char *buf) +static struct attribute *attrs[] = { + &dev_attr_flags.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +#ifdef CONFIG_COMMON_CLK +#define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw) + +static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - struct i2c_client *client = to_i2c_client(dev); - struct m41t80_data *clientdata = i2c_get_clientdata(client); - int val, reg_sqw; + struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw); + struct i2c_client *client = m41t80->client; + int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ? + M41T80_REG_WDAY : M41T80_REG_SQW; + int ret = i2c_smbus_read_byte_data(client, reg_sqw); + unsigned long val = M41T80_SQW_MAX_FREQ; - if (!(clientdata->features & M41T80_FEATURE_SQ)) - return -EINVAL; + if (ret < 0) + return 0; - reg_sqw = M41T80_REG_SQW; - if (clientdata->features & M41T80_FEATURE_SQ_ALT) - reg_sqw = M41T80_REG_WDAY; - val = i2c_smbus_read_byte_data(client, reg_sqw); - if (val < 0) - return val; - val = (val >> 4) & 0xf; - switch (val) { - case 0: - break; - case 1: - val = 32768; - break; - default: - val = 32768 >> val; - } - return sprintf(buf, "%d\n", val); + ret >>= 4; + if (ret == 0) + val = 0; + else if (ret > 1) + val = val / (1 << ret); + + return val; } -static ssize_t sqwfreq_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) { - struct i2c_client *client = to_i2c_client(dev); - struct m41t80_data *clientdata = i2c_get_clientdata(client); - int almon, sqw, reg_sqw, rc; - unsigned long val; + int i, freq = M41T80_SQW_MAX_FREQ; - rc = kstrtoul(buf, 0, &val); - if (rc < 0) - return rc; + if (freq <= rate) + return freq; - if (!(clientdata->features & M41T80_FEATURE_SQ)) - return -EINVAL; + for (i = 2; i <= ilog2(M41T80_SQW_MAX_FREQ); i++) { + freq /= 1 << i; + if (freq <= rate) + return freq; + } - if (val) { - if (!is_power_of_2(val)) + return 0; +} + +static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw); + struct i2c_client *client = m41t80->client; + int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ? + M41T80_REG_WDAY : M41T80_REG_SQW; + int reg, ret, val = 0; + + if (rate) { + if (!is_power_of_2(rate)) return -EINVAL; - val = ilog2(val); - if (val == 15) + val = ilog2(rate); + if (val == ilog2(M41T80_SQW_MAX_FREQ)) val = 1; - else if (val < 14) - val = 15 - val; + else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1)) + val = ilog2(M41T80_SQW_MAX_FREQ) - val; else return -EINVAL; } - /* disable SQW, set SQW frequency & re-enable */ - almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); - if (almon < 0) - return almon; - reg_sqw = M41T80_REG_SQW; - if (clientdata->features & M41T80_FEATURE_SQ_ALT) - reg_sqw = M41T80_REG_WDAY; - sqw = i2c_smbus_read_byte_data(client, reg_sqw); - if (sqw < 0) - return sqw; - sqw = (sqw & 0x0f) | (val << 4); - - rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, - almon & ~M41T80_ALMON_SQWE); - if (rc < 0) - return rc; - if (val) { - rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw); - if (rc < 0) - return rc; + reg = i2c_smbus_read_byte_data(client, reg_sqw); + if (reg < 0) + return reg; - rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, - almon | M41T80_ALMON_SQWE); - if (rc < 0) - return rc; - } - return count; + reg = (reg & 0x0f) | (val << 4); + + ret = i2c_smbus_write_byte_data(client, reg_sqw, reg); + if (ret < 0) + return ret; + + return -EINVAL; } -static DEVICE_ATTR_RW(sqwfreq); -static struct attribute *attrs[] = { - &dev_attr_flags.attr, - &dev_attr_sqwfreq.attr, - NULL, -}; +static int m41t80_sqw_control(struct clk_hw *hw, bool enable) +{ + struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw); + struct i2c_client *client = m41t80->client; + int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); -static struct attribute_group attr_group = { - .attrs = attrs, + if (ret < 0) + return ret; + + if (enable) + ret |= M41T80_ALMON_SQWE; + else + ret &= ~M41T80_ALMON_SQWE; + + return i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret); +} + +static int m41t80_sqw_prepare(struct clk_hw *hw) +{ + return m41t80_sqw_control(hw, 1); +} + +static void m41t80_sqw_unprepare(struct clk_hw *hw) +{ + m41t80_sqw_control(hw, 0); +} + +static int m41t80_sqw_is_prepared(struct clk_hw *hw) +{ + struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw); + struct i2c_client *client = m41t80->client; + int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); + + if (ret < 0) + return ret; + + return !!(ret & M41T80_ALMON_SQWE); +} + +static const struct clk_ops m41t80_sqw_ops = { + .prepare = m41t80_sqw_prepare, + .unprepare = m41t80_sqw_unprepare, + .is_prepared = m41t80_sqw_is_prepared, + .recalc_rate = m41t80_sqw_recalc_rate, + .round_rate = m41t80_sqw_round_rate, + .set_rate = m41t80_sqw_set_rate, }; +static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) +{ + struct i2c_client *client = m41t80->client; + struct device_node *node = client->dev.of_node; + struct clk *clk; + struct clk_init_data init; + int ret; + + /* First disable the clock */ + ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); + if (ret < 0) + return ERR_PTR(ret); + ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, + ret & ~(M41T80_ALMON_SQWE)); + if (ret < 0) + return ERR_PTR(ret); + + init.name = "m41t80-sqw"; + init.ops = &m41t80_sqw_ops; + init.flags = 0; + init.parent_names = NULL; + init.num_parents = 0; + m41t80->sqw.init = &init; + + /* optional override of the clockname */ + of_property_read_string(node, "clock-output-names", &init.name); + + /* register the clock */ + clk = clk_register(&client->dev, &m41t80->sqw); + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return clk; +} +#endif + #ifdef CONFIG_RTC_DRV_M41T80_WDT /* ***************************************************************************** @@ -845,6 +939,7 @@ static int m41t80_probe(struct i2c_client *client, if (!m41t80_data) return -ENOMEM; + m41t80_data->client = client; if (client->dev.of_node) m41t80_data->features = (unsigned long) of_device_get_match_data(&client->dev); @@ -937,6 +1032,10 @@ static int m41t80_probe(struct i2c_client *client, } } #endif +#ifdef CONFIG_COMMON_CLK + if (m41t80_data->features & M41T80_FEATURE_SQ) + m41t80_sqw_register_clk(m41t80_data); +#endif return 0; } diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 77319122642a..401f46d8f21b 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -43,17 +43,6 @@ #define MAX_PIE_NUM 9 #define MAX_PIE_FREQ 512 -static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = { - { 2, RTC_2HZ_BIT }, - { 4, RTC_SAM0_BIT }, - { 8, RTC_SAM1_BIT }, - { 16, RTC_SAM2_BIT }, - { 32, RTC_SAM3_BIT }, - { 64, RTC_SAM4_BIT }, - { 128, RTC_SAM5_BIT }, - { 256, RTC_SAM6_BIT }, - { MAX_PIE_FREQ, RTC_SAM7_BIT }, -}; #define MXC_RTC_TIME 0 #define MXC_RTC_ALARM 1 diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index b1b6b3041bfb..4ed81117cf5f 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -93,7 +93,7 @@ static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER); while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) - && timeout--) + && --timeout) mdelay(1); if (!timeout) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index ea20f627dabe..e2a946c0e667 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -142,6 +142,16 @@ static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) y_m_d = be32_to_cpu(__y_m_d); h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32); + + /* check if no alarm is set */ + if (y_m_d == 0 && h_m_s_ms == 0) { + pr_debug("No alarm is set\n"); + rc = -ENOENT; + goto exit; + } else { + pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms); + } + opal_to_tm(y_m_d, h_m_s_ms, &alarm->time); exit: @@ -157,7 +167,14 @@ static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) u32 y_m_d = 0; int token, rc; - tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms); + /* if alarm is enabled */ + if (alarm->enabled) { + tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms); + pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms); + + } else { + pr_debug("Alarm getting disabled\n"); + } token = opal_async_get_token_interruptible(); if (token < 0) { @@ -190,6 +207,18 @@ exit: return rc; } +int opal_tpo_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct rtc_wkalrm alarm = { .enabled = 0 }; + + /* + * TPO is automatically enabled when opal_set_tpo_time() is called with + * non-zero rtc-time. We only handle disable case which needs to be + * explicitly told to opal. + */ + return enabled ? 0 : opal_set_tpo_time(dev, &alarm); +} + static struct rtc_class_ops opal_rtc_ops = { .read_time = opal_get_rtc_time, .set_time = opal_set_rtc_time, @@ -205,6 +234,7 @@ static int opal_rtc_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); opal_rtc_ops.read_alarm = opal_get_tpo_time; opal_rtc_ops.set_alarm = opal_set_tpo_time; + opal_rtc_ops.alarm_irq_enable = opal_tpo_alarm_irq_enable; } rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops, diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 1227ceab61ee..cea6ea4df970 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -606,7 +606,7 @@ static int pcf8563_probe(struct i2c_client *client, err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8563_irq, IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING, - pcf8563->rtc->name, client); + pcf8563_driver.driver.name, client); if (err) { dev_err(&client->dev, "unable to request IRQ %d\n", client->irq); diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 9ad97ab29866..aae2576741a6 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -68,6 +68,7 @@ struct rv8803_data { struct mutex flags_lock; u8 ctrl; enum rv8803_type type; + struct nvmem_config nvmem_cfg; }; static int rv8803_read_reg(const struct i2c_client *client, u8 reg) @@ -460,48 +461,32 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) } } -static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) +static int rv8803_nvram_write(void *priv, unsigned int offset, void *val, + size_t bytes) { - struct device *dev = kobj_to_dev(kobj); - struct i2c_client *client = to_i2c_client(dev); int ret; - ret = rv8803_write_reg(client, RV8803_RAM, buf[0]); + ret = rv8803_write_reg(priv, RV8803_RAM, *(u8 *)val); if (ret) return ret; - return 1; + return 0; } -static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) +static int rv8803_nvram_read(void *priv, unsigned int offset, + void *val, size_t bytes) { - struct device *dev = kobj_to_dev(kobj); - struct i2c_client *client = to_i2c_client(dev); int ret; - ret = rv8803_read_reg(client, RV8803_RAM); + ret = rv8803_read_reg(priv, RV8803_RAM); if (ret < 0) return ret; - buf[0] = ret; + *(u8 *)val = ret; - return 1; + return 0; } -static struct bin_attribute rv8803_nvram_attr = { - .attr = { - .name = "nvram", - .mode = S_IRUGO | S_IWUSR, - }, - .size = 1, - .read = rv8803_nvram_read, - .write = rv8803_nvram_write, -}; - static struct rtc_class_ops rv8803_rtc_ops = { .read_time = rv8803_get_time, .set_time = rv8803_set_time, @@ -577,6 +562,11 @@ static int rv8803_probe(struct i2c_client *client, if (flags & RV8803_FLAG_AF) dev_warn(&client->dev, "An alarm maybe have been missed.\n"); + rv8803->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(rv8803->rtc)) { + return PTR_ERR(rv8803->rtc); + } + if (client->irq > 0) { err = devm_request_threaded_irq(&client->dev, client->irq, NULL, rv8803_handle_irq, @@ -592,12 +582,20 @@ static int rv8803_probe(struct i2c_client *client, } } - rv8803->rtc = devm_rtc_device_register(&client->dev, client->name, - &rv8803_rtc_ops, THIS_MODULE); - if (IS_ERR(rv8803->rtc)) { - dev_err(&client->dev, "unable to register the class device\n"); - return PTR_ERR(rv8803->rtc); - } + rv8803->nvmem_cfg.name = "rv8803_nvram", + rv8803->nvmem_cfg.word_size = 1, + rv8803->nvmem_cfg.stride = 1, + rv8803->nvmem_cfg.size = 1, + rv8803->nvmem_cfg.reg_read = rv8803_nvram_read, + rv8803->nvmem_cfg.reg_write = rv8803_nvram_write, + rv8803->nvmem_cfg.priv = client; + + rv8803->rtc->ops = &rv8803_rtc_ops; + rv8803->rtc->nvmem_config = &rv8803->nvmem_cfg; + rv8803->rtc->nvram_old_abi = true; + err = rtc_register_device(rv8803->rtc); + if (err) + return err; err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA); if (err) @@ -609,22 +607,11 @@ static int rv8803_probe(struct i2c_client *client, return err; } - err = device_create_bin_file(&client->dev, &rv8803_nvram_attr); - if (err) - return err; - rv8803->rtc->max_user_freq = 1; return 0; } -static int rv8803_remove(struct i2c_client *client) -{ - device_remove_bin_file(&client->dev, &rv8803_nvram_attr); - - return 0; -} - static const struct i2c_device_id rv8803_id[] = { { "rv8803", rv_8803 }, { "rx8900", rx_8900 }, @@ -651,7 +638,6 @@ static struct i2c_driver rv8803_driver = { .of_match_table = of_match_ptr(rv8803_of_match), }, .probe = rv8803_probe, - .remove = rv8803_remove, .id_table = rv8803_id, }; module_i2c_driver(rv8803_driver); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index d44fb34df8fe..a8992c227f61 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -41,7 +41,7 @@ struct s3c_rtc { struct clk *rtc_src_clk; bool clk_disabled; - struct s3c_rtc_data *data; + const struct s3c_rtc_data *data; int irq_alarm; int irq_tick; @@ -49,7 +49,8 @@ struct s3c_rtc { spinlock_t pie_lock; spinlock_t alarm_clk_lock; - int ticnt_save, ticnt_en_save; + int ticnt_save; + int ticnt_en_save; bool wake_en; }; @@ -67,18 +68,32 @@ struct s3c_rtc_data { void (*disable) (struct s3c_rtc *info); }; -static void s3c_rtc_enable_clk(struct s3c_rtc *info) +static int s3c_rtc_enable_clk(struct s3c_rtc *info) { unsigned long irq_flags; + int ret = 0; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); + if (info->clk_disabled) { - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + ret = clk_enable(info->rtc_clk); + if (ret) + goto out; + + if (info->data->needs_src_clk) { + ret = clk_enable(info->rtc_src_clk); + if (ret) { + clk_disable(info->rtc_clk); + goto out; + } + } info->clk_disabled = false; } + +out: spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); + + return ret; } static void s3c_rtc_disable_clk(struct s3c_rtc *info) @@ -121,10 +136,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) { struct s3c_rtc *info = dev_get_drvdata(dev); unsigned int tmp; + int ret; dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled); - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; @@ -135,10 +153,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) s3c_rtc_disable_clk(info); - if (enabled) - s3c_rtc_enable_clk(info); - else + if (enabled) { + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; + } else { s3c_rtc_disable_clk(info); + } return 0; } @@ -146,10 +167,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) /* Set RTC frequency */ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq) { + int ret; + if (!is_power_of_2(freq)) return -EINVAL; - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; spin_lock_irq(&info->pie_lock); if (info->data->set_freq) @@ -166,10 +191,13 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { struct s3c_rtc *info = dev_get_drvdata(dev); unsigned int have_retried = 0; + int ret; - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; - retry_get_time: +retry_get_time: rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN); rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR); rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE); @@ -199,8 +227,8 @@ static int s3c_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); + 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; @@ -211,10 +239,11 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) { struct s3c_rtc *info = dev_get_drvdata(dev); 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); + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); /* we get around y2k by simply not supporting it */ @@ -223,7 +252,9 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) return -EINVAL; } - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC); writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); @@ -242,8 +273,11 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) struct s3c_rtc *info = dev_get_drvdata(dev); struct rtc_time *alm_tm = &alrm->time; unsigned int alm_en; + int ret; - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC); alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN); @@ -259,9 +293,9 @@ 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); + 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); /* decode the alarm enable field */ if (alm_en & S3C2410_RTCALM_SECEN) @@ -292,14 +326,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct s3c_rtc *info = dev_get_drvdata(dev); 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, - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + alrm->enabled, + 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; writeb(0x00, info->base + S3C2410_RTCALM); @@ -348,8 +385,11 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) { struct s3c_rtc *info = dev_get_drvdata(dev); + int ret; - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; if (info->data->enable_tick) info->data->enable_tick(info, seq); @@ -378,8 +418,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info) dev_info(info->dev, "rtc disabled, re-enabling\n"); tmp = readw(info->base + S3C2410_RTCCON); - writew(tmp | S3C2410_RTCCON_RTCEN, - info->base + S3C2410_RTCCON); + writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON); } if (con & S3C2410_RTCCON_CNTSEL) { @@ -387,7 +426,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info) tmp = readw(info->base + S3C2410_RTCCON); writew(tmp & ~S3C2410_RTCCON_CNTSEL, - info->base + S3C2410_RTCCON); + info->base + S3C2410_RTCCON); } if (con & S3C2410_RTCCON_CLKRST) { @@ -395,7 +434,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info) tmp = readw(info->base + S3C2410_RTCCON); writew(tmp & ~S3C2410_RTCCON_CLKRST, - info->base + S3C2410_RTCCON); + info->base + S3C2410_RTCCON); } } @@ -437,12 +476,12 @@ static int s3c_rtc_remove(struct platform_device *pdev) static const struct of_device_id s3c_rtc_dt_match[]; -static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev) +static const struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev) { const struct of_device_id *match; match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); - return (struct s3c_rtc_data *)match->data; + return match->data; } static int s3c_rtc_probe(struct platform_device *pdev) @@ -481,7 +520,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) } dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n", - info->irq_tick, info->irq_alarm); + info->irq_tick, info->irq_alarm); /* get the memory region */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -498,7 +537,9 @@ static int s3c_rtc_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n"); return ret; } - clk_prepare_enable(info->rtc_clk); + ret = clk_prepare_enable(info->rtc_clk); + if (ret) + return ret; if (info->data->needs_src_clk) { info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src"); @@ -510,10 +551,11 @@ static int s3c_rtc_probe(struct platform_device *pdev) else dev_dbg(&pdev->dev, "probe deferred due to missing rtc src clk\n"); - clk_disable_unprepare(info->rtc_clk); - return ret; + goto err_src_clk; } - clk_prepare_enable(info->rtc_src_clk); + ret = clk_prepare_enable(info->rtc_src_clk); + if (ret) + goto err_src_clk; } /* check to see if everything is setup correctly */ @@ -521,7 +563,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) info->data->enable(info); dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", - readw(info->base + S3C2410_RTCCON)); + readw(info->base + S3C2410_RTCCON)); device_init_wakeup(&pdev->dev, 1); @@ -541,7 +583,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) /* register RTC and exit */ info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops, - THIS_MODULE); + THIS_MODULE); if (IS_ERR(info->rtc)) { dev_err(&pdev->dev, "cannot attach rtc\n"); ret = PTR_ERR(info->rtc); @@ -549,14 +591,14 @@ static int s3c_rtc_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq, - 0, "s3c2410-rtc alarm", info); + 0, "s3c2410-rtc alarm", info); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret); goto err_nortc; } ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq, - 0, "s3c2410-rtc tick", info); + 0, "s3c2410-rtc tick", info); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret); goto err_nortc; @@ -569,12 +611,13 @@ static int s3c_rtc_probe(struct platform_device *pdev) return 0; - err_nortc: +err_nortc: if (info->data->disable) info->data->disable(info); if (info->data->needs_src_clk) clk_disable_unprepare(info->rtc_src_clk); +err_src_clk: clk_disable_unprepare(info->rtc_clk); return ret; @@ -585,8 +628,11 @@ static int s3c_rtc_probe(struct platform_device *pdev) static int s3c_rtc_suspend(struct device *dev) { struct s3c_rtc *info = dev_get_drvdata(dev); + int ret; - s3c_rtc_enable_clk(info); + ret = s3c_rtc_enable_clk(info); + if (ret) + return ret; /* save TICNT for anyone using periodic interrupts */ if (info->data->save_tick_cnt) @@ -747,8 +793,7 @@ static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info) writel(info->ticnt_save, info->base + S3C2410_TICNT); if (info->ticnt_en_save) { con = readw(info->base + S3C2410_RTCCON); - writew(con | info->ticnt_en_save, - info->base + S3C2410_RTCCON); + writew(con | info->ticnt_en_save, info->base + S3C2410_RTCCON); } } @@ -802,19 +847,19 @@ static struct s3c_rtc_data const s3c6410_rtc_data = { static const struct of_device_id s3c_rtc_dt_match[] = { { .compatible = "samsung,s3c2410-rtc", - .data = (void *)&s3c2410_rtc_data, + .data = &s3c2410_rtc_data, }, { .compatible = "samsung,s3c2416-rtc", - .data = (void *)&s3c2416_rtc_data, + .data = &s3c2416_rtc_data, }, { .compatible = "samsung,s3c2443-rtc", - .data = (void *)&s3c2443_rtc_data, + .data = &s3c2443_rtc_data, }, { .compatible = "samsung,s3c6410-rtc", - .data = (void *)&s3c6410_rtc_data, + .data = &s3c6410_rtc_data, }, { .compatible = "samsung,exynos3250-rtc", - .data = (void *)&s3c6410_rtc_data, + .data = &s3c6410_rtc_data, }, { /* sentinel */ }, }; diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c index 74c0a336ceea..82b0af159a28 100644 --- a/drivers/rtc/rtc-st-lpc.c +++ b/drivers/rtc/rtc-st-lpc.c @@ -99,7 +99,7 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm) lpt = ((unsigned long long)lpt_msb << 32) | lpt_lsb; do_div(lpt, rtc->clkrate); - rtc_time_to_tm(lpt, tm); + rtc_time64_to_tm(lpt, tm); return 0; } @@ -107,13 +107,10 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm) static int st_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct st_rtc *rtc = dev_get_drvdata(dev); - unsigned long long lpt; - unsigned long secs, flags; - int ret; + unsigned long long lpt, secs; + unsigned long flags; - ret = rtc_tm_to_time(tm, &secs); - if (ret) - return ret; + secs = rtc_tm_to_time64(tm); lpt = (unsigned long long)secs * rtc->clkrate; @@ -161,13 +158,13 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct st_rtc *rtc = dev_get_drvdata(dev); struct rtc_time now; - unsigned long now_secs; - unsigned long alarm_secs; + unsigned long long now_secs; + unsigned long long alarm_secs; unsigned long long lpa; st_rtc_read_time(dev, &now); - rtc_tm_to_time(&now, &now_secs); - rtc_tm_to_time(&t->time, &alarm_secs); + now_secs = rtc_tm_to_time64(&now); + alarm_secs = rtc_tm_to_time64(&t->time); /* Invalid alarm time */ if (now_secs > alarm_secs) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index bd57eb1029e1..3a5c3d7d0c77 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -94,11 +94,17 @@ /* STM32_PWR_CR bit field */ #define PWR_CR_DBP BIT(8) +struct stm32_rtc_data { + bool has_pclk; +}; + struct stm32_rtc { struct rtc_device *rtc_dev; void __iomem *base; struct regmap *dbp; - struct clk *ck_rtc; + struct stm32_rtc_data *data; + struct clk *pclk; + struct clk *rtc_ck; int irq_alarm; }; @@ -122,9 +128,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) writel_relaxed(isr, rtc->base + STM32_RTC_ISR); /* - * It takes around 2 ck_rtc clock cycles to enter in + * It takes around 2 rtc_ck clock cycles to enter in * initialization phase mode (and have INITF flag set). As - * slowest ck_rtc frequency may be 32kHz and highest should be + * slowest rtc_ck frequency may be 32kHz and highest should be * 1MHz, we poll every 10 us with a timeout of 100ms. */ return readl_relaxed_poll_timeout_atomic( @@ -153,7 +159,7 @@ static int stm32_rtc_wait_sync(struct stm32_rtc *rtc) /* * Wait for RSF to be set to ensure the calendar registers are - * synchronised, it takes around 2 ck_rtc clock cycles + * synchronised, it takes around 2 rtc_ck clock cycles */ return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR, isr, @@ -456,7 +462,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) /* * Poll Alarm write flag to be sure that Alarm update is allowed: it - * takes around 2 ck_rtc clock cycles + * takes around 2 rtc_ck clock cycles */ ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR, isr, @@ -490,8 +496,17 @@ static const struct rtc_class_ops stm32_rtc_ops = { .alarm_irq_enable = stm32_rtc_alarm_irq_enable, }; +static const struct stm32_rtc_data stm32_rtc_data = { + .has_pclk = false, +}; + +static const struct stm32_rtc_data stm32h7_rtc_data = { + .has_pclk = true, +}; + static const struct of_device_id stm32_rtc_of_match[] = { - { .compatible = "st,stm32-rtc" }, + { .compatible = "st,stm32-rtc", .data = &stm32_rtc_data }, + { .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data }, {} }; MODULE_DEVICE_TABLE(of, stm32_rtc_of_match); @@ -503,7 +518,7 @@ static int stm32_rtc_init(struct platform_device *pdev, unsigned int rate; int ret = 0; - rate = clk_get_rate(rtc->ck_rtc); + rate = clk_get_rate(rtc->rtc_ck); /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */ pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; @@ -524,7 +539,7 @@ static int stm32_rtc_init(struct platform_device *pdev, pred_a = pred_a_max; pred_s = (rate / (pred_a + 1)) - 1; - dev_warn(&pdev->dev, "ck_rtc is %s\n", + dev_warn(&pdev->dev, "rtc_ck is %s\n", (rate < ((pred_a + 1) * (pred_s + 1))) ? "fast" : "slow"); } @@ -561,6 +576,7 @@ static int stm32_rtc_probe(struct platform_device *pdev) { struct stm32_rtc *rtc; struct resource *res; + const struct of_device_id *match; int ret; rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); @@ -579,15 +595,34 @@ static int stm32_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtc->dbp); } - rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(rtc->ck_rtc)) { - dev_err(&pdev->dev, "no ck_rtc clock"); - return PTR_ERR(rtc->ck_rtc); + match = of_match_device(stm32_rtc_of_match, &pdev->dev); + rtc->data = (struct stm32_rtc_data *)match->data; + + if (!rtc->data->has_pclk) { + rtc->pclk = NULL; + rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL); + } else { + rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(rtc->pclk)) { + dev_err(&pdev->dev, "no pclk clock"); + return PTR_ERR(rtc->pclk); + } + rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); + } + if (IS_ERR(rtc->rtc_ck)) { + dev_err(&pdev->dev, "no rtc_ck clock"); + return PTR_ERR(rtc->rtc_ck); + } + + if (rtc->data->has_pclk) { + ret = clk_prepare_enable(rtc->pclk); + if (ret) + return ret; } - ret = clk_prepare_enable(rtc->ck_rtc); + ret = clk_prepare_enable(rtc->rtc_ck); if (ret) - return ret; + goto err; regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP); @@ -595,7 +630,7 @@ static int stm32_rtc_probe(struct platform_device *pdev) * After a system reset, RTC_ISR.INITS flag can be read to check if * the calendar has been initalized or not. INITS flag is reset by a * power-on reset (no vbat, no power-supply). It is not reset if - * ck_rtc parent clock has changed (so RTC prescalers need to be + * rtc_ck parent clock has changed (so RTC prescalers need to be * changed). That's why we cannot rely on this flag to know if RTC * init has to be done. */ @@ -646,7 +681,9 @@ static int stm32_rtc_probe(struct platform_device *pdev) return 0; err: - clk_disable_unprepare(rtc->ck_rtc); + if (rtc->data->has_pclk) + clk_disable_unprepare(rtc->pclk); + clk_disable_unprepare(rtc->rtc_ck); regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0); @@ -667,7 +704,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) writel_relaxed(cr, rtc->base + STM32_RTC_CR); stm32_rtc_wpr_lock(rtc); - clk_disable_unprepare(rtc->ck_rtc); + clk_disable_unprepare(rtc->rtc_ck); + if (rtc->data->has_pclk) + clk_disable_unprepare(rtc->pclk); /* Enable backup domain write protection */ regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0); @@ -682,6 +721,9 @@ static int stm32_rtc_suspend(struct device *dev) { struct stm32_rtc *rtc = dev_get_drvdata(dev); + if (rtc->data->has_pclk) + clk_disable_unprepare(rtc->pclk); + if (device_may_wakeup(dev)) return enable_irq_wake(rtc->irq_alarm); @@ -693,6 +735,12 @@ static int stm32_rtc_resume(struct device *dev) struct stm32_rtc *rtc = dev_get_drvdata(dev); int ret = 0; + if (rtc->data->has_pclk) { + ret = clk_prepare_enable(rtc->pclk); + if (ret) + return ret; + } + ret = stm32_rtc_wait_sync(rtc); if (ret < 0) return ret; diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 1218d5d4224d..e364550eb9a7 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -27,7 +27,8 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", to_rtc_device(dev)->name); + return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent), + dev_name(dev->parent)); } static DEVICE_ATTR_RO(name); |