summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-09 23:39:00 +0200
committerMark Brown <broonie@kernel.org>2026-10-09 23:39:00 +0200
commitb67802dd382beb56bdfc8eebd2656429828d9bc6 (patch)
treec08b8fe5e48703c3670d63335e2d42ad4b0d3575
parent4467408bc81204b13d75f9768d4e248618eadb64 (diff)
parent8a017ab98412c997b9ce6b57a6941e229bf7f89a (diff)
downloadlinux-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.yaml9
-rw-r--r--Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml18
-rw-r--r--Documentation/devicetree/bindings/rtc/renesas,rzn1-rtc.yaml30
-rw-r--r--drivers/rtc/Kconfig25
-rw-r--r--drivers/rtc/rtc-abx80x.c656
-rw-r--r--drivers/rtc/rtc-bd70528.c5
-rw-r--r--drivers/rtc/rtc-ftrtc010.c73
-rw-r--r--drivers/rtc/rtc-mt6397.c91
-rw-r--r--drivers/rtc/rtc-omap.c5
-rw-r--r--drivers/rtc/rtc-pcf8563.c3
-rw-r--r--drivers/rtc/rtc-rzn1.c52
-rw-r--r--drivers/soc/ti/pm33xx.c2
-rw-r--r--include/linux/mfd/mt6397/rtc.h7
-rw-r--r--include/linux/rtc/rtc-omap.h2
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_ */