diff options
| author | Suraj Gupta <suraj.gupta2@amd.com> | 2026-01-16 22:27:23 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-01-22 05:57:07 +0300 |
| commit | 820ce0c8e98a8999f4c233ffb1ca92c27894614e (patch) | |
| tree | 7fcef9064dd7ab615d8d86adf72b673e6564d914 | |
| parent | 8f0b4cce4481fb22653697cced8d0d04027cb1e8 (diff) | |
| download | linux-820ce0c8e98a8999f4c233ffb1ca92c27894614e.tar.xz | |
clk: Add devm_clk_bulk_get_optional_enable() helper
Add a new managed clock framework helper function that combines getting
optional bulk clocks and enabling them in a single operation.
The devm_clk_bulk_get_optional_enable() function simplifies the common
pattern where drivers need to get optional bulk clocks, prepare and enable
them, and have them automatically disabled/unprepared and freed when the
device is unbound.
This new API follows the established pattern of
devm_clk_bulk_get_all_enabled() and reduces boilerplate code in drivers
that manage multiple optional clocks.
Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Suraj Gupta <suraj.gupta2@amd.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
Acked-by: Stephen Boyd <sboyd@kernel.org>
Link: https://patch.msgid.link/20260116192725.972966-2-suraj.gupta2@amd.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/clk/clk-devres.c | 50 | ||||
| -rw-r--r-- | include/linux/clk.h | 23 |
2 files changed, 73 insertions, 0 deletions
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index 5368d92d9b39..994d5bc5168b 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -179,6 +179,56 @@ int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, } EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional); +static void devm_clk_bulk_release_enable(struct device *dev, void *res) +{ + struct clk_bulk_devres *devres = res; + + clk_bulk_disable_unprepare(devres->num_clks, devres->clks); + clk_bulk_put(devres->num_clks, devres->clks); +} + +static int __devm_clk_bulk_get_enable(struct device *dev, int num_clks, + struct clk_bulk_data *clks, bool optional) +{ + struct clk_bulk_devres *devres; + int ret; + + devres = devres_alloc(devm_clk_bulk_release_enable, + sizeof(*devres), GFP_KERNEL); + if (!devres) + return -ENOMEM; + + if (optional) + ret = clk_bulk_get_optional(dev, num_clks, clks); + else + ret = clk_bulk_get(dev, num_clks, clks); + if (ret) + goto err_clk_get; + + ret = clk_bulk_prepare_enable(num_clks, clks); + if (ret) + goto err_clk_prepare; + + devres->clks = clks; + devres->num_clks = num_clks; + devres_add(dev, devres); + + return 0; + +err_clk_prepare: + clk_bulk_put(num_clks, clks); +err_clk_get: + devres_free(devres); + return ret; +} + +int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks, + struct clk_bulk_data *clks) +{ + return __devm_clk_bulk_get_enable(dev, num_clks, clks, true); +} +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional_enable); + static void devm_clk_bulk_release_all(struct device *dev, void *res) { struct clk_bulk_devres *devres = res; diff --git a/include/linux/clk.h b/include/linux/clk.h index b607482ca77e..c571e294f0ef 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -479,6 +479,22 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, struct clk_bulk_data *clks); /** + * devm_clk_bulk_get_optional_enable - Get and enable optional bulk clocks (managed) + * @dev: device for clock "consumer" + * @num_clks: the number of clk_bulk_data + * @clks: pointer to the clk_bulk_data table of consumer + * + * Behaves the same as devm_clk_bulk_get_optional() but also prepares and enables + * the clocks in one operation with management. The clks will automatically be + * disabled, unprepared and freed when the device is unbound. + * + * Return: 0 if all clocks specified in clk_bulk_data table are obtained + * and enabled successfully, or for any clk there was no clk provider available. + * Otherwise returns valid IS_ERR() condition containing errno. + */ +int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks, + struct clk_bulk_data *clks); +/** * devm_clk_bulk_get_all - managed get multiple clk consumers * @dev: device for clock "consumer" * @clks: pointer to the clk_bulk_data table of consumer @@ -1029,6 +1045,13 @@ static inline int __must_check devm_clk_bulk_get_optional(struct device *dev, return 0; } +static inline int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, + int num_clks, + struct clk_bulk_data *clks) +{ + return 0; +} + static inline int __must_check devm_clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks) { |
