From 8965cf90f13767c1cbf716ceaf02e249a041fe13 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 26 Aug 2016 16:36:12 +0200 Subject: [PATCH] kernel: backport clk *_hw_* API for registering struct clk_hw MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- ...vm_-clk_hw_-register-unregister-APIs.patch | 182 ++++++++++++++ ...0002-clk-Add-clk_hw-OF-clk-providers.patch | 234 ++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch create mode 100644 target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch 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 index 0000000000..0408353138 --- /dev/null +++ b/target/linux/generic/patches-4.4/083-0001-clk-Add-devm_-clk_hw_-register-unregister-APIs.patch @@ -0,0 +1,182 @@ +From 4143804c4fdef40358c654d1fb2271a1a0f1fedf Mon Sep 17 00:00:00 2001 +From: Stephen Boyd +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 +--- + 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 index 0000000000..0bcb5bb805 --- /dev/null +++ b/target/linux/generic/patches-4.4/083-0002-clk-Add-clk_hw-OF-clk-providers.patch @@ -0,0 +1,234 @@ +From 0861e5b8cf80038e91942f1005c8dfce79d18c38 Mon Sep 17 00:00:00 2001 +From: Stephen Boyd +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 +--- + 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; -- 2.30.2