Merge branches 'clk-ti', 'clk-analog', 'clk-trace', 'clk-at91' and 'clk-silabs' into...
[linux-2.6-microblaze.git] / drivers / clk / clk.c
index f83dac5..8c1d04d 100644 (file)
@@ -420,7 +420,7 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
 static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
 {
        struct clk_parent_map *entry = &core->parents[index];
-       struct clk_core *parent = ERR_PTR(-ENOENT);
+       struct clk_core *parent;
 
        if (entry->hw) {
                parent = entry->hw->core;
@@ -2314,6 +2314,8 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
        if (!clk)
                return 0;
 
+       trace_clk_set_rate_range(clk->core, min, max);
+
        if (min > max) {
                pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n",
                       __func__, clk->core->name, clk->dev_id, clk->con_id,
@@ -2381,6 +2383,8 @@ int clk_set_min_rate(struct clk *clk, unsigned long rate)
        if (!clk)
                return 0;
 
+       trace_clk_set_min_rate(clk->core, rate);
+
        return clk_set_rate_range(clk, rate, clk->max_rate);
 }
 EXPORT_SYMBOL_GPL(clk_set_min_rate);
@@ -2397,6 +2401,8 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate)
        if (!clk)
                return 0;
 
+       trace_clk_set_max_rate(clk->core, rate);
+
        return clk_set_rate_range(clk, clk->min_rate, rate);
 }
 EXPORT_SYMBOL_GPL(clk_set_max_rate);
@@ -2931,7 +2937,14 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
        else
                seq_puts(s, "-----");
 
-       seq_printf(s, " %6d\n", clk_core_get_scaled_duty_cycle(c, 100000));
+       seq_printf(s, " %6d", clk_core_get_scaled_duty_cycle(c, 100000));
+
+       if (c->ops->is_enabled)
+               seq_printf(s, " %9c\n", clk_core_is_enabled(c) ? 'Y' : 'N');
+       else if (!c->ops->enable)
+               seq_printf(s, " %9c\n", 'Y');
+       else
+               seq_printf(s, " %9c\n", '?');
 }
 
 static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@@ -2950,9 +2963,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
        struct clk_core *c;
        struct hlist_head **lists = (struct hlist_head **)s->private;
 
-       seq_puts(s, "                                 enable  prepare  protect                                duty\n");
-       seq_puts(s, "   clock                          count    count    count        rate   accuracy phase  cycle\n");
-       seq_puts(s, "---------------------------------------------------------------------------------------------\n");
+       seq_puts(s, "                                 enable  prepare  protect                                duty  hardware\n");
+       seq_puts(s, "   clock                          count    count    count        rate   accuracy phase  cycle    enable\n");
+       seq_puts(s, "-------------------------------------------------------------------------------------------------------\n");
 
        clk_prepare_lock();
 
@@ -3667,6 +3680,24 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
        return clk;
 }
 
+/**
+ * clk_hw_get_clk - get clk consumer given an clk_hw
+ * @hw: clk_hw associated with the clk being consumed
+ * @con_id: connection ID string on device
+ *
+ * Returns: new clk consumer
+ * This is the function to be used by providers which need
+ * to get a consumer clk and act on the clock element
+ * Calls to this function must be balanced with calls clk_put()
+ */
+struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id)
+{
+       struct device *dev = hw->core->dev;
+
+       return clk_hw_create_clk(dev, hw, dev_name(dev), con_id);
+}
+EXPORT_SYMBOL(clk_hw_get_clk);
+
 static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist)
 {
        const char *dst;
@@ -4068,12 +4099,12 @@ void clk_hw_unregister(struct clk_hw *hw)
 }
 EXPORT_SYMBOL_GPL(clk_hw_unregister);
 
-static void devm_clk_release(struct device *dev, void *res)
+static void devm_clk_unregister_cb(struct device *dev, void *res)
 {
        clk_unregister(*(struct clk **)res);
 }
 
