Linux RTC
 help / color / mirror / Atom feed
* [PATCH v3 5/6] rtc: m41t93: Add square wave clock provider support
From: Akhilesh Patil @ 2025-09-20 15:03 UTC (permalink / raw)
  To: alexandre.belloni, krzk+dt, robh, conor+dt
  Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <cover.1758379856.git.akhilesh@ee.iitb.ac.in>

Implement support to configure square wave output (SQW) of m41t93 rtc
via common clock framework clock provider api. Add clock provider
callbacks to control output frequency ranging from 1Hz to 32KHz as
supported by this rtc chip.

Use clock framework debugfs interface or clock consumer DT node to test.
Tested by measuring various frequencies on pull-up connected SWQ(7) pin
of m41t93 rtc chip using logic analyzer.

Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
 drivers/rtc/rtc-m41t93.c | 156 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 155 insertions(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index b86e7a12eba6..46703e32f212 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -13,6 +13,7 @@
 #include <linux/rtc.h>
 #include <linux/spi/spi.h>
 #include <linux/regmap.h>
+#include <linux/clk-provider.h>
 
 #define M41T93_REG_SSEC			0
 #define M41T93_REG_ST_SEC		1
@@ -30,7 +31,11 @@
 #define M41T93_BIT_A1IE                 BIT(7)
 #define M41T93_BIT_ABE                  BIT(5)
 #define M41T93_FLAG_AF1                 BIT(6)
-
+#define M41T93_SRAM_BASE		0x19
+#define M41T93_REG_SQW			0x13
+#define M41T93_SQW_RS_MASK		0xf0
+#define M41T93_SQW_RS_SHIFT		4
+#define M41T93_BIT_SQWE                 BIT(6)
 
 #define M41T93_REG_ALM_HOUR_HT		0xc
 #define M41T93_REG_FLAGS		0xf
@@ -43,6 +48,9 @@
 struct m41t93_data {
 	struct rtc_device *rtc;
 	struct regmap *regmap;
+#ifdef CONFIG_COMMON_CLK
+	struct clk_hw clks;
+#endif
 };
 
 static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
@@ -264,6 +272,146 @@ static const struct rtc_class_ops m41t93_rtc_ops = {
 	.alarm_irq_enable = m41t93_alarm_irq_enable,
 };
 
+#ifdef CONFIG_COMMON_CLK
+#define clk_sqw_to_m41t93_data(clk)	\
+	container_of(clk, struct m41t93_data, clks)
+
+/* m41t93 RTC clock output support */
+static unsigned long m41t93_clk_rates[] = {
+	0,
+	32768, /* RS3:RS0 = 0b0001 */
+	8192,
+	4096,
+	2048,
+	1024,
+	512,
+	256,
+	128,
+	64,
+	32,
+	16,
+	8,
+	4,
+	2,
+	1, /* RS3:RS0 = 0b1111 */
+};
+
+static unsigned long m41t93_clk_sqw_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	int ret;
+	unsigned int rate_id;
+	struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+	ret = regmap_read(m41t93->regmap, M41T93_REG_SQW, &rate_id);
+	if (ret)
+		return ret;
+
+	rate_id &= M41T93_SQW_RS_MASK;
+	rate_id >>= M41T93_SQW_RS_SHIFT;
+
+	return m41t93_clk_rates[rate_id];
+}
+
+static int m41t93_clk_sqw_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req)
+{
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(m41t93_clk_rates); i++) {
+		if (req->rate >= m41t93_clk_rates[i]) {
+			req->rate = m41t93_clk_rates[i];
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int m41t93_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	int id, ret;
+	struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+	for (id = 0; id < ARRAY_SIZE(m41t93_clk_rates); id++) {
+		if (m41t93_clk_rates[id] == rate)
+			break;
+	}
+
+	if (id >= ARRAY_SIZE(m41t93_clk_rates))
+		return -EINVAL;
+
+	ret = regmap_update_bits(m41t93->regmap, M41T93_REG_SQW,
+				 M41T93_SQW_RS_MASK, id << M41T93_SQW_RS_SHIFT);
+
+	return ret;
+}
+
+static int m41t93_clk_sqw_prepare(struct clk_hw *hw)
+{
+	int ret;
+	struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+	ret = regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+				 M41T93_BIT_SQWE, M41T93_BIT_SQWE);
+
+	return ret;
+}
+
+static void m41t93_clk_sqw_unprepare(struct clk_hw *hw)
+{
+	struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+	regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+			   M41T93_BIT_SQWE, 0);
+}
+
+static int m41t93_clk_sqw_is_prepared(struct clk_hw *hw)
+{
+	int ret;
+	struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+	unsigned int status;
+
+	ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &status);
+	if (ret)
+		return ret;
+
+	return !!(status & M41T93_BIT_SQWE);
+}
+
+static const struct clk_ops m41t93_clk_sqw_ops = {
+	.prepare = m41t93_clk_sqw_prepare,
+	.unprepare = m41t93_clk_sqw_unprepare,
+	.is_prepared = m41t93_clk_sqw_is_prepared,
+	.recalc_rate = m41t93_clk_sqw_recalc_rate,
+	.set_rate = m41t93_clk_sqw_set_rate,
+	.determine_rate = m41t93_clk_sqw_determine_rate,
+};
+
+static int rtc_m41t93_clks_register(struct device *dev, struct m41t93_data *m41t93)
+{
+	struct device_node *node = dev->of_node;
+	struct clk *clk;
+	struct clk_init_data init = {0};
+
+	init.name = "m41t93_clk_sqw";
+	init.ops = &m41t93_clk_sqw_ops;
+
+	m41t93->clks.init = &init;
+
+	/* Register the clock with CCF */
+	clk = devm_clk_register(dev, &m41t93->clks);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	if (node)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	return 0;
+}
+#endif
+
 static struct spi_driver m41t93_driver;
 
 static const struct regmap_config regmap_config = {
@@ -312,6 +460,12 @@ static int m41t93_probe(struct spi_device *spi)
 	if (IS_ERR(m41t93->rtc))
 		return PTR_ERR(m41t93->rtc);
 
+#ifdef CONFIG_COMMON_CLK
+	ret = rtc_m41t93_clks_register(&spi->dev, m41t93);
+	if (ret)
+		dev_warn(&spi->dev, "Unable to register clock\n");
+#endif
+
 	return 0;
 }
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 4/6] rtc: m41t93: Add alarm support
From: Akhilesh Patil @ 2025-09-20 15:02 UTC (permalink / raw)
  To: alexandre.belloni, krzk+dt, robh, conor+dt
  Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <cover.1758379856.git.akhilesh@ee.iitb.ac.in>

Implement alarm feature for rtc-m41t93 by adding necessary
callbacks - set_alarm, read_alarm and alarm_irq_enable.
Enable support to configure alarm 1 out of 2 alarms present in this rtc.
Support only alarm configuration in this commit. This commit does not
implement alarm irq handling.

Use selftests/rtc/rtctest for testing. Tested by observing IRQ pin
(pin 12 of SOX18 package) on logic analyzer going low after alarm
condition is met.

Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
 drivers/rtc/rtc-m41t93.c | 105 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index ad862bf706b6..b86e7a12eba6 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -22,6 +22,14 @@
 #define M41T93_REG_DAY			5
 #define M41T93_REG_MON			6
 #define M41T93_REG_YEAR			7
+#define M41T93_REG_AL1_MONTH		0xa
+#define M41T93_REG_AL1_DATE		0xb
+#define M41T93_REG_AL1_HOUR		0xc
+#define M41T93_REG_AL1_MIN		0xd
+#define M41T93_REG_AL1_SEC		0xe
+#define M41T93_BIT_A1IE                 BIT(7)
+#define M41T93_BIT_ABE                  BIT(5)
+#define M41T93_FLAG_AF1                 BIT(6)
 
 
 #define M41T93_REG_ALM_HOUR_HT		0xc
@@ -153,10 +161,107 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
 	return ret;
 }
 
+static int m41t93_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+	int ret;
+	unsigned int val;
+	u8 alarm_vals[5] = {0};
+
+	ret = regmap_bulk_write(m41t93->regmap, M41T93_REG_AL1_DATE, alarm_vals, 4);
+	if (ret)
+		return ret;
+
+	/* Set alarm values */
+	alarm_vals[0] = bin2bcd(alrm->time.tm_mon + 1) & 0x1f;
+	alarm_vals[1] = bin2bcd(alrm->time.tm_mday) & 0x3f;
+	alarm_vals[2] = bin2bcd(alrm->time.tm_hour) & 0x3f;
+	alarm_vals[3] = bin2bcd(alrm->time.tm_min) & 0x7f;
+	alarm_vals[4] = bin2bcd(alrm->time.tm_sec) & 0x7f;
+
+	if (alrm->enabled) {
+		/* Enable alarm IRQ generation */
+		alarm_vals[0] |= M41T93_BIT_A1IE | M41T93_BIT_ABE;
+	}
+
+	/* Preserve SQWE bit */
+	ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &val);
+	if (ret)
+		return ret;
+
+	alarm_vals[0] |= val & 0x40;
+
+	ret = regmap_bulk_write(m41t93->regmap, M41T93_REG_AL1_MONTH,
+				alarm_vals, sizeof(alarm_vals));
+	if (ret)
+		return ret;
+
+	/* Device address pointer is now at FLAG register, move it to other location
+	 * to finish setting alarm, as recommended by the datasheet.
+	 * We do read of AL1_MONTH register to achieve this.
+	 */
+	ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &val);
+	if (ret)
+		return ret;
+
+	if (bcd2bin(val & 0x1f) == (alrm->time.tm_mon & 0x1f))
+		dev_notice(dev, "Alarm set successfully\n");
+
+	return 0;
+}
+
+static int m41t93_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+	int ret;
+	unsigned int val;
+	u8 alarm_vals[5] = {0};
+
+	ret = regmap_bulk_read(m41t93->regmap, M41T93_REG_AL1_MONTH,
+			       alarm_vals, sizeof(alarm_vals));
+	if (ret)
+		return ret;
+
+	alrm->time.tm_mon = bcd2bin(alarm_vals[0] & 0x1f) - 1;
+	alrm->time.tm_mday = bcd2bin(alarm_vals[1] & 0x3f);
+	alrm->time.tm_hour = bcd2bin(alarm_vals[2] & 0x3f);
+	alrm->time.tm_min = bcd2bin(alarm_vals[3] & 0x7f);
+	alrm->time.tm_sec = bcd2bin(alarm_vals[4] & 0x7f);
+
+	alrm->enabled =  !!(alarm_vals[0] & M41T93_BIT_A1IE);
+
+	ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &val);
+	if (ret)
+		return ret;
+
+	alrm->pending = (val & M41T93_FLAG_AF1) && alrm->enabled;
+
+	return 0;
+}
+
+static int m41t93_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+	unsigned int val;
+	int ret;
+
+	val = enabled ? M41T93_BIT_A1IE | M41T93_BIT_ABE : 0;
+
+	ret = regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+				 M41T93_BIT_A1IE | M41T93_BIT_ABE, val);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 
 static const struct rtc_class_ops m41t93_rtc_ops = {
 	.read_time	= m41t93_get_time,
 	.set_time	= m41t93_set_time,
+	.set_alarm	= m41t93_set_alarm,
+	.read_alarm	= m41t93_get_alarm,
+	.alarm_irq_enable = m41t93_alarm_irq_enable,
 };
 
 static struct spi_driver m41t93_driver;
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 3/6] rtc: m41t93: migrate to regmap api for register access
From: Akhilesh Patil @ 2025-09-20 15:02 UTC (permalink / raw)
  To: alexandre.belloni, krzk+dt, robh, conor+dt
  Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <cover.1758379856.git.akhilesh@ee.iitb.ac.in>

Adapt driver to use regmap api with spi bus instead of direct spi
subsystem calls to access device registers. Simplify and standardize the
register interactions using more abstract and bus agnostic regmap api
to reduce code duplication and improve maintainability. Define spi regmap
config suitable for m41t93 spi bus protocol to achieve same transactions on
spi bus.

Tested on TI am62x sk board with m41t93 rtc chip connected over spi0.
Validated set and get time using hwclock tool and verified spi bus
transfers using logic analyzer.

Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
 drivers/rtc/rtc-m41t93.c | 121 ++++++++++++++++++++++-----------------
 1 file changed, 70 insertions(+), 51 deletions(-)

diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index 4e803ff0ce49..ad862bf706b6 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
 
 #define M41T93_REG_SSEC			0
 #define M41T93_REG_ST_SEC		1
@@ -31,23 +32,17 @@
 #define M41T93_FLAG_BL			(1 << 4)
 #define M41T93_FLAG_HT			(1 << 6)
 
-static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
-{
-	u8 buf[2];
-
-	/* MSB must be '1' to write */
-	buf[0] = addr | 0x80;
-	buf[1] = data;
-
-	return spi_write(spi, buf, sizeof(buf));
-}
+struct m41t93_data {
+	struct rtc_device *rtc;
+	struct regmap *regmap;
+};
 
 static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
 {
-	struct spi_device *spi = to_spi_device(dev);
-	int tmp;
-	u8 buf[9] = {0x80};        /* write cmd + 8 data bytes */
-	u8 * const data = &buf[1]; /* ptr to first data byte */
+	struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+	int tmp, ret;
+	u8 buf[8] = {0};        /* 8 data bytes */
+	u8 * const data = &buf[0]; /* ptr to first data byte */
 
 	dev_dbg(dev, "%s secs=%d, mins=%d, "
 		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -56,31 +51,31 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
 		tm->tm_mon, tm->tm_year, tm->tm_wday);
 
 	if (tm->tm_year < 100) {
-		dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n");
+		dev_warn(dev, "unsupported date (before 2000-01-01).\n");
 		return -EINVAL;
 	}
 
-	tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
-	if (tmp < 0)
-		return tmp;
+	ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
+	if (ret < 0)
+		return ret;
 
 	if (tmp & M41T93_FLAG_OF) {
-		dev_warn(&spi->dev, "OF bit is set, resetting.\n");
-		m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
+		dev_warn(dev, "OF bit is set, resetting.\n");
+		regmap_write(m41t93->regmap, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
 
-		tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
-		if (tmp < 0) {
-			return tmp;
+		ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
+		if (ret < 0) {
+			return ret;
 		} else if (tmp & M41T93_FLAG_OF) {
 			/* OF cannot be immediately reset: oscillator has to be
 			 * restarted. */
 			u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
 
-			dev_warn(&spi->dev,
+			dev_warn(dev,
 				 "OF bit is still set, kickstarting clock.\n");
-			m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+			regmap_write(m41t93->regmap, M41T93_REG_ST_SEC, reset_osc);
 			reset_osc &= ~M41T93_FLAG_ST;
-			m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+			regmap_write(m41t93->regmap, M41T93_REG_ST_SEC, reset_osc);
 		}
 	}
 
@@ -94,14 +89,13 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
 	data[M41T93_REG_MON]		= bin2bcd(tm->tm_mon + 1);
 	data[M41T93_REG_YEAR]		= bin2bcd(tm->tm_year % 100);
 
-	return spi_write(spi, buf, sizeof(buf));
+	return regmap_bulk_write(m41t93->regmap, M41T93_REG_SSEC, buf, sizeof(buf));
 }
 
 
 static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
 {
-	struct spi_device *spi = to_spi_device(dev);
-	const u8 start_addr = 0;
+	struct m41t93_data *m41t93 = dev_get_drvdata(dev);
 	u8 buf[8];
 	int century_after_1900;
 	int tmp;
@@ -113,32 +107,32 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
 	      case after poweron. Time is valid after resetting HT bit.
 	   2. oscillator fail bit (OF) is set: time is invalid.
 	*/
-	tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
-	if (tmp < 0)
-		return tmp;
+	ret = regmap_read(m41t93->regmap, M41T93_REG_ALM_HOUR_HT, &tmp);
+	if (ret < 0)
+		return ret;
 
 	if (tmp & M41T93_FLAG_HT) {
-		dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n");
-		m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT,
-			       tmp & ~M41T93_FLAG_HT);
+		dev_dbg(dev, "HT bit is set, reenable clock update.\n");
+		regmap_write(m41t93->regmap, M41T93_REG_ALM_HOUR_HT,
+			     tmp & ~M41T93_FLAG_HT);
 	}
 
-	tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
-	if (tmp < 0)
-		return tmp;
+	ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
+	if (ret < 0)
+		return ret;
 
 	if (tmp & M41T93_FLAG_OF) {
 		ret = -EINVAL;
-		dev_warn(&spi->dev, "OF bit is set, write time to restart.\n");
+		dev_warn(dev, "OF bit is set, write time to restart.\n");
 	}
 
 	if (tmp & M41T93_FLAG_BL)
-		dev_warn(&spi->dev, "BL bit is set, replace battery.\n");
+		dev_warn(dev, "BL bit is set, replace battery.\n");
 
 	/* read actual time/date */
-	tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf));
-	if (tmp < 0)
-		return tmp;
+	ret = regmap_bulk_read(m41t93->regmap, M41T93_REG_SSEC, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
 
 	tm->tm_sec	= bcd2bin(buf[M41T93_REG_ST_SEC]);
 	tm->tm_min	= bcd2bin(buf[M41T93_REG_MIN]);
@@ -167,26 +161,51 @@ static const struct rtc_class_ops m41t93_rtc_ops = {
 
 static struct spi_driver m41t93_driver;
 
+static const struct regmap_config regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.read_flag_mask = 0x00,
+	.write_flag_mask = 0x80,
+	.zero_flag_mask = true,
+};
+
 static int m41t93_probe(struct spi_device *spi)
 {
-	struct rtc_device *rtc;
-	int res;
+	int res, ret;
+	struct m41t93_data *m41t93;
 
 	spi->bits_per_word = 8;
 	spi_setup(spi);
 
-	res = spi_w8r8(spi, M41T93_REG_WDAY);
+	m41t93 = devm_kzalloc(&spi->dev, sizeof(struct m41t93_data), GFP_KERNEL);
+
+	if (!m41t93)
+		return -ENOMEM;
+
+	/* Set up regmap to access device registers*/
+	m41t93->regmap = devm_regmap_init_spi(spi, &regmap_config);
+	if (IS_ERR(m41t93->regmap)) {
+		dev_err(&spi->dev, "regmap init failure\n");
+		return PTR_ERR(m41t93->regmap);
+	}
+
+	ret = regmap_read(m41t93->regmap, M41T93_REG_WDAY, &res);
+	if (ret < 0) {
+		dev_err(&spi->dev, "IO error\n");
+		return -EIO;
+	}
+
 	if (res < 0 || (res & 0xf8) != 0) {
 		dev_err(&spi->dev, "not found 0x%x.\n", res);
 		return -ENODEV;
 	}
 
-	rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
-					&m41t93_rtc_ops, THIS_MODULE);
-	if (IS_ERR(rtc))
-		return PTR_ERR(rtc);
+	spi_set_drvdata(spi, m41t93);
 
-	spi_set_drvdata(spi, rtc);
+	m41t93->rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
+					&m41t93_rtc_ops, THIS_MODULE);
+	if (IS_ERR(m41t93->rtc))
+		return PTR_ERR(m41t93->rtc);
 
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 2/6] rtc: m41t93: add device tree support
From: Akhilesh Patil @ 2025-09-20 15:01 UTC (permalink / raw)
  To: alexandre.belloni, krzk+dt, robh, conor+dt
  Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <cover.1758379856.git.akhilesh@ee.iitb.ac.in>

