git: a2ae5a27ce08 - main - clk: Add a clknode method to get and set the phase

From: Emmanuel Vadot <manu_at_FreeBSD.org>
Date: Fri, 30 Oct 2026 07:35:24 UTC
The branch main has been updated by manu:

URL: https://cgit.FreeBSD.org/src/commit/?id=a2ae5a27ce0898221e2fdbf7fdf2aee6a9925096

commit a2ae5a27ce0898221e2fdbf7fdf2aee6a9925096
Author:     Emmanuel Vadot <manu@FreeBSD.org>
AuthorDate: 2026-10-20 08:09:18 +0000
Commit:     Emmanuel Vadot <manu@FreeBSD.org>
CommitDate: 2026-10-30 07:35:11 +0000

    clk: Add a clknode method to get and set the phase
    
    Add clknode_get_phase/clknode_set_phase (and the clk_get_phase and
    clk_set_phase consumer API) so that clocks which can shift their phase,
    such as the MMC sample and drive clocks of some SoCs, can expose it.
    
    Reviewed by:    mmel
    Differential Revision:  https://reviews.freebsd.org/D60883
---
 sys/dev/clk/clk.c        | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/clk/clk.h        |  4 ++++
 sys/dev/clk/clknode_if.m | 20 +++++++++++++++++
 3 files changed, 82 insertions(+)

diff --git a/sys/dev/clk/clk.c b/sys/dev/clk/clk.c
index 5c74d84cacc8..e2073dfe7f99 100644
--- a/sys/dev/clk/clk.c
+++ b/sys/dev/clk/clk.c
@@ -1228,6 +1228,64 @@ clk_test_freq(clk_t clk, uint64_t freq, int flags)
 	return (rv);
 }
 
+int
+clknode_set_phase(struct clknode *clknode, int degrees)
+{
+	int rv;
+
+	CLK_TOPO_ASSERT();
+
+	CLKNODE_XLOCK(clknode);
+	rv = CLKNODE_SET_PHASE(clknode, degrees);
+	CLKNODE_UNLOCK(clknode);
+	return (rv);
+}
+
+int
+clknode_get_phase(struct clknode *clknode, int *degrees)
+{
+	int rv;
+
+	CLK_TOPO_ASSERT();
+
+	CLKNODE_XLOCK(clknode);
+	rv = CLKNODE_GET_PHASE(clknode, degrees);
+	CLKNODE_UNLOCK(clknode);
+	return (rv);
+}
+
+int
+clk_set_phase(clk_t clk, int degrees)
+{
+	int rv;
+	struct clknode *clknode;
+
+	clknode = clk->clknode;
+	KASSERT(clknode->ref_cnt > 0,
+	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
+
+	CLK_TOPO_XLOCK();
+	rv = clknode_set_phase(clknode, degrees);
+	CLK_TOPO_UNLOCK();
+	return (rv);
+}
+
+int
+clk_get_phase(clk_t clk, int *degrees)
+{
+	int rv;
+	struct clknode *clknode;
+
+	clknode = clk->clknode;
+	KASSERT(clknode->ref_cnt > 0,
+	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
+
+	CLK_TOPO_SLOCK();
+	rv = clknode_get_phase(clknode, degrees);
+	CLK_TOPO_UNLOCK();
+	return (rv);
+}
+
 int
 clk_get_parent(clk_t clk, clk_t *parent)
 {
diff --git a/sys/dev/clk/clk.h b/sys/dev/clk/clk.h
index 4702e8741a67..6f9aa75b46dd 100644
--- a/sys/dev/clk/clk.h
+++ b/sys/dev/clk/clk.h
@@ -116,6 +116,8 @@ int clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags,
     int enablecnt);
 int clknode_test_freq(struct clknode *clknode, uint64_t freq, int flags,
     int enablecnt, uint64_t *out_freq);
+int clknode_set_phase(struct clknode *clknode, int degrees);
+int clknode_get_phase(struct clknode *clknode, int *degrees);
 int clknode_enable(struct clknode *clknode);
 int clknode_disable(struct clknode *clknode);
 int clknode_stop(struct clknode *clknode, int depth);
@@ -129,6 +131,8 @@ int clk_release(clk_t clk);
 int clk_get_freq(clk_t clk, uint64_t *freq);
 int clk_set_freq(clk_t clk, uint64_t freq, int flags);
 int clk_test_freq(clk_t clk, uint64_t freq, int flags);
+int clk_set_phase(clk_t clk, int degrees);
+int clk_get_phase(clk_t clk, int *degrees);
 int clk_enable(clk_t clk);
 int clk_disable(clk_t clk);
 int clk_stop(clk_t clk);
diff --git a/sys/dev/clk/clknode_if.m b/sys/dev/clk/clknode_if.m
index 7269ee03bd74..95b0f64bee41 100644
--- a/sys/dev/clk/clknode_if.m
+++ b/sys/dev/clk/clknode_if.m
@@ -87,3 +87,23 @@ METHOD int set_mux {
 	struct clknode	*clk;
 	int		idx;
 };
+
+#
+# Set clock phase (in degrees)
+#   Return: ENXIO - method is not implemented
+#	    0 - success
+#
+METHOD int set_phase {
+	struct clknode	*clk;
+	int		degrees;
+};
+
+#
+# Get clock phase (in degrees)
+#   Return: ENXIO - method is not implemented
+#	    0 - success
+#
+METHOD int get_phase {
+	struct clknode	*clk;
+	int		*degrees;
+};