
Gate and mux does not have .set_rate operation, but they could have CLK_SET_PARENT_RATE flag set. In that case it's usually possible to find a parent up the tree which is capable of setting the rate (div, pll, etc). Add clk_generic_set_rate to allow them to trasverse the clock tree.
Cc: Sam Protsenko semen.protsenko@linaro.org Signed-off-by: Michael Trimarchi michael@amarulasolutions.com --- drivers/clk/clk-gate.c | 1 + drivers/clk/clk-mux.c | 2 +- drivers/clk/clk-uclass.c | 20 ++++++++++++++++++++ drivers/clk/clk.c | 9 +++++++++ 4 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index cfd90b717e7..c86083ac5a3 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -116,6 +116,7 @@ const struct clk_ops clk_gate_ops = { .enable = clk_gate_enable, .disable = clk_gate_disable, .get_rate = clk_generic_get_rate, + .set_rate = clk_generic_set_rate, };
struct clk *clk_register_gate(struct device *dev, const char *name, diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index e3481be95fa..f99a67ebd35 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -151,13 +151,13 @@ static int clk_mux_set_parent(struct clk *clk, struct clk *parent) #else writel(reg, mux->reg); #endif - return 0; }
const struct clk_ops clk_mux_ops = { .get_rate = clk_generic_get_rate, .set_parent = clk_mux_set_parent, + .set_rate = clk_generic_set_rate, };
struct clk *clk_hw_register_mux_table(struct device *dev, const char *name, diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index ed6e60bc484..638864e6774 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -517,6 +517,26 @@ ulong clk_get_parent_rate(struct clk *clk) return pclk->rate; }
+ulong clk_set_parent_rate(struct clk *clk, ulong rate) +{ + const struct clk_ops *ops; + struct clk *pclk; + + debug("%s(clk=%p)\n", __func__, clk); + if (!clk_valid(clk)) + return 0; + + pclk = clk_get_parent(clk); + if (IS_ERR(pclk)) + return -ENODEV; + + ops = clk_dev_ops(pclk->dev); + if (!ops->set_rate) + return -ENOSYS; + + return clk_set_rate(pclk, rate); +} + ulong clk_round_rate(struct clk *clk, ulong rate) { const struct clk_ops *ops; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 6ede1b4d4dc..febd5314df2 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -14,6 +14,7 @@ #include <dm/uclass.h> #include <dm/lists.h> #include <dm/device-internal.h> +#include <linux/clk-provider.h>
int clk_register(struct clk *clk, const char *drv_name, const char *name, const char *parent_name) @@ -61,6 +62,14 @@ ulong clk_generic_get_rate(struct clk *clk) return clk_get_parent_rate(clk); }
+ulong clk_generic_set_rate(struct clk *clk, ulong rate) +{ + if (clk->flags & CLK_SET_RATE_PARENT) + return clk_set_parent_rate(clk, rate); + + return clk_get_parent_rate(clk); +} + const char *clk_hw_get_name(const struct clk *hw) { assert(hw);