Add device tree support for m41t93 rtc by adding of_match_table.
Define compatible string - "st,m41t93" which can be used to instantiate
this rtc device via DT node.

Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
 drivers/rtc/rtc-m41t93.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index 9444cb5f5190..4e803ff0ce49 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -191,9 +191,16 @@ static int m41t93_probe(struct spi_device *spi)
 	return 0;
 }
 
+static const struct of_device_id m41t93_dt_match[] = {
+	{ .compatible = "st,m41t93" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, m41t93_dt_match);
+
 static struct spi_driver m41t93_driver = {
 	.driver = {
 		.name	= "rtc-m41t93",
+		.of_match_table = m41t93_dt_match,
 	},
 	.probe	= m41t93_probe,
 };
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 1/6] dt-bindings: rtc: Add ST m41t93
From: Akhilesh Patil @ 2025-09-20 15:01 UTC (permalink / raw)
  To: alexandre.belloni, krzk+dt, robh, conor+dt
  Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <cover.1758379856.git.akhilesh@ee.iitb.ac.in>

Document DT bindings for m41t93 rtc which supports time, date,
alarm, watchdog, square wave clock output provider, user sram
and 8 bit timer.

Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
 .../devicetree/bindings/rtc/st,m41t93.yaml    | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/st,m41t93.yaml

diff --git a/Documentation/devicetree/bindings/rtc/st,m41t93.yaml b/Documentation/devicetree/bindings/rtc/st,m41t93.yaml
new file mode 100644
index 000000000000..bdd995c5c1f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/st,m41t93.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/st,m41t93.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ST M41T93 RTC and compatible
+
+maintainers:
+  - Akhilesh Patil <akhilesh@ee.iitb.ac.in>
+
+description:
+  ST M41T93 is spi based Real Time Clock (RTC) with time, date,
+  alarm, watchdog, square wave clock output, 8 bit timer and
+  7 bytes of user SRAM.
+
+properties:
+  compatible:
+    enum:
+      - st,m41t93
+
+  reg:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: rtc.yaml
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      rtc@0 {
+        compatible = "st,m41t93";
+        reg = <0>;
+        #clock-cells = <0>;
+        spi-max-frequency = <2000000>;
+      };
+    };
+
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 0/6] rtc: m41t93: add new features alarm, clock out, watchdog
From: Akhilesh Patil @ 2025-09-20 15:00 UTC (permalink / raw)
  To: alexandre.belloni, krzk+dt, robh, conor+dt
  Cc: skhan, linux-rtc, devicetree, linux-kernel, akhileshpatilvnit

This patch series adds following to m41t93 rtc driver.

Functionalities: 
- Alarm support (support to configure alarm 1)
- Square wave output support
- Watchdog support

Code improvements:
this series migrates existing driver to use standard regmap interface
for spi instead of direct spi calls and uses regmap for new features.

Device tree support:
Adds device tree support to the driver along with binding documentation.

Testing:
This patch series is validated on TI am62x board with m41t93 rtc chip
connected to spi0 bus.
regmap migration is additionally tested by observing spi transfers
with the help of logic analyzer. Short summary of test flow is added in
commit message of respective features.

Datasheet:
https://www.st.com/resource/en/datasheet/m41t93.pdf

patch 4 to 6 depend on patch 3 (regmap patch)

Signed-off-by: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
---
Changes in v3:
- Address comments on bindings from Krzysztof and add myself
as a maintainer.
- Re-validation/testing on top of v6.17-rc6
- Link to v2: https://lore.kernel.org/lkml/cover.1757510157.git.akhilesh@ee.iitb.ac.in/

Changes in v2:
- Address DTS and bindings coding style feedback from Krzysztof
- Verify bindings using $ make dt_binding_check 
- Update example in binding documentation after testing.
- Analyze and Fix build warnings as suggested by kernel test robot.
- Drop patch 5 from series (device detect logic change).
  This will be taken separately. Focus on functionalities in this series.
- Update commit messages with short test steps for each feature.
- Link to v1: https://lore.kernel.org/lkml/cover.1756908788.git.akhilesh@ee.iitb.ac.in/
---

Akhilesh Patil (6):
  dt-bindings: rtc: Add ST m41t93
  rtc: m41t93: add device tree support
  rtc: m41t93: migrate to regmap api for register access
  rtc: m41t93: Add alarm support
  rtc: m41t93: Add square wave clock provider support
  rtc: m41t93: Add watchdog support

 .../devicetree/bindings/rtc/st,m41t93.yaml    |  50 ++
 drivers/rtc/rtc-m41t93.c                      | 488 ++++++++++++++++--
 2 files changed, 486 insertions(+), 52 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/rtc/st,m41t93.yaml

-- 
2.34.1


^ permalink raw reply

* Re: [PATCH v2 1/6] dt-bindings: rtc: Add ST m41t93
From: Akhilesh Patil @ 2025-09-20 14:47 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: alexandre.belloni, krzk+dt, robh, conor+dt, skhan, linux-rtc,
	devicetree, linux-kernel, akhileshpatilvnit
In-Reply-To: <85a46710-64ee-4a21-b95c-d4c18c2f634f@kernel.org>

On Wed, Sep 17, 2025 at 09:52:24AM +0900, Krzysztof Kozlowski wrote:
> On 15/09/2025 16:19, Akhilesh Patil wrote:
> >>> +$id: http://devicetree.org/schemas/rtc/st,m41t93.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: ST M41T93 RTC and compatible
> >>> +
> >>> +maintainers:
> >>> +  - linux-rtc@vger.kernel.org
> >>
> >> Not much improved. This should be a person responsible/caring about this
> >> hardware support in the kernel. Why would we want to take the binding if
> >> no one cares about it?
> > 
> > Okay. As per get_maintainer.pl, linux driver corresponding to this binding does not have a dedicated
> > maintainer, hence it shows rtc subsystem maintainer (Alexandre Belloni).
> 
> And what did I express at v1?
> 
> > Looking forward for your suggestion here.
> > What do you suggest to keep maintainer as Rob Herring or/and me ? as I see in
> > such cases Rob is the maintainer.
> 
> No, I really doubt Rob cares about this particular hardware. Neither do
> I, nor Conor.

okay.
I have this rtc hardware with me and I am willing to own and maintain
this support in the kernel.
Hence I will add myself as a maintainer for this binding and share v3.

Regards,
Akhilesh

> 
> 
> Best regards,
> Krzysztof

^ permalink raw reply

* Re: [PATCH 05/25] dt-bindings: rtc: Add RDA Micro RDA8810PL RTC
From: Dang Huynh @ 2025-09-20  6:49 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Linus Walleij, Bartosz Golaszewski,
	Alexandre Belloni, Michael Turquette, Stephen Boyd, Philipp Zabel,
	Sebastian Reichel, Vinod Koul, Kees Cook, Gustavo A. R. Silva,
	Ulf Hansson, linux-arm-kernel, linux-unisoc, devicetree,
	linux-kernel, linux-gpio, linux-rtc, linux-clk, linux-pm,
	dmaengine, linux-hardening, linux-mmc
In-Reply-To: <20250918-unharmed-bloating-8b573513fce6@spud>

On Thu, Sep 18, 2025 at 04:18:25PM +0100, Conor Dooley wrote:
> On Thu, Sep 18, 2025 at 11:11:10AM +0700, Dang Huynh wrote:
> > On 2025-09-18 03:46, Conor Dooley wrote:
> > > On Wed, Sep 17, 2025 at 03:07:22AM +0700, Dang Huynh wrote:
> > > > Add documentation describing the RTC found in RDA8810PL SoC.
> > > > 
> > > > Signed-off-by: Dang Huynh <dang.huynh@mainlining.org>
> > > > ---
> > > >  .../devicetree/bindings/rtc/rda,8810pl-rtc.yaml    | 30
> > > > ++++++++++++++++++++++
> > > >  1 file changed, 30 insertions(+)
> > > > 
> > > > diff --git
> > > > a/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
> > > > b/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
> > > > new file mode 100644
> > > > index 0000000000000000000000000000000000000000..3ceae294921cc3211cd775d9b3890393196faf82
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
> > > > @@ -0,0 +1,30 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/rtc/rda,8810pl-rtc.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: RDA Micro RDA8810PL Real Time Clock
> > > > +
> > > > +maintainers:
> > > > +  - Dang Huynh <dang.huynh@mainlining.org>
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    const: rda,8810pl-rtc
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +required:
> > > > +  - compatible
> > > > +  - reg
> > > 
> > > Your driver implements functions that turn on an alarm irq, but there is
> > > none mentioned here. What's going on there?
> > The RTC doesn't seem to have an AP IRQ associated. I can't find any
> > reference to it on downstream kernel and the docs.
> > 
> > > 
> > > Additionally, there's no clocks property? For an onboard RTC I'd have
> > > expected there to be a clock sourced outside of the block.
> 
> What about the clock?
I'll fix this in v2.

> 
> > > 
> > > > +
> > > > +additionalProperties: false
> > > > +
> > > > +examples:
> > > > +  - |
> > > > +    rtc@1a06000 {
> > > > +      compatible = "rda,8810pl-rtc";
> > > > +      reg = <0x1a06000 0x1000>;
> > > > +    };
> > > > 
> > > > --
> > > > 2.51.0



^ permalink raw reply

* Re: [PATCH 10/25] drivers: clk: Add Clock and Reset Driver for RDA Micro RDA8810PL SoC
From: Stephen Boyd @ 2025-09-20  4:50 UTC (permalink / raw)
  To: Alexandre Belloni, Bartosz Golaszewski, Conor Dooley,
	Dang Huynh via B4 Relay, Gustavo A. R. Silva, Kees Cook,
	Krzysztof Kozlowski, Linus Walleij, Manivannan Sadhasivam,
	Michael Turquette, Philipp Zabel, Rob Herring, Sebastian Reichel,
	Ulf Hansson, Vinod Koul, dang.huynh
  Cc: linux-arm-kernel, linux-unisoc, devicetree, linux-kernel,
	linux-gpio, linux-rtc, linux-clk, linux-pm, dmaengine,
	linux-hardening, linux-mmc, Dang Huynh
In-Reply-To: <20250917-rda8810pl-drivers-v1-10-9ca9184ca977@mainlining.org>

Quoting Dang Huynh via B4 Relay (2025-09-16 13:25:07)
> diff --git a/drivers/clk/rda/Kconfig b/drivers/clk/rda/Kconfig
> new file mode 100644
> index 0000000000000000000000000000000000000000..b505e3e552cef1e7ea3da4aa46d61d0d0a3d5db0
> --- /dev/null
> +++ b/drivers/clk/rda/Kconfig
> @@ -0,0 +1,14 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config CLK_RDA8810
> +       bool "RDA Micro RDA8810PL Clock and Reset Controller"

Can it be tristate?

> +       depends on ARCH_RDA || COMPILE_TEST
> +       select MFD_SYSCON
> +       select REGMAP_MMIO
> +       select RESET_CONTROLLER
> +       help
> +         This driver supports clock and reset for RDA Micro RDA8810 platform.
> +         If you have a board with the RDA8810PL SoC, say Y to use most of the
> +         board peripherals.
> +
> +         If unsure, say N.
> +
> new file mode 100644
> index 0000000000000000000000000000000000000000..8bea60d5376aeb4c67cd15bc1a64dbcf7a0a1f7c
> --- /dev/null
> +++ b/drivers/clk/rda/clk-rda8810.c
> @@ -0,0 +1,770 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * RDA8810PL Clock and Reset driver
> + *
> + * Copyright (C) 2013 RDA Microelectronics Inc.
> + * Copyright (c) 2025 Dang Huynh <dang.huynh@mainlining.org>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>

Is this used?

> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>

Is this used?

> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/reset-controller.h>
> +#include <dt-bindings/clock/rda,8810pl-apclk.h>
> +
> +#define MHZ 1000000U
> +
> +/*
> + * Some registers are protected, we need to write AP_CTRL_PROTECT_UNLOCK to
> + * AP_REG_DBG then we can make changes to them.
> + */
> +#define AP_CTRL_PROTECT_LOCK   0xA50000
> +#define AP_CTRL_PROTECT_UNLOCK 0xA50001

Lowercase hex please. I don't see these used though so what's going on?

