Merge branches 'clk-cdce-regulator', 'clk-bcm', 'clk-evict-parent-cache' and 'clk...
[sfrench/cifs-2.6.git] / drivers / clk / clk.c
index c0990703ce5403c1092bda6d982c56dffd70e6a0..498cae518147d83a1aee9fb64f3f292911df933d 100644 (file)
@@ -37,6 +37,12 @@ static HLIST_HEAD(clk_root_list);
 static HLIST_HEAD(clk_orphan_list);
 static LIST_HEAD(clk_notifier_list);
 
+static struct hlist_head *all_lists[] = {
+       &clk_root_list,
+       &clk_orphan_list,
+       NULL,
+};
+
 /***    private data structures    ***/
 
 struct clk_parent_map {
@@ -593,6 +599,8 @@ static void clk_core_get_boundaries(struct clk_core *core,
 {
        struct clk *clk_user;
 
+       lockdep_assert_held(&prepare_lock);
+
        *min_rate = core->min_rate;
        *max_rate = core->max_rate;
 
@@ -2437,7 +2445,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
        if (core->parent == parent)
                return 0;
 
-       /* verify ops for for multi-parent clks */
+       /* verify ops for multi-parent clks */
        if (core->num_parents > 1 && !core->ops->set_parent)
                return -EPERM;
 
@@ -2487,6 +2495,12 @@ runtime_put:
        return ret;
 }
 
+int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *parent)
+{
+       return clk_core_set_parent_nolock(hw->core, parent->core);
+}
+EXPORT_SYMBOL_GPL(clk_hw_set_parent);
+
 /**
  * clk_set_parent - switch the parent of a mux clk
  * @clk: the mux clk whose input we are switching
@@ -2833,12 +2847,6 @@ static int inited = 0;
 static DEFINE_MUTEX(clk_debug_lock);
 static HLIST_HEAD(clk_debug_list);
 
-static struct hlist_head *all_lists[] = {
-       &clk_root_list,
-       &clk_orphan_list,
-       NULL,
-};
-
 static struct hlist_head *orphan_list[] = {
        &clk_orphan_list,
        NULL,
@@ -2847,9 +2855,6 @@ static struct hlist_head *orphan_list[] = {
 static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
                                 int level)
 {
-       if (!c)
-               return;
-
        seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n",
                   level * 3 + 1, "",
                   30 - level * 3, c->name,
@@ -2864,9 +2869,6 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
 {
        struct clk_core *child;
 
-       if (!c)
-               return;
-
        clk_summary_show_one(s, c, level);
 
        hlist_for_each_entry(child, &c->children, child_node)
@@ -2896,8 +2898,9 @@ DEFINE_SHOW_ATTRIBUTE(clk_summary);
 
 static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
 {
-       if (!c)
-               return;
+       unsigned long min_rate, max_rate;
+
+       clk_core_get_boundaries(c, &min_rate, &max_rate);
 
        /* This should be JSON format, i.e. elements separated with a comma */
        seq_printf(s, "\"%s\": { ", c->name);
@@ -2905,6 +2908,8 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
        seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
        seq_printf(s, "\"protect_count\": %d,", c->protect_count);
        seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
+       seq_printf(s, "\"min_rate\": %lu,", min_rate);
+       seq_printf(s, "\"max_rate\": %lu,", max_rate);
        seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
        seq_printf(s, "\"phase\": %d,", clk_core_get_phase(c));
        seq_printf(s, "\"duty_cycle\": %u",
@@ -2915,9 +2920,6 @@ static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
 {
        struct clk_core *child;
 
-       if (!c)
-               return;
-
        clk_dump_one(s, c, level);
 
        hlist_for_each_entry(child, &c->children, child_node) {
@@ -3013,15 +3015,15 @@ static void possible_parent_show(struct seq_file *s, struct clk_core *core,
         */
        parent = clk_core_get_parent_by_index(core, i);
        if (parent)
-               seq_printf(s, "%s", parent->name);
+               seq_puts(s, parent->name);
        else if (core->parents[i].name)
-               seq_printf(s, "%s", core->parents[i].name);
+               seq_puts(s, core->parents[i].name);
        else if (core->parents[i].fw_name)
                seq_printf(s, "<%s>(fw)", core->parents[i].fw_name);
        else if (core->parents[i].index >= 0)
-               seq_printf(s, "%s",
-                          of_clk_get_parent_name(core->of_node,
-                                                 core->parents[i].index));
+               seq_puts(s,
+                        of_clk_get_parent_name(core->of_node,
+                                               core->parents[i].index));
        else
                seq_puts(s, "(missing)");
 
@@ -3064,6 +3066,34 @@ static int clk_duty_cycle_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle);
 
+static int clk_min_rate_show(struct seq_file *s, void *data)
+{
+       struct clk_core *core = s->private;
+       unsigned long min_rate, max_rate;
+
+       clk_prepare_lock();
+       clk_core_get_boundaries(core, &min_rate, &max_rate);
+       clk_prepare_unlock();
+       seq_printf(s, "%lu\n", min_rate);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(clk_min_rate);
+
+static int clk_max_rate_show(struct seq_file *s, void *data)
+{
+       struct clk_core *core = s->private;
+       unsigned long min_rate, max_rate;
+
+       clk_prepare_lock();
+       clk_core_get_boundaries(core, &min_rate, &max_rate);
+       clk_prepare_unlock();
+       seq_printf(s, "%lu\n", max_rate);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(clk_max_rate);
+
 static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
 {
        struct dentry *root;
@@ -3075,6 +3105,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
        core->dentry = root;
 
        debugfs_create_ulong("clk_rate", 0444, root, &core->rate);
+       debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops);
+       debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops);
        debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy);
        debugfs_create_u32("clk_phase", 0444, root, &core->phase);
        debugfs_create_file("clk_flags", 0444, root, core, &clk_flags_fops);
@@ -3484,9 +3516,9 @@ static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist)
        return 0;
 }
 
-static int clk_core_populate_parent_map(struct clk_core *core)
+static int clk_core_populate_parent_map(struct clk_core *core,
+                                       const struct clk_init_data *init)
 {
-       const struct clk_init_data *init = core->hw->init;
        u8 num_parents = init->num_parents;
        const char * const *parent_names = init->parent_names;
        const struct clk_hw **parent_hws = init->parent_hws;
@@ -3566,6 +3598,14 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
 {
        int ret;
        struct clk_core *core;
+       const struct clk_init_data *init = hw->init;
+
+       /*
+        * The init data is not supposed to be used outside of registration path.
+        * Set it to NULL so that provider drivers can't use it either and so that
+        * we catch use of hw->init early on in the core.
+        */
+       hw->init = NULL;
 
        core = kzalloc(sizeof(*core), GFP_KERNEL);
        if (!core) {
@@ -3573,17 +3613,17 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
                goto fail_out;
        }
 
-       core->name = kstrdup_const(hw->init->name, GFP_KERNEL);
+       core->name = kstrdup_const(init->name, GFP_KERNEL);
        if (!core->name) {
                ret = -ENOMEM;
                goto fail_name;
        }
 
-       if (WARN_ON(!hw->init->ops)) {
+       if (WARN_ON(!init->ops)) {
                ret = -EINVAL;
                goto fail_ops;
        }
-       core->ops = hw->init->ops;
+       core->ops = init->ops;
 
        if (dev && pm_runtime_enabled(dev))
                core->rpm_enabled = true;
@@ -3592,13 +3632,13 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
        if (dev && dev->driver)
                core->owner = dev->driver->owner;
        core->hw = hw;
-       core->flags = hw->init->flags;
-       core->num_parents = hw->init->num_parents;
+       core->flags = init->flags;
+       core->num_parents = init->num_parents;
        core->min_rate = 0;
        core->max_rate = ULONG_MAX;
        hw->core = core;
 
-       ret = clk_core_populate_parent_map(core);
+       ret = clk_core_populate_parent_map(core, init);
        if (ret)
                goto fail_parents;
 
@@ -3737,6 +3777,34 @@ static const struct clk_ops clk_nodrv_ops = {
        .set_parent     = clk_nodrv_set_parent,
 };
 
+static void clk_core_evict_parent_cache_subtree(struct clk_core *root,
+                                               struct clk_core *target)
+{
+       int i;
+       struct clk_core *child;
+
+       for (i = 0; i < root->num_parents; i++)
+               if (root->parents[i].core == target)
+                       root->parents[i].core = NULL;
+
+       hlist_for_each_entry(child, &root->children, child_node)
+               clk_core_evict_parent_cache_subtree(child, target);
+}
+
+/* Remove this clk from all parent caches */
+static void clk_core_evict_parent_cache(struct clk_core *core)
+{
+       struct hlist_head **lists;
+       struct clk_core *root;
+
+       lockdep_assert_held(&prepare_lock);
+
+       for (lists = all_lists; *lists; lists++)
+               hlist_for_each_entry(root, *lists, child_node)
+                       clk_core_evict_parent_cache_subtree(root, core);
+
+}
+
 /**
  * clk_unregister - unregister a currently registered clock
  * @clk: clock to unregister
@@ -3775,6 +3843,8 @@ void clk_unregister(struct clk *clk)
                        clk_core_set_parent_nolock(child, NULL);
        }
 
+       clk_core_evict_parent_cache(clk->core);
+
        hlist_del_init(&clk->core->child_node);
 
        if (clk->core->prepare_count)
@@ -4316,12 +4386,43 @@ void devm_of_clk_del_provider(struct device *dev)
 }
 EXPORT_SYMBOL(devm_of_clk_del_provider);
 
-/*
- * Beware the return values when np is valid, but no clock provider is found.
- * If name == NULL, the function returns -ENOENT.
- * If name != NULL, the function returns -EINVAL. This is because
- * of_parse_phandle_with_args() is called even if of_property_match_string()
- * returns an error.
+/**
+ * of_parse_clkspec() - Parse a DT clock specifier for a given device node
+ * @np: device node to parse clock specifier from
+ * @index: index of phandle to parse clock out of. If index < 0, @name is used
+ * @name: clock name to find and parse. If name is NULL, the index is used
+ * @out_args: Result of parsing the clock specifier
+ *
+ * Parses a device node's "clocks" and "clock-names" properties to find the
+ * phandle and cells for the index or name that is desired. The resulting clock
+ * specifier is placed into @out_args, or an errno is returned when there's a
+ * parsing error. The @index argument is ignored if @name is non-NULL.
+ *
+ * Example:
+ *
+ * phandle1: clock-controller@1 {
+ *     #clock-cells = <2>;
+ * }
+ *
+ * phandle2: clock-controller@2 {
+ *     #clock-cells = <1>;
+ * }
+ *
+ * clock-consumer@3 {
+ *     clocks = <&phandle1 1 2 &phandle2 3>;
+ *     clock-names = "name1", "name2";
+ * }
+ *
+ * To get a device_node for `clock-controller@2' node you may call this
+ * function a few different ways:
+ *
+ *   of_parse_clkspec(clock-consumer@3, -1, "name2", &args);
+ *   of_parse_clkspec(clock-consumer@3, 1, NULL, &args);
+ *   of_parse_clkspec(clock-consumer@3, 1, "name2", &args);
+ *
+ * Return: 0 upon successfully parsing the clock specifier. Otherwise, -ENOENT
+ * if @name is NULL or -EINVAL if @name is non-NULL and it can't be found in
+ * the "clock-names" property of @np.
  */
 static int of_parse_clkspec(const struct device_node *np, int index,
                            const char *name, struct of_phandle_args *out_args)