[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251219-ds1307-rx8901-add-v1-3-b13f346ebe93@axis.com>
Date: Fri, 19 Dec 2025 13:10:37 +0100
From: Fredrik M Olsson <fredrik.m.olsson@...s.com>
To: Alexandre Belloni <alexandre.belloni@...tlin.com>, Rob Herring
<robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley
<conor+dt@...nel.org>, Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@...l.toshiba>
CC: <linux-rtc@...r.kernel.org>, <devicetree@...r.kernel.org>,
<linux-kernel@...r.kernel.org>, Fredrik M Olsson <fredrik.m.olsson@...s.com>,
<kernel@...s.com>
Subject: [PATCH 3/4] rtc: ds1307: Add Driver for Epson RX8901CE
Adds Support for:
- Reading and writing time to/from the RTC.
- Switching to backup battery supply when primary supply disappears.
- Optionally enabling battery charging.
Signed-off-by: Fredrik M Olsson <fredrik.m.olsson@...s.com>
---
drivers/rtc/rtc-ds1307.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index bf42c250ea7d..99d95e520108 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -48,6 +48,7 @@ enum ds_type {
mcp794xx,
rx_8025,
rx_8130,
+ rx_8901,
last_ds_type /* always last */
/* rs5c372 too? different address... */
};
@@ -129,6 +130,12 @@ enum ds_type {
#define RX8130_REG_CONTROL1_INIEN BIT(4)
#define RX8130_REG_CONTROL1_CHGEN BIT(5)
+#define RX8901_REG_INTF 0x0e
+#define RX8901_REG_INTF_VLF BIT(1)
+#define RX8901_REG_PWSW_CFG 0x37
+#define RX8901_REG_PWSW_CFG_INIEN BIT(6)
+#define RX8901_REG_PWSW_CFG_CHGEN BIT(7)
+
#define MCP794XX_REG_CONTROL 0x07
# define MCP794XX_BIT_ALM0_EN 0x10
# define MCP794XX_BIT_ALM1_EN 0x20
@@ -226,6 +233,19 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
dev_warn_once(dev, "oscillator failed, set time!\n");
return -EINVAL;
}
+ } else if (ds1307->type == rx_8901) {
+ unsigned int regflag;
+
+ ret = regmap_read(ds1307->regmap, RX8901_REG_INTF, ®flag);
+ if (ret) {
+ dev_err(dev, "%s error %d\n", "read", ret);
+ return ret;
+ }
+
+ if (regflag & RX8901_REG_INTF_VLF) {
+ dev_warn_once(dev, "oscillator failed, set time!\n");
+ return -EINVAL;
+ }
}
/* read the RTC date and time registers all at once */
@@ -307,7 +327,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
tmp = regs[DS1307_REG_HOUR] & 0x3f;
t->tm_hour = bcd2bin(tmp);
/* rx8130 is bit position, not BCD */
- if (ds1307->type == rx_8130)
+ if (ds1307->type == rx_8130 || ds1307->type == rx_8901)
t->tm_wday = fls(regs[DS1307_REG_WDAY] & 0x7f) - 1;
else
t->tm_wday = bcd2bin(regs[DS1307_REG_WDAY] & 0x07) - 1;
@@ -358,7 +378,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
regs[DS1307_REG_MIN] = bin2bcd(t->tm_min);
regs[DS1307_REG_HOUR] = bin2bcd(t->tm_hour);
/* rx8130 is bit position, not BCD */
- if (ds1307->type == rx_8130)
+ if (ds1307->type == rx_8130 || ds1307->type == rx_8901)
regs[DS1307_REG_WDAY] = 1 << t->tm_wday;
else
regs[DS1307_REG_WDAY] = bin2bcd(t->tm_wday + 1);
@@ -422,6 +442,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
dev_err(dev, "%s error %d\n", "write", result);
return result;
}
+ } else if (ds1307->type == rx_8901) {
+ /*
+ * clear Voltage Loss Flag as data is available now (writing 1
+ * to the other bits in the INTF register has no effect)
+ */
+ result = regmap_write(ds1307->regmap, RX8901_REG_INTF,
+ 0xff ^ RX8901_REG_INTF_VLF);
+ if (result) {
+ dev_err(dev, "%s error %d\n", "write", result);
+ return result;
+ }
}
return 0;
@@ -568,6 +599,17 @@ static u8 do_trickle_setup_rx8130(struct ds1307 *ds1307, u32 ohms, bool diode)
return setup;
}
+static u8 do_trickle_setup_rx8901(struct ds1307 *ds1307, u32 ohms, bool diode)
+{
+ /* make sure that the backup battery is enabled */
+ u8 setup = RX8901_REG_PWSW_CFG_INIEN;
+
+ if (diode)
+ setup |= RX8901_REG_PWSW_CFG_CHGEN;
+
+ return setup;
+}
+
static irqreturn_t rx8130_irq(int irq, void *dev_id)
{
struct ds1307 *ds1307 = dev_id;
@@ -960,6 +1002,11 @@ static const struct rtc_class_ops rx8130_rtc_ops = {
.alarm_irq_enable = rx8130_alarm_irq_enable,
};
+static const struct rtc_class_ops rx8901_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+};
+
static const struct rtc_class_ops mcp794xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
@@ -1040,6 +1087,12 @@ static const struct chip_desc chips[last_ds_type] = {
.trickle_charger_reg = RX8130_REG_CONTROL1,
.do_trickle_setup = &do_trickle_setup_rx8130,
},
+ [rx_8901] = {
+ .offset = 0x0,
+ .rtc_ops = &rx8901_rtc_ops,
+ .trickle_charger_reg = RX8901_REG_PWSW_CFG,
+ .do_trickle_setup = &do_trickle_setup_rx8901,
+ },
[m41t0] = {
.rtc_ops = &m41txx_rtc_ops,
},
@@ -1081,6 +1134,7 @@ static const struct i2c_device_id ds1307_id[] = {
{ "rx8025", rx_8025 },
{ "isl12057", ds_1337 },
{ "rx8130", rx_8130 },
+ { "rx8901", rx_8901 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);
@@ -1158,6 +1212,10 @@ static const struct of_device_id ds1307_of_match[] = {
.compatible = "epson,rx8130",
.data = (void *)rx_8130
},
+ {
+ .compatible = "epson,rx8901",
+ .data = (void *)rx_8901
+ },
{ }
};
MODULE_DEVICE_TABLE(of, ds1307_of_match);
--
2.43.0
Powered by blists - more mailing lists