> +
> +/* Register Base */
> +#define AP_REG_DBG 0x0
> +#define AP_REG_CPU_ENABLE 0x60
> +#define AP_REG_AXI_ENABLE 0x6C
> +#define AP_REG_AXIDIV2_ENABLE 0x78
> +#define AP_REG_GCG_ENABLE 0x84
> +#define AP_REG_AHB1_ENABLE 0x90
> +#define AP_REG_APB1_ENABLE 0x9C
> +#define AP_REG_APB2_ENABLE 0xA8
> +#define AP_REG_MEM_ENABLE 0xB4
> +#define AP_REG_APO_ENABLE 0xC0
> +
> +/* AP Clk Config Bits */
> +#define AP_PERI_SRC_DIV BIT(12)
> +
> +/* UART Clock Bits */
> +#define AP_UART_DIVIDER GENMASK(9, 0)
> +#define AP_UART_SET_PLL BIT(12)
> +
> +/* AP Clk Enable */
> +#define AP_ENABLE_CPU_CORE BIT(0)
> +#define AP_ENABLE_CPU_DUMMY BIT(1)
> +#define AP_ENABLE_AHB0_CONF BIT(0)
> +#define AP_ENABLE_APB0_CONF BIT(1)
> +#define AP_ENABLE_AXI_VOC  BIT(2)
> +#define AP_ENABLE_AXI_DMA  BIT(3)
> +#define AP_ENABLE_AXI_ALWAYS BIT(4)
> +#define AP_ENABLE_AXI_CONNECT BIT(5)
> +#define AP_ENABLE_APB0_IRQ BIT(6)
> +#define AP_ENABLE_AXIDIV2_IMEM BIT(0)
> +#define AP_ENABLE_AXIDIV2_ALWAYS BIT(1)
> +#define AP_ENABLE_AXIDIV2_CONNECT BIT(2)
> +#define AP_ENABLE_AXIDIV2_VPU BIT(3)
> +#define AP_ENABLE_GCG_APB_CONF BIT(0)
> +#define AP_ENABLE_GCG_GOUDA BIT(1)
> +#define AP_ENABLE_GCG_CAMERA BIT(2)
> +#define AP_ENABLE_GCG_ALWAYS BIT(3)
> +#define AP_ENABLE_GCG_CONNECT BIT(4)
> +#define AP_ENABLE_GCG_DPI BIT(7)
> +#define AP_ENABLE_AHB1_USBC BIT(0)
> +#define AP_ENABLE_AHB1_ALWAYS BIT(1)
> +#define AP_ENABLE_AHB1_SPIFLASH BIT(2)
> +#define AP_ENABLE_APB1_CONF BIT(0)
> +#define AP_ENABLE_APB1_AIF BIT(1)
> +#define AP_ENABLE_APB1_AUIFC BIT(2)
> +#define AP_ENABLE_APB1_AUIFC_CH0 BIT(3)
> +#define AP_ENABLE_APB1_AUIFC_CH1 BIT(4)
> +#define AP_ENABLE_APB1_I2C1 BIT(5)
> +#define AP_ENABLE_APB1_I2C2 BIT(6)
> +#define AP_ENABLE_APB1_I2C3 BIT(7)
> +#define AP_ENABLE_APB1D_OSC BIT(8)
> +#define AP_ENABLE_APB1D_PWM BIT(9)
> +#define AP_ENABLE_APB1_ALWAYS BIT(10)
> +#define AP_ENABLE_APB1_DAPLITE BIT(11)
> +#define AP_ENABLE_APB1_TIMER BIT(12)
> +#define AP_ENABLE_APB1_GPIO BIT(13)
> +#define AP_ENABLE_APB2_CONF BIT(0)
> +#define AP_ENABLE_APB2_IFC BIT(1)
> +#define AP_ENABLE_APB2_IFC_CH0 BIT(2)
> +#define AP_ENABLE_APB2_IFC_CH1 BIT(3)
> +#define AP_ENABLE_APB2_IFC_CH2 BIT(4)
> +#define AP_ENABLE_APB2_IFC_CH3 BIT(5)
> +#define AP_ENABLE_APB2_IFC_CH4 BIT(6)
> +#define AP_ENABLE_APB2_IFC_CH5 BIT(7)
> +#define AP_ENABLE_APB2_IFC_CH6 BIT(8)
> +#define AP_ENABLE_APB2_IFC_CH7 BIT(9)
> +#define AP_ENABLE_APB2_UART1 BIT(10)
> +#define AP_ENABLE_APB2_UART2 BIT(11)
> +#define AP_ENABLE_APB2_UART3 BIT(12)
> +#define AP_ENABLE_APB2_SPI1 BIT(13)
> +#define AP_ENABLE_APB2_SPI2 BIT(14)
> +#define AP_ENABLE_APB2_SPI3 BIT(15)
> +#define AP_ENABLE_APB2_SDMMC1 BIT(16)
> +#define AP_ENABLE_APB2_SDMMC2 BIT(17)
> +#define AP_ENABLE_APB2_SDMMC3 BIT(18)
> +#define AP_ENABLE_APB2_ALWAYS BIT(19)
> +#define AP_ENABLE_APB2_NANDFLASH BIT(20)
> +#define AP_ENABLE_MEM_CONF BIT(0)
> +#define AP_ENABLE_MEM_DMC  BIT(1)
> +#define AP_ENABLE_MEM_GPU  BIT(2)
> +#define AP_ENABLE_MEM_VPU  BIT(3)
> +#define AP_ENABLE_MEM_DDRPHY_P BIT(4)
> +#define AP_ENABLE_MEM_CONNECT BIT(5)
> +#define AP_ENABLE_APOC_VPU BIT(0)
> +#define AP_ENABLE_APOC_BCK BIT(1)
> +#define AP_ENABLE_APOC_UART1 BIT(2)
> +#define AP_ENABLE_APOC_UART2 BIT(3)
> +#define AP_ENABLE_APOC_UART3 BIT(4)
> +#define AP_ENABLE_APOC_VOC_CORE BIT(5)
> +#define AP_ENABLE_APOC_VOC BIT(6)
> +#define AP_ENABLE_APOC_VOC_ALWAYS BIT(7)
> +#define AP_ENABLE_APOC_DDRPHY_N BIT(8)
> +#define AP_ENABLE_APOC_DDRPHY2XP BIT(9)
> +#define AP_ENABLE_APOC_DDRPHY2XN BIT(10)
> +#define AP_ENABLE_APOC_GPU BIT(11)
> +#define AP_ENABLE_APOC_USBPHY BIT(12)
> +#define AP_ENABLE_APOC_CSI BIT(13)
> +#define AP_ENABLE_APOC_DSI BIT(14)
> +#define AP_ENABLE_APOC_GPIO BIT(15)
> +#define AP_ENABLE_APOC_SPIFLASH BIT(16)
> +#define AP_ENABLE_APOC_PIX BIT(17)
> +#define AP_ENABLE_APOC_PDGB BIT(18)
> +
> +/* AP Reset */
> +#define AP_RST_CPU_REG 0x1C
> +#define AP_RST_AXI_REG 0x24
> +#define AP_RST_AXIDIV2_REG 0x2C
> +#define AP_RST_GCG_REG 0x34
> +#define AP_RST_AHB1_REG 0x3C
> +#define AP_RST_APB1_REG 0x44
> +#define AP_RST_APB2_REG 0x4C
> +#define AP_RST_MEM_REG 0x54
> +
> +/* Bits */
> +#define AP_RST_CPU_CORE BIT(0)
> +#define AP_RST_CPU_SYS BIT(1)

Please add tabs because this is really hard to read when the define is
one space away from the definition.

> +#define AP_RST_AXI_VOC BIT(0)
> +#define AP_RST_AXI_DMA BIT(1)
> +#define AP_RST_AXI_SYS BIT(2)
> +#define AP_RST_AXI_CONNECT BIT(3)
> +#define AP_RST_AXI_VPU BIT(5)
> +#define AP_RST_AXIDIV2_IMEM BIT(0)
> +#define AP_RST_AXIDIV2_SYS BIT(1)
> +#define AP_RST_AXIDIV2_VPU BIT(2)
> +#define AP_RST_GCG_SYS BIT(0)
> +#define AP_RST_GCG_GOUDA BIT(1)
> +#define AP_RST_GCG_CAMERA BIT(2)
> +#define AP_RST_GCG_LCDC BIT(4)
> +#define AP_RST_AHB1_SYS BIT(0)
> +#define AP_RST_AHB1_USBC BIT(1)
> +#define AP_RST_AHB1_SPIFLASH BIT(2)
> +#define AP_RST_APB1_SYS BIT(0)
> +#define AP_RST_APB1_TIMER BIT(1)
> +#define AP_RST_APB1_KEYPAD BIT(2)
> +#define AP_RST_APB1_GPIO BIT(3)
> +#define AP_RST_APB1_PWM BIT(4)
> +#define AP_RST_APB1_AIF BIT(5)
> +#define AP_RST_APB1_AUIFC BIT(6)
> +#define AP_RST_APB1_I2C1 BIT(7)
> +#define AP_RST_APB1_I2C2 BIT(8)
> +#define AP_RST_APB1_I2C3 BIT(9)
> +#define AP_RST_APB1_COMREGS BIT(10)
> +#define AP_RST_APB1_DMC BIT(11)
> +#define AP_RST_APB1_DDRPHY_P BIT(12)
> +#define AP_RST_APB2_SYS BIT(0)
> +#define AP_RST_APB2_IFC BIT(1)
> +#define AP_RST_APB2_UART1 BIT(2)
> +#define AP_RST_APB2_UART2 BIT(3)
> +#define AP_RST_APB2_UART3 BIT(4)
> +#define AP_RST_APB2_SPI1 BIT(5)
> +#define AP_RST_APB2_SPI2 BIT(6)
> +#define AP_RST_APB2_SPI3 BIT(7)
> +#define AP_RST_APB2_SDMMC1 BIT(8)
> +#define AP_RST_APB2_SDMMC2 BIT(9)
> +#define AP_RST_APB2_SDMMC3 BIT(10)
> +#define AP_RST_APB2_NANDFLASH BIT(11)
> +#define AP_RST_MEM_SYS BIT(0)
> +#define AP_RST_MEM_GPU BIT(1)
> +#define AP_RST_MEM_VPU BIT(2)
> +#define AP_RST_MEM_DMC BIT(3)
> +#define AP_RST_MEM_DDRPHY_P BIT(4)
> +
> +/* Default PLL frequency */
> +#define AP_PLL_CPU_FREQ (988 * MHZ)
> +#define AP_PLL_BUS_FREQ (800 * MHZ)
> +#define AP_PLL_MEM_FREQ (260 * MHZ)
> +#define AP_PLL_USB_FREQ (480 * MHZ)

Are these inputs to the clk controller? Can we get these values from
fixed rate clk nodes in the DT instead of hard coding the rates in this
driver, especially if this is controllable outside of this device?

> +
> +struct rda8810_reset_list {
> +       int reg;
> +       int bit;

Why signed?

> +};
> +
> +struct rda_clk_priv {
> +       struct device *dev;
> +       struct regmap *regmap;
> +       struct clk_hw_onecell_data *onecell;
> +       struct reset_controller_dev rstctl;
> +       const struct rda8810_reset_list *rstlist;
> +};
> +
> +struct rda_clk_hw {
> +       int id;
> +       int reg;

Why signed?

> +       struct clk_hw hw;
> +
> +       int ena_reg;
> +       int ena_bit;

Why signed? Are they offsets? Use u32 or u8?

> +
> +       struct rda_clk_priv *priv;
> +};
> +
> +struct rda_clk_matchdata {
> +       const struct rda_clk_hw *clk_list;
> +       int max_clocks;
> +};
> +
> +static const struct clk_ops rda8810_clk_ops;

Presumably this can be defined instead of forward declared and then the
clk data can follow the functions?

