rtc: abx80x: add support for ABX81X

Abracon ABX81X is a family of RTCs with SPI interface featuring
the same functionalities as the ABX80X I2C clocks.

Signed-off-by: Antoni Pokusinski <apokusinski01@gmail.com>
Link: https://patch.msgid.link/20260916205138.16771-10-apokusinski01@gmail.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
Antoni Pokusinski 2026-09-16 22:51:38 +02:00 committed by Alexandre Belloni
parent 3fcf5a9795
commit 8a017ab984
2 changed files with 115 additions and 17 deletions

View File

@ -212,18 +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
select REGMAP_I2C
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
@ -955,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

View File

@ -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.
*
@ -19,6 +19,7 @@
#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
@ -109,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;
@ -123,10 +124,12 @@ 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}
};
@ -1076,14 +1079,107 @@ 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)
{
return abx80x_register_driver();
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);