linux-rtc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/1] rtc: ds1307: add support for clock provider in ds1307
@ 2025-08-19 10:46 Akhilesh Patil
  2025-08-19 10:47 ` [PATCH 1/1] " Akhilesh Patil
  0 siblings, 1 reply; 2+ messages in thread
From: Akhilesh Patil @ 2025-08-19 10:46 UTC (permalink / raw)
  To: alexandre.belloni, mturquette, sboyd
  Cc: linux-rtc, linux-clk, linux-kernel, akhileshpatilvnit, skhan

Hi all, 

This work adds support for square-wave output from ds1307 rtc chip. 
ds1307 rtc supports generating 4 rates of square wave output signal,
1, 4096, 8192, 32768 Hz. This output can be controlled by device
register - CONTROL_REGISTER at I2C address 0x7 as follows: 
OUT [7] : control default state of SQW/OUT pin if clock output is disabled.
SQWE [4] : Enable/Disable output clock
RS [1:0] : Select the rate for output clock.

Other devices can use this clock via DT and Common Clock Framework.

I have done testing and validation using CCF's debugfs interface.
Below are the details of test/validation done for this patch.

*** Test setup

Hardware:
* I am using Texas Instruments AM62x SK board (ARM64 based SoC)
* ds1307 RTC hardware module.
* I have connected ds1307 module at I2C0 bus of am62x available
at 40pin user expansion connector headers.
SDA --> pin 27
SCL --> pin 28
No pull up needed as board already have pull ups on I2C0 lines.
* 24MHz logic analyzer to see the waveforms and validate frequency.

Kernel:
* v6.17-rc2
* define CLOCK_ALLOW_WRITE_DEBUGFS manually in drivers/clk/clk.c
so that we can use debugfs interface to test setting clock rates.
Note: This config is intentionally kept manual in the kernel and 
should be defined manually only.

*** Validation steps: 

Step 1: Probe the module
$ modprobe rtc-ds1307

Step 2: Mount debugfs
$ mount -t debugfs none /sys/kernel/debug

Step 3: Instantiate device
$ echo "ds1307 0x68" > /sys/class/i2c-dev/i2c-0/device/new_device

Step 4: read initial rate
$ cat /sys/kernel/debug/clk/ds1307_clk_sqw/clk_rate
1

Step 5: Set rate to 8192 and enable square-wave output
$ echo 8192 > /sys/kernel/debug/clk/ds1307_clk_sqw/clk_rate
$ echo 1 > /sys/kernel/debug/clk/ds1307_clk_sqw/clk_prepare_enable

Step 6: Verify rate
$ cat /sys/kernel/debug/clk/ds1307_clk_sqw/clk_rate
8192
Validate output clock using logic analyzer.
Probe at pin #7 (SQW/OUT) of ds1307 chip.

Step 7: delete the device
$ echo "0x68" > /sys/class/i2c-dev/i2c-0/device/delete_device

Step 8: use i2ctools to direct read device register 0x7
$ i2cget -y 0 0x68 0x7
0x12
0x12 shows that clock is enabled with frequency 8192Hz by our driver.

step 9: Redo Step 3 through 8 for various supported rates
I have put few important debug printk() on various callbacks
to validate codepaths. Below is testing log for various random rates. 

$ echo 81929999 > /sys/kernel/debug/clk/ds1307_clk
[  913.107859] ds1307 determine rate callback rate:
[  913.114978] DS1307 set rate callback
[  913.119598] ds1307 recalc rate callback rate: 1

$ echo 10 > /sys/kernel/debug/clk/ds1307_clk
[  976.439016] ds1307 determine rate callback rate:
[  976.446192] DS1307 set rate callback
[  976.450849] ds1307 recalc rate callback rate: 4096

$ echo 5000 > /sys/kernel/debug/clk/ds1307_clk
[  991.732748] ds1307 determine rate callback rate:
[  991.739954] DS1307 set rate callback
[  991.744576] ds1307 recalc rate callback rate: 8192

$ echo 9000 > /sys/kernel/debug/clk/ds1307_clk
[ 1007.463786] ds1307 determine rate callback rate:
[ 1007.471000] DS1307 set rate callback
[ 1007.475636] ds1307 recalc rate callback rate: 32768

$ echo 40000 > /sys/kernel/debug/clk/ds1307_clk
[ 1020.292701] ds1307 determine rate callback rate:
[ 1020.299934] DS1307 set rate callback
[ 1020.304563] ds1307 recalc rate callback rate: 1

Regards,
Akhilesh

Akhilesh Patil (1):
  rtc: ds1307: add support for clock provider in ds1307

 drivers/rtc/rtc-ds1307.c | 139 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 137 insertions(+), 2 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH 1/1] rtc: ds1307: add support for clock provider in ds1307
  2025-08-19 10:46 [PATCH 0/1] rtc: ds1307: add support for clock provider in ds1307 Akhilesh Patil
@ 2025-08-19 10:47 ` Akhilesh Patil
  0 siblings, 0 replies; 2+ messages in thread
From: Akhilesh Patil @ 2025-08-19 10:47 UTC (permalink / raw)
  To: alexandre.belloni, mturquette, sboyd
  Cc: linux-rtc, linux-clk, linux-kernel, akhileshpatilvnit, skhan

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@ee.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


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2025-08-19 10:47 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-19 10:46 [PATCH 0/1] rtc: ds1307: add support for clock provider in ds1307 Akhilesh Patil
2025-08-19 10:47 ` [PATCH 1/1] " Akhilesh Patil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).