> +
> +#define RDA_CLK_INIT(_id, _name, _parent, _flags, _reg, _ena_reg, _ena_bit) { \
> +       .id = _id, \
> +       .reg = _reg, \
> +       .ena_reg = _ena_reg, \
> +       .ena_bit = _ena_bit, \
> +       .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \
> +                       _parent, \
> +                       &rda8810_clk_ops, \
> +                       _flags) \
> +}
> +
> +#define RDA_CLK_INIT_NO_PARENT(_id, _name, _flags, _reg, _ena_reg, _ena_bit) { \
> +       .id = _id, \
> +       .reg = _reg, \
> +       .ena_reg = _ena_reg, \
> +       .ena_bit = _ena_bit, \
> +       .hw.init = CLK_HW_INIT_NO_PARENT(_name, &rda8810_clk_ops, _flags) \
> +}
> +
> +#define to_rda_rst(p) container_of(p, struct rda_clk_priv, rstctl)
> +
> +static inline struct rda_clk_hw *to_rda_hw(struct clk_hw *hw)
> +{
> +       return container_of(hw, struct rda_clk_hw, hw);
> +}
> +
> +/* clock division value map */
> +static const u8 clk_div_map[] = {
> +       4*60,   /* 0 */

Maybe
	[0 .. 7] = 4 * 60,
	[8] = 4 * 40,

etc. so the comment isn't needed and it is shorter.

> +       4*60,   /* 1 */
> +       4*60,   /* 2 */
> +       4*60,   /* 3 */
> +       4*60,   /* 4 */
> +       4*60,   /* 5 */
> +       4*60,   /* 6 */
> +       4*60,   /* 7 */
> +       4*40,   /* 8 */
> +       4*30,   /* 9 */
> +       4*24,   /* 10 */
> +       4*20,   /* 11 */
> +       4*17,   /* 12 */
> +       4*15,   /* 13 */
> +       4*13,   /* 14 */
> +       4*12,   /* 15 */
> +       4*11,   /* 16 */
> +       4*10,   /* 17 */
> +       4*9,    /* 18 */
> +       4*8,    /* 19 */
> +       4*7,    /* 20 */
> +       4*13/2, /* 21 */
> +       4*6,    /* 22 */
> +       4*11/2, /* 23 */
> +       4*5,    /* 24 */
> +       4*9/2,  /* 25 */
> +       4*4,    /* 26 */
> +       4*7/2,  /* 27 */
> +       4*3,    /* 28 */
> +       4*5/2,  /* 29 */
> +       4*2,    /* 30 */
> +       4*1,    /* 31 */
> +};
> +
> +static u32 apsys_get_divreg(u32 basefreq, u32 reqfreq, u32 *pdiv2)
> +{
> +       int i;
> +       int index;
> +       u32 adiv;
> +       u32 ndiv;
> +
> +       adiv = basefreq / (reqfreq >> 2);
> +       if (pdiv2) {
> +               /* try div2 mode first */
> +               ndiv = adiv >> 1;
> +       } else {
> +               ndiv = adiv;
> +       }
> +
> +       for (i = ARRAY_SIZE(clk_div_map) - 1; i >= 1; i--)
> +               if (ndiv < ((clk_div_map[i] + clk_div_map[i-1]) >> 1))
> +                       break;
> +       index = i;
> +
> +       if (pdiv2) {
> +               if (adiv == (clk_div_map[index] << 1)) {
> +                       /* div2 mode is OK */
> +                       *pdiv2 = 1;
> +               } else {
> +                       /* try div1 mode */
> +                       for (i = ARRAY_SIZE(clk_div_map) - 1; i >= 1; i--)
> +                               if (adiv < ((clk_div_map[i] + clk_div_map[i-1]) >> 1))
> +                                       break;
> +                       /* compare the results between div1 and div2 */
> +                       if (abs(adiv - (clk_div_map[index] << 1)) <=
> +                                       abs(adiv - clk_div_map[i])) {
> +                               *pdiv2 = 1;
> +                       } else {
> +                               *pdiv2 = 0;
> +                               index = i;
> +                       }
> +               }
> +       }
> +
> +       return index;
> +}
> +
> +static u32 apsys_cal_freq_by_divreg(u32 basefreq, u32 reg, u32 div2)
> +{
> +       u32 newfreq;
> +
> +       if (reg >= ARRAY_SIZE(clk_div_map))
> +               reg = ARRAY_SIZE(clk_div_map) - 1;
> +
> +       /* Assuming basefreq is smaller than 2^31 (2.147G Hz) */
> +       newfreq = (basefreq << (div2 ? 0 : 1)) / (clk_div_map[reg] >> 1);
> +       return newfreq;
> +}
> +
> +static void apsys_get_reg_div(struct rda_clk_hw *rda_hw, u32 *reg, u32 *div2)
> +{
> +       struct rda_clk_priv *priv = rda_hw->priv;
> +       int tmp_reg, tmp_div2;
> +       int ret;
> +
> +       ret = regmap_read(priv->regmap, rda_hw->reg, &tmp_reg);
> +       if (ret)
> +               return;
> +
> +       tmp_div2 = tmp_reg & AP_PERI_SRC_DIV;
> +
> +       *reg = tmp_reg;
> +       *div2 = tmp_div2;
> +}
> +
> +static int apsys_get_uart_clock(unsigned long parent_rate, u32 *reg)
> +{
> +       int clksrc = 26000000;
> +       u32 div;
> +       int rate = 0;
> +
> +       if (*reg & AP_UART_SET_PLL)
> +               clksrc = parent_rate / 8;
> +
> +       div = FIELD_GET(AP_UART_DIVIDER, *reg);
> +
> +       /* rate = clksrc / divmode / (div+2) */
> +       rate =  clksrc / 4 / (div + 2);

Maybe

	const unsigned int divmode = 4;

	rate = clksrc / divmode / (div + 2);

and then the comment is unnecessary.

> +
> +       return rate;
> +}
> +
> +static int apsys_cal_uart_clock(int freq)
> +{
> +       int new_freq = freq;
> +
> +       /*
> +        * To calculate maximum clock:
> +        *     freq = 26 MHz / div / (0 + 2)
> +        *
> +        * For lowest clock:
> +        *     freq = 26 MHz / div / (0x3FF + 2)
> +        */
> +       if (freq > 3250000)
> +               new_freq = 3250000;
> +       else if (freq < 6342)
> +               new_freq = 6342;

Use clamp()

> +
> +       new_freq = (26000000 + 4 / 2 * new_freq) / (4 * new_freq) - 2;
> +
> +       return new_freq;
> +}
> +
> +static int rda8810_clk_set_rate(struct clk_hw *clk, unsigned long rate,
> +               unsigned long parent_rate)
> +{
> +       struct rda_clk_hw *rda_hw = to_rda_hw(clk);
> +       struct rda_clk_priv *priv = rda_hw->priv;
> +       struct device *dev = priv->dev;
> +       int val, div2 = 0;
> +       int ret;
> +
> +       switch (rda_hw->id) {
> +       case CLK_CPU:
> +               val = apsys_get_divreg(AP_PLL_CPU_FREQ, rate, NULL);
> +               break;
> +       case CLK_AXI:
> +       case CLK_AHB1:
> +       case CLK_APB1:
> +       case CLK_APB2:
> +       case CLK_GCG:
> +       case CLK_GPU:
> +       case CLK_SFLSH:
> +       case CLK_VOC:
> +       case CLK_VPU:
> +               val = apsys_get_divreg(parent_rate, rate, &div2);
> +               break;
> +       case CLK_UART1:
> +       case CLK_UART2:
> +       case CLK_UART3:
> +               val = apsys_cal_uart_clock(rate);
> +               if (val == 0)
> +                       return -EINVAL;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       if (div2)
> +               val |= AP_PERI_SRC_DIV;
> +
> +       dev_dbg(dev, "clk_id: %d - rate: %ld - parent rate: %ld - val: %d - div: %d\n",
> +                       rda_hw->id, rate, parent_rate, val, div2);
> +
> +       ret = regmap_write(priv->regmap, rda_hw->reg, val);
> +       if (ret < 0)
> +               return ret;
> +
> +       return rate;
> +}
> +
> +static unsigned long rda8810_clk_recalc_rate(struct clk_hw *clk,
> +               unsigned long parent_rate)
> +{
> +       struct rda_clk_hw *rda_hw = to_rda_hw(clk);
> +       u32 reg, div2;
> +
> +       apsys_get_reg_div(rda_hw, &reg, &div2);
> +
> +       switch (rda_hw->id) {
> +       case CLK_CPU:
> +               return apsys_cal_freq_by_divreg(AP_PLL_CPU_FREQ, reg, 0);
> +       case CLK_BUS:
> +               return AP_PLL_BUS_FREQ;
> +       case CLK_MEM:
> +               return AP_PLL_MEM_FREQ >> (2 + div2);
> +       /* Bus peripherals */
> +       case CLK_USB:
> +               return AP_PLL_USB_FREQ;
> +       case CLK_AXI:
> +       case CLK_AHB1:
> +       case CLK_APB1:
> +       case CLK_APB2:
> +       case CLK_GCG:
> +       case CLK_GPU:
> +       case CLK_SFLSH:
> +       case CLK_VOC:
> +       case CLK_VPU:
> +               return apsys_cal_freq_by_divreg(parent_rate, reg, div2);
> +       /* For UART clocks, we'll have to do more calculation */
> +       case CLK_UART1:
> +       case CLK_UART2:
> +       case CLK_UART3:
> +               return apsys_get_uart_clock(parent_rate, &reg);
> +       default:
> +               return 0;
> +       }
> +}
> +
> +static long rda8810_clk_round_rate(struct clk_hw *clk, unsigned long rate,
> +               unsigned long *parent_rate)
> +{
> +       return rate;
> +}
> +
> +static int rda8810_clk_enable(struct clk_hw *clk)
> +{
> +       struct rda_clk_hw *rda_hw = to_rda_hw(clk);
> +       struct rda_clk_priv *priv = rda_hw->priv;
> +
> +       if (rda_hw->ena_reg < 0 || rda_hw->ena_bit < 0)
> +               return 0;
> +
> +       return regmap_write(priv->regmap, rda_hw->ena_reg, rda_hw->ena_bit);
> +}
> +
> +static void rda8810_clk_disable(struct clk_hw *clk)
> +{
> +       struct rda_clk_hw *rda_hw = to_rda_hw(clk);
> +       struct rda_clk_priv *priv = rda_hw->priv;
> +
> +       if (rda_hw->ena_reg < 0 || rda_hw->ena_bit < 0)
> +               return;
> +
> +       regmap_write(priv->regmap, rda_hw->ena_reg + 4, rda_hw->ena_bit);
> +}
> +
> +static const struct clk_ops rda8810_clk_ops = {
> +       .enable = rda8810_clk_enable,
> +       .disable = rda8810_clk_disable,
> +
> +       .recalc_rate = rda8810_clk_recalc_rate,
> +       .round_rate = rda8810_clk_round_rate,
> +       .set_rate = rda8810_clk_set_rate,
> +};
> +
> +/* Root clocks */
> +static struct rda_clk_hw rda8810_clk_cpu_desc =
> +RDA_CLK_INIT_NO_PARENT(CLK_CPU, "cpu", CLK_IS_CRITICAL, 0xC8,
> +               AP_REG_CPU_ENABLE, AP_ENABLE_CPU_CORE);
> +static struct rda_clk_hw rda8810_clk_mem_desc =
> +RDA_CLK_INIT_NO_PARENT(CLK_MEM, "mem", CLK_IS_CRITICAL, 0xE0, -1, -1);
> +
> +static struct rda_clk_hw rda8810_clk_bus_desc =
> +RDA_CLK_INIT_NO_PARENT(CLK_BUS, "bus", CLK_IS_CRITICAL, -1, -1, -1);

If they're critical can we just enabled them once in probe and not make
structures in memory that are basically useless?

> +
> +/* Bus clocks */
> +static struct rda_clk_hw rda8810_clk_usb_desc = RDA_CLK_INIT(CLK_USB, "usb",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, -1, -1, -1);
> +static struct rda_clk_hw rda8810_clk_axi_desc = RDA_CLK_INIT(CLK_AXI, "axi",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xCC, -1, -1);
> +static struct rda_clk_hw rda8810_clk_gcg_desc = RDA_CLK_INIT(CLK_GCG, "gcg",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xD0, -1, -1);
> +static struct rda_clk_hw rda8810_clk_ahb1_desc = RDA_CLK_INIT(CLK_AHB1, "ahb1",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xD4, -1, -1);
> +static struct rda_clk_hw rda8810_clk_apb1_desc = RDA_CLK_INIT(CLK_APB1, "apb1",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xD8, -1, -1);
> +static struct rda_clk_hw rda8810_clk_apb2_desc = RDA_CLK_INIT(CLK_APB2, "apb2",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xDC, -1, -1);
> +static struct rda_clk_hw rda8810_clk_gpu_desc = RDA_CLK_INIT(CLK_GPU, "gpu",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xE4, AP_REG_APO_ENABLE, AP_ENABLE_APOC_GPU);
> +static struct rda_clk_hw rda8810_clk_vpu_desc = RDA_CLK_INIT(CLK_VPU, "vpu",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xE8, AP_REG_APO_ENABLE, AP_ENABLE_APOC_VPU);
> +static struct rda_clk_hw rda8810_clk_voc_desc = RDA_CLK_INIT(CLK_VOC, "voc",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_bus_desc.hw } },
> +               0, 0xEC, AP_REG_APO_ENABLE,
> +               AP_ENABLE_APOC_VOC | AP_ENABLE_APOC_VOC_CORE | AP_ENABLE_APOC_VOC_ALWAYS);
> +
> +/* APB1 peripherals */
> +static struct rda_clk_hw rda8810_clk_spiflash_desc = RDA_CLK_INIT(CLK_SFLSH, "spiflash",
> +               (const struct clk_parent_data[]) { { .hw = &rda8810_clk_apb1_desc.hw } },
> +               0, 0xF0, AP_REG_APO_ENABLE, AP_ENABLE_APOC_SPIFLASH);
> +
> +/* APB2 peripherals */
> +static struct rda_clk_hw rda8810_clk_uart_desc[] = {
> +       RDA_CLK_INIT(CLK_UART1, "uart1",
> +                       (const struct clk_parent_data[]) { { .hw = &rda8810_clk_apb2_desc.hw } },

If the only parent is a clk_hw pointer please use clk_hws in struct
clk_init_data instead of parent_data.

> +                       0, 0xF4,
> +                       AP_REG_APO_ENABLE, AP_ENABLE_APOC_UART1),
> +       RDA_CLK_INIT(CLK_UART2, "uart2",
> +                       (const struct clk_parent_data[]) { { .hw = &rda8810_clk_apb2_desc.hw } },
> +                       0, 0xF8,
> +                       AP_REG_APO_ENABLE, AP_ENABLE_APOC_UART2),
> +       RDA_CLK_INIT(CLK_UART3, "uart3",
> +                       (const struct clk_parent_data[]) { { .hw = &rda8810_clk_apb2_desc.hw } },
> +                       0, 0xFC,
> +                       AP_REG_APO_ENABLE, AP_ENABLE_APOC_UART3),
> +};
> +
> +static struct rda_clk_hw *const rda8810_clk_list[] = {
> +       &rda8810_clk_cpu_desc,
> +       &rda8810_clk_bus_desc,
> +       &rda8810_clk_mem_desc,
> +
> +       &rda8810_clk_usb_desc,
> +       &rda8810_clk_axi_desc,
> +       &rda8810_clk_gcg_desc,
> +       &rda8810_clk_ahb1_desc,
> +       &rda8810_clk_apb1_desc,
> +       &rda8810_clk_apb2_desc,
> +
> +       &rda8810_clk_gpu_desc,
> +       &rda8810_clk_vpu_desc,
> +       &rda8810_clk_voc_desc,
> +
> +       &rda8810_clk_spiflash_desc,
> +
> +       &rda8810_clk_uart_desc[0],
> +       &rda8810_clk_uart_desc[1],
> +       &rda8810_clk_uart_desc[2],
> +};
> +
> +static const struct rda8810_reset_list rda8810_rst_data[] = {
> +       /* ID, REG */
> +
> +       /* CPU */
> +       [RST_CPU] = { AP_RST_CPU_REG, AP_RST_CPU_CORE },
> +
> +       /* AXI */
> +       [RST_AXI_VOC] = { AP_RST_AXI_REG, AP_RST_AXI_VOC },
> +       [RST_AXI_DMA] = { AP_RST_AXI_REG, AP_RST_AXI_DMA },
> +       [RST_AXI_CONNECT] = { AP_RST_AXI_REG, AP_RST_AXI_CONNECT },
> +       [RST_AXI_VPU] = { AP_RST_AXI_REG, AP_RST_AXI_VPU },
> +
> +       /* GCG */
> +       [RST_GCG_GOUDA] = { AP_RST_GCG_REG, AP_RST_GCG_GOUDA },
> +       [RST_GCG_CAMERA] = { AP_RST_GCG_REG, AP_RST_GCG_CAMERA },
> +       [RST_GCG_LCDC] = { AP_RST_GCG_REG, AP_RST_GCG_LCDC },
> +
> +       /* AHB1 */
> +       [RST_AHB1_USBC] = { AP_RST_AHB1_REG, AP_RST_AHB1_USBC },
> +       [RST_AHB1_SPIFLASH] = { AP_RST_AHB1_REG, AP_RST_AHB1_SPIFLASH },
> +
> +       /* APB1 */
> +       [RST_APB1_TIMER] = { AP_RST_APB1_REG, AP_RST_APB1_TIMER },
> +       [RST_APB1_KEYPAD] = { AP_RST_APB1_REG, AP_RST_APB1_KEYPAD },
> +       [RST_APB1_GPIO] = { AP_RST_APB1_REG, AP_RST_APB1_GPIO },
> +       [RST_APB1_PWM] = { AP_RST_APB1_REG, AP_RST_APB1_PWM },
> +       [RST_APB1_AIF] = { AP_RST_APB1_REG, AP_RST_APB1_AIF },
> +       [RST_APB1_AUIFC] = { AP_RST_APB1_REG, AP_RST_APB1_AUIFC },
> +       [RST_APB1_I2C1] = { AP_RST_APB1_REG, AP_RST_APB1_I2C1 },
> +       [RST_APB1_I2C2] = { AP_RST_APB1_REG, AP_RST_APB1_I2C2 },
> +       [RST_APB1_I2C3] = { AP_RST_APB1_REG, AP_RST_APB1_I2C3 },
> +       [RST_APB1_COMREGS] = { AP_RST_APB1_REG, AP_RST_APB1_COMREGS },
> +       [RST_APB1_DMC] = { AP_RST_APB1_REG, AP_RST_APB1_DMC },
> +       [RST_APB1_DDRPHY_P] = { AP_RST_APB1_REG, AP_RST_APB1_DDRPHY_P },
> +
> +       /* APB2 */
> +       [RST_APB2_IFC] = { AP_RST_APB2_REG, AP_RST_APB2_IFC },
> +       [RST_APB2_UART1] = { AP_RST_APB2_REG, AP_RST_APB2_UART1 },
> +       [RST_APB2_UART2] = { AP_RST_APB2_REG, AP_RST_APB2_UART2 },
> +       [RST_APB2_UART3] = { AP_RST_APB2_REG, AP_RST_APB2_UART3 },
> +       [RST_APB2_SPI1] = { AP_RST_APB2_REG, AP_RST_APB2_SPI1 },
> +       [RST_APB2_SPI2] = { AP_RST_APB2_REG, AP_RST_APB2_SPI2 },
> +       [RST_APB2_SPI3] = { AP_RST_APB2_REG, AP_RST_APB2_SPI3 },
> +       [RST_APB2_SDMMC1] = { AP_RST_APB2_REG, AP_RST_APB2_SDMMC1 },
> +       [RST_APB2_SDMMC2] = { AP_RST_APB2_REG, AP_RST_APB2_SDMMC2 },
> +       [RST_APB2_SDMMC3] = { AP_RST_APB2_REG, AP_RST_APB2_SDMMC3 },
> +       [RST_APB2_NAND] = { AP_RST_APB2_REG, AP_RST_APB2_NANDFLASH },
> +
> +       /* MEM */
> +       [RST_MEM_GPU] = { AP_RST_MEM_REG, AP_RST_MEM_GPU },
> +       [RST_MEM_VPU] = { AP_RST_MEM_REG, AP_RST_MEM_VPU },
> +       [RST_MEM_DMC] = { AP_RST_MEM_REG, AP_RST_MEM_DMC },
> +       [RST_MEM_DDRPHY_P] = { AP_RST_MEM_REG, AP_RST_MEM_DDRPHY_P },
> +};
> +
> +static int rda8810_reset_assert(struct reset_controller_dev *rstctl, unsigned long id)
> +{
> +       struct rda_clk_priv *priv = to_rda_rst(rstctl);
> +
> +       return regmap_write(priv->regmap, rda8810_rst_data[id].reg, rda8810_rst_data[id].bit);
> +}
> +
> +static int rda8810_reset_deassert(struct reset_controller_dev *rstctl, unsigned long id)
> +{
> +       struct rda_clk_priv *priv = to_rda_rst(rstctl);
> +
> +       return regmap_write(priv->regmap, rda8810_rst_data[id].reg + 4, rda8810_rst_data[id].bit);
> +}
> +
> +static const struct reset_control_ops rda8810_rst_ops = {
> +       .assert = &rda8810_reset_assert,
> +       .deassert = &rda8810_reset_deassert,
> +};
> +
> +static int rda8810_clk_register(struct rda_clk_priv *priv)
> +{
> +       struct device *dev = priv->dev;
> +       struct clk_hw_onecell_data *onecell_data;
> +       int ret;
> +       int i;
> +
> +       onecell_data = devm_kzalloc(dev,
> +                       struct_size(onecell_data, hws, ARRAY_SIZE(rda8810_clk_list)),
> +                       GFP_KERNEL);
> +       if (!onecell_data)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < ARRAY_SIZE(rda8810_clk_list); i++) {
> +               rda8810_clk_list[i]->priv = priv;
> +
> +               ret = devm_clk_hw_register(dev, &rda8810_clk_list[i]->hw);
> +               if (ret) {
> +                       dev_err(dev, "Failed to register clock: %d\n", ret);
> +                       return ret;
> +               }
> +               onecell_data->hws[i] = &rda8810_clk_list[i]->hw;
> +       }
> +       onecell_data->num = i;
> +       priv->onecell = onecell_data;
> +
> +       return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, onecell_data);
> +}
> +
> +static int rda8810_rst_register(struct rda_clk_priv *priv)
> +{
> +       struct device *dev = priv->dev;
> +
> +       priv->rstctl.dev = priv->dev;
> +       priv->rstctl.nr_resets = RST_COUNT;
> +       priv->rstctl.of_node = priv->dev->of_node;
> +       priv->rstctl.ops = &rda8810_rst_ops;
> +       priv->rstctl.owner = THIS_MODULE;
> +
> +       return devm_reset_controller_register(dev, &priv->rstctl);

Please use auxiliary bus and put the reset driver in drivers/reset/

> +}
> +
> +static int rda8810_clk_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct rda_clk_priv *priv;
> +       int ret;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return dev_err_probe(dev, -ENOMEM, "Cannot allocate memory\n");

