clk: Add write operation for clk_parent debugfs node
authorSam Protsenko <semen.protsenko@linaro.org>
Wed, 13 Oct 2021 17:20:42 +0000 (20:20 +0300)
committerStephen Boyd <sboyd@kernel.org>
Fri, 10 Dec 2021 01:27:24 +0000 (17:27 -0800)
Useful for testing mux clocks. One can write the index of the parent to
be set into clk_parent node, starting from 0. Example

    # cd /sys/kernel/debug/clk/mout_peri_bus
    # cat clk_possible_parents
      dout_shared0_div4 dout_shared1_div4
    # cat clk_parent
      dout_shared0_div4
    # echo 1 > clk_parent
    # cat clk_parent
      dout_shared1_div4

CLOCK_ALLOW_WRITE_DEBUGFS has to be defined in drivers/clk/clk.c in
order to use this feature.

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Fabio Estevam <festevam@gmail.com>
Acked-by: Michael Turquette <mturquette@baylibre.com>
Link: https://lore.kernel.org/r/20211013172042.10884-1-semen.protsenko@linaro.org
[sboyd@kernel.org: Collapse ifdefs]
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/clk.c

index f467d63..8ccedec 100644 (file)
@@ -3217,6 +3217,42 @@ static int current_parent_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(current_parent);
 
+#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
+static ssize_t current_parent_write(struct file *file, const char __user *ubuf,
+                                   size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       struct clk_core *core = s->private;
+       struct clk_core *parent;
+       u8 idx;
+       int err;
+
+       err = kstrtou8_from_user(ubuf, count, 0, &idx);
+       if (err < 0)
+               return err;
+
+       parent = clk_core_get_parent_by_index(core, idx);
+       if (!parent)
+               return -ENOENT;
+
+       clk_prepare_lock();
+       err = clk_core_set_parent_nolock(core, parent);
+       clk_prepare_unlock();
+       if (err)
+               return err;
+
+       return count;
+}
+
+static const struct file_operations current_parent_rw_fops = {
+       .open           = current_parent_open,
+       .write          = current_parent_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif
+
 static int clk_duty_cycle_show(struct seq_file *s, void *data)
 {
        struct clk_core *core = s->private;
@@ -3282,8 +3318,12 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
 #ifdef CLOCK_ALLOW_WRITE_DEBUGFS
        debugfs_create_file("clk_prepare_enable", 0644, root, core,
                            &clk_prepare_enable_fops);
-#endif
 
+       if (core->num_parents > 1)
+               debugfs_create_file("clk_parent", 0644, root, core,
+                                   &current_parent_rw_fops);
+       else
+#endif
        if (core->num_parents > 0)
                debugfs_create_file("clk_parent", 0444, root, core,
                                    &current_parent_fops);