linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks
@ 2021-03-01 13:50 Uwe Kleine-König
  2021-03-01 13:50 ` [PATCH v3 1/3] clk: generalize devm_clk_get() a bit Uwe Kleine-König
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2021-03-01 13:50 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-pwm, linux-clk, kernel, linux-kernel

Hello,

this is a brown paper bag version (aka v3) of my series adding
devm_clk_get_enabled() et al.

Changes since v2 (sent with Message-Id:
20210301110821.1445756-1-uwe@kleine-koenig.org):

 - send it from the right email account to have the sender matching the
   SoB line
 - make __devm_clk_get static
 - fix EXPORT_SYMBOL usage

The last two were found by the kernel test robot.

Range-diff can be found below.

Best regards
Uwe

Uwe Kleine-König (3):
  clk: generalize devm_clk_get() a bit
  clk: Provide new devm_clk_helpers for prepared and enabled clocks
  pwm: atmel: Simplify using devm_clk_get_prepared()

 drivers/clk/clk-devres.c | 96 +++++++++++++++++++++++++++++++++-------
 drivers/pwm/pwm-atmel.c  | 15 +------
 include/linux/clk.h      | 87 +++++++++++++++++++++++++++++++++++-
 3 files changed, 168 insertions(+), 30 deletions(-)

Range-diff against v2:
1:  7203dc0837af ! 1:  3faadae49fed clk: generalize devm_clk_get a bit
    @@ drivers/clk/clk-devres.c
      }
      
     -struct clk *devm_clk_get(struct device *dev, const char *id)
    -+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))
    ++static 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 clk **ptr, *clk;
     +	struct devm_clk_state *state;
2:  4d2107992b8c ! 2:  82005b4a9ea1 clk: Provide new devm_clk_helpers for prepared and enabled clocks
    @@ drivers/clk/clk-devres.c: struct clk *devm_clk_get(struct device *dev, const cha
     +			      clk_prepare_enable, clk_disable_unprepare);
     +
     +}
    -+EXPORT_SYMBOL(devm_clk_get_prepared);
    ++EXPORT_SYMBOL(devm_clk_get_enabled);
     +
      struct clk *devm_clk_get_optional(struct device *dev, const char *id)
      {
    @@ drivers/clk/clk-devres.c: struct clk *devm_clk_get(struct device *dev, const cha
     +			      clk_prepare_enable, clk_disable_unprepare);
     +
     +}
    -+EXPORT_SYMBOL(devm_clk_get_optional_prepared);
    ++EXPORT_SYMBOL(devm_clk_get_optional_enabled);
     +
      struct clk_bulk_devres {
      	struct clk_bulk_data *clks;
3:  63f799a4ff32 = 3:  1f73d17d4da7 pwm: atmel: Simplify using devm_clk_get_prepared()

base-commit: fe07bfda2fb9cdef8a4d4008a409bb02f35f1bd8
-- 
2.30.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 1/3] clk: generalize devm_clk_get() a bit
  2021-03-01 13:50 [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König
@ 2021-03-01 13:50 ` Uwe Kleine-König
  2021-03-01 13:50 ` [PATCH v3 2/3] clk: Provide new devm_clk_helpers for prepared and enabled clocks Uwe Kleine-König
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2021-03-01 13:50 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-pwm, linux-clk, kernel, linux-kernel

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@pengutronix.de>
---
 drivers/clk/clk-devres.c | 67 ++++++++++++++++++++++++++++++----------
 1 file changed, 50 insertions(+), 17 deletions(-)

diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index be160764911b..91c995815b57 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)
+static 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 clk **ptr, *clk;
+	struct devm_clk_state *state;
+	struct clk *clk;
+	int ret;
 
-	ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
-	if (!ptr)
+	state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
+	if (!state)
 		return ERR_PTR(-ENOMEM);
 
-	clk = clk_get(dev, id);
-	if (!IS_ERR(clk)) {
-		*ptr = clk;
-		devres_add(dev, ptr);
-	} else {
-		devres_free(ptr);
+	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);
 }
-EXPORT_SYMBOL(devm_clk_get);
 
-struct clk *devm_clk_get_optional(struct device *dev, const char *id)
+struct clk *devm_clk_get(struct device *dev, const char *id)
 {
-	struct clk *clk = devm_clk_get(dev, id);
+	return __devm_clk_get(dev, id, clk_get, NULL, NULL);
 
-	if (clk == ERR_PTR(-ENOENT))
-		return NULL;
+}
+EXPORT_SYMBOL(devm_clk_get);
 
-	return clk;
+struct clk *devm_clk_get_optional(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
 }
 EXPORT_SYMBOL(devm_clk_get_optional);
 
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v3 2/3] clk: Provide new devm_clk_helpers for prepared and enabled clocks
  2021-03-01 13:50 [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König
  2021-03-01 13:50 ` [PATCH v3 1/3] clk: generalize devm_clk_get() a bit Uwe Kleine-König
