kernel: split patches folder up into backport, pending and hack folders
[openwrt/openwrt.git] / target / linux / generic / pending-4.4 / 083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch
diff --git a/target/linux/generic/pending-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch b/target/linux/generic/pending-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);