summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/clk-mux.c2
-rw-r--r--drivers/clk/clk.c13
-rw-r--r--include/linux/clk-provider.h6
3 files changed, 20 insertions, 1 deletions
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 0811633fcc4d..2718b1139948 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -143,7 +143,7 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
init.ops = &clk_mux_ro_ops;
else
init.ops = &clk_mux_ops;
- init.flags = flags | CLK_IS_BASIC;
+ init.flags = flags | CLK_IS_BASIC | CLK_IS_BASIC_MUX;
init.parent_names = parent_names;
init.num_parents = num_parents;
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 02e75d4e0a77..91894db43c50 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1567,6 +1567,7 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
*/
int clk_set_parent(struct clk *clk, struct clk *parent)
{
+ struct clk *child;
int ret = 0;
u8 p_index = 0;
unsigned long p_rate = 0;
@@ -1593,6 +1594,18 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
goto out;
}
+ /* check two consecutive basic mux clocks */
+ if (clk->flags & CLK_IS_BASIC_MUX) {
+ hlist_for_each_entry(child, &clk->children, child_node) {
+ if (child->flags & CLK_IS_BASIC_MUX) {
+ pr_err("%s: failed to switch parent of %s due to child mux %s\n",
+ __func__, clk->name, child->name);
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+ }
+
/* try finding the new parent index */
if (parent) {
p_index = clk_fetch_parent_index(clk, parent);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 4e9f36a15033..0c71babde4a7 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -28,6 +28,12 @@
#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+/*
+ * Basic mux clk, can't switch parent while there is another basic mux clk
+ * being its child. Otherwise, a glitch might be propagated to downstream
+ * clocks through this child mux.
+ */
+#define CLK_IS_BASIC_MUX BIT(8)
struct clk_hw;