@@ -3085,6 +3085,17 @@ int of_clk_parent_fill(struct device_node *np, const char **parents,
}
EXPORT_SYMBOL_GPL(of_clk_parent_fill);
+static void init_disabled_clk_provider(struct device_node *np)
+{
+ struct clk *clk;
+
+ clk = clk_register_fixed_rate(NULL, of_node_full_name(np), NULL, 0, 0);
+ if (IS_ERR(clk))
+ return;
+
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
struct clock_provider {
of_clk_init_cb_t clk_init_cb;
struct device_node *np;
@@ -3150,9 +3161,6 @@ void __init of_clk_init(const struct of_device_id *matches)
for_each_matching_node_and_match(np, matches, &match) {
struct clock_provider *parent;
- if (!of_device_is_available(np))
- continue;
-
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
if (!parent) {
list_for_each_entry_safe(clk_provider, next,
@@ -3165,7 +3173,18 @@ void __init of_clk_init(const struct of_device_id *matches)
return;
}
- parent->clk_init_cb = match->data;
+ /*
+ * Sometimes DT nodes are status = "disabled" but they're used
+ * by other clk providers. In that case we make the disabled
+ * provider return fixed rate clks with a frequency of 0 so
+ * that nothing is orphaned and drivers can still get all
+ * their clks.
+ */
+ if (!of_device_is_available(np)) {
+ parent->clk_init_cb = init_disabled_clk_provider;
+ } else {
+ parent->clk_init_cb = match->data;
+ }
parent->np = of_node_get(np);
list_add_tail(&parent->node, &clk_provider_list);
}