lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <6b44b47567e418a7bc3f68b626e287b8106641f3.1755599808.git.akhilesh@ee.iitb.ac.in>
Date: Tue, 19 Aug 2025 16:17:23 +0530
From: Akhilesh Patil <akhilesh@...iitb.ac.in>
To: alexandre.belloni@...tlin.com, mturquette@...libre.com,
	sboyd@...nel.org
Cc: linux-rtc@...r.kernel.org, linux-clk@...r.kernel.org,
	linux-kernel@...r.kernel.org, akhileshpatilvnit@...il.com,
	skhan@...uxfoundation.org
Subject: [PATCH 1/1] rtc: ds1307: add support for clock provider in ds1307

Add support for square-wave output for ds1307 rtc via
common clock framework clock provider.

tested on TI am62x SK board using ds1307 RTC hardware module.

Signed-off-by: Akhilesh Patil <akhilesh@...iitb.ac.in>
---
 drivers/rtc/rtc-ds1307.c | 139 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 137 insertions(+), 2 deletions(-)

diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 7205c59ff729..dd99b9a3836d 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -1658,18 +1658,153 @@ static int ds3231_clks_register(struct ds1307 *ds1307)
 	return 0;
 }
 
+/* ds1307 RTC clock output support */
+static unsigned long ds1307_clk_rates[] = {
+	1,
+	4096,
+	8192,
+	32768,
+};
+
+static unsigned long ds1307_clk_sqw_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	int ret;
+	unsigned int rate_id;
+	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+	ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &rate_id);
+	if (ret)
+		return ret;
+
+	rate_id &= (DS1307_BIT_RS1 | DS1307_BIT_RS0);
+
+	return ds1307_clk_rates[rate_id];
+}
+
+static int ds1307_clk_sqw_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ds1307_clk_rates); i++) {
+		if (req->rate <= ds1307_clk_rates[i]) {
+			req->rate = ds1307_clk_rates[i];
+			return 0;
+		}
+	}
+
+	/* Default rate 1Hz */
+	req->rate = ds1307_clk_rates[0];
+
+	return 0;
+}
+
+static int ds1307_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	int id, ret;
+	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+	for (id = 0; id < ARRAY_SIZE(ds1307_clk_rates); id++) {
+		if (ds1307_clk_rates[id] == rate)
+			break;
+	}
+
+	if (id >= ARRAY_SIZE(ds1307_clk_rates))
+		return -EINVAL;
+
+	ret = regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+				 DS1307_BIT_RS0 | DS1307_BIT_RS1, id);
+
+	return ret;
+}
+
+static int ds1307_clk_sqw_prepare(struct clk_hw *hw)
+{
+	int ret;
+	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+	ret = regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+				 DS1307_BIT_SQWE, DS1307_BIT_SQWE);
+
+	return ret;
+}
+
+static void ds1307_clk_sqw_unprepare(struct clk_hw *hw)
+{
+	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+	regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+			   DS1307_BIT_SQWE, ~DS1307_BIT_SQWE);
+}
+
+static int ds1307_clk_sqw_is_prepared(struct clk_hw *hw)
+{
+	int ret;
+	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+	unsigned int status;
+
+	ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &status);
+	if (ret)
+		return ret;
+
+	return !!(status & DS1307_BIT_SQWE);
+}
+
+static const struct clk_ops ds1307_clk_sqw_ops = {
+	.prepare = ds1307_clk_sqw_prepare,
+	.unprepare = ds1307_clk_sqw_unprepare,
+	.is_prepared = ds1307_clk_sqw_is_prepared,
+	.recalc_rate = ds1307_clk_sqw_recalc_rate,
+	.set_rate = ds1307_clk_sqw_set_rate,
+	.determine_rate = ds1307_clk_sqw_determine_rate,
+};
+
+static int rtc_ds1307_clks_register(struct ds1307 *ds1307)
+{
+	struct device_node *node = ds1307->dev->of_node;
+	struct clk *clk;
+	struct clk_init_data init = {0};
+
+	init.name = "ds1307_clk_sqw";
+	init.ops = &ds1307_clk_sqw_ops;
+
+	ds1307->clks[0].init = &init;
+
+	/* Register the clock with CCF */
+	clk = devm_clk_register(ds1307->dev, &ds1307->clks[0]);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	if (node)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	return 0;
+}
+
 static void ds1307_clks_register(struct ds1307 *ds1307)
 {
 	int ret;
 
-	if (ds1307->type != ds_3231)
+	switch (ds1307->type) {
+	case ds_3231:
+		ret = ds3231_clks_register(ds1307);
+		break;
+
+	case ds_1307:
+		ret = rtc_ds1307_clks_register(ds1307);
+		break;
+
+	default:
 		return;
+	}
 
-	ret = ds3231_clks_register(ds1307);
 	if (ret) {
 		dev_warn(ds1307->dev, "unable to register clock device %d\n",
 			 ret);
 	}
+
 }
 
 #else
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