@ 2021-03-01 13:50 ` Uwe Kleine-König
  2021-03-01 13:50 ` [PATCH v3 3/3] pwm: atmel: Simplify using devm_clk_get_prepared() Uwe Kleine-König
  2021-03-22 14:22 ` [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König
  3 siblings, 0 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2021-03-01 13:50 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-pwm, linux-clk, kernel, linux-kernel

When a driver keeps a clock prepared (or enabled) during the whole
lifetime of the driver, these helpers allow to simplify the drivers.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/clk/clk-devres.c | 31 ++++++++++++++
 include/linux/clk.h      | 87 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c
index 91c995815b57..b54f7f0f2a35 100644
--- a/drivers/clk/clk-devres.c
+++ b/drivers/clk/clk-devres.c
@@ -67,12 +67,43 @@ struct clk *devm_clk_get(struct device *dev, const char *id)
 }
 EXPORT_SYMBOL(devm_clk_get);
 
+struct clk *devm_clk_get_prepared(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_prepared);
+
+struct clk *devm_clk_get_enabled(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get,
+			      clk_prepare_enable, clk_disable_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_enabled);
+
 struct clk *devm_clk_get_optional(struct device *dev, const char *id)
 {
 	return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
 }
 EXPORT_SYMBOL(devm_clk_get_optional);
 
+struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get_optional,
+			      clk_prepare, clk_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_optional_prepared);
+
+struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
+{
+	return __devm_clk_get(dev, id, clk_get_optional,
+			      clk_prepare_enable, clk_disable_unprepare);
+
+}
+EXPORT_SYMBOL(devm_clk_get_optional_enabled);
+
 struct clk_bulk_devres {
 	struct clk_bulk_data *clks;
 	int num_clks;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 266e8de3cb51..b3c5da388b08 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -449,7 +449,7 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
  * the clock producer.  (IOW, @id may be identical strings, but
  * clk_get may return different clock producers depending on @dev.)
  *
- * Drivers must assume that the clock source is not enabled.
+ * Drivers must assume that the clock source is neither prepared nor enabled.
  *
  * devm_clk_get should not be called from within interrupt context.
  *
@@ -458,6 +458,47 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
  */
 struct clk *devm_clk_get(struct device *dev, const char *id);
 
+/**
+ * devm_clk_get_prepared - devm_clk_get() + clk_prepare()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno.  The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer.  (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * The returned clk (if valid) is prepared. Drivers must however assume that the
+ * clock is not enabled.
+ *
+ * devm_clk_get_prepared should not be called from within interrupt context.
+ *
+ * The clock will automatically be unprepared and freed when the
+ * device is unbound from the bus.
+ */
+struct clk *devm_clk_get_prepared(struct device *dev, const char *id);
+
+/**
+ * devm_clk_get_enabled - devm_clk_get() + clk_prepare_enable()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno.  The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer.  (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * The returned clk (if valid) is prepared and enabled.
+ *
+ * devm_clk_get_prepared should not be called from within interrupt context.
+ *
+ * The clock will automatically be disabled, unprepared and freed when the
+ * device is unbound from the bus.
+ */
+struct clk *devm_clk_get_enabled(struct device *dev, const char *id);
+
 /**
  * devm_clk_get_optional - lookup and obtain a managed reference to an optional
  *			   clock producer.
@@ -469,6 +510,26 @@ struct clk *devm_clk_get(struct device *dev, const char *id);
  */
 struct clk *devm_clk_get_optional(struct device *dev, const char *id);
 
+/**
+ * devm_clk_get_optional_prepared - devm_clk_get_optional() + clk_prepare()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as devm_clk_get_prepared() except where there is no clock producer.
+ * In this case, instead of returning -ENOENT, the function returns NULL.
+ */
+struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id);
+
+/**
+ * devm_clk_get_optional_enabled - devm_clk_get_optional() + clk_prepare_enable()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as devm_clk_get_enabled() except where there is no clock producer.
+ * In this case, instead of returning -ENOENT, the function returns NULL.
+ */
+struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id);
+
 /**
  * devm_get_clk_from_child - lookup and obtain a managed reference to a
  *			     clock producer from child node.
@@ -813,12 +874,36 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id)
 	return NULL;
 }
 
+static inline struct clk *devm_clk_get_prepared(struct device *dev,
+						const char *id)
+{
+	return NULL;
+}
+
+static inline struct clk *devm_clk_get_enabled(struct device *dev,
+					       const char *id)
+{
+	return NULL;
+}
+
 static inline struct clk *devm_clk_get_optional(struct device *dev,
 						const char *id)
 {
 	return NULL;
 }
 
+static inline struct clk *devm_clk_get_optional_prepared(struct device *dev,
+							 const char *id)
+{
+	return NULL;
+}
+
+static inline struct clk *devm_clk_get_optional_enabled(struct device *dev,
+							const char *id)
+{
+	return NULL;
+}
+
 static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
 						 struct clk_bulk_data *clks)
 {
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v3 3/3] pwm: atmel: Simplify using devm_clk_get_prepared()
  2021-03-01 13:50 [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König
  2021-03-01 13:50 ` [PATCH v3 1/3] clk: generalize devm_clk_get() a bit Uwe Kleine-König
  2021-03-01 13:50 ` [PATCH v3 2/3] clk: Provide new devm_clk_helpers for prepared and enabled clocks Uwe Kleine-König
@ 2021-03-01 13:50 ` Uwe Kleine-König
  2021-03-22 14:22 ` [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König
  3 siblings, 0 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2021-03-01 13:50 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-pwm, linux-clk, kernel, linux-kernel

With devm_clk_get_prepared() caring to unprepare the clock the error
path and remove callback can be simplified accordingly.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-atmel.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 5813339b597b..d65e23da2582 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -415,16 +415,10 @@ static int atmel_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(atmel_pwm->base))
 		return PTR_ERR(atmel_pwm->base);
 
-	atmel_pwm->clk = devm_clk_get(&pdev->dev, NULL);
+	atmel_pwm->clk = devm_clk_get_prepared(&pdev->dev, NULL);
 	if (IS_ERR(atmel_pwm->clk))
 		return PTR_ERR(atmel_pwm->clk);
 
-	ret = clk_prepare(atmel_pwm->clk);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to prepare PWM clock\n");
-		return ret;
-	}
-
 	atmel_pwm->chip.dev = &pdev->dev;
 	atmel_pwm->chip.ops = &atmel_pwm_ops;
 	atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
@@ -435,23 +429,18 @@ static int atmel_pwm_probe(struct platform_device *pdev)
 	ret = pwmchip_add(&atmel_pwm->chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret);
-		goto unprepare_clk;
+		return ret;
 	}
 
 	platform_set_drvdata(pdev, atmel_pwm);
 
 	return ret;
-
-unprepare_clk:
-	clk_unprepare(atmel_pwm->clk);
-	return ret;
 }
 
 static int atmel_pwm_remove(struct platform_device *pdev)
 {
 	struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev);
 
-	clk_unprepare(atmel_pwm->clk);
 	mutex_destroy(&atmel_pwm->isr_lock);
 
 	return pwmchip_remove(&atmel_pwm->chip);
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks
  2021-03-01 13:50 [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König
                   ` (2 preceding siblings ...)
  2021-03-01 13:50 ` [PATCH v3 3/3] pwm: atmel: Simplify using devm_clk_get_prepared() Uwe Kleine-König
@ 2021-03-22 14:22 ` Uwe Kleine-König
  3 siblings, 0 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2021-03-22 14:22 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: linux-pwm, linux-clk, kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 929 bytes --]

