clk: provide devm_clk_get_optional_enabled_with_rate()
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 5 Aug 2024 08:57:31 +0000 (10:57 +0200)
committerStephen Boyd <sboyd@kernel.org>
Thu, 5 Sep 2024 20:51:46 +0000 (13:51 -0700)
There are clock users in the kernel that can't use
devm_clk_get_optional_enabled() as they need to set rate after getting
the clock and before enabling it. Provide a managed helper that wraps
these operations in the correct order.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Link: https://lore.kernel.org/r/20240805-clk-new-helper-v2-1-e5fdd1e1d729@linaro.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/clk-devres.c
include/linux/clk.h

index 90e6078fb6e1b2d524b3673da1077db3a43bc2ea..82ae1f26e634572b943d18b8d86267f0a69911a6 100644 (file)
@@ -99,6 +99,34 @@ struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
 }
 EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
 
+struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
+                                                   const char *id,
+                                                   unsigned long rate)
+{
+       struct clk *clk;
+       int ret;
+
+       clk = __devm_clk_get(dev, id, clk_get_optional, NULL,
+                            clk_disable_unprepare);
+       if (IS_ERR(clk))
+               return ERR_CAST(clk);
+
+       ret = clk_set_rate(clk, rate);
+       if (ret)
+               goto out_put_clk;
+
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               goto out_put_clk;
+
+       return clk;
+
+out_put_clk:
+       devm_clk_put(dev, clk);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled_with_rate);
+
 struct clk_bulk_devres {
        struct clk_bulk_data *clks;
        int num_clks;
index 0fa56d672532157290264c8dfa0a79dab94657bb..851a0f2cf42c8c1bbada49d991bc185587942155 100644 (file)
@@ -640,6 +640,32 @@ struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id);
  */
 struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id);
 
+/**
+ * devm_clk_get_optional_enabled_with_rate - devm_clk_get_optional() +
+ *                                           clk_set_rate() +
+ *                                           clk_prepare_enable()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ * @rate: new clock rate
+ *
+ * Context: May sleep.
+ *
+ * Return: 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.  If no such clk is found, it returns NULL
+ * which serves as a dummy clk.  That's the only difference compared
+ * to devm_clk_get_enabled().
+ *
+ * The returned clk (if valid) is prepared and enabled and rate was set.
+ *
+ * The clock will automatically be disabled, unprepared and freed
+ * when the device is unbound from the bus.
+ */
+struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
+                                                   const char *id,
+                                                   unsigned long rate);
+
 /**
  * devm_get_clk_from_child - lookup and obtain a managed reference to a
  *                          clock producer from child node.
@@ -982,6 +1008,13 @@ static inline struct clk *devm_clk_get_optional_enabled(struct device *dev,
        return NULL;
 }
 
+static inline struct clk *
+devm_clk_get_optional_enabled_with_rate(struct device *dev, const char *id,
+                                       unsigned long rate)
+{
+       return NULL;
+}
+
 static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
                                                 struct clk_bulk_data *clks)
 {