From 31f077c374a8e7cf1960560c0c5e4065048557c0 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:44 -0400 Subject: [PATCH 01/73] rtc: pcf2127: improve rtc_read_time() performance Improve performance and readability of rtc_read_time() by reading only the 7 time registers, instead of reading 8 registers (additional CTRL3 register). We drop reading of CTRL3 to monitor the low battery flag, as this check is already available in the ioctl. Anyway, this check only display an info message and has no other impacts. The code readability also improves as we do not have to fiddle with buffer pointer and size arithmetic. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-2-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 42 +++++++++++++-------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index ee03b04b74baa..8d40a413a8fe3 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -45,12 +45,6 @@ /* Time and date registers */ #define PCF2127_REG_SC 0x03 #define PCF2127_BIT_SC_OSF BIT(7) -#define PCF2127_REG_MN 0x04 -#define PCF2127_REG_HR 0x05 -#define PCF2127_REG_DM 0x06 -#define PCF2127_REG_DW 0x07 -#define PCF2127_REG_MO 0x08 -#define PCF2127_REG_YR 0x09 /* Alarm registers */ #define PCF2127_REG_ALARM_SC 0x0A #define PCF2127_REG_ALARM_MN 0x0B @@ -117,27 +111,22 @@ struct pcf2127 { static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned char buf[10]; + unsigned char buf[7]; int ret; /* * Avoid reading CTRL2 register as it causes WD_VAL register * value to reset to 0 which means watchdog is stopped. */ - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3, - (buf + PCF2127_REG_CTRL3), - ARRAY_SIZE(buf) - PCF2127_REG_CTRL3); + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC, buf, + sizeof(buf)); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; } - if (buf[PCF2127_REG_CTRL3] & PCF2127_BIT_CTRL3_BLF) - dev_info(dev, - "low voltage detected, check/replace RTC battery.\n"); - /* Clock integrity is not guaranteed when OSF flag is set. */ - if (buf[PCF2127_REG_SC] & PCF2127_BIT_SC_OSF) { + if (buf[0] & PCF2127_BIT_SC_OSF) { /* * no need clear the flag here, * it will be cleared once the new date is saved @@ -148,20 +137,17 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) } dev_dbg(dev, - "%s: raw data is cr3=%02x, sec=%02x, min=%02x, hr=%02x, " + "%s: raw data is sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", - __func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC], - buf[PCF2127_REG_MN], buf[PCF2127_REG_HR], - buf[PCF2127_REG_DM], buf[PCF2127_REG_DW], - buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]); - - tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); - tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); - tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */ - tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F); - tm->tm_wday = buf[PCF2127_REG_DW] & 0x07; - tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]); + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + tm->tm_sec = bcd2bin(buf[0] & 0x7F); + tm->tm_min = bcd2bin(buf[1] & 0x7F); + tm->tm_hour = bcd2bin(buf[2] & 0x3F); /* rtc hr 0-23 */ + tm->tm_mday = bcd2bin(buf[3] & 0x3F); + tm->tm_wday = buf[4] & 0x07; + tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(buf[6]); tm->tm_year += 100; dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " From 720fb4b83b565c7ae31059620e960ecbf5dc73a3 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:45 -0400 Subject: [PATCH 02/73] rtc: pcf2127: improve timestamp reading performance Reading the 7 timetamp registers currently involves reading 25 registers solely to be able to print the content of the three control registers, in addition to the 7 timestamp registers. This print never occurs, unless the user enables dynamic debug in this driver or set CONFIG_RTC_DEBUG. Reading the timestamp registers should consist of reading 7 consecutive timestamp registers. This patch optimize the performance of reading the timestamp registers by reading 7 consecutive registers instead of 25, and dropping the print of the control registers. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-3-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 8d40a413a8fe3..3332d26aee118 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -66,12 +66,6 @@ #define PCF2127_REG_TS_CTRL 0x12 #define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) #define PCF2127_BIT_TS_CTRL_TSM BIT(7) -#define PCF2127_REG_TS_SC 0x13 -#define PCF2127_REG_TS_MN 0x14 -#define PCF2127_REG_TS_HR 0x15 -#define PCF2127_REG_TS_DM 0x16 -#define PCF2127_REG_TS_MO 0x17 -#define PCF2127_REG_TS_YR 0x18 /* * RAM registers * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is @@ -440,9 +434,9 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) struct pcf2127 *pcf2127 = dev_get_drvdata(dev); struct rtc_time tm; int ret; - unsigned char data[25]; + unsigned char data[7]; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_TS_CTRL, data, sizeof(data)); if (ret) { dev_err(dev, "%s: read error ret=%d\n", __func__, ret); @@ -450,20 +444,16 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) } dev_dbg(dev, - "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", - __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], - data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC], - data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], - data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], - data[PCF2127_REG_TS_YR]); - - tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F); - tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F); - tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F); - tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F); + "%s: raw data is ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", + __func__, data[1], data[2], data[3], data[4], data[5], data[6]); + + tm.tm_sec = bcd2bin(data[1] & 0x7F); + tm.tm_min = bcd2bin(data[2] & 0x7F); + tm.tm_hour = bcd2bin(data[3] & 0x3F); + tm.tm_mday = bcd2bin(data[4] & 0x3F); /* TS_MO register (month) value range: 1-12 */ - tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; - tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); + tm.tm_mon = bcd2bin(data[5] & 0x1F) - 1; + tm.tm_year = bcd2bin(data[6]); if (tm.tm_year < 70) tm.tm_year += 100; /* assume we are in 1970...2069 */ From 3d740c647ff8b77b2a560ebd95ac746c46f49ed4 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:46 -0400 Subject: [PATCH 03/73] rtc: pcf2127: lower message severity if setting time fails Noted while reviewing new PCF2131 driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-4-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 3332d26aee118..2a4d980bb7d5a 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -181,8 +181,7 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) /* write register's data */ err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); if (err) { - dev_err(dev, - "%s: err=%d", __func__, err); + dev_dbg(dev, "%s: err=%d", __func__, err); return err; } From 0476b6c8e8b1a6dfa3a259bc7e3c135145532c71 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:47 -0400 Subject: [PATCH 04/73] rtc: pcf2127: remove superfluous comments Noted while reviewing new PCF2131 driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-5-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 2a4d980bb7d5a..309d1710a1c85 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -137,10 +137,10 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec = bcd2bin(buf[0] & 0x7F); tm->tm_min = bcd2bin(buf[1] & 0x7F); - tm->tm_hour = bcd2bin(buf[2] & 0x3F); /* rtc hr 0-23 */ + tm->tm_hour = bcd2bin(buf[2] & 0x3F); tm->tm_mday = bcd2bin(buf[3] & 0x3F); tm->tm_wday = buf[4] & 0x07; - tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; tm->tm_year = bcd2bin(buf[6]); tm->tm_year += 100; From fd28ceb4603f9541dcb4ed12b1365cff5af38203 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:48 -0400 Subject: [PATCH 05/73] rtc: pcf2127: add variant-specific configuration structure Create variant-specific configuration structures to simplify the implementation of new variants into this driver. It will also avoid to have too many tests for a specific variant, or a list of variants for new devices, inside the code itself. Add configuration options for the support of the NVMEM, bit CD0 in register WD_CTL as well as the maximum number of registers for each variant, instead of hardcoding the variant (PCF2127) inside the i2c_device_id and spi_device_id structures. Also specify a different maximum number of registers (max_register) for the PCF2129. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-6-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 98 +++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 309d1710a1c85..23ab872c36cb2 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -89,10 +90,24 @@ PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_TSF2) +enum pcf21xx_type { + PCF2127, + PCF2129, + PCF21XX_LAST_ID +}; + +struct pcf21xx_config { + int type; /* IC variant */ + int max_register; + unsigned int has_nvmem:1; + unsigned int has_bit_wd_ctl_cd0:1; +}; + struct pcf2127 { struct rtc_device *rtc; struct watchdog_device wdd; struct regmap *regmap; + const struct pcf21xx_config *cfg; time64_t ts; bool ts_valid; bool irq_enabled; @@ -606,8 +621,23 @@ static const struct attribute_group pcf2127_attr_group = { .attrs = pcf2127_attrs, }; +static struct pcf21xx_config pcf21xx_cfg[] = { + [PCF2127] = { + .type = PCF2127, + .max_register = 0x1d, + .has_nvmem = 1, + .has_bit_wd_ctl_cd0 = 1, + }, + [PCF2129] = { + .type = PCF2129, + .max_register = 0x19, + .has_nvmem = 0, + .has_bit_wd_ctl_cd0 = 0, + }, +}; + static int pcf2127_probe(struct device *dev, struct regmap *regmap, - int alarm_irq, const char *name, bool is_pcf2127) + int alarm_irq, const char *name, const struct pcf21xx_config *config) { struct pcf2127 *pcf2127; int ret = 0; @@ -620,6 +650,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, return -ENOMEM; pcf2127->regmap = regmap; + pcf2127->cfg = config; dev_set_drvdata(dev, pcf2127); @@ -663,7 +694,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); } - if (is_pcf2127) { + if (pcf2127->cfg->has_nvmem) { struct nvmem_config nvmem_cfg = { .priv = pcf2127, .reg_read = pcf2127_nvmem_read, @@ -709,7 +740,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, PCF2127_BIT_WD_CTL_TF1 | PCF2127_BIT_WD_CTL_TF0, PCF2127_BIT_WD_CTL_CD1 | - (is_pcf2127 ? PCF2127_BIT_WD_CTL_CD0 : 0) | + (pcf2127->cfg->has_bit_wd_ctl_cd0 ? PCF2127_BIT_WD_CTL_CD0 : 0) | PCF2127_BIT_WD_CTL_TF1); if (ret) { dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__); @@ -774,9 +805,9 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, #ifdef CONFIG_OF static const struct of_device_id pcf2127_of_match[] = { - { .compatible = "nxp,pcf2127" }, - { .compatible = "nxp,pcf2129" }, - { .compatible = "nxp,pca2129" }, + { .compatible = "nxp,pcf2127", .data = &pcf21xx_cfg[PCF2127] }, + { .compatible = "nxp,pcf2129", .data = &pcf21xx_cfg[PCF2129] }, + { .compatible = "nxp,pca2129", .data = &pcf21xx_cfg[PCF2129] }, {} }; MODULE_DEVICE_TABLE(of, pcf2127_of_match); @@ -861,26 +892,40 @@ static const struct regmap_bus pcf2127_i2c_regmap = { static struct i2c_driver pcf2127_i2c_driver; static const struct i2c_device_id pcf2127_i2c_id[] = { - { "pcf2127", 1 }, - { "pcf2129", 0 }, - { "pca2129", 0 }, + { "pcf2127", PCF2127 }, + { "pcf2129", PCF2129 }, + { "pca2129", PCF2129 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); static int pcf2127_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_match_id(pcf2127_i2c_id, client); struct regmap *regmap; - static const struct regmap_config config = { + static struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x1d, }; + const struct pcf21xx_config *variant; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; + if (client->dev.of_node) { + variant = of_device_get_match_data(&client->dev); + if (!variant) + return -ENODEV; + } else { + enum pcf21xx_type type = + i2c_match_id(pcf2127_i2c_id, client)->driver_data; + + if (type >= PCF21XX_LAST_ID) + return -ENODEV; + variant = &pcf21xx_cfg[type]; + } + + config.max_register = variant->max_register, + regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap, &client->dev, &config); if (IS_ERR(regmap)) { @@ -890,7 +935,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client) } return pcf2127_probe(&client->dev, regmap, client->irq, - pcf2127_i2c_driver.driver.name, id->driver_data); + pcf2127_i2c_driver.driver.name, variant); } static struct i2c_driver pcf2127_i2c_driver = { @@ -928,17 +973,32 @@ static void pcf2127_i2c_unregister_driver(void) #if IS_ENABLED(CONFIG_SPI_MASTER) static struct spi_driver pcf2127_spi_driver; +static const struct spi_device_id pcf2127_spi_id[]; static int pcf2127_spi_probe(struct spi_device *spi) { - static const struct regmap_config config = { + static struct regmap_config config = { .reg_bits = 8, .val_bits = 8, .read_flag_mask = 0xa0, .write_flag_mask = 0x20, - .max_register = 0x1d, }; struct regmap *regmap; + const struct pcf21xx_config *variant; + + if (spi->dev.of_node) { + variant = of_device_get_match_data(&spi->dev); + if (!variant) + return -ENODEV; + } else { + enum pcf21xx_type type = spi_get_device_id(spi)->driver_data; + + if (type >= PCF21XX_LAST_ID) + return -ENODEV; + variant = &pcf21xx_cfg[type]; + } + + config.max_register = variant->max_register, regmap = devm_regmap_init_spi(spi, &config); if (IS_ERR(regmap)) { @@ -949,13 +1009,13 @@ static int pcf2127_spi_probe(struct spi_device *spi) return pcf2127_probe(&spi->dev, regmap, spi->irq, pcf2127_spi_driver.driver.name, - spi_get_device_id(spi)->driver_data); + variant); } static const struct spi_device_id pcf2127_spi_id[] = { - { "pcf2127", 1 }, - { "pcf2129", 0 }, - { "pca2129", 0 }, + { "pcf2127", PCF2127 }, + { "pcf2129", PCF2129 }, + { "pca2129", PCF2129 }, { } }; MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); From 6211acee8edf4af61f7745a92c4b4cb05a4340f9 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:49 -0400 Subject: [PATCH 06/73] rtc: pcf2127: adapt for time/date registers at any offset This will simplify the implementation of new variants into this driver. Some variants (PCF2131) have a 100th seconds register. This register is currently not supported in this driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-7-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 23ab872c36cb2..e65e86e08acc3 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -44,7 +44,7 @@ #define PCF2127_BIT_CTRL3_BF BIT(3) #define PCF2127_BIT_CTRL3_BTSE BIT(4) /* Time and date registers */ -#define PCF2127_REG_SC 0x03 +#define PCF2127_REG_TIME_BASE 0x03 #define PCF2127_BIT_SC_OSF BIT(7) /* Alarm registers */ #define PCF2127_REG_ALARM_SC 0x0A @@ -101,6 +101,7 @@ struct pcf21xx_config { int max_register; unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; + u8 reg_time_base; /* Time/date base register. */ }; struct pcf2127 { @@ -127,8 +128,8 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) * Avoid reading CTRL2 register as it causes WD_VAL register * value to reset to 0 which means watchdog is stopped. */ - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC, buf, - sizeof(buf)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->reg_time_base, + buf, sizeof(buf)); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; @@ -194,7 +195,7 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[i++] = bin2bcd(tm->tm_year - 100); /* write register's data */ - err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); + err = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->reg_time_base, buf, i); if (err) { dev_dbg(dev, "%s: err=%d", __func__, err); return err; @@ -627,12 +628,14 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x1d, .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, + .reg_time_base = PCF2127_REG_TIME_BASE, }, [PCF2129] = { .type = PCF2129, .max_register = 0x19, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .reg_time_base = PCF2127_REG_TIME_BASE, }, }; From 7c6f0db41ab5fbd7ee3a2f9880ac23509a5d55d1 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:50 -0400 Subject: [PATCH 07/73] rtc: pcf2127: adapt for alarm registers at any offset This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-8-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index e65e86e08acc3..8849d57c0384a 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -47,11 +47,7 @@ #define PCF2127_REG_TIME_BASE 0x03 #define PCF2127_BIT_SC_OSF BIT(7) /* Alarm registers */ -#define PCF2127_REG_ALARM_SC 0x0A -#define PCF2127_REG_ALARM_MN 0x0B -#define PCF2127_REG_ALARM_HR 0x0C -#define PCF2127_REG_ALARM_DM 0x0D -#define PCF2127_REG_ALARM_DW 0x0E +#define PCF2127_REG_ALARM_BASE 0x0A #define PCF2127_BIT_ALARM_AE BIT(7) /* CLKOUT control register */ #define PCF2127_REG_CLKOUT 0x0f @@ -102,6 +98,7 @@ struct pcf21xx_config { unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; u8 reg_time_base; /* Time/date base register. */ + u8 regs_alarm_base; /* Alarm function base registers. */ }; struct pcf2127 { @@ -381,8 +378,8 @@ static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret) return ret; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, - sizeof(buf)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->regs_alarm_base, + buf, sizeof(buf)); if (ret) return ret; @@ -432,8 +429,8 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) buf[3] = bin2bcd(alrm->time.tm_mday); buf[4] = PCF2127_BIT_ALARM_AE; /* Do not match on week day */ - ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, - sizeof(buf)); + ret = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->regs_alarm_base, + buf, sizeof(buf)); if (ret) return ret; @@ -629,6 +626,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, .reg_time_base = PCF2127_REG_TIME_BASE, + .regs_alarm_base = PCF2127_REG_ALARM_BASE, }, [PCF2129] = { .type = PCF2129, @@ -636,6 +634,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, .reg_time_base = PCF2127_REG_TIME_BASE, + .regs_alarm_base = PCF2127_REG_ALARM_BASE, }, }; From 6b57ec29e3fc31d43e672f6fede5d4a76140308b Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:51 -0400 Subject: [PATCH 08/73] rtc: pcf2127: adapt for WD registers at any offset This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Tested-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-9-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 8849d57c0384a..fb1b2b89e9098 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -99,6 +99,8 @@ struct pcf21xx_config { unsigned int has_bit_wd_ctl_cd0:1; u8 reg_time_base; /* Time/date base register. */ u8 regs_alarm_base; /* Alarm function base registers. */ + u8 reg_wd_ctl; /* Watchdog control register. */ + u8 reg_wd_val; /* Watchdog value register. */ }; struct pcf2127 { @@ -269,7 +271,7 @@ static int pcf2127_wdt_ping(struct watchdog_device *wdd) { struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, wdd->timeout); + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wdd->timeout); } /* @@ -303,7 +305,7 @@ static int pcf2127_wdt_stop(struct watchdog_device *wdd) { struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, PCF2127_WD_VAL_STOP); } @@ -352,7 +354,7 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) watchdog_set_drvdata(&pcf2127->wdd, pcf2127); /* Test if watchdog timer is started by bootloader */ - ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout); + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val, &wdd_timeout); if (ret) return ret; @@ -627,6 +629,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_bit_wd_ctl_cd0 = 1, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, + .reg_wd_ctl = PCF2127_REG_WD_CTL, + .reg_wd_val = PCF2127_REG_WD_VAL, }, [PCF2129] = { .type = PCF2129, @@ -635,6 +639,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_bit_wd_ctl_cd0 = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, + .reg_wd_ctl = PCF2127_REG_WD_CTL, + .reg_wd_val = PCF2127_REG_WD_VAL, }, }; @@ -736,7 +742,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, * as T. Bits labeled as T must always be written with * logic 0. */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL, + ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_wd_ctl, PCF2127_BIT_WD_CTL_CD1 | PCF2127_BIT_WD_CTL_CD0 | PCF2127_BIT_WD_CTL_TF1 | From fc16599e0153e91ba12d856e40f6fc56906077f1 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:52 -0400 Subject: [PATCH 09/73] rtc: pcf2127: adapt for CLKOUT register at any offset This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-10-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index fb1b2b89e9098..c4c0bf574e6b0 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -101,6 +101,7 @@ struct pcf21xx_config { u8 regs_alarm_base; /* Alarm function base registers. */ u8 reg_wd_ctl; /* Watchdog control register. */ u8 reg_wd_val; /* Watchdog value register. */ + u8 reg_clkout; /* Clkout register. */ }; struct pcf2127 { @@ -631,6 +632,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, + .reg_clkout = PCF2127_REG_CLKOUT, }, [PCF2129] = { .type = PCF2129, @@ -641,6 +643,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, + .reg_clkout = PCF2127_REG_CLKOUT, }, }; @@ -720,12 +723,12 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1, PCF2127_BIT_CTRL1_POR_OVRD); - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CLKOUT, &val); + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_clkout, &val); if (ret < 0) return ret; if (!(val & PCF2127_BIT_CLKOUT_OTPR)) { - ret = regmap_set_bits(pcf2127->regmap, PCF2127_REG_CLKOUT, + ret = regmap_set_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout, PCF2127_BIT_CLKOUT_OTPR); if (ret < 0) return ret; From 420cc9e850dbc8e6ea7dd1e53d62d64cd8766354 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:53 -0400 Subject: [PATCH 10/73] rtc: pcf2127: add support for multiple TS functions This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-11-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 268 ++++++++++++++++++++++++++++---------- 1 file changed, 201 insertions(+), 67 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index c4c0bf574e6b0..9d91cff173cf2 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -59,8 +59,8 @@ #define PCF2127_BIT_WD_CTL_CD0 BIT(6) #define PCF2127_BIT_WD_CTL_CD1 BIT(7) #define PCF2127_REG_WD_VAL 0x11 -/* Tamper timestamp registers */ -#define PCF2127_REG_TS_CTRL 0x12 +/* Tamper timestamp1 registers */ +#define PCF2127_REG_TS1_BASE 0x12 #define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) #define PCF2127_BIT_TS_CTRL_TSM BIT(7) /* @@ -86,12 +86,36 @@ PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_TSF2) +#define PCF2127_MAX_TS_SUPPORTED 1 + enum pcf21xx_type { PCF2127, PCF2129, PCF21XX_LAST_ID }; +struct pcf21xx_ts_config { + u8 reg_base; /* Base register to read timestamp values. */ + + /* + * If the TS input pin is driven to GND, an interrupt can be generated + * (supported by all variants). + */ + u8 gnd_detect_reg; /* Interrupt control register address. */ + u8 gnd_detect_bit; /* Interrupt bit. */ + + /* + * If the TS input pin is driven to an intermediate level between GND + * and supply, an interrupt can be generated (optional feature depending + * on variant). + */ + u8 inter_detect_reg; /* Interrupt control register address. */ + u8 inter_detect_bit; /* Interrupt bit. */ + + u8 ie_reg; /* Interrupt enable control register. */ + u8 ie_bit; /* Interrupt enable bit. */ +}; + struct pcf21xx_config { int type; /* IC variant */ int max_register; @@ -102,6 +126,9 @@ struct pcf21xx_config { u8 reg_wd_ctl; /* Watchdog control register. */ u8 reg_wd_val; /* Watchdog value register. */ u8 reg_clkout; /* Clkout register. */ + unsigned int ts_count; + struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED]; + struct attribute_group attribute_group; }; struct pcf2127 { @@ -109,9 +136,9 @@ struct pcf2127 { struct watchdog_device wdd; struct regmap *regmap; const struct pcf21xx_config *cfg; - time64_t ts; - bool ts_valid; bool irq_enabled; + time64_t ts[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp values. */ + bool ts_valid[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp valid indication. */ }; /* @@ -441,18 +468,19 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) } /* - * This function reads ctrl2 register, caller is responsible for calling - * pcf2127_wdt_active_ping() + * This function reads one timestamp function data, caller is responsible for + * calling pcf2127_wdt_active_ping() */ -static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) +static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts, + int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); struct rtc_time tm; int ret; unsigned char data[7]; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_TS_CTRL, data, - sizeof(data)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->ts[ts_id].reg_base, + data, sizeof(data)); if (ret) { dev_err(dev, "%s: read error ret=%d\n", __func__, ret); return ret; @@ -482,18 +510,21 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) return 0; }; -static void pcf2127_rtc_ts_snapshot(struct device *dev) +static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); int ret; + if (ts_id >= pcf2127->cfg->ts_count) + return; + /* Let userspace read the first timestamp */ - if (pcf2127->ts_valid) + if (pcf2127->ts_valid[ts_id]) return; - ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts); + ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts[ts_id], ts_id); if (!ret) - pcf2127->ts_valid = true; + pcf2127->ts_valid[ts_id] = true; } static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) @@ -514,7 +545,7 @@ static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) return IRQ_NONE; if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) - pcf2127_rtc_ts_snapshot(dev); + pcf2127_rtc_ts_snapshot(dev, 0); if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, @@ -543,28 +574,41 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { /* sysfs interface */ -static ssize_t timestamp0_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t timestamp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); int ret; + if (ts_id >= pcf2127->cfg->ts_count) + return 0; + if (pcf2127->irq_enabled) { - pcf2127->ts_valid = false; + pcf2127->ts_valid[ts_id] = false; } else { - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, - PCF2127_BIT_CTRL1_TSF1, 0); + /* Always clear GND interrupt bit. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].gnd_detect_reg, + pcf2127->cfg->ts[ts_id].gnd_detect_bit, + 0); + if (ret) { - dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret); + dev_err(dev, "%s: update TS gnd detect ret=%d\n", __func__, ret); return ret; } - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, - PCF2127_BIT_CTRL2_TSF2, 0); - if (ret) { - dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); - return ret; + if (pcf2127->cfg->ts[ts_id].inter_detect_bit) { + /* Clear intermediate level interrupt bit if supported. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].inter_detect_reg, + pcf2127->cfg->ts[ts_id].inter_detect_bit, + 0); + if (ret) { + dev_err(dev, "%s: update TS intermediate level detect ret=%d\n", + __func__, ret); + return ret; + } } ret = pcf2127_wdt_active_ping(&pcf2127->wdd); @@ -573,34 +617,63 @@ static ssize_t timestamp0_store(struct device *dev, } return count; +} + +static ssize_t timestamp0_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 0); }; -static ssize_t timestamp0_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t timestamp_show(struct device *dev, + struct device_attribute *attr, char *buf, + int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); - unsigned int ctrl1, ctrl2; int ret; time64_t ts; + if (ts_id >= pcf2127->cfg->ts_count) + return 0; + if (pcf2127->irq_enabled) { - if (!pcf2127->ts_valid) + if (!pcf2127->ts_valid[ts_id]) return 0; - ts = pcf2127->ts; + ts = pcf2127->ts[ts_id]; } else { - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); - if (ret) - return 0; + u8 valid_low = 0; + u8 valid_inter = 0; + unsigned int ctrl; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); + /* Check if TS input pin is driven to GND, supported by all + * variants. + */ + ret = regmap_read(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].gnd_detect_reg, + &ctrl); if (ret) return 0; - if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) && - !(ctrl2 & PCF2127_BIT_CTRL2_TSF2)) + valid_low = ctrl & pcf2127->cfg->ts[ts_id].gnd_detect_bit; + + if (pcf2127->cfg->ts[ts_id].inter_detect_bit) { + /* Check if TS input pin is driven to intermediate level + * between GND and supply, if supported by variant. + */ + ret = regmap_read(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].inter_detect_reg, + &ctrl); + if (ret) + return 0; + + valid_inter = ctrl & pcf2127->cfg->ts[ts_id].inter_detect_bit; + } + + if (!valid_low && !valid_inter) return 0; - ret = pcf2127_rtc_ts_read(dev->parent, &ts); + ret = pcf2127_rtc_ts_read(dev->parent, &ts, ts_id); if (ret) return 0; @@ -609,6 +682,12 @@ static ssize_t timestamp0_show(struct device *dev, return ret; } return sprintf(buf, "%llu\n", (unsigned long long)ts); +} + +static ssize_t timestamp0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 0); }; static DEVICE_ATTR_RW(timestamp0); @@ -618,10 +697,6 @@ static struct attribute *pcf2127_attrs[] = { NULL }; -static const struct attribute_group pcf2127_attr_group = { - .attrs = pcf2127_attrs, -}; - static struct pcf21xx_config pcf21xx_cfg[] = { [PCF2127] = { .type = PCF2127, @@ -633,6 +708,19 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .ts_count = 1, + .ts[0] = { + .reg_base = PCF2127_REG_TS1_BASE, + .gnd_detect_reg = PCF2127_REG_CTRL1, + .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1, + .inter_detect_reg = PCF2127_REG_CTRL2, + .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2, + .ie_reg = PCF2127_REG_CTRL2, + .ie_bit = PCF2127_BIT_CTRL2_TSIE, + }, + .attribute_group = { + .attrs = pcf2127_attrs, + }, }, [PCF2129] = { .type = PCF2129, @@ -644,9 +732,74 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .ts_count = 1, + .ts[0] = { + .reg_base = PCF2127_REG_TS1_BASE, + .gnd_detect_reg = PCF2127_REG_CTRL1, + .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1, + .inter_detect_reg = PCF2127_REG_CTRL2, + .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2, + .ie_reg = PCF2127_REG_CTRL2, + .ie_bit = PCF2127_BIT_CTRL2_TSIE, + }, + .attribute_group = { + .attrs = pcf2127_attrs, + }, }, }; +/* + * Enable timestamp function and corresponding interrupt(s). + */ +static int pcf2127_enable_ts(struct device *dev, int ts_id) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + int ret; + + if (ts_id >= pcf2127->cfg->ts_count) { + dev_err(dev, "%s: invalid tamper detection ID (%d)\n", + __func__, ts_id); + return -EINVAL; + } + + /* Enable timestamp function. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].reg_base, + PCF2127_BIT_TS_CTRL_TSOFF | + PCF2127_BIT_TS_CTRL_TSM, + PCF2127_BIT_TS_CTRL_TSM); + if (ret) { + dev_err(dev, "%s: tamper detection config (ts%d_ctrl) failed\n", + __func__, ts_id); + return ret; + } + + /* TS input pin driven to GND detection is supported by all variants. + * Make sure that interrupt bit is defined. + */ + if (pcf2127->cfg->ts[ts_id].gnd_detect_bit == 0) { + dev_err(dev, "%s: tamper detection to GND configuration invalid\n", + __func__); + return ret; + } + + /* + * Enable interrupt generation when TSF timestamp flag is set. + * Interrupt signals are open-drain outputs and can be left floating if + * unused. + */ + ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->ts[ts_id].ie_reg, + pcf2127->cfg->ts[ts_id].ie_bit, + pcf2127->cfg->ts[ts_id].ie_bit); + if (ret) { + dev_err(dev, "%s: tamper detection TSIE%d config failed\n", + __func__, ts_id); + return ret; + } + + return ret; +} + static int pcf2127_probe(struct device *dev, struct regmap *regmap, int alarm_irq, const char *name, const struct pcf21xx_config *config) { @@ -777,34 +930,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, } /* - * Enable timestamp function and store timestamp of first trigger - * event until TSF1 and TSF2 interrupt flags are cleared. + * Enable timestamp functions 1 to 4. */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL, - PCF2127_BIT_TS_CTRL_TSOFF | - PCF2127_BIT_TS_CTRL_TSM, - PCF2127_BIT_TS_CTRL_TSM); - if (ret) { - dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n", - __func__); - return ret; - } - - /* - * Enable interrupt generation when TSF1 or TSF2 timestamp flags - * are set. Interrupt signal is an open-drain output and can be - * left floating if unused. - */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, - PCF2127_BIT_CTRL2_TSIE, - PCF2127_BIT_CTRL2_TSIE); - if (ret) { - dev_err(dev, "%s: tamper detection config (ctrl2) failed\n", - __func__); - return ret; + for (int i = 0; i < pcf2127->cfg->ts_count; i++) { + ret = pcf2127_enable_ts(dev, i); + if (ret) + return ret; } - ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group); + ret = rtc_add_group(pcf2127->rtc, &pcf2127->cfg->attribute_group); if (ret) { dev_err(dev, "%s: tamper sysfs registering failed\n", __func__); From afc505bf9039caf5a377d8b9705ef42f6d4ac7d4 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:54 -0400 Subject: [PATCH 11/73] rtc: pcf2127: add support for PCF2131 RTC This RTC is very similar in functionality to the PCF2127/29. Basically it: -supports two new control registers at offsets 4 and 5 -supports a new reset register (not implemented in this driver) -supports 4 tamper detection functions instead of 1 -has no nvmem (like the PCF2129) -has two output interrupt pins Because of that, most of the register addresses are very different, although they still follow the same layout. For example, the tamper registers have a different base address, but the offsets are all the same. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-12-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 4 +- drivers/rtc/rtc-pcf2127.c | 234 ++++++++++++++++++++++++++++++++++---- 2 files changed, 215 insertions(+), 23 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 05f4b2d66290d..e8bad8c93ba99 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -904,9 +904,9 @@ config RTC_DRV_PCF2127 select REGMAP_SPI if SPI_MASTER select WATCHDOG_CORE if WATCHDOG help - If you say yes here you get support for the NXP PCF2127/29 RTC + If you say yes here you get support for the NXP PCF2127/29/31 RTC chips with integrated quartz crystal for industrial applications. - Both chips also have watchdog timer and tamper switch detection + These chips also have watchdog timer and tamper switch detection features. PCF2127 has an additional feature of 512 bytes battery backed diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 9d91cff173cf2..8c2ad9eac861b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * An I2C and SPI driver for the NXP PCF2127/29 RTC + * An I2C and SPI driver for the NXP PCF2127/29/31 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato @@ -8,9 +8,13 @@ * Watchdog and tamper functions * Author: Bruno Thomsen * + * PCF2131 support + * Author: Hugo Villeneuve + * * based on the other drivers in this same directory. * - * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf + * Datasheets: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf + * https://www.nxp.com/docs/en/data-sheet/PCF2131DS.pdf */ #include @@ -67,7 +71,7 @@ * RAM registers * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is * battery backed and can survive a power outage. - * PCF2129 doesn't have this feature. + * PCF2129/31 doesn't have this feature. */ #define PCF2127_REG_RAM_ADDR_MSB 0x1A #define PCF2127_REG_RAM_WRT_CMD 0x1C @@ -86,11 +90,65 @@ PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_TSF2) -#define PCF2127_MAX_TS_SUPPORTED 1 +#define PCF2127_MAX_TS_SUPPORTED 4 + +/* Control register 4 */ +#define PCF2131_REG_CTRL4 0x03 +#define PCF2131_BIT_CTRL4_TSF4 BIT(4) +#define PCF2131_BIT_CTRL4_TSF3 BIT(5) +#define PCF2131_BIT_CTRL4_TSF2 BIT(6) +#define PCF2131_BIT_CTRL4_TSF1 BIT(7) +/* Control register 5 */ +#define PCF2131_REG_CTRL5 0x04 +#define PCF2131_BIT_CTRL5_TSIE4 BIT(4) +#define PCF2131_BIT_CTRL5_TSIE3 BIT(5) +#define PCF2131_BIT_CTRL5_TSIE2 BIT(6) +#define PCF2131_BIT_CTRL5_TSIE1 BIT(7) +/* Software reset register */ +#define PCF2131_REG_SR_RESET 0x05 +#define PCF2131_SR_RESET_READ_PATTERN (BIT(2) | BIT(5)) +#define PCF2131_SR_RESET_CPR_CMD (PCF2131_SR_RESET_READ_PATTERN | BIT(7)) +/* Time and date registers */ +#define PCF2131_REG_TIME_BASE 0x07 +/* Alarm registers */ +#define PCF2131_REG_ALARM_BASE 0x0E +/* CLKOUT control register */ +#define PCF2131_REG_CLKOUT 0x13 +/* Watchdog registers */ +#define PCF2131_REG_WD_CTL 0x35 +#define PCF2131_REG_WD_VAL 0x36 +/* Tamper timestamp1 registers */ +#define PCF2131_REG_TS1_BASE 0x14 +/* Tamper timestamp2 registers */ +#define PCF2131_REG_TS2_BASE 0x1B +/* Tamper timestamp3 registers */ +#define PCF2131_REG_TS3_BASE 0x22 +/* Tamper timestamp4 registers */ +#define PCF2131_REG_TS4_BASE 0x29 +/* Interrupt mask registers */ +#define PCF2131_REG_INT_A_MASK1 0x31 +#define PCF2131_REG_INT_A_MASK2 0x32 +#define PCF2131_REG_INT_B_MASK1 0x33 +#define PCF2131_REG_INT_B_MASK2 0x34 +#define PCF2131_BIT_INT_BLIE BIT(0) +#define PCF2131_BIT_INT_BIE BIT(1) +#define PCF2131_BIT_INT_AIE BIT(2) +#define PCF2131_BIT_INT_WD_CD BIT(3) +#define PCF2131_BIT_INT_SI BIT(4) +#define PCF2131_BIT_INT_MI BIT(5) +#define PCF2131_CTRL2_IRQ_MASK ( \ + PCF2127_BIT_CTRL2_AF | \ + PCF2127_BIT_CTRL2_WDTF) +#define PCF2131_CTRL4_IRQ_MASK ( \ + PCF2131_BIT_CTRL4_TSF4 | \ + PCF2131_BIT_CTRL4_TSF3 | \ + PCF2131_BIT_CTRL4_TSF2 | \ + PCF2131_BIT_CTRL4_TSF1) enum pcf21xx_type { PCF2127, PCF2129, + PCF2131, PCF21XX_LAST_ID }; @@ -530,30 +588,64 @@ static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id) static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned int ctrl1, ctrl2; + unsigned int ctrl2; int ret = 0; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); - if (ret) - return IRQ_NONE; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); if (ret) return IRQ_NONE; - if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) - return IRQ_NONE; + if (pcf2127->cfg->ts_count == 1) { + /* PCF2127/29 */ + unsigned int ctrl1; + + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); + if (ret) + return IRQ_NONE; + + if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) + return IRQ_NONE; + + if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) + pcf2127_rtc_ts_snapshot(dev, 0); + + if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, + ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); - if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) - pcf2127_rtc_ts_snapshot(dev, 0); + if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, + ctrl2 & ~PCF2127_CTRL2_IRQ_MASK); + } else { + /* PCF2131. */ + unsigned int ctrl4; + + ret = regmap_read(pcf2127->regmap, PCF2131_REG_CTRL4, &ctrl4); + if (ret) + return IRQ_NONE; - if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) - regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, - ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); + if (!(ctrl4 & PCF2131_CTRL4_IRQ_MASK || ctrl2 & PCF2131_CTRL2_IRQ_MASK)) + return IRQ_NONE; - if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) - regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, - ctrl2 & ~PCF2127_CTRL2_IRQ_MASK); + if (ctrl4 & PCF2131_CTRL4_IRQ_MASK) { + int i; + int tsf_bit = PCF2131_BIT_CTRL4_TSF1; /* Start at bit 7. */ + + for (i = 0; i < pcf2127->cfg->ts_count; i++) { + if (ctrl4 & tsf_bit) + pcf2127_rtc_ts_snapshot(dev, i); + + tsf_bit = tsf_bit >> 1; + } + + regmap_write(pcf2127->regmap, PCF2131_REG_CTRL4, + ctrl4 & ~PCF2131_CTRL4_IRQ_MASK); + } + + if (ctrl2 & PCF2131_CTRL2_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, + ctrl2 & ~PCF2131_CTRL2_IRQ_MASK); + } if (ctrl2 & PCF2127_BIT_CTRL2_AF) rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF); @@ -626,6 +718,27 @@ static ssize_t timestamp0_store(struct device *dev, return timestamp_store(dev, attr, buf, count, 0); }; +static ssize_t timestamp1_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 1); +}; + +static ssize_t timestamp2_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 2); +}; + +static ssize_t timestamp3_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 3); +}; + static ssize_t timestamp_show(struct device *dev, struct device_attribute *attr, char *buf, int ts_id) @@ -690,13 +803,42 @@ static ssize_t timestamp0_show(struct device *dev, return timestamp_show(dev, attr, buf, 0); }; +static ssize_t timestamp1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 1); +}; + +static ssize_t timestamp2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 2); +}; + +static ssize_t timestamp3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 3); +}; + static DEVICE_ATTR_RW(timestamp0); +static DEVICE_ATTR_RW(timestamp1); +static DEVICE_ATTR_RW(timestamp2); +static DEVICE_ATTR_RW(timestamp3); static struct attribute *pcf2127_attrs[] = { &dev_attr_timestamp0.attr, NULL }; +static struct attribute *pcf2131_attrs[] = { + &dev_attr_timestamp0.attr, + &dev_attr_timestamp1.attr, + &dev_attr_timestamp2.attr, + &dev_attr_timestamp3.attr, + NULL +}; + static struct pcf21xx_config pcf21xx_cfg[] = { [PCF2127] = { .type = PCF2127, @@ -746,6 +888,53 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .attrs = pcf2127_attrs, }, }, + [PCF2131] = { + .type = PCF2131, + .max_register = 0x36, + .has_nvmem = 0, + .has_bit_wd_ctl_cd0 = 0, + .reg_time_base = PCF2131_REG_TIME_BASE, + .regs_alarm_base = PCF2131_REG_ALARM_BASE, + .reg_wd_ctl = PCF2131_REG_WD_CTL, + .reg_wd_val = PCF2131_REG_WD_VAL, + .reg_clkout = PCF2131_REG_CLKOUT, + .ts_count = 4, + .ts[0] = { + .reg_base = PCF2131_REG_TS1_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF1, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE1, + }, + .ts[1] = { + .reg_base = PCF2131_REG_TS2_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF2, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE2, + }, + .ts[2] = { + .reg_base = PCF2131_REG_TS3_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF3, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE3, + }, + .ts[3] = { + .reg_base = PCF2131_REG_TS4_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF4, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE4, + }, + .attribute_group = { + .attrs = pcf2131_attrs, + }, + }, }; /* @@ -893,7 +1082,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, * Watchdog timer enabled and reset pin /RST activated when timed out. * Select 1Hz clock source for watchdog timer. * Note: Countdown timer disabled and not available. - * For pca2129, pcf2129, only bit[7] is for Symbol WD_CD + * For pca2129, pcf2129 and pcf2131, only bit[7] is for Symbol WD_CD * of register watchdg_tim_ctl. The bit[6] is labeled * as T. Bits labeled as T must always be written with * logic 0. @@ -953,6 +1142,7 @@ static const struct of_device_id pcf2127_of_match[] = { { .compatible = "nxp,pcf2127", .data = &pcf21xx_cfg[PCF2127] }, { .compatible = "nxp,pcf2129", .data = &pcf21xx_cfg[PCF2129] }, { .compatible = "nxp,pca2129", .data = &pcf21xx_cfg[PCF2129] }, + { .compatible = "nxp,pcf2131", .data = &pcf21xx_cfg[PCF2131] }, {} }; MODULE_DEVICE_TABLE(of, pcf2127_of_match); @@ -1040,6 +1230,7 @@ static const struct i2c_device_id pcf2127_i2c_id[] = { { "pcf2127", PCF2127 }, { "pcf2129", PCF2129 }, { "pca2129", PCF2129 }, + { "pcf2131", PCF2131 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); @@ -1161,6 +1352,7 @@ static const struct spi_device_id pcf2127_spi_id[] = { { "pcf2127", PCF2127 }, { "pcf2129", PCF2129 }, { "pca2129", PCF2129 }, + { "pcf2131", PCF2131 }, { } }; MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); @@ -1225,5 +1417,5 @@ static void __exit pcf2127_exit(void) module_exit(pcf2127_exit) MODULE_AUTHOR("Renaud Cerrato "); -MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver"); +MODULE_DESCRIPTION("NXP PCF2127/29/31 RTC driver"); MODULE_LICENSE("GPL v2"); From e1849b8fcdfaa71f2e8f9376c9568877ff2bf52b Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:55 -0400 Subject: [PATCH 12/73] rtc: pcf2127: add support for PCF2131 interrupts on output INT_A The PCF2127 and PCF2129 have one output interrupt pin. The PCF2131 has two, named INT_A and INT_B. The hardware support that any interrupt source can be routed to either one or both of them. Force all interrupt sources to go to the INT A pin. Support to route any interrupt source to INT A/B pins is not supported by this driver at the moment. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-13-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 8c2ad9eac861b..83dcb1e43abb0 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -179,6 +179,7 @@ struct pcf21xx_config { int max_register; unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; + unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */ u8 reg_time_base; /* Time/date base register. */ u8 regs_alarm_base; /* Alarm function base registers. */ u8 reg_wd_ctl; /* Watchdog control register. */ @@ -845,6 +846,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x1d, .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, + .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, @@ -869,6 +871,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x19, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, @@ -893,6 +896,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x36, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .has_int_a_b = 1, .reg_time_base = PCF2131_REG_TIME_BASE, .regs_alarm_base = PCF2131_REG_ALARM_BASE, .reg_wd_ctl = PCF2131_REG_WD_CTL, @@ -989,6 +993,28 @@ static int pcf2127_enable_ts(struct device *dev, int ts_id) return ret; } +/* Route all interrupt sources to INT A pin. */ +static int pcf2127_configure_interrupt_pins(struct device *dev) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + int ret; + + /* Mask bits need to be cleared to enable corresponding + * interrupt source. + */ + ret = regmap_write(pcf2127->regmap, + PCF2131_REG_INT_A_MASK1, 0); + if (ret) + return ret; + + ret = regmap_write(pcf2127->regmap, + PCF2131_REG_INT_A_MASK2, 0); + if (ret) + return ret; + + return ret; +} + static int pcf2127_probe(struct device *dev, struct regmap *regmap, int alarm_irq, const char *name, const struct pcf21xx_config *config) { @@ -1047,6 +1073,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); } + if (pcf2127->cfg->has_int_a_b) { + /* Configure int A/B pins, independently of alarm_irq. */ + ret = pcf2127_configure_interrupt_pins(dev); + if (ret) { + dev_err(dev, "failed to configure interrupt pins\n"); + return ret; + } + } + if (pcf2127->cfg->has_nvmem) { struct nvmem_config nvmem_cfg = { .priv = pcf2127, From 3d715ebaf006bd5a495e9a717cf0fc5c260ee738 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:56 -0400 Subject: [PATCH 13/73] rtc: pcf2127: adapt time/date registers write sequence for PCF2131 The sequence for updating the time/date registers is slightly different between PCF2127/29 and PCF2131. For PCF2127/29, during write operations, the time counting circuits (memory locations 03h through 09h) are automatically blocked. For PCF2131, time/date registers write access requires setting the STOP bit and sending the clear prescaler instruction (CPR). STOP then needs to be released once write operation is completed. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-14-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 83dcb1e43abb0..f6a549b1f743b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -33,6 +33,7 @@ #define PCF2127_REG_CTRL1 0x00 #define PCF2127_BIT_CTRL1_POR_OVRD BIT(3) #define PCF2127_BIT_CTRL1_TSF1 BIT(4) +#define PCF2127_BIT_CTRL1_STOP BIT(5) /* Control register 2 */ #define PCF2127_REG_CTRL2 0x01 #define PCF2127_BIT_CTRL2_AIE BIT(1) @@ -280,13 +281,45 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) /* year */ buf[i++] = bin2bcd(tm->tm_year - 100); - /* write register's data */ + /* Write access to time registers: + * PCF2127/29: no special action required. + * PCF2131: requires setting the STOP and CPR bits. STOP bit needs to + * be cleared after time registers are updated. + */ + if (pcf2127->cfg->type == PCF2131) { + err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_STOP, + PCF2127_BIT_CTRL1_STOP); + if (err) { + dev_dbg(dev, "setting STOP bit failed\n"); + return err; + } + + err = regmap_write(pcf2127->regmap, PCF2131_REG_SR_RESET, + PCF2131_SR_RESET_CPR_CMD); + if (err) { + dev_dbg(dev, "sending CPR cmd failed\n"); + return err; + } + } + + /* write time register's data */ err = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->reg_time_base, buf, i); if (err) { dev_dbg(dev, "%s: err=%d", __func__, err); return err; } + if (pcf2127->cfg->type == PCF2131) { + /* Clear STOP bit (PCF2131 only) after write is completed. */ + err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_STOP, 0); + if (err) { + dev_dbg(dev, "clearing STOP bit failed\n"); + return err; + } + } + return 0; } From adb9675d74e403537150f025ed2b7a2e1ed0a7b4 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:57 -0400 Subject: [PATCH 14/73] rtc: pcf2127: support generic watchdog timing configuration Introduce in the configuration structure two new values to hold the watchdog clock source and the min_hw_heartbeat_ms value. The minimum and maximum timeout values are automatically computed from the watchdog clock source value for each variant. The PCF2131 has no 1Hz watchdog clock source, as is the case for PCF2127/29. The next best choice is using a 1/4Hz clock, giving a watchdog timeout range between 4 and 1016s. By using the same register configuration as for the PCF2127/29, the 1/4Hz clock source is selected. Note: the PCF2127 datasheet gives a min/max range between 1 and 255s, but it should be between 2 and 254s, because the watchdog is triggered when the timer value reaches 1, not 0. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-15-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 64 +++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index f6a549b1f743b..59c0dcfed5c80 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -80,9 +80,14 @@ /* Watchdog timer value constants */ #define PCF2127_WD_VAL_STOP 0 -#define PCF2127_WD_VAL_MIN 2 -#define PCF2127_WD_VAL_MAX 255 -#define PCF2127_WD_VAL_DEFAULT 60 +/* PCF2127/29 watchdog timer value constants */ +#define PCF2127_WD_CLOCK_HZ_X1000 1000 /* 1Hz */ +#define PCF2127_WD_MIN_HW_HEARTBEAT_MS 500 +/* PCF2131 watchdog timer value constants */ +#define PCF2131_WD_CLOCK_HZ_X1000 250 /* 1/4Hz */ +#define PCF2131_WD_MIN_HW_HEARTBEAT_MS 4000 + +#define PCF2127_WD_DEFAULT_TIMEOUT_S 60 /* Mask for currently enabled interrupts */ #define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1) @@ -186,6 +191,8 @@ struct pcf21xx_config { u8 reg_wd_ctl; /* Watchdog control register. */ u8 reg_wd_val; /* Watchdog value register. */ u8 reg_clkout; /* Clkout register. */ + int wdd_clock_hz_x1000; /* Watchdog clock in Hz multiplicated by 1000 */ + int wdd_min_hw_heartbeat_ms; unsigned int ts_count; struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED]; struct attribute_group attribute_group; @@ -389,9 +396,16 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset, static int pcf2127_wdt_ping(struct watchdog_device *wdd) { + int wd_val; struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wdd->timeout); + /* + * Compute counter value of WATCHDG_TIM_VAL to obtain desired period + * in seconds, depending on the source clock frequency. + */ + wd_val = ((wdd->timeout * pcf2127->cfg->wdd_clock_hz_x1000) / 1000) + 1; + + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wd_val); } /* @@ -453,6 +467,23 @@ static const struct watchdog_ops pcf2127_watchdog_ops = { .set_timeout = pcf2127_wdt_set_timeout, }; +/* + * Compute watchdog period, t, in seconds, from the WATCHDG_TIM_VAL register + * value, n, and the clock frequency, f1000, in Hz x 1000. + * + * The PCF2127/29 datasheet gives t as: + * t = n / f + * The PCF2131 datasheet gives t as: + * t = (n - 1) / f + * For both variants, the watchdog is triggered when the WATCHDG_TIM_VAL reaches + * the value 1, and not zero. Consequently, the equation from the PCF2131 + * datasheet seems to be the correct one for both variants. + */ +static int pcf2127_watchdog_get_period(int n, int f1000) +{ + return (1000 * (n - 1)) / f1000; +} + static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) { u32 wdd_timeout; @@ -465,10 +496,19 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) pcf2127->wdd.parent = dev; pcf2127->wdd.info = &pcf2127_wdt_info; pcf2127->wdd.ops = &pcf2127_watchdog_ops; - pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN; - pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX; - pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT; - pcf2127->wdd.min_hw_heartbeat_ms = 500; + + pcf2127->wdd.min_timeout = + pcf2127_watchdog_get_period( + 2, pcf2127->cfg->wdd_clock_hz_x1000); + pcf2127->wdd.max_timeout = + pcf2127_watchdog_get_period( + 255, pcf2127->cfg->wdd_clock_hz_x1000); + pcf2127->wdd.timeout = PCF2127_WD_DEFAULT_TIMEOUT_S; + + dev_dbg(dev, "%s clock = %d Hz / 1000\n", __func__, + pcf2127->cfg->wdd_clock_hz_x1000); + + pcf2127->wdd.min_hw_heartbeat_ms = pcf2127->cfg->wdd_min_hw_heartbeat_ms; pcf2127->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS; watchdog_set_drvdata(&pcf2127->wdd, pcf2127); @@ -885,6 +925,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS, .ts_count = 1, .ts[0] = { .reg_base = PCF2127_REG_TS1_BASE, @@ -910,6 +952,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS, .ts_count = 1, .ts[0] = { .reg_base = PCF2127_REG_TS1_BASE, @@ -935,6 +979,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2131_REG_WD_CTL, .reg_wd_val = PCF2131_REG_WD_VAL, .reg_clkout = PCF2131_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2131_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2131_WD_MIN_HW_HEARTBEAT_MS, .ts_count = 4, .ts[0] = { .reg_base = PCF2131_REG_TS1_BASE, @@ -1148,7 +1194,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, /* * Watchdog timer enabled and reset pin /RST activated when timed out. - * Select 1Hz clock source for watchdog timer. + * Select 1Hz clock source for watchdog timer (1/4Hz for PCF2131). * Note: Countdown timer disabled and not available. * For pca2129, pcf2129 and pcf2131, only bit[7] is for Symbol WD_CD * of register watchdg_tim_ctl. The bit[6] is labeled From 081602a1d85b1fd7ad9ea298cffb4e5ad5296952 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:58 -0400 Subject: [PATCH 15/73] rtc: pcf2127: add flag for watchdog register value read support The watchdog value register cannot be read on the PCF2131 after being set. Add a new flag to identify which variant has read access to this register, and use this flag to selectively test if watchdog timer was started by bootloader. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-16-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 59c0dcfed5c80..3acab5a19aba5 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -185,6 +185,7 @@ struct pcf21xx_config { int max_register; unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; + unsigned int wd_val_reg_readable:1; /* If watchdog value register can be read. */ unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */ u8 reg_time_base; /* Time/date base register. */ u8 regs_alarm_base; /* Alarm function base registers. */ @@ -486,7 +487,6 @@ static int pcf2127_watchdog_get_period(int n, int f1000) static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) { - u32 wdd_timeout; int ret; if (!IS_ENABLED(CONFIG_WATCHDOG) || @@ -514,12 +514,17 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) watchdog_set_drvdata(&pcf2127->wdd, pcf2127); /* Test if watchdog timer is started by bootloader */ - ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val, &wdd_timeout); - if (ret) - return ret; + if (pcf2127->cfg->wd_val_reg_readable) { + u32 wdd_timeout; + + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val, + &wdd_timeout); + if (ret) + return ret; - if (wdd_timeout) - set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); + if (wdd_timeout) + set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); + } return devm_watchdog_register_device(dev, &pcf2127->wdd); } @@ -919,6 +924,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x1d, .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, + .wd_val_reg_readable = 1, .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, @@ -946,6 +952,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x19, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .wd_val_reg_readable = 1, .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, @@ -973,6 +980,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x36, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .wd_val_reg_readable = 0, .has_int_a_b = 1, .reg_time_base = PCF2131_REG_TIME_BASE, .regs_alarm_base = PCF2131_REG_ALARM_BASE, From e9a5a1b418dd9a82d1de71e82ec64ad195b5300a Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:59 -0400 Subject: [PATCH 16/73] rtc: pcf2127: add UIE support for PCF2131 The PCF2127/29 do NOT support alarms with a 1 second resolution, but the PCF2131 does. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-17-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 3acab5a19aba5..78141bb06ab0b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1128,8 +1128,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */ - set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features); - clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features); + + /* + * PCF2127/29 do not work correctly when setting alarms at 1s intervals. + * PCF2131 is ok. + */ + if (pcf2127->cfg->type == PCF2127 || pcf2127->cfg->type == PCF2129) { + set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features); + } + clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); if (alarm_irq > 0) { From 2080e08460c41c6d432575132868fdf076768c92 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:58:00 -0400 Subject: [PATCH 17/73] dt-bindings: rtc: pcf2127: add PCF2131 Add support for new NXP RTC PCF2131. Signed-off-by: Hugo Villeneuve Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230622145800.2442116-18-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml index bcb2300276227..2d9fe5a75b067 100644 --- a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml @@ -18,6 +18,7 @@ properties: - nxp,pca2129 - nxp,pcf2127 - nxp,pcf2129 + - nxp,pcf2131 reg: maxItems: 1 From f69cb2d6034ddf8dae6848d29b9d4efba8cd4df9 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 5 Jul 2023 19:43:51 +0200 Subject: [PATCH 18/73] rtc: stm32: use the proper register sequence to read date/time Date and time are read from two separate RTC registers. To ensure consistency between the two registers, reading the time register locks the values in the shadow date register until the date register is read. Thus, the whole date/time read requires reading the time register first, followed by reading the date register. If the reads are done in reversed order, the shadow date register will remain locked until a future read operation. The future read will read the former date value that could be already invalid. Fix the read order of date/time registers in stm32_rtc_valid_alrm() Signed-off-by: Antonio Borneo Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-2-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3d36e11cff80c..abb77ad774a1c 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -429,8 +429,8 @@ static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) { const struct stm32_rtc_registers *regs = &rtc->data->regs; int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; - unsigned int dr = readl_relaxed(rtc->base + regs->dr); unsigned int tr = readl_relaxed(rtc->base + regs->tr); + unsigned int dr = readl_relaxed(rtc->base + regs->dr); cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; From 1c18b8ec52396af6a6e20cd3450dc9bff0781ab8 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 5 Jul 2023 19:43:52 +0200 Subject: [PATCH 19/73] rtc: stm32: don't stop time counter if not needed RTC counters are stopped when INIT bit in ISR register is set and start counting from the (eventual) new value when INIT is reset. In stm32_rtc_init(), called during probe, the INIT bit is set to program the prescaler and the 24h mode. This halts the RTC counter at each probe tentative causing the RTC time to loose from 0.3s to 0.8s at each kernel boot. If the RTC is battery powered, both prescaler value and 24h mode are kept during power cycle and there is no need to program them again. Check if the desired prescaler value and the 24h mode are already programmed, then skip reprogramming them to avoid halting the time counter. Signed-off-by: Antonio Borneo Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-3-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index abb77ad774a1c..bd7a59a07537d 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -628,7 +628,7 @@ static int stm32_rtc_init(struct platform_device *pdev, const struct stm32_rtc_registers *regs = &rtc->data->regs; unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr; unsigned int rate; - int ret = 0; + int ret; rate = clk_get_rate(rtc->rtc_ck); @@ -656,6 +656,20 @@ static int stm32_rtc_init(struct platform_device *pdev, "fast" : "slow"); } + cr = readl_relaxed(rtc->base + regs->cr); + + prer = readl_relaxed(rtc->base + regs->prer); + prer &= STM32_RTC_PRER_PRED_S | STM32_RTC_PRER_PRED_A; + + pred_s = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & + STM32_RTC_PRER_PRED_S; + pred_a = (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & + STM32_RTC_PRER_PRED_A; + + /* quit if there is nothing to initialize */ + if ((cr & STM32_RTC_CR_FMT) == 0 && prer == (pred_s | pred_a)) + return 0; + stm32_rtc_wpr_unlock(rtc); ret = stm32_rtc_enter_init_mode(rtc); @@ -665,13 +679,10 @@ static int stm32_rtc_init(struct platform_device *pdev, goto end; } - prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; - writel_relaxed(prer, rtc->base + regs->prer); - prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A; - writel_relaxed(prer, rtc->base + regs->prer); + writel_relaxed(pred_s, rtc->base + regs->prer); + writel_relaxed(pred_a | pred_s, rtc->base + regs->prer); /* Force 24h time format */ - cr = readl_relaxed(rtc->base + regs->cr); cr &= ~STM32_RTC_CR_FMT; writel_relaxed(cr, rtc->base + regs->cr); From 2487925731b75961cf4b7d1d0d28d204b63787b9 Mon Sep 17 00:00:00 2001 From: Christophe Guibout Date: Wed, 5 Jul 2023 19:43:53 +0200 Subject: [PATCH 20/73] rtc: stm32: improve rtc precision The rtc is used to update the stgen counter on wake up from low power modes, so it needs to be as much accurate as possible. The maximization of asynchronous divider leads to a 4ms rtc precision clock. By decreasing pred_a to 0, it will have pred_s=32767 (when need_accuracy is true), so stgen clock becomes more accurate with 30us precision. Nevertheless this will leads to an increase of power consumption. Signed-off-by: Christophe Guibout Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-4-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index bd7a59a07537d..cad88668bcfb3 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -114,6 +114,7 @@ struct stm32_rtc_data { void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); bool has_pclk; bool need_dbp; + bool need_accuracy; }; struct stm32_rtc { @@ -545,6 +546,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32_rtc_data = { .has_pclk = false, .need_dbp = true, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -566,6 +568,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = { .has_pclk = true, .need_dbp = true, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -596,6 +599,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32mp1_data = { .has_pclk = true, .need_dbp = false, + .need_accuracy = true, .regs = { .tr = 0x00, .dr = 0x04, @@ -636,11 +640,25 @@ static int stm32_rtc_init(struct platform_device *pdev, pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; - for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { - pred_s = (rate / (pred_a + 1)) - 1; + if (rate > (pred_a_max + 1) * (pred_s_max + 1)) { + dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate); + return -EINVAL; + } + + if (rtc->data->need_accuracy) { + for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { + pred_s = (rate / (pred_a + 1)) - 1; - if (((pred_s + 1) * (pred_a + 1)) == rate) - break; + if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate) + break; + } + } else { + for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { + pred_s = (rate / (pred_a + 1)) - 1; + + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } } /* From 95f7679c3ab2d032d935692426b6d9f7e681fd60 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Wed, 5 Jul 2023 19:43:54 +0200 Subject: [PATCH 21/73] rtc: stm32: don't print an error on probe deferral Change stm32-rtc driver to not generate an error message when device probe operation is deferred for a clock. Signed-off-by: Etienne Carriere Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-5-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index cad88668bcfb3..5ebf0b8e75f97 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -759,16 +760,13 @@ static int stm32_rtc_probe(struct platform_device *pdev) rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL); } else { rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(rtc->pclk)) { - dev_err(&pdev->dev, "no pclk clock"); - return PTR_ERR(rtc->pclk); - } + if (IS_ERR(rtc->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->pclk), "no pclk clock"); + rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); } - if (IS_ERR(rtc->rtc_ck)) { - dev_err(&pdev->dev, "no rtc_ck clock"); - return PTR_ERR(rtc->rtc_ck); - } + if (IS_ERR(rtc->rtc_ck)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_ck), "no rtc_ck clock"); if (rtc->data->has_pclk) { ret = clk_prepare_enable(rtc->pclk); From fb9a7e5360dc8089097337a9685f6fed350a310f Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Wed, 5 Jul 2023 19:43:55 +0200 Subject: [PATCH 22/73] rtc: stm32: change PM callbacks to "_noirq()" The RTC driver stops the RTCAPB clock during suspend, but the irq handler from RTC is called before starting clock. Then we are blocked while accessing RTC registers. We changes PM callbacks to '_no_irq()' to disable irq during resume callback and so irq handler will be called after the enable of RTCAPB clock. Signed-off-by: Gabriel Fernandez Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-6-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 5ebf0b8e75f97..17e5498067847 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -919,8 +919,9 @@ static int stm32_rtc_resume(struct device *dev) } #endif -static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, - stm32_rtc_suspend, stm32_rtc_resume); +static const struct dev_pm_ops stm32_rtc_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) +}; static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, From 46828a5f89044b8e057f6bbb50ae2bac926a0fa2 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Wed, 5 Jul 2023 19:43:56 +0200 Subject: [PATCH 23/73] rtc: stm32: fix issues of stm32_rtc_valid_alrm function stm32_rtc_valid_alrm function has some issues : - arithmetical operations are impossible on BCD values - "cur_mon + 1" can overflow - the use case with the next month, the same day/hour/minutes went wrong To solve that, we prefer to use timestamp comparison. e.g. : On 5 Dec. 2021, the alarm limit is 5 Jan. 2022 (+31 days) On 31 Jan 2021, the alarm limit is 28 Feb. 2022 (+28 days) Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-7-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 61 ++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 17e5498067847..836d39a124dd6 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -90,6 +90,9 @@ /* Max STM32 RTC register offset is 0x3FC */ #define UNDEF_REG 0xFFFF +/* STM32 RTC driver time helpers */ +#define SEC_PER_DAY (24 * 60 * 60) + struct stm32_rtc; struct stm32_rtc_registers { @@ -427,40 +430,42 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) +static int stm32_rtc_valid_alrm(struct device *dev, struct rtc_time *tm) { - const struct stm32_rtc_registers *regs = &rtc->data->regs; - int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; - unsigned int tr = readl_relaxed(rtc->base + regs->tr); - unsigned int dr = readl_relaxed(rtc->base + regs->dr); - - cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; - cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; - cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT; - cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT; - cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT; - cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT; + static struct rtc_time now; + time64_t max_alarm_time64; + int max_day_forward; + int next_month; + int next_year; /* * Assuming current date is M-D-Y H:M:S. * RTC alarm can't be set on a specific month and year. * So the valid alarm range is: * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S - * with a specific case for December... */ - if ((((tm->tm_year > cur_year) && - (tm->tm_mon == 0x1) && (cur_mon == 0x12)) || - ((tm->tm_year == cur_year) && - (tm->tm_mon <= cur_mon + 1))) && - ((tm->tm_mday > cur_day) || - ((tm->tm_mday == cur_day) && - ((tm->tm_hour > cur_hour) || - ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || - ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && - (tm->tm_sec >= cur_sec)))))) - return 0; + stm32_rtc_read_time(dev, &now); + + /* + * Find the next month and the year of the next month. + * Note: tm_mon and next_month are from 0 to 11 + */ + next_month = now.tm_mon + 1; + if (next_month == 12) { + next_month = 0; + next_year = now.tm_year + 1; + } else { + next_year = now.tm_year; + } - return -EINVAL; + /* Find the maximum limit of alarm in days. */ + max_day_forward = rtc_month_days(now.tm_mon, now.tm_year) + - now.tm_mday + + min(rtc_month_days(next_month, next_year), now.tm_mday); + + /* Convert to timestamp and compare the alarm time and its upper limit */ + max_alarm_time64 = rtc_tm_to_time64(&now) + max_day_forward * SEC_PER_DAY; + return rtc_tm_to_time64(tm) <= max_alarm_time64 ? 0 : -EINVAL; } static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -471,17 +476,17 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned int cr, isr, alrmar; int ret = 0; - tm2bcd(tm); - /* * RTC alarm can't be set on a specific date, unless this date is * up to the same day of month next month. */ - if (stm32_rtc_valid_alrm(rtc, tm) < 0) { + if (stm32_rtc_valid_alrm(dev, tm) < 0) { dev_err(dev, "Alarm can be set only on upcoming month.\n"); return -EINVAL; } + tm2bcd(tm); + alrmar = 0; /* tm_year and tm_mon are not used because not supported by RTC */ alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) & From 650915ecd8f8cbb58e1ef55430f9e15ae03fd7d8 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Wed, 5 Jul 2023 19:43:57 +0200 Subject: [PATCH 24/73] rtc: stm32: fix unnecessary parentheses Fix a few style issues reported by checkpatch.pl: - Unnecessary parentheses - Lines should not end with a '(' Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-8-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 836d39a124dd6..85689192fa7ae 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -163,10 +163,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) * slowest rtc_ck frequency may be 32kHz and highest should be * 1MHz, we poll every 10 us with a timeout of 100ms. */ - return readl_relaxed_poll_timeout_atomic( - rtc->base + regs->isr, - isr, (isr & STM32_RTC_ISR_INITF), - 10, 100000); + return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr, + (isr & STM32_RTC_ISR_INITF), + 10, 100000); } return 0; @@ -671,7 +670,7 @@ static int stm32_rtc_init(struct platform_device *pdev, * Can't find a 1Hz, so give priority to RTC power consumption * by choosing the higher possible value for prediv_a */ - if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) { + if (pred_s > pred_s_max || pred_a > pred_a_max) { pred_a = pred_a_max; pred_s = (rate / (pred_a + 1)) - 1; From b7f73b6e921b457a222e86cf53fe3950c6b5aed5 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 10 Jul 2023 12:47:47 +0100 Subject: [PATCH 25/73] rtc: isl1208: Simplify probe() Simplify the probe() by replacing of_device_get_match_data() and i2c_match_id() by i2c_get_match_data() as we have similar I2C and DT-based matching table. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230710114747.106496-1-biju.das.jz@bp.renesas.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index b0712b4e36489..57e77b55e4842 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -862,17 +862,9 @@ isl1208_probe(struct i2c_client *client) i2c_set_clientdata(client, isl1208); /* Determine which chip we have */ - if (client->dev.of_node) { - isl1208->config = of_device_get_match_data(&client->dev); - if (!isl1208->config) - return -ENODEV; - } else { - const struct i2c_device_id *id = i2c_match_id(isl1208_id, client); - - if (!id) - return -ENODEV; - isl1208->config = (struct isl1208_config *)id->driver_data; - } + isl1208->config = i2c_get_match_data(client); + if (!isl1208->config) + return -ENODEV; rc = isl1208_clk_present(client, "xin"); if (rc < 0) From 68c624f860b30408afde81a91b4c9df3e915ed85 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 17 Jul 2023 13:40:58 +0100 Subject: [PATCH 26/73] rtc: pcf85063: Simplify probe() The pcf85063_ids[].driver_data could store a pointer to the config, like for DT-based matching, making I2C and DT-based matching more similar. After that, we can simplify the probe() by replacing of_device_get_ match_data() and i2c_match_id() by i2c_get_match_data() as we have similar I2C and DT-based matching table. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230717124059.196244-2-biju.das.jz@bp.renesas.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index e517abfaee2a0..a3b75c96ff9ae 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -556,8 +556,6 @@ static struct pcf85063_config pcf85063_cfg[] = { }, }; -static const struct i2c_device_id pcf85063_ids[]; - static int pcf85063_probe(struct i2c_client *client) { struct pcf85063 *pcf85063; @@ -579,17 +577,9 @@ static int pcf85063_probe(struct i2c_client *client) if (!pcf85063) return -ENOMEM; - if (client->dev.of_node) { - config = of_device_get_match_data(&client->dev); - if (!config) - return -ENODEV; - } else { - enum pcf85063_type type = - i2c_match_id(pcf85063_ids, client)->driver_data; - if (type >= PCF85063_LAST_ID) - return -ENODEV; - config = &pcf85063_cfg[type]; - } + config = i2c_get_match_data(client); + if (!config) + return -ENODEV; pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap); if (IS_ERR(pcf85063->regmap)) @@ -655,11 +645,11 @@ static int pcf85063_probe(struct i2c_client *client) } static const struct i2c_device_id pcf85063_ids[] = { - { "pca85073a", PCF85063A }, - { "pcf85063", PCF85063 }, - { "pcf85063tp", PCF85063TP }, - { "pcf85063a", PCF85063A }, - { "rv8263", RV8263 }, + { "pca85073a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, + { "pcf85063", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063] }, + { "pcf85063tp", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063TP] }, + { "pcf85063a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, + { "rv8263", .driver_data = (kernel_ulong_t)&pcf85063_cfg[RV8263] }, {} }; MODULE_DEVICE_TABLE(i2c, pcf85063_ids); From 5789837c782771eadc9be47487067399609832e7 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 17 Jul 2023 13:40:59 +0100 Subject: [PATCH 27/73] rtc: pcf85063: Drop enum pcf85063_type and split pcf85063_cfg[] Drop enum pcf85063_type and split the array pcf85063_cfg[] as individual variables, and make lines shorter by referring to e.g. &pcf85063_cfg instead of &pcf85063_cfg[PCF85063]. Suggested-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230717124059.196244-3-biju.das.jz@bp.renesas.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 83 +++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index a3b75c96ff9ae..f501b6f9ed014 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -514,46 +514,39 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) } #endif -enum pcf85063_type { - PCF85063, - PCF85063TP, - PCF85063A, - RV8263, - PCF85063_LAST_ID +static const struct pcf85063_config config_pcf85063 = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0a, + }, }; -static struct pcf85063_config pcf85063_cfg[] = { - [PCF85063] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x0a, - }, - }, - [PCF85063TP] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x0a, - }, +static const struct pcf85063_config config_pcf85063tp = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0a, }, - [PCF85063A] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x11, - }, - .has_alarms = 1, +}; + +static const struct pcf85063_config config_pcf85063a = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, }, - [RV8263] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x11, - }, - .has_alarms = 1, - .force_cap_7000 = 1, + .has_alarms = 1, +}; + +static const struct pcf85063_config config_rv8263 = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, }, + .has_alarms = 1, + .force_cap_7000 = 1, }; static int pcf85063_probe(struct i2c_client *client) @@ -645,22 +638,22 @@ static int pcf85063_probe(struct i2c_client *client) } static const struct i2c_device_id pcf85063_ids[] = { - { "pca85073a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, - { "pcf85063", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063] }, - { "pcf85063tp", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063TP] }, - { "pcf85063a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, - { "rv8263", .driver_data = (kernel_ulong_t)&pcf85063_cfg[RV8263] }, + { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a }, + { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 }, + { "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp }, + { "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a }, + { "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 }, {} }; MODULE_DEVICE_TABLE(i2c, pcf85063_ids); #ifdef CONFIG_OF static const struct of_device_id pcf85063_of_match[] = { - { .compatible = "nxp,pca85073a", .data = &pcf85063_cfg[PCF85063A] }, - { .compatible = "nxp,pcf85063", .data = &pcf85063_cfg[PCF85063] }, - { .compatible = "nxp,pcf85063tp", .data = &pcf85063_cfg[PCF85063TP] }, - { .compatible = "nxp,pcf85063a", .data = &pcf85063_cfg[PCF85063A] }, - { .compatible = "microcrystal,rv8263", .data = &pcf85063_cfg[RV8263] }, + { .compatible = "nxp,pca85073a", .data = &config_pcf85063a }, + { .compatible = "nxp,pcf85063", .data = &config_pcf85063 }, + { .compatible = "nxp,pcf85063tp", .data = &config_pcf85063tp }, + { .compatible = "nxp,pcf85063a", .data = &config_pcf85063a }, + { .compatible = "microcrystal,rv8263", .data = &config_rv8263 }, {} }; MODULE_DEVICE_TABLE(of, pcf85063_of_match); From 766c3f8a092b4d42abd68ee0338349838430a5ee Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 19 Jul 2023 21:28:18 +0200 Subject: [PATCH 28/73] rtc: bq4802: add sparc dependency The added HAS_IOPORT dependency might not actually be necessary as Geert points out, but the driver is also only used on one architecture. Sparc is also a special case here since it converts port numbers into virtual addresses rather than having them mapped into a particular part of the __iomem address space, so the difference is actually not important here. Add a dependency on sparc, but allow compile-testing otherwise, to make this clearer without anyone having to spend much time modernizing the driver beyond that. Reported-by: Geert Uytterhoeven Cc: David S. Miller Link: https://lore.kernel.org/all/CAMuHMdWEx0F=fNei4Bz_JPkuvoaN-+zk08h0i8KnSi_VjO615g@mail.gmail.com/ Signed-off-by: Arnd Bergmann Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230719192835.1025406-1-arnd@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e8bad8c93ba99..d7502433c78aa 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1196,6 +1196,7 @@ config RTC_DRV_MSM6242 config RTC_DRV_BQ4802 tristate "TI BQ4802" depends on HAS_IOMEM && HAS_IOPORT + depends on SPARC || COMPILE_TEST help If you say Y here you will get support for the TI BQ4802 RTC chip. From 3c87b351809f220294aec3c0df7b078ff5c5b15b Mon Sep 17 00:00:00 2001 From: Andrej Picej Date: Fri, 23 Jun 2023 10:15:33 +0200 Subject: [PATCH 29/73] rtc: rv3028: Add support for "aux-voltage-chargeable" property Property "trickle-resistor-ohms" allows us to set trickle charger resistor. However there is no possibility to disable it afterwards. Add support for "aux-voltage-chargeable" property which can be used to enable/disable the trickle charger circuit explicitly. The default behavior of the code is kept as it is! Additionally, lets make sure we only update internal EEPROM in case of a change. This prevents wear due to excessive EEPROM writes on each probe. Signed-off-by: Andrej Picej Link: https://lore.kernel.org/r/20230623081533.76334-1-andrej.picej@norik.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv3028.c | 80 ++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 076e56f4e01a5..e039b472eaa63 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -855,11 +855,68 @@ static const struct regmap_config regmap_config = { .max_register = 0x37, }; +static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028, + struct i2c_client *client) +{ + int ret, val_old, val; + u32 ohms, chargeable; + + ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old); + if (ret < 0) + return ret; + + /* mask out only trickle charger bits */ + val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK); + val = val_old; + + /* setup trickle charger */ + if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", + &ohms)) { + int i; + + for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++) + if (ohms == rv3028_trickle_resistors[i]) + break; + + if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { + /* enable trickle charger and its resistor */ + val = RV3028_BACKUP_TCE | i; + } else { + dev_warn(&client->dev, "invalid trickle resistor value\n"); + } + } + + if (!device_property_read_u32(&client->dev, "aux-voltage-chargeable", + &chargeable)) { + switch (chargeable) { + case 0: + val &= ~RV3028_BACKUP_TCE; + break; + case 1: + val |= RV3028_BACKUP_TCE; + break; + default: + dev_warn(&client->dev, + "unsupported aux-voltage-chargeable value\n"); + break; + } + } + + /* only update EEPROM if changes are necessary */ + if (val_old != val) { + ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | + RV3028_BACKUP_TCR_MASK, val); + if (ret) + return ret; + } + + return ret; +} + static int rv3028_probe(struct i2c_client *client) { struct rv3028_data *rv3028; int ret, status; - u32 ohms; struct nvmem_config nvmem_cfg = { .name = "rv3028_nvram", .word_size = 1, @@ -937,24 +994,9 @@ static int rv3028_probe(struct i2c_client *client) if (ret) return ret; - /* setup trickle charger */ - if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", - &ohms)) { - int i; - - for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++) - if (ohms == rv3028_trickle_resistors[i]) - break; - - if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { - ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | - RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i); - if (ret) - return ret; - } else { - dev_warn(&client->dev, "invalid trickle resistor value\n"); - } - } + ret = rv3028_set_trickle_charger(rv3028, client); + if (ret) + return ret; ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group); if (ret) From 48144c2890503b919bc8ee128b63e37008d69250 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Jul 2023 14:54:54 -0600 Subject: [PATCH 30/73] rtc: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230724205456.767430-1-robh@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 2 +- drivers/rtc/rtc-armada38x.c | 1 - drivers/rtc/rtc-at91rm9200.c | 1 - drivers/rtc/rtc-ds1742.c | 1 - drivers/rtc/rtc-fsl-ftm-alarm.c | 5 +---- drivers/rtc/rtc-isl12026.c | 1 - drivers/rtc/rtc-isl1208.c | 2 +- drivers/rtc/rtc-jz4740.c | 2 +- drivers/rtc/rtc-lpc24xx.c | 3 +-- drivers/rtc/rtc-m41t80.c | 2 +- drivers/rtc/rtc-mpc5121.c | 4 +--- drivers/rtc/rtc-mt6397.c | 2 +- drivers/rtc/rtc-mt7622.c | 4 ++-- drivers/rtc/rtc-mxc.c | 1 - drivers/rtc/rtc-pcf85063.c | 2 +- drivers/rtc/rtc-pcf85363.c | 1 - drivers/rtc/rtc-pxa.c | 1 - drivers/rtc/rtc-rs5c372.c | 2 +- drivers/rtc/rtc-rv3028.c | 2 +- drivers/rtc/rtc-rv3032.c | 2 +- drivers/rtc/rtc-rv8803.c | 2 +- drivers/rtc/rtc-rx6110.c | 1 - drivers/rtc/rtc-rx8581.c | 1 - drivers/rtc/rtc-rzn1.c | 2 +- drivers/rtc/rtc-s3c.c | 1 - drivers/rtc/rtc-stm32.c | 3 ++- drivers/rtc/rtc-stmp3xxx.c | 1 - drivers/rtc/rtc-sun6i.c | 1 - drivers/rtc/rtc-sunxi.c | 2 -- drivers/rtc/rtc-ti-k3.c | 2 +- 30 files changed, 19 insertions(+), 38 deletions(-) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index e08d3181bd2a6..fde2b8054c2ea 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index b4139c2006766..8abcad38b10c2 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index e9d17232d0a81..245588a7b417c 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index a5026b0514e78..6ae8b9a294fee 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c index 3d7c4077fe1c6..a72c4ad0cec6e 100644 --- a/drivers/rtc/rtc-fsl-ftm-alarm.c +++ b/drivers/rtc/rtc-fsl-ftm-alarm.c @@ -11,11 +11,8 @@ #include #include #include -#include -#include #include -#include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 5abff5d348acd..8b00659fc955e 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 57e77b55e4842..712ca652d6d3c 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 36453b008139b..6ba889d7d4c4f 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c index a4612e543f353..df17c48ff086e 100644 --- a/drivers/rtc/rtc-lpc24xx.c +++ b/drivers/rtc/rtc-lpc24xx.c @@ -9,9 +9,8 @@ #include #include #include +#include #include -#include -#include #include #include diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 3cc5151e09864..866489ad56d67 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 07df43e4c4d06..28858fcaea8f6 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -11,10 +11,8 @@ #include #include #include -#include -#include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 1d297af80f878..1617063669cc5 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c index 81857a457c326..094c649fc137f 100644 --- a/drivers/rtc/rtc-mt7622.c +++ b/drivers/rtc/rtc-mt7622.c @@ -7,9 +7,9 @@ #include #include +#include +#include #include -#include -#include #include #include diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 762cf03345f14..dbb935dbbd8ab 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -11,7 +11,6 @@ #include #include #include -#include #define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index f501b6f9ed014..fdbc07f14036a 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index 65b8b1338dbb0..569c79bac0ee8 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -15,7 +15,6 @@ #include #include #include -#include #include /* diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index eeacf480cf362..e400c78252e82 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "rtc-sa1100.h" diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index a5a6c8772ecd4..ecabeef091960 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* * Ricoh has a family of I2C based RTCs, which differ only slightly from diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index e039b472eaa63..2f001c59c61d5 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index 6b8eb2039a333..35b2e36b426a0 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 98679cae13e84..fd8ab0b2f731b 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #define RV8803_I2C_TRY_COUNT 4 diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 8702db6096ba4..834274db8c3fd 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 82881fd2e14a1..48efd61a114d4 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index dca736caba852..6f98969eedca3 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 70e1a18e5efdf..282238818f63b 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 85689192fa7ae..3ae875b19af82 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -11,7 +11,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 6f11b745f34d9..7566d0a44af82 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 71548dd59a3a6..753a2d9c8a177 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 5d019e3a835ad..5cab9953c44f5 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c index 0d90fe9233550..ec759d8f7023c 100644 --- a/drivers/rtc/rtc-ti-k3.c +++ b/drivers/rtc/rtc-ti-k3.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include From 58f3e83260a78cfd5648efa5448b237b9c230fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 25 Jul 2023 09:04:29 +0200 Subject: [PATCH 31/73] rtc: isl12026: Drop "_new" from probe callback name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver was introduced when .probe_new was the right probe callback to use for i2c drivers. Today .probe is the right one (again) and the driver was already switched in commit 31b0cecb4042 ("rtc: Switch i2c drivers back to use .probe()") but the name continued to include "_new" in its name. To prevent code readers wondering about what might be new here, drop that irritating part of the name. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230725070429.383070-1-u.kleine-koenig@pengutronix.de Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12026.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 8b00659fc955e..2aabb9151d4c6 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -428,7 +428,7 @@ static void isl12026_force_power_modes(struct i2c_client *client) } } -static int isl12026_probe_new(struct i2c_client *client) +static int isl12026_probe(struct i2c_client *client) { struct isl12026 *priv; int ret; @@ -489,7 +489,7 @@ static struct i2c_driver isl12026_driver = { .name = "rtc-isl12026", .of_match_table = isl12026_dt_match, }, - .probe = isl12026_probe_new, + .probe = isl12026_probe, .remove = isl12026_remove, }; From a69c610e13e2b2de8a1ed2683f13e21b3200bd7a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 1 Aug 2023 12:59:15 +0200 Subject: [PATCH 32/73] rtc: stm32: remove incorrect #ifdef check After a previous commit changed the driver over to SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(), the suspend/resume functions must no longer be hidden behind an #ifdef: In file included from include/linux/clk.h:13, from drivers/rtc/rtc-stm32.c:8: drivers/rtc/rtc-stm32.c:927:39: error: 'stm32_rtc_suspend' undeclared here (not in a function); did you mean 'stm32_rtc_probe'? 927 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) | ^~~~~~~~~~~~~~~~~ include/linux/kernel.h:58:44: note: in definition of macro 'PTR_IF' 58 | #define PTR_IF(cond, ptr) ((cond) ? (ptr) : NULL) | ^~~ include/linux/pm.h:329:26: note: in expansion of macro 'pm_sleep_ptr' 329 | .suspend_noirq = pm_sleep_ptr(suspend_fn), \ | ^~~~~~~~~~~~ Fixes: fb9a7e5360dc8 ("rtc: stm32: change PM callbacks to "_noirq()"") Signed-off-by: Arnd Bergmann Reviewed-by: Valentin Caron Link: https://lore.kernel.org/r/20230801105932.3738430-1-arnd@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3ae875b19af82..3ce4b3d08155b 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -891,7 +891,6 @@ static void stm32_rtc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, false); } -#ifdef CONFIG_PM_SLEEP static int stm32_rtc_suspend(struct device *dev) { struct stm32_rtc *rtc = dev_get_drvdata(dev); @@ -922,7 +921,6 @@ static int stm32_rtc_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops stm32_rtc_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) From df9c16b5ccc8e4aab5e492b5f110167c75c74b0a Mon Sep 17 00:00:00 2001 From: Chen Jiahao Date: Wed, 2 Aug 2023 17:36:50 +0800 Subject: [PATCH 33/73] rtc: sunplus: Clean up redundant dev_err_probe() Referring to platform_get_irq()'s definition, the return value has already been checked if ret < 0, and printed via dev_err_probe(). Calling dev_err_probe() one more time outside platform_get_irq() is obviously redundant. Removing dev_err_probe() outside platform_get_irq() to clean up above problem. Signed-off-by: Chen Jiahao Link: https://lore.kernel.org/r/20230802093650.976352-1-chenjiahao16@huawei.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sunplus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c index f33dc301f3019..20c7e97c2fc81 100644 --- a/drivers/rtc/rtc-sunplus.c +++ b/drivers/rtc/rtc-sunplus.c @@ -244,7 +244,7 @@ static int sp_rtc_probe(struct platform_device *plat_dev) sp_rtc->irq = platform_get_irq(plat_dev, 0); if (sp_rtc->irq < 0) - return dev_err_probe(&plat_dev->dev, sp_rtc->irq, "platform_get_irq failed\n"); + return sp_rtc->irq; ret = devm_request_irq(&plat_dev->dev, sp_rtc->irq, sp_rtc_irq_handler, IRQF_TRIGGER_RISING, "rtc irq", plat_dev); From 4f3688dca15053555ade31a785a9c75837a64fb8 Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Tue, 8 Aug 2023 19:52:09 +0800 Subject: [PATCH 34/73] rtc: remove redundant of_match_ptr() Signed-off-by: Zhu Wang Link: https://lore.kernel.org/r/20230808115213.154377-2-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-3-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-4-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-5-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-6-wangzhu9@huawei.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 4 +--- drivers/rtc/rtc-aspeed.c | 2 +- drivers/rtc/rtc-at91rm9200.c | 2 +- drivers/rtc/rtc-at91sam9.c | 2 +- drivers/rtc/rtc-nct3018y.c | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 8abcad38b10c2..569c1054d6b0b 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -473,7 +473,6 @@ static const struct armada38x_rtc_data armada8k_data = { .alarm = ALARM2, }; -#ifdef CONFIG_OF static const struct of_device_id armada38x_rtc_of_match_table[] = { { .compatible = "marvell,armada-380-rtc", @@ -486,7 +485,6 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = { {} }; MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); -#endif static __init int armada38x_rtc_probe(struct platform_device *pdev) { @@ -576,7 +574,7 @@ static struct platform_driver armada38x_rtc_driver = { .driver = { .name = "armada38x-rtc", .pm = &armada38x_rtc_pm_ops, - .of_match_table = of_match_ptr(armada38x_rtc_of_match_table), + .of_match_table = armada38x_rtc_of_match_table, }, }; diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c index a93352ed3aec9..880b015eebaf7 100644 --- a/drivers/rtc/rtc-aspeed.c +++ b/drivers/rtc/rtc-aspeed.c @@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(of, aspeed_rtc_match); static struct platform_driver aspeed_rtc_driver = { .driver = { .name = "aspeed-rtc", - .of_match_table = of_match_ptr(aspeed_rtc_match), + .of_match_table = aspeed_rtc_match, }, }; diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 245588a7b417c..add4f71d7b3b9 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -641,7 +641,7 @@ static struct platform_driver at91_rtc_driver = { .driver = { .name = "at91_rtc", .pm = &at91_rtc_pm_ops, - .of_match_table = of_match_ptr(at91_rtc_dt_ids), + .of_match_table = at91_rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 610f27dfc462d..f93bee96e3623 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -534,7 +534,7 @@ static struct platform_driver at91_rtc_driver = { .driver = { .name = "rtc-at91sam9", .pm = &at91_rtc_pm_ops, - .of_match_table = of_match_ptr(at91_rtc_dt_ids), + .of_match_table = at91_rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c index a4e3f924837e0..ed4e606be8e58 100644 --- a/drivers/rtc/rtc-nct3018y.c +++ b/drivers/rtc/rtc-nct3018y.c @@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(of, nct3018y_of_match); static struct i2c_driver nct3018y_driver = { .driver = { .name = "rtc-nct3018y", - .of_match_table = of_match_ptr(nct3018y_of_match), + .of_match_table = nct3018y_of_match, }, .probe = nct3018y_probe, .id_table = nct3018y_id, From 4d6af37cafad69ff93f62db80d5a3daa9ac3223f Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:19 +0200 Subject: [PATCH 35/73] rtc: isl12022: remove wrong warning for low battery level There are multiple problems with this warning. First of all, it triggers way too often, in fact nearly on every boot, because the SR_LBAT85/SR_LBAT75 bits have another meaning when in battery backup mode. Quoting from the data sheet: LOW BATTERY INDICATOR 85% BIT (LBAT85) In Normal Mode (VDD), this bit indicates when the battery level has dropped below the pre-selected trip levels. [...] The LBAT85 detection happens automatically once every minute when seconds register reaches 59. In Battery Mode (VBAT), this bit indicates the device has entered into battery mode by polling once every 10 minutes. The LBAT85 detection happens automatically once when the minute register reaches x9h or x0h minutes. Similar wording applies to the LBAT75 bit. This means that if the device is powered off for more than 10 minutes, the LBAT85 bit is guaranteed to be set. Upon power-on, unless we're close enough to the end of a minute and/or the boot is slow enough that the second register passes 59, the LBAT85 bit is still set when the kernel (or early userspace) reads the RTC to set the system's wallclock time. Another minor problem is with the bit logic. If the 75% level is reached, logically we're also below 85%, so both bits would most likely be set. So even if the battery is below 75%, the warning would still say "voltage dropped below 85%". A third problem is that the driver and current DT binding offer no way to indicate the nominal battery level and/or settings of the Battery Level Monitor Trip Bits. Since the default value of the VB85TP[2:0] and VB75TP[2:0] bits are 000, this means the actual setting of the LBAT85/LBAT75 bits in VDD mode doesn't happen until the battery is below 2.125V/1.875V, which for a standard 3V battery is way too late. A fourth problem is emitting this warning from ->read_time: util-linux' hwclock will, in the absence of support for getting an interrupt when the seconds counter is updated, issue ioctl(RTC_RD_TIME) in a busy-loop until it sees a change in the seconds field. In that case, if the battery low bits are set (either genuinely, more than a minute after boot, due to the battery actually being low, or as above, bogusly shortly after boot), the kernel log is swamped with hundreds of identical warnings. Subsequent patches will add such bindings and driver support, and also proper support for RTC_VL_READ. For now, remove the broken warning. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-2-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a613257d1574d..a39aea90230fe 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -141,12 +141,6 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ret) return ret; - if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) { - dev_warn(dev, - "voltage dropped below %u%%, date and time is not reliable.\n", - buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75); - } - dev_dbg(dev, "raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x", buf[ISL12022_REG_SC], From ffc005280a47030d16cbbf3105c75d3562dba5a8 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:20 +0200 Subject: [PATCH 36/73] dt-bindings: rtc: Move isil,isl12022 from trivial-rtc.yaml into own schema file Move the isil,isl12022 RTC bindings from trivial-rtc.yaml into its own intersil,isl12022.yaml file, in preparation for adding more bindings. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-3-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- .../bindings/rtc/intersil,isl12022.yaml | 45 +++++++++++++++++++ .../devicetree/bindings/rtc/trivial-rtc.yaml | 2 - 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml diff --git a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml new file mode 100644 index 0000000000000..054d3fc649ba3 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/intersil,isl12022.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intersil ISL12022 Real-time Clock + +maintainers: + - Alexandre Belloni + +properties: + compatible: + const: isil,isl12022 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +allOf: + - $ref: rtc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rtc@6f { + compatible = "isil,isl12022"; + reg = <0x6f>; + interrupts-extended = <&gpio1 5 IRQ_TYPE_LEVEL_LOW>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index 9af77f21bb7f4..2a65f31ac5a05 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -45,8 +45,6 @@ properties: - isil,isl1208 # Intersil ISL1218 Low Power RTC with Battery Backed SRAM - isil,isl1218 - # Intersil ISL12022 Real-time Clock - - isil,isl12022 # Real Time Clock Module with I2C-Bus - microcrystal,rv3029 # Real Time Clock From 69b569c124ffa698de25d039018fe86313c46c84 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:21 +0200 Subject: [PATCH 37/73] dt-bindings: rtc: isl12022: add bindings for battery alarm trip levels The isl12022 has a built-in support for monitoring the voltage of the backup battery, and setting bits in the status register when that voltage drops below two predetermined levels (usually 85% and 75% of the nominal voltage). However, since it can operate at wide range of battery voltages (2.5V - 5.5V), one must configure those trip levels according to which battery is used on a given board. Add bindings for defining these two trip levels. While the register and bit names suggest that they should correspond to 85% and 75% of the nominal battery voltage, the data sheet also says There are total of 7 levels that could be selected for the first alarm. Any of the of levels could be selected as the first alarm with no reference as to nominal Battery voltage level. Hence this provides the hardware designer the ability to choose values based on the discharge characteristics of the battery chosen for the given product, rather than just having one battery-microvolt property and having the driver choose levels close to 0.85/0.75 times that. Signed-off-by: Rasmus Villemoes Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230615105826.411953-4-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/intersil,isl12022.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml index 054d3fc649ba3..3c6c07aaa78f0 100644 --- a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml +++ b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml @@ -19,6 +19,14 @@ properties: interrupts: maxItems: 1 + isil,battery-trip-levels-microvolt: + description: + The battery voltages at which the first alarm and second alarm + should trigger (normally ~85% and ~75% of nominal V_BAT). + items: + - enum: [2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000] + - enum: [1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000] + required: - compatible - reg @@ -39,6 +47,7 @@ examples: compatible = "isil,isl12022"; reg = <0x6f>; interrupts-extended = <&gpio1 5 IRQ_TYPE_LEVEL_LOW>; + isil,battery-trip-levels-microvolt = <2550000>, <2250000>; }; }; From 2caeb566baabb65add7d99ca6d8bfd566fe91582 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:22 +0200 Subject: [PATCH 38/73] rtc: isl12022: add support for trip level DT binding Implement support for using the values given in the isil,battery-trip-levels-microvolt property to set appropriate values in the VB85TP/VB75TP bits in the PWR_VBAT register. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-5-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a39aea90230fe..a50eed4e40281 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -31,6 +32,8 @@ #define ISL12022_REG_SR 0x07 #define ISL12022_REG_INT 0x08 +#define ISL12022_REG_PWR_VBAT 0x0a + #define ISL12022_REG_BETA 0x0d #define ISL12022_REG_TEMP_L 0x28 @@ -42,6 +45,9 @@ #define ISL12022_INT_WRTC (1 << 6) +#define ISL12022_REG_VB85_MASK GENMASK(5, 3) +#define ISL12022_REG_VB75_MASK GENMASK(2, 0) + #define ISL12022_BETA_TSE (1 << 7) static umode_t isl12022_hwmon_is_visible(const void *data, @@ -209,6 +215,38 @@ static const struct regmap_config regmap_config = { .use_single_write = true, }; +static const u32 trip_levels[2][7] = { + { 2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000 }, + { 1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000 }, +}; + +static void isl12022_set_trip_levels(struct device *dev) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 levels[2] = {0, 0}; + int ret, i, j, x[2]; + u8 val, mask; + + device_property_read_u32_array(dev, "isil,battery-trip-levels-microvolt", + levels, 2); + + for (i = 0; i < 2; i++) { + for (j = 0; j < ARRAY_SIZE(trip_levels[i]) - 1; j++) { + if (levels[i] <= trip_levels[i][j]) + break; + } + x[i] = j; + } + + val = FIELD_PREP(ISL12022_REG_VB85_MASK, x[0]) | + FIELD_PREP(ISL12022_REG_VB75_MASK, x[1]); + mask = ISL12022_REG_VB85_MASK | ISL12022_REG_VB75_MASK; + + ret = regmap_update_bits(regmap, ISL12022_REG_PWR_VBAT, mask, val); + if (ret) + dev_warn(dev, "unable to set battery alarm levels: %d\n", ret); +} + static int isl12022_probe(struct i2c_client *client) { struct rtc_device *rtc; @@ -225,6 +263,7 @@ static int isl12022_probe(struct i2c_client *client) dev_set_drvdata(&client->dev, regmap); + isl12022_set_trip_levels(&client->dev); isl12022_hwmon_register(&client->dev); rtc = devm_rtc_allocate_device(&client->dev); From eccebd813874b748ac4e79a9fe4c7290117ad3be Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:23 +0200 Subject: [PATCH 39/73] rtc: isl12022: implement RTC_VL_READ ioctl Hook up support for reading the values of the SR_LBAT85 and SR_LBAT75 bits. Translate the former to "battery low", and the latter to "battery empty or not-present". Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-6-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a50eed4e40281..0ed28b57bcd89 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -204,7 +204,34 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf)); } +static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 user, val; + int ret; + + switch (cmd) { + case RTC_VL_READ: + ret = regmap_read(regmap, ISL12022_REG_SR, &val); + if (ret) + return ret; + + user = 0; + if (val & ISL12022_SR_LBAT85) + user |= RTC_VL_BACKUP_LOW; + + if (val & ISL12022_SR_LBAT75) + user |= RTC_VL_BACKUP_EMPTY; + + return put_user(user, (u32 __user *)arg); + + default: + return -ENOIOCTLCMD; + } +} + static const struct rtc_class_ops isl12022_rtc_ops = { + .ioctl = isl12022_rtc_ioctl, .read_time = isl12022_rtc_read_time, .set_time = isl12022_rtc_set_time, }; From a11b6c460620f7fb5fae4c3aee5a5ba2e1e1129b Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:24 +0200 Subject: [PATCH 40/73] rtc: isl12022: trigger battery level detection during probe Since the meaning of the SR_LBAT85 and SR_LBAT75 bits are different in battery backup mode, they may very well be set after power on, and stay set for up to a minute (i.e. until the battery detection in VDD mode happens when the seconds counter hits 59). This would mean that userspace doing a ioctl(RTC_VL_READ) early on could get a false positive. The battery level detection can also be triggered by explicitly writing a 1 to the TSE bit in the BETA register. Do that once during boot. Empirically, this does not immediately update the bits in the status register (i.e., an immediate read of SR after this write can still show stale values), but the update is done after a few milliseconds, so certainly before the RTC device gets registered and userspace has a chance of doing the ioctl() on this device. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-7-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 0ed28b57bcd89..a816c5447295d 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -272,6 +272,16 @@ static void isl12022_set_trip_levels(struct device *dev) ret = regmap_update_bits(regmap, ISL12022_REG_PWR_VBAT, mask, val); if (ret) dev_warn(dev, "unable to set battery alarm levels: %d\n", ret); + + /* + * Force a write of the TSE bit in the BETA register, in order + * to trigger an update of the LBAT75 and LBAT85 bits in the + * status register. In battery backup mode, those bits have + * another meaning, so without this, they may contain stale + * values for up to a minute after power-on. + */ + regmap_write_bits(regmap, ISL12022_REG_BETA, + ISL12022_BETA_TSE, ISL12022_BETA_TSE); } static int isl12022_probe(struct i2c_client *client) From ab246c897be0bdf981f776399ca62b5ec4b8138f Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:25 +0200 Subject: [PATCH 41/73] dt-bindings: rtc: isl12022: add #clock-cells property The isl12022 has a dual-purpose irq/f_out pin, which can either be used as an interrupt or clock output. Signed-off-by: Rasmus Villemoes Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230615105826.411953-8-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/intersil,isl12022.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml index 3c6c07aaa78f0..c2d1441ef273f 100644 --- a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml +++ b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml @@ -19,6 +19,9 @@ properties: interrupts: maxItems: 1 + '#clock-cells': + const: 0 + isil,battery-trip-levels-microvolt: description: The battery voltages at which the first alarm and second alarm @@ -33,6 +36,13 @@ required: allOf: - $ref: rtc.yaml# + # If #clock-cells is present, interrupts must not be present + - if: + required: + - '#clock-cells' + then: + properties: + interrupts: false unevaluatedProperties: false From d57d12db774820819d0e591548a56b5cfc95f82a Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:26 +0200 Subject: [PATCH 42/73] rtc: isl12022: implement support for the #clock-cells DT property If device tree implies that the chip's IRQ/F_OUT pin is used as a clock, expose that in the driver. For now, pretend it is a fixed-rate (32kHz) clock; if other use cases appear the driver can be updated to provide its own clk_ops etc. When the clock output is not used on a given board, one can prolong the battery life by ensuring that the FOx bits are 0. For the hardware I'm currently working on, the RTC draws 1.2uA with the FOx bits at their default 0001 value, dropping to 0.88uA when those bits are cleared. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-9-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a816c5447295d..4eef7afcc8bcc 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -44,6 +45,9 @@ #define ISL12022_SR_LBAT75 (1 << 1) #define ISL12022_INT_WRTC (1 << 6) +#define ISL12022_INT_FO_MASK GENMASK(3, 0) +#define ISL12022_INT_FO_OFF 0x0 +#define ISL12022_INT_FO_32K 0x1 #define ISL12022_REG_VB85_MASK GENMASK(5, 3) #define ISL12022_REG_VB75_MASK GENMASK(2, 0) @@ -242,6 +246,41 @@ static const struct regmap_config regmap_config = { .use_single_write = true, }; +static int isl12022_register_clock(struct device *dev) +{ + struct regmap *regmap = dev_get_drvdata(dev); + struct clk_hw *hw; + int ret; + + if (!device_property_present(dev, "#clock-cells")) { + /* + * Disabling the F_OUT pin reduces the power + * consumption in battery mode by ~25%. + */ + regmap_update_bits(regmap, ISL12022_REG_INT, ISL12022_INT_FO_MASK, + ISL12022_INT_FO_OFF); + + return 0; + } + + if (!IS_ENABLED(CONFIG_COMMON_CLK)) + return 0; + + /* + * For now, only support a fixed clock of 32768Hz (the reset default). + */ + ret = regmap_update_bits(regmap, ISL12022_REG_INT, + ISL12022_INT_FO_MASK, ISL12022_INT_FO_32K); + if (ret) + return ret; + + hw = devm_clk_hw_register_fixed_rate(dev, "isl12022", NULL, 0, 32768); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); +} + static const u32 trip_levels[2][7] = { { 2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000 }, { 1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000 }, @@ -288,6 +327,7 @@ static int isl12022_probe(struct i2c_client *client) { struct rtc_device *rtc; struct regmap *regmap; + int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -300,6 +340,10 @@ static int isl12022_probe(struct i2c_client *client) dev_set_drvdata(&client->dev, regmap); + ret = isl12022_register_clock(&client->dev); + if (ret) + return ret; + isl12022_set_trip_levels(&client->dev); isl12022_hwmon_register(&client->dev); From 737055e11729836fc3d7b26220affad30b4736ec Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:38:59 +0200 Subject: [PATCH 43/73] rtc: ds1307: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-ds1307.c:1747:18: error: cast to smaller integer type 'enum ds_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-1-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index cb5acecc11aa4..506b7d1c23970 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1744,7 +1744,7 @@ static int ds1307_probe(struct i2c_client *client) match = device_get_match_data(&client->dev); if (match) { - ds1307->type = (enum ds_type)match; + ds1307->type = (uintptr_t)match; chip = &chips[ds1307->type]; } else if (id) { chip = &chips[id->driver_data]; From fbbeae0af551b8e5fba6ba128d2190c2a29dce90 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:39:00 +0200 Subject: [PATCH 44/73] rtc: rv8803: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-rv8803.c:648:18: error: cast to smaller integer type 'enum rv8803_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-2-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index fd8ab0b2f731b..1a3ec1bb5b814 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -645,8 +645,7 @@ static int rv8803_probe(struct i2c_client *client) mutex_init(&rv8803->flags_lock); rv8803->client = client; if (client->dev.of_node) { - rv8803->type = (enum rv8803_type) - of_device_get_match_data(&client->dev); + rv8803->type = (uintptr_t)of_device_get_match_data(&client->dev); } else { const struct i2c_device_id *id = i2c_match_id(rv8803_id, client); From 4ebbd463050d14989b4dd2de52deb0779969af41 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:39:01 +0200 Subject: [PATCH 45/73] rtc: jz4740: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-jz4740.c:352:14: error: cast to smaller integer type 'enum jz4740_rtc_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-3-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 6ba889d7d4c4f..bafa7d1b9b883 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -349,7 +349,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev) if (!rtc) return -ENOMEM; - rtc->type = (enum jz4740_rtc_type)device_get_match_data(dev); + rtc->type = (uintptr_t)device_get_match_data(dev); irq = platform_get_irq(pdev, 0); if (irq < 0) From e5aabfbc09ca2037e299e0c2c41235922c39b840 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:39:02 +0200 Subject: [PATCH 46/73] rtc: rs5c372: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-rs5c372.c:829:19: error: cast to smaller integer type 'enum rtc_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-4-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rs5c372.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index ecabeef091960..f8fab0205f8cc 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -826,8 +826,7 @@ static int rs5c372_probe(struct i2c_client *client) rs5c372->client = client; i2c_set_clientdata(client, rs5c372); if (client->dev.of_node) { - rs5c372->type = (enum rtc_type) - of_device_get_match_data(&client->dev); + rs5c372->type = (uintptr_t)of_device_get_match_data(&client->dev); } else { const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client); rs5c372->type = id->driver_data; From 2cf2a1acc6ebdffc6363de9156db8737f33c1803 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 15 Aug 2023 15:16:41 -0700 Subject: [PATCH 47/73] rtc: stm32: Use NOIRQ_SYSTEM_SLEEP_PM_OPS() After the switch to SET_NOIRQ_SYSTEM_SLEEP_PM_OPS() and a subsequent fix, stm32_rtc_{suspend,resume}() are unused when CONFIG_PM_SLEEP is not set because SET_NOIRQ_SYSTEM_SLEEP_PM_OPS() is a no-op in that configuration: drivers/rtc/rtc-stm32.c:904:12: error: 'stm32_rtc_resume' defined but not used [-Werror=unused-function] 904 | static int stm32_rtc_resume(struct device *dev) | ^~~~~~~~~~~~~~~~ drivers/rtc/rtc-stm32.c:894:12: error: 'stm32_rtc_suspend' defined but not used [-Werror=unused-function] 894 | static int stm32_rtc_suspend(struct device *dev) | ^~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors The non-"SET_" version of this macro, NOIRQ_SYSTEM_SLEEP_PM_OPS(), is designed to handle this situation by only assigning the callbacks when CONFIG_PM_SLEEP is set while allowing the functions to appear used to the compiler. Switch to that macro to resolve the warnings. There is no functional change with this, as SET_NOIRQ_SYSTEM_SLEEP_PM_OPS() is defined using NOIRQ_SYSTEM_SLEEP_PM_OPS() when CONFIG_PM_SLEEP is set. Signed-off-by: Nathan Chancellor Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230815-rtc-stm32-unused-pm-funcs-v1-1-82eb8e02d903@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3ce4b3d08155b..76753c71d92ee 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -923,7 +923,7 @@ static int stm32_rtc_resume(struct device *dev) } static const struct dev_pm_ops stm32_rtc_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) }; static struct platform_driver stm32_rtc_driver = { From d890cfc25fe9421ffdff3a9ea678172addb36762 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 7 Aug 2023 09:31:06 +0200 Subject: [PATCH 48/73] rtc: ds2404: Convert to GPIO descriptors This converts the DS2404 to use GPIO descriptors instead of hard-coded global GPIO numbers. The platform data can be deleted because there are no in-tree users and it only contained GPIO numbers which are now passed using descriptor tables (or device tree or ACPI). The driver was rewritten to use a state container for the device driver state (struct ds2404 *chip) and pass that around instead of using a global singleton storage for the GPIO handles. When declaring GPIO descriptor tables or other hardware descriptions for the RTC driver, implementers should take care to flag the RESET line as active low, such as by using the GPIOD_ACTIVE_LOW flag in the descriptor table. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230807-descriptors-rtc-v1-1-ce0f9187576e@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds2404.c | 169 +++++++++-------------- include/linux/platform_data/rtc-ds2404.h | 20 --- 2 files changed, 69 insertions(+), 120 deletions(-) delete mode 100644 include/linux/platform_data/rtc-ds2404.h diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 0480f592307e9..3231fd9f61da4 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -7,9 +7,8 @@ #include #include #include -#include #include -#include +#include #include #include @@ -27,164 +26,140 @@ #define DS2404_CLK 1 #define DS2404_DQ 2 -struct ds2404_gpio { - const char *name; - unsigned int gpio; -}; - struct ds2404 { - struct ds2404_gpio *gpio; + struct device *dev; + struct gpio_desc *rst_gpiod; + struct gpio_desc *clk_gpiod; + struct gpio_desc *dq_gpiod; struct rtc_device *rtc; }; -static struct ds2404_gpio ds2404_gpio[] = { - { "RTC RST", 0 }, - { "RTC CLK", 0 }, - { "RTC DQ", 0 }, -}; - -static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev, - struct ds2404_platform_data *pdata) +static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev) { - int i, err; - - ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst; - ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk; - ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq; - - for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) { - err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name); - if (err) { - dev_err(&pdev->dev, "error mapping gpio %s: %d\n", - ds2404_gpio[i].name, err); - goto err_request; - } - if (i != DS2404_DQ) - gpio_direction_output(ds2404_gpio[i].gpio, 1); - } + struct device *dev = &pdev->dev; - chip->gpio = ds2404_gpio; - return 0; + /* This will de-assert RESET, declare this GPIO as GPIOD_ACTIVE_LOW */ + chip->rst_gpiod = devm_gpiod_get(dev, "rst", GPIOD_OUT_LOW); + if (IS_ERR(chip->rst_gpiod)) + return PTR_ERR(chip->rst_gpiod); -err_request: - while (--i >= 0) - gpio_free(ds2404_gpio[i].gpio); - return err; -} + chip->clk_gpiod = devm_gpiod_get(dev, "clk", GPIOD_OUT_HIGH); + if (IS_ERR(chip->clk_gpiod)) + return PTR_ERR(chip->clk_gpiod); -static void ds2404_gpio_unmap(void *data) -{ - int i; + chip->dq_gpiod = devm_gpiod_get(dev, "dq", GPIOD_ASIS); + if (IS_ERR(chip->dq_gpiod)) + return PTR_ERR(chip->dq_gpiod); - for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) - gpio_free(ds2404_gpio[i].gpio); + return 0; } -static void ds2404_reset(struct device *dev) +static void ds2404_reset(struct ds2404 *chip) { - gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0); + gpiod_set_value(chip->rst_gpiod, 1); udelay(1000); - gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1); - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); - gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0); + gpiod_set_value(chip->rst_gpiod, 0); + gpiod_set_value(chip->clk_gpiod, 0); + gpiod_direction_output(chip->dq_gpiod, 0); udelay(10); } -static void ds2404_write_byte(struct device *dev, u8 byte) +static void ds2404_write_byte(struct ds2404 *chip, u8 byte) { int i; - gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1); + gpiod_direction_output(chip->dq_gpiod, 1); for (i = 0; i < 8; i++) { - gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i)); + gpiod_set_value(chip->dq_gpiod, byte & (1 << i)); udelay(10); - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); + gpiod_set_value(chip->clk_gpiod, 1); udelay(10); - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); + gpiod_set_value(chip->clk_gpiod, 0); udelay(10); } } -static u8 ds2404_read_byte(struct device *dev) +static u8 ds2404_read_byte(struct ds2404 *chip) { int i; u8 ret = 0; - gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); + gpiod_direction_input(chip->dq_gpiod); for (i = 0; i < 8; i++) { - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); + gpiod_set_value(chip->clk_gpiod, 0); udelay(10); - if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio)) + if (gpiod_get_value(chip->dq_gpiod)) ret |= 1 << i; - gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); + gpiod_set_value(chip->clk_gpiod, 1); udelay(10); } return ret; } -static void ds2404_read_memory(struct device *dev, u16 offset, +static void ds2404_read_memory(struct ds2404 *chip, u16 offset, int length, u8 *out) { - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD); - ds2404_write_byte(dev, offset & 0xff); - ds2404_write_byte(dev, (offset >> 8) & 0xff); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_READ_MEMORY_CMD); + ds2404_write_byte(chip, offset & 0xff); + ds2404_write_byte(chip, (offset >> 8) & 0xff); while (length--) - *out++ = ds2404_read_byte(dev); + *out++ = ds2404_read_byte(chip); } -static void ds2404_write_memory(struct device *dev, u16 offset, +static void ds2404_write_memory(struct ds2404 *chip, u16 offset, int length, u8 *out) { int i; u8 ta01, ta02, es; - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD); - ds2404_write_byte(dev, offset & 0xff); - ds2404_write_byte(dev, (offset >> 8) & 0xff); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_WRITE_SCRATCHPAD_CMD); + ds2404_write_byte(chip, offset & 0xff); + ds2404_write_byte(chip, (offset >> 8) & 0xff); for (i = 0; i < length; i++) - ds2404_write_byte(dev, out[i]); + ds2404_write_byte(chip, out[i]); - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_READ_SCRATCHPAD_CMD); - ta01 = ds2404_read_byte(dev); - ta02 = ds2404_read_byte(dev); - es = ds2404_read_byte(dev); + ta01 = ds2404_read_byte(chip); + ta02 = ds2404_read_byte(chip); + es = ds2404_read_byte(chip); for (i = 0; i < length; i++) { - if (out[i] != ds2404_read_byte(dev)) { - dev_err(dev, "read invalid data\n"); + if (out[i] != ds2404_read_byte(chip)) { + dev_err(chip->dev, "read invalid data\n"); return; } } - ds2404_reset(dev); - ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD); - ds2404_write_byte(dev, ta01); - ds2404_write_byte(dev, ta02); - ds2404_write_byte(dev, es); + ds2404_reset(chip); + ds2404_write_byte(chip, DS2404_COPY_SCRATCHPAD_CMD); + ds2404_write_byte(chip, ta01); + ds2404_write_byte(chip, ta02); + ds2404_write_byte(chip, es); - gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); - while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio)) + while (gpiod_get_value(chip->dq_gpiod)) ; } -static void ds2404_enable_osc(struct device *dev) +static void ds2404_enable_osc(struct ds2404 *chip) { u8 in[1] = { 0x10 }; /* enable oscillator */ - ds2404_write_memory(dev, 0x201, 1, in); + + ds2404_write_memory(chip, 0x201, 1, in); } static int ds2404_read_time(struct device *dev, struct rtc_time *dt) { + struct ds2404 *chip = dev_get_drvdata(dev); unsigned long time = 0; __le32 hw_time = 0; - ds2404_read_memory(dev, 0x203, 4, (u8 *)&hw_time); + ds2404_read_memory(chip, 0x203, 4, (u8 *)&hw_time); time = le32_to_cpu(hw_time); rtc_time64_to_tm(time, dt); @@ -193,8 +168,9 @@ static int ds2404_read_time(struct device *dev, struct rtc_time *dt) static int ds2404_set_time(struct device *dev, struct rtc_time *dt) { + struct ds2404 *chip = dev_get_drvdata(dev); u32 time = cpu_to_le32(rtc_tm_to_time64(dt)); - ds2404_write_memory(dev, 0x203, 4, (u8 *)&time); + ds2404_write_memory(chip, 0x203, 4, (u8 *)&time); return 0; } @@ -205,7 +181,6 @@ static const struct rtc_class_ops ds2404_rtc_ops = { static int rtc_probe(struct platform_device *pdev) { - struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev); struct ds2404 *chip; int retval = -EBUSY; @@ -213,22 +188,16 @@ static int rtc_probe(struct platform_device *pdev) if (!chip) return -ENOMEM; + chip->dev = &pdev->dev; + chip->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(chip->rtc)) return PTR_ERR(chip->rtc); - retval = ds2404_gpio_map(chip, pdev, pdata); + retval = ds2404_gpio_map(chip, pdev); if (retval) return retval; - retval = devm_add_action_or_reset(&pdev->dev, ds2404_gpio_unmap, chip); - if (retval) - return retval; - - dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n", - chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio, - chip->gpio[DS2404_DQ].gpio); - platform_set_drvdata(pdev, chip); chip->rtc->ops = &ds2404_rtc_ops; @@ -238,7 +207,7 @@ static int rtc_probe(struct platform_device *pdev) if (retval) return retval; - ds2404_enable_osc(&pdev->dev); + ds2404_enable_osc(chip); return 0; } diff --git a/include/linux/platform_data/rtc-ds2404.h b/include/linux/platform_data/rtc-ds2404.h deleted file mode 100644 index 22c53825528f0..0000000000000 --- a/include/linux/platform_data/rtc-ds2404.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * ds2404.h - platform data structure for the DS2404 RTC. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 Sven Schnelle - */ - -#ifndef __LINUX_DS2404_H -#define __LINUX_DS2404_H - -struct ds2404_platform_data { - - unsigned int gpio_rst; - unsigned int gpio_clk; - unsigned int gpio_dq; -}; -#endif From 4e5eb7ef73c4c45e2e621eb51a76565153b63afe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 31 Jul 2023 17:09:30 +0300 Subject: [PATCH 49/73] rtc: pcf2127: fix error code in pcf2127_enable_ts() This error path accidentally returns success. Return -EINVAL instead. Fixes: 420cc9e850db ("rtc: pcf2127: add support for multiple TS functions") Signed-off-by: Dan Carpenter Reviewed-by: Bruno Thomsen Reviewed-by: Hugo Villeneuve Reviewed-by: Hugo Villeneuve Link: https://lore.kernel.org/r/55b9c84b-9d21-444f-b91a-cf9316b65833@moroto.mountain Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 78141bb06ab0b..988cad1711746 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1060,7 +1060,7 @@ static int pcf2127_enable_ts(struct device *dev, int ts_id) if (pcf2127->cfg->ts[ts_id].gnd_detect_bit == 0) { dev_err(dev, "%s: tamper detection to GND configuration invalid\n", __func__); - return ret; + return -EINVAL; } /* From e4163fc59d088caf3250cc9c9862239a954d85b5 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 28 Jul 2023 13:12:12 -0400 Subject: [PATCH 50/73] rtc: pcf2127: add error checking when disabling POR0 If PCF2127 device is absent from the I2C bus, or if there is a communication problem, disabling POR0 may fail silently and we still continue with probing the device. In that case, abort probe operation. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230728171211.3016019-1-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 988cad1711746..f10bffc9e4871 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1192,8 +1192,10 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, * The "Power-On Reset Override" facility prevents the RTC to do a reset * after power on. For normal operation the PORO must be disabled. */ - regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + ret = regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1, PCF2127_BIT_CTRL1_POR_OVRD); + if (ret < 0) + return ret; ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_clkout, &val); if (ret < 0) From 58dffa96e62ccf30ecba718f124ce822ddc1150a Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Tue, 1 Aug 2023 15:04:32 -0400 Subject: [PATCH 51/73] rtc: pcf2127: remove unused function argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/rtc/rtc-pcf2127.c: In function ‘pcf2127_probe’: drivers/rtc/rtc-pcf2127.c:635:32: warning: unused parameter ‘name’ [-Wunused-parameter] 635 | int alarm_irq, const char *name, bool is_pcf2127) | ~~~~~~~~~~~~^~~~ Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230801190432.3340545-1-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index f10bffc9e4871..de8164e1b5626 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1103,7 +1103,7 @@ static int pcf2127_configure_interrupt_pins(struct device *dev) } static int pcf2127_probe(struct device *dev, struct regmap *regmap, - int alarm_irq, const char *name, const struct pcf21xx_config *config) + int alarm_irq, const struct pcf21xx_config *config) { struct pcf2127 *pcf2127; int ret = 0; @@ -1402,8 +1402,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client) return PTR_ERR(regmap); } - return pcf2127_probe(&client->dev, regmap, client->irq, - pcf2127_i2c_driver.driver.name, variant); + return pcf2127_probe(&client->dev, regmap, client->irq, variant); } static struct i2c_driver pcf2127_i2c_driver = { @@ -1475,9 +1474,7 @@ static int pcf2127_spi_probe(struct spi_device *spi) return PTR_ERR(regmap); } - return pcf2127_probe(&spi->dev, regmap, spi->irq, - pcf2127_spi_driver.driver.name, - variant); + return pcf2127_probe(&spi->dev, regmap, spi->irq, variant); } static const struct spi_device_id pcf2127_spi_id[] = { From ed17a2bcbb75505bb979e3e8ecb6c5fb2518bf3b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 17 Jul 2023 12:09:37 -0700 Subject: [PATCH 52/73] rtc: da9063: Mark the alarm IRQ as a wake IRQ This keeps the IRQ enabled during system suspend, if the RTC's wakeup source is enabled. Since the IRQ is not required to wake from shutdown, continue to add the wakeup source even if registering the wakeirq fails. See commit 029d3a6f2f3c ("rtc: da9063: add as wakeup source"). Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20230717190937.1301509-1-samuel.holland@sifive.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-da9063.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index ee2efb4961744..2f5d60622564a 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -496,6 +497,12 @@ static int da9063_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", irq_alarm, ret); + ret = dev_pm_set_wake_irq(&pdev->dev, irq_alarm); + if (ret) + dev_warn(&pdev->dev, + "Failed to set IRQ %d as a wake IRQ: %d\n", + irq_alarm, ret); + device_init_wakeup(&pdev->dev, true); return devm_rtc_register_device(rtc->rtc_dev); From 0197a7cb44872e49919b0068a512aaf4e06f1850 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 28 Jul 2023 15:57:10 +0530 Subject: [PATCH 53/73] dt-bindings: rtc: at91rm9200: add sam9x7 compatible Add compatible for SAM9X7 RTC. Signed-off-by: Varshini Rajendran Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230728102710.266457-1-varshini.rajendran@microchip.com Signed-off-by: Alexandre Belloni --- .../bindings/rtc/atmel,at91rm9200-rtc.yaml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml index 4d2bef15fb7ab..c8bb2eef442dd 100644 --- a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.yaml @@ -14,13 +14,17 @@ maintainers: properties: compatible: - enum: - - atmel,at91rm9200-rtc - - atmel,at91sam9x5-rtc - - atmel,sama5d4-rtc - - atmel,sama5d2-rtc - - microchip,sam9x60-rtc - - microchip,sama7g5-rtc + oneOf: + - enum: + - atmel,at91rm9200-rtc + - atmel,at91sam9x5-rtc + - atmel,sama5d4-rtc + - atmel,sama5d2-rtc + - microchip,sam9x60-rtc + - microchip,sama7g5-rtc + - items: + - const: microchip,sam9x7-rtc + - const: microchip,sam9x60-rtc reg: maxItems: 1 From 4d349a5793f7a42da27ea56d9f6e2f9488d44e0d Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 3 Aug 2023 16:07:12 +0800 Subject: [PATCH 54/73] rtc: omap: Do not check for 0 return after calling platform_get_irq() It is not possible for platform_get_irq() to return 0. Use the return value from platform_get_irq(). Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230803080713.4061782-2-ruanjinjie@huawei.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 8ae4d7824ec9f..5b10ab06cd2e2 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -747,12 +747,12 @@ static int omap_rtc_probe(struct platform_device *pdev) } rtc->irq_timer = platform_get_irq(pdev, 0); - if (rtc->irq_timer <= 0) - return -ENOENT; + if (rtc->irq_timer < 0) + return rtc->irq_timer; rtc->irq_alarm = platform_get_irq(pdev, 1); - if (rtc->irq_alarm <= 0) - return -ENOENT; + if (rtc->irq_alarm < 0) + return rtc->irq_alarm; rtc->clk = devm_clk_get(&pdev->dev, "ext-clk"); if (!IS_ERR(rtc->clk)) From dac7837848485bf1d0bd3aa56923f8bf5075682f Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 3 Aug 2023 16:07:13 +0800 Subject: [PATCH 55/73] rtc: tps65910: Remove redundant dev_warn() and do not check for 0 return after calling platform_get_irq() It is not possible for platform_get_irq() to return 0. Use the return value from platform_get_irq(). And there is no need to call the dev_warn() function directly to print a custom message when handling an error from platform_get_irq() function as it is going to display an appropriate error message in case of a failure. Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230803080713.4061782-3-ruanjinjie@huawei.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-tps65910.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 75e4c2d777b9c..411ff66c04682 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -406,11 +406,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tps_rtc); irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n", - irq); - return -ENXIO; - } + if (irq < 0) + return irq; ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, From 45cc2a7de905a1f3bb38fb7d6f68a204c71630be Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Fri, 25 Aug 2023 07:39:10 +0200 Subject: [PATCH 56/73] MAINTAINERS: remove obsolete pattern in RTC SUBSYSTEM section Commit d890cfc25fe9 ("rtc: ds2404: Convert to GPIO descriptors") removes the rtc-ds2404.h platform data and with that, there is no file remaining matching the pattern 'include/linux/platform_data/rtc-*'. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Remove the obsolete file pattern in the REAL TIME CLOCK (RTC) SUBSYSTEM. Signed-off-by: Lukas Bulwahn Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20230825053910.17941-1-lukas.bulwahn@gmail.com Signed-off-by: Alexandre Belloni --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc7..03cbac3b72110 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17928,7 +17928,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git F: Documentation/admin-guide/rtc.rst F: Documentation/devicetree/bindings/rtc/ F: drivers/rtc/ -F: include/linux/platform_data/rtc-* F: include/linux/rtc.h F: include/linux/rtc/ F: include/uapi/linux/rtc.h From f45d32d2cd183c09b6c9aa8689a91d6f2760b557 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 17 Aug 2023 17:10:38 +0100 Subject: [PATCH 57/73] rtc: isl1208: Fix incorrect logic in isl1208_set_xtoscb() The XTOSCB bit is not bit 0, but xtosb_val is either 0 or 1. If it is 1, test will never succeed. Fix this issue by using double negation. While at it, remove unnecessary blank line from probe(). Reported-by: Pavel Machek Closes: https://lore.kernel.org/all/ZN4BgzG2xmzOzdFZ@duo.ucw.cz/ Signed-off-by: Biju Das Reviewed-by: Pavel Machek Link: https://lore.kernel.org/r/20230817161038.407960-1-biju.das.jz@bp.renesas.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 712ca652d6d3c..e50c23ee1646a 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -188,7 +188,7 @@ isl1208_i2c_validate_client(struct i2c_client *client) static int isl1208_set_xtoscb(struct i2c_client *client, int sr, int xtosb_val) { /* Do nothing if bit is already set to desired value */ - if ((sr & ISL1208_REG_SR_XTOSCB) == xtosb_val) + if (!!(sr & ISL1208_REG_SR_XTOSCB) == xtosb_val) return 0; if (xtosb_val) @@ -944,7 +944,6 @@ isl1208_probe(struct i2c_client *client) rc = isl1208_setup_irq(client, client->irq); if (rc) return rc; - } else { clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, isl1208->rtc->features); } From 781589e40ac5f929f58824c15448e1ba49c3ac32 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 17 Aug 2023 15:55:31 -0700 Subject: [PATCH 58/73] rtc: Add support for limited alarm timer offsets Some alarm timers are based on time offsets, not on absolute times. In some situations, the amount of time that can be scheduled in the future is limited. This may result in a refusal to suspend the system, causing substantial battery drain. Some RTC alarm drivers remedy the situation by setting the alarm time to the maximum supported time if a request for an out-of-range timeout is made. This is not really desirable since it may result in unexpected early wakeups. To reduce the impact of this problem, let RTC drivers report the maximum supported alarm timer offset. The code setting alarm timers can then decide if it wants to reject setting alarm timers to a larger value, if it wants to implement recurring alarms until the actually requested alarm time is met, or if it wants to accept the limited alarm time. Only introduce the necessary variable into struct rtc_device. Code to set and use the variable will follow with subsequent patches. Cc: Brian Norris Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230817225537.4053865-2-linux@roeck-us.net Signed-off-by: Alexandre Belloni --- include/linux/rtc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 1fd9c6a21ebe8..4c0bcbeb1f00c 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -146,6 +146,7 @@ struct rtc_device { time64_t range_min; timeu64_t range_max; + timeu64_t alarm_offset_max; time64_t start_secs; time64_t offset_secs; bool set_start_time; From 00c3092d881bc9d63dc36eecd140cdb38962c7ec Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 17 Aug 2023 15:55:33 -0700 Subject: [PATCH 59/73] rtc: cros-ec: Detect and report supported alarm window size The RTC on some older Chromebooks can only handle alarms less than 24 hours in the future. The only way to find out is to try to set an alarm further in the future. If that fails, assume that the RTC connected to the EC can only handle less than 24 hours of alarm window, and report that value to the RTC core. After that change, it is no longer necessary to limit the alarm time when setting it. Report any excessive alarms to the caller instead. Cc: Brian Norris Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230817225537.4053865-4-linux@roeck-us.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cros-ec.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c index 998ab8606f0b6..0cd397c04ff0e 100644 --- a/drivers/rtc/rtc-cros-ec.c +++ b/drivers/rtc/rtc-cros-ec.c @@ -182,21 +182,15 @@ static int cros_ec_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset); if (ret < 0) { - if (ret == -EINVAL && alarm_offset >= SECS_PER_DAY) { - /* - * RTC chips on some older Chromebooks can only handle - * alarms up to 24h in the future. Try to set an alarm - * below that limit to avoid suspend failures. - */ - ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, - SECS_PER_DAY - 1); - } - - if (ret < 0) { - dev_err(dev, "error setting alarm in %u seconds: %d\n", - alarm_offset, ret); - return ret; - } + dev_err(dev, "error setting alarm in %u seconds: %d\n", + alarm_offset, ret); + /* + * The EC code returns -EINVAL if the alarm time is too + * far in the future. Convert it to the expected error code. + */ + if (ret == -EINVAL) + ret = -ERANGE; + return ret; } return 0; @@ -355,6 +349,20 @@ static int cros_ec_rtc_probe(struct platform_device *pdev) cros_ec_rtc->rtc->ops = &cros_ec_rtc_ops; cros_ec_rtc->rtc->range_max = U32_MAX; + /* + * The RTC on some older Chromebooks can only handle alarms less than + * 24 hours in the future. The only way to find out is to try to set an + * alarm further in the future. If that fails, assume that the RTC + * connected to the EC can only handle less than 24 hours of alarm + * window. + */ + ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, SECS_PER_DAY * 2); + if (ret == -EINVAL) + cros_ec_rtc->rtc->alarm_offset_max = SECS_PER_DAY - 1; + + (void)cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, + EC_RTC_ALARM_CLEAR); + ret = devm_rtc_register_device(cros_ec_rtc->rtc); if (ret) return ret; From 2546e7083f2ea96bdd6157961dc2748d65a9e487 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 17 Aug 2023 15:55:34 -0700 Subject: [PATCH 60/73] rtc: cmos: Report supported alarm limit to rtc infrastructure The alarm window supported by the cmos RTC depends on the chip and its configuration. Report the limit to the RTC core. Cc: Brian Norris Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230817225537.4053865-5-linux@roeck-us.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index c9416fe8542d7..228fb2d11c709 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -913,6 +913,10 @@ static inline void cmos_check_acpi_rtc_status(struct device *dev, #define INITSECTION __init #endif +#define SECS_PER_DAY (24 * 60 * 60) +#define SECS_PER_MONTH (28 * SECS_PER_DAY) +#define SECS_PER_YEAR (365 * SECS_PER_DAY) + static int INITSECTION cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) { @@ -1019,6 +1023,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup0; } + if (cmos_rtc.mon_alrm) + cmos_rtc.rtc->alarm_offset_max = SECS_PER_YEAR - 1; + else if (cmos_rtc.day_alrm) + cmos_rtc.rtc->alarm_offset_max = SECS_PER_MONTH - 1; + else + cmos_rtc.rtc->alarm_offset_max = SECS_PER_DAY - 1; + rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); if (!mc146818_does_rtc_work()) { From 3637bbdc8a446b8edb369383d2abc816c96ee864 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 17 Aug 2023 15:55:35 -0700 Subject: [PATCH 61/73] rtc: tps6586x: Report maximum alarm limit to rtc core tps6586x only supports alarms up to 16,383 seconds in the future. Report the limit to the RTC core. Cc: Brian Norris Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230817225537.4053865-6-linux@roeck-us.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-tps6586x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 9f14e24757470..20faf08c254cc 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -252,6 +252,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) rtc->rtc->ops = &tps6586x_rtc_ops; rtc->rtc->range_max = (1ULL << 30) - 1; /* 30-bit seconds */ + rtc->rtc->alarm_offset_max = ALM1_VALID_RANGE_IN_SEC; rtc->rtc->start_secs = mktime64(2009, 1, 1, 0, 0, 0); rtc->rtc->set_start_time = true; From 46b79ac0b463e155b098805ff66f1f22ff249b45 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 17 Aug 2023 15:55:36 -0700 Subject: [PATCH 62/73] rtc: ds1305: Report maximum alarm limit to rtc core DS1305 only supports alarms up to 24 hours in the future. Report the limit to the RTC core, and use the reported limit to validate the requested alarm time when setting it. If the alarm is too large when trying to set an alarm, return -ERANGE instead of -EDOM to align with error codes returned by other rtc drivers. Cc: Brian Norris Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230817225537.4053865-7-linux@roeck-us.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1305.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index ed9360486953e..d4de401548b42 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -336,8 +336,8 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm) /* make sure alarm fires within the next 24 hours */ if (later <= now) return -EINVAL; - if ((later - now) > 24 * 60 * 60) - return -EDOM; + if ((later - now) > ds1305->rtc->alarm_offset_max) + return -ERANGE; /* disable alarm if needed */ if (ds1305->ctrl[0] & DS1305_AEI0) { @@ -691,6 +691,7 @@ static int ds1305_probe(struct spi_device *spi) ds1305->rtc->ops = &ds1305_ops; ds1305->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; ds1305->rtc->range_max = RTC_TIMESTAMP_END_2099; + ds1305->rtc->alarm_offset_max = 24 * 60 * 60; ds1305_nvmem_cfg.priv = ds1305; status = devm_rtc_register_device(ds1305->rtc); From 2b0386d578836b9cd5d2e63cff38b7229c319e4a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 17 Aug 2023 15:55:37 -0700 Subject: [PATCH 63/73] rtc: rzn1: Report maximum alarm limit to rtc core RZN1 only supports alarms up to one week in the future. Report the limit to the RTC core and use the reported limit to validate the requested alarm time when setting it. Cc: Brian Norris Signed-off-by: Guenter Roeck Reviewed-by: Miquel Raynal Link: https://lore.kernel.org/r/20230817225537.4053865-8-linux@roeck-us.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rzn1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index 6f98969eedca3..56ebbd4d04814 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -227,7 +227,7 @@ static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; /* We cannot set alarms more than one week ahead */ - farest = rtc_tm_to_time64(&tm_now) + (7 * 86400); + farest = rtc_tm_to_time64(&tm_now) + rtc->rtcdev->alarm_offset_max; alarm = rtc_tm_to_time64(tm); if (time_after(alarm, farest)) return -ERANGE; @@ -351,6 +351,7 @@ static int rzn1_rtc_probe(struct platform_device *pdev) rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099; + rtc->rtcdev->alarm_offset_max = 7 * 86400; rtc->rtcdev->ops = &rzn1_rtc_ops; set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features); From eeeb77716f5f7c03d157980c7ad3af037c61c8ae Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 27 Aug 2023 23:46:49 +0200 Subject: [PATCH 64/73] rtc: pcf2127: remove useless check This check is only useful when introducing support for a new RTC in the driver. Cut down the number of strings in th driver. Link: https://lore.kernel.org/r/20230827214649.537095-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index de8164e1b5626..9c04c4e1a49c3 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1054,15 +1054,6 @@ static int pcf2127_enable_ts(struct device *dev, int ts_id) return ret; } - /* TS input pin driven to GND detection is supported by all variants. - * Make sure that interrupt bit is defined. - */ - if (pcf2127->cfg->ts[ts_id].gnd_detect_bit == 0) { - dev_err(dev, "%s: tamper detection to GND configuration invalid\n", - __func__); - return -EINVAL; - } - /* * Enable interrupt generation when TSF timestamp flag is set. * Interrupt signals are open-drain outputs and can be left floating if From a5aeccabb53673331f78a97ce492ce6d01f1e036 Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Fri, 25 Aug 2023 11:43:25 +0300 Subject: [PATCH 65/73] dt-bindings: rtc: Add ST M48T86 Add YAML bindings for ST M48T86 / Dallas DS12887 RTC. Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/lkml/61b9e036-7864-65c6-d43b-463fff896ddc@linaro.org/ Signed-off-by: Nikita Shubin Link: https://lore.kernel.org/r/20230823-m48t86_device_tree-v2-1-21ff275f949d@maquefel.me Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/st,m48t86.yaml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/st,m48t86.yaml diff --git a/Documentation/devicetree/bindings/rtc/st,m48t86.yaml b/Documentation/devicetree/bindings/rtc/st,m48t86.yaml new file mode 100644 index 0000000000000..e3e12fa233806 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/st,m48t86.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/st,m48t86.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ST M48T86 / Dallas DS12887 RTC with SRAM + +maintainers: + - Alexandre Belloni + +allOf: + - $ref: rtc.yaml + +properties: + compatible: + enum: + - st,m48t86 + + reg: + items: + - description: index register + - description: data register + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + rtc@10800000 { + compatible = "st,m48t86"; + reg = <0x10800000 0x1>, <0x11700000 0x1>; + }; + +... From 6ec3f5ec2eecabab065a39f5e04562c8c3c81ece Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Fri, 25 Aug 2023 11:43:26 +0300 Subject: [PATCH 66/73] rtc: m48t86: add DT support for m48t86 Add OF ID match table. Acked-by: Arnd Bergmann Reviewed-by: Linus Walleij Link: https://lore.kernel.org/lkml/20230601054549.10843-12-nikita.shubin@maquefel.me/ Signed-off-by: Nikita Shubin Link: https://lore.kernel.org/r/20230823-m48t86_device_tree-v2-2-21ff275f949d@maquefel.me Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t86.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 481c9525b1ddb..dd4a62e2d39c7 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -269,9 +270,16 @@ static int m48t86_rtc_probe(struct platform_device *pdev) return 0; } +static const struct of_device_id m48t86_rtc_of_ids[] = { + { .compatible = "st,m48t86" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, m48t86_rtc_of_ids); + static struct platform_driver m48t86_rtc_platform_driver = { .driver = { .name = "rtc-m48t86", + .of_match_table = m48t86_rtc_of_ids, }, .probe = m48t86_rtc_probe, }; From 1e786b03705938870dafb629f2248f88d507a0ff Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Mon, 21 Aug 2023 09:20:13 +0200 Subject: [PATCH 67/73] rtc: pcf85363: Allow to wake up system without IRQ When wakeup-source is set in the devicetree, set up the device for using the output as interrupt instead of clock. This is similar to how other RTC devices handle this. This allows the clock chip to turn on the board when wired to do so in hardware. Signed-off-by: Mike Looijmans Link: https://lore.kernel.org/r/20230821072013.7072-1-mike.looijmans@topic.nl Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85363.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index 569c79bac0ee8..06194674d71c5 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -402,6 +402,7 @@ static int pcf85363_probe(struct i2c_client *client) }, }; int ret, i, err; + bool wakeup_source; if (data) config = data; @@ -431,25 +432,36 @@ static int pcf85363_probe(struct i2c_client *client) pcf85363->rtc->ops = &rtc_ops; pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; - clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); + + wakeup_source = device_property_read_bool(&client->dev, + "wakeup-source"); + if (client->irq > 0 || wakeup_source) { + regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); + regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, + PIN_IO_INTA_OUT, PIN_IO_INTAPM); + } if (client->irq > 0) { unsigned long irqflags = IRQF_TRIGGER_LOW; if (dev_fwnode(&client->dev)) irqflags = 0; - - regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); - regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, - PIN_IO_INTA_OUT, PIN_IO_INTAPM); ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf85363_rtc_handle_irq, irqflags | IRQF_ONESHOT, "pcf85363", client); - if (ret) - dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); - else - set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); + if (ret) { + dev_warn(&client->dev, + "unable to request IRQ, alarms disabled\n"); + client->irq = 0; + } + } + + if (client->irq > 0 || wakeup_source) { + device_init_wakeup(&client->dev, true); + set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); + } else { + clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); } ret = devm_rtc_register_device(pcf85363->rtc); From 7130856f56054a031c492d37896cbcbfd04a61b5 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Sat, 28 May 2022 19:36:13 +0200 Subject: [PATCH 68/73] rtc: twl: add NVRAM support Export SRAM using nvmem. Signed-off-by: Ladislav Michl Reviewed-by: Tony Lindgren Link: https://lore.kernel.org/r/ZDf7qZTiml0ijD2g@lenoch Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-twl.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 81b36948c2fa3..f8f0d774a06e0 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -487,11 +487,24 @@ static const struct rtc_class_ops twl_rtc_ops = { .alarm_irq_enable = twl_rtc_alarm_irq_enable, }; +static int twl_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + return twl_i2c_read((long)priv, val, offset, bytes); +} + +static int twl_nvram_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + return twl_i2c_write((long)priv, val, offset, bytes); +} + /*----------------------------------------------------------------------*/ static int twl_rtc_probe(struct platform_device *pdev) { struct twl_rtc *twl_rtc; + struct nvmem_config nvmem_cfg; struct device_node *np = pdev->dev.of_node; int ret = -EINVAL; int irq = platform_get_irq(pdev, 0); @@ -579,6 +592,30 @@ static int twl_rtc_probe(struct platform_device *pdev) return ret; } + memset(&nvmem_cfg, 0, sizeof(nvmem_cfg)); + nvmem_cfg.name = "twl-secured-"; + nvmem_cfg.type = NVMEM_TYPE_BATTERY_BACKED; + nvmem_cfg.reg_read = twl_nvram_read, + nvmem_cfg.reg_write = twl_nvram_write, + nvmem_cfg.word_size = 1; + nvmem_cfg.stride = 1; + if (twl_class_is_4030()) { + /* 20 bytes SECURED_REG area */ + nvmem_cfg.size = 20; + nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG; + devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg); + /* 8 bytes BACKUP area */ + nvmem_cfg.name = "twl-backup-"; + nvmem_cfg.size = 8; + nvmem_cfg.priv = (void *)TWL4030_MODULE_BACKUP; + devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg); + } else { + /* 8 bytes SECURED_REG area */ + nvmem_cfg.size = 8; + nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG; + devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg); + } + return 0; } From 348c11a7d71b0b216f28ea077137e2351ab0dea8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 28 Aug 2023 00:15:31 +0200 Subject: [PATCH 69/73] rtc: stop warning for invalid alarms when the alarm is disabled When the alarm is not enabled, it may never have been set and so we can't expect it to be valid. This will prevent the apparition of boot messages like this one: rtc rtc0: invalid alarm value: 2023-7-8 45:85:85 Link: https://lore.kernel.org/r/20230827221532.543353-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 499d89150afc9..1b63111cdda2e 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -376,7 +376,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) err = rtc_valid_tm(&alarm->time); done: - if (err) + if (err && alarm->enabled) dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", &alarm->time); From 94ec1f06d02350860e0579b8058f1ef87506f697 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 28 Aug 2023 00:16:40 +0200 Subject: [PATCH 70/73] rtc: sun6i: remove unnecessary message The core already print a message once the rtc is successfully registered, it is not necessary to print an other one. Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20230827221643.544259-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 753a2d9c8a177..8e0c669061036 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -846,8 +846,6 @@ static int sun6i_rtc_probe(struct platform_device *pdev) if (ret) return ret; - dev_info(&pdev->dev, "RTC enabled\n"); - return 0; } From 8805baceb0aa24757916300667940f12aa002dab Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 28 Aug 2023 00:16:41 +0200 Subject: [PATCH 71/73] rtc: twl: remove unnecessary messages The RTC core already prints a message when the RTC is registered and when registering fails, it is not necessary to have more in the driver. Link: https://lore.kernel.org/r/20230827221643.544259-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-twl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index f8f0d774a06e0..13f8ce08243c8 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -555,7 +555,6 @@ static int twl_rtc_probe(struct platform_device *pdev) REG_INT_MSK_STS_A); } - dev_info(&pdev->dev, "Enabling TWL-RTC\n"); ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG); if (ret < 0) @@ -577,11 +576,8 @@ static int twl_rtc_probe(struct platform_device *pdev) twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &twl_rtc_ops, THIS_MODULE); - if (IS_ERR(twl_rtc->rtc)) { - dev_err(&pdev->dev, "can't register RTC device, err %ld\n", - PTR_ERR(twl_rtc->rtc)); + if (IS_ERR(twl_rtc->rtc)) return PTR_ERR(twl_rtc->rtc); - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, twl_rtc_interrupt, From d844c64bbc86682f4ac3e92627b8e3b57ddfad6a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 28 Aug 2023 00:16:42 +0200 Subject: [PATCH 72/73] rtc: wm8350: remove unnecessary messages The RTC core already prints a message when the RTC is registered and when registering fails, it is not necessary to have more in the driver. Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20230827221643.544259-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-wm8350.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index 947f8071803f1..3c773cff2b393 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -386,8 +386,6 @@ static int wm8350_rtc_probe(struct platform_device *pdev) /* enable the RTC if it's not already enabled */ power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); if (!(power5 & WM8350_RTC_TICK_ENA)) { - dev_info(wm8350->dev, "Starting RTC\n"); - wm8350_reg_unlock(wm8350); ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, @@ -426,11 +424,8 @@ static int wm8350_rtc_probe(struct platform_device *pdev) wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350", &wm8350_rtc_ops, THIS_MODULE); - if (IS_ERR(wm_rtc->rtc)) { - ret = PTR_ERR(wm_rtc->rtc); - dev_err(&pdev->dev, "failed to register RTC: %d\n", ret); - return ret; - } + if (IS_ERR(wm_rtc->rtc)) + return PTR_ERR(wm_rtc->rtc); ret = wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350_rtc_update_handler, 0, From ce413486c9a0d735d86cc7d88660abeac99c2501 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 2 Sep 2023 10:44:07 -0300 Subject: [PATCH 73/73] dt-bindings: rtc: ds3231: Remove text binding The "maxim,ds3231" compatible is described in the rtc-ds1307.yaml, so there is no need to keep the text bindings version. Remove the maxim,ds3231.txt file in favor of the rtc-ds1307.yaml binding. Signed-off-by: Fabio Estevam Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230902134407.2589099-1-festevam@gmail.com Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/maxim,ds3231.txt | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/maxim,ds3231.txt diff --git a/Documentation/devicetree/bindings/rtc/maxim,ds3231.txt b/Documentation/devicetree/bindings/rtc/maxim,ds3231.txt deleted file mode 100644 index 85be53a421809..0000000000000 --- a/Documentation/devicetree/bindings/rtc/maxim,ds3231.txt +++ /dev/null @@ -1,38 +0,0 @@ -* Maxim DS3231 Real Time Clock - -Required properties: -- compatible: Should contain "maxim,ds3231". -- reg: I2C address for chip. - -Optional property: -- #clock-cells: Should be 1. -- clock-output-names: - overwrite the default clock names "ds3231_clk_sqw" and "ds3231_clk_32khz". - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. Following indices are allowed: - - 0: square-wave output on the SQW pin - - 1: square-wave output on the 32kHz pin - -- interrupts: rtc alarm/event interrupt. When this property is selected, - clock on the SQW pin cannot be used. - -Example: - -ds3231: ds3231@51 { - compatible = "maxim,ds3231"; - reg = <0x68>; - #clock-cells = <1>; -}; - -device1 { -... - clocks = <&ds3231 0>; -... -}; - -device2 { -... - clocks = <&ds3231 1>; -... -};