No error messages for allocation failures please. The allocator already
has a more informative message.

> +
> +       priv->dev = dev;
> +
> +       priv->regmap = syscon_node_to_regmap(dev->of_node);

Why is it a syscon?

> +       if (IS_ERR(priv->regmap))
> +               return dev_err_probe(dev, -ENOMEM, "Cannot initialize regmap\n");
> +
> +       ret = rda8810_clk_register(priv);
> +       if (ret)
> +               return dev_err_probe(dev, -EINVAL, "Failed to setup clock: %d\n", ret);
> +
> +       ret = rda8810_rst_register(priv);
> +       if (ret)
> +               return dev_err_probe(dev, -EINVAL, "Failed to setup reset: %d\n", ret);
> +
> +       platform_set_drvdata(pdev, priv);
> +
> +       return 0;

^ permalink raw reply

* Re: [PATCH] rtc: tegra: Add ACPI support
From: kernel test robot @ 2025-09-20  2:09 UTC (permalink / raw)
  To: Kartik Rajput, alexandre.belloni, thierry.reding, jonathanh,
	andriy.shevchenko, linux-rtc, linux-tegra, linux-kernel
  Cc: oe-kbuild-all, Kartik Rajput
In-Reply-To: <20250919111232.605405-1-kkartik@nvidia.com>

Hi Kartik,

kernel test robot noticed the following build errors:

[auto build test ERROR on tegra/for-next]
[also build test ERROR on abelloni/rtc-next linus/master v6.17-rc6 next-20250919]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kartik-Rajput/rtc-tegra-Add-ACPI-support/20250919-191553
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
patch link:    https://lore.kernel.org/r/20250919111232.605405-1-kkartik%40nvidia.com
patch subject: [PATCH] rtc: tegra: Add ACPI support
config: arm-randconfig-001-20250920 (https://download.01.org/0day-ci/archive/20250920/202509200953.uZOl24Is-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 12.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250920/202509200953.uZOl24Is-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509200953.uZOl24Is-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/rtc/rtc-tegra.c: In function 'tegra_rtc_probe':
>> drivers/rtc/rtc-tegra.c:310:13: error: implicit declaration of function 'is_of_node'; did you mean 'dev_of_node'? [-Werror=implicit-function-declaration]
     310 |         if (is_of_node(dev_fwnode(&pdev->dev))) {
         |             ^~~~~~~~~~
         |             dev_of_node
   cc1: some warnings being treated as errors


vim +310 drivers/rtc/rtc-tegra.c

   283	
   284	static int tegra_rtc_probe(struct platform_device *pdev)
   285	{
   286		struct tegra_rtc_info *info;
   287		int ret;
   288	
   289		info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
   290		if (!info)
   291			return -ENOMEM;
   292	
   293		info->base = devm_platform_ioremap_resource(pdev, 0);
   294		if (IS_ERR(info->base))
   295			return PTR_ERR(info->base);
   296	
   297		ret = platform_get_irq(pdev, 0);
   298		if (ret <= 0)
   299			return ret;
   300	
   301		info->irq = ret;
   302	
   303		info->rtc = devm_rtc_allocate_device(&pdev->dev);
   304		if (IS_ERR(info->rtc))
   305			return PTR_ERR(info->rtc);
   306	
   307		info->rtc->ops = &tegra_rtc_ops;
   308		info->rtc->range_max = U32_MAX;
   309	
 > 310		if (is_of_node(dev_fwnode(&pdev->dev))) {
   311			info->clk = devm_clk_get(&pdev->dev, NULL);
   312			if (IS_ERR(info->clk))
   313				return PTR_ERR(info->clk);
   314	
   315			ret = clk_prepare_enable(info->clk);
   316			if (ret < 0)
   317				return ret;
   318		}
   319	
   320		/* set context info */
   321		info->pdev = pdev;
   322		spin_lock_init(&info->lock);
   323	
   324		platform_set_drvdata(pdev, info);
   325	
   326		/* clear out the hardware */
   327		writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0);
   328		writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS);
   329		writel(0, info->base + TEGRA_RTC_REG_INTR_MASK);
   330	
   331		device_init_wakeup(&pdev->dev, true);
   332	
   333		ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler,
   334				       IRQF_TRIGGER_HIGH, dev_name(&pdev->dev),
   335				       &pdev->dev);
   336		if (ret) {
   337			dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret);
   338			goto disable_clk;
   339		}
   340	
   341		ret = devm_rtc_register_device(info->rtc);
   342		if (ret)
   343			goto disable_clk;
   344	
   345		dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
   346	
   347		return 0;
   348	
   349	disable_clk:
   350		if (is_of_node(dev_fwnode(&pdev->dev)))
   351			clk_disable_unprepare(info->clk);
   352		return ret;
   353	}
   354	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH v6 2/4] arm64: tegra: Add device-tree node for NVVRS RTC
From: Rob Herring (Arm) @ 2025-09-19 17:03 UTC (permalink / raw)
  To: Shubhi Garg
  Cc: Krzysztof Kozlowski, Alexandre Belloni, devicetree,
	linux-arm-kernel, linux-rtc, Will Deacon, linux-tegra,
	Conor Dooley, Jonathan Hunter, Catalin Marinas, Lee Jones
In-Reply-To: <20250919140217.10531-1-shgarg@nvidia.com>


On Fri, 19 Sep 2025 14:02:17 +0000, Shubhi Garg wrote:
> Add NVIDIA VRS (Voltage Regulator Specification) RTC device tree node for
> Tegra234 P3701 and P3767 platforms. Assign VRS RTC as primary RTC (rtc0).
> 
> Signed-off-by: Shubhi Garg <shgarg@nvidia.com>
> ---
> 
> v6:
> - compatible name fixes to "nvidia,vrs-10"
> - changed dtb node name to pmic@3c
> 
> v5:
> - changed dtb node name to rtc@3c
> 
> v4:
> - fixed device tree node name to "pmic@3c" in aliases
> 
> v3:
> - fixed device tree node name to generic "pmic@3c"
> 
> v2:
> - added alias to assign VRS RTC to rtc0
> - removed status node from VRS DTB node
> 
>  arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi | 11 +++++++++++
>  arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi | 15 +++++++++++++++
>  2 files changed, 26 insertions(+)
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


This patch series was applied (using b4) to base:
 Base: attempting to guess base-commit...
 Base: tags/next-20250919 (exact match)

If this is not the correct base, please add 'base-commit' tag
(or use b4 which does this automatically)

New warnings running 'make CHECK_DTBS=y for arch/arm64/boot/dts/nvidia/' for 20250919140217.10531-1-shgarg@nvidia.com:

arch/arm64/boot/dts/nvidia/tegra234-p3768-0000+p3767-0000.dtb: /bpmp/i2c/pmic@3c: failed to match any schema with compatible: ['nvidia,vrs-10']
arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0008.dtb: /bpmp/i2c/pmic@3c: failed to match any schema with compatible: ['nvidia,vrs-10']
arch/arm64/boot/dts/nvidia/tegra234-p3740-0002+p3701-0008.dtb: /bpmp/i2c/pmic@3c: failed to match any schema with compatible: ['nvidia,vrs-10']
arch/arm64/boot/dts/nvidia/tegra234-p3768-0000+p3767-0005.dtb: /bpmp/i2c/pmic@3c: failed to match any schema with compatible: ['nvidia,vrs-10']
arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dtb: /bpmp/i2c/pmic@3c: failed to match any schema with compatible: ['nvidia,vrs-10']






^ permalink raw reply

* [PATCH v6 4/4] arm64: defconfig: enable NVIDIA VRS PSEQ RTC
From: Shubhi Garg @ 2025-09-19 14:02 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Catalin Marinas, Will Deacon, Alexandre Belloni, Jonathan Hunter
  Cc: devicetree, linux-arm-kernel, linux-rtc, linux-tegra, Shubhi Garg

Enable NVIDIA VRS (Voltage Regulator Specification) RTC device module.
It provides functionality to get/set system time, retain system time
across boot, wake system from suspend and shutdown state.

Supported platforms:
- NVIDIA Jetson AGX Orin Developer Kit
- NVIDIA IGX Orin Development Kit
- NVIDIA Jetson Orin NX Developer Kit
- NVIDIA Jetson Orin Nano Developer Kit

Signed-off-by: Shubhi Garg <shgarg@nvidia.com>
---

v6:
- no changes

v5:
- removed VRS MFD CONFIG
- changed VRS RTC CONFIG name

v4:
- no changes

v3:
- no changes

v2:
- moved VRS RTC config to correct place

 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index e3a2d37bd104..a7fb6aa4062c 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1283,6 +1283,7 @@ CONFIG_RTC_DRV_MT6397=m
 CONFIG_RTC_DRV_XGENE=y
 CONFIG_RTC_DRV_TI_K3=m
 CONFIG_RTC_DRV_RENESAS_RTCA3=m
+CONFIG_RTC_DRV_NVIDIA_VRS10=m
 CONFIG_DMADEVICES=y
 CONFIG_DMA_BCM2835=y
 CONFIG_DMA_SUN6I=m
-- 
2.43.0


^ permalink raw reply related

* [PATCH v6 3/4] rtc: nvvrs: add NVIDIA VRS RTC device driver
From: Shubhi Garg @ 2025-09-19 14:02 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Catalin Marinas, Will Deacon, Alexandre Belloni, Jonathan Hunter
  Cc: devicetree, linux-arm-kernel, linux-rtc, linux-tegra, Shubhi Garg

Add support for NVIDIA VRS (Voltage Regulator Specification) RTC device
driver. NVIDIA VRS is a Power Management IC (PMIC) that implements a
power sequencing solution with I2C interface. The device includes RTC
which provides functionality to get/set system time, retain system
time across boot, wake system from suspend and shutdown state.

Supported platforms:
- NVIDIA Jetson AGX Orin Developer Kit
- NVIDIA IGX Orin Development Kit
- NVIDIA Jetson Orin NX Developer Kit
- NVIDIA Jetson Orin Nano Developer Kit

Signed-off-by: Shubhi Garg <shgarg@nvidia.com>
---

v6:
- compatible name fixes to "nvidia,vrs-10"

v5:
- removed unused register definitions from header
- added VRS to maintainers list
- removed MFD dependency from Kconfig
- improved driver filename and CONFIG name
- handle all VRS interrupts in RTC driver
- validate chip vendor info during RTC probe
- clear any pending IRQs during RTC probe

v4:
- no changes

v3:
- fixed return value in RTC read_time and read_alarm functions
- fixed sizeof(*variable) inside rtc driver devm_kzalloc
- switch to devm_device_init_wakeup() for automatic cleanup

v2:
- removed regmap struct since it is not required
- removed rtc_map definition to directly use register definition
- removed unnecessary dev_err logs
- fixed dev_err logs to dev_dbg
- used rtc_lock/unlock in irq handler
- changed RTC allocation and register APIs as per latest kernel
- removed nvvrs_rtc_remove function since it's not required

 MAINTAINERS                          |   8 +
 drivers/rtc/Kconfig                  |   9 +
 drivers/rtc/Makefile                 |   1 +
 drivers/rtc/rtc-nvidia-vrs10.c       | 508 +++++++++++++++++++++++++++
 include/linux/rtc/rtc-nvidia-vrs10.h |  78 ++++
 5 files changed, 604 insertions(+)
 create mode 100644 drivers/rtc/rtc-nvidia-vrs10.c
 create mode 100644 include/linux/rtc/rtc-nvidia-vrs10.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 8886d66bd824..0bd459932741 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18347,6 +18347,14 @@ S:	Maintained
 F:	drivers/video/fbdev/nvidia/
 F:	drivers/video/fbdev/riva/
 
+NVIDIA VRS RTC DRIVER
+M:	Shubhi Garg <shgarg@nvidia.com>
+L:	linux-tegra@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml
+F:	drivers/rtc/rtc-nvidia-vrs10.c
+F:	include/linux/rtc/rtc-nvidia-vrs10.h
+
 NVIDIA WMI EC BACKLIGHT DRIVER
 M:	Daniel Dadap <ddadap@nvidia.com>
 L:	platform-driver-x86@vger.kernel.org
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 31d355b103d4..609f8c67f36a 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -416,6 +416,15 @@ config RTC_DRV_SPACEMIT_P1
 	  This driver can also be built as a module, which will be called
 	  "spacemit-p1-rtc".
 
+config RTC_DRV_NVIDIA_VRS10
+	tristate "NVIDIA VRS10 RTC device"
+	help
+	  If you say yes here you will get support for the battery backed RTC device
+	  of NVIDIA VRS (Voltage Regulator Specification). The RTC is connected via
+	  I2C interface and supports alarm functionality.
+	  This driver can also be built as a module. If so, the module will be called
+	  rtc-nvidia-vrs10.
+
 config RTC_DRV_NCT3018Y
 	tristate "Nuvoton NCT3018Y"
 	depends on OF
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f41fdb4fabae..36ffb10cc9b7 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_MXC_V2)	+= rtc-mxc_v2.o
 obj-$(CONFIG_RTC_DRV_GAMECUBE)	+= rtc-gamecube.o
 obj-$(CONFIG_RTC_DRV_NCT3018Y)	+= rtc-nct3018y.o
 obj-$(CONFIG_RTC_DRV_NTXEC)	+= rtc-ntxec.o
+obj-$(CONFIG_RTC_DRV_NVIDIA_VRS10)+= rtc-nvidia-vrs10.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
 obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
 obj-$(CONFIG_RTC_DRV_OPTEE)	+= rtc-optee.o
