From 8719a17613e0233d707eb22e1645d217594631ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Sep 2021 20:49:20 +0100 Subject: rtc: ds1302: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210923194922.53386-2-broonie@kernel.org --- drivers/rtc/rtc-ds1302.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/rtc') 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); -- cgit v1.2.3 From da87639d6312afb8855717c791768bf2d4ca8ac8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Sep 2021 20:49:21 +0100 Subject: rtc: ds1390: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210923194922.53386-3-broonie@kernel.org --- drivers/rtc/rtc-ds1390.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/rtc') 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); -- cgit v1.2.3 From 5f84478e14aa8b43a4ea85d2e091931741947749 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Sep 2021 20:49:22 +0100 Subject: rtc: pcf2123: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210923194922.53386-4-broonie@kernel.org --- drivers/rtc/rtc-pcf2123.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/rtc') 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); -- cgit v1.2.3 From 5e295f9402039aaa38d0949f598745b98850fd13 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 18:45:12 +0200 Subject: rtc: omap: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210916164513.134725-1-krzysztof.kozlowski@canonical.com --- drivers/rtc/rtc-omap.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/rtc') 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"); -- cgit v1.2.3 From 6eee1c48be7cb0b9b14408521a9151c1021901d3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 18:46:04 +0200 Subject: rtc: s5m: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210916164604.134924-1-krzysztof.kozlowski@canonical.com --- drivers/rtc/rtc-s5m.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/rtc') 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 "); MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s5m-rtc"); -- cgit v1.2.3 From 38b17bc9c40e8f3138b02c624d9063b6781c8150 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 18 Sep 2021 23:35:51 +0200 Subject: rtc: rx6110: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210918213553.14514-1-wsa+renesas@sang-engineering.com --- drivers/rtc/rtc-rx6110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') 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 -- cgit v1.2.3 From be7d9c9161b9c76edeff15e79edc2f256568fe05 Mon Sep 17 00:00:00 2001 From: Daniel Palmer Date: Mon, 23 Aug 2021 19:16:12 +0200 Subject: rtc: Add support for the MSTAR MSC313 RTC This adds support for the RTC block on the Mstar MSC313e SoCs and newer. Signed-off-by: Daniel Palmer Co-developed-by: Romain Perier Signed-off-by: Romain Perier Reviewed-by: Nobuhiro Iwamatsu Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210823171613.18941-3-romain.perier@gmail.com --- MAINTAINERS | 1 + drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-msc313.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 drivers/rtc/rtc-msc313.c (limited to 'drivers/rtc') diff --git a/MAINTAINERS b/MAINTAINERS index eeb4c70b3d5b..caedf3c29286 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2247,6 +2247,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 e1bc5214494e..59dc1410a160 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1935,4 +1935,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..e76308053b0f 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 diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c new file mode 100644 index 000000000000..f493ca5f181b --- /dev/null +++ b/drivers/rtc/rtc-msc313.c @@ -0,0 +1,258 @@ +// 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 +#include +#include +#include +#include +#include + +/* 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) + | (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) + | (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 "); +MODULE_AUTHOR("Romain Perier "); +MODULE_DESCRIPTION("MStar RTC Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 27ff63eb076c31086e0a72d41b5c635193a58516 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 27 Sep 2021 08:37:23 +0200 Subject: rtc: msc313: fix missing include The driver needs io.h Reported-by: Stephen Rothwell Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210927063724.312687-1-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-msc313.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c index f493ca5f181b..5f178d29cfd8 100644 --- a/drivers/rtc/rtc-msc313.c +++ b/drivers/rtc/rtc-msc313.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From 3109151c47343c80300177ec7704e0757064efdc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 27 Sep 2021 14:02:40 +0100 Subject: rtc: mcp795: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210927130240.33693-1-broonie@kernel.org --- drivers/rtc/rtc-mcp795.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/rtc') 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); -- cgit v1.2.3 From f3606687b447c41d28a011c98373b62b1cd52345 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Sep 2021 14:46:54 +0100 Subject: rtc: msc313: Fix unintentional sign extension issues with left shift of a u16 Shifting the u16 value returned by readw by 16 bits to the left will be promoted to a 32 bit signed int and then sign-extended to an unsigned long. If the top bit of the readw is set then the shifted value will be sign extended and the top 32 bits of the result will be set. Fixes: be7d9c9161b9 ("rtc: Add support for the MSTAR MSC313 RTC") Signed-off-by: Colin Ian King Reviewed-by: Romain Perier Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210928134654.991923-1-colin.king@canonical.com --- drivers/rtc/rtc-msc313.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c index 5f178d29cfd8..f3fde013c4b8 100644 --- a/drivers/rtc/rtc-msc313.c +++ b/drivers/rtc/rtc-msc313.c @@ -53,7 +53,7 @@ static int msc313_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) unsigned long seconds; seconds = readw(priv->rtc_base + REG_RTC_MATCH_VAL_L) - | (readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16); + | ((unsigned long)readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16); rtc_time64_to_tm(seconds, &alarm->time); @@ -122,7 +122,7 @@ static int msc313_rtc_read_time(struct device *dev, struct rtc_time *tm) udelay(1); seconds = readw(priv->rtc_base + REG_RTC_CNT_VAL_L) - | (readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16); + | ((unsigned long)readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16); rtc_time64_to_tm(seconds, tm); -- cgit v1.2.3 From 7caadcfa8a7c6f8e754d982b99d959a222e7f863 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 25 Sep 2021 23:34:41 +0100 Subject: rtc: m41t80: return NULL rather than a plain 0 integer Function m41t80_sqw_register_clk returns a pointer to struct clk, so returning a plain 0 integer isn't good practice. Fix this by returning a NULL instead. Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210925223441.182673-1-colin.king@canonical.com --- drivers/rtc/rtc-m41t80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') 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 */ -- cgit v1.2.3 From 789c1093f02c436b320d78a739f9610c8271cb73 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 11 Oct 2021 21:21:14 +0800 Subject: rtc: class: don't call cdev_device_del() when cdev_device_add() failed I got a null-ptr-deref report when doing fault injection test: general protection fault, probably for non-canonical address 0xdffffc0000000022: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000110-0x0000000000000117] RIP: 0010:device_del+0x132/0xdc0 Call Trace: cdev_device_del+0x1a/0x80 devm_rtc_unregister_device+0x37/0x80 release_nodes+0xc3/0x3b0 If cdev_device_add() fails, 'dev->p' is not set, it causes null-ptr-deref when calling cdev_device_del(). Registering character device is optional, we don't return error code here, so introduce a new flag 'RTC_NO_CDEV' to indicate if it has character device, cdev_device_del() is called when this bit is not set. Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211011132114.3663509-1-yangyingliang@huawei.com --- drivers/rtc/class.c | 9 ++++++--- include/linux/rtc.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index f77bc089eb6b..654e921244bf 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -334,7 +334,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); } @@ -397,12 +398,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/include/linux/rtc.h b/include/linux/rtc.h index bd611e26291d..354e0843ab17 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -80,6 +80,7 @@ struct rtc_timer { /* flags */ #define RTC_DEV_BUSY 0 +#define RTC_NO_CDEV 1 struct rtc_device { struct device dev; -- cgit v1.2.3 From 24d23181e43d72ca692a479e70dfe5b0b5dd33f1 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 12 Oct 2021 12:16:29 +0800 Subject: rtc: class: check return value when calling dev_set_name() I got a null-ptr-deref report when doing fault injection test: BUG: kernel NULL pointer dereference, address: 0000000000000000 RIP: 0010:strcmp+0xc/0x20 Call Trace: __devm_rtc_register_device.cold.7+0x16a/0x2df rv3029_probe+0x4b1/0x770 [rtc_rv3029c2] rv3029_i2c_probe+0x141/0x180 [rtc_rv3029c2] i2c_device_probe+0xa07/0xbb0 really_probe+0x285/0xc30 If dev_set_name() fails, dev_name() is null, it causes null-ptr-deref, we need check the return value of dev_set_name(). Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211012041629.2504158-1-yangyingliang@huawei.com --- drivers/rtc/class.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 654e921244bf..dbccd71589b9 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -364,7 +364,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) -- cgit v1.2.3 From c3336b8ac6091df60a5c1049a8c685d0b947cc61 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 12 Oct 2021 13:10:28 +0300 Subject: rtc: rv3032: fix error handling in rv3032_clkout_set_rate() Do not call rv3032_exit_eerd() if the enter function fails but don't forget to call the exit when the enter succeeds. Fixes: 2eeaa532acca ("rtc: rv3032: Add a driver for Microcrystal RV-3032") Signed-off-by: Dan Carpenter Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211012101028.GT2083@kadam --- drivers/rtc/rtc-rv3032.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index d63102d5cb1e..1b62ed2f1459 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -617,11 +617,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)); -- cgit v1.2.3 From 4c8a7b80d5f3c924fbe08b24634fb67a97f96465 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 13 Oct 2021 09:49:54 +0200 Subject: rtc: pcf85063: add support for fixed clock TQ-Systems' TQMa8Mx module (SoM) uses a pcf85063 as RTC. The default output is 32768Hz. This is to provide the i.MX8M CKIL clock. Once the RTC driver is probed, the clock is disabled and all i.MX8M functionality depending on the 32 KHz clock will halt. In our case the whole system halts and a power cycle is required. Referencing the pcf85063 directly results in a deadlock. The kernel will see, that i.MX8M system clock needs the RTC clock and do probe deferral. But the i.MX8M I2C module never becomes usable without the i.MX8M CKIL clock and thus the RTC's clock will not be probed. So from the kernel's perspective this is a chicken-and-egg problem. Technically everything is fine by not touching anything, since the RTC clock correctly enables the clock on reset (i.e. on battery backup power loss). A workaround for this issue is describing the square wave pin as fixed-clock, which is registered early and basically how this pin is used on the i.MX8M. This addresses the exact same issue as in commit f765e349c3e1 ("rtc: m41t80: add support for fixed clock"). Signed-off-by: Alexander Stein Reported-by: kernel test robot Signed-off-by: Alexandre Belloni [Fixed return value 0 -> NULL] Link: https://lore.kernel.org/r/20211013074954.997445-1-alexander.stein@ew.tq-group.com --- Documentation/devicetree/bindings/rtc/nxp,pcf85063.txt | 9 +++++++++ drivers/rtc/rtc-pcf85063.c | 12 ++++++++++++ 2 files changed, 21 insertions(+) (limited to 'drivers/rtc') 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/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 14da4ab30104..3e59590f9b69 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -479,6 +479,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; -- cgit v1.2.3 From 9f08c9ed580a287de6546044e28f15bb183d00ff Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 15 Oct 2021 12:12:08 +0100 Subject: rtc: pcf85063: Always clear EXT_TEST from set_time Power-on reset after the insertion of a battery does not always complete successfully, leading to corrupted register content. The EXT_TEST bit will stop the clock from running, but currently the driver will never recover. Safely handle the erroneous state by clearing EXT_TEST as part of the usual set_time method. Signed-off-by: Phil Elwell Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211015111208.1757110-1-phil@raspberrypi.com --- drivers/rtc/rtc-pcf85063.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 3e59590f9b69..4a70d6bae859 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) -- cgit v1.2.3 From 6a8af1b6568ad9ee08a419fb12c793f7992cf8a4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:19:28 +0200 Subject: rtc: add parameter ioctl Add an ioctl allowing to get and set extra parameters for an RTC. For now, only handle getting available features. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018151933.76865-3-alexandre.belloni@bootlin.com --- drivers/rtc/dev.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/rtc.h | 18 ++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index 5b8ebe86124a..143c097eff0f 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,44 @@ 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; + + default: + 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: + default: + err = -EINVAL; + } + + break; + default: /* Finally try the driver's ioctl interface */ if (ops->ioctl) { diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h index f4037c541925..3241f9ecc639 100644 --- a/include/uapi/linux/rtc.h +++ b/include/uapi/linux/rtc.h @@ -14,6 +14,7 @@ #include #include +#include /* * 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 */ @@ -118,6 +133,9 @@ struct rtc_pll_info { #define RTC_FEATURE_UPDATE_INTERRUPT 4 #define RTC_FEATURE_CNT 5 +/* parameter list */ +#define RTC_PARAM_FEATURES 0 + #define RTC_MAX_FREQ 8192 -- cgit v1.2.3 From 2268551935dbf1abcbb4d4fb7b1ad74dbe0d1be0 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:19:29 +0200 Subject: rtc: expose correction feature Add a new feature for RTCs able to correct the oscillator imprecision. This is also called offset or trimming. Such drivers have a .set_offset callback, use that to set the feature bit from the core. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018151933.76865-4-alexandre.belloni@bootlin.com --- drivers/rtc/class.c | 3 +++ include/uapi/linux/rtc.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index dbccd71589b9..2e0cbc190a8a 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -389,6 +389,9 @@ 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->ops->set_offset) + set_bit(RTC_FEATURE_CORRECTION, rtc->features); + rtc->owner = owner; rtc_device_get_offset(rtc); diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h index 3241f9ecc639..c83bb9a4fa4f 100644 --- a/include/uapi/linux/rtc.h +++ b/include/uapi/linux/rtc.h @@ -131,7 +131,8 @@ struct rtc_param { #define RTC_FEATURE_NEED_WEEK_DAY 2 #define RTC_FEATURE_ALARM_RES_2S 3 #define RTC_FEATURE_UPDATE_INTERRUPT 4 -#define RTC_FEATURE_CNT 5 +#define RTC_FEATURE_CORRECTION 5 +#define RTC_FEATURE_CNT 6 /* parameter list */ #define RTC_PARAM_FEATURES 0 -- cgit v1.2.3 From a6d8c6e1a5c6fb982964861dc84c0c7cb0151c7c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:19:30 +0200 Subject: rtc: add correction parameter Add a new parameter allowing the get and set the correction using ioctls instead of just sysfs. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018151933.76865-5-alexandre.belloni@bootlin.com --- drivers/rtc/dev.c | 19 +++++++++++++++++++ include/uapi/linux/rtc.h | 1 + 2 files changed, 20 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index 143c097eff0f..abee1fc4705e 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -398,6 +398,16 @@ static long rtc_dev_ioctl(struct file *file, 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: err = -EINVAL; } @@ -416,6 +426,15 @@ static long rtc_dev_ioctl(struct file *file, 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: err = -EINVAL; } diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h index c83bb9a4fa4f..5debe82439c2 100644 --- a/include/uapi/linux/rtc.h +++ b/include/uapi/linux/rtc.h @@ -136,6 +136,7 @@ struct rtc_param { /* parameter list */ #define RTC_PARAM_FEATURES 0 +#define RTC_PARAM_CORRECTION 1 #define RTC_MAX_FREQ 8192 -- cgit v1.2.3 From 0d20e9fb1262b1f9ac895b287db892bc75b05b84 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:19:31 +0200 Subject: rtc: add BSM parameter BSM or Backup Switch Mode is a common feature on RTCs, allowing to select how the RTC will decide when to switch from its primary power supply to the backup power supply. It is necessary to be able to set it from userspace as there are uses cases where it has to be done dynamically. Supported values are: RTC_BSM_DISABLED: disabled RTC_BSM_DIRECT: switching will happen as soon as Vbackup > Vdd RTC_BSM_LEVEL: switching will happen around a threshold, usually with an hysteresis RTC_BSM_STANDBY: switching will not happen until Vdd > Vbackup, this is useful to ensure the RTC doesn't draw any power until the device is first powered on. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018151933.76865-6-alexandre.belloni@bootlin.com --- drivers/rtc/dev.c | 10 ++++++++-- include/linux/rtc.h | 2 ++ include/uapi/linux/rtc.h | 9 ++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index abee1fc4705e..e104972a28fd 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -409,7 +409,10 @@ static long rtc_dev_ioctl(struct file *file, break; default: - err = -EINVAL; + if (rtc->ops->param_get) + err = rtc->ops->param_get(rtc->dev.parent, ¶m); + else + err = -EINVAL; } if (!err) @@ -436,7 +439,10 @@ static long rtc_dev_ioctl(struct file *file, return rtc_set_offset(rtc, param.svalue); default: - err = -EINVAL; + if (rtc->ops->param_set) + err = rtc->ops->param_set(rtc->dev.parent, ¶m); + else + err = -EINVAL; } break; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 354e0843ab17..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; diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h index 5debe82439c2..03e5b776e597 100644 --- a/include/uapi/linux/rtc.h +++ b/include/uapi/linux/rtc.h @@ -132,11 +132,18 @@ struct rtc_param { #define RTC_FEATURE_ALARM_RES_2S 3 #define RTC_FEATURE_UPDATE_INTERRUPT 4 #define RTC_FEATURE_CORRECTION 5 -#define RTC_FEATURE_CNT 6 +#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 -- cgit v1.2.3 From 018d959ba7ffcadcc21e007f81c4b2b7a2b47447 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:19:32 +0200 Subject: rtc: rv3028: add BSM support Backup Switch Mode controls how the RTC decides when to switch to the backup power supply. As it is disabled by default, provide a way to enable and configure it. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018151933.76865-7-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rv3028.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'drivers/rtc') 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 #include +#include #include #include #include @@ -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; -- cgit v1.2.3 From 6084eac38e765c5ee1338f4e9b1ad3321f4c53eb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:19:33 +0200 Subject: rtc: rv3032: allow setting BSM Backup Switch Mode is currently set properly when the trickle charger is enabled. However, in the case of a non-rechargeable battery, it is necessary to be able to enable it, only allow that when the trickle charger is disabled. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018151933.76865-8-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rv3032.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index 1b62ed2f1459..a3c73179ecb1 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 @@ -402,6 +403,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 +611,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)); @@ -813,6 +885,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 +957,8 @@ 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); + rv3032->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rv3032->rtc->range_max = RTC_TIMESTAMP_END_2099; rv3032->rtc->ops = &rv3032_rtc_ops; -- cgit v1.2.3 From 7d7234a4fff395ab17b021ec18f852e8ec8703b3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 15 Oct 2021 21:24:00 +0200 Subject: rtc: pcf8523: avoid reading BLF in pcf8523_rtc_read_time BLF, battery low doesn't mean the time is imprecise or invalid, it simply mean the backup battery has to be replaced. This information can be read using the VL_READ ioctl. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211015192400.818254-1-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-pcf8523.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 8b6fb20774bf..09110b3ae25f 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -24,6 +24,7 @@ #define PCF8523_CONTROL3_PM_DSM BIT(5) /* direct switching mode */ #define PCF8523_CONTROL3_PM_MASK 0xe0 #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) @@ -94,18 +95,6 @@ static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) return 0; } -static int pcf8523_voltage_low(struct i2c_client *client) -{ - u8 value; - int err; - - err = pcf8523_read(client, 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; @@ -220,14 +209,6 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) struct i2c_msg msgs[2]; int err; - err = pcf8523_voltage_low(client); - if (err < 0) { - return err; - } else if (err > 0) { - dev_err(dev, "low voltage detected, time is unreliable\n"); - return -EINVAL; - } - msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 1; @@ -412,10 +393,11 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, switch (cmd) { case RTC_VL_READ: - ret = pcf8523_voltage_low(client); + ret = pcf8523_read(client, 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); -- cgit v1.2.3 From adb17a053e460f20740d713c4843d6966e66b1b1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:23:36 +0200 Subject: rtc: expose RTC_FEATURE_UPDATE_INTERRUPT Set RTC_FEATURE_UPDATE_INTERRUPT by default and clear it when it is not supported. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018152337.78732-1-alexandre.belloni@bootlin.com --- drivers/rtc/class.c | 4 ++++ drivers/rtc/interface.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 2e0cbc190a8a..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; } @@ -389,6 +390,9 @@ 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); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 9a2bd4947007..d005623e6eb3 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -561,7 +561,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); -- cgit v1.2.3 From 91f3849d956d58073ef55e01f2e8871dc30847a5 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:36:46 +0200 Subject: rtc: pcf8523: switch to regmap Use regmap to access the RTC registers, this is a huge reduction in code lines and generated code. Values on ARMv7: text data bss dec hex 5180 132 0 5312 14c0 before 3900 132 0 4032 fc0 after Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018153651.82069-1-alexandre.belloni@bootlin.com --- drivers/rtc/Kconfig | 1 + drivers/rtc/rtc-pcf8523.c | 303 +++++++++++++--------------------------------- 2 files changed, 85 insertions(+), 219 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 59dc1410a160..8dc92b4e042f 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. diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 09110b3ae25f..c5d31c525997 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -49,115 +50,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_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; @@ -166,60 +97,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; - 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; @@ -239,63 +124,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; @@ -305,12 +177,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); @@ -320,30 +192,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; + struct pcf8523 *pcf8523 = dev_get_drvdata(dev); - err = pcf8523_read(client, PCF8523_REG_CONTROL1, &value); - if (err < 0) - return err; - - value &= PCF8523_CONTROL1_AIE; - - 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; @@ -351,7 +209,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; @@ -363,16 +221,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; @@ -386,21 +241,21 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) 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_read(client, PCF8523_REG_CONTROL3, &value); + ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); if (ret < 0) return 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; @@ -419,12 +274,12 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, 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; @@ -437,9 +292,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); @@ -449,7 +304,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 = { @@ -463,6 +318,12 @@ static const struct rtc_class_ops pcf8523_rtc_ops = { .set_offset = pcf8523_rtc_set_offset, }; +static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x13, +}; + static int pcf8523_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -478,37 +339,41 @@ 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_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL3, + PCF8523_CONTROL3_PM_MASK, 0); if (err < 0) return err; - rtc = devm_rtc_allocate_device(&client->dev); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - 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; -- cgit v1.2.3 From 5537752c53497fca0469488d1788ceba1b75d5a7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:36:47 +0200 Subject: rtc: pcf8523: always compile pcf8523_rtc_ioctl Compiling out pcf8523_rtc_ioctl saves about 5% of the generated machine code. However, it certainly never happens as the RTC character device interface is the most useful one and is probably always compiled in. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018153651.82069-2-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-pcf8523.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index c5d31c525997..103557f48409 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -237,7 +237,6 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) return 0; } -#ifdef CONFIG_RTC_INTF_DEV static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { @@ -268,9 +267,6 @@ 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) { -- cgit v1.2.3 From 7c176119aefd64a099d06ba33b4730f643b3a890 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:36:48 +0200 Subject: rtc: pcf8523: remove unecessary ifdefery If CONFIG_OF is not defined, of_property_read_bool will return false which is our default value Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018153651.82069-3-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-pcf8523.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 103557f48409..79a571db803b 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -376,9 +376,7 @@ static int pcf8523_probe(struct i2c_client *client, 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); -- cgit v1.2.3 From ebf48cbe32e9e2b74e9d5d8f7daf3422a3ec27ea Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:36:49 +0200 Subject: rtc: pcf8523: allow usage on ACPI platforms Always provide an OF table to ensure ACPI platforms can also use this driver. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018153651.82069-4-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-pcf8523.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 79a571db803b..181c3425d6c7 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -389,19 +389,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, -- cgit v1.2.3 From f8d4e4fa51ec817edfee49c173521a1102f7f7a6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 18 Oct 2021 17:36:50 +0200 Subject: rtc: pcf8523: add BSM support Backup Switch Mode allows to select the strategy to use to switch from the main power supply to the backup power supply. As before, the driver will switch from standby mode to level mode but now only when it has never been set. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211018153651.82069-5-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-pcf8523.c | 103 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 181c3425d6c7..c93acade7205 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -20,10 +21,8 @@ #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) @@ -237,6 +236,83 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) return 0; } +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) { @@ -312,6 +388,8 @@ 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 = { @@ -326,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)) @@ -351,11 +430,23 @@ static int pcf8523_probe(struct i2c_client *client, dev_warn(&client->dev, "failed to set xtal load capacitance: %d", err); - err = regmap_update_bits(pcf8523->regmap, PCF8523_REG_CONTROL3, - PCF8523_CONTROL3_PM_MASK, 0); + err = regmap_read(pcf8523->regmap, PCF8523_REG_SECONDS, &value); if (err < 0) return err; + 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; + } + } + rtc->ops = &pcf8523_rtc_ops; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_max = RTC_TIMESTAMP_END_2099; -- cgit v1.2.3 From 814691c7f7d1f958ac30c3dca5070a95c1f658dd Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 28 Sep 2021 03:03:32 -0500 Subject: rtc: sun6i: Allow probing without an early clock provider Some SoCs have an RTC supported by this RTC driver, but do not have an early clock provider declared here. Currently, this prevents the RTC driver from probing, because it expects a global struct to already be allocated. Fix probing the driver by copying the missing pieces from the clock provider setup function, replacing them with the devm variants. Signed-off-by: Samuel Holland Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210928080335.36706-7-samuel@sholland.org --- drivers/rtc/rtc-sun6i.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/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); -- cgit v1.2.3 From 005870f46cf6f98417ec48d129721e945dfb3a43 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 21 Oct 2021 22:22:56 +0300 Subject: rtc: tps80031: Remove driver Driver was upstreamed in 2013 and never got a user, remove it. Signed-off-by: Dmitry Osipenko Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211021192258.21968-2-digetx@gmail.com --- drivers/rtc/Kconfig | 8 -- drivers/rtc/Makefile | 1 - drivers/rtc/rtc-tps80031.c | 324 --------------------------------------------- 3 files changed, 333 deletions(-) delete mode 100644 drivers/rtc/rtc-tps80031.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8dc92b4e042f..f4dfc65693a4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -583,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 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e76308053b0f..678a8ef4abae 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -170,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/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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 "); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From dba28c37f23a09fc32dbc37463ddb2feb3886f98 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 21 Oct 2021 23:22:54 +0300 Subject: rtc: s3c: Remove usage of devm_rtc_device_register() devm_rtc_device_register() is deprecated. Use devm_rtc_allocate_device() and devm_rtc_register_device() API instead. This change doesn't change the behavior, but allows for further improvements. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211021202256.28517-2-semen.protsenko@linaro.org --- drivers/rtc/rtc-s3c.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e57d3ca70a78..10e591794276 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -447,15 +447,18 @@ 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; + + 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) { -- cgit v1.2.3 From e4a1444e10cbda2892a4ea7325ef5efa47c75cfb Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 21 Oct 2021 23:22:55 +0300 Subject: rtc: s3c: Extract read/write IO into separate functions Create dedicated functions for I/O operations and BCD conversion. It can be useful to separate those from representation conversion and other stuff found in RTC callbacks. This patch does not introduce any functional changes, it's merely refactoring change. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211021202256.28517-3-semen.protsenko@linaro.org --- drivers/rtc/rtc-s3c.c | 98 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 37 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 10e591794276..d1baf655c008 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,53 @@ 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; + + if (rtc_tm.tm_year < 0 || rtc_tm.tm_year >= 100) { + dev_err(dev, "rtc only supports 100 years\n"); + return -EINVAL; + } + + 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); -- cgit v1.2.3 From a5feda3b361e11b291786d5c4ff86d4b9a55498f Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 21 Oct 2021 23:22:56 +0300 Subject: rtc: s3c: Add time range This RTC driver starts counting from 2000 to avoid Y2K problem. Also it only supports 100 years range for all RTCs. Provide that info to RTC framework. Also remove check for 100 years range in s3c_rtc_settime(), as RTC core won't pass any invalid values to the driver, now that correct range is set. Here is the rationale on 100 years range limitation. Info on different Samsung RTCs (credit goes to Krzysztof Kozlowski): - All S3C chips have only 8-bit wide year register (can store 100 years range in BCD format) - S5Pv210 and Exynos chips have 12-bit year register (can store 1000 years range in BCD format) But in reality we usually can't make use of those 12 bits either: - RTCs might think that both 2000 and 2100 years are leap years. So when the YEAR register is 0, RTC goes from 28 Feb to 29 Feb, and when the YEAR register is 100, RTC also goes from 28 Feb to 29 Feb. This is of course incorrect: RTC breaks leap year criteria, which breaks the time contiguity, which leads to inability to use the RTC after year of 2099. It was found for example on Exynos850 SoC. - Despite having 12 bits for holding the year value, RTC might overflow the year value internally much earlier. For example, on Exynos850 the RTC overflows when YEAR=159, making the next YEAR=0. This way RTC actually has range of 160 years, not 1000 as one may think. All that said, there is no sense in trying to increase the time range for more than 100 years on RTCs that seem capable of that. It also doesn't have too much practical value -- current hardware will be probably obsolete by 2100. Tested manually on Exynos850 RTC: $ date -s "1999-12-31 23:59:50" $ hwclock -w -f /dev/rtc0 $ date -s "2100-01-01 00:00:00" $ hwclock -w -f /dev/rtc0 $ date -s "2000-01-01 00:00:00" $ hwclock -w -f /dev/rtc0 $ hwclock -r -f /dev/rtc0 $ date -s "2099-12-31 23:59:50" $ hwclock -w -f /dev/rtc0 $ hwclock -r -f /dev/rtc0 Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211021202256.28517-4-semen.protsenko@linaro.org --- drivers/rtc/rtc-s3c.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index d1baf655c008..db529733c9c4 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -219,11 +219,6 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) rtc_tm.tm_year -= 100; rtc_tm.tm_mon += 1; - if (rtc_tm.tm_year < 0 || rtc_tm.tm_year >= 100) { - dev_err(dev, "rtc only supports 100 years\n"); - return -EINVAL; - } - return s3c_rtc_write_time(info, &rtc_tm); } @@ -478,6 +473,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) } 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) -- cgit v1.2.3 From 03a86cda4123084c7969387e7e0b69f23c2f8acf Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 1 Nov 2021 10:33:59 +0900 Subject: rtc: rv8803: fix writing back ctrl in flag register ctrl is set from read_regs(..FLAG, 2, ctrl), so ctrl[0] is FLAG and ctrl[1] is the CTRL register. Use ctrl[0] to write back to the FLAG register as appropriate. Signed-off-by: Dominique Martinet Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211101013400.325855-1-dominique.martinet@atmark-techno.com --- drivers/rtc/rtc-rv8803.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') 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; -- cgit v1.2.3 From 72e4ee638d8e1d7d80079c37ec8641fec0d63016 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:53:48 +0100 Subject: rtc: pcf85063: silence cppcheck warning cppcheck warnings: (new ones prefixed by >>) >> drivers/rtc/rtc-pcf85063.c:292:40: warning: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] status = status & PCF85063_REG_SC_OS ? RTC_VL_DATA_INVALID : 0; Reported-by: kernel test robot Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225349.110707-1-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-pcf85063.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 4a70d6bae859..15e50bb10cf0 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -299,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); -- cgit v1.2.3 From d87f741dddabd670a82bccf94ac73cec80209bc0 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:46 +0100 Subject: rtc: handle alarms with a minute resolution Handle alarms with a minute resolution in the core. Until now drivers have been open coding the seconds part removal and have been doing that wrongly. Most of them are rounding up which means the allow the system to miss deadlines. So, round down and let __rtc_set_alarm return immediately if the time has already passed. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-1-alexandre.belloni@bootlin.com --- drivers/rtc/interface.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index d005623e6eb3..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); -- cgit v1.2.3 From 654815eff130a42e861241b848dfea2c50d6c7b1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:47 +0100 Subject: rtc: s35390a: let the core handle the alarm resolution Tell the RTC core UIE are not supported because the resolution of the alarm is a minute. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-2-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-s35390a.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') 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); -- cgit v1.2.3 From ac86964ff9791f8da27b321772db85369ec59506 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:48 +0100 Subject: rtc: rv3032: let the core handle the alarm resolution Let the RTC core know the resolution of the alarm is a minute. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-3-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rv3032.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index a3c73179ecb1..c3bee305eacc 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -311,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) @@ -958,6 +950,7 @@ 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; -- cgit v1.2.3 From 24370014011f8df7a098a83a453204b1f05fd1d2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:49 +0100 Subject: rtc: ab-eoz9: use RTC_FEATURE_UPDATE_INTERRUPT Switch from uie_unsupported to RTC_FEATURE_UPDATE_INTERRUPT Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-4-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-ab-eoz9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c index a9b355510cd4..50ead6fce880 100644 --- a/drivers/rtc/rtc-ab-eoz9.c +++ b/drivers/rtc/rtc-ab-eoz9.c @@ -534,7 +534,7 @@ 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_UPDATE_INTERRUPT, data->rtc->features); clear_bit(RTC_FEATURE_ALARM, data->rtc->features); if (client->irq > 0) { -- cgit v1.2.3 From 27f06af753149f62d681297177bafc95c1551bfe Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:50 +0100 Subject: rtc: ab-eoz9: support UIE when available The RTC actually supports UIE when an interrupt is available. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-5-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-ab-eoz9.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c index 50ead6fce880..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; - clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, data->rtc->features); 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")) { -- cgit v1.2.3 From a5f828036c2e9f46d84c7c9b27bf248c7f4bb0fe Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:51 +0100 Subject: rtc: ab8500: let the core handle the alarm resolution Tell the RTC core UIE are not supported because the resolution of the alarm is a minute. Note that this is in fact also fixing how the resolution is reported as the previous test was simply ensuring the alarm was more than a minute in the future while the register has a minute resolution. This would be ok if the alarm was a countdown but ab8500_rtc_read_alarm suggests otherwise and the AB8500 datasheet states that the RTC documentation is not public. Finally, the comment is wrong and what makes the UIE emulation work is uie_unsupported being set. Signed-off-by: Alexandre Belloni Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20211107225458.111068-6-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-ab8500.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'drivers/rtc') 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; -- cgit v1.2.3 From 5e7f635aa64764f34266d22ee0fa27c8f4834309 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:52 +0100 Subject: rtc: rx8025: switch to devm_rtc_allocate_device Switch to devm_rtc_allocate_device/devm_rtc_register_device, this allows for further improvement of the driver. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-7-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rx8025.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index d38aaf08108c..617b044c66f0 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -559,12 +559,11 @@ 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; if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); @@ -583,6 +582,10 @@ static int rx8025_probe(struct i2c_client *client, /* the rx8025 alarm only supports a minute accuracy */ rx8025->rtc->uie_unsupported = 1; + err = devm_rtc_register_device(rx8025->rtc); + if (err) + return err; + err = rx8025_sysfs_register(&client->dev); return err; } -- cgit v1.2.3 From 8670558f9e296ce9874284b3c3fcd3ed9fa717d3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:53 +0100 Subject: rtc: rx8025: let the core handle the alarm resolution Tell the RTC core UIE are not supported because the resolution of the alarm is a minute. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-8-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rx8025.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 617b044c66f0..6941e0518290 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -358,17 +358,6 @@ static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t) 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); @@ -579,8 +568,8 @@ static int rx8025_probe(struct i2c_client *client, 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 = devm_rtc_register_device(rx8025->rtc); if (err) -- cgit v1.2.3 From 1709d7eea1c6d7269eb85248dc8c3cacb8324d83 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:54 +0100 Subject: rtc: rx8025: set range Set the RTC range, it is a classic BCD RTC, with 00 being a leap year. Let the core handle range checking. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-9-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rx8025.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 6941e0518290..6002305efa2d 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. @@ -553,6 +550,8 @@ static int rx8025_probe(struct i2c_client *client, 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); -- cgit v1.2.3 From 5be3933fea2e9de50655f3cd3cda23184e8bf6bb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:55 +0100 Subject: rtc: rx8025: clear RTC_FEATURE_ALARM when alarm are not supported Clear RTC_FEATURE_ALARM to signal alarms are not supported to the core instead of checking client->irq. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-10-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rx8025.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 6002305efa2d..fcfdefe94a7c 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -315,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; @@ -352,9 +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; - ald[0] = bin2bcd(t->time.tm_min); if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) ald[1] = bin2bcd(t->time.tm_hour); @@ -559,10 +553,8 @@ 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; -- cgit v1.2.3 From 3d35840dfb75ac1a87dfbbddc9446b17446c2473 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:56 +0100 Subject: rtc: rx8025: use rtc_add_group Remove open coded sysfs registration by using rtc_add_group. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-11-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rx8025.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index fcfdefe94a7c..c5b3814f8c8e 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -502,15 +502,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) @@ -562,18 +561,11 @@ static int rx8025_probe(struct i2c_client *client, set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rx8025->rtc->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rx8025->rtc->features); - err = devm_rtc_register_device(rx8025->rtc); + err = rtc_add_group(rx8025->rtc, &rx8025_attr_group); if (err) return err; - err = rx8025_sysfs_register(&client->dev); - 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 = { @@ -581,7 +573,6 @@ static struct i2c_driver rx8025_driver = { .name = "rtc-rx8025", }, .probe = rx8025_probe, - .remove = rx8025_remove, .id_table = rx8025_id, }; -- cgit v1.2.3 From b476266f063e680039be1541cfde5f5cee400da3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 7 Nov 2021 23:54:57 +0100 Subject: rtc: rx8025: use .set_offset/.read_offset The driver has its own sysfs file to adjust the clock. Fortunately, it is already in pbb, however, the sign it expects is the opposite of what the RTC core does (which actually aligns with the RTC). Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20211107225458.111068-12-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rx8025.c | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 37 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index c5b3814f8c8e..5bfdd34a72ff 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -403,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: @@ -424,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; @@ -437,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; } -- cgit v1.2.3