[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210301110821.1445756-2-uwe@kleine-koenig.org>
Date: Mon, 1 Mar 2021 12:08:19 +0100
From: Uwe Kleine-König <uwe@...ine-koenig.org>
To: Michael Turquette <mturquette@...libre.com>,
Stephen Boyd <sboyd@...nel.org>
Cc: linux-pwm@...r.kernel.org, linux-clk@...r.kernel.org,
kernel@...gutronix.de, linux-kernel@...r.kernel.org,
Uwe Kleine-König
<u.kleine-koenig@...gutronix.de>
Subject: [PATCH v2 1/3] clk: generalize devm_clk_get() a bit
From: Uwe Kleine-König <u.kleine-koenig@...gutronix.de>
Allow to add an exit hook to devm managed clocks. Also use
clk_get_optional() in devm_clk_get_optional instead of open coding it.
The generalisation will be used in the next commit to add some more
devm_clk helpers.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@...gutronix.de>
---
drivers/clk/clk-devres.c | 75 +++++++++++++++++++++++++++++-----------
1 file changed, 54 insertions(+), 21 deletions(-)
diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index be160764911b..7ba8670deeb6 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -4,39 +4,72 @@
#include <linux/export.h>
#include <linux/gfp.h>
+struct devm_clk_state {
+ struct clk *clk;
+ void (*exit)(struct clk *clk);
+};
+
static void devm_clk_release(struct device *dev, void *res)
{
- clk_put(*(struct clk **)res);
+ struct devm_clk_state *state = *(struct devm_clk_state **)res;
+
+ if (state->exit)
+ state->exit(state->clk);
+
+ clk_put(state->clk);
+}
+
+struct clk *__devm_clk_get(struct device *dev, const char *id,
+ struct clk *(*get)(struct device *dev, const char *id),
+ int (*init)(struct clk *clk),
+ void (*exit)(struct clk *clk))
+{
+ struct devm_clk_state *state;
+ struct clk *clk;
+ int ret;
+
+ state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ clk = get(dev, id);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto err_clk_get;
+ }
+
+ if (init) {
+ ret = init(clk);
+ if (ret)
+ goto err_clk_init;
+ }
+
+ state->clk = clk;
+ state->exit = exit;
+
+ devres_add(dev, state);
+
+ return clk;
+
+err_clk_init:
+
+ clk_put(clk);
+err_clk_get:
+
+ devres_free(state);
+ return ERR_PTR(ret);
}
struct clk *devm_clk_get(struct device *dev, const char *id)
{
- struct clk **ptr, *clk;
+ return __devm_clk_get(dev, id, clk_get, NULL, NULL);
- ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
-
- clk = clk_get(dev, id);
- if (!IS_ERR(clk)) {
- *ptr = clk;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
-
- return clk;
}
EXPORT_SYMBOL(devm_clk_get);
struct clk *devm_clk_get_optional(struct device *dev, const char *id)
{
- struct clk *clk = devm_clk_get(dev, id);
-
- if (clk == ERR_PTR(-ENOENT))
- return NULL;
-
- return clk;
+ return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
}
EXPORT_SYMBOL(devm_clk_get_optional);
--
2.30.0
Powered by blists - more mailing lists