diff options
31 files changed, 982 insertions, 761 deletions
diff --git a/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml b/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml new file mode 100644 index 000000000000..114199cf4d28 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/mstar,msc313-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mstar MSC313e RTC Device Tree Bindings + +allOf: + - $ref: "rtc.yaml#" + +maintainers: + - Daniel Palmer <daniel@0x0f.com> + - Romain Perier <romain.perier@gmail.com> + +properties: + compatible: + enum: + - mstar,msc313-rtc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + start-year: true + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + rtc@2400 { + compatible = "mstar,msc313-rtc"; + reg = <0x2400 0x40>; + clocks = <&xtal_div2>; + interrupts-extended = <&intc_irq GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; + }; +... diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.txt b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.txt index 627bb533eff7..6439682c9319 100644 --- a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.txt +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.txt @@ -13,10 +13,19 @@ Optional property: expressed in femto Farad (fF). Valid values are 7000 and 12500. Default value (if no value is specified) is 7000fF. +Optional child node: +- clock: Provide this if the square wave pin is used as boot-enabled fixed clock. + Example: pcf85063: rtc@51 { compatible = "nxp,pcf85063"; reg = <0x51>; quartz-load-femtofarads = <12500>; + + clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; }; diff --git a/MAINTAINERS b/MAINTAINERS index a2fe76f56b32..f65baad1d857 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2283,6 +2283,7 @@ F: arch/arm/boot/dts/mstar-* F: arch/arm/mach-mstar/ F: drivers/clk/mstar/ F: drivers/gpio/gpio-msc313.c +F: drivers/rtc/rtc-msc313.c F: drivers/watchdog/msc313e_wdt.c F: include/dt-bindings/clock/mstar-* F: include/dt-bindings/gpio/msc313-gpio.h diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7208eeb8459a..058e56a10ab8 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -441,6 +441,7 @@ config RTC_DRV_X1205 config RTC_DRV_PCF8523 tristate "NXP PCF8523" + select REGMAP_I2C help If you say yes here you get support for the NXP PCF8523 RTC chips. @@ -582,14 +583,6 @@ config RTC_DRV_TPS65910 This driver can also be built as a module. If so, the module will be called rtc-tps65910. -config RTC_DRV_TPS80031 - tristate "TI TPS80031/TPS80032 RTC driver" - depends on MFD_TPS80031 - help - TI Power Management IC TPS80031 supports RTC functionality - along with alarm. This driver supports the RTC driver for - the TPS80031 RTC module. - config RTC_DRV_RC5T583 tristate "RICOH 5T583 RTC driver" depends on MFD_RC5T583 @@ -1929,4 +1922,14 @@ config RTC_DRV_WILCO_EC This can also be built as a module. If so, the module will be named "rtc_wilco_ec". +config RTC_DRV_MSC313 + tristate "MStar MSC313 RTC" + depends on ARCH_MSTARV7 || COMPILE_TEST + help + If you say yes here you get support for the Mstar MSC313e On-Chip + Real Time Clock. + + This driver can also be built as a module, if so, the module + will be called "rtc-msc313". + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 5ceeafe4d5b2..678a8ef4abae 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o +obj-$(CONFIG_RTC_DRV_MSC313) += rtc-msc313.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MT2712) += rtc-mt2712.o obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o @@ -169,7 +170,6 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o -obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index f77bc089eb6b..4b460c61f1d8 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -232,6 +232,7 @@ static struct rtc_device *rtc_allocate_device(void) rtc->pie_enabled = 0; set_bit(RTC_FEATURE_ALARM, rtc->features); + set_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); return rtc; } @@ -334,7 +335,8 @@ static void devm_rtc_unregister_device(void *data) * letting any rtc_class_open() users access it again */ rtc_proc_del_device(rtc); - cdev_device_del(&rtc->char_dev, &rtc->dev); + if (!test_bit(RTC_NO_CDEV, &rtc->flags)) + cdev_device_del(&rtc->char_dev, &rtc->dev); rtc->ops = NULL; mutex_unlock(&rtc->ops_lock); } @@ -363,7 +365,9 @@ struct rtc_device *devm_rtc_allocate_device(struct device *dev) rtc->id = id; rtc->dev.parent = dev; - dev_set_name(&rtc->dev, "rtc%d", id); + err = dev_set_name(&rtc->dev, "rtc%d", id); + if (err) + return ERR_PTR(err); err = devm_add_action_or_reset(dev, devm_rtc_release_device, rtc); if (err) @@ -386,6 +390,12 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc) if (!rtc->ops->set_alarm) clear_bit(RTC_FEATURE_ALARM, rtc->features); + if (rtc->uie_unsupported) + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); + + if (rtc->ops->set_offset) + set_bit(RTC_FEATURE_CORRECTION, rtc->features); + rtc->owner = owner; rtc_device_get_offset(rtc); @@ -397,12 +407,14 @@ int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc) rtc_dev_prepare(rtc); err = cdev_device_add(&rtc->char_dev, &rtc->dev); - if (err) + if (err) { + set_bit(RTC_NO_CDEV, &rtc->flags); dev_warn(rtc->dev.parent, "failed to add char device %d:%d\n", MAJOR(rtc->dev.devt), rtc->id); - else + } else { dev_dbg(rtc->dev.parent, "char device (%d:%d)\n", MAJOR(rtc->dev.devt), rtc->id); + } rtc_proc_add_device(rtc); diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index 5b8ebe86124a..e104972a28fd 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -208,6 +208,7 @@ static long rtc_dev_ioctl(struct file *file, const struct rtc_class_ops *ops = rtc->ops; struct rtc_time tm; struct rtc_wkalrm alarm; + struct rtc_param param; void __user *uarg = (void __user *)arg; err = mutex_lock_interruptible(&rtc->ops_lock); @@ -221,6 +222,7 @@ static long rtc_dev_ioctl(struct file *file, switch (cmd) { case RTC_EPOCH_SET: case RTC_SET_TIME: + case RTC_PARAM_SET: if (!capable(CAP_SYS_TIME)) err = -EACCES; break; @@ -382,6 +384,69 @@ static long rtc_dev_ioctl(struct file *file, err = -EFAULT; return err; + case RTC_PARAM_GET: + if (copy_from_user(¶m, uarg, sizeof(param))) { + mutex_unlock(&rtc->ops_lock); + return -EFAULT; + } + + switch(param.param) { + long offset; + case RTC_PARAM_FEATURES: + if (param.index != 0) + err = -EINVAL; + param.uvalue = rtc->features[0]; + break; + + case RTC_PARAM_CORRECTION: + mutex_unlock(&rtc->ops_lock); + if (param.index != 0) + return -EINVAL; + err = rtc_read_offset(rtc, &offset); + mutex_lock(&rtc->ops_lock); + if (err == 0) + param.svalue = offset; + break; + + default: + if (rtc->ops->param_get) + err = rtc->ops->param_get(rtc->dev.parent, ¶m); + else + err = -EINVAL; + } + + if (!err) + if (copy_to_user(uarg, ¶m, sizeof(param))) + err = -EFAULT; + + break; + + case RTC_PARAM_SET: + if (copy_from_user(¶m, uarg, sizeof(param))) { + mutex_unlock(&rtc->ops_lock); + return -EFAULT; + } + + switch(param.param) { + case RTC_PARAM_FEATURES: + err = -EINVAL; + break; + + case RTC_PARAM_CORRECTION: + mutex_unlock(&rtc->ops_lock); + if (param.index != 0) + return -EINVAL; + return rtc_set_offset(rtc, param.svalue); + + default: + if (rtc->ops->param_set) + err = rtc->ops->param_set(rtc->dev.parent, ¶m); + else + err = -EINVAL; + } + + break; + default: /* Finally try the driver's ioctl interface */ if (ops->ioctl) { diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 9a2bd4947007..d8e835798153 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -423,6 +423,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) if (err) return err; now = rtc_tm_to_time64(&tm); + if (scheduled <= now) return -ETIME; /* @@ -447,6 +448,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { + ktime_t alarm_time; int err; if (!rtc->ops) @@ -468,7 +470,15 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) if (rtc->aie_timer.enabled) rtc_timer_remove(rtc, &rtc->aie_timer); - rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); + alarm_time = rtc_tm_to_ktime(alarm->time); + /* + * Round down so we never miss a deadline, checking for past deadline is + * done in __rtc_set_alarm + */ + if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features)) + alarm_time = ktime_sub_ns(alarm_time, (u64)alarm->time.tm_sec * NSEC_PER_SEC); + + rtc->aie_timer.node.expires = alarm_time; rtc->aie_timer.period = 0; if (alarm->enabled) err = rtc_timer_enqueue(rtc, &rtc->aie_timer); @@ -561,7 +571,8 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (rtc->uie_rtctimer.enabled == enabled) goto out; - if (rtc->uie_unsupported || !test_bit(RTC_FEATURE_ALARM, rtc->features)) { + if (!test_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features) || + !test_bit(RTC_FEATURE_ALARM, rtc->features)) { mutex_unlock(&rtc->ops_lock); #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL return rtc_dev_update_irq_enable_emul(rtc, enabled); diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c index a9b355510cd4..e188ab517f1e 100644 --- a/drivers/rtc/rtc-ab-eoz9.c +++ b/drivers/rtc/rtc-ab-eoz9.c @@ -534,7 +534,6 @@ static int abeoz9_probe(struct i2c_client *client, data->rtc->ops = &rtc_ops; data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; data->rtc->range_max = RTC_TIMESTAMP_END_2099; - data->rtc->uie_unsupported = 1; clear_bit(RTC_FEATURE_ALARM, data->rtc->features); if (client->irq > 0) { @@ -546,6 +545,8 @@ static int abeoz9_probe(struct i2c_client *client, dev_err(dev, "failed to request alarm irq\n"); return ret; } + } else { + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, data->rtc->features); } if (client->irq > 0 || device_property_read_bool(dev, "wakeup-source")) { diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index b40048871295..ea33e149d545 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -184,25 +184,9 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { int retval, i; unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; - unsigned long mins, secs = 0, cursec = 0; - struct rtc_time curtm; + unsigned long mins; - /* Get the number of seconds since 1970 */ - secs = rtc_tm_to_time64(&alarm->time); - - /* - * Check whether alarm is set less than 1min. - * Since our RTC doesn't support alarm resolution less than 1min, - * return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON - */ - ab8500_rtc_read_time(dev, &curtm); /* Read current time */ - cursec = rtc_tm_to_time64(&curtm); - if ((secs - cursec) < 59) { - dev_dbg(dev, "Alarm less than 1 minute not supported\r\n"); - return -EINVAL; - } - - mins = secs / 60; + mins = (unsigned long)rtc_tm_to_time64(&alarm->time) / 60; buf[2] = mins & 0xFF; buf[1] = (mins >> 8) & 0xFF; @@ -394,7 +378,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev) dev_pm_set_wake_irq(&pdev->dev, irq); platform_set_drvdata(pdev, rtc); - rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); rtc->range_max = (1ULL << 24) * 60 - 1; // 24-bit minutes + 59 secs rtc->start_secs = RTC_TIMESTAMP_BEGIN_2000; diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index b3de6d2e680a..2f83adef966e 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -199,11 +199,18 @@ static const struct of_device_id ds1302_dt_ids[] = { MODULE_DEVICE_TABLE(of, ds1302_dt_ids); #endif +static const struct spi_device_id ds1302_spi_ids[] = { + { .name = "ds1302", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, ds1302_spi_ids); + static struct spi_driver ds1302_driver = { .driver.name = "rtc-ds1302", .driver.of_match_table = of_match_ptr(ds1302_dt_ids), .probe = ds1302_probe, .remove = ds1302_remove, + .id_table = ds1302_spi_ids, }; module_spi_driver(ds1302_driver); diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 66fc8617d07e..93ce72b9ae59 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -219,12 +219,19 @@ static const struct of_device_id ds1390_of_match[] = { }; MODULE_DEVICE_TABLE(of, ds1390_of_match); +static const struct spi_device_id ds1390_spi_ids[] = { + { .name = "ds1390" }, + {} +}; +MODULE_DEVICE_TABLE(spi, ds1390_spi_ids); + static struct spi_driver ds1390_driver = { .driver = { .name = "rtc-ds1390", .of_match_table = of_match_ptr(ds1390_of_match), }, .probe = ds1390_probe, + .id_table = ds1390_spi_ids, }; module_spi_driver(ds1390_driver); diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index f736f8c22e96..6d383b629d20 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -557,7 +557,7 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) * registered automatically when being referenced. */ of_node_put(fixed_clock); - return 0; + return NULL; } /* First disable the clock */ diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index bad7792b6ca5..0d515b3df571 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -430,12 +430,19 @@ static const struct of_device_id mcp795_of_match[] = { MODULE_DEVICE_TABLE(of, mcp795_of_match); #endif +static const struct spi_device_id mcp795_spi_ids[] = { + { .name = "mcp795" }, + { } +}; +MODULE_DEVICE_TABLE(spi, mcp795_spi_ids); + static struct spi_driver mcp795_driver = { .driver = { .name = "rtc-mcp795", .of_match_table = of_match_ptr(mcp795_of_match), }, .probe = mcp795_probe, + .id_table = mcp795_spi_ids, }; module_spi_driver(mcp795_driver); diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c new file mode 100644 index 000000000000..f3fde013c4b8 --- /dev/null +++ b/drivers/rtc/rtc-msc313.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Real time clocks driver for MStar/SigmaStar ARMv7 SoCs. + * Based on "Real Time Clock driver for msb252x." that was contained + * in various MStar kernels. + * + * (C) 2019 Daniel Palmer + * (C) 2021 Romain Perier + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +/* Registers */ +#define REG_RTC_CTRL 0x00 +#define REG_RTC_FREQ_CW_L 0x04 +#define REG_RTC_FREQ_CW_H 0x08 +#define REG_RTC_LOAD_VAL_L 0x0C +#define REG_RTC_LOAD_VAL_H 0x10 +#define REG_RTC_MATCH_VAL_L 0x14 +#define REG_RTC_MATCH_VAL_H 0x18 +#define REG_RTC_STATUS_INT 0x1C +#define REG_RTC_CNT_VAL_L 0x20 +#define REG_RTC_CNT_VAL_H 0x24 + +/* Control bits for REG_RTC_CTRL */ +#define SOFT_RSTZ_BIT BIT(0) +#define CNT_EN_BIT BIT(1) +#define WRAP_EN_BIT BIT(2) +#define LOAD_EN_BIT BIT(3) +#define READ_EN_BIT BIT(4) +#define INT_MASK_BIT BIT(5) +#define INT_FORCE_BIT BIT(6) +#define INT_CLEAR_BIT BIT(7) + +/* Control bits for REG_RTC_STATUS_INT */ +#define RAW_INT_BIT BIT(0) +#define ALM_INT_BIT BIT(1) + +struct msc313_rtc { + struct rtc_device *rtc_dev; + void __iomem *rtc_base; +}; + +static int msc313_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + unsigned long seconds; + + seconds = readw(priv->rtc_base + REG_RTC_MATCH_VAL_L) + | ((unsigned long)readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16); + + rtc_time64_to_tm(seconds, &alarm->time); + + if (!(readw(priv->rtc_base + REG_RTC_CTRL) & INT_MASK_BIT)) + alarm->enabled = 1; + + return 0; +} + +static int msc313_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + u16 reg; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + if (enabled) + reg &= ~INT_MASK_BIT; + else + reg |= INT_MASK_BIT; + writew(reg, priv->rtc_base + REG_RTC_CTRL); + return 0; +} + +static int msc313_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + unsigned long seconds; + + seconds = rtc_tm_to_time64(&alarm->time); + writew((seconds & 0xFFFF), priv->rtc_base + REG_RTC_MATCH_VAL_L); + writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_MATCH_VAL_H); + + msc313_rtc_alarm_irq_enable(dev, alarm->enabled); + + return 0; +} + +static bool msc313_rtc_get_enabled(struct msc313_rtc *priv) +{ + return readw(priv->rtc_base + REG_RTC_CTRL) & CNT_EN_BIT; +} + +static void msc313_rtc_set_enabled(struct msc313_rtc *priv) +{ + u16 reg; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + reg |= CNT_EN_BIT; + writew(reg, priv->rtc_base + REG_RTC_CTRL); +} + +static int msc313_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + u32 seconds; + u16 reg; + + if (!msc313_rtc_get_enabled(priv)) + return -EINVAL; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + writew(reg | READ_EN_BIT, priv->rtc_base + REG_RTC_CTRL); + + /* Wait for HW latch done */ + while (readw(priv->rtc_base + REG_RTC_CTRL) & READ_EN_BIT) + udelay(1); + + seconds = readw(priv->rtc_base + REG_RTC_CNT_VAL_L) + | ((unsigned long)readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16); + + rtc_time64_to_tm(seconds, tm); + + return 0; +} + +static int msc313_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + unsigned long seconds; + u16 reg; + + seconds = rtc_tm_to_time64(tm); + writew(seconds & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_L); + writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_H); + + /* Enable load for loading value into internal RTC counter */ + reg = readw(priv->rtc_base + REG_RTC_CTRL); + writew(reg | LOAD_EN_BIT, priv->rtc_base + REG_RTC_CTRL); + + /* Wait for HW latch done */ + while (readw(priv->rtc_base + REG_RTC_CTRL) & LOAD_EN_BIT) + udelay(1); + msc313_rtc_set_enabled(priv); + return 0; +} + +static const struct rtc_class_ops msc313_rtc_ops = { + .read_time = msc313_rtc_read_time, + .set_time = msc313_rtc_set_time, + .read_alarm = msc313_rtc_read_alarm, + .set_alarm = msc313_rtc_set_alarm, + .alarm_irq_enable = msc313_rtc_alarm_irq_enable, +}; + +static irqreturn_t msc313_rtc_interrupt(s32 irq, void *dev_id) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev_id); + u16 reg; + + reg = readw(priv->rtc_base + REG_RTC_STATUS_INT); + if (!(reg & ALM_INT_BIT)) + return IRQ_NONE; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + reg |= INT_CLEAR_BIT; + reg &= ~INT_FORCE_BIT; + writew(reg, priv->rtc_base + REG_RTC_CTRL); + + rtc_update_irq(priv->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int msc313_rtc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct msc313_rtc *priv; + unsigned long rate; + struct clk *clk; + int ret; + int irq; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct msc313_rtc), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->rtc_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->rtc_base)) + return PTR_ERR(priv->rtc_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + priv->rtc_dev = devm_rtc_allocate_device(dev); + if (IS_ERR(priv->rtc_dev)) + return PTR_ERR(priv->rtc_dev); + + priv->rtc_dev->ops = &msc313_rtc_ops; + priv->rtc_dev->range_max = U32_MAX; + + ret = devm_request_irq(dev, irq, msc313_rtc_interrupt, IRQF_SHARED, + dev_name(&pdev->dev), &pdev->dev); + if (ret) { + dev_err(dev, "Could not request IRQ\n"); + return ret; + } + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "No input reference clock\n"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "Failed to enable the reference clock, %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, clk); + if (ret) + return ret; + + rate = clk_get_rate(clk); + writew(rate & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_L); + writew((rate >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_H); + + platform_set_drvdata(pdev, priv); + + return devm_rtc_register_device(priv->rtc_dev); +} + +static const struct of_device_id msc313_rtc_of_match_table[] = { + { .compatible = "mstar,msc313-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, msc313_rtc_of_match_table); + +static struct platform_driver msc313_rtc_driver = { + .probe = msc313_rtc_probe, + .driver = { + .name = "msc313-rtc", + .of_match_table = msc313_rtc_of_match_table, + }, +}; + +module_platform_driver(msc313_rtc_driver); + +MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>"); +MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>"); +MODULE_DESCRIPTION("MStar RTC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index d46e0f0cc502..4d4f3b1a7309 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -1029,6 +1029,5 @@ static struct platform_driver omap_rtc_driver = { module_platform_driver(omap_rtc_driver); -MODULE_ALIAS("platform:omap_rtc"); MODULE_AUTHOR("George G. Davis (and others)"); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 0f58cac81d8c..7473e6c8a183 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -451,12 +451,21 @@ static const struct of_device_id pcf2123_dt_ids[] = { MODULE_DEVICE_TABLE(of, pcf2123_dt_ids); #endif +static const struct spi_device_id pcf2123_spi_ids[] = { + { .name = "pcf2123", }, + { .name = "rv2123", }, + { .name = "rtc-pcf2123", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, pcf2123_spi_ids); + static struct spi_driver pcf2123_driver = { .driver = { .name = "rtc-pcf2123", .of_match_table = of_match_ptr(pcf2123_dt_ids), }, .probe = pcf2123_probe, + .id_table = pcf2123_spi_ids, }; module_spi_driver(pcf2123_driver); diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 14da4ab30104..15e50bb10cf0 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -34,6 +34,7 @@ #define PCF85063_REG_CTRL1 0x00 /* status */ #define PCF85063_REG_CTRL1_CAP_SEL BIT(0) #define PCF85063_REG_CTRL1_STOP BIT(5) +#define PCF85063_REG_CTRL1_EXT_TEST BIT(7) #define PCF85063_REG_CTRL2 0x01 #define PCF85063_CTRL2_AF BIT(6) @@ -117,6 +118,7 @@ static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm) * reset state until all time/date registers are written */ rc = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1, + PCF85063_REG_CTRL1_EXT_TEST | PCF85063_REG_CTRL1_STOP, PCF85063_REG_CTRL1_STOP); if (rc) @@ -297,7 +299,7 @@ static int pcf85063_ioctl(struct device *dev, unsigned int cmd, if (ret < 0) return ret; - status = status & PCF85063_REG_SC_OS ? RTC_VL_DATA_INVALID : 0; + status = (status & PCF85063_REG_SC_OS) ? RTC_VL_DATA_INVALID : 0; return put_user(status, (unsigned int __user *)arg); @@ -479,6 +481,18 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) struct clk *clk; struct clk_init_data init; struct device_node *node = pcf85063->rtc->dev.parent->of_node; + struct device_node *fixed_clock; + + fixed_clock = of_get_child_by_name(node, "clock"); + if (fixed_clock) { + /* + * skip registering square wave clock when a fixed + * clock has been registered. The fixed clock is + * registered automatically when being referenced. + */ + of_node_put(fixed_clock); + return NULL; + } init.name = "pcf85063-clkout"; init.ops = &pcf85063_clkout_ops; diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 8b6fb20774bf..c93acade7205 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -4,8 +4,10 @@ */ #include <linux/bcd.h> +#include <linux/bitfield.h> #include <linux/i2c.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/rtc.h> #include <linux/of.h> #include <linux/pm_wakeirq.h> @@ -19,11 +21,10 @@ #define PCF8523_CONTROL2_AF BIT(3) #define PCF8523_REG_CONTROL3 0x02 -#define PCF8523_CONTROL3_PM_BLD BIT(7) /* battery low detection disabled */ -#define PCF8523_CONTROL3_PM_VDD BIT(6) /* switch-over disabled */ -#define PCF8523_CONTROL3_PM_DSM BIT(5) /* direct switching mode */ -#define PCF8523_CONTROL3_PM_MASK 0xe0 +#define PCF8523_CONTROL3_PM GENMASK(7,5) +#define PCF8523_PM_STANDBY 0x7 #define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */ +#define PCF8523_CONTROL3_BSF BIT(3) #define PCF8523_REG_SECONDS 0x03 #define PCF8523_SECONDS_OS BIT(7) @@ -48,127 +49,45 @@ struct pcf8523 { struct rtc_device *rtc; - struct i2c_client *client; + struct regmap *regmap; }; -static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep) +static int pcf8523_load_capacitance(struct pcf8523 *pcf8523, struct device_node *node) { - struct i2c_msg msgs[2]; - u8 value = 0; - int err; - - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = sizeof(reg); - msgs[0].buf = ® - - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(value); - msgs[1].buf = &value; - - err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (err < 0) - return err; - - *valuep = value; - - return 0; -} - -static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) -{ - u8 buffer[2] = { reg, value }; - struct i2c_msg msg; - int err; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = sizeof(buffer); - msg.buf = buffer; - - err = i2c_transfer(client->adapter, &msg, 1); - if (err < 0) - return err; - - return 0; -} - -static int pcf8523_voltage_low(struct i2c_client *client) -{ - u8 value; - int err; - - err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value); - if (err < 0) - return err; - - return !!(value & PCF8523_CONTROL3_BLF); -} - -static int pcf8523_load_capacitance(struct i2c_client *client) -{ - u32 load; - u8 value; - int err; - - err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); - if (err < 0) - return err; + u32 load, value = 0; load = 12500; - of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads", - &load); + of_property_read_u32(node, "quartz-load-femtofarads", &load); switch (load) { default: - dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500", + dev_warn(&pcf8523->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500", load); fallthrough; case 12500: value |= PCF8523_CONTROL1_CAP_SEL; break; case 7000: - value &= ~PCF8523_CONTROL1_CAP_SEL; break; } - err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); - - return err; -} - -static int pcf8523_set_pm(struct i2c_client *client, u8 pm) -{ - u8 value; - int err; - - err = pcf8523_read(client, PCF8523_REG_CONTROL3, &value); - if (err < 0) - return err; - - value = (value & ~PCF8523_CONTROL3_PM_MASK) | pm; - - err = pcf8523_write(client, PCF8523_REG_CONTROL3, value); - if (err < 0) - return err; - - return 0; + return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, + PCF8523_CONTROL1_CAP_SEL, value); } static irqreturn_t pcf8523_irq(int irq, void *dev_id) { - struct pcf8523 *pcf8523 = i2c_get_clientdata(dev_id); - u8 value; + struct pcf8523 *pcf8523 = dev_id; + u32 value; int err; - err = pcf8523_read(pcf8523->client, PCF8523_REG_CONTROL2, &value); + err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL2, &value); if (err < 0) return IRQ_HANDLED; if (value & PCF8523_CONTROL2_AF) { value &= ~PCF8523_CONTROL2_AF; - pcf8523_write(pcf8523->client, PCF8523_REG_CONTROL2, value); + regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL2, value); rtc_update_irq(pcf8523->rtc, 1, RTC_IRQF | RTC_AF); return IRQ_HANDLED; @@ -177,68 +96,14 @@ static irqreturn_t pcf8523_irq(int irq, void *dev_id) return IRQ_NONE; } -static int pcf8523_stop_rtc(struct i2c_client *client) -{ - u8 value; - int err; - - err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); - if (err < 0) - return err; - - value |= PCF8523_CONTROL1_STOP; - - err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); - if (err < 0) - return err; - - return 0; -} - -static int pcf8523_start_rtc(struct i2c_client *client) -{ - u8 value; - int err; - - err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); - if (err < 0) - return err; - - value &= ~PCF8523_CONTROL1_STOP; - - err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); - if (err < 0) - return err; - - return 0; -} - static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); - u8 start = PCF8523_REG_SECONDS, regs[7]; - struct i2c_msg msgs[2]; + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + u8 regs[7]; int err; - err = pcf8523_voltage_low(client); - if (err < 0) { - return err; - } else if (err > 0) { - dev_err(dev, "low voltage detected, time is unreliable\n"); - return -EINVAL; - } - - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = 1; - msgs[0].buf = &start; - - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(regs); - msgs[1].buf = regs; - - err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_SECONDS, regs, + sizeof(regs)); if (err < 0) return err; @@ -258,63 +123,50 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_msg msg; - u8 regs[8]; + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + u8 regs[7]; int err; - err = pcf8523_stop_rtc(client); + err = regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, + PCF8523_CONTROL1_STOP, PCF8523_CONTROL1_STOP); if (err < 0) return err; - regs[0] = PCF8523_REG_SECONDS; /* This will purposely overwrite PCF8523_SECONDS_OS */ - regs[1] = bin2bcd(tm->tm_sec); - regs[2] = bin2bcd(tm->tm_min); - regs[3] = bin2bcd(tm->tm_hour); - regs[4] = bin2bcd(tm->tm_mday); - regs[5] = tm->tm_wday; - regs[6] = bin2bcd(tm->tm_mon + 1); - regs[7] = bin2bcd(tm->tm_year - 100); - - msg.addr = client->addr; - msg.flags = 0; - msg.len = sizeof(regs); - msg.buf = regs; - - err = i2c_transfer(client->adapter, &msg, 1); + regs[0] = bin2bcd(tm->tm_sec); + regs[1] = bin2bcd(tm->tm_min); + regs[2] = bin2bcd(tm->tm_hour); + regs[3] = bin2bcd(tm->tm_mday); + regs[4] = tm->tm_wday; + regs[5] = bin2bcd(tm->tm_mon + 1); + regs[6] = bin2bcd(tm->tm_year - 100); + + err = regmap_bulk_write(pcf8523->regmap, PCF8523_REG_SECONDS, regs, + sizeof(regs)); if (err < 0) { /* * If the time cannot be set, restart the RTC anyway. Note * that errors are ignored if the RTC cannot be started so * that we have a chance to propagate the original error. */ - pcf8523_start_rtc(client); + regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, + PCF8523_CONTROL1_STOP, 0); return err; } - return pcf8523_start_rtc(client); + return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, + PCF8523_CONTROL1_STOP, 0); } static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) { - struct i2c_client *client = to_i2c_client(dev); - u8 start = PCF8523_REG_MINUTE_ALARM, regs[4]; - struct i2c_msg msgs[2]; - u8 value; + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + u8 regs[4]; + u32 value; int err; - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = 1; - msgs[0].buf = &start; - - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = sizeof(regs); - msgs[1].buf = regs; - - err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_MINUTE_ALARM, regs, + sizeof(regs)); if (err < 0) return err; @@ -324,12 +176,12 @@ static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) tm->time.tm_mday = bcd2bin(regs[2] & 0x3F); tm->time.tm_wday = bcd2bin(regs[3] & 0x7); - err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); + err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL1, &value); if (err < 0) return err; tm->enabled = !!(value & PCF8523_CONTROL1_AIE); - err = pcf8523_read(client, PCF8523_REG_CONTROL2, &value); + err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL2, &value); if (err < 0) return err; tm->pending = !!(value & PCF8523_CONTROL2_AF); @@ -339,30 +191,16 @@ static int pcf8523_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) static int pcf8523_irq_enable(struct device *dev, unsigned int enabled) { - struct i2c_client *client = to_i2c_client(dev); - u8 value; - int err; - - err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); - if (err < 0) - return err; - - value &= PCF8523_CONTROL1_AIE; + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); - if (enabled) - value |= PCF8523_CONTROL1_AIE; - - err = pcf8523_write(client, PCF8523_REG_CONTROL1, value); - if (err < 0) - return err; - - return 0; + return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL1, + PCF8523_CONTROL1_AIE, enabled ? + PCF8523_CONTROL1_AIE : 0); } static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_msg msg; + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); u8 regs[5]; int err; @@ -370,7 +208,7 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) if (err) return err; - err = pcf8523_write(client, PCF8523_REG_CONTROL2, 0); + err = regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL2, 0); if (err < 0) return err; @@ -382,16 +220,13 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) rtc_time64_to_tm(alarm_time, &tm->time); } - regs[0] = PCF8523_REG_MINUTE_ALARM; - regs[1] = bin2bcd(tm->time.tm_min); - regs[2] = bin2bcd(tm->time.tm_hour); - regs[3] = bin2bcd(tm->time.tm_mday); - regs[4] = ALARM_DIS; - msg.addr = client->addr; - msg.flags = 0; - msg.len = sizeof(regs); - msg.buf = regs; - err = i2c_transfer(client->adapter, &msg, 1); + regs[0] = bin2bcd(tm->time.tm_min); + regs[1] = bin2bcd(tm->time.tm_hour); + regs[2] = bin2bcd(tm->time.tm_mday); + regs[3] = ALARM_DIS; + + err = regmap_bulk_write(pcf8523->regmap, PCF8523_REG_MINUTE_ALARM, regs, + sizeof(regs)); if (err < 0) return err; @@ -401,24 +236,101 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) return 0; } -#ifdef CONFIG_RTC_INTF_DEV +static int pcf8523_param_get(struct device *dev, struct rtc_param *param) +{ + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + int ret; + + switch(param->param) { + u32 value; + + case RTC_PARAM_BACKUP_SWITCH_MODE: + ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); + if (ret < 0) + return ret; + + value = FIELD_GET(PCF8523_CONTROL3_PM, value); + + switch(value) { + case 0x0: + case 0x4: + param->uvalue = RTC_BSM_LEVEL; + break; + case 0x1: + case 0x5: + param->uvalue = RTC_BSM_DIRECT; + break; + case PCF8523_PM_STANDBY: + param->uvalue = RTC_BSM_STANDBY; + break; + default: + param->uvalue = RTC_BSM_DISABLED; + } + + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int pcf8523_param_set(struct device *dev, struct rtc_param *param) +{ + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + + switch(param->param) { + u8 mode; + case RTC_PARAM_BACKUP_SWITCH_MODE: + switch (param->uvalue) { + case RTC_BSM_DISABLED: + mode = 0x2; + break; + case RTC_BSM_DIRECT: + mode = 0x1; + break; + case RTC_BSM_LEVEL: + mode = 0x0; + break; + case RTC_BSM_STANDBY: + mode = PCF8523_PM_STANDBY; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL3, + PCF8523_CONTROL3_PM, + FIELD_PREP(PCF8523_CONTROL3_PM, mode)); + + break; + + default: + return -EINVAL; + } + + return 0; +} + static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); unsigned int flags = 0; - u8 value; + u32 value; int ret; switch (cmd) { case RTC_VL_READ: - ret = pcf8523_voltage_low(client); + ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); if (ret < 0) return ret; - if (ret) + + if (value & PCF8523_CONTROL3_BLF) flags |= RTC_VL_BACKUP_LOW; - ret = pcf8523_read(client, PCF8523_REG_SECONDS, &value); + ret = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, &value); if (ret < 0) return ret; @@ -431,18 +343,15 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, return -ENOIOCTLCMD; } } -#else -#define pcf8523_rtc_ioctl NULL -#endif static int pcf8523_rtc_read_offset(struct device *dev, long *offset) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); int err; - u8 value; + u32 value; s8 val; - err = pcf8523_read(client, PCF8523_REG_OFFSET, &value); + err = regmap_read(pcf8523->regmap, PCF8523_REG_OFFSET, &value); if (err < 0) return err; @@ -455,9 +364,9 @@ static int pcf8523_rtc_read_offset(struct device *dev, long *offset) static int pcf8523_rtc_set_offset(struct device *dev, long offset) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); long reg_m0, reg_m1; - u8 value; + u32 value; reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L); reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L); @@ -467,7 +376,7 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset) else value = (reg_m1 & 0x7f) | PCF8523_OFFSET_MODE; - return pcf8523_write(client, PCF8523_REG_OFFSET, value); + return regmap_write(pcf8523->regmap, PCF8523_REG_OFFSET, value); } static const struct rtc_class_ops pcf8523_rtc_ops = { @@ -479,6 +388,14 @@ static const struct rtc_class_ops pcf8523_rtc_ops = { .ioctl = pcf8523_rtc_ioctl, .read_offset = pcf8523_rtc_read_offset, .set_offset = pcf8523_rtc_set_offset, + .param_get = pcf8523_param_get, + .param_set = pcf8523_param_set, +}; + +static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x13, }; static int pcf8523_probe(struct i2c_client *client, @@ -487,6 +404,7 @@ static int pcf8523_probe(struct i2c_client *client, struct pcf8523 *pcf8523; struct rtc_device *rtc; bool wakeup_source = false; + u32 value; int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) @@ -496,46 +414,60 @@ static int pcf8523_probe(struct i2c_client *client, if (!pcf8523) return -ENOMEM; + pcf8523->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(pcf8523->regmap)) + return PTR_ERR(pcf8523->regmap); + i2c_set_clientdata(client, pcf8523); - pcf8523->client = client; - err = pcf8523_load_capacitance(client); + rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + pcf8523->rtc = rtc; + + err = pcf8523_load_capacitance(pcf8523, client->dev.of_node); if (err < 0) dev_warn(&client->dev, "failed to set xtal load capacitance: %d", err); - err = pcf8523_set_pm(client, 0); + err = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, &value); if (err < 0) return err; - rtc = devm_rtc_allocate_device(&client->dev); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (value & PCF8523_SECONDS_OS) { + err = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); + if (err < 0) + return err; + + if (FIELD_GET(PCF8523_CONTROL3_PM, value) == PCF8523_PM_STANDBY) { + err = regmap_write(pcf8523->regmap, PCF8523_REG_CONTROL3, + value & ~PCF8523_CONTROL3_PM); + if (err < 0) + return err; + } + } - pcf8523->rtc = rtc; rtc->ops = &pcf8523_rtc_ops; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_max = RTC_TIMESTAMP_END_2099; rtc->uie_unsupported = 1; if (client->irq > 0) { - err = pcf8523_write(client, PCF8523_TMR_CLKOUT_CTRL, 0x38); + err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38); if (err < 0) return err; err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8523_irq, IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, - dev_name(&rtc->dev), client); + dev_name(&rtc->dev), pcf8523); if (err) return err; dev_pm_set_wake_irq(&client->dev, client->irq); } -#ifdef CONFIG_OF wakeup_source = of_property_read_bool(client->dev.of_node, "wakeup-source"); -#endif if (client->irq > 0 || wakeup_source) device_init_wakeup(&client->dev, true); @@ -548,19 +480,17 @@ static const struct i2c_device_id pcf8523_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcf8523_id); -#ifdef CONFIG_OF static const struct of_device_id pcf8523_of_match[] = { { .compatible = "nxp,pcf8523" }, { .compatible = "microcrystal,rv8523" }, { } }; MODULE_DEVICE_TABLE(of, pcf8523_of_match); -#endif static struct i2c_driver pcf8523_driver = { .driver = { .name = "rtc-pcf8523", - .of_match_table = of_match_ptr(pcf8523_of_match), + .of_match_table = pcf8523_of_match, }, .probe = pcf8523_probe, .id_table = pcf8523_id, diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 12c807306893..cdc623b3e365 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -10,6 +10,7 @@ #include <linux/clk-provider.h> #include <linux/bcd.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -80,6 +81,10 @@ #define RV3028_BACKUP_TCE BIT(5) #define RV3028_BACKUP_TCR_MASK GENMASK(1,0) +#define RV3028_BACKUP_BSM GENMASK(3,2) + +#define RV3028_BACKUP_BSM_DSM 0x1 +#define RV3028_BACKUP_BSM_LSM 0x3 #define OFFSET_STEP_PPT 953674 @@ -512,6 +517,71 @@ exit_eerd: } +static int rv3028_param_get(struct device *dev, struct rtc_param *param) +{ + struct rv3028_data *rv3028 = dev_get_drvdata(dev); + int ret; + + switch(param->param) { + u32 value; + + case RTC_PARAM_BACKUP_SWITCH_MODE: + ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value); + if (ret < 0) + return ret; + + value = FIELD_GET(RV3028_BACKUP_BSM, value); + + switch(value) { + case RV3028_BACKUP_BSM_DSM: + param->uvalue = RTC_BSM_DIRECT; + break; + case RV3028_BACKUP_BSM_LSM: + param->uvalue = RTC_BSM_LEVEL; + break; + default: + param->uvalue = RTC_BSM_DISABLED; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int rv3028_param_set(struct device *dev, struct rtc_param *param) +{ + struct rv3028_data *rv3028 = dev_get_drvdata(dev); + + switch(param->param) { + u8 mode; + case RTC_PARAM_BACKUP_SWITCH_MODE: + switch (param->uvalue) { + case RTC_BSM_DISABLED: + mode = 0; + break; + case RTC_BSM_DIRECT: + mode = RV3028_BACKUP_BSM_DSM; + break; + case RTC_BSM_LEVEL: + mode = RV3028_BACKUP_BSM_LSM; + break; + default: + return -EINVAL; + } + + return rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_BSM, + FIELD_PREP(RV3028_BACKUP_BSM, mode)); + + default: + return -EINVAL; + } + + return 0; +} + static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct rv3028_data *rv3028 = dev_get_drvdata(dev); @@ -776,6 +846,8 @@ static const struct rtc_class_ops rv3028_rtc_ops = { .read_offset = rv3028_read_offset, .set_offset = rv3028_set_offset, .ioctl = rv3028_ioctl, + .param_get = rv3028_param_get, + .param_set = rv3028_param_set, }; static const struct regmap_config regmap_config = { @@ -878,6 +950,8 @@ static int rv3028_probe(struct i2c_client *client) if (ret) return ret; + set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3028->rtc->features); + rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099; rv3028->rtc->ops = &rv3028_rtc_ops; diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index d63102d5cb1e..c3bee305eacc 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -106,6 +106,7 @@ struct rv3032_data { struct regmap *regmap; struct rtc_device *rtc; + bool trickle_charger_set; #ifdef CONFIG_COMMON_CLK struct clk_hw clkout_hw; #endif @@ -310,14 +311,6 @@ static int rv3032_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) u8 ctrl = 0; int ret; - /* The alarm has no seconds, round up to nearest minute */ - if (alrm->time.tm_sec) { - time64_t alarm_time = rtc_tm_to_time64(&alrm->time); - - alarm_time += 60 - alrm->time.tm_sec; - rtc_time64_to_tm(alarm_time, &alrm->time); - } - ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL2, RV3032_CTRL2_AIE | RV3032_CTRL2_UIE, 0); if (ret) @@ -402,6 +395,75 @@ static int rv3032_set_offset(struct device *dev, long offset) FIELD_PREP(RV3032_OFFSET_MSK, offset)); } +static int rv3032_param_get(struct device *dev, struct rtc_param *param) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + int ret; + + switch(param->param) { + u32 value; + + case RTC_PARAM_BACKUP_SWITCH_MODE: + ret = regmap_read(rv3032->regmap, RV3032_PMU, &value); + if (ret < 0) + return ret; + + value = FIELD_GET(RV3032_PMU_BSM, value); + + switch(value) { + case RV3032_PMU_BSM_DSM: + param->uvalue = RTC_BSM_DIRECT; + break; + case RV3032_PMU_BSM_LSM: + param->uvalue = RTC_BSM_LEVEL; + break; + default: + param->uvalue = RTC_BSM_DISABLED; + } + + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int rv3032_param_set(struct device *dev, struct rtc_param *param) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + + switch(param->param) { + u8 mode; + case RTC_PARAM_BACKUP_SWITCH_MODE: + if (rv3032->trickle_charger_set) + return -EINVAL; + + switch (param->uvalue) { + case RTC_BSM_DISABLED: + mode = 0; + break; + case RTC_BSM_DIRECT: + mode = RV3032_PMU_BSM_DSM; + break; + case RTC_BSM_LEVEL: + mode = RV3032_PMU_BSM_LSM; + break; + default: + return -EINVAL; + } + + return rv3032_update_cfg(rv3032, RV3032_PMU, RV3032_PMU_BSM, + FIELD_PREP(RV3032_PMU_BSM, mode)); + + default: + return -EINVAL; + } + + return 0; +} + static int rv3032_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct rv3032_data *rv3032 = dev_get_drvdata(dev); @@ -541,6 +603,8 @@ static int rv3032_trickle_charger_setup(struct device *dev, struct rv3032_data * return 0; } + rv3032->trickle_charger_set = true; + return rv3032_update_cfg(rv3032, RV3032_PMU, RV3032_PMU_TCR | RV3032_PMU_TCM | RV3032_PMU_BSM, val | FIELD_PREP(RV3032_PMU_TCR, i)); @@ -617,11 +681,11 @@ static int rv3032_clkout_set_rate(struct clk_hw *hw, unsigned long rate, ret = rv3032_enter_eerd(rv3032, &eerd); if (ret) - goto exit_eerd; + return ret; ret = regmap_write(rv3032->regmap, RV3032_CLKOUT1, hfd & 0xff); if (ret) - return ret; + goto exit_eerd; ret = regmap_write(rv3032->regmap, RV3032_CLKOUT2, RV3032_CLKOUT2_OS | FIELD_PREP(RV3032_CLKOUT2_HFD_MSK, hfd >> 8)); @@ -813,6 +877,8 @@ static const struct rtc_class_ops rv3032_rtc_ops = { .read_alarm = rv3032_get_alarm, .set_alarm = rv3032_set_alarm, .alarm_irq_enable = rv3032_alarm_irq_enable, + .param_get = rv3032_param_get, + .param_set = rv3032_param_set, }; static const struct regmap_config regmap_config = { @@ -883,6 +949,9 @@ static int rv3032_probe(struct i2c_client *client) rv3032_trickle_charger_setup(&client->dev, rv3032); + set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3032->rtc->features); + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rv3032->rtc->features); + rv3032->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rv3032->rtc->range_max = RTC_TIMESTAMP_END_2099; rv3032->rtc->ops = &rv3032_rtc_ops; diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 72adef5a5ebe..0d5ed38bf60c 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -340,8 +340,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) } } - ctrl[1] &= ~RV8803_FLAG_AF; - err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[1]); + ctrl[0] &= ~RV8803_FLAG_AF; + err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[0]); mutex_unlock(&rv8803->flags_lock); if (err) return err; diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index f4d425002f7f..758fd6e11a15 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -422,7 +422,7 @@ static struct regmap_config regmap_i2c_config = { static int rx6110_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct rx6110_data *rx6110; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index d38aaf08108c..5bfdd34a72ff 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -248,9 +248,6 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) u8 date[7]; int ret; - if ((dt->tm_year < 100) || (dt->tm_year > 199)) - return -EINVAL; - /* * Here the read-only bits are written as "0". I'm not sure if that * is sound. @@ -318,9 +315,6 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) u8 ald[2]; int ctrl2, err; - if (client->irq <= 0) - return -EINVAL; - err = rx8025_read_regs(client, RX8025_REG_ALDMIN, 2, ald); if (err) return err; @@ -355,20 +349,6 @@ static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t) u8 ald[2]; int err; - if (client->irq <= 0) - return -EINVAL; - - /* - * Hardware alarm precision is 1 minute! - * round up to nearest minute - */ - if (t->time.tm_sec) { - time64_t alarm_time = rtc_tm_to_time64(&t->time); - - alarm_time += 60 - t->time.tm_sec; - rtc_time64_to_tm(alarm_time, &t->time); - } - ald[0] = bin2bcd(t->time.tm_min); if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) ald[1] = bin2bcd(t->time.tm_hour); @@ -423,17 +403,7 @@ static int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static const struct rtc_class_ops rx8025_rtc_ops = { - .read_time = rx8025_get_time, - .set_time = rx8025_set_time, - .read_alarm = rx8025_read_alarm, - .set_alarm = rx8025_set_alarm, - .alarm_irq_enable = rx8025_alarm_irq_enable, -}; - /* - * Clock precision adjustment support - * * According to the RX8025 SA/NB application manual the frequency and * temperature characteristics can be approximated using the following * equation: @@ -444,11 +414,8 @@ static const struct rtc_class_ops rx8025_rtc_ops = { * a : Coefficient = (-35 +-5) * 10**-9 * ut: Ultimate temperature in degree = +25 +-5 degree * t : Any temperature in degree - * - * Note that the clock adjustment in ppb must be entered (which is - * the negative value of the deviation). */ -static int rx8025_get_clock_adjust(struct device *dev, int *adj) +static int rx8025_read_offset(struct device *dev, long *offset) { struct i2c_client *client = to_i2c_client(dev); int digoff; @@ -457,63 +424,75 @@ static int rx8025_get_clock_adjust(struct device *dev, int *adj) if (digoff < 0) return digoff; - *adj = digoff >= 64 ? digoff - 128 : digoff; - if (*adj > 0) - (*adj)--; - *adj *= -RX8025_ADJ_RESOLUTION; + *offset = digoff >= 64 ? digoff - 128 : digoff; + if (*offset > 0) + (*offset)--; + *offset *= RX8025_ADJ_RESOLUTION; return 0; } -static int rx8025_set_clock_adjust(struct device *dev, int adj) +static int rx8025_set_offset(struct device *dev, long offset) { struct i2c_client *client = to_i2c_client(dev); u8 digoff; int err; - adj /= -RX8025_ADJ_RESOLUTION; - if (adj > RX8025_ADJ_DATA_MAX) - adj = RX8025_ADJ_DATA_MAX; - else if (adj < RX8025_ADJ_DATA_MIN) - adj = RX8025_ADJ_DATA_MIN; - else if (adj > 0) - adj++; - else if (adj < 0) - adj += 128; - digoff = adj; + offset /= RX8025_ADJ_RESOLUTION; + if (offset > RX8025_ADJ_DATA_MAX) + offset = RX8025_ADJ_DATA_MAX; + else if (offset < RX8025_ADJ_DATA_MIN) + offset = RX8025_ADJ_DATA_MIN; + else if (offset > 0) + offset++; + else if (offset < 0) + offset += 128; + digoff = offset; err = rx8025_write_reg(client, RX8025_REG_DIGOFF, digoff); if (err) return err; - dev_dbg(dev, "%s: write 0x%02x\n", __func__, digoff); - return 0; } +static const struct rtc_class_ops rx8025_rtc_ops = { + .read_time = rx8025_get_time, + .set_time = rx8025_set_time, + .read_alarm = rx8025_read_alarm, + .set_alarm = rx8025_set_alarm, + .alarm_irq_enable = rx8025_alarm_irq_enable, + .read_offset = rx8025_read_offset, + .set_offset = rx8025_set_offset, +}; + static ssize_t rx8025_sysfs_show_clock_adjust(struct device *dev, struct device_attribute *attr, char *buf) { - int err, adj; + long adj; + int err; - err = rx8025_get_clock_adjust(dev, &adj); + dev_warn_once(dev, "clock_adjust_ppb is deprecated, use offset\n"); + err = rx8025_read_offset(dev, &adj); if (err) return err; - return sprintf(buf, "%d\n", adj); + return sprintf(buf, "%ld\n", -adj); } static ssize_t rx8025_sysfs_store_clock_adjust(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int adj, err; + long adj; + int err; - if (sscanf(buf, "%i", &adj) != 1) + dev_warn_once(dev, "clock_adjust_ppb is deprecated, use offset\n"); + if (kstrtol(buf, 10, &adj) != 0) return -EINVAL; - err = rx8025_set_clock_adjust(dev, adj); + err = rx8025_set_offset(dev, -adj); return err ? err : count; } @@ -522,15 +501,14 @@ static DEVICE_ATTR(clock_adjust_ppb, S_IRUGO | S_IWUSR, rx8025_sysfs_show_clock_adjust, rx8025_sysfs_store_clock_adjust); -static int rx8025_sysfs_register(struct device *dev) -{ - return device_create_file(dev, &dev_attr_clock_adjust_ppb); -} +static struct attribute *rx8025_attrs[] = { + &dev_attr_clock_adjust_ppb.attr, + NULL +}; -static void rx8025_sysfs_unregister(struct device *dev) -{ - device_remove_file(dev, &dev_attr_clock_adjust_ppb); -} +static const struct attribute_group rx8025_attr_group = { + .attrs = rx8025_attrs, +}; static int rx8025_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -559,12 +537,13 @@ static int rx8025_probe(struct i2c_client *client, if (err) return err; - rx8025->rtc = devm_rtc_device_register(&client->dev, client->name, - &rx8025_rtc_ops, THIS_MODULE); - if (IS_ERR(rx8025->rtc)) { - dev_err(&client->dev, "unable to register the class device\n"); + rx8025->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(rx8025->rtc)) return PTR_ERR(rx8025->rtc); - } + + rx8025->rtc->ops = &rx8025_rtc_ops; + rx8025->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900; + rx8025->rtc->range_max = RTC_TIMESTAMP_END_2099; if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); @@ -572,25 +551,20 @@ static int rx8025_probe(struct i2c_client *client, rx8025_handle_irq, IRQF_ONESHOT, "rx8025", client); - if (err) { - dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); - client->irq = 0; - } + if (err) + clear_bit(RTC_FEATURE_ALARM, rx8025->rtc->features); } rx8025->rtc->max_user_freq = 1; - /* the rx8025 alarm only supports a minute accuracy */ - rx8025->rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rx8025->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rx8025->rtc->features); - err = rx8025_sysfs_register(&client->dev); - return err; -} + err = rtc_add_group(rx8025->rtc, &rx8025_attr_group); + if (err) + return err; -static int rx8025_remove(struct i2c_client *client) -{ - rx8025_sysfs_unregister(&client->dev); - return 0; + return devm_rtc_register_device(rx8025->rtc); } static struct i2c_driver rx8025_driver = { @@ -598,7 +572,6 @@ static struct i2c_driver rx8025_driver = { .name = "rtc-rx8025", }, .probe = rx8025_probe, - .remove = rx8025_remove, .id_table = rx8025_id, }; diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index b5bdeda7d767..26278c770731 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -285,9 +285,6 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday, alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday); - if (alm->time.tm_sec != 0) - dev_warn(&client->dev, "Alarms are only supported on a per minute basis!\n"); - /* disable interrupt (which deasserts the irq line) */ err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); if (err < 0) @@ -491,8 +488,8 @@ static int s35390a_probe(struct i2c_client *client, s35390a->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; s35390a->rtc->range_max = RTC_TIMESTAMP_END_2099; - /* supports per-minute alarms only, therefore set uie_unsupported */ - s35390a->rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, s35390a->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, s35390a->rtc->features ); if (status1 & S35390A_FLAG_INT2) rtc_update_irq(s35390a->rtc, 1, RTC_AF); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e57d3ca70a78..db529733c9c4 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -127,10 +127,9 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) return ret; } -/* Time read/write */ -static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +/* Read time from RTC and convert it from BCD */ +static int s3c_rtc_read_time(struct s3c_rtc *info, struct rtc_time *tm) { - struct s3c_rtc *info = dev_get_drvdata(dev); unsigned int have_retried = 0; int ret; @@ -139,54 +138,40 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) return ret; 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); - rtc_tm->tm_mon = readb(info->base + S3C2410_RTCMON); - rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR); - rtc_tm->tm_sec = readb(info->base + S3C2410_RTCSEC); - - /* the only way to work out whether the system was mid-update + tm->tm_min = readb(info->base + S3C2410_RTCMIN); + tm->tm_hour = readb(info->base + S3C2410_RTCHOUR); + tm->tm_mday = readb(info->base + S3C2410_RTCDATE); + tm->tm_mon = readb(info->base + S3C2410_RTCMON); + tm->tm_year = readb(info->base + S3C2410_RTCYEAR); + tm->tm_sec = readb(info->base + S3C2410_RTCSEC); + + /* + * The only way to work out whether the system was mid-update * when we read it is to check the second counter, and if it * is zero, then we re-try the entire read */ - - if (rtc_tm->tm_sec == 0 && !have_retried) { + if (tm->tm_sec == 0 && !have_retried) { have_retried = 1; goto retry_get_time; } - rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); - rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); - rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); - rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); - rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); - rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); - s3c_rtc_disable_clk(info); - rtc_tm->tm_year += 100; - rtc_tm->tm_mon -= 1; + tm->tm_sec = bcd2bin(tm->tm_sec); + tm->tm_min = bcd2bin(tm->tm_min); + tm->tm_hour = bcd2bin(tm->tm_hour); + tm->tm_mday = bcd2bin(tm->tm_mday); + tm->tm_mon = bcd2bin(tm->tm_mon); + tm->tm_year = bcd2bin(tm->tm_year); - dev_dbg(dev, "read time %ptR\n", rtc_tm); return 0; } -static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) +/* Convert time to BCD and write it to RTC */ +static int s3c_rtc_write_time(struct s3c_rtc *info, const 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 %ptR\n", tm); - - /* we get around y2k by simply not supporting it */ - - if (year < 0 || year >= 100) { - dev_err(dev, "rtc only supports 100 years\n"); - return -EINVAL; - } - ret = s3c_rtc_enable_clk(info); if (ret) return ret; @@ -195,14 +180,48 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR); writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE); - writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON); - writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR); + writeb(bin2bcd(tm->tm_mon), info->base + S3C2410_RTCMON); + writeb(bin2bcd(tm->tm_year), info->base + S3C2410_RTCYEAR); s3c_rtc_disable_clk(info); return 0; } +static int s3c_rtc_gettime(struct device *dev, struct rtc_time *tm) +{ + struct s3c_rtc *info = dev_get_drvdata(dev); + int ret; + + ret = s3c_rtc_read_time(info, tm); + if (ret) + return ret; + + /* Convert internal representation to actual date/time */ + tm->tm_year += 100; + tm->tm_mon -= 1; + + dev_dbg(dev, "read time %ptR\n", tm); + return 0; +} + +static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + struct s3c_rtc *info = dev_get_drvdata(dev); + struct rtc_time rtc_tm = *tm; + + dev_dbg(dev, "set time %ptR\n", tm); + + /* + * Convert actual date/time to internal representation. + * We get around Y2K by simply not supporting it. + */ + rtc_tm.tm_year -= 100; + rtc_tm.tm_mon += 1; + + return s3c_rtc_write_time(info, &rtc_tm); +} + static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s3c_rtc *info = dev_get_drvdata(dev); @@ -447,15 +466,20 @@ static int s3c_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - /* register RTC and exit */ - info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops, - THIS_MODULE); + info->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(info->rtc)) { - dev_err(&pdev->dev, "cannot attach rtc\n"); ret = PTR_ERR(info->rtc); goto err_nortc; } + info->rtc->ops = &s3c_rtcops; + info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc->range_max = RTC_TIMESTAMP_END_2099; + + ret = devm_rtc_register_device(info->rtc); + if (ret) + goto err_nortc; + ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq, 0, "s3c2410-rtc alarm", info); if (ret) { diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index fb9c6b709e13..4243fe6d3842 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -861,4 +861,3 @@ module_platform_driver(s5m_rtc_driver); MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s5m-rtc"); diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index adec1b14a8de..711832c758ae 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -673,8 +673,17 @@ static int sun6i_rtc_probe(struct platform_device *pdev) struct sun6i_rtc_dev *chip = sun6i_rtc; int ret; - if (!chip) - return -ENODEV; + if (!chip) { + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + spin_lock_init(&chip->lock); + + chip->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + } platform_set_drvdata(pdev, chip); diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c deleted file mode 100644 index c77b8eab94a0..000000000000 --- a/drivers/rtc/rtc-tps80031.c +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver - * - * RTC driver for TI TPS80031/TPS80032 Fully Integrated - * Power Management with Power Path and Battery Charger - * - * Copyright (c) 2012, NVIDIA Corporation. - * - * Author: Laxman Dewangan <ldewangan@nvidia.com> - */ - -#include <linux/bcd.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mfd/tps80031.h> -#include <linux/platform_device.h> -#include <linux/pm.h> -#include <linux/rtc.h> -#include <linux/slab.h> - -#define ENABLE_ALARM_INT 0x08 -#define ALARM_INT_STATUS 0x40 - -/** - * Setting bit to 1 in STOP_RTC will run the RTC and - * setting this bit to 0 will freeze RTC. - */ -#define STOP_RTC 0x1 - -/* Power on reset Values of RTC registers */ -#define TPS80031_RTC_POR_YEAR 0 -#define TPS80031_RTC_POR_MONTH 1 -#define TPS80031_RTC_POR_DAY 1 - -/* Numbers of registers for time and alarms */ -#define TPS80031_RTC_TIME_NUM_REGS 7 -#define TPS80031_RTC_ALARM_NUM_REGS 6 - -/** - * PMU RTC have only 2 nibbles to store year information, so using an - * offset of 100 to set the base year as 2000 for our driver. - */ -#define RTC_YEAR_OFFSET 100 - -struct tps80031_rtc { - struct rtc_device *rtc; - int irq; -}; - -static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - u8 buff[TPS80031_RTC_TIME_NUM_REGS]; - int ret; - - ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_SECONDS_REG, TPS80031_RTC_TIME_NUM_REGS, buff); - if (ret < 0) { - dev_err(dev, "reading RTC_SECONDS_REG failed, err = %d\n", ret); - return ret; - } - - tm->tm_sec = bcd2bin(buff[0]); - tm->tm_min = bcd2bin(buff[1]); - tm->tm_hour = bcd2bin(buff[2]); - tm->tm_mday = bcd2bin(buff[3]); - tm->tm_mon = bcd2bin(buff[4]) - 1; - tm->tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; - tm->tm_wday = bcd2bin(buff[6]); - return 0; -} - -static int tps80031_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - u8 buff[7]; - int ret; - - buff[0] = bin2bcd(tm->tm_sec); - buff[1] = bin2bcd(tm->tm_min); - buff[2] = bin2bcd(tm->tm_hour); - buff[3] = bin2bcd(tm->tm_mday); - buff[4] = bin2bcd(tm->tm_mon + 1); - buff[5] = bin2bcd(tm->tm_year % RTC_YEAR_OFFSET); - buff[6] = bin2bcd(tm->tm_wday); - - /* Stop RTC while updating the RTC time registers */ - ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_RTC_CTRL_REG, STOP_RTC); - if (ret < 0) { - dev_err(dev->parent, "Stop RTC failed, err = %d\n", ret); - return ret; - } - - ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_SECONDS_REG, - TPS80031_RTC_TIME_NUM_REGS, buff); - if (ret < 0) { - dev_err(dev, "writing RTC_SECONDS_REG failed, err %d\n", ret); - return ret; - } - - ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_RTC_CTRL_REG, STOP_RTC); - if (ret < 0) - dev_err(dev->parent, "Start RTC failed, err = %d\n", ret); - return ret; -} - -static int tps80031_rtc_alarm_irq_enable(struct device *dev, - unsigned int enable) -{ - int ret; - - if (enable) - ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); - else - ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT); - if (ret < 0) { - dev_err(dev, "Update on RTC_INT failed, err = %d\n", ret); - return ret; - } - return 0; -} - -static int tps80031_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - u8 buff[TPS80031_RTC_ALARM_NUM_REGS]; - int ret; - - buff[0] = bin2bcd(alrm->time.tm_sec); - buff[1] = bin2bcd(alrm->time.tm_min); - buff[2] = bin2bcd(alrm->time.tm_hour); - buff[3] = bin2bcd(alrm->time.tm_mday); - buff[4] = bin2bcd(alrm->time.tm_mon + 1); - buff[5] = bin2bcd(alrm->time.tm_year % RTC_YEAR_OFFSET); - ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_ALARM_SECONDS_REG, - TPS80031_RTC_ALARM_NUM_REGS, buff); - if (ret < 0) { - dev_err(dev, "Writing RTC_ALARM failed, err %d\n", ret); - return ret; - } - return tps80031_rtc_alarm_irq_enable(dev, alrm->enabled); -} - -static int tps80031_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - u8 buff[6]; - int ret; - - ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_ALARM_SECONDS_REG, - TPS80031_RTC_ALARM_NUM_REGS, buff); - if (ret < 0) { - dev_err(dev->parent, - "reading RTC_ALARM failed, err = %d\n", ret); - return ret; - } - - alrm->time.tm_sec = bcd2bin(buff[0]); - alrm->time.tm_min = bcd2bin(buff[1]); - alrm->time.tm_hour = bcd2bin(buff[2]); - alrm->time.tm_mday = bcd2bin(buff[3]); - alrm->time.tm_mon = bcd2bin(buff[4]) - 1; - alrm->time.tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET; - return 0; -} - -static int clear_alarm_int_status(struct device *dev, struct tps80031_rtc *rtc) -{ - int ret; - u8 buf; - - /** - * As per datasheet, A dummy read of this RTC_STATUS_REG register - * is necessary before each I2C read in order to update the status - * register value. - */ - ret = tps80031_read(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_RTC_STATUS_REG, &buf); - if (ret < 0) { - dev_err(dev, "reading RTC_STATUS failed. err = %d\n", ret); - return ret; - } - - /* clear Alarm status bits.*/ - ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1, - TPS80031_RTC_STATUS_REG, ALARM_INT_STATUS); - if (ret < 0) { - dev_err(dev, "clear Alarm INT failed, err = %d\n", ret); - return ret; - } - return 0; -} - -static irqreturn_t tps80031_rtc_irq(int irq, void *data) -{ - struct device *dev = data; - struct tps80031_rtc *rtc = dev_get_drvdata(dev); - int ret; - - ret = clear_alarm_int_status(dev, rtc); - if (ret < 0) - return ret; - - rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); - return IRQ_HANDLED; -} - -static const struct rtc_class_ops tps80031_rtc_ops = { - .read_time = tps80031_rtc_read_time, - .set_time = tps80031_rtc_set_time, - .set_alarm = tps80031_rtc_set_alarm, - .read_alarm = tps80031_rtc_read_alarm, - .alarm_irq_enable = tps80031_rtc_alarm_irq_enable, -}; - -static int tps80031_rtc_probe(struct platform_device *pdev) -{ - struct tps80031_rtc *rtc; - struct rtc_time tm; - int ret; - - rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); - if (!rtc) - return -ENOMEM; - - rtc->irq = platform_get_irq(pdev, 0); - platform_set_drvdata(pdev, rtc); - - /* Start RTC */ - ret = tps80031_set_bits(pdev->dev.parent, TPS80031_SLAVE_ID1, - TPS80031_RTC_CTRL_REG, STOP_RTC); - if (ret < 0) { - dev_err(&pdev->dev, "failed to start RTC. err = %d\n", ret); - return ret; - } - - /* If RTC have POR values, set time 01:01:2000 */ - tps80031_rtc_read_time(&pdev->dev, &tm); - if ((tm.tm_year == RTC_YEAR_OFFSET + TPS80031_RTC_POR_YEAR) && - (tm.tm_mon == (TPS80031_RTC_POR_MONTH - 1)) && - (tm.tm_mday == TPS80031_RTC_POR_DAY)) { - tm.tm_year = 2000; - tm.tm_mday = 1; - tm.tm_mon = 1; - ret = tps80031_rtc_set_time(&pdev->dev, &tm); - if (ret < 0) { - dev_err(&pdev->dev, - "RTC set time failed, err = %d\n", ret); - return ret; - } - } - - /* Clear alarm intretupt status if it is there */ - ret = clear_alarm_int_status(&pdev->dev, rtc); - if (ret < 0) { - dev_err(&pdev->dev, "Clear alarm int failed, err = %d\n", ret); - return ret; - } - - rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &tps80031_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc)) { - ret = PTR_ERR(rtc->rtc); - dev_err(&pdev->dev, "RTC registration failed, err %d\n", ret); - return ret; - } - - ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, - tps80031_rtc_irq, - IRQF_ONESHOT, - dev_name(&pdev->dev), rtc); - if (ret < 0) { - dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n", - rtc->irq, ret); - return ret; - } - device_set_wakeup_capable(&pdev->dev, 1); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int tps80031_rtc_suspend(struct device *dev) -{ - struct tps80031_rtc *rtc = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(rtc->irq); - return 0; -} - -static int tps80031_rtc_resume(struct device *dev) -{ - struct tps80031_rtc *rtc = dev_get_drvdata(dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(rtc->irq); - return 0; -}; -#endif - -static SIMPLE_DEV_PM_OPS(tps80031_pm_ops, tps80031_rtc_suspend, - tps80031_rtc_resume); - -static struct platform_driver tps80031_rtc_driver = { - .driver = { - .name = "tps80031-rtc", - .pm = &tps80031_pm_ops, - }, - .probe = tps80031_rtc_probe, -}; - -module_platform_driver(tps80031_rtc_driver); - -MODULE_ALIAS("platform:tps80031-rtc"); -MODULE_DESCRIPTION("TI TPS80031/TPS80032 RTC driver"); -MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/include/linux/rtc.h b/include/linux/rtc.h index bd611e26291d..47fd1c2d3a57 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -66,6 +66,8 @@ struct rtc_class_ops { int (*alarm_irq_enable)(struct device *, unsigned int enabled); int (*read_offset)(struct device *, long *offset); int (*set_offset)(struct device *, long offset); + int (*param_get)(struct device *, struct rtc_param *param); + int (*param_set)(struct device *, struct rtc_param *param); }; struct rtc_device; @@ -80,6 +82,7 @@ struct rtc_timer { /* flags */ #define RTC_DEV_BUSY 0 +#define RTC_NO_CDEV 1 struct rtc_device { struct device dev; diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h index f950bff75e97..03e5b776e597 100644 --- a/include/uapi/linux/rtc.h +++ b/include/uapi/linux/rtc.h @@ -14,6 +14,7 @@ #include <linux/const.h> #include <linux/ioctl.h> +#include <linux/types.h> /* * The struct used to pass data via the following ioctl. Similar to the @@ -66,6 +67,17 @@ struct rtc_pll_info { long pll_clock; /* base PLL frequency */ }; +struct rtc_param { + __u64 param; + union { + __u64 uvalue; + __s64 svalue; + __u64 ptr; + }; + __u32 index; + __u32 __pad; +}; + /* * ioctl calls that are permitted to the /dev/rtc interface, if * any of the RTC drivers are enabled. @@ -95,6 +107,9 @@ struct rtc_pll_info { #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ +#define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param) /* Get parameter */ +#define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param) /* Set parameter */ + #define RTC_VL_DATA_INVALID _BITUL(0) /* Voltage too low, RTC data is invalid */ #define RTC_VL_BACKUP_LOW _BITUL(1) /* Backup voltage is low */ #define RTC_VL_BACKUP_EMPTY _BITUL(2) /* Backup empty or not present */ @@ -114,7 +129,21 @@ struct rtc_pll_info { #define RTC_FEATURE_ALARM 0 #define RTC_FEATURE_ALARM_RES_MINUTE 1 #define RTC_FEATURE_NEED_WEEK_DAY 2 -#define RTC_FEATURE_CNT 3 +#define RTC_FEATURE_ALARM_RES_2S 3 +#define RTC_FEATURE_UPDATE_INTERRUPT 4 +#define RTC_FEATURE_CORRECTION 5 +#define RTC_FEATURE_BACKUP_SWITCH_MODE 6 +#define RTC_FEATURE_CNT 7 + +/* parameter list */ +#define RTC_PARAM_FEATURES 0 +#define RTC_PARAM_CORRECTION 1 +#define RTC_PARAM_BACKUP_SWITCH_MODE 2 + +#define RTC_BSM_DISABLED 0 +#define RTC_BSM_DIRECT 1 +#define RTC_BSM_LEVEL 2 +#define RTC_BSM_STANDBY 3 #define RTC_MAX_FREQ 8192 |