With MFD devices the clk properties may be contained in MFD (parent) DT node. Current devm_of_clk_add_hw_provider assumes the clk is bound to MFD subdevice not to MFD device (parent). Add devm_of_clk_add_hw_provider_parent to tackle this issue. Signed-off-by: Matti Vaittinen <matti.vaittinen@xxxxxxxxxxxxxxxxx> --- Documentation/driver-model/devres.txt | 1 + drivers/clk/clk.c | 65 ++++++++++++++++++++++++++++++----- include/linux/clk-provider.h | 11 ++++++ 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index dbf14326243b..97c9c575b2af 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -238,6 +238,7 @@ CLOCK devm_clk_put() devm_clk_hw_register() devm_of_clk_add_hw_provider() + devm_of_clk_add_parent_hw_provider() devm_clk_hw_register_clkdev() DMA diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index af011974d4ec..30beb60bd8f9 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3893,12 +3893,12 @@ static void devm_of_clk_release_provider(struct device *dev, void *res) of_clk_del_provider(*(struct device_node **)res); } -int devm_of_clk_add_hw_provider(struct device *dev, +static int __devm_of_clk_add_hw_provider(struct device *dev, struct clk_hw *(*get)(struct of_phandle_args *clkspec, void *data), - void *data) + struct device_node *of_node, void *data) { - struct device_node **ptr, *np; + struct device_node **ptr; int ret; ptr = devres_alloc(devm_of_clk_release_provider, sizeof(*ptr), @@ -3906,19 +3906,62 @@ int devm_of_clk_add_hw_provider(struct device *dev, if (!ptr) return -ENOMEM; - np = dev->of_node; - ret = of_clk_add_hw_provider(np, get, data); - if (!ret) { - *ptr = np; + *ptr = of_node; + ret = of_clk_add_hw_provider(of_node, get, data); + if (!ret) devres_add(dev, ptr); - } else { + else devres_free(ptr); - } return ret; } + +/** + * devm_of_clk_add_hw_provider() - Managed clk provider node registration + * @dev: Device acting as the clock provider. Used for DT node and lifetime. + * @get: callback for decoding clk_hw + * @data: context pointer for @get callback. + * + * Returns 0 on success or an errno on failure. + * + * Registers clock provider for given device's node. Provider is automatically + * released at device exit. + */ +int devm_of_clk_add_hw_provider(struct device *dev, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data) +{ + return __devm_of_clk_add_hw_provider(dev, get, dev->of_node, data); +} EXPORT_SYMBOL_GPL(devm_of_clk_add_hw_provider); +/** + * devm_of_clk_add_parent_hw_provider() - Managed clk provider node registration + * @dev: Device acting as the clock provider. Provider's DT node is parent node. + * @get: callback for decoding clk_hw + * @data: context pointer for @get callback. + * + * Returns 0 on success or an errno on failure. + * + * Registers clock provider for given device's parent node. Usable in cases + * where it really is the parent node that contains the provider information. + * Typical use-cases are MFD devices where the MFD sub-device is handling + * actual clock HW but the MFD node (parent) is containing the clock + * information. + * + * Provider is automatically released at device exit. + */ +int devm_of_clk_add_parent_hw_provider(struct device *dev, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data) +{ + return __devm_of_clk_add_hw_provider(dev, get, dev->parent->of_node, + data); +} +EXPORT_SYMBOL_GPL(devm_of_clk_add_parent_hw_provider); + /** * of_clk_del_provider() - Remove a previously registered clock provider * @np: Device node pointer associated with clock provider @@ -3950,6 +3993,10 @@ static int devm_clk_provider_match(struct device *dev, void *res, void *data) return *np == data; } +/** + * devm_of_clk_del_provider() - Remove clock provider registered using devm + * @dev: Device to whose lifetime the clock provider was bound + */ void devm_of_clk_del_provider(struct device *dev) { int ret; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 60c51871b04b..a6663f084cf1 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -916,6 +916,10 @@ int devm_of_clk_add_hw_provider(struct device *dev, struct clk_hw *(*get)(struct of_phandle_args *clkspec, void *data), void *data); +int devm_of_clk_add_parent_hw_provider(struct device *dev, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data); void of_clk_del_provider(struct device_node *np); void devm_of_clk_del_provider(struct device *dev); struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, @@ -953,6 +957,13 @@ static inline int devm_of_clk_add_hw_provider(struct device *dev, { return 0; } +static inline int devm_of_clk_add_parent_hw_provider(struct device *dev, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data) +{ + return 0; +} static inline void of_clk_del_provider(struct device_node *np) {} static inline void devm_of_clk_del_provider(struct device *dev) {} static inline struct clk *of_clk_src_simple_get( -- 2.14.3 -- Matti Vaittinen ROHM Semiconductors ~~~ "I don't think so," said Rene Descartes. Just then, he vanished ~~~