diff options
| author | Suraj Gupta <suraj.gupta2@amd.com> | 2026-01-17 00:57:23 +0530 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-01-21 18:57:07 -0800 |
| commit | 820ce0c8e98a8999f4c233ffb1ca92c27894614e (patch) | |
| tree | 7fcef9064dd7ab615d8d86adf72b673e6564d914 /drivers/clk | |
| parent | 8f0b4cce4481fb22653697cced8d0d04027cb1e8 (diff) | |
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>
Diffstat (limited to 'drivers/clk')
| -rw-r--r-- | drivers/clk/clk-devres.c | 50 |
1 files changed, 50 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; |
