kernel: backport clk *_hw_* API for registering struct clk_hw
authorRafał Miłecki <rafal@milecki.pl>
Fri, 26 Aug 2016 14:36:12 +0000 (16:36 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Fri, 26 Aug 2016 14:37:59 +0000 (16:37 +0200)
Drivers have been modified to use it and new ones have to be written
this way, so we need it for backporting code.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch [new file with mode: 0644]
target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch [new file with mode: 0644]

diff --git a/target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch b/target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch
new file mode 100644 (file)
index 0000000..0408353
--- /dev/null
@@ -0,0 +1,182 @@
+From 4143804c4fdef40358c654d1fb2271a1a0f1fedf Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Fri, 5 Feb 2016 17:02:52 -0800
+Subject: [PATCH] clk: Add {devm_}clk_hw_{register,unregister}() APIs
+
+We've largely split the clk consumer and provider APIs along
+struct clk and struct clk_hw, but clk_register() still returns a
+struct clk pointer for each struct clk_hw that's registered.
+Eventually we'd like to only allocate struct clks when there's a
+user, because struct clk is per-user now, so clk_register() needs
+to change.
+
+Let's add new APIs to register struct clk_hws, but this time
+we'll hide the struct clk from the caller by returning an int
+error code. Also add an unregistration API that takes the clk_hw
+structure that was passed to the registration API. This way
+provider drivers never have to deal with a struct clk pointer
+unless they're using the clk consumer APIs.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ Documentation/driver-model/devres.txt |  1 +
+ drivers/clk/clk.c                     | 86 +++++++++++++++++++++++++++++++++++
+ include/linux/clk-provider.h          |  6 +++
+ 3 files changed, 93 insertions(+)
+
+--- a/Documentation/driver-model/devres.txt
++++ b/Documentation/driver-model/devres.txt
+@@ -236,6 +236,7 @@ certainly invest a bit more effort into
+ CLOCK
+   devm_clk_get()
+   devm_clk_put()
++  devm_clk_hw_register()
+ DMA
+   dmam_alloc_coherent()
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -2595,6 +2595,22 @@ fail_out:
+ }
+ EXPORT_SYMBOL_GPL(clk_register);
++/**
++ * clk_hw_register - register a clk_hw and return an error code
++ * @dev: device that is registering this clock
++ * @hw: link to hardware-specific clock data
++ *
++ * clk_hw_register is the primary interface for populating the clock tree with
++ * new clock nodes. It returns an integer equal to zero indicating success or
++ * less than zero indicating failure. Drivers must test for an error code after
++ * calling clk_hw_register().
++ */
++int clk_hw_register(struct device *dev, struct clk_hw *hw)
++{
++      return PTR_ERR_OR_ZERO(clk_register(dev, hw));
++}
++EXPORT_SYMBOL_GPL(clk_hw_register);
++
+ /* Free memory allocated for a clock. */
+ static void __clk_release(struct kref *ref)
+ {
+@@ -2696,11 +2712,26 @@ void clk_unregister(struct clk *clk)
+ }
+ EXPORT_SYMBOL_GPL(clk_unregister);
++/**
++ * clk_hw_unregister - unregister a currently registered clk_hw
++ * @hw: hardware-specific clock data to unregister
++ */
++void clk_hw_unregister(struct clk_hw *hw)
++{
++      clk_unregister(hw->clk);
++}
++EXPORT_SYMBOL_GPL(clk_hw_unregister);
++
+ static void devm_clk_release(struct device *dev, void *res)
+ {
+       clk_unregister(*(struct clk **)res);
+ }
++static void devm_clk_hw_release(struct device *dev, void *res)
++{
++      clk_hw_unregister(*(struct clk_hw **)res);
++}
++
+ /**
+  * devm_clk_register - resource managed clk_register()
+  * @dev: device that is registering this clock
+@@ -2731,6 +2762,36 @@ struct clk *devm_clk_register(struct dev
+ }
+ EXPORT_SYMBOL_GPL(devm_clk_register);
++/**
++ * devm_clk_hw_register - resource managed clk_hw_register()
++ * @dev: device that is registering this clock
++ * @hw: link to hardware-specific clock data
++ *
++ * Managed clk_hw_register(). Clocks returned from this function are
++ * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register()
++ * for more information.
++ */
++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);
++      if (!hwp)
++              return -ENOMEM;
++
++      ret = clk_hw_register(dev, hw);
++      if (!ret) {
++              *hwp = hw;
++              devres_add(dev, hwp);
++      } else {
++              devres_free(hwp);
++      }
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(devm_clk_hw_register);
++
+ static int devm_clk_match(struct device *dev, void *res, void *data)
+ {
+       struct clk *c = res;
+@@ -2739,6 +2800,15 @@ static int devm_clk_match(struct device
+       return c == data;
+ }
++static int devm_clk_hw_match(struct device *dev, void *res, void *data)
++{
++      struct clk_hw *hw = res;
++
++      if (WARN_ON(!hw))
++              return 0;
++      return hw == data;
++}
++
+ /**
+  * devm_clk_unregister - resource managed clk_unregister()
+  * @clk: clock to unregister
+@@ -2753,6 +2823,22 @@ void devm_clk_unregister(struct device *
+ }
+ EXPORT_SYMBOL_GPL(devm_clk_unregister);
++/**
++ * devm_clk_hw_unregister - resource managed clk_hw_unregister()
++ * @dev: device that is unregistering the hardware-specific clock data
++ * @hw: link to hardware-specific clock data
++ *
++ * Unregister a clk_hw registered with devm_clk_hw_register(). Normally
++ * this function will not need to be called and the resource management
++ * code will ensure that the resource is freed.
++ */
++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,
++                              hw));
++}
++EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
++
+ /*
+  * clkdev helpers
+  */
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -639,9 +639,15 @@ void of_gpio_mux_clk_setup(struct device
+ struct clk *clk_register(struct device *dev, struct clk_hw *hw);
+ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
++int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw);
++int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw);
++
+ void clk_unregister(struct clk *clk);
+ void devm_clk_unregister(struct device *dev, struct clk *clk);
++void clk_hw_unregister(struct clk_hw *hw);
++void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw);
++
+ /* helper functions */
+ const char *__clk_get_name(const struct clk *clk);
+ const char *clk_hw_get_name(const struct clk_hw *hw);
diff --git a/target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch b/target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch
new file mode 100644 (file)
index 0000000..0bcb5bb
--- /dev/null
@@ -0,0 +1,234 @@
+From 0861e5b8cf80038e91942f1005c8dfce79d18c38 Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Fri, 5 Feb 2016 17:38:26 -0800
+Subject: [PATCH] clk: Add clk_hw OF clk providers
+
+Now that we have a clk registration API that doesn't return
+struct clks, we need to have some way to hand out struct clks via
+the clk_get() APIs that doesn't involve associating struct clk
+pointers with an OF node. Currently we ask the OF provider to
+give us a struct clk pointer for some clkspec, turn that struct
+clk into a struct clk_hw and then allocate a new struct clk to
+return to the caller.
+
+Let's add a clk_hw based OF provider hook that returns a struct
+clk_hw directly, so that we skip the intermediate step of
+converting from struct clk to struct clk_hw. Eventually when
+we've converted all OF clk providers to struct clk_hw based APIs
+we can remove the struct clk based ones.
+
+It should also be noted that we change the onecell provider to
+have a flex array instead of a pointer for the array of clk_hw
+pointers. This allows providers to allocate one structure of the
+correct length in one step instead of two.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/clk.c            | 85 +++++++++++++++++++++++++++++++++++++++++---
+ include/linux/clk-provider.h | 30 ++++++++++++++++
+ 2 files changed, 111 insertions(+), 4 deletions(-)
+
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -3001,6 +3001,7 @@ struct of_clk_provider {
+       struct device_node *node;
+       struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
++      struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data);
+       void *data;
+ };
+@@ -3017,6 +3018,12 @@ struct clk *of_clk_src_simple_get(struct
+ }
+ EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
++struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
++{
++      return data;
++}
++EXPORT_SYMBOL_GPL(of_clk_hw_simple_get);
++
+ struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
+ {
+       struct clk_onecell_data *clk_data = data;
+@@ -3031,6 +3038,21 @@ struct clk *of_clk_src_onecell_get(struc
+ }
+ EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
++struct clk_hw *
++of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
++{
++      struct clk_hw_onecell_data *hw_data = data;
++      unsigned int idx = clkspec->args[0];
++
++      if (idx >= hw_data->num) {
++              pr_err("%s: invalid index %u\n", __func__, idx);
++              return ERR_PTR(-EINVAL);
++      }
++
++      return hw_data->hws[idx];
++}
++EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get);
++
+ /**
+  * of_clk_add_provider() - Register a clock provider for a node
+  * @np: Device node pointer associated with clock provider
+@@ -3067,6 +3089,41 @@ int of_clk_add_provider(struct device_no
+ EXPORT_SYMBOL_GPL(of_clk_add_provider);
+ /**
++ * of_clk_add_hw_provider() - Register a clock provider for a node
++ * @np: Device node pointer associated with clock provider
++ * @get: callback for decoding clk_hw
++ * @data: context pointer for @get callback.
++ */
++int of_clk_add_hw_provider(struct device_node *np,
++                         struct clk_hw *(*get)(struct of_phandle_args *clkspec,
++                                               void *data),
++                         void *data)
++{
++      struct of_clk_provider *cp;
++      int ret;
++
++      cp = kzalloc(sizeof(*cp), GFP_KERNEL);
++      if (!cp)
++              return -ENOMEM;
++
++      cp->node = of_node_get(np);
++      cp->data = data;
++      cp->get_hw = get;
++
++      mutex_lock(&of_clk_mutex);
++      list_add(&cp->link, &of_clk_providers);
++      mutex_unlock(&of_clk_mutex);
++      pr_debug("Added clk_hw provider from %s\n", np->full_name);
++
++      ret = of_clk_set_defaults(np, true);
++      if (ret < 0)
++              of_clk_del_provider(np);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(of_clk_add_hw_provider);
++
++/**
+  * of_clk_del_provider() - Remove a previously registered clock provider
+  * @np: Device node pointer associated with clock provider
+  */
+@@ -3087,11 +3144,32 @@ void of_clk_del_provider(struct device_n
+ }
+ EXPORT_SYMBOL_GPL(of_clk_del_provider);
++static struct clk_hw *
++__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
++                            struct of_phandle_args *clkspec)
++{
++      struct clk *clk;
++      struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
++
++      if (provider->get_hw) {
++              hw = provider->get_hw(clkspec, provider->data);
++      } else if (provider->get) {
++              clk = provider->get(clkspec, provider->data);
++              if (!IS_ERR(clk))
++                      hw = __clk_get_hw(clk);
++              else
++                      hw = ERR_CAST(clk);
++      }
++
++      return hw;
++}
++
+ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+                                      const char *dev_id, const char *con_id)
+ {
+       struct of_clk_provider *provider;
+       struct clk *clk = ERR_PTR(-EPROBE_DEFER);
++      struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
+       if (!clkspec)
+               return ERR_PTR(-EINVAL);
+@@ -3100,10 +3178,9 @@ struct clk *__of_clk_get_from_provider(s
+       mutex_lock(&of_clk_mutex);
+       list_for_each_entry(provider, &of_clk_providers, link) {
+               if (provider->node == clkspec->np)
+-                      clk = provider->get(clkspec, provider->data);
+-              if (!IS_ERR(clk)) {
+-                      clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
+-                                             con_id);
++                      hw = __of_clk_get_hw_from_provider(provider, clkspec);
++              if (!IS_ERR(hw)) {
++                      clk = __clk_create_clk(hw, dev_id, con_id);
+                       if (!IS_ERR(clk) && !__clk_get(clk)) {
+                               __clk_free_clk(clk);
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -693,6 +693,11 @@ struct clk_onecell_data {
+       unsigned int clk_num;
+ };
++struct clk_hw_onecell_data {
++      size_t num;
++      struct clk_hw *hws[];
++};
++
+ extern struct of_device_id __clk_of_table;
+ #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
+@@ -702,10 +707,19 @@ int of_clk_add_provider(struct device_no
+                       struct clk *(*clk_src_get)(struct of_phandle_args *args,
+                                                  void *data),
+                       void *data);
++int of_clk_add_hw_provider(struct device_node *np,
++                         struct clk_hw *(*get)(struct of_phandle_args *clkspec,
++                                               void *data),
++                         void *data);
+ void of_clk_del_provider(struct device_node *np);
+ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
+                                 void *data);
++
++struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec,
++                                  void *data);
+ struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
++struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec,
++                                   void *data);
+ int of_clk_get_parent_count(struct device_node *np);
+ int of_clk_parent_fill(struct device_node *np, const char **parents,
+                      unsigned int size);
+@@ -722,6 +736,13 @@ static inline int of_clk_add_provider(st
+ {
+       return 0;
+ }
++static inline int of_clk_add_hw_provider(struct device_node *np,
++                      struct clk_hw *(*get)(struct of_phandle_args *clkspec,
++                                            void *data),
++                      void *data)
++{
++      return 0;
++}
+ #define of_clk_del_provider(np) \
+       { while (0); }
+ static inline struct clk *of_clk_src_simple_get(
+@@ -729,11 +750,21 @@ static inline struct clk *of_clk_src_sim
+ {
+       return ERR_PTR(-ENOENT);
+ }
++static inline struct clk_hw *
++of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
++{
++      return ERR_PTR(-ENOENT);
++}
+ static inline struct clk *of_clk_src_onecell_get(
+       struct of_phandle_args *clkspec, void *data)
+ {
+       return ERR_PTR(-ENOENT);
+ }
++static inline struct clk_hw *
++of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
++{
++      return ERR_PTR(-ENOENT);
++}
+ static inline int of_clk_get_parent_count(struct device_node *np)
+ {
+       return 0;