From c254bcd7231a3eeafc453f6ee3a483a2e7ff486e Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Fri, 14 Aug 2020 19:17:30 +1000 Subject: rtc: cmos: zero-init wkalrm when reading from CMOS cmos_read_alarm() may leave certain fields of a struct rtc_wkalrm untouched; therefore, these fields contain garbage if not properly initialized, leading to inconsistent values when converting into time64_t. This patch to zero initialize the struct before calling cmos_read_alarm(). Note that this patch is not intended to produce a correct time64_t, it is only to produce a consistent value. In the case of suspend/resume, a correct time64_t is not necessary; a consistent value is sufficient to correctly perform an equality test for t_current_expires and t_saved_expires. Logic to deduce a correct time64_t is expensive and hence should be avoided. Signed-off-by: Victor Ding Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200814191654.v2.1.Iaf7638a2f2a87ff68d85fcb8dec615e41340c97f@changeid --- drivers/rtc/rtc-cmos.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index bcc96ab7793f..c633319cdb91 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -1006,6 +1006,7 @@ static int cmos_suspend(struct device *dev) enable_irq_wake(cmos->irq); } + memset(&cmos->saved_wkalrm, 0, sizeof(struct rtc_wkalrm)); cmos_read_alarm(dev, &cmos->saved_wkalrm); dev_dbg(dev, "suspend%s, ctrl %02x\n", @@ -1054,6 +1055,7 @@ static void cmos_check_wkalrm(struct device *dev) return; } + memset(¤t_alarm, 0, sizeof(struct rtc_wkalrm)); cmos_read_alarm(dev, ¤t_alarm); t_current_expires = rtc_tm_to_time64(¤t_alarm.time); t_saved_expires = rtc_tm_to_time64(&cmos->saved_wkalrm.time); -- cgit v1.2.3 From fc9656a370499e5a32425b715f8fed241e832458 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Aug 2020 13:07:29 +0200 Subject: rtc: rtc-rs5c313: Drop obsolete platform_set_drvdata() call Commit 284e2fa1da00a998 ("rtc: rtc-rs5c313: use devm_rtc_device_register()"), removed the last user of the driver-specific data. Hence there is no longer a need to set it. Signed-off-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200814110731.29029-2-geert+renesas@glider.be --- drivers/rtc/rtc-rs5c313.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index 89f38e3e917d..00b5ef753935 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -369,12 +369,7 @@ static int rs5c313_rtc_probe(struct platform_device *pdev) struct rtc_device *rtc = devm_rtc_device_register(&pdev->dev, "rs5c313", &rs5c313_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - platform_set_drvdata(pdev, rtc); - - return 0; + return PTR_ERR_OR_ZERO(rtc); } static struct platform_driver rs5c313_rtc_platform_driver = { -- cgit v1.2.3 From f65e727464d7c0090f05548e8f323779eaa97eda Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Aug 2020 13:07:30 +0200 Subject: rtc: rtc-rs5c313: Fix late hardware init rs5c313_rtc_init() calls platform_driver_register(), and initializes the hardware. This is wrong because of two reasons: 1. As soon as the driver has been registered, the device may be probed. If devm_rtc_device_register() is called before hardware initialization, reading the current time will fail: rs5c313 rs5c313: rs5c313_rtc_read_time: timeout error rs5c313 rs5c313: registered as rtc0 rs5c313 rs5c313: rs5c313_rtc_read_time: timeout error rs5c313 rs5c313: hctosys: unable to read the hardware clock 2. If the platform device does not exist, the driver will still write to a hardware device that may not be present. Fix this by moving the hardware initialization sequence to the driver's .probe() method. Signed-off-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200814110731.29029-3-geert+renesas@glider.be --- drivers/rtc/rtc-rs5c313.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index 00b5ef753935..af72e428b218 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -366,8 +366,13 @@ static const struct rtc_class_ops rs5c313_rtc_ops = { static int rs5c313_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc = devm_rtc_device_register(&pdev->dev, "rs5c313", - &rs5c313_rtc_ops, THIS_MODULE); + struct rtc_device *rtc; + + rs5c313_init_port(); + rs5c313_check_xstp_bit(); + + rtc = devm_rtc_device_register(&pdev->dev, "rs5c313", &rs5c313_rtc_ops, + THIS_MODULE); return PTR_ERR_OR_ZERO(rtc); } @@ -381,16 +386,7 @@ static struct platform_driver rs5c313_rtc_platform_driver = { static int __init rs5c313_rtc_init(void) { - int err; - - err = platform_driver_register(&rs5c313_rtc_platform_driver); - if (err) - return err; - - rs5c313_init_port(); - rs5c313_check_xstp_bit(); - - return 0; + return platform_driver_register(&rs5c313_rtc_platform_driver); } static void __exit rs5c313_rtc_exit(void) -- cgit v1.2.3 From 163a512cd929d6db712a3021720362749653998b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Aug 2020 13:07:31 +0200 Subject: rtc: rtc-rs5c313: Convert to module_platform_driver() Reduce boilerplate by using the module_platform_driver() helper. Signed-off-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200814110731.29029-4-geert+renesas@glider.be --- drivers/rtc/rtc-rs5c313.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index af72e428b218..e98f85f34206 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -384,18 +384,7 @@ static struct platform_driver rs5c313_rtc_platform_driver = { .probe = rs5c313_rtc_probe, }; -static int __init rs5c313_rtc_init(void) -{ - return platform_driver_register(&rs5c313_rtc_platform_driver); -} - -static void __exit rs5c313_rtc_exit(void) -{ - platform_driver_unregister(&rs5c313_rtc_platform_driver); -} - -module_init(rs5c313_rtc_init); -module_exit(rs5c313_rtc_exit); +module_platform_driver(rs5c313_rtc_platform_driver); MODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu "); MODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver"); -- cgit v1.2.3 From 59ed0127155201863db49f3dc5fb41316433340a Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Mon, 17 Aug 2020 11:57:31 +1200 Subject: rtc: ds1307: Ensure oscillator is enabled for DS1388 Similar to the other variants the DS1388 has a bit to stop the oscillator to reduce the power consumption from VBAT. Ensure that the oscillator is enabled when the system is up. Signed-off-by: Chris Packham Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200816235731.21071-1-chris.packham@alliedtelesis.co.nz --- drivers/rtc/rtc-ds1307.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 54c85cdd019d..2182f4e97c0a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -153,6 +153,7 @@ enum ds_type { #define DS1388_REG_CONTROL 0x0c # define DS1388_BIT_RST BIT(0) # define DS1388_BIT_WDE BIT(1) +# define DS1388_BIT_nEOSC BIT(7) /* negative offset step is -2.034ppm */ #define M41TXX_NEG_OFFSET_STEP_PPB 2034 @@ -1881,6 +1882,19 @@ static int ds1307_probe(struct i2c_client *client, DS1307_REG_HOUR << 4 | 0x08, hour); } break; + case ds_1388: + err = regmap_read(ds1307->regmap, DS1388_REG_CONTROL, &tmp); + if (err) { + dev_dbg(ds1307->dev, "read error %d\n", err); + goto exit; + } + + /* oscillator off? turn it on, so clock can tick. */ + if (tmp & DS1388_BIT_nEOSC) { + tmp &= ~DS1388_BIT_nEOSC; + regmap_write(ds1307->regmap, DS1388_REG_CONTROL, tmp); + } + break; default: break; } -- cgit v1.2.3 From f471b05f76e4b1b6ba07ebc7681920a5c5b97c5d Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Tue, 18 Aug 2020 13:35:43 +1200 Subject: rtc: ds1307: Clear OSF flag on DS1388 when setting time Ensure the OSF flag is cleared on the DS1388 when the clock is set. Fixes: df11b323b16f ("rtc: ds1307: handle oscillator failure flags for ds1388 variant") Signed-off-by: Chris Packham Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200818013543.4283-1-chris.packham@alliedtelesis.co.nz --- drivers/rtc/rtc-ds1307.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 2182f4e97c0a..8f4ddbaa2052 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -353,6 +353,10 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG, DS1340_BIT_OSF, 0); break; + case ds_1388: + regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG, + DS1388_BIT_OSF, 0); + break; case mcp794xx: /* * these bits were cleared when preparing the date/time -- cgit v1.2.3 From 0d982de3e27e8091dfa62368cd3eefbc7c17c8a2 Mon Sep 17 00:00:00 2001 From: Peng Ma Date: Tue, 18 Aug 2020 14:36:09 +0800 Subject: rtc: fsl-ftm-alarm: update acpi device id Original device id would conflict with crypto driver, change it. Signed-off-by: Peng Ma Signed-off-by: Ran Wang Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200818063609.39859-1-ran.wang_1@nxp.com --- drivers/rtc/rtc-fsl-ftm-alarm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c index 68f0a1801a2e..48d3b38ea348 100644 --- a/drivers/rtc/rtc-fsl-ftm-alarm.c +++ b/drivers/rtc/rtc-fsl-ftm-alarm.c @@ -3,7 +3,7 @@ * Freescale FlexTimer Module (FTM) alarm device driver. * * Copyright 2014 Freescale Semiconductor, Inc. - * Copyright 2019 NXP + * Copyright 2019-2020 NXP * */ @@ -312,7 +312,7 @@ static const struct of_device_id ftm_rtc_match[] = { }; static const struct acpi_device_id ftm_imx_acpi_ids[] = { - {"NXP0011",}, + {"NXP0014",}, { } }; MODULE_DEVICE_TABLE(acpi, ftm_imx_acpi_ids); -- cgit v1.2.3 From c52d270c68a02f94c5c081b7fc57119058e4670a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 30 Aug 2020 10:09:37 +0200 Subject: rtc: s3c: Simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and the error value gets printed. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200830080937.14367-1-krzk@kernel.org --- drivers/rtc/rtc-s3c.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e1b50e682fc4..24a41909f049 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -494,13 +494,8 @@ static int s3c_rtc_probe(struct platform_device *pdev) if (info->data->needs_src_clk) { info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src"); if (IS_ERR(info->rtc_src_clk)) { - ret = PTR_ERR(info->rtc_src_clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "failed to find rtc source clock\n"); - else - dev_dbg(&pdev->dev, - "probe deferred due to missing rtc src clk\n"); + ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk), + "failed to find rtc source clock\n"); goto err_src_clk; } ret = clk_prepare_enable(info->rtc_src_clk); -- cgit v1.2.3 From d3b14296da69adb7825022f3224ac6137eb30abf Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:48 +0200 Subject: rtc: rx8010: don't modify the global rtc ops The way the driver is implemented is buggy for the (admittedly unlikely) use case where there are two RTCs with one having an interrupt configured and the second not. This is caused by the fact that we use a global rtc_class_ops struct which we modify depending on whether the irq number is present or not. Fix it by using two const ops structs with and without alarm operations. While at it: not being able to request a configured interrupt is an error so don't ignore it and bail out of probe(). Fixes: ed13d89b08e3 ("rtc: Add Epson RX8010SJ RTC driver") Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200914154601.32245-2-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index fe010151ec8f..08c93d492494 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -407,16 +407,26 @@ static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) } } -static struct rtc_class_ops rx8010_rtc_ops = { +static const struct rtc_class_ops rx8010_rtc_ops_default = { .read_time = rx8010_get_time, .set_time = rx8010_set_time, .ioctl = rx8010_ioctl, }; +static const struct rtc_class_ops rx8010_rtc_ops_alarm = { + .read_time = rx8010_get_time, + .set_time = rx8010_set_time, + .ioctl = rx8010_ioctl, + .read_alarm = rx8010_read_alarm, + .set_alarm = rx8010_set_alarm, + .alarm_irq_enable = rx8010_alarm_irq_enable, +}; + static int rx8010_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; + const struct rtc_class_ops *rtc_ops; struct rx8010_data *rx8010; int err = 0; @@ -447,16 +457,16 @@ static int rx8010_probe(struct i2c_client *client, if (err) { dev_err(&client->dev, "unable to request IRQ\n"); - client->irq = 0; - } else { - rx8010_rtc_ops.read_alarm = rx8010_read_alarm; - rx8010_rtc_ops.set_alarm = rx8010_set_alarm; - rx8010_rtc_ops.alarm_irq_enable = rx8010_alarm_irq_enable; + return err; } + + rtc_ops = &rx8010_rtc_ops_alarm; + } else { + rtc_ops = &rx8010_rtc_ops_default; } rx8010->rtc = devm_rtc_device_register(&client->dev, client->name, - &rx8010_rtc_ops, THIS_MODULE); + rtc_ops, THIS_MODULE); if (IS_ERR(rx8010->rtc)) { dev_err(&client->dev, "unable to register the class device\n"); -- cgit v1.2.3 From 2e0ce569102ccb1ca9bacc499c8411fb8fa53069 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:49 +0200 Subject: rtc: rx8010: remove a stray newline Remove an unnecessary newline after requesting the interrupt. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-3-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 08c93d492494..c6797ec0aba1 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -454,7 +454,6 @@ static int rx8010_probe(struct i2c_client *client, rx8010_irq_1_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "rx8010", client); - if (err) { dev_err(&client->dev, "unable to request IRQ\n"); return err; -- cgit v1.2.3 From 28c86f30c979f9d4460dd7680610c3470b4d009b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:50 +0200 Subject: rtc: rx8010: remove unnecessary brackets Remove brackets wherever they guard a single line. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-4-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index c6797ec0aba1..79a3d90d2c43 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -181,9 +181,8 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) return ret; flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); - if (flagreg < 0) { + if (flagreg < 0) return flagreg; - } if (flagreg & RX8010_FLAG_VLF) ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, @@ -284,17 +283,15 @@ static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t) int err; flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); - if (flagreg < 0) { + if (flagreg < 0) return flagreg; - } if (rx8010->ctrlreg & (RX8010_CTRL_AIE | RX8010_CTRL_UIE)) { rx8010->ctrlreg &= ~(RX8010_CTRL_AIE | RX8010_CTRL_UIE); err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, rx8010->ctrlreg); - if (err < 0) { + if (err < 0) return err; - } } flagreg &= ~RX8010_FLAG_AF; -- cgit v1.2.3 From 75677971991940581e76bcd5176ea40d0baf8fcd Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:51 +0200 Subject: rtc: rx8010: consolidate local variables of the same type Move local variables of the same type into a single line for better readability. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-5-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 79a3d90d2c43..153fa58f0365 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -109,8 +109,7 @@ static int rx8010_get_time(struct device *dev, struct rtc_time *dt) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 date[7]; - int flagreg; - int err; + int flagreg, err; flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); if (flagreg < 0) @@ -141,8 +140,7 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 date[7]; - int ctrl, flagreg; - int ret; + int ctrl, flagreg, ret; if ((dt->tm_year < 100) || (dt->tm_year > 199)) return -EINVAL; @@ -250,8 +248,7 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t) struct rx8010_data *rx8010 = dev_get_drvdata(dev); struct i2c_client *client = rx8010->client; u8 alarmvals[3]; - int flagreg; - int err; + int flagreg, err; err = i2c_smbus_read_i2c_block_data(client, RX8010_ALMIN, 3, alarmvals); if (err != 3) @@ -279,8 +276,7 @@ static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t) struct i2c_client *client = to_i2c_client(dev); struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 alarmvals[3]; - int extreg, flagreg; - int err; + int extreg, flagreg, err; flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); if (flagreg < 0) @@ -346,9 +342,8 @@ static int rx8010_alarm_irq_enable(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct rx8010_data *rx8010 = dev_get_drvdata(dev); - int flagreg; + int flagreg, err; u8 ctrl; - int err; ctrl = rx8010->ctrlreg; @@ -387,8 +382,7 @@ static int rx8010_alarm_irq_enable(struct device *dev, static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); - int tmp; - int flagreg; + int tmp, flagreg; switch (cmd) { case RTC_VL_READ: -- cgit v1.2.3 From e9e4c2dae4313b88c62ee9df9d177a71c23121b2 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:52 +0200 Subject: rtc: rx8010: use tabs instead of spaces for code formatting The define values in this driver are close to their names and they are separated by spaces. Use tabs instead and align all defines. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-6-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 58 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 153fa58f0365..51ac4fac8f19 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -13,40 +13,40 @@ #include #include -#define RX8010_SEC 0x10 -#define RX8010_MIN 0x11 -#define RX8010_HOUR 0x12 -#define RX8010_WDAY 0x13 -#define RX8010_MDAY 0x14 -#define RX8010_MONTH 0x15 -#define RX8010_YEAR 0x16 -#define RX8010_RESV17 0x17 -#define RX8010_ALMIN 0x18 -#define RX8010_ALHOUR 0x19 -#define RX8010_ALWDAY 0x1A -#define RX8010_TCOUNT0 0x1B -#define RX8010_TCOUNT1 0x1C -#define RX8010_EXT 0x1D -#define RX8010_FLAG 0x1E -#define RX8010_CTRL 0x1F +#define RX8010_SEC 0x10 +#define RX8010_MIN 0x11 +#define RX8010_HOUR 0x12 +#define RX8010_WDAY 0x13 +#define RX8010_MDAY 0x14 +#define RX8010_MONTH 0x15 +#define RX8010_YEAR 0x16 +#define RX8010_RESV17 0x17 +#define RX8010_ALMIN 0x18 +#define RX8010_ALHOUR 0x19 +#define RX8010_ALWDAY 0x1A +#define RX8010_TCOUNT0 0x1B +#define RX8010_TCOUNT1 0x1C +#define RX8010_EXT 0x1D +#define RX8010_FLAG 0x1E +#define RX8010_CTRL 0x1F /* 0x20 to 0x2F are user registers */ -#define RX8010_RESV30 0x30 -#define RX8010_RESV31 0x31 -#define RX8010_IRQ 0x32 +#define RX8010_RESV30 0x30 +#define RX8010_RESV31 0x31 +#define RX8010_IRQ 0x32 -#define RX8010_EXT_WADA BIT(3) +#define RX8010_EXT_WADA BIT(3) -#define RX8010_FLAG_VLF BIT(1) -#define RX8010_FLAG_AF BIT(3) -#define RX8010_FLAG_TF BIT(4) -#define RX8010_FLAG_UF BIT(5) +#define RX8010_FLAG_VLF BIT(1) +#define RX8010_FLAG_AF BIT(3) +#define RX8010_FLAG_TF BIT(4) +#define RX8010_FLAG_UF BIT(5) -#define RX8010_CTRL_AIE BIT(3) -#define RX8010_CTRL_UIE BIT(5) -#define RX8010_CTRL_STOP BIT(6) -#define RX8010_CTRL_TEST BIT(7) +#define RX8010_CTRL_AIE BIT(3) +#define RX8010_CTRL_UIE BIT(5) +#define RX8010_CTRL_STOP BIT(6) +#define RX8010_CTRL_TEST BIT(7) -#define RX8010_ALARM_AE BIT(7) +#define RX8010_ALARM_AE BIT(7) static const struct i2c_device_id rx8010_id[] = { { "rx8010", 0 }, -- cgit v1.2.3 From 13952c9e35384fd7f63a5ce8261108695491bb56 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:53 +0200 Subject: rtc: rx8010: rename ret to err in rx8010_set_time() All other functions in this driver use 'err' for integer return values. Do the same in rx8010_set_time() for consistency. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-7-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 51ac4fac8f19..300314ab7b6d 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -140,7 +140,7 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 date[7]; - int ctrl, flagreg, ret; + int ctrl, flagreg, err; if ((dt->tm_year < 100) || (dt->tm_year > 199)) return -EINVAL; @@ -150,10 +150,10 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) if (ctrl < 0) return ctrl; rx8010->ctrlreg = ctrl | RX8010_CTRL_STOP; - ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, rx8010->ctrlreg); - if (ret < 0) - return ret; + if (err < 0) + return err; date[RX8010_SEC - RX8010_SEC] = bin2bcd(dt->tm_sec); date[RX8010_MIN - RX8010_SEC] = bin2bcd(dt->tm_min); @@ -163,27 +163,27 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) date[RX8010_YEAR - RX8010_SEC] = bin2bcd(dt->tm_year - 100); date[RX8010_WDAY - RX8010_SEC] = bin2bcd(1 << dt->tm_wday); - ret = i2c_smbus_write_i2c_block_data(rx8010->client, + err = i2c_smbus_write_i2c_block_data(rx8010->client, RX8010_SEC, 7, date); - if (ret < 0) - return ret; + if (err < 0) + return err; /* clear STOP bit after changing clock/calendar */ ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL); if (ctrl < 0) return ctrl; rx8010->ctrlreg = ctrl & ~RX8010_CTRL_STOP; - ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, rx8010->ctrlreg); - if (ret < 0) - return ret; + if (err < 0) + return err; flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); if (flagreg < 0) return flagreg; if (flagreg & RX8010_FLAG_VLF) - ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, + err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg & ~RX8010_FLAG_VLF); return 0; -- cgit v1.2.3 From f702699c67d315e4a232c64801b2de9af87fd9f4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:54 +0200 Subject: rtc: rx8010: don't use magic values for time buffer length The time buffer len is used directly in this driver. For readability it's better to define it as the difference between the date register offsets and use sizeof() whenever referencing it. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-8-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 300314ab7b6d..2c894e7aab6d 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -108,7 +108,7 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id) static int rx8010_get_time(struct device *dev, struct rtc_time *dt) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); - u8 date[7]; + u8 date[RX8010_YEAR - RX8010_SEC + 1]; int flagreg, err; flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); @@ -121,8 +121,8 @@ static int rx8010_get_time(struct device *dev, struct rtc_time *dt) } err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_SEC, - 7, date); - if (err != 7) + sizeof(date), date); + if (err != sizeof(date)) return err < 0 ? err : -EIO; dt->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f); @@ -139,7 +139,7 @@ static int rx8010_get_time(struct device *dev, struct rtc_time *dt) static int rx8010_set_time(struct device *dev, struct rtc_time *dt) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); - u8 date[7]; + u8 date[RX8010_YEAR - RX8010_SEC + 1]; int ctrl, flagreg, err; if ((dt->tm_year < 100) || (dt->tm_year > 199)) @@ -164,7 +164,8 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) date[RX8010_WDAY - RX8010_SEC] = bin2bcd(1 << dt->tm_wday); err = i2c_smbus_write_i2c_block_data(rx8010->client, - RX8010_SEC, 7, date); + RX8010_SEC, sizeof(date), + date); if (err < 0) return err; -- cgit v1.2.3 From b3ff7fd68d925de2159a5312f28dcd178d0d3715 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:55 +0200 Subject: rtc: rx8010: drop unnecessary initialization The 'err' local variable in rx8010_init_client() doesn't need to be initialized. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-9-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 2c894e7aab6d..64a9964eb5e0 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -194,7 +194,7 @@ static int rx8010_init_client(struct i2c_client *client) { struct rx8010_data *rx8010 = i2c_get_clientdata(client); u8 ctrl[2]; - int need_clear = 0, err = 0; + int need_clear = 0, err; /* Initialize reserved registers as specified in datasheet */ err = i2c_smbus_write_byte_data(client, RX8010_RESV17, 0xD8); -- cgit v1.2.3 From 955a123c14906e3adc43d43281f8fde91f631f7f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:56 +0200 Subject: rtc: rx8010: use a helper variable for client->dev in probe() Simple 'dev' looks better then repeated &client->dev and has the added benefit of avoiding unnecessary line breaks. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-10-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 64a9964eb5e0..dba7c3f87d9e 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -419,6 +419,7 @@ static int rx8010_probe(struct i2c_client *client, { struct i2c_adapter *adapter = client->adapter; const struct rtc_class_ops *rtc_ops; + struct device *dev = &client->dev; struct rx8010_data *rx8010; int err = 0; @@ -428,8 +429,7 @@ static int rx8010_probe(struct i2c_client *client, return -EIO; } - rx8010 = devm_kzalloc(&client->dev, sizeof(struct rx8010_data), - GFP_KERNEL); + rx8010 = devm_kzalloc(dev, sizeof(struct rx8010_data), GFP_KERNEL); if (!rx8010) return -ENOMEM; @@ -441,13 +441,13 @@ static int rx8010_probe(struct i2c_client *client, return err; if (client->irq > 0) { - dev_info(&client->dev, "IRQ %d supplied\n", client->irq); - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + dev_info(dev, "IRQ %d supplied\n", client->irq); + err = devm_request_threaded_irq(dev, client->irq, NULL, rx8010_irq_1_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "rx8010", client); if (err) { - dev_err(&client->dev, "unable to request IRQ\n"); + dev_err(dev, "unable to request IRQ\n"); return err; } @@ -456,11 +456,10 @@ static int rx8010_probe(struct i2c_client *client, rtc_ops = &rx8010_rtc_ops_default; } - rx8010->rtc = devm_rtc_device_register(&client->dev, client->name, + rx8010->rtc = devm_rtc_device_register(dev, client->name, rtc_ops, THIS_MODULE); - if (IS_ERR(rx8010->rtc)) { - dev_err(&client->dev, "unable to register the class device\n"); + dev_err(dev, "unable to register the class device\n"); return PTR_ERR(rx8010->rtc); } -- cgit v1.2.3 From 666f21413b881e159efaf862f119d4d058fa2c4a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:57 +0200 Subject: rtc: rx8010: prefer sizeof(*val) over sizeof(struct type_of_val) Using the size of the variable is preferred over using the size of its type when allocating memory. Convert the call to devm_kzalloc() in probe(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-11-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index dba7c3f87d9e..aa357f800ad4 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -429,7 +429,7 @@ static int rx8010_probe(struct i2c_client *client, return -EIO; } - rx8010 = devm_kzalloc(dev, sizeof(struct rx8010_data), GFP_KERNEL); + rx8010 = devm_kzalloc(dev, sizeof(*rx8010), GFP_KERNEL); if (!rx8010) return -ENOMEM; -- cgit v1.2.3 From 0ce627785afa730d8f6568eb8738d1700cbc4569 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:58 +0200 Subject: rtc: rx8010: switch to using the preferred RTC API Use devm_rtc_allocate_device() + rtc_register_device() instead of the deprecated devm_rtc_device_register(). Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-12-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index aa357f800ad4..6aeed3802670 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -418,7 +418,6 @@ static int rx8010_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; - const struct rtc_class_ops *rtc_ops; struct device *dev = &client->dev; struct rx8010_data *rx8010; int err = 0; @@ -440,6 +439,10 @@ static int rx8010_probe(struct i2c_client *client, if (err) return err; + rx8010->rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rx8010->rtc)) + return PTR_ERR(rx8010->rtc); + if (client->irq > 0) { dev_info(dev, "IRQ %d supplied\n", client->irq); err = devm_request_threaded_irq(dev, client->irq, NULL, @@ -451,21 +454,14 @@ static int rx8010_probe(struct i2c_client *client, return err; } - rtc_ops = &rx8010_rtc_ops_alarm; + rx8010->rtc->ops = &rx8010_rtc_ops_alarm; } else { - rtc_ops = &rx8010_rtc_ops_default; - } - - rx8010->rtc = devm_rtc_device_register(dev, client->name, - rtc_ops, THIS_MODULE); - if (IS_ERR(rx8010->rtc)) { - dev_err(dev, "unable to register the class device\n"); - return PTR_ERR(rx8010->rtc); + rx8010->rtc->ops = &rx8010_rtc_ops_default; } rx8010->rtc->max_user_freq = 1; - return 0; + return rtc_register_device(rx8010->rtc); } static struct i2c_driver rx8010_driver = { -- cgit v1.2.3 From cee015d90d96495d8376871af0f1a33027303d5e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:45:59 +0200 Subject: rtc: rx8010: switch to using the preferred i2c API We should generally use probe_new instead of probe when registering i2c drivers. Convert rx8010 to using it. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-13-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 6aeed3802670..3c82f7d48a65 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -414,8 +414,7 @@ static const struct rtc_class_ops rx8010_rtc_ops_alarm = { .alarm_irq_enable = rx8010_alarm_irq_enable, }; -static int rx8010_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rx8010_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -469,7 +468,7 @@ static struct i2c_driver rx8010_driver = { .name = "rtc-rx8010", .of_match_table = of_match_ptr(rx8010_of_match), }, - .probe = rx8010_probe, + .probe_new = rx8010_probe, .id_table = rx8010_id, }; -- cgit v1.2.3 From 9868bc1ce272dc0387488e779c585e7a12cf7a1b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:46:00 +0200 Subject: rtc: rx8010: convert to using regmap This driver requires SMBUS to work. We can relax this requirement if we switch to using i2c regmap and let the regmap sub-system figure out how to talk to the bus. This also has the advantage of shrinking the code for register updates. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-14-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 198 +++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 3c82f7d48a65..b8aa98fb62de 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #define RX8010_SEC 0x10 @@ -61,7 +62,7 @@ static const struct of_device_id rx8010_of_match[] = { MODULE_DEVICE_TABLE(of, rx8010_of_match); struct rx8010_data { - struct i2c_client *client; + struct regmap *regs; struct rtc_device *rtc; u8 ctrlreg; }; @@ -70,13 +71,12 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8010_data *rx8010 = i2c_get_clientdata(client); - int flagreg; + int flagreg, err; mutex_lock(&rx8010->rtc->ops_lock); - flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); - - if (flagreg <= 0) { + err = regmap_read(rx8010->regs, RX8010_FLAG, &flagreg); + if (err) { mutex_unlock(&rx8010->rtc->ops_lock); return IRQ_NONE; } @@ -99,10 +99,9 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id) rtc_update_irq(rx8010->rtc, 1, RTC_UF | RTC_IRQF); } - i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg); - + err = regmap_write(rx8010->regs, RX8010_FLAG, flagreg); mutex_unlock(&rx8010->rtc->ops_lock); - return IRQ_HANDLED; + return err ? IRQ_NONE : IRQ_HANDLED; } static int rx8010_get_time(struct device *dev, struct rtc_time *dt) @@ -111,19 +110,18 @@ static int rx8010_get_time(struct device *dev, struct rtc_time *dt) u8 date[RX8010_YEAR - RX8010_SEC + 1]; int flagreg, err; - flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); - if (flagreg < 0) - return flagreg; + err = regmap_read(rx8010->regs, RX8010_FLAG, &flagreg); + if (err) + return err; if (flagreg & RX8010_FLAG_VLF) { dev_warn(dev, "Frequency stop detected\n"); return -EINVAL; } - err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_SEC, - sizeof(date), date); - if (err != sizeof(date)) - return err < 0 ? err : -EIO; + err = regmap_bulk_read(rx8010->regs, RX8010_SEC, date, sizeof(date)); + if (err) + return err; dt->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f); dt->tm_min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f); @@ -140,19 +138,14 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 date[RX8010_YEAR - RX8010_SEC + 1]; - int ctrl, flagreg, err; + int err; if ((dt->tm_year < 100) || (dt->tm_year > 199)) return -EINVAL; /* set STOP bit before changing clock/calendar */ - ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL); - if (ctrl < 0) - return ctrl; - rx8010->ctrlreg = ctrl | RX8010_CTRL_STOP; - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, - rx8010->ctrlreg); - if (err < 0) + err = regmap_set_bits(rx8010->regs, RX8010_CTRL, RX8010_CTRL_STOP); + if (err) return err; date[RX8010_SEC - RX8010_SEC] = bin2bcd(dt->tm_sec); @@ -163,66 +156,54 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) date[RX8010_YEAR - RX8010_SEC] = bin2bcd(dt->tm_year - 100); date[RX8010_WDAY - RX8010_SEC] = bin2bcd(1 << dt->tm_wday); - err = i2c_smbus_write_i2c_block_data(rx8010->client, - RX8010_SEC, sizeof(date), - date); - if (err < 0) + err = regmap_bulk_write(rx8010->regs, RX8010_SEC, date, sizeof(date)); + if (err) return err; /* clear STOP bit after changing clock/calendar */ - ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL); - if (ctrl < 0) - return ctrl; - rx8010->ctrlreg = ctrl & ~RX8010_CTRL_STOP; - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, - rx8010->ctrlreg); - if (err < 0) + err = regmap_clear_bits(rx8010->regs, RX8010_CTRL, RX8010_CTRL_STOP); + if (err) return err; - flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); - if (flagreg < 0) - return flagreg; - - if (flagreg & RX8010_FLAG_VLF) - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, - flagreg & ~RX8010_FLAG_VLF); + err = regmap_clear_bits(rx8010->regs, RX8010_FLAG, RX8010_FLAG_VLF); + if (err) + return err; return 0; } -static int rx8010_init_client(struct i2c_client *client) +static int rx8010_init_client(struct device *dev) { - struct rx8010_data *rx8010 = i2c_get_clientdata(client); + struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 ctrl[2]; int need_clear = 0, err; /* Initialize reserved registers as specified in datasheet */ - err = i2c_smbus_write_byte_data(client, RX8010_RESV17, 0xD8); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_RESV17, 0xD8); + if (err) return err; - err = i2c_smbus_write_byte_data(client, RX8010_RESV30, 0x00); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_RESV30, 0x00); + if (err) return err; - err = i2c_smbus_write_byte_data(client, RX8010_RESV31, 0x08); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_RESV31, 0x08); + if (err) return err; - err = i2c_smbus_write_byte_data(client, RX8010_IRQ, 0x00); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_IRQ, 0x00); + if (err) return err; - err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_FLAG, - 2, ctrl); - if (err != 2) - return err < 0 ? err : -EIO; + err = regmap_bulk_read(rx8010->regs, RX8010_FLAG, ctrl, 2); + if (err) + return err; if (ctrl[0] & RX8010_FLAG_VLF) - dev_warn(&client->dev, "Frequency stop was detected\n"); + dev_warn(dev, "Frequency stop was detected\n"); if (ctrl[0] & RX8010_FLAG_AF) { - dev_warn(&client->dev, "Alarm was detected\n"); + dev_warn(dev, "Alarm was detected\n"); need_clear = 1; } @@ -234,8 +215,8 @@ static int rx8010_init_client(struct i2c_client *client) if (need_clear) { ctrl[0] &= ~(RX8010_FLAG_AF | RX8010_FLAG_TF | RX8010_FLAG_UF); - err = i2c_smbus_write_byte_data(client, RX8010_FLAG, ctrl[0]); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_FLAG, ctrl[0]); + if (err) return err; } @@ -247,17 +228,16 @@ static int rx8010_init_client(struct i2c_client *client) static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); - struct i2c_client *client = rx8010->client; u8 alarmvals[3]; int flagreg, err; - err = i2c_smbus_read_i2c_block_data(client, RX8010_ALMIN, 3, alarmvals); - if (err != 3) - return err < 0 ? err : -EIO; + err = regmap_bulk_read(rx8010->regs, RX8010_ALMIN, alarmvals, 3); + if (err) + return err; - flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); - if (flagreg < 0) - return flagreg; + err = regmap_read(rx8010->regs, RX8010_FLAG, &flagreg); + if (err) + return err; t->time.tm_sec = 0; t->time.tm_min = bcd2bin(alarmvals[0] & 0x7f); @@ -274,52 +254,38 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t) static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 alarmvals[3]; - int extreg, flagreg, err; - - flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); - if (flagreg < 0) - return flagreg; + int err; if (rx8010->ctrlreg & (RX8010_CTRL_AIE | RX8010_CTRL_UIE)) { rx8010->ctrlreg &= ~(RX8010_CTRL_AIE | RX8010_CTRL_UIE); - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, - rx8010->ctrlreg); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_CTRL, rx8010->ctrlreg); + if (err) return err; } - flagreg &= ~RX8010_FLAG_AF; - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg); - if (err < 0) + err = regmap_clear_bits(rx8010->regs, RX8010_FLAG, RX8010_FLAG_AF); + if (err) return err; alarmvals[0] = bin2bcd(t->time.tm_min); alarmvals[1] = bin2bcd(t->time.tm_hour); alarmvals[2] = bin2bcd(t->time.tm_mday); - err = i2c_smbus_write_i2c_block_data(rx8010->client, RX8010_ALMIN, - 2, alarmvals); - if (err < 0) + err = regmap_bulk_write(rx8010->regs, RX8010_ALMIN, alarmvals, 2); + if (err) return err; - extreg = i2c_smbus_read_byte_data(client, RX8010_EXT); - if (extreg < 0) - return extreg; - - extreg |= RX8010_EXT_WADA; - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_EXT, extreg); - if (err < 0) + err = regmap_clear_bits(rx8010->regs, RX8010_EXT, RX8010_EXT_WADA); + if (err) return err; if (alarmvals[2] == 0) alarmvals[2] |= RX8010_ALARM_AE; - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_ALWDAY, - alarmvals[2]); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_ALWDAY, alarmvals[2]); + if (err) return err; if (t->enabled) { @@ -329,9 +295,8 @@ static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t) rx8010->ctrlreg |= (RX8010_CTRL_AIE | RX8010_CTRL_UIE); - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, - rx8010->ctrlreg); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_CTRL, rx8010->ctrlreg); + if (err) return err; } @@ -341,9 +306,8 @@ static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t) static int rx8010_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct i2c_client *client = to_i2c_client(dev); struct rx8010_data *rx8010 = dev_get_drvdata(dev); - int flagreg, err; + int err; u8 ctrl; ctrl = rx8010->ctrlreg; @@ -360,20 +324,14 @@ static int rx8010_alarm_irq_enable(struct device *dev, ctrl &= ~RX8010_CTRL_AIE; } - flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG); - if (flagreg < 0) - return flagreg; - - flagreg &= ~RX8010_FLAG_AF; - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg); - if (err < 0) + err = regmap_clear_bits(rx8010->regs, RX8010_FLAG, RX8010_FLAG_AF); + if (err) return err; if (ctrl != rx8010->ctrlreg) { rx8010->ctrlreg = ctrl; - err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL, - rx8010->ctrlreg); - if (err < 0) + err = regmap_write(rx8010->regs, RX8010_CTRL, rx8010->ctrlreg); + if (err) return err; } @@ -383,13 +341,13 @@ static int rx8010_alarm_irq_enable(struct device *dev, static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); - int tmp, flagreg; + int tmp, flagreg, err; switch (cmd) { case RTC_VL_READ: - flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG); - if (flagreg < 0) - return flagreg; + err = regmap_read(rx8010->regs, RX8010_FLAG, &flagreg); + if (err) + return err; tmp = flagreg & RX8010_FLAG_VLF ? RTC_VL_DATA_INVALID : 0; return put_user(tmp, (unsigned int __user *)arg); @@ -414,27 +372,29 @@ static const struct rtc_class_ops rx8010_rtc_ops_alarm = { .alarm_irq_enable = rx8010_alarm_irq_enable, }; +static const struct regmap_config rx8010_regmap_config = { + .name = "rx8010-rtc", + .reg_bits = 8, + .val_bits = 8, +}; + static int rx8010_probe(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; struct rx8010_data *rx8010; int err = 0; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_I2C_BLOCK)) { - dev_err(&adapter->dev, "doesn't support required functionality\n"); - return -EIO; - } - rx8010 = devm_kzalloc(dev, sizeof(*rx8010), GFP_KERNEL); if (!rx8010) return -ENOMEM; - rx8010->client = client; i2c_set_clientdata(client, rx8010); - err = rx8010_init_client(client); + rx8010->regs = devm_regmap_init_i2c(client, &rx8010_regmap_config); + if (IS_ERR(rx8010->regs)) + return PTR_ERR(rx8010->regs); + + err = rx8010_init_client(dev); if (err) return err; -- cgit v1.2.3 From 2fc1af3095af5cbcd8fc406610dc196b62e3ed21 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 14 Sep 2020 17:46:01 +0200 Subject: rtc: rx8010: use range checking provided by core RTC code We don't need to check the time range manually in set_time(), we can use range_min and range_max exposed by struct rtc_device. Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200914154601.32245-15-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index b8aa98fb62de..01e9017d4025 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -140,9 +140,6 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) u8 date[RX8010_YEAR - RX8010_SEC + 1]; int err; - if ((dt->tm_year < 100) || (dt->tm_year > 199)) - return -EINVAL; - /* set STOP bit before changing clock/calendar */ err = regmap_set_bits(rx8010->regs, RX8010_CTRL, RX8010_CTRL_STOP); if (err) @@ -419,6 +416,8 @@ static int rx8010_probe(struct i2c_client *client) } rx8010->rtc->max_user_freq = 1; + rx8010->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rx8010->rtc->range_max = RTC_TIMESTAMP_END_2099; return rtc_register_device(rx8010->rtc); } -- cgit v1.2.3 From d0a3b65052f041852c855ea1135659770ba0bc09 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 13 Sep 2020 14:26:44 +0200 Subject: rtc: st-lpc: Constify st_rtc_ops The only usage of st_rtc_ops is to assign its address to the ops field in the rtc_device struct. which is a const pointer. Make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200913122644.35515-1-rikard.falkeborn@gmail.com --- drivers/rtc/rtc-st-lpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c index 51041dc08af4..0c65448b85ee 100644 --- a/drivers/rtc/rtc-st-lpc.c +++ b/drivers/rtc/rtc-st-lpc.c @@ -173,7 +173,7 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -static struct rtc_class_ops st_rtc_ops = { +static const struct rtc_class_ops st_rtc_ops = { .read_time = st_rtc_read_time, .set_time = st_rtc_set_time, .read_alarm = st_rtc_read_alarm, -- cgit v1.2.3 From 9f8010e71f091b0609452742cfed4650ee633c44 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Thu, 10 Sep 2020 10:41:24 +0200 Subject: rtc: ds1685: Fix bank switching to avoid endless loop ds1685_rtc_begin_data_access() tried to access an extended register before enabling access to it by switching to bank 1. Depending on content in NVRAM this could lead to an endless loop. While at it fix also switch back to bank 0 in ds1685_rtc_end_data_access(). Signed-off-by: Thomas Bogendoerfer Signed-off-by: Alexandre Belloni Acked-by: Joshua Kinard Link: https://lore.kernel.org/r/20200910084124.138560-1-tsbogend@alpha.franken.de --- drivers/rtc/rtc-ds1685.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 56c670af2e50..dfbd7b88b2b9 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -193,12 +193,12 @@ ds1685_rtc_begin_data_access(struct ds1685_priv *rtc) rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) | RTC_CTRL_B_SET)); + /* Switch to Bank 1 */ + ds1685_rtc_switch_to_bank1(rtc); + /* Read Ext Ctrl 4A and check the INCR bit to avoid a lockout. */ while (rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_INCR) cpu_relax(); - - /* Switch to Bank 1 */ - ds1685_rtc_switch_to_bank1(rtc); } /** @@ -213,7 +213,7 @@ static inline void ds1685_rtc_end_data_access(struct ds1685_priv *rtc) { /* Switch back to Bank 0 */ - ds1685_rtc_switch_to_bank1(rtc); + ds1685_rtc_switch_to_bank0(rtc); /* Clear the SET bit in Ctrl B */ rtc->write(rtc, RTC_CTRL_B, -- cgit v1.2.3 From 35425bafc772ee189e3c3790d7c672b80ba65909 Mon Sep 17 00:00:00 2001 From: Biwen Li Date: Tue, 15 Sep 2020 15:32:09 +0800 Subject: rtc: pcf2127: fix a bug when not specify interrupts property Fix a bug when not specify interrupts property in dts as follows, rtc-pcf2127-i2c 1-0051: failed to request alarm irq rtc-pcf2127-i2c: probe of 1-0051 failed with error -22 Signed-off-by: Biwen Li Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200915073213.12779-1-biwen.li@oss.nxp.com --- drivers/rtc/rtc-pcf2127.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index ed6316992cbb..07a5630ec841 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -559,7 +559,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */ pcf2127->rtc->uie_unsupported = 1; - if (alarm_irq >= 0) { + if (alarm_irq > 0) { ret = devm_request_threaded_irq(dev, alarm_irq, NULL, pcf2127_rtc_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, @@ -570,7 +570,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, } } - if (alarm_irq >= 0 || device_property_read_bool(dev, "wakeup-source")) { + if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) { device_init_wakeup(dev, true); pcf2127->rtc->ops = &pcf2127_rtc_alrm_ops; } -- cgit v1.2.3 From 462eb736db3db76899022e4e4db788a7b6efbe09 Mon Sep 17 00:00:00 2001 From: Bastian Krause Date: Thu, 17 Sep 2020 20:32:42 +0200 Subject: rtc: ds1307: apply DS13XX_TRICKLE_CHARGER_MAGIC only conditionally DS13XX_TRICKLE_CHARGER_MAGIC sets the trickle-charge select (TCS) bits (7..4). The datasheet of Maxim Integrated's DS1339 [1] for instance reads: "To prevent accidental enabling, only a pattern on 1010 enables the trickle charger. All other patterns disable the trickle charger." Since not all RTCs connected to a backup battery or supercap use these bits DS13XX_TRICKLE_CHARGER_MAGIC should not get applied for all charger setups unconditionally. Epson's RX8130 is such an example: Instead of TCS bits "SMPTSEL1", "SMPTSEL0", "CHGEN" and "INIEN" are expected as bit 7..4. DS1339 and DS1340 are currently the only RTCs in the ds1307 driver that apply DS13XX_TRICKLE_CHARGER_MAGIC to their setup register value. So apply DS13XX_TRICKLE_CHARGER_MAGIC in do_trickle_setup_ds1339() which is used by both RTCs. [1] https://datasheets.maximintegrated.com/en/ds/DS1339-DS1339U.pdf [2] https://support.epson.biz/td/api/doc_check.php?dl=app_RX8130CE Signed-off-by: Bastian Krause Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200917183246.19446-5-bst@pengutronix.de --- drivers/rtc/rtc-ds1307.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 8f4ddbaa2052..82f75a798705 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -512,6 +512,8 @@ static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307, u32 ohms, bool diode) u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE : DS1307_TRICKLE_CHARGER_NO_DIODE; + setup |= DS13XX_TRICKLE_CHARGER_MAGIC; + switch (ohms) { case 250: setup |= DS1307_TRICKLE_CHARGER_250_OHM; @@ -1763,7 +1765,6 @@ static int ds1307_probe(struct i2c_client *client, trickle_charger_setup = pdata->trickle_charger_setup; if (trickle_charger_setup && chip->trickle_charger_reg) { - trickle_charger_setup |= DS13XX_TRICKLE_CHARGER_MAGIC; dev_dbg(ds1307->dev, "writing trickle charger info 0x%x to 0x%x\n", trickle_charger_setup, chip->trickle_charger_reg); -- cgit v1.2.3 From 1b5b6af788ae59ee73e3f3230dbfa4f0e31d8d18 Mon Sep 17 00:00:00 2001 From: Bastian Krause Date: Thu, 17 Sep 2020 20:32:43 +0200 Subject: rtc: ds1307: introduce requires_trickle_resistor per chip Make trickle-resistor-ohms optional for charging setups that do not require specifying ROUT bits (specifying the resistor value between Vcc and Vbackup). In order to allow specifying that, introduce requires_trickle_resistor per chip. Signed-off-by: Bastian Krause Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200917183246.19446-6-bst@pengutronix.de --- drivers/rtc/rtc-ds1307.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 82f75a798705..64fa1318817c 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -191,6 +191,10 @@ struct chip_desc { u16 trickle_charger_reg; u8 (*do_trickle_setup)(struct ds1307 *, u32, bool); + /* Does the RTC require trickle-resistor-ohms to select the value of + * the resistor between Vcc and Vbackup? + */ + bool requires_trickle_resistor; }; static const struct chip_desc chips[last_ds_type]; @@ -986,6 +990,7 @@ static const struct chip_desc chips[last_ds_type] = { .bbsqi_bit = DS1339_BIT_BBSQI, .trickle_charger_reg = 0x10, .do_trickle_setup = &do_trickle_setup_ds1339, + .requires_trickle_resistor = true, }, [ds_1340] = { .century_reg = DS1307_REG_HOUR, @@ -993,6 +998,7 @@ static const struct chip_desc chips[last_ds_type] = { .century_bit = DS1340_BIT_CENTURY, .do_trickle_setup = &do_trickle_setup_ds1339, .trickle_charger_reg = 0x08, + .requires_trickle_resistor = true, }, [ds_1341] = { .century_reg = DS1307_REG_MONTH, @@ -1307,7 +1313,7 @@ static u8 ds1307_trickle_init(struct ds1307 *ds1307, return 0; if (device_property_read_u32(ds1307->dev, "trickle-resistor-ohms", - &ohms)) + &ohms) && chip->requires_trickle_resistor) return 0; if (device_property_read_bool(ds1307->dev, "trickle-diode-disable")) -- cgit v1.2.3 From 95a74cbb21a2431dd2fd8918fa26113629b6e13e Mon Sep 17 00:00:00 2001 From: Bastian Krause Date: Thu, 17 Sep 2020 20:32:44 +0200 Subject: rtc: ds1307: store previous charge default per chip Some RTC's batteries and supercaps were charged by default until now. In contrast other RTCs allow charging but the driver did not configure them to do so until now. These must not be charged by default to stay backwards compatible. In order to do that, store the charge default per chip. Signed-off-by: Bastian Krause Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200917183246.19446-7-bst@pengutronix.de --- drivers/rtc/rtc-ds1307.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 64fa1318817c..fdd6f9fda6f9 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -195,6 +195,11 @@ struct chip_desc { * the resistor between Vcc and Vbackup? */ bool requires_trickle_resistor; + /* Some RTC's batteries and supercaps were charged by default, others + * allow charging but were not configured previously to do so. + * Remember this behavior to stay backwards compatible. + */ + bool charge_default; }; static const struct chip_desc chips[last_ds_type]; @@ -991,6 +996,7 @@ static const struct chip_desc chips[last_ds_type] = { .trickle_charger_reg = 0x10, .do_trickle_setup = &do_trickle_setup_ds1339, .requires_trickle_resistor = true, + .charge_default = true, }, [ds_1340] = { .century_reg = DS1307_REG_HOUR, @@ -999,6 +1005,7 @@ static const struct chip_desc chips[last_ds_type] = { .do_trickle_setup = &do_trickle_setup_ds1339, .trickle_charger_reg = 0x08, .requires_trickle_resistor = true, + .charge_default = true, }, [ds_1341] = { .century_reg = DS1307_REG_MONTH, @@ -1307,7 +1314,7 @@ static u8 ds1307_trickle_init(struct ds1307 *ds1307, const struct chip_desc *chip) { u32 ohms; - bool diode = true; + bool diode = chip->charge_default; if (!chip->do_trickle_setup) return 0; -- cgit v1.2.3 From 0874734e09af5cc05439dbe2c8ff704f14d679f5 Mon Sep 17 00:00:00 2001 From: Bastian Krause Date: Thu, 17 Sep 2020 20:32:45 +0200 Subject: rtc: ds1307: consider aux-voltage-chargeable Prefer aux-voltage-chargeable over trickle-diode-disable and set diode accordingly. This is then passed to the chip's appropriate charge setup function. Signed-off-by: Bastian Krause Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200917183246.19446-8-bst@pengutronix.de --- drivers/rtc/rtc-ds1307.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index fdd6f9fda6f9..03e166d2b0f8 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1313,7 +1313,7 @@ static int ds1307_nvram_write(void *priv, unsigned int offset, void *val, static u8 ds1307_trickle_init(struct ds1307 *ds1307, const struct chip_desc *chip) { - u32 ohms; + u32 ohms, chargeable; bool diode = chip->charge_default; if (!chip->do_trickle_setup) @@ -1323,8 +1323,27 @@ static u8 ds1307_trickle_init(struct ds1307 *ds1307, &ohms) && chip->requires_trickle_resistor) return 0; - if (device_property_read_bool(ds1307->dev, "trickle-diode-disable")) + /* aux-voltage-chargeable takes precedence over the deprecated + * trickle-diode-disable + */ + if (!device_property_read_u32(ds1307->dev, "aux-voltage-chargeable", + &chargeable)) { + switch (chargeable) { + case 0: + diode = false; + break; + case 1: + diode = true; + break; + default: + dev_warn(ds1307->dev, + "unsupported aux-voltage-chargeable value\n"); + break; + } + } else if (device_property_read_bool(ds1307->dev, + "trickle-diode-disable")) { diode = false; + } return chip->do_trickle_setup(ds1307, ohms, diode); } -- cgit v1.2.3 From 0026f1604c9ba1ae8108d4977da0366c283552bc Mon Sep 17 00:00:00 2001 From: Bastian Krause Date: Thu, 17 Sep 2020 20:32:46 +0200 Subject: rtc: ds1307: enable rx8130's backup battery, make it chargeable optionally The ds1307 charger infrastructure now allows to add a rx8130 charger setup that.. - does not depend on trickle-resistor-ohms - does not use DS13XX_TRICKLE_CHARGER_MAGIC trickle-charge select (TCS) bits - keeps previous no-charge behavior for device trees without aux-voltage-chargeable Make that happen. Signed-off-by: Bastian Krause Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200917183246.19446-9-bst@pengutronix.de --- drivers/rtc/rtc-ds1307.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 03e166d2b0f8..9f5f54ca039d 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -122,6 +122,9 @@ enum ds_type { #define RX8130_REG_FLAG_AF BIT(3) #define RX8130_REG_CONTROL0 0x1e #define RX8130_REG_CONTROL0_AIE BIT(3) +#define RX8130_REG_CONTROL1 0x1f +#define RX8130_REG_CONTROL1_INIEN BIT(4) +#define RX8130_REG_CONTROL1_CHGEN BIT(5) #define MCP794XX_REG_CONTROL 0x07 # define MCP794XX_BIT_ALM0_EN 0x10 @@ -541,6 +544,16 @@ static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307, u32 ohms, bool diode) return setup; } +static u8 do_trickle_setup_rx8130(struct ds1307 *ds1307, u32 ohms, bool diode) +{ + /* make sure that the backup battery is enabled */ + u8 setup = RX8130_REG_CONTROL1_INIEN; + if (diode) + setup |= RX8130_REG_CONTROL1_CHGEN; + + return setup; +} + static irqreturn_t rx8130_irq(int irq, void *dev_id) { struct ds1307 *ds1307 = dev_id; @@ -1029,6 +1042,8 @@ static const struct chip_desc chips[last_ds_type] = { .offset = 0x10, .irq_handler = rx8130_irq, .rtc_ops = &rx8130_rtc_ops, + .trickle_charger_reg = RX8130_REG_CONTROL1, + .do_trickle_setup = &do_trickle_setup_rx8130, }, [m41t0] = { .rtc_ops = &m41txx_rtc_ops, -- cgit v1.2.3 From ba1bcafb29571f525bf563972e4241998db74e98 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 17 Sep 2020 13:46:56 +0200 Subject: rtc: rx8010: rename rx8010_init_client() to rx8010_init() Since the switch to using regmap this function no longer takes the I2C client struct as argument nor do we even interact with the client anywhere other than when creating the regmap. Rename it to a less misleading name: "rx8010_init()". Signed-off-by: Bartosz Golaszewski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200917114656.9036-1-brgl@bgdev.pl --- drivers/rtc/rtc-rx8010.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index 01e9017d4025..dca41a2a39b2 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -169,7 +169,7 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt) return 0; } -static int rx8010_init_client(struct device *dev) +static int rx8010_init(struct device *dev) { struct rx8010_data *rx8010 = dev_get_drvdata(dev); u8 ctrl[2]; @@ -391,7 +391,7 @@ static int rx8010_probe(struct i2c_client *client) if (IS_ERR(rx8010->regs)) return PTR_ERR(rx8010->regs); - err = rx8010_init_client(dev); + err = rx8010_init(dev); if (err) return err; -- cgit v1.2.3 From 9ce42e8e0323d39fad01f3d17c35dd16d91c4f46 Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Sat, 19 Sep 2020 18:08:56 +0800 Subject: rtc: meson: simplify the return expression of meson_vrtc_probe Simplify the return expression. Signed-off-by: Liu Shixin Signed-off-by: Alexandre Belloni Acked-by: Kevin Hilman Link: https://lore.kernel.org/r/20200919100856.1639319-1-liushixin2@huawei.com --- drivers/rtc/rtc-meson-vrtc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-meson-vrtc.c b/drivers/rtc/rtc-meson-vrtc.c index 89e5ba0dae69..e6bd0808a092 100644 --- a/drivers/rtc/rtc-meson-vrtc.c +++ b/drivers/rtc/rtc-meson-vrtc.c @@ -65,7 +65,6 @@ static const struct rtc_class_ops meson_vrtc_ops = { static int meson_vrtc_probe(struct platform_device *pdev) { struct meson_vrtc_data *vrtc; - int ret; vrtc = devm_kzalloc(&pdev->dev, sizeof(*vrtc), GFP_KERNEL); if (!vrtc) @@ -84,11 +83,7 @@ static int meson_vrtc_probe(struct platform_device *pdev) return PTR_ERR(vrtc->rtc); vrtc->rtc->ops = &meson_vrtc_ops; - ret = rtc_register_device(vrtc->rtc); - if (ret) - return ret; - - return 0; + return rtc_register_device(vrtc->rtc); } static int __maybe_unused meson_vrtc_suspend(struct device *dev) -- cgit v1.2.3 From 179b4bcc4c0cf62e3737c718e05f5a69b3e9041c Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Mon, 21 Sep 2020 16:24:49 +0800 Subject: rtc: rv8803: simplify the return expression of rv8803_nvram_write Simplify the return expression. Signed-off-by: Liu Shixin Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20200921082449.2591981-1-liushixin2@huawei.com --- drivers/rtc/rtc-rv8803.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 93c3a6b627bd..c6d8e3425688 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -454,13 +454,7 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) static int rv8803_nvram_write(void *priv, unsigned int offset, void *val, size_t bytes) { - int ret; - - ret = rv8803_write_reg(priv, RV8803_RAM, *(u8 *)val); - if (ret) - return ret; - - return 0; + return rv8803_write_reg(priv, RV8803_RAM, *(u8 *)val); } static int rv8803_nvram_read(void *priv, unsigned int offset, -- cgit v1.2.3 From 770c03e6dabacd5b9f57bba93c4311d32b618640 Mon Sep 17 00:00:00 2001 From: Fei Shao Date: Thu, 8 Oct 2020 17:34:14 +0800 Subject: rtc: mt6397: Remove unused member dev Removing the struct member "dev" in mt6397 RTC driver because it's not initialized and the only usage is for one debugging message. Also fixed a typo in the error message. Signed-off-by: Fei Shao Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201008093414.1911699-1-fshao@chromium.org --- drivers/rtc/rtc-mt6397.c | 3 ++- include/linux/mfd/mt6397/rtc.h | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index f8b1353777ba..1894aded4c85 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -31,7 +31,8 @@ static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc) MTK_RTC_POLL_DELAY_US, MTK_RTC_POLL_TIMEOUT); if (ret < 0) - dev_err(rtc->dev, "failed to write WRTGE: %d\n", ret); + dev_err(rtc->rtc_dev->dev.parent, + "failed to write WRTGR: %d\n", ret); return ret; } diff --git a/include/linux/mfd/mt6397/rtc.h b/include/linux/mfd/mt6397/rtc.h index 66989a16221a..c3748b53bf7d 100644 --- a/include/linux/mfd/mt6397/rtc.h +++ b/include/linux/mfd/mt6397/rtc.h @@ -72,7 +72,6 @@ struct mtk_rtc_data { }; struct mt6397_rtc { - struct device *dev; struct rtc_device *rtc_dev; /* Protect register access from multiple tasks */ -- cgit v1.2.3 From 00e8e87f10155b06ae2bc9f93c4d006681640e65 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 9 Oct 2020 17:30:58 +0200 Subject: rtc: rv3028: fix clock output support rv3028_clkout_set_rate unconditionally sets RV3028_CLKOUT_CLKOE but clk_set_rate may be called with the clock disabled. Ensure the clock is kept disabled if it was not yet enabled. Also, the actual rate was overwritten when enabling the clock, properly write to the register only once. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201009153101.721149-1-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rv3028.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index ec84db0b3d7a..fcc21b1b07b4 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -619,24 +619,23 @@ static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { int i, ret; + u32 enabled; struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); + ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &enabled); + if (ret < 0) + return ret; + ret = regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0); if (ret < 0) return ret; - for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) { - if (clkout_rates[i] == rate) { - ret = regmap_update_bits(rv3028->regmap, - RV3028_CLKOUT, - RV3028_CLKOUT_FD_MASK, i); - if (ret < 0) - return ret; + enabled &= RV3028_CLKOUT_CLKOE; + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] == rate) return regmap_write(rv3028->regmap, RV3028_CLKOUT, - RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE); - } - } + RV3028_CLKOUT_CLKSY | enabled | i); return -EINVAL; } -- cgit v1.2.3 From c1efae1432018063e7e723c4267edd3f13ce0f48 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 9 Oct 2020 17:30:59 +0200 Subject: rtc: rv3028: fix trickle resistor values Version 1.0 of the application manual had the wrong resistor values. Fix them according to version 1.1 Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201009153101.721149-2-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rv3028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index fcc21b1b07b4..5cfce6415d9c 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -95,7 +95,7 @@ struct rv3028_data { #endif }; -static u16 rv3028_trickle_resistors[] = {1000, 3000, 6000, 11000}; +static u16 rv3028_trickle_resistors[] = {3000, 5000, 9000, 15000}; static ssize_t timestamp0_store(struct device *dev, struct device_attribute *attr, -- cgit v1.2.3 From de0ad60e79e1ce563223b3fddf03fc19f606c6d4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 9 Oct 2020 17:31:00 +0200 Subject: rtc: rv3028: factorize EERD bit handling Both rv3028_eeprom_write and rv3028_eeprom_read enable EERD before sending commands to the EEPROM and restore it afterwards. Factorize this code. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201009153101.721149-3-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rv3028.c | 118 +++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 5cfce6415d9c..7b8823f43626 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -171,6 +171,44 @@ static const struct attribute_group rv3028_attr_group = { .attrs = rv3028_attrs, }; +static int rv3028_exit_eerd(struct rv3028_data *rv3028, u32 eerd) +{ + if (eerd) + return 0; + + return regmap_update_bits(rv3028->regmap, RV3028_CTRL1, RV3028_CTRL1_EERD, 0); +} + +static int rv3028_enter_eerd(struct rv3028_data *rv3028, u32 *eerd) +{ + u32 ctrl1, status; + int ret; + + ret = regmap_read(rv3028->regmap, RV3028_CTRL1, &ctrl1); + if (ret) + return ret; + + *eerd = ctrl1 & RV3028_CTRL1_EERD; + if (*eerd) + return 0; + + ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1, + RV3028_CTRL1_EERD, RV3028_CTRL1_EERD); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, + !(status & RV3028_STATUS_EEBUSY), + RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); + if (ret) { + rv3028_exit_eerd(rv3028, *eerd); + + return ret; + } + + return 0; +} + static irqreturn_t rv3028_handle_irq(int irq, void *dev_id) { struct rv3028_data *rv3028 = dev_id; @@ -451,49 +489,36 @@ static int rv3028_nvram_read(void *priv, unsigned int offset, void *val, static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val, size_t bytes) { - u32 status, ctrl1; - int i, ret, err; + struct rv3028_data *rv3028 = priv; + u32 status, eerd; + int i, ret; u8 *buf = val; - ret = regmap_read(priv, RV3028_CTRL1, &ctrl1); + ret = rv3028_enter_eerd(rv3028, &eerd); if (ret) return ret; - if (!(ctrl1 & RV3028_CTRL1_EERD)) { - ret = regmap_update_bits(priv, RV3028_CTRL1, - RV3028_CTRL1_EERD, RV3028_CTRL1_EERD); - if (ret) - return ret; - - ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status, - !(status & RV3028_STATUS_EEBUSY), - RV3028_EEBUSY_POLL, - RV3028_EEBUSY_TIMEOUT); - if (ret) - goto restore_eerd; - } - for (i = 0; i < bytes; i++) { - ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i); + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i); if (ret) goto restore_eerd; - ret = regmap_write(priv, RV3028_EEPROM_DATA, buf[i]); + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_DATA, buf[i]); if (ret) goto restore_eerd; - ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0); + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0); if (ret) goto restore_eerd; - ret = regmap_write(priv, RV3028_EEPROM_CMD, + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, RV3028_EEPROM_CMD_WRITE); if (ret) goto restore_eerd; usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); - ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status, + ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, !(status & RV3028_STATUS_EEBUSY), RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); @@ -502,13 +527,7 @@ static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val, } restore_eerd: - if (!(ctrl1 & RV3028_CTRL1_EERD)) - { - err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD, - 0); - if (err && !ret) - ret = err; - } + rv3028_exit_eerd(rv3028, eerd); return ret; } @@ -516,63 +535,44 @@ restore_eerd: static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val, size_t bytes) { - u32 status, ctrl1, data; - int i, ret, err; + struct rv3028_data *rv3028 = priv; + u32 status, eerd, data; + int i, ret; u8 *buf = val; - ret = regmap_read(priv, RV3028_CTRL1, &ctrl1); + ret = rv3028_enter_eerd(rv3028, &eerd); if (ret) return ret; - if (!(ctrl1 & RV3028_CTRL1_EERD)) { - ret = regmap_update_bits(priv, RV3028_CTRL1, - RV3028_CTRL1_EERD, RV3028_CTRL1_EERD); - if (ret) - return ret; - - ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status, - !(status & RV3028_STATUS_EEBUSY), - RV3028_EEBUSY_POLL, - RV3028_EEBUSY_TIMEOUT); - if (ret) - goto restore_eerd; - } - for (i = 0; i < bytes; i++) { - ret = regmap_write(priv, RV3028_EEPROM_ADDR, offset + i); + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i); if (ret) goto restore_eerd; - ret = regmap_write(priv, RV3028_EEPROM_CMD, 0x0); + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0); if (ret) goto restore_eerd; - ret = regmap_write(priv, RV3028_EEPROM_CMD, + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, RV3028_EEPROM_CMD_READ); if (ret) goto restore_eerd; - ret = regmap_read_poll_timeout(priv, RV3028_STATUS, status, + ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, !(status & RV3028_STATUS_EEBUSY), RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); if (ret) goto restore_eerd; - ret = regmap_read(priv, RV3028_EEPROM_DATA, &data); + ret = regmap_read(rv3028->regmap, RV3028_EEPROM_DATA, &data); if (ret) goto restore_eerd; buf[i] = data; } restore_eerd: - if (!(ctrl1 & RV3028_CTRL1_EERD)) - { - err = regmap_update_bits(priv, RV3028_CTRL1, RV3028_CTRL1_EERD, - 0); - if (err && !ret) - ret = err; - } + rv3028_exit_eerd(rv3028, eerd); return ret; } @@ -834,7 +834,7 @@ static int rv3028_probe(struct i2c_client *client) nvmem_cfg.priv = rv3028->regmap; rtc_nvmem_register(rv3028->rtc, &nvmem_cfg); - eeprom_cfg.priv = rv3028->regmap; + eeprom_cfg.priv = rv3028; rtc_nvmem_register(rv3028->rtc, &eeprom_cfg); rv3028->rtc->max_user_freq = 1; -- cgit v1.2.3 From 024e6f3dce9ef0bc61acc5b93bb1eba491e4f8d0 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 9 Oct 2020 17:31:01 +0200 Subject: rtc: rv3028: ensure ram configuration registers are saved If RV3028_CTRL1_EERD is not set (this is the default), the RTC will refresh the RAM configuration registers from the EEPROM at midnight. It is necessary to save the RAM registers back to EEPROM after modifying them. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201009153101.721149-4-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-rv3028.c | 76 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 7b8823f43626..fa226f0fe67d 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -71,6 +71,7 @@ #define RV3028_EVT_CTRL_TSR BIT(2) +#define RV3028_EEPROM_CMD_UPDATE 0x11 #define RV3028_EEPROM_CMD_WRITE 0x21 #define RV3028_EEPROM_CMD_READ 0x22 @@ -209,6 +210,50 @@ static int rv3028_enter_eerd(struct rv3028_data *rv3028, u32 *eerd) return 0; } +static int rv3028_update_eeprom(struct rv3028_data *rv3028, u32 eerd) +{ + u32 status; + int ret; + + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0); + if (ret) + goto exit_eerd; + + ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, RV3028_EEPROM_CMD_UPDATE); + if (ret) + goto exit_eerd; + + usleep_range(63000, RV3028_EEBUSY_TIMEOUT); + + ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, + !(status & RV3028_STATUS_EEBUSY), + RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); + +exit_eerd: + rv3028_exit_eerd(rv3028, eerd); + + return ret; +} + +static int rv3028_update_cfg(struct rv3028_data *rv3028, unsigned int reg, + unsigned int mask, unsigned int val) +{ + u32 eerd; + int ret; + + ret = rv3028_enter_eerd(rv3028, &eerd); + if (ret) + return ret; + + ret = regmap_update_bits(rv3028->regmap, reg, mask, val); + if (ret) { + rv3028_exit_eerd(rv3028, eerd); + return ret; + } + + return rv3028_update_eeprom(rv3028, eerd); +} + static irqreturn_t rv3028_handle_irq(int irq, void *dev_id) { struct rv3028_data *rv3028 = dev_id; @@ -442,17 +487,32 @@ static int rv3028_read_offset(struct device *dev, long *offset) static int rv3028_set_offset(struct device *dev, long offset) { struct rv3028_data *rv3028 = dev_get_drvdata(dev); + u32 eerd; int ret; offset = clamp(offset, -244141L, 243187L) * 1000; offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT); + ret = rv3028_enter_eerd(rv3028, &eerd); + if (ret) + return ret; + ret = regmap_write(rv3028->regmap, RV3028_OFFSET, offset >> 1); if (ret < 0) - return ret; + goto exit_eerd; + + ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7), + offset << 7); + if (ret < 0) + goto exit_eerd; + + return rv3028_update_eeprom(rv3028, eerd); + +exit_eerd: + rv3028_exit_eerd(rv3028, eerd); + + return ret; - return regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7), - offset << 7); } static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) @@ -634,8 +694,8 @@ static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate, for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) if (clkout_rates[i] == rate) - return regmap_write(rv3028->regmap, RV3028_CLKOUT, - RV3028_CLKOUT_CLKSY | enabled | i); + return rv3028_update_cfg(rv3028, RV3028_CLKOUT, 0xff, + RV3028_CLKOUT_CLKSY | enabled | i); return -EINVAL; } @@ -810,10 +870,8 @@ static int rv3028_probe(struct i2c_client *client) break; if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { - ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP, - RV3028_BACKUP_TCE | - RV3028_BACKUP_TCR_MASK, - RV3028_BACKUP_TCE | i); + ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | + RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i); if (ret) return ret; } else { -- cgit v1.2.3 From 2eeaa532accab8810ca9fe21f52d149713561235 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 13 Oct 2020 16:41:10 +0200 Subject: rtc: rv3032: Add a driver for Microcrystal RV-3032 New driver for the Microcrystal RV-3032, including support for: - Date/time - Alarms - Low voltage detection - Trickle charge - Trimming - Clkout - RAM - EEPROM - Temperature sensor Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201013144110.1942218-3-alexandre.belloni@bootlin.com --- drivers/rtc/Kconfig | 10 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-rv3032.c | 925 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 936 insertions(+) create mode 100644 drivers/rtc/rtc-rv3032.c (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 48c536acd777..65ad9d0b47ab 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -669,6 +669,16 @@ config RTC_DRV_RV3028 This driver can also be built as a module. If so, the module will be called rtc-rv3028. +config RTC_DRV_RV3032 + tristate "Micro Crystal RV3032" + select REGMAP_I2C + help + If you say yes here you get support for the Micro Crystal + RV3032. + + This driver can also be built as a module. If so, the module + will be called rtc-rv3032. + config RTC_DRV_RV8803 tristate "Micro Crystal RV8803, Epson RX8900" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 880e08a409c3..bfb57464118d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -141,6 +141,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RTD119X) += rtc-rtd119x.o obj-$(CONFIG_RTC_DRV_RV3028) += rtc-rv3028.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o +obj-$(CONFIG_RTC_DRV_RV3032) += rtc-rv3032.o obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c new file mode 100644 index 000000000000..3e67f71f4261 --- /dev/null +++ b/drivers/rtc/rtc-rv3032.c @@ -0,0 +1,925 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RTC driver for the Micro Crystal RV3032 + * + * Copyright (C) 2020 Micro Crystal SA + * + * Alexandre Belloni + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RV3032_SEC 0x01 +#define RV3032_MIN 0x02 +#define RV3032_HOUR 0x03 +#define RV3032_WDAY 0x04 +#define RV3032_DAY 0x05 +#define RV3032_MONTH 0x06 +#define RV3032_YEAR 0x07 +#define RV3032_ALARM_MIN 0x08 +#define RV3032_ALARM_HOUR 0x09 +#define RV3032_ALARM_DAY 0x0A +#define RV3032_STATUS 0x0D +#define RV3032_TLSB 0x0E +#define RV3032_TMSB 0x0F +#define RV3032_CTRL1 0x10 +#define RV3032_CTRL2 0x11 +#define RV3032_CTRL3 0x12 +#define RV3032_TS_CTRL 0x13 +#define RV3032_CLK_IRQ 0x14 +#define RV3032_EEPROM_ADDR 0x3D +#define RV3032_EEPROM_DATA 0x3E +#define RV3032_EEPROM_CMD 0x3F +#define RV3032_RAM1 0x40 +#define RV3032_PMU 0xC0 +#define RV3032_OFFSET 0xC1 +#define RV3032_CLKOUT1 0xC2 +#define RV3032_CLKOUT2 0xC3 +#define RV3032_TREF0 0xC4 +#define RV3032_TREF1 0xC5 + +#define RV3032_STATUS_VLF BIT(0) +#define RV3032_STATUS_PORF BIT(1) +#define RV3032_STATUS_EVF BIT(2) +#define RV3032_STATUS_AF BIT(3) +#define RV3032_STATUS_TF BIT(4) +#define RV3032_STATUS_UF BIT(5) +#define RV3032_STATUS_TLF BIT(6) +#define RV3032_STATUS_THF BIT(7) + +#define RV3032_TLSB_CLKF BIT(1) +#define RV3032_TLSB_EEBUSY BIT(2) +#define RV3032_TLSB_TEMP GENMASK(7, 4) + +#define RV3032_CLKOUT2_HFD_MSK GENMASK(4, 0) +#define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5) +#define RV3032_CLKOUT2_OS BIT(7) + +#define RV3032_CTRL1_EERD BIT(3) +#define RV3032_CTRL1_WADA BIT(5) + +#define RV3032_CTRL2_STOP BIT(0) +#define RV3032_CTRL2_EIE BIT(2) +#define RV3032_CTRL2_AIE BIT(3) +#define RV3032_CTRL2_TIE BIT(4) +#define RV3032_CTRL2_UIE BIT(5) +#define RV3032_CTRL2_CLKIE BIT(6) +#define RV3032_CTRL2_TSE BIT(7) + +#define RV3032_PMU_TCM GENMASK(1, 0) +#define RV3032_PMU_TCR GENMASK(3, 2) +#define RV3032_PMU_BSM GENMASK(5, 4) +#define RV3032_PMU_NCLKE BIT(6) + +#define RV3032_PMU_BSM_DSM 1 +#define RV3032_PMU_BSM_LSM 2 + +#define RV3032_OFFSET_MSK GENMASK(5, 0) + +#define RV3032_EVT_CTRL_TSR BIT(2) + +#define RV3032_EEPROM_CMD_UPDATE 0x11 +#define RV3032_EEPROM_CMD_WRITE 0x21 +#define RV3032_EEPROM_CMD_READ 0x22 + +#define RV3032_EEPROM_USER 0xCB + +#define RV3032_EEBUSY_POLL 10000 +#define RV3032_EEBUSY_TIMEOUT 100000 + +#define OFFSET_STEP_PPT 238419 + +struct rv3032_data { + struct regmap *regmap; + struct rtc_device *rtc; +#ifdef CONFIG_COMMON_CLK + struct clk_hw clkout_hw; +#endif +}; + +static u16 rv3032_trickle_resistors[] = {1000, 2000, 7000, 11000}; +static u16 rv3032_trickle_voltages[] = {0, 1750, 3000, 4400}; + +static int rv3032_exit_eerd(struct rv3032_data *rv3032, u32 eerd) +{ + if (eerd) + return 0; + + return regmap_update_bits(rv3032->regmap, RV3032_CTRL1, RV3032_CTRL1_EERD, 0); +} + +static int rv3032_enter_eerd(struct rv3032_data *rv3032, u32 *eerd) +{ + u32 ctrl1, status; + int ret; + + ret = regmap_read(rv3032->regmap, RV3032_CTRL1, &ctrl1); + if (ret) + return ret; + + *eerd = ctrl1 & RV3032_CTRL1_EERD; + if (*eerd) + return 0; + + ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL1, + RV3032_CTRL1_EERD, RV3032_CTRL1_EERD); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(rv3032->regmap, RV3032_TLSB, status, + !(status & RV3032_TLSB_EEBUSY), + RV3032_EEBUSY_POLL, RV3032_EEBUSY_TIMEOUT); + if (ret) { + rv3032_exit_eerd(rv3032, *eerd); + + return ret; + } + + return 0; +} + +static int rv3032_update_cfg(struct rv3032_data *rv3032, unsigned int reg, + unsigned int mask, unsigned int val) +{ + u32 status, eerd; + int ret; + + ret = rv3032_enter_eerd(rv3032, &eerd); + if (ret) + return ret; + + ret = regmap_update_bits(rv3032->regmap, reg, mask, val); + if (ret) + goto exit_eerd; + + ret = regmap_write(rv3032->regmap, RV3032_EEPROM_CMD, RV3032_EEPROM_CMD_UPDATE); + if (ret) + goto exit_eerd; + + usleep_range(46000, RV3032_EEBUSY_TIMEOUT); + + ret = regmap_read_poll_timeout(rv3032->regmap, RV3032_TLSB, status, + !(status & RV3032_TLSB_EEBUSY), + RV3032_EEBUSY_POLL, RV3032_EEBUSY_TIMEOUT); + +exit_eerd: + rv3032_exit_eerd(rv3032, eerd); + + return ret; +} + +static irqreturn_t rv3032_handle_irq(int irq, void *dev_id) +{ + struct rv3032_data *rv3032 = dev_id; + unsigned long events = 0; + u32 status = 0, ctrl = 0; + + if (regmap_read(rv3032->regmap, RV3032_STATUS, &status) < 0 || + status == 0) { + return IRQ_NONE; + } + + if (status & RV3032_STATUS_TF) { + status |= RV3032_STATUS_TF; + ctrl |= RV3032_CTRL2_TIE; + events |= RTC_PF; + } + + if (status & RV3032_STATUS_AF) { + status |= RV3032_STATUS_AF; + ctrl |= RV3032_CTRL2_AIE; + events |= RTC_AF; + } + + if (status & RV3032_STATUS_UF) { + status |= RV3032_STATUS_UF; + ctrl |= RV3032_CTRL2_UIE; + events |= RTC_UF; + } + + if (events) { + rtc_update_irq(rv3032->rtc, 1, events); + regmap_update_bits(rv3032->regmap, RV3032_STATUS, status, 0); + regmap_update_bits(rv3032->regmap, RV3032_CTRL2, ctrl, 0); + } + + return IRQ_HANDLED; +} + +static int rv3032_get_time(struct device *dev, struct rtc_time *tm) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + u8 date[7]; + int ret, status; + + ret = regmap_read(rv3032->regmap, RV3032_STATUS, &status); + if (ret < 0) + return ret; + + if (status & (RV3032_STATUS_PORF | RV3032_STATUS_VLF)) + return -EINVAL; + + ret = regmap_bulk_read(rv3032->regmap, RV3032_SEC, date, sizeof(date)); + if (ret) + return ret; + + tm->tm_sec = bcd2bin(date[0] & 0x7f); + tm->tm_min = bcd2bin(date[1] & 0x7f); + tm->tm_hour = bcd2bin(date[2] & 0x3f); + tm->tm_wday = date[3] & 0x7; + tm->tm_mday = bcd2bin(date[4] & 0x3f); + tm->tm_mon = bcd2bin(date[5] & 0x1f) - 1; + tm->tm_year = bcd2bin(date[6]) + 100; + + return 0; +} + +static int rv3032_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + u8 date[7]; + int ret; + + date[0] = bin2bcd(tm->tm_sec); + date[1] = bin2bcd(tm->tm_min); + date[2] = bin2bcd(tm->tm_hour); + date[3] = tm->tm_wday; + date[4] = bin2bcd(tm->tm_mday); + date[5] = bin2bcd(tm->tm_mon + 1); + date[6] = bin2bcd(tm->tm_year - 100); + + ret = regmap_bulk_write(rv3032->regmap, RV3032_SEC, date, + sizeof(date)); + if (ret) + return ret; + + ret = regmap_update_bits(rv3032->regmap, RV3032_STATUS, + RV3032_STATUS_PORF | RV3032_STATUS_VLF, 0); + + return ret; +} + +static int rv3032_get_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + u8 alarmvals[3]; + int status, ctrl, ret; + + ret = regmap_bulk_read(rv3032->regmap, RV3032_ALARM_MIN, alarmvals, + sizeof(alarmvals)); + if (ret) + return ret; + + ret = regmap_read(rv3032->regmap, RV3032_STATUS, &status); + if (ret < 0) + return ret; + + ret = regmap_read(rv3032->regmap, RV3032_CTRL2, &ctrl); + if (ret < 0) + return ret; + + alrm->time.tm_sec = 0; + alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f); + alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f); + alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f); + + alrm->enabled = !!(ctrl & RV3032_CTRL2_AIE); + alrm->pending = (status & RV3032_STATUS_AF) && alrm->enabled; + + return 0; +} + +static int rv3032_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + u8 alarmvals[3]; + 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) + return ret; + + alarmvals[0] = bin2bcd(alrm->time.tm_min); + alarmvals[1] = bin2bcd(alrm->time.tm_hour); + alarmvals[2] = bin2bcd(alrm->time.tm_mday); + + ret = regmap_update_bits(rv3032->regmap, RV3032_STATUS, + RV3032_STATUS_AF, 0); + if (ret) + return ret; + + ret = regmap_bulk_write(rv3032->regmap, RV3032_ALARM_MIN, alarmvals, + sizeof(alarmvals)); + if (ret) + return ret; + + if (alrm->enabled) { + if (rv3032->rtc->uie_rtctimer.enabled) + ctrl |= RV3032_CTRL2_UIE; + if (rv3032->rtc->aie_timer.enabled) + ctrl |= RV3032_CTRL2_AIE; + } + + ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL2, + RV3032_CTRL2_UIE | RV3032_CTRL2_AIE, ctrl); + + return ret; +} + +static int rv3032_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + int ctrl = 0, ret; + + if (enabled) { + if (rv3032->rtc->uie_rtctimer.enabled) + ctrl |= RV3032_CTRL2_UIE; + if (rv3032->rtc->aie_timer.enabled) + ctrl |= RV3032_CTRL2_AIE; + } + + ret = regmap_update_bits(rv3032->regmap, RV3032_STATUS, + RV3032_STATUS_AF | RV3032_STATUS_UF, 0); + if (ret) + return ret; + + ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL2, + RV3032_CTRL2_UIE | RV3032_CTRL2_AIE, ctrl); + if (ret) + return ret; + + return 0; +} + +static int rv3032_read_offset(struct device *dev, long *offset) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + int ret, value, steps; + + ret = regmap_read(rv3032->regmap, RV3032_OFFSET, &value); + if (ret < 0) + return ret; + + steps = sign_extend32(FIELD_GET(RV3032_OFFSET_MSK, value), 5); + + *offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000); + + return 0; +} + +static int rv3032_set_offset(struct device *dev, long offset) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + + offset = clamp(offset, -7629L, 7391L) * 1000; + offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT); + + return rv3032_update_cfg(rv3032, RV3032_OFFSET, RV3032_OFFSET_MSK, + FIELD_PREP(RV3032_OFFSET_MSK, offset)); +} + +static int rv3032_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + int status, val = 0, ret = 0; + + switch (cmd) { + case RTC_VL_READ: + ret = regmap_read(rv3032->regmap, RV3032_STATUS, &status); + if (ret < 0) + return ret; + + if (status & (RV3032_STATUS_PORF | RV3032_STATUS_VLF)) + val = RTC_VL_DATA_INVALID; + return put_user(val, (unsigned int __user *)arg); + + default: + return -ENOIOCTLCMD; + } +} + +static int rv3032_nvram_write(void *priv, unsigned int offset, void *val, size_t bytes) +{ + return regmap_bulk_write(priv, RV3032_RAM1 + offset, val, bytes); +} + +static int rv3032_nvram_read(void *priv, unsigned int offset, void *val, size_t bytes) +{ + return regmap_bulk_read(priv, RV3032_RAM1 + offset, val, bytes); +} + +static int rv3032_eeprom_write(void *priv, unsigned int offset, void *val, size_t bytes) +{ + struct rv3032_data *rv3032 = priv; + u32 status, eerd; + int i, ret; + u8 *buf = val; + + ret = rv3032_enter_eerd(rv3032, &eerd); + if (ret) + return ret; + + for (i = 0; i < bytes; i++) { + ret = regmap_write(rv3032->regmap, RV3032_EEPROM_ADDR, + RV3032_EEPROM_USER + offset + i); + if (ret) + goto exit_eerd; + + ret = regmap_write(rv3032->regmap, RV3032_EEPROM_DATA, buf[i]); + if (ret) + goto exit_eerd; + + ret = regmap_write(rv3032->regmap, RV3032_EEPROM_CMD, + RV3032_EEPROM_CMD_WRITE); + if (ret) + goto exit_eerd; + + usleep_range(RV3032_EEBUSY_POLL, RV3032_EEBUSY_TIMEOUT); + + ret = regmap_read_poll_timeout(rv3032->regmap, RV3032_TLSB, status, + !(status & RV3032_TLSB_EEBUSY), + RV3032_EEBUSY_POLL, RV3032_EEBUSY_TIMEOUT); + if (ret) + goto exit_eerd; + } + +exit_eerd: + rv3032_exit_eerd(rv3032, eerd); + + return ret; +} + +static int rv3032_eeprom_read(void *priv, unsigned int offset, void *val, size_t bytes) +{ + struct rv3032_data *rv3032 = priv; + u32 status, eerd, data; + int i, ret; + u8 *buf = val; + + ret = rv3032_enter_eerd(rv3032, &eerd); + if (ret) + return ret; + + for (i = 0; i < bytes; i++) { + ret = regmap_write(rv3032->regmap, RV3032_EEPROM_ADDR, + RV3032_EEPROM_USER + offset + i); + if (ret) + goto exit_eerd; + + ret = regmap_write(rv3032->regmap, RV3032_EEPROM_CMD, + RV3032_EEPROM_CMD_READ); + if (ret) + goto exit_eerd; + + ret = regmap_read_poll_timeout(rv3032->regmap, RV3032_TLSB, status, + !(status & RV3032_TLSB_EEBUSY), + RV3032_EEBUSY_POLL, RV3032_EEBUSY_TIMEOUT); + if (ret) + goto exit_eerd; + + ret = regmap_read(rv3032->regmap, RV3032_EEPROM_DATA, &data); + if (ret) + goto exit_eerd; + buf[i] = data; + } + +exit_eerd: + rv3032_exit_eerd(rv3032, eerd); + + return ret; +} + +static int rv3032_trickle_charger_setup(struct device *dev, struct rv3032_data *rv3032) +{ + u32 val, ohms, voltage; + int i; + + val = FIELD_PREP(RV3032_PMU_TCM, 1) | FIELD_PREP(RV3032_PMU_BSM, RV3032_PMU_BSM_DSM); + if (!device_property_read_u32(dev, "trickle-voltage-millivolt", &voltage)) { + for (i = 0; i < ARRAY_SIZE(rv3032_trickle_voltages); i++) + if (voltage == rv3032_trickle_voltages[i]) + break; + if (i < ARRAY_SIZE(rv3032_trickle_voltages)) + val = FIELD_PREP(RV3032_PMU_TCM, i) | + FIELD_PREP(RV3032_PMU_BSM, RV3032_PMU_BSM_LSM); + } + + if (device_property_read_u32(dev, "trickle-resistor-ohms", &ohms)) + return 0; + + for (i = 0; i < ARRAY_SIZE(rv3032_trickle_resistors); i++) + if (ohms == rv3032_trickle_resistors[i]) + break; + + if (i >= ARRAY_SIZE(rv3032_trickle_resistors)) { + dev_warn(dev, "invalid trickle resistor value\n"); + + return 0; + } + + return rv3032_update_cfg(rv3032, RV3032_PMU, + RV3032_PMU_TCR | RV3032_PMU_TCM | RV3032_PMU_BSM, + val | FIELD_PREP(RV3032_PMU_TCR, i)); +} + +#ifdef CONFIG_COMMON_CLK +#define clkout_hw_to_rv3032(hw) container_of(hw, struct rv3032_data, clkout_hw) + +static int clkout_xtal_rates[] = { + 32768, + 1024, + 64, + 1, +}; + +#define RV3032_HFD_STEP 8192 + +static unsigned long rv3032_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int clkout, ret; + struct rv3032_data *rv3032 = clkout_hw_to_rv3032(hw); + + ret = regmap_read(rv3032->regmap, RV3032_CLKOUT2, &clkout); + if (ret < 0) + return 0; + + if (clkout & RV3032_CLKOUT2_OS) { + unsigned long rate = FIELD_GET(RV3032_CLKOUT2_HFD_MSK, clkout) << 8; + + ret = regmap_read(rv3032->regmap, RV3032_CLKOUT1, &clkout); + if (ret < 0) + return 0; + + rate += clkout + 1; + + return rate * RV3032_HFD_STEP; + } + + return clkout_xtal_rates[FIELD_GET(RV3032_CLKOUT2_FD_MSK, clkout)]; +} + +static long rv3032_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i, hfd; + + if (rate < RV3032_HFD_STEP) + for (i = 0; i < ARRAY_SIZE(clkout_xtal_rates); i++) + if (clkout_xtal_rates[i] <= rate) + return clkout_xtal_rates[i]; + + hfd = DIV_ROUND_CLOSEST(rate, RV3032_HFD_STEP); + + return RV3032_HFD_STEP * clamp(hfd, 0, 8192); +} + +static int rv3032_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct rv3032_data *rv3032 = clkout_hw_to_rv3032(hw); + u32 status, eerd; + int i, hfd, ret; + + for (i = 0; i < ARRAY_SIZE(clkout_xtal_rates); i++) { + if (clkout_xtal_rates[i] == rate) { + return rv3032_update_cfg(rv3032, RV3032_CLKOUT2, 0xff, + FIELD_PREP(RV3032_CLKOUT2_FD_MSK, i)); + } + } + + hfd = DIV_ROUND_CLOSEST(rate, RV3032_HFD_STEP); + hfd = clamp(hfd, 1, 8192) - 1; + + ret = rv3032_enter_eerd(rv3032, &eerd); + if (ret) + goto exit_eerd; + + ret = regmap_write(rv3032->regmap, RV3032_CLKOUT1, hfd & 0xff); + if (ret) + return ret; + + ret = regmap_write(rv3032->regmap, RV3032_CLKOUT2, RV3032_CLKOUT2_OS | + FIELD_PREP(RV3032_CLKOUT2_HFD_MSK, hfd >> 8)); + if (ret) + goto exit_eerd; + + ret = regmap_write(rv3032->regmap, RV3032_EEPROM_CMD, RV3032_EEPROM_CMD_UPDATE); + if (ret) + goto exit_eerd; + + usleep_range(46000, RV3032_EEBUSY_TIMEOUT); + + ret = regmap_read_poll_timeout(rv3032->regmap, RV3032_TLSB, status, + !(status & RV3032_TLSB_EEBUSY), + RV3032_EEBUSY_POLL, RV3032_EEBUSY_TIMEOUT); + +exit_eerd: + rv3032_exit_eerd(rv3032, eerd); + + return ret; +} + +static int rv3032_clkout_prepare(struct clk_hw *hw) +{ + struct rv3032_data *rv3032 = clkout_hw_to_rv3032(hw); + + return rv3032_update_cfg(rv3032, RV3032_PMU, RV3032_PMU_NCLKE, 0); +} + +static void rv3032_clkout_unprepare(struct clk_hw *hw) +{ + struct rv3032_data *rv3032 = clkout_hw_to_rv3032(hw); + + rv3032_update_cfg(rv3032, RV3032_PMU, RV3032_PMU_NCLKE, RV3032_PMU_NCLKE); +} + +static int rv3032_clkout_is_prepared(struct clk_hw *hw) +{ + int val, ret; + struct rv3032_data *rv3032 = clkout_hw_to_rv3032(hw); + + ret = regmap_read(rv3032->regmap, RV3032_PMU, &val); + if (ret < 0) + return ret; + + return !(val & RV3032_PMU_NCLKE); +} + +static const struct clk_ops rv3032_clkout_ops = { + .prepare = rv3032_clkout_prepare, + .unprepare = rv3032_clkout_unprepare, + .is_prepared = rv3032_clkout_is_prepared, + .recalc_rate = rv3032_clkout_recalc_rate, + .round_rate = rv3032_clkout_round_rate, + .set_rate = rv3032_clkout_set_rate, +}; + +static int rv3032_clkout_register_clk(struct rv3032_data *rv3032, + struct i2c_client *client) +{ + int ret; + struct clk *clk; + struct clk_init_data init; + struct device_node *node = client->dev.of_node; + + ret = regmap_update_bits(rv3032->regmap, RV3032_TLSB, RV3032_TLSB_CLKF, 0); + if (ret < 0) + return ret; + + ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL2, RV3032_CTRL2_CLKIE, 0); + if (ret < 0) + return ret; + + ret = regmap_write(rv3032->regmap, RV3032_CLK_IRQ, 0); + if (ret < 0) + return ret; + + init.name = "rv3032-clkout"; + init.ops = &rv3032_clkout_ops; + init.flags = 0; + init.parent_names = NULL; + init.num_parents = 0; + rv3032->clkout_hw.init = &init; + + of_property_read_string(node, "clock-output-names", &init.name); + + clk = devm_clk_register(&client->dev, &rv3032->clkout_hw); + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return 0; +} +#endif + +static int rv3032_hwmon_read_temp(struct device *dev, long *mC) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + u8 buf[2]; + int temp, prev = 0; + int ret; + + ret = regmap_bulk_read(rv3032->regmap, RV3032_TLSB, buf, sizeof(buf)); + if (ret) + return ret; + + temp = sign_extend32(buf[1], 7) << 4; + temp |= FIELD_GET(RV3032_TLSB_TEMP, buf[0]); + + /* No blocking or shadowing on RV3032_TLSB and RV3032_TMSB */ + do { + prev = temp; + + ret = regmap_bulk_read(rv3032->regmap, RV3032_TLSB, buf, sizeof(buf)); + if (ret) + return ret; + + temp = sign_extend32(buf[1], 7) << 4; + temp |= FIELD_GET(RV3032_TLSB_TEMP, buf[0]); + } while (temp != prev); + + *mC = (temp * 1000) / 16; + + return 0; +} + +static umode_t rv3032_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + return 0444; + default: + return 0; + } +} + +static int rv3032_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *temp) +{ + int err; + + switch (attr) { + case hwmon_temp_input: + err = rv3032_hwmon_read_temp(dev, temp); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static const struct hwmon_channel_info *rv3032_hwmon_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST), + NULL +}; + +static const struct hwmon_ops rv3032_hwmon_hwmon_ops = { + .is_visible = rv3032_hwmon_is_visible, + .read = rv3032_hwmon_read, +}; + +static const struct hwmon_chip_info rv3032_hwmon_chip_info = { + .ops = &rv3032_hwmon_hwmon_ops, + .info = rv3032_hwmon_info, +}; + +static void rv3032_hwmon_register(struct device *dev) +{ + struct rv3032_data *rv3032 = dev_get_drvdata(dev); + + if (!IS_REACHABLE(CONFIG_HWMON)) + return; + + devm_hwmon_device_register_with_info(dev, "rv3032", rv3032, &rv3032_hwmon_chip_info, NULL); +} + +static struct rtc_class_ops rv3032_rtc_ops = { + .read_time = rv3032_get_time, + .set_time = rv3032_set_time, + .read_offset = rv3032_read_offset, + .set_offset = rv3032_set_offset, + .ioctl = rv3032_ioctl, +}; + +static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xCA, +}; + +static int rv3032_probe(struct i2c_client *client) +{ + struct rv3032_data *rv3032; + int ret, status; + struct nvmem_config nvmem_cfg = { + .name = "rv3032_nvram", + .word_size = 1, + .stride = 1, + .size = 16, + .type = NVMEM_TYPE_BATTERY_BACKED, + .reg_read = rv3032_nvram_read, + .reg_write = rv3032_nvram_write, + }; + struct nvmem_config eeprom_cfg = { + .name = "rv3032_eeprom", + .word_size = 1, + .stride = 1, + .size = 32, + .type = NVMEM_TYPE_EEPROM, + .reg_read = rv3032_eeprom_read, + .reg_write = rv3032_eeprom_write, + }; + + rv3032 = devm_kzalloc(&client->dev, sizeof(struct rv3032_data), + GFP_KERNEL); + if (!rv3032) + return -ENOMEM; + + rv3032->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(rv3032->regmap)) + return PTR_ERR(rv3032->regmap); + + i2c_set_clientdata(client, rv3032); + + ret = regmap_read(rv3032->regmap, RV3032_STATUS, &status); + if (ret < 0) + return ret; + + rv3032->rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(rv3032->rtc)) + return PTR_ERR(rv3032->rtc); + + if (client->irq > 0) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, rv3032_handle_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "rv3032", rv3032); + if (ret) { + dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); + client->irq = 0; + } else { + rv3032_rtc_ops.read_alarm = rv3032_get_alarm; + rv3032_rtc_ops.set_alarm = rv3032_set_alarm; + rv3032_rtc_ops.alarm_irq_enable = rv3032_alarm_irq_enable; + } + } + + ret = regmap_update_bits(rv3032->regmap, RV3032_CTRL1, + RV3032_CTRL1_WADA, RV3032_CTRL1_WADA); + if (ret) + return ret; + + rv3032_trickle_charger_setup(&client->dev, rv3032); + + rv3032->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rv3032->rtc->range_max = RTC_TIMESTAMP_END_2099; + rv3032->rtc->ops = &rv3032_rtc_ops; + ret = rtc_register_device(rv3032->rtc); + if (ret) + return ret; + + nvmem_cfg.priv = rv3032; + rtc_nvmem_register(rv3032->rtc, &nvmem_cfg); + eeprom_cfg.priv = rv3032; + rtc_nvmem_register(rv3032->rtc, &eeprom_cfg); + + rv3032->rtc->max_user_freq = 1; + +#ifdef CONFIG_COMMON_CLK + rv3032_clkout_register_clk(rv3032, client); +#endif + + rv3032_hwmon_register(&client->dev); + + return 0; +} + +static const struct of_device_id rv3032_of_match[] = { + { .compatible = "microcrystal,rv3032", }, + { } +}; +MODULE_DEVICE_TABLE(of, rv3032_of_match); + +static struct i2c_driver rv3032_driver = { + .driver = { + .name = "rtc-rv3032", + .of_match_table = of_match_ptr(rv3032_of_match), + }, + .probe_new = rv3032_probe, +}; +module_i2c_driver(rv3032_driver); + +MODULE_AUTHOR("Alexandre Belloni "); +MODULE_DESCRIPTION("Micro Crystal RV3032 RTC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 92c6dcfbd1eb803d4669c82b3d8a0fcbb803e3f9 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 15 Oct 2020 21:11:30 +0200 Subject: rtc: r9701: remove leftover comment Commit 22652ba72453 ("rtc: stop validating rtc_time in .read_time") removed the code but not the associated comment. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201015191135.471249-1-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-r9701.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 84f0d25259ae..eb00879f7c9a 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -85,10 +85,6 @@ static int r9701_get_datetime(struct device *dev, struct rtc_time *dt) dt->tm_mon = bcd2bin(buf[4]) - 1; /* RMONCNT */ dt->tm_year = bcd2bin(buf[5]) + 100; /* RYRCNT */ - /* the rtc device may contain illegal values on power up - * according to the data sheet. make sure they are valid. - */ - return 0; } -- cgit v1.2.3 From 7390bec4ed5d510d1a637257ff75e9ab49030411 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 15 Oct 2020 21:11:31 +0200 Subject: rtc: r9701: stop setting a default time It doesn't make sense to set the RTC to a default value at probe time. Let the core handle invalid date and time. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201015191135.471249-2-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-r9701.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index eb00879f7c9a..f8f7044ff808 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -115,7 +115,6 @@ static const struct rtc_class_ops r9701_rtc_ops = { static int r9701_probe(struct spi_device *spi) { struct rtc_device *rtc; - struct rtc_time dt; unsigned char tmp; int res; @@ -126,27 +125,6 @@ static int r9701_probe(struct spi_device *spi) return -ENODEV; } - /* - * The device seems to be present. Now check if the registers - * contain invalid values. If so, try to write a default date: - * 2000/1/1 00:00:00 - */ - if (r9701_get_datetime(&spi->dev, &dt)) { - dev_info(&spi->dev, "trying to repair invalid date/time\n"); - dt.tm_sec = 0; - dt.tm_min = 0; - dt.tm_hour = 0; - dt.tm_mday = 1; - dt.tm_mon = 0; - dt.tm_year = 100; - - if (r9701_set_datetime(&spi->dev, &dt) || - r9701_get_datetime(&spi->dev, &dt)) { - dev_err(&spi->dev, "cannot repair RTC register\n"); - return -ENODEV; - } - } - rtc = devm_rtc_device_register(&spi->dev, "r9701", &r9701_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) -- cgit v1.2.3 From 2a8f3380c9e50a36b99a92febfd78f7c7afd29b0 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 15 Oct 2020 21:11:32 +0200 Subject: rtc: r9701: remove useless memset The RTC core already sets to zero the struct rtc_tie it passes to the driver, avoid doing it a second time. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201015191135.471249-3-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-r9701.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index f8f7044ff808..4b688e9c4192 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -75,8 +75,6 @@ static int r9701_get_datetime(struct device *dev, struct rtc_time *dt) if (ret) return ret; - memset(dt, 0, sizeof(*dt)); - dt->tm_sec = bcd2bin(buf[0]); /* RSECCNT */ dt->tm_min = bcd2bin(buf[1]); /* RMINCNT */ dt->tm_hour = bcd2bin(buf[2]); /* RHRCNT */ -- cgit v1.2.3 From 8b34134907e7d70b8b51fa56ecd4f8c50c46692c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 15 Oct 2020 21:11:33 +0200 Subject: rtc: r9701: stop setting RWKCNT tm_wday is never checked for validity and it is not read back in r9701_get_datetime. Avoid setting it to stop tripping static checkers: drivers/rtc/rtc-r9701.c:109 r9701_set_datetime() error: undefined (user controlled) shift '1 << dt->tm_wday' Reported-by: Dan Carpenter Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201015191135.471249-4-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-r9701.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 4b688e9c4192..183c5a0fe78c 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -100,7 +100,6 @@ static int r9701_set_datetime(struct device *dev, struct rtc_time *dt) ret = ret ? ret : write_reg(dev, RDAYCNT, bin2bcd(dt->tm_mday)); ret = ret ? ret : write_reg(dev, RMONCNT, bin2bcd(dt->tm_mon + 1)); ret = ret ? ret : write_reg(dev, RYRCNT, bin2bcd(dt->tm_year - 100)); - ret = ret ? ret : write_reg(dev, RWKCNT, 1 << dt->tm_wday); return ret; } -- cgit v1.2.3 From dfe13cf2ae5a7cdb131e61a8aae4fb27cd379bd4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 15 Oct 2020 21:11:34 +0200 Subject: rtc: r9701: convert to devm_rtc_allocate_device This allows further improvement of the driver. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201015191135.471249-5-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-r9701.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 183c5a0fe78c..9165c180b0e6 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -122,14 +122,14 @@ static int r9701_probe(struct spi_device *spi) return -ENODEV; } - rtc = devm_rtc_device_register(&spi->dev, "r9701", - &r9701_rtc_ops, THIS_MODULE); + rtc = devm_rtc_allocate_device(&spi->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); spi_set_drvdata(spi, rtc); + rtc->ops = &r9701_rtc_ops; - return 0; + return rtc_register_device(rtc); } static struct spi_driver r9701_driver = { -- cgit v1.2.3 From 35331b506f6c67a0b4042fac1ae2785cef9ac8c3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 15 Oct 2020 21:11:35 +0200 Subject: rtc: r9701: set range Set range and remove the set_time check. This is a classic BCD RTC. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201015191135.471249-6-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-r9701.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 9165c180b0e6..7ceb968f0e44 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -88,11 +88,7 @@ static int r9701_get_datetime(struct device *dev, struct rtc_time *dt) static int r9701_set_datetime(struct device *dev, struct rtc_time *dt) { - int ret, year; - - year = dt->tm_year + 1900; - if (year >= 2100 || year < 2000) - return -EINVAL; + int ret; ret = write_reg(dev, RHRCNT, bin2bcd(dt->tm_hour)); ret = ret ? ret : write_reg(dev, RMINCNT, bin2bcd(dt->tm_min)); @@ -128,6 +124,8 @@ static int r9701_probe(struct spi_device *spi) spi_set_drvdata(spi, rtc); rtc->ops = &r9701_rtc_ops; + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2099; return rtc_register_device(rtc); } -- cgit v1.2.3