diff mbox series

[1/3] rtc: cv1800: Add seconds counter support

Message ID 20261003-cv18xx-rtc-sysreset-v1-1-c0837e26eb29@zohomail.com
State Superseded
Delegated to: Tim Ouyang
Headers show
Series rtc: cv1800: Use the RTC node for time and system reset | expand

Commit Message

Zhuxu Ran Oct. 3, 2026, 11:55 a.m. UTC
Add a driver for the CV1800 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 <zhuxu_ran@zohomail.com>
---
 drivers/rtc/Kconfig      |   9 ++++
 drivers/rtc/Makefile     |   1 +
 drivers/rtc/rtc-cv1800.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+)

Comments

Hiago De Franco Oct. 3, 2026, 5:12 p.m. UTC | #1
Hi Zhuxu Ran,

On Sat, Oct 03, 2026 at 07:55:06PM +0800, Zhuxu Ran wrote:
> Add a driver for the CV1800 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 <zhuxu_ran@zohomail.com>

Overall on this patch I think it is better to have consistent names: the
driver file name is cv1800, but in other places like the config or the
driver name you call it cv1800b. It is better to choose one and stick to
it.

> ---
>  drivers/rtc/Kconfig      |   9 ++++
>  drivers/rtc/Makefile     |   1 +
>  drivers/rtc/rtc-cv1800.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 133 insertions(+)
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 5b44cc99c97..547ac1643c9 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 CV1800
> +	  series 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..961fe5409f0 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-cv1800.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-cv1800.c b/drivers/rtc/rtc-cv1800.c
> new file mode 100644
> index 00000000000..3a2b7b25748
> --- /dev/null
> +++ b/drivers/rtc/rtc-cv1800.c
> @@ -0,0 +1,123 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Zhuxu Ran <zhuxu_ran@zohomail.com>
> + *
> + * Based on the Linux driver by Jingbao Qiu <qiujingbao.dlmu@gmail.com>.
> + */
> +
> +#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 cv1800_rtc_priv {
> +	struct regmap *regmap;
> +	struct clk clk;
> +};
> +
> +static int cv1800_rtc_get(struct udevice *dev, struct rtc_time *time)
> +{
> +	struct cv1800_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 cv1800_rtc_set(struct udevice *dev, const struct rtc_time *time)
> +{
> +	struct cv1800_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 cv1800_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 cv1800_rtc_probe(struct udevice *dev)
> +{
> +	struct cv1800_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 cv1800_rtc_ops = {
> +	.get = cv1800_rtc_get,
> +	.set = cv1800_rtc_set,
> +};
> +
> +static const struct udevice_id cv1800_rtc_ids[] = {
> +	{ .compatible = "sophgo,cv1800b-rtc" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(cv1800b_rtc) = {
> +	.name = "cv1800b_rtc",
> +	.id = UCLASS_RTC,
> +	.of_match = cv1800_rtc_ids,
> +	.bind = cv1800_rtc_bind,
> +	.probe = cv1800_rtc_probe,
> +	.ops = &cv1800_rtc_ops,
> +	.priv_auto = sizeof(struct cv1800_rtc_priv),
> +};
> 
> -- 
> 2.55.0
> 

Best regards,
diff mbox series

Patch

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 5b44cc99c97..547ac1643c9 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 CV1800
+	  series 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..961fe5409f0 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-cv1800.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-cv1800.c b/drivers/rtc/rtc-cv1800.c
new file mode 100644
index 00000000000..3a2b7b25748
--- /dev/null
+++ b/drivers/rtc/rtc-cv1800.c
@@ -0,0 +1,123 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Zhuxu Ran <zhuxu_ran@zohomail.com>
+ *
+ * Based on the Linux driver by Jingbao Qiu <qiujingbao.dlmu@gmail.com>.
+ */
+
+#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 cv1800_rtc_priv {
+	struct regmap *regmap;
+	struct clk clk;
+};
+
+static int cv1800_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+	struct cv1800_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 cv1800_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+	struct cv1800_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 cv1800_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 cv1800_rtc_probe(struct udevice *dev)
+{
+	struct cv1800_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 cv1800_rtc_ops = {
+	.get = cv1800_rtc_get,
+	.set = cv1800_rtc_set,
+};
+
+static const struct udevice_id cv1800_rtc_ids[] = {
+	{ .compatible = "sophgo,cv1800b-rtc" },
+	{ }
+};
+
+U_BOOT_DRIVER(cv1800b_rtc) = {
+	.name = "cv1800b_rtc",
+	.id = UCLASS_RTC,
+	.of_match = cv1800_rtc_ids,
+	.bind = cv1800_rtc_bind,
+	.probe = cv1800_rtc_probe,
+	.ops = &cv1800_rtc_ops,
+	.priv_auto = sizeof(struct cv1800_rtc_priv),
+};