Merge branches 'clk-doc', 'clk-renesas', 'clk-at91', 'clk-cleanup' and 'clk-debugfs...
[linux-2.6-microblaze.git] / drivers / clk / clk.c
index d9414a7..c3c4849 100644 (file)
@@ -2966,7 +2966,9 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
 {
        struct clk_core *child;
 
+       clk_pm_runtime_get(c);
        clk_summary_show_one(s, c, level);
+       clk_pm_runtime_put(c);
 
        hlist_for_each_entry(child, &c->children, child_node)
                clk_summary_show_subtree(s, child, level + 1);
@@ -3218,6 +3220,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;
@@ -3283,8 +3321,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);
@@ -3344,6 +3386,24 @@ static int __init clk_debug_init(void)
 {
        struct clk_core *core;
 
+#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
+       pr_warn("\n");
+       pr_warn("********************************************************************\n");
+       pr_warn("**     NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE           **\n");
+       pr_warn("**                                                                **\n");
+       pr_warn("**  WRITEABLE clk DebugFS SUPPORT HAS BEEN ENABLED IN THIS KERNEL **\n");
+       pr_warn("**                                                                **\n");
+       pr_warn("** This means that this kernel is built to expose clk operations  **\n");
+       pr_warn("** such as parent or rate setting, enabling, disabling, etc.      **\n");
+       pr_warn("** to userspace, which may compromise security on your system.    **\n");
+       pr_warn("**                                                                **\n");
+       pr_warn("** If you see this message and you are not debugging the          **\n");
+       pr_warn("** kernel, report this immediately to your vendor!                **\n");
+       pr_warn("**                                                                **\n");
+       pr_warn("**     NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE           **\n");
+       pr_warn("********************************************************************\n");
+#endif
+
        rootdir = debugfs_create_dir("clk", NULL);
 
        debugfs_create_file("clk_summary", 0444, rootdir, &all_lists,