]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/clk/clk.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux.git] / drivers / clk / clk.c
index 772258de2d1f3c270e0c5747fb848be5e7c506e4..f0f2b599fd7e90a5faacc1499f28aa058ef79d0d 100644 (file)
@@ -429,7 +429,7 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
                        parent = ERR_PTR(-EPROBE_DEFER);
        } else {
                parent = clk_core_get(core, index);
-               if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT && entry->name)
+               if (PTR_ERR(parent) == -ENOENT && entry->name)
                        parent = clk_core_lookup(entry->name);
        }
 
@@ -2996,6 +2996,41 @@ static int clk_dump_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(clk_dump);
 
+#undef CLOCK_ALLOW_WRITE_DEBUGFS
+#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
+/*
+ * This can be dangerous, therefore don't provide any real compile time
+ * configuration option for this feature.
+ * People who want to use this will need to modify the source code directly.
+ */
+static int clk_rate_set(void *data, u64 val)
+{
+       struct clk_core *core = data;
+       int ret;
+
+       clk_prepare_lock();
+       ret = clk_core_set_rate_nolock(core, val);
+       clk_prepare_unlock();
+
+       return ret;
+}
+
+#define clk_rate_mode  0644
+#else
+#define clk_rate_set   NULL
+#define clk_rate_mode  0444
+#endif
+
+static int clk_rate_get(void *data, u64 *val)
+{
+       struct clk_core *core = data;
+
+       *val = core->rate;
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(clk_rate_fops, clk_rate_get, clk_rate_set, "%llu\n");
+
 static const struct {
        unsigned long flag;
        const char *name;
@@ -3145,7 +3180,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
        root = debugfs_create_dir(core->name, pdentry);
        core->dentry = root;
 
-       debugfs_create_ulong("clk_rate", 0444, root, &core->rate);
+       debugfs_create_file("clk_rate", clk_rate_mode, root, core,
+                           &clk_rate_fops);
        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);
@@ -3338,6 +3374,26 @@ static int __clk_core_init(struct clk_core *core)
                goto out;
        }
 
+       /*
+        * optional platform-specific magic
+        *
+        * The .init callback is not used by any of the basic clock types, but
+        * exists for weird hardware that must perform initialization magic for
+        * CCF to get an accurate view of clock for any other callbacks. It may
+        * also be used needs to perform dynamic allocations. Such allocation
+        * must be freed in the terminate() callback.
+        * This callback shall not be used to initialize the parameters state,
+        * such as rate, parent, etc ...
+        *
+        * If it exist, this callback should called before any other callback of
+        * the clock
+        */
+       if (core->ops->init) {
+               ret = core->ops->init(core->hw);
+               if (ret)
+                       goto out;
+       }
+
        core->parent = __clk_init_parent(core);
 
        /*
@@ -3362,17 +3418,6 @@ static int __clk_core_init(struct clk_core *core)
                core->orphan = true;
        }
 
-       /*
-        * optional platform-specific magic
-        *
-        * The .init callback is not used by any of the basic clock types, but
-        * exists for weird hardware that must perform initialization magic.
-        * Please consider other ways of solving initialization problems before
-        * using this callback, as its use is discouraged.
-        */
-       if (core->ops->init)
-               core->ops->init(core->hw);
-
        /*
         * Set clk's accuracy.  The preferred method is to use
         * .recalc_accuracy. For simple clocks and lazy developers the default
@@ -3427,13 +3472,18 @@ static int __clk_core_init(struct clk_core *core)
                unsigned long flags;
 
                ret = clk_core_prepare(core);
-               if (ret)
+               if (ret) {
+                       pr_warn("%s: critical clk '%s' failed to prepare\n",
+                              __func__, core->name);
                        goto out;
+               }
 
                flags = clk_enable_lock();
                ret = clk_core_enable(core);
                clk_enable_unlock(flags);
                if (ret) {
+                       pr_warn("%s: critical clk '%s' failed to enable\n",
+                              __func__, core->name);
                        clk_core_unprepare(core);
                        goto out;
                }
@@ -3732,6 +3782,28 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
        return ERR_PTR(ret);
 }
 
+/**
+ * dev_or_parent_of_node() - Get device node of @dev or @dev's parent
+ * @dev: Device to get device node of
+ *
+ * Return: device node pointer of @dev, or the device node pointer of
+ * @dev->parent if dev doesn't have a device node, or NULL if neither
+ * @dev or @dev->parent have a device node.
+ */
+static struct device_node *dev_or_parent_of_node(struct device *dev)
+{
+       struct device_node *np;
+
+       if (!dev)
+               return NULL;
+
+       np = dev_of_node(dev);
+       if (!np)
+               np = dev_of_node(dev->parent);
+
+       return np;
+}
+
 /**
  * clk_register - allocate a new clock, register it and return an opaque cookie
  * @dev: device that is registering this clock
@@ -3747,7 +3819,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
  */
 struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 {
-       return __clk_register(dev, dev_of_node(dev), hw);
+       return __clk_register(dev, dev_or_parent_of_node(dev), hw);
 }
 EXPORT_SYMBOL_GPL(clk_register);
 
@@ -3763,7 +3835,8 @@ EXPORT_SYMBOL_GPL(clk_register);
  */
 int clk_hw_register(struct device *dev, struct clk_hw *hw)
 {
-       return PTR_ERR_OR_ZERO(__clk_register(dev, dev_of_node(dev), hw));
+       return PTR_ERR_OR_ZERO(__clk_register(dev, dev_or_parent_of_node(dev),
+                              hw));
 }
 EXPORT_SYMBOL_GPL(clk_hw_register);
 
@@ -3866,6 +3939,7 @@ static void clk_core_evict_parent_cache(struct clk_core *core)
 void clk_unregister(struct clk *clk)
 {
        unsigned long flags;
+       const struct clk_ops *ops;
 
        if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
                return;
@@ -3874,7 +3948,8 @@ void clk_unregister(struct clk *clk)
 
        clk_prepare_lock();
 
-       if (clk->core->ops == &clk_nodrv_ops) {
+       ops = clk->core->ops;
+       if (ops == &clk_nodrv_ops) {
                pr_err("%s: unregistered clock: %s\n", __func__,
                       clk->core->name);
                goto unlock;
@@ -3887,6 +3962,9 @@ void clk_unregister(struct clk *clk)
        clk->core->ops = &clk_nodrv_ops;
        clk_enable_unlock(flags);
 
+       if (ops->terminate)
+               ops->terminate(clk->core->hw);
+
        if (!hlist_empty(&clk->core->children)) {
                struct clk_core *child;
                struct hlist_node *t;