Add a driver for the CV1800B RTC seconds counter described by the upstream devicetree. Map the node's register range, enable the RTC clock, and implement reading and setting the 32-bit counter. Bind the existing sysreset driver as a child when enabled.
Adapt the register definitions and seconds-counter sequence from Linux drivers/rtc/rtc-cv1800.c by Jingbao Qiu. Link: https://git.kernel.org/linus/d9f82683b123ce315cc36c4b20a5bc3d8644f947 Signed-off-by: Zhuxu Ran <[email protected]> --- drivers/rtc/Kconfig | 9 ++++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-cv1800b.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 5b44cc99c97..52d0e51acc3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -54,6 +54,15 @@ config RTC_ARMADA38X This adds support for the in-chip RTC that can be found in the Armada 38x Marvell's SoC devices. +config RTC_CV1800B + bool "Enable Sophgo CV1800B RTC driver" + depends on DM_RTC + select REGMAP + help + Enable access to the RTC seconds counter found on Sophgo CV1800B + SoCs. When system reset support is enabled, the driver also + binds the reset function provided by the RTC subsystem. + config RTC_PCF2127 bool "Enable PCF2127 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 742481ce185..53f704fe511 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_$(PHASE_)DM_RTC) += rtc-uclass.o obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o +obj-$(CONFIG_RTC_CV1800B) += rtc-cv1800b.o obj-$(CONFIG_RTC_DAVINCI) += davinci.o obj-$(CONFIG_RTC_DS1307) += ds1307.o obj-$(CONFIG_RTC_DS1337) += ds1337.o diff --git a/drivers/rtc/rtc-cv1800b.c b/drivers/rtc/rtc-cv1800b.c new file mode 100644 index 00000000000..e98efb319d7 --- /dev/null +++ b/drivers/rtc/rtc-cv1800b.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Zhuxu Ran <[email protected]> + * + * Based on the Linux driver by Jingbao Qiu <[email protected]>. + */ + +#include <clk.h> +#include <dm.h> +#include <dm/lists.h> +#include <regmap.h> +#include <rtc.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/err.h> + +#define SEC_PULSE_GEN 0x1004 +#define SET_SEC_CNTR_VAL 0x1010 +#define SET_SEC_CNTR_TRIG 0x1014 +#define SEC_CNTR_VAL 0x1018 +#define MACRO_RG_SET_T 0x1498 + +#define SEL_SEC_PULSE BIT(31) + +struct cv1800b_rtc_priv { + struct regmap *regmap; + struct clk clk; +}; + +static int cv1800b_rtc_get(struct udevice *dev, struct rtc_time *time) +{ + struct cv1800b_rtc_priv *priv = dev_get_priv(dev); + u32 value; + int ret; + + ret = regmap_read(priv->regmap, SEC_PULSE_GEN, &value); + if (ret) + return ret; + if (value & SEL_SEC_PULSE) + return -EINVAL; + + ret = regmap_read(priv->regmap, SEC_CNTR_VAL, &value); + if (ret) + return ret; + + rtc_to_tm(value, time); + + return 0; +} + +static int cv1800b_rtc_set(struct udevice *dev, const struct rtc_time *time) +{ + struct cv1800b_rtc_priv *priv = dev_get_priv(dev); + time64_t seconds; + int ret; + + if (time->tm_year < 1970) + return -EINVAL; + + seconds = rtc_mktime(time); + if (seconds < 0 || seconds > U32_MAX) + return -ERANGE; + + ret = regmap_write(priv->regmap, SET_SEC_CNTR_VAL, seconds); + if (ret) + return ret; + + ret = regmap_write(priv->regmap, SET_SEC_CNTR_TRIG, 1); + if (ret) + return ret; + + ret = regmap_write(priv->regmap, MACRO_RG_SET_T, seconds); + if (ret) + return ret; + + return regmap_update_bits(priv->regmap, SEC_PULSE_GEN, + SEL_SEC_PULSE, 0); +} + +static int cv1800b_rtc_bind(struct udevice *dev) +{ + if (!CONFIG_IS_ENABLED(SYSRESET_CV1800B)) + return 0; + + return device_bind_driver_to_node(dev, "cv1800b_sysreset", + "sysreset", dev_ofnode(dev), NULL); +} + +static int cv1800b_rtc_probe(struct udevice *dev) +{ + struct cv1800b_rtc_priv *priv = dev_get_priv(dev); + int ret; + + priv->regmap = devm_regmap_init(dev, NULL, NULL, NULL); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + ret = clk_get_by_name(dev, "rtc", &priv->clk); + if (ret) + return ret; + + return clk_enable(&priv->clk); +} + +static const struct rtc_ops cv1800b_rtc_ops = { + .get = cv1800b_rtc_get, + .set = cv1800b_rtc_set, +}; + +static const struct udevice_id cv1800b_rtc_ids[] = { + { .compatible = "sophgo,cv1800b-rtc" }, + { } +}; + +U_BOOT_DRIVER(cv1800b_rtc) = { + .name = "cv1800b_rtc", + .id = UCLASS_RTC, + .of_match = cv1800b_rtc_ids, + .bind = cv1800b_rtc_bind, + .probe = cv1800b_rtc_probe, + .ops = &cv1800b_rtc_ops, + .priv_auto = sizeof(struct cv1800b_rtc_priv), +}; -- 2.55.0
