diff options
| author | Mark Brown <broonie@kernel.org> | 2026-10-09 23:39:00 +0200 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-10-09 23:39:00 +0200 |
| commit | b67802dd382beb56bdfc8eebd2656429828d9bc6 (patch) | |
| tree | c08b8fe5e48703c3670d63335e2d42ad4b0d3575 | |
| parent | 4467408bc81204b13d75f9768d4e248618eadb64 (diff) | |
| parent | 8a017ab98412c997b9ce6b57a6941e229bf7f89a (diff) | |
| download | linux-next-b67802dd382beb56bdfc8eebd2656429828d9bc6.tar.gz linux-next-b67802dd382beb56bdfc8eebd2656429828d9bc6.zip | |
Merge branch 'rtc-next' of https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
| -rw-r--r-- | Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml | 9 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml | 18 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml | 30 | ||||
| -rw-r--r-- | drivers/rtc/Kconfig | 25 | ||||
| -rw-r--r-- | drivers/rtc/rtc-abx80x.c | 656 | ||||
| -rw-r--r-- | drivers/rtc/rtc-bd70528.c | 5 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ftrtc010.c | 73 | ||||
| -rw-r--r-- | drivers/rtc/rtc-mt6397.c | 91 | ||||
| -rw-r--r-- | drivers/rtc/rtc-omap.c | 5 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 3 | ||||
| -rw-r--r-- | drivers/rtc/rtc-rzn1.c | 52 | ||||
| -rw-r--r-- | drivers/soc/ti/pm33xx.c | 2 | ||||
| -rw-r--r-- | include/linux/mfd/mt6397/rtc.h | 7 | ||||
| -rw-r--r-- | include/linux/rtc/rtc-omap.h | 2 |
14 files changed, 644 insertions, 334 deletions
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml index d2de227ae7a6..1d5502303495 100644 --- a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml @@ -81,6 +81,15 @@ properties: start-year: true + nvmem-layout: + $ref: /schemas/nvmem/layouts/nvmem-layout.yaml + description: + The RTC carries four bytes of storage that neither the clock nor the + alarm uses, in the high half of four of the alarm registers, and + offers them as a battery-backed nvmem provider. MediaTek's + documentation names them RTC_NEW_SPARE0 to RTC_NEW_SPARE3 and gives + the first to a fuel gauge. + required: - compatible diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml b/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml index 355b0598411a..d105570bcd5a 100644 --- a/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml +++ b/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/rtc/abracon,abx80x.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Abracon ABX80X I2C ultra low power RTC/Alarm chip +title: Abracon ABX80X (I2C) and ABX81X (SPI) ultra low power RTC/Alarm chips maintainers: - linux-rtc@vger.kernel.org @@ -21,10 +21,12 @@ properties: - abracon,ab0803 - abracon,ab0804 - abracon,ab0805 + - abracon,ab0815 - abracon,ab1801 - abracon,ab1803 - abracon,ab1804 - abracon,ab1805 + - abracon,ab1815 - microcrystal,rv1805 reg: @@ -61,6 +63,7 @@ required: - reg allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# - $ref: rtc.yaml# - if: properties: @@ -73,6 +76,8 @@ allOf: - abracon,ab1804 - abracon,ab0805 - abracon,ab1805 + - abracon,ab0815 + - abracon,ab1815 then: properties: abracon,tc-diode: false @@ -96,3 +101,14 @@ examples: interrupts = <44 IRQ_TYPE_EDGE_FALLING>; }; }; + + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + rtc@0 { + compatible = "abracon,ab1815"; + reg = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml b/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml index ea7b039a91e7..b448725671ec 100644 --- a/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml @@ -14,14 +14,16 @@ properties: oneOf: - items: - enum: - - renesas,r9a06g032-rtc - - const: renesas,rzn1-rtc + - renesas,r9a06g032-rtc # RZ/N1D + - const: renesas,rzn1-rtc # RZ/N1 - - const: renesas,r9a09g077-rtc + - const: renesas,r9a09g077-rtc # RZ/T2H - items: - - const: renesas,r9a09g087-rtc - - const: renesas,r9a09g077-rtc + - const: renesas,r9a09g087-rtc # RZ/N2H + - const: renesas,r9a09g077-rtc # RZ/T2H + + - const: renesas,r8a78000-rtc # R-Car X5H reg: maxItems: 1 @@ -52,8 +54,6 @@ properties: required: - compatible - reg - - interrupts - - interrupt-names - clocks - clock-names - power-domains @@ -66,6 +66,7 @@ allOf: compatible: contains: enum: + - renesas,r8a78000-rtc - renesas,r9a09g077-rtc - renesas,r9a09g087-rtc then: @@ -75,6 +76,20 @@ allOf: clock-names: minItems: 2 + - if: + properties: + compatible: + contains: + const: renesas,r8a78000-rtc + then: + properties: + interrupts: false + interrupt-names: false + else: + required: + - interrupts + - interrupt-names + unevaluatedProperties: false examples: @@ -91,5 +106,4 @@ examples: clocks = <&sysctrl R9A06G032_HCLK_RTC>; clock-names = "hclk"; power-domains = <&sysctrl>; - start-year = <2000>; }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 0636b9ead2c2..8d9f4ef92f5a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -212,17 +212,6 @@ config RTC_DRV_ABEOZ9 This driver can also be built as a module. If so, the module will be called rtc-ab-e0z9. -config RTC_DRV_ABX80X - tristate "Abracon ABx80x" - select WATCHDOG_CORE if WATCHDOG - help - If you say yes here you get support for Abracon AB080X and AB180X - families of ultra-low-power battery- and capacitor-backed real-time - clock chips. - - This driver can also be built as a module. If so, the module - will be called rtc-abx80x. - config RTC_DRV_AC100 tristate "X-Powers AC100" depends on MFD_AC100 @@ -954,6 +943,20 @@ config RTC_I2C_AND_SPI comment "SPI and I2C RTC drivers" +config RTC_DRV_ABX80X + tristate "Abracon ABx80x" + depends on RTC_I2C_AND_SPI + select WATCHDOG_CORE if WATCHDOG + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER + help + If you say yes here you get support for Abracon AB080X, AB180X, + AB081X and AB181X families of ultra-low-power battery- and + capacitor-backed real-time clock chips. + + This driver can also be built as a module. If so, the module + will be called rtc-abx80x. + config RTC_DRV_DS3232 tristate "Dallas/Maxim DS3232/DS3234" depends on RTC_I2C_AND_SPI diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 5486d9d0b1e5..718e6b8555f5 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * A driver for the I2C members of the Abracon AB x8xx RTC family, - * and compatible: AB 1805 and AB 0805 + * A driver for the I2C and SPI members of the Abracon AB x8xx RTC family, + * and compatible: AB 1805, AB 0805, AB 1815 and AB 0815 * * Copyright 2014-2015 Macq S.A. * @@ -15,8 +15,11 @@ #include <linux/i2c.h> #include <linux/kstrtox.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/of.h> +#include <linux/regmap.h> #include <linux/rtc.h> +#include <linux/spi/spi.h> #include <linux/watchdog.h> #define ABX8XX_REG_HTH 0x00 @@ -50,12 +53,18 @@ #define ABX8XX_CTRL2_RSVD BIT(5) #define ABX8XX_REG_IRQ 0x12 +#define ABX8XX_IRQ_EX1E BIT(0) +#define ABX8XX_IRQ_EX2E BIT(1) #define ABX8XX_IRQ_AIE BIT(2) +#define ABX8XX_IRQ_TIE BIT(3) +#define ABX8XX_IRQ_BLIE BIT(4) #define ABX8XX_IRQ_IM_1_4 (0x3 << 5) #define ABX8XX_REG_CD_TIMER_CTL 0x18 #define ABX8XX_REG_OSC 0x1c +#define ABX8XX_OSC_ACIE BIT(0) +#define ABX8XX_OSC_OFIE BIT(1) #define ABX8XX_OSC_FOS BIT(3) #define ABX8XX_OSC_BOS BIT(4) #define ABX8XX_OSC_ACAL_512 BIT(5) @@ -101,8 +110,8 @@ static u8 trickle_resistors[] = {0, 3, 6, 11}; -enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, - AB1801, AB1803, AB1804, AB1805, RV1805, ABX80X}; +enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, AB0815, + AB1801, AB1803, AB1804, AB1805, AB1815, RV1805, ABX80X}; struct abx80x_cap { u16 pn; @@ -115,61 +124,67 @@ static struct abx80x_cap abx80x_caps[] = { [AB0803] = {.pn = 0x0803}, [AB0804] = {.pn = 0x0804, .has_tc = true, .has_wdog = true}, [AB0805] = {.pn = 0x0805, .has_tc = true, .has_wdog = true}, + [AB0815] = {.pn = 0x0815, .has_tc = true, .has_wdog = true}, [AB1801] = {.pn = 0x1801}, [AB1803] = {.pn = 0x1803}, [AB1804] = {.pn = 0x1804, .has_tc = true, .has_wdog = true}, [AB1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true}, + [AB1815] = {.pn = 0x1815, .has_tc = true, .has_wdog = true}, [RV1805] = {.pn = 0x1805, .has_tc = true, .has_wdog = true}, [ABX80X] = {.pn = 0} }; struct abx80x_priv { struct rtc_device *rtc; - struct i2c_client *client; + struct regmap *regmap; struct watchdog_device wdog; + struct mutex lock; + int irq; }; -static int abx80x_write_config_key(struct i2c_client *client, u8 key) +static int abx80x_write_config_key(struct device *dev, u8 key) { - if (i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY, key) < 0) { - dev_err(&client->dev, "Unable to write configuration key\n"); + struct abx80x_priv *priv = dev_get_drvdata(dev); + + if (regmap_write(priv->regmap, ABX8XX_REG_CFG_KEY, key) < 0) { + dev_err(dev, "Unable to write configuration key\n"); return -EIO; } return 0; } -static int abx80x_is_rc_mode(struct i2c_client *client) +static int abx80x_is_rc_mode(struct device *dev) { - int flags = 0; + struct abx80x_priv *priv = dev_get_drvdata(dev); + unsigned int flags = 0; + int err; - flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); - if (flags < 0) { - dev_err(&client->dev, - "Failed to read autocalibration attribute\n"); - return flags; + err = regmap_read(priv->regmap, ABX8XX_REG_OSS, &flags); + if (err < 0) { + dev_err(dev, "Failed to read autocalibration attribute\n"); + return err; } return (flags & ABX8XX_OSS_OMODE) ? 1 : 0; } -static int abx80x_enable_trickle_charger(struct i2c_client *client, - u8 trickle_cfg) +static int abx80x_enable_trickle_charger(struct device *dev, u8 trickle_cfg) { + struct abx80x_priv *priv = dev_get_drvdata(dev); int err; /* * Write the configuration key register to enable access to the Trickle * register */ - if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_MISC) < 0) + if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_MISC) < 0) return -EIO; - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_TRICKLE, - ABX8XX_TRICKLE_CHARGE_ENABLE | - trickle_cfg); + err = regmap_write(priv->regmap, ABX8XX_REG_TRICKLE, + ABX8XX_TRICKLE_CHARGE_ENABLE | trickle_cfg); if (err < 0) { - dev_err(&client->dev, "Unable to write trickle register\n"); + dev_err(dev, "Unable to write trickle register\n"); return -EIO; } @@ -178,19 +193,20 @@ static int abx80x_enable_trickle_charger(struct i2c_client *client, static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); + struct abx80x_priv *priv = dev_get_drvdata(dev); unsigned char buf[8]; - int err, flags, rc_mode = 0; + unsigned int flags; + int err, rc_mode = 0; /* Read the Oscillator Failure only in XT mode */ - rc_mode = abx80x_is_rc_mode(client); + rc_mode = abx80x_is_rc_mode(dev); if (rc_mode < 0) return rc_mode; if (!rc_mode) { - flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); - if (flags < 0) - return flags; + err = regmap_read(priv->regmap, ABX8XX_REG_OSS, &flags); + if (err < 0) + return err; if (flags & ABX8XX_OSS_OF) { dev_err(dev, "Oscillator failure, data is invalid.\n"); @@ -198,10 +214,9 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm) } } - err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH, - sizeof(buf), buf); + err = regmap_bulk_read(priv->regmap, ABX8XX_REG_HTH, buf, sizeof(buf)); if (err < 0) { - dev_err(&client->dev, "Unable to read date\n"); + dev_err(dev, "Unable to read date\n"); return -EIO; } @@ -218,9 +233,9 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm) static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); + struct abx80x_priv *priv = dev_get_drvdata(dev); unsigned char buf[8]; - int err, flags; + int err; if (tm->tm_year < 100) return -EINVAL; @@ -234,37 +249,35 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[ABX8XX_REG_YR] = bin2bcd(tm->tm_year - 100); buf[ABX8XX_REG_WD] = tm->tm_wday; - err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_HTH, - sizeof(buf), buf); + guard(mutex)(&priv->lock); + + err = regmap_bulk_write(priv->regmap, ABX8XX_REG_HTH, buf, + sizeof(buf)); if (err < 0) { - dev_err(&client->dev, "Unable to write to date registers\n"); + dev_err(dev, "Unable to write to date registers\n"); return -EIO; } /* Clear the OF bit of Oscillator Status Register */ - flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); - if (flags < 0) - return flags; + err = regmap_update_bits(priv->regmap, ABX8XX_REG_OSS, ABX8XX_OSS_OF, 0); + if (err < 0) + dev_err(dev, "Unable to write oscillator status register\n"); - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSS, - flags & ~ABX8XX_OSS_OF); - if (err < 0) { - dev_err(&client->dev, "Unable to write oscillator status register\n"); - return err; - } - - return 0; + return err; } static irqreturn_t abx80x_handle_irq(int irq, void *dev_id) { - struct i2c_client *client = dev_id; - struct abx80x_priv *priv = i2c_get_clientdata(client); + struct device *dev = dev_id; + struct abx80x_priv *priv = dev_get_drvdata(dev); struct rtc_device *rtc = priv->rtc; - int status; + unsigned int status, status_flags_clear; + int err; + + guard(mutex)(&priv->lock); - status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); - if (status < 0) + err = regmap_read(priv->regmap, ABX8XX_REG_STATUS, &status); + if (err < 0) return IRQ_NONE; if (status & ABX8XX_STATUS_AF) @@ -275,31 +288,37 @@ static irqreturn_t abx80x_handle_irq(int irq, void *dev_id) * reset kicks in. */ if (status & ABX8XX_STATUS_WDT) - dev_alert(&client->dev, "watchdog timeout interrupt.\n"); + dev_alert(dev, "watchdog timeout interrupt.\n"); - i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0); + status_flags_clear = status & (ABX8XX_STATUS_AF | ABX8XX_STATUS_WDT); + + if (status_flags_clear) { + regmap_write(priv->regmap, ABX8XX_REG_STATUS, + status & ~status_flags_clear); + return IRQ_HANDLED; + } - return IRQ_HANDLED; + return IRQ_NONE; } static int abx80x_read_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); + struct abx80x_priv *priv = dev_get_drvdata(dev); unsigned char buf[7]; - int irq_mask, err; + unsigned int irq_mask; + int err; - if (client->irq <= 0) + if (priv->irq <= 0) return -EINVAL; - err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ASC, - sizeof(buf), buf); + err = regmap_bulk_read(priv->regmap, ABX8XX_REG_ASC, buf, sizeof(buf)); if (err) return err; - irq_mask = i2c_smbus_read_byte_data(client, ABX8XX_REG_IRQ); - if (irq_mask < 0) - return irq_mask; + err = regmap_read(priv->regmap, ABX8XX_REG_IRQ, &irq_mask); + if (err < 0) + return err; t->time.tm_sec = bcd2bin(buf[0] & 0x7F); t->time.tm_min = bcd2bin(buf[1] & 0x7F); @@ -311,16 +330,16 @@ static int abx80x_read_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled = !!(irq_mask & ABX8XX_IRQ_AIE); t->pending = (buf[6] & ABX8XX_STATUS_AF) && t->enabled; - return err; + return 0; } static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); + struct abx80x_priv *priv = dev_get_drvdata(dev); u8 alarm[6]; int err; - if (client->irq <= 0) + if (priv->irq <= 0) return -EINVAL; alarm[0] = 0x0; @@ -330,17 +349,18 @@ static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t) alarm[4] = bin2bcd(t->time.tm_mday); alarm[5] = bin2bcd(t->time.tm_mon + 1); - err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_AHTH, - sizeof(alarm), alarm); + guard(mutex)(&priv->lock); + + err = regmap_bulk_write(priv->regmap, ABX8XX_REG_AHTH, + alarm, sizeof(alarm)); if (err < 0) { - dev_err(&client->dev, "Unable to write alarm registers\n"); + dev_err(dev, "Unable to write alarm registers\n"); return -EIO; } if (t->enabled) { - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ, - (ABX8XX_IRQ_IM_1_4 | - ABX8XX_IRQ_AIE)); + err = regmap_write(priv->regmap, ABX8XX_REG_IRQ, + ABX8XX_IRQ_IM_1_4 | ABX8XX_IRQ_AIE); if (err) return err; } @@ -351,8 +371,8 @@ static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t) static int abx80x_rtc_set_autocalibration(struct device *dev, int autocalibration) { - struct i2c_client *client = to_i2c_client(dev); - int retval, flags = 0; + struct abx80x_priv *priv = dev_get_drvdata(dev); + unsigned int flags = 0; if ((autocalibration != 0) && (autocalibration != 1024) && (autocalibration != 512)) { @@ -360,10 +380,6 @@ static int abx80x_rtc_set_autocalibration(struct device *dev, return -EINVAL; } - flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC); - if (flags < 0) - return flags; - if (autocalibration == 0) { flags &= ~(ABX8XX_OSC_ACAL_512 | ABX8XX_OSC_ACAL_1024); } else if (autocalibration == 1024) { @@ -375,23 +391,26 @@ static int abx80x_rtc_set_autocalibration(struct device *dev, flags |= (ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512); } + guard(mutex)(&priv->lock); + /* Unlock write access to Oscillator Control Register */ - if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_OSC) < 0) + if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_OSC) < 0) return -EIO; - retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags); - - return retval; + return regmap_write_bits(priv->regmap, ABX8XX_REG_OSC, + ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512, + flags); } static int abx80x_rtc_get_autocalibration(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - int flags = 0, autocalibration; + struct abx80x_priv *priv = dev_get_drvdata(dev); + unsigned int flags = 0; + int autocalibration, err; - flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC); - if (flags < 0) - return flags; + err = regmap_read(priv->regmap, ABX8XX_REG_OSC, &flags); + if (err < 0) + return err; if (flags & ABX8XX_OSC_ACAL_512) autocalibration = 512; @@ -442,8 +461,8 @@ static ssize_t oscillator_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev->parent); - int retval, flags, rc_mode = 0; + struct abx80x_priv *priv = dev_get_drvdata(dev->parent); + int retval, rc_mode = 0; if (strncmp(buf, "rc", 2) == 0) { rc_mode = 1; @@ -454,24 +473,16 @@ static ssize_t oscillator_store(struct device *dev, return -EINVAL; } - flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC); - if (flags < 0) - return flags; - - if (rc_mode == 0) - flags &= ~(ABX8XX_OSC_OSEL); - else - flags |= (ABX8XX_OSC_OSEL); + guard(mutex)(&priv->lock); /* Unlock write access on Oscillator Control register */ - if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_OSC) < 0) + if (abx80x_write_config_key(dev->parent, ABX8XX_CFG_KEY_OSC) < 0) return -EIO; - retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags); - if (retval < 0) { + retval = regmap_write_bits(priv->regmap, ABX8XX_REG_OSC, ABX8XX_OSC_OSEL, + rc_mode == 0 ? 0 : (ABX8XX_OSC_OSEL)); + if (retval < 0) dev_err(dev, "Failed to write Oscillator Control register\n"); - return retval; - } return retval ? retval : count; } @@ -480,9 +491,8 @@ static ssize_t oscillator_show(struct device *dev, struct device_attribute *attr, char *buf) { int rc_mode = 0; - struct i2c_client *client = to_i2c_client(dev->parent); - rc_mode = abx80x_is_rc_mode(client); + rc_mode = abx80x_is_rc_mode(dev->parent); if (rc_mode < 0) { dev_err(dev, "Failed to read RTC oscillator selection\n"); @@ -510,47 +520,43 @@ static const struct attribute_group rtc_calib_attr_group = { static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct i2c_client *client = to_i2c_client(dev); + struct abx80x_priv *priv = dev_get_drvdata(dev); int err; + guard(mutex)(&priv->lock); + if (enabled) - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ, - (ABX8XX_IRQ_IM_1_4 | - ABX8XX_IRQ_AIE)); + err = regmap_write(priv->regmap, ABX8XX_REG_IRQ, + ABX8XX_IRQ_IM_1_4 | ABX8XX_IRQ_AIE); else - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ, - ABX8XX_IRQ_IM_1_4); + err = regmap_write(priv->regmap, ABX8XX_REG_IRQ, + ABX8XX_IRQ_IM_1_4); return err; } static int abx80x_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct i2c_client *client = to_i2c_client(dev); - int status, tmp; + struct abx80x_priv *priv = dev_get_drvdata(dev); + unsigned int status; + int err, tmp; switch (cmd) { case RTC_VL_READ: - status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); - if (status < 0) - return status; + err = regmap_read(priv->regmap, ABX8XX_REG_STATUS, &status); + if (err < 0) + return err; tmp = status & ABX8XX_STATUS_BLF ? RTC_VL_BACKUP_LOW : 0; return put_user(tmp, (unsigned int __user *)arg); case RTC_VL_CLR: - status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); - if (status < 0) - return status; - - status &= ~ABX8XX_STATUS_BLF; - - tmp = i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, - status); - if (tmp < 0) - return tmp; + scoped_guard(mutex, &priv->lock) { + err = regmap_update_bits(priv->regmap, ABX8XX_REG_STATUS, + ABX8XX_STATUS_BLF, 0); + } - return 0; + return err; default: return -ENOIOCTLCMD; @@ -566,9 +572,9 @@ static const struct rtc_class_ops abx80x_rtc_ops = { .ioctl = abx80x_ioctl, }; -static int abx80x_dt_trickle_cfg(struct i2c_client *client) +static int abx80x_dt_trickle_cfg(struct device *dev) { - struct device_node *np = client->dev.of_node; + struct device_node *np = dev->of_node; const char *diode; int trickle_cfg = 0; int i, ret; @@ -583,7 +589,7 @@ static int abx80x_dt_trickle_cfg(struct i2c_client *client) } else if (!strcmp(diode, "schottky")) { trickle_cfg |= ABX8XX_TRICKLE_SCHOTTKY_DIODE; } else { - dev_dbg(&client->dev, "Invalid tc-diode value: %s\n", diode); + dev_dbg(dev, "Invalid tc-diode value: %s\n", diode); return -EINVAL; } @@ -596,7 +602,7 @@ static int abx80x_dt_trickle_cfg(struct i2c_client *client) break; if (i == sizeof(trickle_resistors)) { - dev_dbg(&client->dev, "Invalid tc-resistor value: %u\n", tmp); + dev_dbg(dev, "Invalid tc-resistor value: %u\n", tmp); return -EINVAL; } @@ -617,11 +623,13 @@ static int __abx80x_wdog_set_timeout(struct watchdog_device *wdog, struct abx80x_priv *priv = watchdog_get_drvdata(wdog); u8 val = ABX8XX_WDT_WDS | timeout_bits(timeout); + guard(mutex)(&priv->lock); + /* * Writing any timeout to the WDT register resets the watchdog timer. * Writing 0 disables it. */ - return i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_WDT, val); + return regmap_write(priv->regmap, ABX8XX_REG_WDT, val); } static int abx80x_wdog_set_timeout(struct watchdog_device *wdog, @@ -666,9 +674,11 @@ static const struct watchdog_ops abx80x_wdog_ops = { .set_timeout = abx80x_wdog_set_timeout, }; -static int abx80x_setup_watchdog(struct abx80x_priv *priv) +static int abx80x_setup_watchdog(struct device *dev) { - priv->wdog.parent = &priv->client->dev; + struct abx80x_priv *priv = dev_get_drvdata(dev); + + priv->wdog.parent = dev; priv->wdog.ops = &abx80x_wdog_ops; priv->wdog.info = &abx80x_wdog_info; priv->wdog.min_timeout = 1; @@ -677,10 +687,10 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv) watchdog_set_drvdata(&priv->wdog, priv); - return devm_watchdog_register_device(&priv->client->dev, &priv->wdog); + return devm_watchdog_register_device(dev, &priv->wdog); } #else -static int abx80x_setup_watchdog(struct abx80x_priv *priv) +static int abx80x_setup_watchdog(struct device *dev) { return 0; } @@ -692,31 +702,29 @@ static int abx80x_nvmem_xfer(struct abx80x_priv *priv, unsigned int offset, int ret; while (bytes) { - u8 extram, reg, len, lower, upper; + u8 reg, len, lower, upper; lower = FIELD_GET(NVMEM_ADDR_LOWER, offset); upper = FIELD_GET(NVMEM_ADDR_UPPER, offset); - extram = FIELD_PREP(ABX8XX_EXTRAM_XADS, upper); reg = ABX8XX_SRAM_BASE + lower; len = min(lower + bytes, (size_t)ABX8XX_SRAM_WIN_SIZE) - lower; len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); - ret = i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_EXTRAM, - extram); + guard(mutex)(&priv->lock); + + ret = regmap_update_bits(priv->regmap, ABX8XX_REG_EXTRAM, + ABX8XX_EXTRAM_XADS, upper); if (ret) return ret; if (write) { - ret = i2c_smbus_write_i2c_block_data(priv->client, reg, - len, val); + ret = regmap_bulk_write(priv->regmap, reg, val, len); if (ret) return ret; } else { - ret = i2c_smbus_read_i2c_block_data(priv->client, reg, - len, val); - if (ret <= 0) - return ret ? ret : -EIO; - len = ret; + ret = regmap_bulk_read(priv->regmap, reg, val, len); + if (ret) + return ret; } offset += len; @@ -752,41 +760,61 @@ static int abx80x_setup_nvmem(struct abx80x_priv *priv) return devm_rtc_nvmem_register(priv->rtc, &config); } -static const struct i2c_device_id abx80x_id[] = { - { .name = "abx80x", .driver_data = ABX80X }, - { .name = "ab0801", .driver_data = AB0801 }, - { .name = "ab0803", .driver_data = AB0803 }, - { .name = "ab0804", .driver_data = AB0804 }, - { .name = "ab0805", .driver_data = AB0805 }, - { .name = "ab1801", .driver_data = AB1801 }, - { .name = "ab1803", .driver_data = AB1803 }, - { .name = "ab1804", .driver_data = AB1804 }, - { .name = "ab1805", .driver_data = AB1805 }, - { .name = "rv1805", .driver_data = RV1805 }, - { } +static const struct regmap_range abx80x_no_read_ranges[] = { + regmap_reg_range(0x1e, 0x1e), + regmap_reg_range(0x22, 0x25), + regmap_reg_range(0x31, 0x3e), +}; + +static const struct regmap_range abx80x_no_write_ranges[] = { + regmap_reg_range(0x1e, 0x1e), + regmap_reg_range(0x22, 0x25), + regmap_reg_range(ABX8XX_REG_ID0, ABX8XX_REG_ID0 + 6), + regmap_reg_range(0x31, 0x3e), }; -MODULE_DEVICE_TABLE(i2c, abx80x_id); -static int abx80x_probe(struct i2c_client *client) +static const struct regmap_access_table abx80x_read_table = { + .no_ranges = abx80x_no_read_ranges, + .n_no_ranges = ARRAY_SIZE(abx80x_no_read_ranges), +}; + +static const struct regmap_access_table abx80x_write_table = { + .no_ranges = abx80x_no_write_ranges, + .n_no_ranges = ARRAY_SIZE(abx80x_no_write_ranges), +}; + +static int abx80x_probe(struct device *dev, struct regmap *regmap, int irq, + struct device_node *np, unsigned int part) { - struct device_node *np = client->dev.of_node; struct abx80x_priv *priv; - int i, data, err, trickle_cfg = -EINVAL; + int i, err, trickle_cfg = -EINVAL; char buf[7]; - unsigned int part = (uintptr_t)i2c_get_match_data(client); unsigned int partnumber; unsigned int majrev, minrev; unsigned int lot; unsigned int wafer; unsigned int uid; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; - err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ID0, - sizeof(buf), buf); + priv->rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(priv->rtc)) + return PTR_ERR(priv->rtc); + + priv->rtc->ops = &abx80x_rtc_ops; + priv->irq = irq; + priv->regmap = regmap; + err = devm_mutex_init(dev, &priv->lock); + if (err) + return err; + + dev_set_drvdata(dev, priv); + + err = regmap_bulk_read(regmap, ABX8XX_REG_ID0, buf, sizeof(buf)); if (err < 0) { - dev_err(&client->dev, "Unable to read partnumber\n"); + dev_err(dev, "Unable to read partnumber\n"); return -EIO; } @@ -796,21 +824,14 @@ static int abx80x_probe(struct i2c_client *client) lot = ((buf[4] & 0x80) << 2) | ((buf[6] & 0x80) << 1) | buf[3]; uid = ((buf[4] & 0x7f) << 8) | buf[5]; wafer = (buf[6] & 0x7c) >> 2; - dev_info(&client->dev, "model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n", + dev_info(dev, "model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n", partnumber, majrev, minrev, lot, wafer, uid); - data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL1); - if (data < 0) { - dev_err(&client->dev, "Unable to read control register\n"); - return -EIO; - } - - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1, - ((data & ~(ABX8XX_CTRL_12_24 | - ABX8XX_CTRL_ARST)) | - ABX8XX_CTRL_WRITE)); + err = regmap_update_bits(regmap, ABX8XX_REG_CTRL1, + ABX8XX_CTRL_12_24 | ABX8XX_CTRL_ARST | ABX8XX_CTRL_WRITE, + ABX8XX_CTRL_WRITE); if (err < 0) { - dev_err(&client->dev, "Unable to write control register\n"); + dev_err(dev, "Unable to write control register\n"); return -EIO; } @@ -822,30 +843,10 @@ static int abx80x_probe(struct i2c_client *client) * register is set. RV-1805-C3 datasheet indicates that * the bit should be cleared in section 11h - Control2. */ - data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL2); - if (data < 0) { - dev_err(&client->dev, - "Unable to read control2 register\n"); - return -EIO; - } - - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL2, - data & ~ABX8XX_CTRL2_RSVD); + err = regmap_update_bits(regmap, ABX8XX_REG_CTRL2, + ABX8XX_CTRL2_RSVD, 0); if (err < 0) { - dev_err(&client->dev, - "Unable to write control2 register\n"); - return -EIO; - } - - /* - * Avoid extra power leakage. The RV1805 uses smaller - * 10pin package and the EXTI input is not present. - * Disable it to avoid leakage. - */ - data = i2c_smbus_read_byte_data(client, ABX8XX_REG_OUT_CTRL); - if (data < 0) { - dev_err(&client->dev, - "Unable to read output control register\n"); + dev_err(dev, "Unable to write control2 register\n"); return -EIO; } @@ -853,13 +854,19 @@ static int abx80x_probe(struct i2c_client *client) * Write the configuration key register to enable access to * the config2 register */ - if (abx80x_write_config_key(client, ABX8XX_CFG_KEY_MISC) < 0) + if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_MISC) < 0) return -EIO; - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OUT_CTRL, - data | ABX8XX_OUT_CTRL_EXDS); + /* + * Avoid extra power leakage. The RV1805 uses smaller + * 10pin package and the EXTI input is not present. + * Disable it to avoid leakage. + */ + err = regmap_write_bits(regmap, ABX8XX_REG_OUT_CTRL, + ABX8XX_OUT_CTRL_EXDS, + ABX8XX_OUT_CTRL_EXDS); if (err < 0) { - dev_err(&client->dev, + dev_err(dev, "Unable to write output control register\n"); return -EIO; } @@ -871,48 +878,52 @@ static int abx80x_probe(struct i2c_client *client) if (partnumber == abx80x_caps[i].pn) break; if (abx80x_caps[i].pn == 0) { - dev_err(&client->dev, "Unknown part: %04x\n", - partnumber); + dev_err(dev, "Unknown part: %04x\n", partnumber); return -EINVAL; } part = i; } if (partnumber != abx80x_caps[part].pn) { - dev_err(&client->dev, "partnumber mismatch %04x != %04x\n", + dev_err(dev, "partnumber mismatch %04x != %04x\n", partnumber, abx80x_caps[part].pn); return -EINVAL; } if (np && abx80x_caps[part].has_tc) - trickle_cfg = abx80x_dt_trickle_cfg(client); + trickle_cfg = abx80x_dt_trickle_cfg(dev); if (trickle_cfg > 0) { - dev_info(&client->dev, "Enabling trickle charger: %02x\n", - trickle_cfg); - abx80x_enable_trickle_charger(client, trickle_cfg); + dev_info(dev, "Enabling trickle charger: %02x\n", trickle_cfg); + abx80x_enable_trickle_charger(dev, trickle_cfg); } - err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CD_TIMER_CTL, - BIT(2)); + err = regmap_write(regmap, ABX8XX_REG_CD_TIMER_CTL, BIT(2)); if (err) return err; - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - priv->rtc = devm_rtc_allocate_device(&client->dev); - if (IS_ERR(priv->rtc)) - return PTR_ERR(priv->rtc); + /* Disable unused interrupts */ + err = regmap_update_bits(regmap, ABX8XX_REG_IRQ, + ABX8XX_IRQ_EX1E | ABX8XX_IRQ_EX2E | + ABX8XX_IRQ_TIE | ABX8XX_IRQ_BLIE, 0); + if (err < 0) { + dev_err(dev, "Unable to update irq register\n"); + return -EIO; + } - priv->rtc->ops = &abx80x_rtc_ops; - priv->client = client; + /* Unlock write access to Oscillator Control Register */ + if (abx80x_write_config_key(dev, ABX8XX_CFG_KEY_OSC) < 0) + return -EIO; - i2c_set_clientdata(client, priv); + err = regmap_write_bits(regmap, ABX8XX_REG_OSC, + ABX8XX_OSC_ACIE | ABX8XX_OSC_OFIE, 0); + if (err < 0) { + dev_err(dev, "Unable to update Oscillator Control register\n"); + return -EIO; + } if (abx80x_caps[part].has_wdog) { - err = abx80x_setup_watchdog(priv); + err = abx80x_setup_watchdog(dev); if (err) return err; } @@ -921,31 +932,56 @@ static int abx80x_probe(struct i2c_client *client) if (err) return err; - if (client->irq > 0) { - dev_info(&client->dev, "IRQ %d supplied\n", client->irq); - err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + if (priv->irq > 0) { + dev_info(dev, "IRQ %d supplied\n", priv->irq); + err = devm_request_threaded_irq(dev, priv->irq, NULL, abx80x_handle_irq, IRQF_SHARED | IRQF_ONESHOT, "abx8xx", - client); + dev); if (err) { - dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); - client->irq = 0; + dev_err(dev, "unable to request IRQ, alarms disabled\n"); + priv->irq = 0; } } - if (client->irq <= 0) + if (priv->irq <= 0) clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); if (err) { - dev_err(&client->dev, "Failed to create sysfs group: %d\n", - err); + dev_err(dev, "Failed to create sysfs group: %d\n", err); return err; } return devm_rtc_register_device(priv->rtc); } +#if IS_ENABLED(CONFIG_I2C) + +static const struct regmap_config abx80x_regmap_config_i2c = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ABX8XX_SRAM_BASE + ABX8XX_SRAM_WIN_SIZE - 1, + + .rd_table = &abx80x_read_table, + .wr_table = &abx80x_write_table, +}; + +static const struct i2c_device_id abx80x_id[] = { + { .name = "abx80x", .driver_data = ABX80X }, + { .name = "ab0801", .driver_data = AB0801 }, + { .name = "ab0803", .driver_data = AB0803 }, + { .name = "ab0804", .driver_data = AB0804 }, + { .name = "ab0805", .driver_data = AB0805 }, + { .name = "ab1801", .driver_data = AB1801 }, + { .name = "ab1803", .driver_data = AB1803 }, + { .name = "ab1804", .driver_data = AB1804 }, + { .name = "ab1805", .driver_data = AB1805 }, + { .name = "rv1805", .driver_data = RV1805 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, abx80x_id); + #ifdef CONFIG_OF static const struct of_device_id abx80x_of_match[] = { { @@ -993,16 +1029,160 @@ static const struct of_device_id abx80x_of_match[] = { MODULE_DEVICE_TABLE(of, abx80x_of_match); #endif +static int abx80x_i2c_probe(struct i2c_client *client) +{ + unsigned int part = (uintptr_t)i2c_get_match_data(client); + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + regmap = devm_regmap_init_i2c(client, &abx80x_regmap_config_i2c); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Unable to allocate regmap\n"); + return PTR_ERR(regmap); + } + + return abx80x_probe(&client->dev, regmap, client->irq, + client->dev.of_node, part); +} + static struct i2c_driver abx80x_driver = { .driver = { .name = "rtc-abx80x", .of_match_table = of_match_ptr(abx80x_of_match), }, - .probe = abx80x_probe, + .probe = abx80x_i2c_probe, .id_table = abx80x_id, }; -module_i2c_driver(abx80x_driver); +static int abx80x_register_driver(void) +{ + return i2c_add_driver(&abx80x_driver); +} + +static void abx80x_unregister_driver(void) +{ + i2c_del_driver(&abx80x_driver); +} + +#else + +static int abx80x_register_driver(void) +{ + return 0; +} + +static void abx80x_unregister_driver(void) +{ +} + +#endif /* IS_ENABLED(CONFIG_I2C) */ + +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static const struct regmap_config abx80x_regmap_config_spi = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ABX8XX_SRAM_BASE + ABX8XX_SRAM_WIN_SIZE - 1, + + .rd_table = &abx80x_read_table, + .wr_table = &abx80x_write_table, + + .write_flag_mask = BIT(7), +}; + +static const struct spi_device_id abx81x_id[] = { + { "ab0815", AB0815 }, + { "ab1815", AB1815 }, + { } +}; +MODULE_DEVICE_TABLE(spi, abx81x_id); + +#ifdef CONFIG_OF +static const struct of_device_id abx81x_of_match[] = { + { + .compatible = "abracon,ab0815", + .data = (void *)AB0815 + }, + { + .compatible = "abracon,ab1815", + .data = (void *)AB1815 + }, + { } +}; +MODULE_DEVICE_TABLE(of, abx81x_of_match); +#endif + +static int abx81x_spi_probe(struct spi_device *spi) +{ + unsigned int part = (uintptr_t)spi_get_device_match_data(spi); + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &abx80x_regmap_config_spi); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Unable to allocate regmap\n"); + return PTR_ERR(regmap); + } + + return abx80x_probe(&spi->dev, regmap, spi->irq, + spi->dev.of_node, part); +} + +static struct spi_driver abx81x_driver = { + .driver = { + .name = "rtc-abx81x", + .of_match_table = of_match_ptr(abx81x_of_match), + }, + .probe = abx81x_spi_probe, + .id_table = abx81x_id, +}; + +static int abx81x_register_driver(void) +{ + return spi_register_driver(&abx81x_driver); +} + +static void abx81x_unregister_driver(void) +{ + spi_unregister_driver(&abx81x_driver); +} + +#else + +static int abx81x_register_driver(void) +{ + return 0; +} + +static void abx81x_unregister_driver(void) +{ +} + +#endif /* IS_ENABLED(CONFIG_SPI_MASTER) */ + +static int __init abx80x_init(void) +{ + int ret; + + ret = abx80x_register_driver(); + if (ret) + return ret; + + ret = abx81x_register_driver(); + if (ret) + abx80x_unregister_driver(); + + return ret; +} +module_init(abx80x_init); + +static void __exit abx80x_exit(void) +{ + abx81x_unregister_driver(); + abx80x_unregister_driver(); +} +module_exit(abx80x_exit); MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>"); MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>"); diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c index fd415e327ea6..dd5569d17567 100644 --- a/drivers/rtc/rtc-bd70528.c +++ b/drivers/rtc/rtc-bd70528.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> #include <linux/regmap.h> #include <linux/rtc.h> @@ -328,6 +329,10 @@ static int bd70528_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); device_wakeup_enable(&pdev->dev); + ret = devm_pm_set_wake_irq(&pdev->dev, irq); + if (ret) + return ret; + rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc)) { dev_err(&pdev->dev, "RTC device creation failed\n"); diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c index 98fa0f518303..c66d4a85f23c 100644 --- a/drivers/rtc/rtc-ftrtc010.c +++ b/drivers/rtc/rtc-ftrtc010.c @@ -72,7 +72,7 @@ static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm) days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS); offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD); - time = offset + days * 86400 + hour * 3600 + min * 60 + sec; + time = offset + (timeu64_t)days * 86400 + hour * 3600 + min * 60 + sec; rtc_time64_to_tm(time, tm); @@ -92,7 +92,7 @@ static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm) hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR); day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS); - offset = time - (day * 86400 + hour * 3600 + min * 60 + sec); + offset = time - ((timeu64_t)day * 86400 + hour * 3600 + min * 60 + sec); writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD); writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR); @@ -119,51 +119,33 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, rtc); - rtc->pclk = devm_clk_get(dev, "PCLK"); - if (IS_ERR(rtc->pclk)) { + rtc->pclk = devm_clk_get_enabled(dev, "PCLK"); + if (IS_ERR_OR_NULL(rtc->pclk)) { dev_err(dev, "could not get PCLK\n"); - } else { - ret = clk_prepare_enable(rtc->pclk); - if (ret) { - dev_err(dev, "failed to enable PCLK\n"); - return ret; - } + return PTR_ERR_OR_ZERO(rtc->pclk); } - rtc->extclk = devm_clk_get(dev, "EXTCLK"); - if (IS_ERR(rtc->extclk)) { + rtc->extclk = devm_clk_get_enabled(dev, "EXTCLK"); + if (IS_ERR_OR_NULL(rtc->extclk)) { dev_err(dev, "could not get EXTCLK\n"); - } else { - ret = clk_prepare_enable(rtc->extclk); - if (ret) { - dev_err(dev, "failed to enable EXTCLK\n"); - goto err_disable_pclk; - } + return PTR_ERR_OR_ZERO(rtc->extclk); } rtc->rtc_irq = platform_get_irq(pdev, 0); - if (rtc->rtc_irq < 0) { - ret = rtc->rtc_irq; - goto err_disable_extclk; - } + if (rtc->rtc_irq < 0) + return rtc->rtc_irq; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto err_disable_extclk; - } + if (!res) + return -ENODEV; rtc->rtc_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!rtc->rtc_base) { - ret = -ENOMEM; - goto err_disable_extclk; - } + if (!rtc->rtc_base) + return -ENOMEM; rtc_dev = devm_rtc_allocate_device(dev); - if (IS_ERR(rtc_dev)) { - ret = PTR_ERR(rtc_dev); - goto err_disable_extclk; - } + if (IS_ERR(rtc_dev)) + return PTR_ERR(rtc_dev); rtc_dev->ops = &ftrtc010_rtc_ops; @@ -178,25 +160,13 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev) ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt, IRQF_SHARED, pdev->name, dev); if (unlikely(ret)) - goto err_disable_extclk; + return ret; - return devm_rtc_register_device(rtc_dev); + ret = devm_rtc_register_device(rtc_dev); + if (ret) + return ret; -err_disable_extclk: - clk_disable_unprepare(rtc->extclk); -err_disable_pclk: - clk_disable_unprepare(rtc->pclk); - return ret; -} - -static void ftrtc010_rtc_remove(struct platform_device *pdev) -{ - struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev); - - if (!IS_ERR(rtc->extclk)) - clk_disable_unprepare(rtc->extclk); - if (!IS_ERR(rtc->pclk)) - clk_disable_unprepare(rtc->pclk); + return 0; } static const struct of_device_id ftrtc010_rtc_dt_match[] = { @@ -212,7 +182,6 @@ static struct platform_driver ftrtc010_rtc_driver = { .of_match_table = ftrtc010_rtc_dt_match, }, .probe = ftrtc010_rtc_probe, - .remove = ftrtc010_rtc_remove, }; module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe); diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 3d857681f760..d6e156516aa6 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -4,6 +4,8 @@ * Author: Tianping.Fang <tianping.fang@mediatek.com> */ +#include <linux/array_size.h> +#include <linux/bitfield.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/mfd/mt6397/core.h> @@ -243,10 +245,91 @@ static const struct rtc_class_ops mtk_rtc_ops = { .set_alarm = mtk_rtc_set_alarm, }; +/* + * The spare byte of each of these registers, in the order a board addresses + * them as RTC_NEW_SPARE0 to RTC_NEW_SPARE3. + */ +static const u32 mtk_rtc_spare_reg[] = { + RTC_AL_HOU, RTC_AL_DOM, RTC_AL_DOW, RTC_AL_MTH, +}; + +static int mtk_rtc_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct mt6397_rtc *rtc = priv; + u8 *buf = val; + u32 data; + int ret = 0; + + if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) || + bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset) + return -EINVAL; + + mutex_lock(&rtc->lock); + + while (bytes--) { + ret = regmap_read(rtc->regmap, + rtc->addr_base + mtk_rtc_spare_reg[offset++], + &data); + if (ret) + break; + + *buf++ = FIELD_GET(RTC_SPARE_MASK, data); + } + + mutex_unlock(&rtc->lock); + + return ret; +} + +static int mtk_rtc_nvram_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct mt6397_rtc *rtc = priv; + u8 *buf = val; + int ret = 0; + + if (offset >= ARRAY_SIZE(mtk_rtc_spare_reg) || + bytes > ARRAY_SIZE(mtk_rtc_spare_reg) - offset) + return -EINVAL; + + mutex_lock(&rtc->lock); + + while (bytes--) { + ret = regmap_update_bits(rtc->regmap, + rtc->addr_base + mtk_rtc_spare_reg[offset++], + RTC_SPARE_MASK, + FIELD_PREP(RTC_SPARE_MASK, *buf++)); + if (ret) + goto out; + } + + /* + * None of it reaches the always-on domain until the write trigger, + * which commits every pending alarm register at once -- so this runs + * under the same lock the alarm paths take, rather than landing in + * the middle of one of them. + */ + ret = mtk_rtc_write_trigger(rtc); +out: + mutex_unlock(&rtc->lock); + + return ret; +} + static int mtk_rtc_probe(struct platform_device *pdev) { struct resource *res; struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent); + struct nvmem_config nvmem_cfg = { + .name = "mt6397_rtc_spare", + .word_size = 1, + .stride = 1, + .size = ARRAY_SIZE(mtk_rtc_spare_reg), + .type = NVMEM_TYPE_BATTERY_BACKED, + .reg_read = mtk_rtc_nvram_read, + .reg_write = mtk_rtc_nvram_write, + }; struct mt6397_rtc *rtc; int ret; @@ -293,7 +376,13 @@ static int mtk_rtc_probe(struct platform_device *pdev) rtc->rtc_dev->start_secs = mktime64(1968, 1, 2, 0, 0, 0); rtc->rtc_dev->set_start_time = true; - return devm_rtc_register_device(rtc->rtc_dev); + ret = devm_rtc_register_device(rtc->rtc_dev); + if (ret) + return ret; + + nvmem_cfg.priv = rtc; + + return devm_rtc_nvmem_register(rtc->rtc_dev, &nvmem_cfg); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 0f90065e352c..18492165a19f 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -408,7 +408,7 @@ static struct omap_rtc *omap_rtc_power_off_rtc; * generates pmic_pwr_enable control, which can be used to control an external * PMIC. */ -int omap_rtc_power_off_program(struct device *dev) +int omap_rtc_power_off_program(void) { struct omap_rtc *rtc = omap_rtc_power_off_rtc; struct rtc_time tm; @@ -481,10 +481,9 @@ EXPORT_SYMBOL(omap_rtc_power_off_program); */ static void omap_rtc_power_off(void) { - struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc; u32 val; - omap_rtc_power_off_program(rtc->dev.parent); + omap_rtc_power_off_program(); /* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */ omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 7eebdb058067..56e75664c7b4 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -479,7 +479,8 @@ static int pcf8563_probe(struct i2c_client *client) dev_dbg(&client->dev, "%s\n", __func__); - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) && + !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -ENODEV; pcf8563 = devm_kzalloc(&client->dev, sizeof(struct pcf8563), diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index b9d69ebdd224..1db518ab3a3a 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -68,6 +68,7 @@ struct rzn1_rtc_data { bool has_subu; + bool broken_irqs; }; struct rzn1_rtc { @@ -396,6 +397,11 @@ static const struct rtc_class_ops rzn1_rtc_ops_scmp = { .alarm_irq_enable = rzn1_rtc_alarm_irq_enable, }; +static const struct rtc_class_ops rzn1_rtc_ops_scmp_no_alarm = { + .read_time = rzn1_rtc_read_time, + .set_time = rzn1_rtc_set_time, +}; + static void rzn1_rtc_disable_hardware(void *data) { struct device *dev = data; @@ -431,10 +437,6 @@ static int rzn1_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc->base)) return dev_err_probe(dev, PTR_ERR(rtc->base), "Missing reg\n"); - irq = platform_get_irq_byname(pdev, "alarm"); - if (irq < 0) - return irq; - rtc->rtcdev = devm_rtc_allocate_device(dev); if (IS_ERR(rtc->rtcdev)) return PTR_ERR(rtc->rtcdev); @@ -503,25 +505,40 @@ static int rzn1_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->ctl1_access_lock); - ret = devm_request_irq(dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc); - if (ret) - return dev_err_probe(dev, ret, "RTC alarm interrupt not available\n"); - - irq = platform_get_irq_byname_optional(pdev, "pps"); - if (irq == -EPROBE_DEFER) - return irq; - if (irq >= 0) - ret = devm_request_irq(dev, irq, rzn1_rtc_1s_irq, 0, "RZN1 RTC 1s", rtc); - - if (irq < 0 || ret) { - set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features); + if (data->broken_irqs) { + /* All known broken irqs are on SCMP only variants */ + rtc->rtcdev->ops = &rzn1_rtc_ops_scmp_no_alarm; clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features); - dev_warn(dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n"); + } else { + irq = platform_get_irq_byname(pdev, "alarm"); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, rzn1_rtc_alarm_irq, 0, "RZN1 RTC Alarm", rtc); + if (ret) + return dev_err_probe(dev, ret, "RTC alarm interrupt not available\n"); + + irq = platform_get_irq_byname_optional(pdev, "pps"); + if (irq == -EPROBE_DEFER) + return irq; + if (irq >= 0) + ret = devm_request_irq(dev, irq, rzn1_rtc_1s_irq, 0, "RZN1 RTC 1s", rtc); + + if (irq < 0 || ret) { + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features); + dev_warn(dev, "RTC pps interrupt not available. Alarm has only minute accuracy\n"); + } } return devm_rtc_register_device(rtc->rtcdev); } +static const struct rzn1_rtc_data rzn1_rtc_r8a78000_data = { + .has_subu = false, + .broken_irqs = true, +}; + static const struct rzn1_rtc_data rzn1_rtc_rzt2h_data = { .has_subu = false, }; @@ -531,6 +548,7 @@ static const struct rzn1_rtc_data rzn1_rtc_rzn1_data = { }; static const struct of_device_id rzn1_rtc_of_match[] = { + { .compatible = "renesas,r8a78000-rtc", .data = &rzn1_rtc_r8a78000_data }, { .compatible = "renesas,r9a09g077-rtc", .data = &rzn1_rtc_rzt2h_data }, { .compatible = "renesas,rzn1-rtc", .data = &rzn1_rtc_rzn1_data }, { /* sentinel */ } diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index dc52a2197d24..82979122417d 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -174,7 +174,7 @@ static struct wkup_m3_wakeup_src rtc_wake_src(void) static int am33xx_rtc_only_idle(unsigned long wfi_flags) { - omap_rtc_power_off_program(&omap_rtc->dev); + omap_rtc_power_off_program(); am33xx_do_wfi_sram(wfi_flags); return 0; } diff --git a/include/linux/mfd/mt6397/rtc.h b/include/linux/mfd/mt6397/rtc.h index 27883af44f87..f4da579ec638 100644 --- a/include/linux/mfd/mt6397/rtc.h +++ b/include/linux/mfd/mt6397/rtc.h @@ -49,6 +49,13 @@ #define RTC_AL_SEC 0x0018 +/* The high byte of four of the alarms is spare, always-on storage */ +#define RTC_AL_HOU 0x001c +#define RTC_AL_DOM 0x001e +#define RTC_AL_DOW 0x0020 +#define RTC_AL_MTH 0x0022 +#define RTC_SPARE_MASK GENMASK(15, 8) + #define RTC_AL_SEC_MASK 0x003f #define RTC_AL_MIN_MASK 0x003f #define RTC_AL_HOU_MASK 0x001f diff --git a/include/linux/rtc/rtc-omap.h b/include/linux/rtc/rtc-omap.h index 9f03a329e63f..d6ec7c4daea6 100644 --- a/include/linux/rtc/rtc-omap.h +++ b/include/linux/rtc/rtc-omap.h @@ -3,5 +3,5 @@ #ifndef _LINUX_RTCOMAP_H_ #define _LINUX_RTCOMAP_H_ -int omap_rtc_power_off_program(struct device *dev); +int omap_rtc_power_off_program(void); #endif /* _LINUX_RTCOMAP_H_ */ |