-static void devm_clk_hw_release(struct device *dev, void *res)
+static void devm_clk_hw_unregister_cb(struct device *dev, void *res)
 {
        clk_hw_unregister(*(struct clk_hw **)res);
 }
@@ -4093,7 +4124,7 @@ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw)
        struct clk *clk;
        struct clk **clkp;
 
-       clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL);
+       clkp = devres_alloc(devm_clk_unregister_cb, sizeof(*clkp), GFP_KERNEL);
        if (!clkp)
                return ERR_PTR(-ENOMEM);
 
@@ -4123,7 +4154,7 @@ int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
        struct clk_hw **hwp;
        int ret;
 
-       hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
+       hwp = devres_alloc(devm_clk_hw_unregister_cb, sizeof(*hwp), GFP_KERNEL);
        if (!hwp)
                return -ENOMEM;
 
@@ -4167,7 +4198,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data)
  */
 void devm_clk_unregister(struct device *dev, struct clk *clk)
 {
-       WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk));
+       WARN_ON(devres_release(dev, devm_clk_unregister_cb, devm_clk_match, clk));
 }
 EXPORT_SYMBOL_GPL(devm_clk_unregister);
 
@@ -4182,11 +4213,54 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
  */
 void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
 {
-       WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
+       WARN_ON(devres_release(dev, devm_clk_hw_unregister_cb, devm_clk_hw_match,
                                hw));
 }
 EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
 
+static void devm_clk_release(struct device *dev, void *res)
+{
+       clk_put(*(struct clk **)res);
+}
+
+/**
+ * devm_clk_hw_get_clk - resource managed clk_hw_get_clk()
+ * @dev: device that is registering this clock
+ * @hw: clk_hw associated with the clk being consumed
+ * @con_id: connection ID string on device
+ *
+ * Managed clk_hw_get_clk(). Clocks got with this function are
+ * automatically clk_put() on driver detach. See clk_put()
+ * for more information.
+ */
+struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw,
+                               const char *con_id)
+{
+       struct clk *clk;
+       struct clk **clkp;
+
+       /* This should not happen because it would mean we have drivers
+        * passing around clk_hw pointers instead of having the caller use
+        * proper clk_get() style APIs
+        */
+       WARN_ON_ONCE(dev != hw->core->dev);
+
+       clkp = devres_alloc(devm_clk_release, sizeof(*clkp), GFP_KERNEL);
+       if (!clkp)
+               return ERR_PTR(-ENOMEM);
+
+       clk = clk_hw_get_clk(hw, con_id);
+       if (!IS_ERR(clk)) {
+               *clkp = clk;
+               devres_add(dev, clkp);
+       } else {
+               devres_free(clkp);
+       }
+
+       return clk;
+}
+EXPORT_SYMBOL_GPL(devm_clk_hw_get_clk);
+
 /*
  * clkdev helpers
  */
@@ -4334,6 +4408,42 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(clk_notifier_unregister);
 
+struct clk_notifier_devres {
+       struct clk *clk;
+       struct notifier_block *nb;
+};
+
+static void devm_clk_notifier_release(struct device *dev, void *res)
+{
+       struct clk_notifier_devres *devres = res;
+
+       clk_notifier_unregister(devres->clk, devres->nb);
+}
+
+int devm_clk_notifier_register(struct device *dev, struct clk *clk,
+                              struct notifier_block *nb)
+{
+       struct clk_notifier_devres *devres;
+       int ret;
+
+       devres = devres_alloc(devm_clk_notifier_release,
+                             sizeof(*devres), GFP_KERNEL);
+
+       if (!devres)
+               return -ENOMEM;
+
+       ret = clk_notifier_register(clk, nb);
+       if (!ret) {
+               devres->clk = clk;
+               devres->nb = nb;
+       } else {
+               devres_free(devres);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(devm_clk_notifier_register);
+
 #ifdef CONFIG_OF
 static void clk_core_reparent_orphans(void)
 {