diff --git a/drivers/rtc/rtc-nvidia-vrs10.c b/drivers/rtc/rtc-nvidia-vrs10.c
new file mode 100644
index 000000000000..4c488723854c
--- /dev/null
+++ b/drivers/rtc/rtc-nvidia-vrs10.c
@@ -0,0 +1,508 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NVIDIA Voltage Regulator Specification RTC
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+ * All rights reserved.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <linux/rtc/rtc-nvidia-vrs10.h>
+
+#define ALARM_RESET_VAL		0xffffffff
+#define NVVRS_MIN_MODEL_REV	0x40
+
+struct nvvrs_rtc_info {
+	struct device          *dev;
+	struct i2c_client      *client;
+	struct rtc_device      *rtc;
+	unsigned int           irq;
+	/* Mutex to protect RTC operations */
+	struct mutex           lock;
+};
+
+static int nvvrs_update_bits(struct nvvrs_rtc_info *info, u8 reg,
+			     u8 mask, u8 value)
+{
+	int ret;
+	u8 val;
+
+	ret = i2c_smbus_read_byte_data(info->client, reg);
+	if (ret < 0)
+		return ret;
+
+	val = (u8)ret;
+	val &= ~mask;
+	val |= (value & mask);
+
+	return i2c_smbus_write_byte_data(info->client, reg, val);
+}
+
+static int nvvrs_rtc_write_alarm(struct i2c_client *client, u8 *time)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A3, time[3]);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A2, time[2]);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A1, time[1]);
+	if (ret < 0)
+		return ret;
+
+	return i2c_smbus_write_byte_data(client, NVVRS_REG_RTC_A0, time[0]);
+}
+
+static int nvvrs_rtc_enable_alarm(struct nvvrs_rtc_info *info)
+{
+	int ret;
+
+	/* Set RTC_WAKE bit for autonomous wake from sleep */
+	ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE,
+				NVVRS_REG_CTL_2_RTC_WAKE);
+	if (ret < 0) {
+		dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n", ret);
+		return ret;
+	}
+
+	/* Set RTC_PU bit for autonomous wake from shutdown */
+	ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU,
+				NVVRS_REG_CTL_2_RTC_PU);
+	if (ret < 0) {
+		dev_err(info->dev, "Failed to set RTC_PU bit (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int nvvrs_rtc_disable_alarm(struct nvvrs_rtc_info *info)
+{
+	struct i2c_client *client = info->client;
+	u8 val[4];
+	int ret;
+
+	/* Clear RTC_WAKE bit */
+	ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_WAKE,
+				0);
+	if (ret < 0) {
+		dev_err(info->dev, "Failed to clear RTC_WAKE bit (%d)\n", ret);
+		return ret;
+	}
+
+	/* Clear RTC_PU bit */
+	ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2, NVVRS_REG_CTL_2_RTC_PU,
+				0);
+	if (ret < 0) {
+		dev_err(info->dev, "Failed to clear RTC_PU bit (%d)\n", ret);
+		return ret;
+	}
+
+	/* Write ALARM_RESET_VAL in RTC Alarm register to disable alarm */
+	val[0] = 0xff;
+	val[1] = 0xff;
+	val[2] = 0xff;
+	val[3] = 0xff;
+
+	ret = nvvrs_rtc_write_alarm(client, val);
+	if (ret < 0)
+		dev_err(info->dev, "Failed to disable Alarm (%d)\n", ret);
+
+	return 0;
+}
+
+static int nvvrs_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+	time64_t secs = 0;
+	int ret;
+	u8 val;
+
+	mutex_lock(&info->lock);
+
+	/*
+	 * Multi-byte transfers are not supported with PEC enabled
+	 * Read MSB first to avoid coherency issues
+	 */
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T3);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	secs |= (time64_t)val << 24;
+
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T2);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	secs |= (time64_t)val << 16;
+
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T1);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	secs |= (time64_t)val << 8;
+
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_T0);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	secs |= val;
+
+	rtc_time64_to_tm(secs, tm);
+	ret = 0;
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int nvvrs_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+	time64_t secs;
+	u8 time[4];
+	int ret;
+
+	mutex_lock(&info->lock);
+
+	secs = rtc_tm_to_time64(tm);
+	time[0] = secs & 0xff;
+	time[1] = (secs >> 8) & 0xff;
+	time[2] = (secs >> 16) & 0xff;
+	time[3] = (secs >> 24) & 0xff;
+
+	ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T3, time[3]);
+	if (ret < 0)
+		goto out;
+
+	ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T2, time[2]);
+	if (ret < 0)
+		goto out;
+
+	ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T1, time[1]);
+	if (ret < 0)
+		goto out;
+
+	ret = i2c_smbus_write_byte_data(info->client, NVVRS_REG_RTC_T0, time[0]);
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int nvvrs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+	time64_t alarm_val = 0;
+	int ret;
+	u8 val;
+
+	mutex_lock(&info->lock);
+
+	/* Multi-byte transfers are not supported with PEC enabled */
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A3);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	alarm_val |= (time64_t)val << 24;
+
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A2);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	alarm_val |= (time64_t)val << 16;
+
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A1);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	alarm_val |= (time64_t)val << 8;
+
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_RTC_A0);
+	if (ret < 0)
+		goto out;
+
+	val = (u8)ret;
+	alarm_val |= val;
+
+	if (alarm_val == ALARM_RESET_VAL)
+		alrm->enabled = 0;
+	else
+		alrm->enabled = 1;
+
+	rtc_time64_to_tm(alarm_val, &alrm->time);
+	ret = 0;
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int nvvrs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+	time64_t secs;
+	u8 time[4];
+	int ret;
+
+	mutex_lock(&info->lock);
+
+	if (!alrm->enabled) {
+		ret = nvvrs_rtc_disable_alarm(info);
+		if (ret < 0)
+			goto out;
+	}
+
+	ret = nvvrs_rtc_enable_alarm(info);
+	if (ret < 0)
+		goto out;
+
+	secs = rtc_tm_to_time64(&alrm->time);
+	time[0] = secs & 0xff;
+	time[1] = (secs >> 8) & 0xff;
+	time[2] = (secs >> 16) & 0xff;
+	time[3] = (secs >> 24) & 0xff;
+
+	ret = nvvrs_rtc_write_alarm(info->client, time);
+
+out:
+	mutex_unlock(&info->lock);
+	return ret;
+}
+
+static int nvvrs_pseq_irq_clear(struct nvvrs_rtc_info *info)
+{
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < NVVRS_IRQ_REG_COUNT; i++) {
+		ret = i2c_smbus_read_byte_data(info->client,
+					       NVVRS_REG_INT_SRC1 + i);
+		if (ret < 0) {
+			dev_err(info->dev, "Failed to read INT_SRC%d : %d\n",
+				i + 1, ret);
+			return ret;
+		}
+
+		ret = i2c_smbus_write_byte_data(info->client,
+						NVVRS_REG_INT_SRC1 + i,
+						(u8)ret);
+		if (ret < 0) {
+			dev_err(info->dev, "Failed to clear INT_SRC%d : %d\n",
+				i + 1, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data)
+{
+	struct nvvrs_rtc_info *info = data;
+	int ret;
+
+	/* Check for RTC alarm interrupt */
+	ret = i2c_smbus_read_byte_data(info->client, NVVRS_REG_INT_SRC1);
+	if (ret < 0) {
+		dev_err(info->dev, "Failed to read INT_SRC1: %d\n", ret);
+		return IRQ_NONE;
+	}
+
+	if (ret & NVVRS_INT_SRC1_RTC_MASK) {
+		rtc_lock(info->rtc);
+		rtc_update_irq(info->rtc, 1, RTC_IRQF | RTC_AF);
+		rtc_unlock(info->rtc);
+	}
+
+	/* Clear all interrupts */
+	if (nvvrs_pseq_irq_clear(info) < 0)
+		return IRQ_NONE;
+
+	return IRQ_HANDLED;
+}
+
+static int nvvrs_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	/*
+	 * This hardware does not support enabling/disabling the alarm IRQ
+	 * independently. The alarm is disabled by clearing the alarm time
+	 * via set_alarm().
+	 */
+	return 0;
+}
+
+static const struct rtc_class_ops nvvrs_rtc_ops = {
+	.read_time = nvvrs_rtc_read_time,
+	.set_time = nvvrs_rtc_set_time,
+	.read_alarm = nvvrs_rtc_read_alarm,
+	.set_alarm = nvvrs_rtc_set_alarm,
+	.alarm_irq_enable = nvvrs_rtc_alarm_irq_enable,
+};
+
+static int nvvrs_pseq_vendor_info(struct nvvrs_rtc_info *info)
+{
+	struct i2c_client *client = info->client;
+	u8 vendor_id, model_rev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, NVVRS_REG_VENDOR_ID);
+	if (ret < 0)
+		return dev_err_probe(&client->dev, ret,
+				     "Failed to read Vendor ID\n");
+
+	vendor_id = (u8)ret;
+
+	ret = i2c_smbus_read_byte_data(client, NVVRS_REG_MODEL_REV);
+	if (ret < 0)
+		return dev_err_probe(&client->dev, ret,
+				     "Failed to read Model Revision\n");
+
+	model_rev = (u8)ret;
+
+	if (model_rev < NVVRS_MIN_MODEL_REV) {
+		return dev_err_probe(&client->dev, -ENODEV,
+				     "Chip revision 0x%02x is not supported!\n",
+				     model_rev);
+	}
+
+	dev_dbg(&client->dev, "NVVRS Vendor ID: 0x%02x, Model Rev: 0x%02x\n",
+		vendor_id, model_rev);
+
+	return 0;
+}
+
+static int nvvrs_rtc_probe(struct i2c_client *client)
+{
+	struct nvvrs_rtc_info *info;
+	int ret;
+
+	info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	mutex_init(&info->lock);
+
+	if (client->irq <= 0)
+		return dev_err_probe(&client->dev, -EINVAL, "No IRQ specified\n");
+
+	info->irq = client->irq;
+	info->dev = &client->dev;
+	client->flags |= I2C_CLIENT_PEC;
+	i2c_set_clientdata(client, info);
+	info->client = client;
+
+	/* Check vendor info */
+	if (nvvrs_pseq_vendor_info(info) < 0)
+		return dev_err_probe(&client->dev, -EINVAL,
+				     "Failed to get vendor info\n");
+
+	/* Clear any pending IRQs before requesting IRQ handler */
+	if (nvvrs_pseq_irq_clear(info) < 0)
+		return dev_err_probe(&client->dev, -EINVAL,
+				     "Failed to clear interrupts\n");
+
+	/* Allocate RTC device */
+	info->rtc = devm_rtc_allocate_device(info->dev);
+	if (IS_ERR(info->rtc))
+		return PTR_ERR(info->rtc);
+
+	info->rtc->ops = &nvvrs_rtc_ops;
+	info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+	info->rtc->range_max = RTC_TIMESTAMP_END_2099;
+
+	/* Request RTC IRQ */
+	ret = devm_request_threaded_irq(info->dev, info->irq, NULL,
+					nvvrs_rtc_irq_handler, IRQF_ONESHOT,
+					"nvvrs-rtc", info);
+	if (ret < 0) {
+		dev_err_probe(info->dev, ret, "Failed to request RTC IRQ\n");
+		return ret;
+	}
+
+	/* RTC as a wakeup source */
+	devm_device_init_wakeup(info->dev);
+
+	return devm_rtc_register_device(info->rtc);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int nvvrs_rtc_suspend(struct device *dev)
+{
+	struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+	int ret;
+
+	if (device_may_wakeup(dev)) {
+		/* Set RTC_WAKE bit for auto wake system from suspend state */
+		ret = nvvrs_update_bits(info, NVVRS_REG_CTL_2,
+					NVVRS_REG_CTL_2_RTC_WAKE,
+					NVVRS_REG_CTL_2_RTC_WAKE);
+		if (ret < 0) {
+			dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n",
+				ret);
+			return ret;
+		}
+
+		return enable_irq_wake(info->irq);
+	}
+
+	return 0;
+}
+
+static int nvvrs_rtc_resume(struct device *dev)
+{
+	struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
+	int ret;
+
+	if (device_may_wakeup(dev)) {
+		/* Clear FORCE_ACT bit */
+		ret = nvvrs_update_bits(info, NVVRS_REG_CTL_1,
+					NVVRS_REG_CTL_1_FORCE_ACT, 0);
+		if (ret < 0) {
+			dev_err(info->dev, "Failed to clear FORCE_ACT bit (%d)\n",
+				ret);
+			return ret;
+		}
+
+		return disable_irq_wake(info->irq);
+	}
+
+	return 0;
+}
+
+#endif
+static SIMPLE_DEV_PM_OPS(nvvrs_rtc_pm_ops, nvvrs_rtc_suspend, nvvrs_rtc_resume);
+
+static const struct of_device_id nvvrs_rtc_of_match[] = {
+	{ .compatible = "nvidia,vrs-10" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, nvvrs_rtc_of_match);
+
+static struct i2c_driver nvvrs_rtc_driver = {
+	.driver		= {
+		.name   = "rtc-nvidia-vrs10",
+		.pm     = &nvvrs_rtc_pm_ops,
+		.of_match_table = nvvrs_rtc_of_match,
+	},
+	.probe		= nvvrs_rtc_probe,
+};
+
+module_i2c_driver(nvvrs_rtc_driver);
+
+MODULE_AUTHOR("Shubhi Garg <shgarg@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Voltage Regulator Specification RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/rtc/rtc-nvidia-vrs10.h b/include/linux/rtc/rtc-nvidia-vrs10.h
new file mode 100644
index 000000000000..3c9c46abf555
--- /dev/null
+++ b/include/linux/rtc/rtc-nvidia-vrs10.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+ * All rights reserved
+ */
+
+#ifndef _RTC_NVIDIA_VRS_H_
+#define _RTC_NVIDIA_VRS_H_
+
+#include <linux/types.h>
+
+/* Vendor Info */
+#define NVVRS_REG_VENDOR_ID			0x00
+#define NVVRS_REG_MODEL_REV			0x01
+
+/*  Interrupts registers */
+#define NVVRS_REG_INT_SRC1			0x10
+#define NVVRS_REG_INT_SRC2			0x11
+#define NVVRS_REG_INT_VENDOR			0x12
+
+/* Control Registers */
+#define NVVRS_REG_CTL_1				0x28
+#define NVVRS_REG_CTL_2				0x29
+
+/* RTC Registers */
+#define NVVRS_REG_RTC_T3			0x70
+#define NVVRS_REG_RTC_T2			0x71
+#define NVVRS_REG_RTC_T1			0x72
+#define NVVRS_REG_RTC_T0			0x73
+#define NVVRS_REG_RTC_A3			0x74
+#define NVVRS_REG_RTC_A2			0x75
+#define NVVRS_REG_RTC_A1			0x76
+#define NVVRS_REG_RTC_A0			0x77
+
+/* Interrupt Mask */
+#define NVVRS_INT_SRC1_RSTIRQ_MASK		BIT(0)
+#define NVVRS_INT_SRC1_OSC_MASK			BIT(1)
+#define NVVRS_INT_SRC1_EN_MASK			BIT(2)
+#define NVVRS_INT_SRC1_RTC_MASK			BIT(3)
+#define NVVRS_INT_SRC1_PEC_MASK			BIT(4)
+#define NVVRS_INT_SRC1_WDT_MASK			BIT(5)
+#define NVVRS_INT_SRC1_EM_PD_MASK		BIT(6)
+#define NVVRS_INT_SRC1_INTERNAL_MASK		BIT(7)
+#define NVVRS_INT_SRC2_PBSP_MASK		BIT(0)
+#define NVVRS_INT_SRC2_ECC_DED_MASK		BIT(1)
+#define NVVRS_INT_SRC2_TSD_MASK			BIT(2)
+#define NVVRS_INT_SRC2_LDO_MASK			BIT(3)
+#define NVVRS_INT_SRC2_BIST_MASK		BIT(4)
+#define NVVRS_INT_SRC2_RT_CRC_MASK		BIT(5)
+#define NVVRS_INT_SRC2_VENDOR_MASK		BIT(7)
+#define NVVRS_INT_VENDOR0_MASK			BIT(0)
+#define NVVRS_INT_VENDOR1_MASK			BIT(1)
+#define NVVRS_INT_VENDOR2_MASK			BIT(2)
+#define NVVRS_INT_VENDOR3_MASK			BIT(3)
+#define NVVRS_INT_VENDOR4_MASK			BIT(4)
+#define NVVRS_INT_VENDOR5_MASK			BIT(5)
+#define NVVRS_INT_VENDOR6_MASK			BIT(6)
+#define NVVRS_INT_VENDOR7_MASK			BIT(7)
+
+/* Controller Register Mask */
+#define NVVRS_REG_CTL_1_FORCE_SHDN		(BIT(0) | BIT(1))
+#define NVVRS_REG_CTL_1_FORCE_ACT		BIT(2)
+#define NVVRS_REG_CTL_1_FORCE_INT		BIT(3)
+#define NVVRS_REG_CTL_2_EN_PEC			BIT(0)
+#define NVVRS_REG_CTL_2_REQ_PEC			BIT(1)
+#define NVVRS_REG_CTL_2_RTC_PU			BIT(2)
+#define NVVRS_REG_CTL_2_RTC_WAKE		BIT(3)
+#define NVVRS_REG_CTL_2_RST_DLY			0xF0
+
+enum nvvrs_irq_regs {
+	NVVRS_IRQ_REG_INT_SRC1 = 0,
+	NVVRS_IRQ_REG_INT_SRC2 = 1,
+	NVVRS_IRQ_REG_INT_VENDOR = 2,
+	NVVRS_IRQ_REG_COUNT = 3,
+};
+
+#endif /* _RTC_NVIDIA_VRS_H_ */
+
-- 
2.43.0


^ permalink raw reply related

* [PATCH v6 2/4] arm64: tegra: Add device-tree node for NVVRS RTC
From: Shubhi Garg @ 2025-09-19 14:02 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Catalin Marinas, Will Deacon, Alexandre Belloni, Jonathan Hunter
  Cc: devicetree, linux-arm-kernel, linux-rtc, linux-tegra, Shubhi Garg

Add NVIDIA VRS (Voltage Regulator Specification) RTC device tree node for
Tegra234 P3701 and P3767 platforms. Assign VRS RTC as primary RTC (rtc0).

Signed-off-by: Shubhi Garg <shgarg@nvidia.com>
---

v6:
- compatible name fixes to "nvidia,vrs-10"
- changed dtb node name to pmic@3c

v5:
- changed dtb node name to rtc@3c

v4:
- fixed device tree node name to "pmic@3c" in aliases

v3:
- fixed device tree node name to generic "pmic@3c"

v2:
- added alias to assign VRS RTC to rtc0
- removed status node from VRS DTB node

 arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi | 11 +++++++++++
 arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi | 15 +++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi
index 9086a0d010e5..58bf55c0e414 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi
@@ -8,6 +8,7 @@ / {
 	aliases {
 		mmc0 = "/bus@0/mmc@3460000";
 		mmc1 = "/bus@0/mmc@3400000";
+		rtc0 = "/bpmp/i2c/pmic@3c";
 	};
 
 	bus@0 {
@@ -170,6 +171,16 @@ bpmp {
 		i2c {
 			status = "okay";
 
+			pmic@3c {
+				compatible = "nvidia,vrs-10";
+				reg = <0x3c>;
+				interrupt-parent = <&pmc>;
+				/* VRS Wake ID is 24 */
+				interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
 			thermal-sensor@4c {
 				compatible = "ti,tmp451";
 				status = "okay";
diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi
index 84db7132e8fc..ab391a71c3d3 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi
@@ -7,6 +7,7 @@ / {
 
 	aliases {
 		mmc0 = "/bus@0/mmc@3400000";
+		rtc0 = "/bpmp/i2c/pmic@3c";
 	};
 
 	bus@0 {
@@ -121,6 +122,20 @@ pmc@c360000 {
 		};
 	};
 
+	bpmp {
+		i2c {
+			pmic@3c {
+				compatible = "nvidia,vrs-10";
+				reg = <0x3c>;
+				interrupt-parent = <&pmc>;
+				/* VRS Wake ID is 24 */
+				interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+		};
+	};
+
 	vdd_5v0_sys: regulator-vdd-5v0-sys {
 		compatible = "regulator-fixed";
 		regulator-name = "VDD_5V0_SYS";
-- 
2.43.0


^ permalink raw reply related

* [PATCH v6 0/4] Add NVIDIA VRS RTC support
From: Shubhi Garg @ 2025-09-19 14:02 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Catalin Marinas, Will Deacon, Alexandre Belloni, Jonathan Hunter
  Cc: devicetree, linux-arm-kernel, linux-rtc, linux-tegra, Shubhi Garg

This patch series adds support for NVIDIA's Voltage Regulator Specification
(VRS) RTC device. It provides following features:
- read/set system time
- 32kHz clock support with backup battery input to retain system time
  across boot
- alarm functionality to wake system from suspend and shutdown state

The series includes:
- Device tree bindings for the VRS RTC
- VRS device tree nodes for NVIDIA platforms
- VRS RTC device driver
- Configuration updates to enable the driver

Changes in v6:
- compatible name fixes to "nvidia,vrs-10"
- changed dtb node name to pmic@3c

Changes in v5:
- moved device tree bindings from mfd to rtc
- changed dtb node name to rtc@3c
- removed VRS MFD driver
- moved VRS common functions to RTC driver
- removed unused register definitions from header
- changed driver compatible to "nvidia,vrs10-rtc"

Changes in v4:
- fixed device tree node name to "pmic@3c" in dtb aliases

Changes in v3:
- fixed device tree node name to generic "pmic@3c"
- fixed indentation in dt-bindings
- added rate limiting to interrupt clearing debug logs
- removed unnecessary braces in if blocks
- changed dependency from I2C=y to I2C in mfd Kconfig
- fixed return value in RTC driver function calls
- fixed sizeof(*variable) inside rtc driver devm_kzalloc
- switch to devm_device_init_wakeup() for automatic cleanup

Changes in v2:
- fixed, copyrights, definitions and dtb node in dt-bindings
- removed unnecessary logs from MFD and RTC driver
- fixed RTC allocation and registration APIs
- removed unnecessary functions in RTC driver
- used rtc_lock/unlock in RTC irq handler
- added alias to assign VRS RTC as RTC0
- added driver entry in MAINTAINERS
- few other miinor changes done in drivers

Shubhi Garg (4):
  dt-bindings: rtc: Document NVIDIA VRS RTC
  arm64: tegra: Add device-tree node for NVVRS RTC
  rtc: nvvrs: add NVIDIA VRS RTC device driver
  arm64: defconfig: enable NVIDIA VRS PSEQ RTC

 .../bindings/rtc/nvidia,vrs10-rtc.yaml        |  59 ++
 MAINTAINERS                                   |   8 +
 .../arm64/boot/dts/nvidia/tegra234-p3701.dtsi |  11 +
 .../arm64/boot/dts/nvidia/tegra234-p3767.dtsi |  15 +
 arch/arm64/configs/defconfig                  |   1 +
 drivers/rtc/Kconfig                           |   9 +
 drivers/rtc/Makefile                          |   1 +
 drivers/rtc/rtc-nvidia-vrs10.c                | 508 ++++++++++++++++++
 include/linux/rtc/rtc-nvidia-vrs10.h          |  78 +++
 9 files changed, 690 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml
 create mode 100644 drivers/rtc/rtc-nvidia-vrs10.c
 create mode 100644 include/linux/rtc/rtc-nvidia-vrs10.h

-- 
2.43.0


^ permalink raw reply

* Re: [PATCH 06/25] rtc: Add driver for RDA Micro SoC
From: kernel test robot @ 2025-09-19 13:59 UTC (permalink / raw)
  To: Dang Huynh via B4 Relay, Manivannan Sadhasivam, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
	Bartosz Golaszewski, Alexandre Belloni, Michael Turquette,
	Stephen Boyd, Philipp Zabel, Sebastian Reichel, Vinod Koul,
	Kees Cook, Gustavo A. R. Silva, Ulf Hansson
  Cc: oe-kbuild-all, linux-arm-kernel, linux-unisoc, devicetree,
	linux-kernel, linux-gpio, linux-rtc, linux-clk, linux-pm,
	dmaengine, linux-hardening, linux-mmc, Dang Huynh
In-Reply-To: <20250917-rda8810pl-drivers-v1-6-9ca9184ca977@mainlining.org>

Hi Dang,

kernel test robot noticed the following build errors:

[auto build test ERROR on 590b221ed4256fd6c34d3dea77aa5bd6e741bbc1]

url:    https://github.com/intel-lab-lkp/linux/commits/Dang-Huynh-via-B4-Relay/ARM-dts-unisoc-rda8810pl-Add-label-to-GPIO-nodes/20250917-043025
base:   590b221ed4256fd6c34d3dea77aa5bd6e741bbc1
patch link:    https://lore.kernel.org/r/20250917-rda8810pl-drivers-v1-6-9ca9184ca977%40mainlining.org
patch subject: [PATCH 06/25] rtc: Add driver for RDA Micro SoC
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20250919/202509192152.OXdK6bpd-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250919/202509192152.OXdK6bpd-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509192152.OXdK6bpd-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/rtc/rtc-rda.c: In function 'rda_rtc_settime':
>> drivers/rtc/rtc-rda.c:67:15: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
      67 |         low = FIELD_PREP(RDA_SEC_MASK, tm->tm_sec) |
         |               ^~~~~~~~~~
   drivers/rtc/rtc-rda.c: In function 'rda_rtc_readtime':
>> drivers/rtc/rtc-rda.c:128:22: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
     128 |         tm->tm_sec = FIELD_GET(RDA_SEC_MASK, low);
         |                      ^~~~~~~~~


vim +/FIELD_PREP +67 drivers/rtc/rtc-rda.c

    50	
    51	static int rda_rtc_settime(struct device *dev, struct rtc_time *tm)
    52	{
    53		struct rda_rtc *rtc = dev_get_drvdata(dev);
    54		u32 high, low;
    55		int ret;
    56	
    57		ret = rtc_valid_tm(tm);
    58		if (ret < 0)
    59			return ret;
    60	
    61		/*
    62		 * The number of years since 1900 in kernel,
    63		 * but it is defined since 2000 by HW.
    64		 * The number of mons' range is from 0 to 11 in kernel,
    65		 * but it is defined from 1 to 12 by HW.
    66		 */
  > 67		low = FIELD_PREP(RDA_SEC_MASK, tm->tm_sec) |
    68			FIELD_PREP(RDA_MIN_MASK, tm->tm_min) |
    69			FIELD_PREP(RDA_HRS_MASK, tm->tm_hour);
    70	
    71		high = FIELD_PREP(RDA_MDAY_MASK, tm->tm_mday) |
    72			FIELD_PREP(RDA_MON_MASK, tm->tm_mon + 1) |
    73			FIELD_PREP(RDA_YEAR_MASK, tm->tm_year - 100) |
    74			FIELD_PREP(RDA_WDAY_MASK, tm->tm_wday);
    75	
    76		ret = regmap_write(rtc->regmap, RDA_RTC_CAL_LOAD_LOW_REG, low);
    77		if (ret < 0) {
    78			dev_err(dev, "Failed to update RTC low register: %d\n", ret);
    79			return ret;
    80		}
    81	
    82		ret = regmap_write(rtc->regmap, RDA_RTC_CAL_LOAD_HIGH_REG, high);
    83		if (ret < 0) {
    84			dev_err(dev, "Failed to update RTC low register: %d\n", ret);
    85			return ret;
    86		}
    87	
    88		ret = regmap_update_bits(rtc->regmap, RDA_RTC_CMD_REG, RDA_RTC_CMD_CAL_LOAD, 1);
    89		if (ret < 0) {
    90			dev_err(dev, "Failed to update RTC cal load register: %d\n", ret);
    91			return ret;
    92		}
    93	
    94		return 0;
    95	}
    96	
    97	static int rda_rtc_readtime(struct device *dev, struct rtc_time *tm)
    98	{
    99		struct rda_rtc *rtc = dev_get_drvdata(dev);
   100		unsigned int high, low;
   101		int ret;
   102	
   103		/*
   104		 * Check if RTC data is valid.
   105		 *
   106		 * When this bit is set, it means the data in the RTC is invalid
   107		 * or not configured.
   108		 */
   109		ret = regmap_test_bits(rtc->regmap, RDA_RTC_STA_REG, RDA_RTC_STA_NOT_PROG);
   110		if (ret < 0) {
   111			dev_err(dev, "Failed to read RTC status: %d\n", ret);
   112			return ret;
   113		} else if (ret > 0)
   114			return -EINVAL;
   115	
   116		ret = regmap_read(rtc->regmap, RDA_RTC_CUR_LOAD_HIGH_REG, &high);
   117		if (ret) {
   118			dev_err(dev, "Failed to read RTC high reg: %d\n", ret);
   119			return ret;
   120		}
   121	
   122		ret = regmap_read(rtc->regmap, RDA_RTC_CUR_LOAD_LOW_REG, &low);
   123		if (ret) {
   124			dev_err(dev, "Failed to read RTC low reg: %d\n", ret);
   125			return ret;
   126		}
   127	
 > 128		tm->tm_sec = FIELD_GET(RDA_SEC_MASK, low);
   129		tm->tm_min = FIELD_GET(RDA_MIN_MASK, low);
   130		tm->tm_hour = FIELD_GET(RDA_HRS_MASK, low);
   131		tm->tm_mday = FIELD_GET(RDA_MDAY_MASK, high);
   132		tm->tm_mon = FIELD_GET(RDA_MON_MASK, high);
   133		tm->tm_year = FIELD_GET(RDA_YEAR_MASK, high);
   134		tm->tm_wday = FIELD_GET(RDA_WDAY_MASK, high);
   135	
   136		/*
   137		 * The number of years since 1900 in kernel,
   138		 * but it is defined since 2000 by HW.
   139		 */
   140		tm->tm_year += 100;
   141		/*
   142		 * The number of mons' range is from 0 to 11 in kernel,
   143		 * but it is defined from 1 to 12 by HW.
   144		 */
   145		tm->tm_mon -= 1;
   146	
   147		return 0;
   148	}
   149	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* [PATCH v6 1/4] dt-bindings: rtc: Document NVIDIA VRS RTC
From: Shubhi Garg @ 2025-09-19 13:59 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Catalin Marinas, Will Deacon, Alexandre Belloni, Jonathan Hunter
  Cc: devicetree, linux-arm-kernel, linux-rtc, linux-tegra, Shubhi Garg

Add device tree bindings for NVIDIA VRS (Voltage Regulator Specification)
RTC device. NVIDIA VRS is a Power Management IC (PMIC) that implements a
power sequencing solution with I2C interface. The device includes RTC
which provides functionality to get/set system time, retain system
time across boot, wake system from suspend and shutdown state.

Supported platforms:
- NVIDIA Jetson AGX Orin Developer Kit
- NVIDIA IGX Orin Development Kit
- NVIDIA Jetson Orin NX Developer Kit
- NVIDIA Jetson Orin Nano Developer Kit

Signed-off-by: Shubhi Garg <shgarg@nvidia.com>
---

v6:
- compatible name fixes to "nvidia,vrs-10"
- changed dtb node name to pmic@3c

v5:
- moved device tree bindings from mfd to rtc
- changed dtb node name to rtc@3c
- changed compatible string to "nvidia,vrs10-rtc"

v4:
- no changes

v3:
- fixed device tree node name to generic "pmic@3c"
- fixed indentation

v2:
- fixed copyrights
- updated description with RTC information
- added status node in dtb node example

 .../bindings/rtc/nvidia,vrs10-rtc.yaml        | 59 +++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml

diff --git a/Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml b/Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml
new file mode 100644
index 000000000000..e8f3c25607e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/nvidia,vrs10-rtc.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/nvidia,vrs10-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Voltage Regulator Specification Real Time Clock
+
+maintainers:
+  - Shubhi Garg <shgarg@nvidia.com>
+
+description:
+  NVIDIA VRS-10 (Voltage Regulator Specification) is a Power Management IC
+  (PMIC) that implements a power sequencing solution with I2C interface.
+  The device includes a real-time clock (RTC) with 32kHz clock output and
+  backup battery support, alarm functionality for system wake-up from
+  suspend and shutdown states, OTP memory for power sequencing configuration,
+  and an interrupt controller for managing VRS events.
+
+properties:
+  compatible:
+    const: nvidia,vrs-10
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        pmic@3c {
+            compatible = "nvidia,vrs-10";
+            reg = <0x3c>;
+            interrupt-parent = <&pmc>;
+            interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
+            interrupt-controller;
+            #interrupt-cells = <2>;
+        };
+    };
-- 
2.43.0


^ permalink raw reply related

* [PATCH] rtc: tegra: Add ACPI support
From: Kartik Rajput @ 2025-09-19 11:12 UTC (permalink / raw)
  To: alexandre.belloni, thierry.reding, jonathanh, andriy.shevchenko,
	linux-rtc, linux-tegra, linux-kernel
  Cc: Kartik Rajput

Add ACPI support for Tegra RTC, which is available on Tegra241 and
Tegra410. Both Tegra241 and Tegra410 use the same ACPI ID 'NVDA0280'.
The RTC clock is configured by UEFI before the kernel boots.

Signed-off-by: Kartik Rajput <kkartik@nvidia.com>
---
 drivers/rtc/rtc-tegra.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 46788db89953..40617c82070f 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -5,6 +5,7 @@
  * Copyright (c) 2010-2019, NVIDIA Corporation.
  */
 
+#include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -274,6 +275,12 @@ static const struct of_device_id tegra_rtc_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
 
+static const struct acpi_device_id tegra_rtc_acpi_match[] = {
+	{ "NVDA0280", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, tegra_rtc_acpi_match);
+
 static int tegra_rtc_probe(struct platform_device *pdev)
 {
 	struct tegra_rtc_info *info;
@@ -300,13 +307,15 @@ static int tegra_rtc_probe(struct platform_device *pdev)
 	info->rtc->ops = &tegra_rtc_ops;
 	info->rtc->range_max = U32_MAX;
 
-	info->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(info->clk))
-		return PTR_ERR(info->clk);
+	if (is_of_node(dev_fwnode(&pdev->dev))) {
+		info->clk = devm_clk_get(&pdev->dev, NULL);
+		if (IS_ERR(info->clk))
+			return PTR_ERR(info->clk);
 
-	ret = clk_prepare_enable(info->clk);
-	if (ret < 0)
-		return ret;
+		ret = clk_prepare_enable(info->clk);
+		if (ret < 0)
+			return ret;
+	}
 
 	/* set context info */
 	info->pdev = pdev;
@@ -338,7 +347,8 @@ static int tegra_rtc_probe(struct platform_device *pdev)
 	return 0;
 
 disable_clk:
-	clk_disable_unprepare(info->clk);
+	if (is_of_node(dev_fwnode(&pdev->dev)))
+		clk_disable_unprepare(info->clk);
 	return ret;
 }
 
@@ -346,7 +356,8 @@ static void tegra_rtc_remove(struct platform_device *pdev)
 {
 	struct tegra_rtc_info *info = platform_get_drvdata(pdev);
 
-	clk_disable_unprepare(info->clk);
+	if (is_of_node(dev_fwnode(&pdev->dev)))
+		clk_disable_unprepare(info->clk);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -404,6 +415,7 @@ static struct platform_driver tegra_rtc_driver = {
 	.driver = {
 		.name = "tegra_rtc",
 		.of_match_table = tegra_rtc_dt_match,
+		.acpi_match_table = tegra_rtc_acpi_match,
 		.pm = &tegra_rtc_pm_ops,
 	},
 };
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH 05/25] dt-bindings: rtc: Add RDA Micro RDA8810PL RTC
From: Conor Dooley @ 2025-09-18 15:18 UTC (permalink / raw)
  To: Dang Huynh
  Cc: Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Linus Walleij, Bartosz Golaszewski,
	Alexandre Belloni, Michael Turquette, Stephen Boyd, Philipp Zabel,
	Sebastian Reichel, Vinod Koul, Kees Cook, Gustavo A. R. Silva,
	Ulf Hansson, linux-arm-kernel, linux-unisoc, devicetree,
	linux-kernel, linux-gpio, linux-rtc, linux-clk, linux-pm,
	dmaengine, linux-hardening, linux-mmc
In-Reply-To: <c905fb3ace281280f1ac11c7fbe8e0aa@mainlining.org>

[-- Attachment #1: Type: text/plain, Size: 2104 bytes --]

On Thu, Sep 18, 2025 at 11:11:10AM +0700, Dang Huynh wrote:
> On 2025-09-18 03:46, Conor Dooley wrote:
> > On Wed, Sep 17, 2025 at 03:07:22AM +0700, Dang Huynh wrote:
> > > Add documentation describing the RTC found in RDA8810PL SoC.
> > > 
> > > Signed-off-by: Dang Huynh <dang.huynh@mainlining.org>
> > > ---
> > >  .../devicetree/bindings/rtc/rda,8810pl-rtc.yaml    | 30
> > > ++++++++++++++++++++++
> > >  1 file changed, 30 insertions(+)
> > > 
> > > diff --git
> > > a/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
> > > b/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
> > > new file mode 100644
> > > index 0000000000000000000000000000000000000000..3ceae294921cc3211cd775d9b3890393196faf82
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
> > > @@ -0,0 +1,30 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/rtc/rda,8810pl-rtc.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: RDA Micro RDA8810PL Real Time Clock
> > > +
> > > +maintainers:
> > > +  - Dang Huynh <dang.huynh@mainlining.org>
> > > +
> > > +properties:
> > > +  compatible:
> > > +    const: rda,8810pl-rtc
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +required:
> > > +  - compatible
> > > +  - reg
> > 
> > Your driver implements functions that turn on an alarm irq, but there is
> > none mentioned here. What's going on there?
> The RTC doesn't seem to have an AP IRQ associated. I can't find any
> reference to it on downstream kernel and the docs.
> 
> > 
> > Additionally, there's no clocks property? For an onboard RTC I'd have
> > expected there to be a clock sourced outside of the block.

What about the clock?

> > 
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    rtc@1a06000 {
> > > +      compatible = "rda,8810pl-rtc";
> > > +      reg = <0x1a06000 0x1000>;
> > > +    };
> > > 
> > > --
> > > 2.51.0

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* [PATCH 2/2] rtc: optee: Fix error code in optee_rtc_read_alarm()
From: Dan Carpenter @ 2025-09-18  9:49 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Clément Léger, Alexandre Belloni, linux-rtc,
	linux-kernel
In-Reply-To: <cover.1758182509.git.dan.carpenter@linaro.org>

Return "optee_alarm" instead of "alarm".  The "alarm" pointer is a valid
pointer and not an error pointer.

Fixes: 6266aea864fa ("rtc: optee: add alarm related rtc ops to optee rtc driver")
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
---
 drivers/rtc/rtc-optee.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c
index 7b44d7723cae..3d5662aa1bd8 100644
--- a/drivers/rtc/rtc-optee.c
+++ b/drivers/rtc/rtc-optee.c
@@ -299,7 +299,7 @@ static int optee_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 
 	optee_alarm = tee_shm_get_va(priv->shm, 0);
 	if (IS_ERR(optee_alarm))
-		return PTR_ERR(alarm);
+		return PTR_ERR(optee_alarm);
 
 	if (param[0].u.memref.size != sizeof(*optee_alarm))
 		return -EPROTO;
-- 
2.51.0


^ permalink raw reply related

* [PATCH 1/2] rtc: optee: fix error code in probe()
From: Dan Carpenter @ 2025-09-18  9:49 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Clément Léger, Alexandre Belloni, linux-rtc,
	linux-kernel
In-Reply-To: <cover.1758182509.git.dan.carpenter@linaro.org>

Return an error code if kthread_create() fails.  Currently the code
returns success.

Fixes: 6266aea864fa ("rtc: optee: add alarm related rtc ops to optee rtc driver")
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
---
 drivers/rtc/rtc-optee.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/rtc/rtc-optee.c b/drivers/rtc/rtc-optee.c
index 27db403e3047..7b44d7723cae 100644
--- a/drivers/rtc/rtc-optee.c
+++ b/drivers/rtc/rtc-optee.c
@@ -614,6 +614,7 @@ static int optee_rtc_probe(struct device *dev)
 						  priv, "rtc_alarm_evt");
 		if (IS_ERR(priv->alarm_task)) {
 			dev_err(dev, "Failed to create alarm thread\n");
+			err = PTR_ERR(priv->alarm_task);
 			goto out_shm;
 		}
 
-- 
2.51.0


^ permalink raw reply related

* [PATCH 0/2] rtc: optee: Fix a couple error codes
From: Dan Carpenter @ 2025-09-18  9:48 UTC (permalink / raw)
  To: Clément Le Goffic
  Cc: Alexandre Belloni, Clément Léger, linux-kernel,
	linux-rtc

Fix a couple error codes detected by Smatch.

Dan Carpenter (2):
  rtc: optee: fix error code in probe()
  rtc: optee: Fix error code in optee_rtc_read_alarm()

 drivers/rtc/rtc-optee.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

-- 
2.51.0


^ permalink raw reply

* Re: [PATCH 00/25] RDA8810PL Clock, RTC and MMC driver
From: Dang Huynh @ 2025-09-18  5:02 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
	Bartosz Golaszewski, Alexandre Belloni, Michael Turquette,
	Stephen Boyd, Philipp Zabel, Sebastian Reichel, Vinod Koul,
	Kees Cook, Gustavo A. R. Silva, Ulf Hansson, linux-arm-kernel,
	linux-unisoc, devicetree, linux-kernel, linux-gpio, linux-rtc,
	linux-clk, linux-pm, dmaengine, linux-hardening, linux-mmc
In-Reply-To: <lnfervvwctvemjdmyue2aohlsqpfd5gsuzjho3u6mtdtewl4vr@saqnionh72am>

On 2025-09-17 17:03, Manivannan Sadhasivam wrote:
> On Wed, Sep 17, 2025 at 03:24:57AM GMT, Dang Huynh via B4 Relay wrote:
>> This patch series aims to add support for Clock/Reset, Real-Time Clock 
>> and
>> SDMMC on the RDA Micro RDA8810PL platform.
>> 
>> It also adds Intelligent Flow Controller (IOW, a DMA controller) which 
>> is
>> important for working with this MMC IP.
>> 
>> Tested on the Orange Pi 2G-IOT.
>> 
> 
> Thanks for work! Is it possible to split this patchset logically to 
> ease
> reviewing and also merging? It currently touches different subsystems 
> and has 25
> patches.
> 
> You could easily split this into different series adding Clock/Reset, 
> RTC, IFC,
> SDMMC and other misc patches in one series.
Will do. Is it possible for you to test it on your i96 board?

> 
> - Mani
> 
>> Signed-off-by: Dang Huynh <dang.huynh@mainlining.org>
>> ---
>> Dang Huynh (25):
>>       ARM: dts: unisoc: rda8810pl: Add label to GPIO nodes
>>       drivers: gpio: rda: Make IRQ optional
>>       dt-bindings: gpio: rda: Make interrupts optional
>>       rtc: Add timestamp for the end of 2127
>>       dt-bindings: rtc: Add RDA Micro RDA8810PL RTC
>>       rtc: Add driver for RDA Micro SoC
>>       ARM: dts: unisoc: rda8810pl: Enable Real-Time Clock
>>       ARM: dts: unisoc: rda8810pl: Enable ARM PMU
>>       dt-bindings: clock: Add RDA Micro RDA8810PL clock/reset 
>> controller
>>       drivers: clk: Add Clock and Reset Driver for RDA Micro RDA8810PL 
>> SoC
>>       dts: unisoc: rda8810pl: Enable clock/reset driver
>>       dts: unisoc: rda8810pl: Add OPP for CPU and define L2 cache
>>       dts: unisoc: orangepi: Disable UART with no users
>>       dt-bindings: power: reset: Add RDA Micro Modem Reset
>>       power: reset: Add basic power reset driver for RDA8810PL
>>       dts: unisoc: rda8810pl: Enable modem reset
>>       drivers: gpio: rda: Make direction register unreadable
>>       dt-bindings: dma: Add RDA IFC DMA
>>       dmaengine: Add RDA IFC driver
>>       dts: unisoc: rda8810pl: Enable IFC
>>       dt-bindings: mmc: Add RDA SDMMC controller
>>       mmc: host: Add RDA Micro SD/MMC driver
>>       dts: unisoc: rda8810pl: Add SDMMC controllers
>>       dts: unisoc: orangepi-2g: Enable SD Card
>>       dts: unisoc: orangepi-i96: Enable SD Card
>> 
>>  .../bindings/clock/rda,8810pl-apsyscon.yaml        |  44 ++
>>  Documentation/devicetree/bindings/dma/rda,ifc.yaml |  42 +
>>  .../devicetree/bindings/gpio/gpio-rda.yaml         |   3 -
>>  Documentation/devicetree/bindings/mmc/rda,mmc.yaml |  91 +++
>>  .../bindings/power/reset/rda,md-reset.yaml         |  36 +
>>  .../devicetree/bindings/rtc/rda,8810pl-rtc.yaml    |  30 +
>>  MAINTAINERS                                        |  30 +
>>  .../boot/dts/unisoc/rda8810pl-orangepi-2g-iot.dts  |  24 +-
>>  .../arm/boot/dts/unisoc/rda8810pl-orangepi-i96.dts |  24 +-
>>  arch/arm/boot/dts/unisoc/rda8810pl.dtsi            | 115 ++-
>>  drivers/clk/Kconfig                                |   1 +
>>  drivers/clk/Makefile                               |   1 +
>>  drivers/clk/rda/Kconfig                            |  14 +
>>  drivers/clk/rda/Makefile                           |   2 +
>>  drivers/clk/rda/clk-rda8810.c                      | 770 
>> +++++++++++++++++++
>>  drivers/dma/Kconfig                                |  10 +
>>  drivers/dma/Makefile                               |   1 +
>>  drivers/dma/rda-ifc.c                              | 450 +++++++++++
>>  drivers/gpio/gpio-rda.c                            |   4 +-
>>  drivers/mmc/host/Kconfig                           |  12 +
>>  drivers/mmc/host/Makefile                          |   1 +
>>  drivers/mmc/host/rda-mmc.c                         | 853 
>> +++++++++++++++++++++
>>  drivers/power/reset/Kconfig                        |   9 +
>>  drivers/power/reset/Makefile                       |   1 +
>>  drivers/power/reset/rda-reboot.c                   |  58 ++
>>  drivers/rtc/Kconfig                                |  11 +
>>  drivers/rtc/Makefile                               |   1 +
>>  drivers/rtc/rtc-rda.c                              | 356 +++++++++
>>  include/dt-bindings/clock/rda,8810pl-apclk.h       |  79 ++
>>  include/dt-bindings/dma/rda-ifc.h                  |  28 +
>>  include/linux/rtc.h                                |   1 +
>>  31 files changed, 3079 insertions(+), 23 deletions(-)
>> ---
>> base-commit: 590b221ed4256fd6c34d3dea77aa5bd6e741bbc1
>> change-id: 20250916-rda8810pl-drivers-9a5271452635
>> 
>> Best regards,
>> --
>> Dang Huynh <dang.huynh@mainlining.org>
>> 
>> 

^ permalink raw reply

* Re: [PATCH 05/25] dt-bindings: rtc: Add RDA Micro RDA8810PL RTC
From: Dang Huynh @ 2025-09-18  4:11 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Linus Walleij, Bartosz Golaszewski,
	Alexandre Belloni, Michael Turquette, Stephen Boyd, Philipp Zabel,
	Sebastian Reichel, Vinod Koul, Kees Cook, Gustavo A. R. Silva,
	Ulf Hansson, linux-arm-kernel, linux-unisoc, devicetree,
	linux-kernel, linux-gpio, linux-rtc, linux-clk, linux-pm,
	dmaengine, linux-hardening, linux-mmc
In-Reply-To: <20250917-contort-sassy-df07fd7515a0@spud>

On 2025-09-18 03:46, Conor Dooley wrote:
> On Wed, Sep 17, 2025 at 03:07:22AM +0700, Dang Huynh wrote:
>> Add documentation describing the RTC found in RDA8810PL SoC.
>> 
>> Signed-off-by: Dang Huynh <dang.huynh@mainlining.org>
>> ---
>>  .../devicetree/bindings/rtc/rda,8810pl-rtc.yaml    | 30 
>> ++++++++++++++++++++++
>>  1 file changed, 30 insertions(+)
>> 
>> diff --git a/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml 
>> b/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
>> new file mode 100644
>> index 
>> 0000000000000000000000000000000000000000..3ceae294921cc3211cd775d9b3890393196faf82
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/rtc/rda,8810pl-rtc.yaml
>> @@ -0,0 +1,30 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/rtc/rda,8810pl-rtc.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: RDA Micro RDA8810PL Real Time Clock
>> +
>> +maintainers:
>> +  - Dang Huynh <dang.huynh@mainlining.org>
>> +
>> +properties:
>> +  compatible:
>> +    const: rda,8810pl-rtc
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +required:
>> +  - compatible
>> +  - reg
> 
> Your driver implements functions that turn on an alarm irq, but there 
> is
> none mentioned here. What's going on there?
The RTC doesn't seem to have an AP IRQ associated. I can't find any
reference to it on downstream kernel and the docs.

> 
> Additionally, there's no clocks property? For an onboard RTC I'd have
> expected there to be a clock sourced outside of the block.
> 
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    rtc@1a06000 {
>> +      compatible = "rda,8810pl-rtc";
>> +      reg = <0x1a06000 0x1000>;
>> +    };
>> 
>> --
>> 2.51.0

^ permalink raw reply

* Re: [PATCH 03/25] dt-bindings: gpio: rda: Make interrupts optional
From: Conor Dooley @ 2025-09-17 20:47 UTC (permalink / raw)
  To: Dang Huynh
  Cc: Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Linus Walleij, Bartosz Golaszewski,
	Alexandre Belloni, Michael Turquette, Stephen Boyd, Philipp Zabel,
	Sebastian Reichel, Vinod Koul, Kees Cook, Gustavo A. R. Silva,
	Ulf Hansson, linux-arm-kernel, linux-unisoc, devicetree,
	linux-kernel, linux-gpio, linux-rtc, linux-clk, linux-pm,
	dmaengine, linux-hardening, linux-mmc
In-Reply-To: <20250917-rda8810pl-drivers-v1-3-74866def1fe3@mainlining.org>

[-- Attachment #1: Type: text/plain, Size: 52 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox