From: "Stefan Dösinger" <stefandoesinger@gmail.com>
To: Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Philipp Zabel <p.zabel@pengutronix.de>,
Brian Masney <bmasney@redhat.com>
Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
"Stefan Dösinger" <stefandoesinger@gmail.com>
Subject: [PATCH RFC v5 07/12] clk: zte: Add regmap based clocks
Date: Sun, 28 Jun 2026 22:59:02 +0300 [thread overview]
Message-ID: <20260628-zx29clk-v5-7-79ff044e4192@gmail.com> (raw)
In-Reply-To: <20260628-zx29clk-v5-0-79ff044e4192@gmail.com>
This is based on meson/clk-regmap.c, although slightly simplified. I
have kept the copyright lines at the top of the file to indicate its
origin.
I see that numerous clock drivers have their own incarnation of regmap
based mux/div/gate clocks. If there is any version of it that is likely
to be elevated to shared code liks clk-gate.c I'll copy that and try to
use it as unmodified as possible.
Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
---
Version 5: Use regmap_test_bits in zte_clk_regmap_gate_is_enabled
---
drivers/clk/zte/clk-regmap.c | 221 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 218 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/zte/clk-regmap.c b/drivers/clk/zte/clk-regmap.c
index 7908f1562f63..903998ca9508 100644
--- a/drivers/clk/zte/clk-regmap.c
+++ b/drivers/clk/zte/clk-regmap.c
@@ -6,25 +6,240 @@
* Author: Stefan Dösinger <stefandoesinger@gmail.com>
*/
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+
#include "clk-zx.h"
+struct zte_clk_regmap {
+ struct clk_hw hw;
+ struct regmap *map;
+ u16 reg;
+ u8 shift;
+ u8 size;
+};
+
+static inline struct zte_clk_regmap *to_zte_clk_regmap(struct clk_hw *hw)
+{
+ return container_of(hw, struct zte_clk_regmap, hw);
+}
+
+static int zte_clk_regmap_gate_enable(struct clk_hw *hw)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+ return regmap_set_bits(clk->map, clk->reg, BIT(clk->shift));
+}
+
+static void zte_clk_regmap_gate_disable(struct clk_hw *hw)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+ regmap_clear_bits(clk->map, clk->reg, BIT(clk->shift));
+}
+
+static int zte_clk_regmap_gate_is_enabled(struct clk_hw *hw)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+ return regmap_test_bits(clk->map, clk->reg, BIT(clk->shift));
+}
+
+static const struct clk_ops zte_clk_regmap_gate_ops = {
+ .enable = zte_clk_regmap_gate_enable,
+ .disable = zte_clk_regmap_gate_disable,
+ .is_enabled = zte_clk_regmap_gate_is_enabled,
+};
+
int zx_clk_register_gates(struct device *dev, struct regmap *regmap,
const struct zx_gate_desc *desc, unsigned int num,
struct clk_hw_onecell_data *clocks)
{
- return -ENODEV;
+ struct zte_clk_regmap *clk;
+ unsigned int i;
+ int res;
+
+ for (i = 0; i < num; ++i) {
+ struct clk_init_data init = {};
+
+ clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return -ENOMEM;
+
+ init.name = desc[i].name;
+ init.ops = &zte_clk_regmap_gate_ops;
+ init.parent_names = &desc[i].parent;
+ init.num_parents = 1;
+ init.flags = CLK_SET_RATE_PARENT | desc[i].flags;
+ clk->hw.init = &init;
+ clk->map = regmap;
+ clk->reg = desc[i].reg;
+ clk->shift = desc[i].shift;
+ clk->size = 1;
+
+ res = devm_clk_hw_register(dev, &clk->hw);
+ if (res)
+ return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].name);
+
+ if (desc[i].id)
+ clocks->hws[desc[i].id] = &clk->hw;
+ }
+
+ return 0;
+}
+
+static unsigned long zte_clk_regmap_div_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(clk->map, clk->reg, &val);
+ if (ret)
+ /* Gives a hint that something is wrong */
+ return 0;
+
+ val >>= clk->shift;
+ val &= clk_div_mask(clk->size);
+ return divider_recalc_rate(hw, prate, val, NULL, 0, clk->size);
}
+static int zte_clk_regmap_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+ return divider_determine_rate(hw, req, NULL, clk->size, 0);
+}
+
+static int zte_clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+ unsigned int val;
+ int ret;
+
+ ret = divider_get_val(rate, parent_rate, NULL, clk->size, 0);
+ if (ret < 0)
+ return ret;
+
+ val = (unsigned int)ret << clk->shift;
+ return regmap_update_bits(clk->map, clk->reg, clk_div_mask(clk->size) << clk->shift, val);
+};
+
+static const struct clk_ops zte_clk_regmap_divider_ops = {
+ .recalc_rate = zte_clk_regmap_div_recalc_rate,
+ .determine_rate = zte_clk_regmap_div_determine_rate,
+ .set_rate = zte_clk_regmap_div_set_rate,
+};
+
int zx_clk_register_dividers(struct device *dev, struct regmap *regmap,
const struct zx_div_desc *desc, unsigned int num,
struct clk_hw_onecell_data *clocks)
{
- return -ENODEV;
+ struct zte_clk_regmap *clk;
+ unsigned int i;
+ int res;
+
+ for (i = 0; i < num; ++i) {
+ struct clk_init_data init = {};
+
+ clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return -ENOMEM;
+
+ init.name = desc[i].name;
+ init.ops = &zte_clk_regmap_divider_ops;
+ init.parent_names = &desc[i].parent;
+ init.num_parents = 1;
+ init.flags = CLK_SET_RATE_PARENT;
+ clk->hw.init = &init;
+ clk->map = regmap;
+ clk->reg = desc[i].reg;
+ clk->shift = desc[i].shift;
+ clk->size = desc[i].size;
+
+ res = devm_clk_hw_register(dev, &clk->hw);
+ if (res)
+ return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].name);
+
+ if (desc[i].id)
+ clocks->hws[desc[i].id] = &clk->hw;
+ }
+
+ return 0;
}
+static u8 zte_clk_regmap_mux_get_parent(struct clk_hw *hw)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(clk->map, clk->reg, &val);
+ if (ret)
+ return 0xff;
+
+ val >>= clk->shift;
+ val &= GENMASK(clk->size - 1, 0);
+ return clk_mux_val_to_index(hw, NULL, 0, val);
+}
+
+static int zte_clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+ unsigned int val = clk_mux_index_to_val(NULL, 0, index);
+
+ return regmap_update_bits(clk->map, clk->reg,
+ GENMASK(clk->size - 1, 0) << clk->shift,
+ val << clk->shift);
+}
+
+static int zte_clk_regmap_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ return clk_mux_determine_rate_flags(hw, req, 0);
+}
+
+static const struct clk_ops zte_clk_regmap_mux_ops = {
+ .get_parent = zte_clk_regmap_mux_get_parent,
+ .set_parent = zte_clk_regmap_mux_set_parent,
+ .determine_rate = zte_clk_regmap_mux_determine_rate,
+};
+
int zx_clk_register_muxes(struct device *dev, struct regmap *regmap,
const struct zx_mux_desc *desc, unsigned int num,
struct clk_hw_onecell_data *clocks)
{
- return -ENODEV;
+ struct zte_clk_regmap *clk;
+ unsigned int i;
+ int res;
+
+ for (i = 0; i < num; ++i) {
+ struct clk_init_data init = {};
+
+ clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return -ENOMEM;
+
+ init.name = desc[i].name;
+ init.ops = &zte_clk_regmap_mux_ops;
+ init.parent_names = desc[i].parents;
+ init.num_parents = desc[i].num_parents;
+ clk->hw.init = &init;
+ clk->map = regmap;
+ clk->reg = desc[i].reg;
+ clk->shift = desc[i].shift;
+ clk->size = desc[i].size;
+
+ res = devm_clk_hw_register(dev, &clk->hw);
+ if (res)
+ return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].name);
+
+ if (desc[i].id)
+ clocks->hws[desc[i].id] = &clk->hw;
+ }
+
+ return 0;
}
--
2.53.0
next prev parent reply other threads:[~2026-06-28 19:59 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-28 19:58 [PATCH RFC v5 00/12] ZTE zx297520v3 clock bindings and driver Stefan Dösinger
2026-06-28 19:58 ` [PATCH RFC v5 01/12] dt-bindings: soc: zte: Add zx297520v3 top clock and reset bindings Stefan Dösinger
2026-06-28 20:12 ` sashiko-bot
2026-06-28 19:58 ` [PATCH RFC v5 02/12] dt-bindings: soc: zte: Add zx297520v3 matrix " Stefan Dösinger
2026-06-28 20:09 ` sashiko-bot
2026-06-28 19:58 ` [PATCH RFC v5 03/12] dt-bindings: clk: zte: Add zx297520v3 LSP " Stefan Dösinger
2026-06-28 19:58 ` [PATCH RFC v5 04/12] mfd: zx297520v3: Add a clock and reset MFD driver Stefan Dösinger
2026-06-28 20:10 ` sashiko-bot
2026-06-28 19:59 ` [PATCH RFC v5 05/12] clk: zte: Add Clock registration infrastructure Stefan Dösinger
2026-06-28 20:10 ` sashiko-bot
2026-06-30 8:27 ` Philipp Zabel
2026-06-30 8:53 ` Stefan Dösinger
2026-07-02 9:01 ` Philipp Zabel
2026-06-28 19:59 ` [PATCH RFC v5 06/12] clk: zte: Add zx PLL support infrastructure Stefan Dösinger
2026-06-28 20:14 ` sashiko-bot
2026-06-28 19:59 ` Stefan Dösinger [this message]
2026-06-28 20:28 ` [PATCH RFC v5 07/12] clk: zte: Add regmap based clocks sashiko-bot
2026-06-28 19:59 ` [PATCH RFC v5 08/12] clk: zte: Introduce a driver for zx297520v3 top clocks Stefan Dösinger
2026-06-28 20:16 ` sashiko-bot
2026-06-28 19:59 ` [PATCH RFC v5 09/12] clk: zte: Introduce a driver for zx297520v3 matrix clocks Stefan Dösinger
2026-06-28 20:12 ` sashiko-bot
2026-06-28 19:59 ` [PATCH RFC v5 10/12] clk: zte: Introduce a driver for zx297520v3 LSP clocks and resets Stefan Dösinger
2026-06-28 20:18 ` sashiko-bot
2026-06-28 19:59 ` [PATCH RFC v5 11/12] reset: zte: Add a zx297520v3 reset driver Stefan Dösinger
2026-06-28 20:23 ` sashiko-bot
2026-06-30 8:45 ` Philipp Zabel
2026-06-28 19:59 ` [PATCH RFC v5 12/12] ARM: dts: zte: Declare zx297520v3 CRM device nodes Stefan Dösinger
2026-06-29 15:49 ` [PATCH RFC v5 00/12] ZTE zx297520v3 clock bindings and driver Conor Dooley
2026-07-01 17:22 ` Stefan Dösinger
2026-07-02 19:05 ` Conor Dooley
2026-07-02 19:26 ` Stefan Dösinger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260628-zx29clk-v5-7-79ff044e4192@gmail.com \
--to=stefandoesinger@gmail.com \
--cc=bmasney@redhat.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mturquette@baylibre.com \
--cc=p.zabel@pengutronix.de \
--cc=robh@kernel.org \
--cc=sboyd@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.