Hello,

On Mon, Mar 01, 2021 at 02:50:50PM +0100, Uwe Kleine-König wrote:
> Uwe Kleine-König (3):
>   clk: generalize devm_clk_get() a bit
>   clk: Provide new devm_clk_helpers for prepared and enabled clocks
>   pwm: atmel: Simplify using devm_clk_get_prepared()
> 
>  drivers/clk/clk-devres.c | 96 +++++++++++++++++++++++++++++++++-------
>  drivers/pwm/pwm-atmel.c  | 15 +------
>  include/linux/clk.h      | 87 +++++++++++++++++++++++++++++++++++-
>  3 files changed, 168 insertions(+), 30 deletions(-)

can I get some feedback on this series please? The idea is on the list
since October last year with absolutely no maintainer feedback.

I think it's a good idea and not too hard to review, so I wonder what is
stopping you.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-03-22 14:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-01 13:50 [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König
2021-03-01 13:50 ` [PATCH v3 1/3] clk: generalize devm_clk_get() a bit Uwe Kleine-König
2021-03-01 13:50 ` [PATCH v3 2/3] clk: Provide new devm_clk_helpers for prepared and enabled clocks Uwe Kleine-König
2021-03-01 13:50 ` [PATCH v3 3/3] pwm: atmel: Simplify using devm_clk_get_prepared() Uwe Kleine-König
2021-03-22 14:22 ` [PATCH v3 0/3] clk: provide new devm helpers for prepared and enabled clocks Uwe Kleine-König

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).