summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Jacques Hiblot <jjhiblot@ti.com>2019-10-22 14:00:04 +0200
committerLukasz Majewski <lukma@denx.de>2019-10-22 16:14:05 +0200
commit52720c536ffdbe0e6aece79840e2791d87204cf7 (patch)
tree190272b13beda559e06c6ad8c274014b1a267854
parent8a1661f20e6cdda682820eba9ccc79bff5a3d7f8 (diff)
downloadu-boot-52720c536ffdbe0e6aece79840e2791d87204cf7.tar.gz
u-boot-52720c536ffdbe0e6aece79840e2791d87204cf7.tar.xz
u-boot-52720c536ffdbe0e6aece79840e2791d87204cf7.zip
drivers: clk: Add a managed API to get clocks from the device-tree
Add devm_clk_get(), devm_clk_get_optional() to get clocks from the device-tree. The clocks is automatically released and the data structure freed when the device is unbound. Also add devm_clk_put() to release the clock and free the data structure manually. Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
-rw-r--r--drivers/clk/clk-uclass.c48
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c30
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h4
-rw-r--r--include/clk.h47
4 files changed, 95 insertions, 34 deletions
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 82a62c02d9..80346987b9 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -625,6 +625,54 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
return false;
}
+static void devm_clk_release(struct udevice *dev, void *res)
+{
+ clk_free(res);
+}
+
+static int devm_clk_match(struct udevice *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+struct clk *devm_clk_get(struct udevice *dev, const char *id)
+{
+ int rc;
+ struct clk *clk;
+
+ clk = devres_alloc(devm_clk_release, sizeof(struct clk), __GFP_ZERO);
+ if (unlikely(!clk))
+ return ERR_PTR(-ENOMEM);
+
+ rc = clk_get_by_name(dev, id, clk);
+ if (rc)
+ return ERR_PTR(rc);
+
+ devres_add(dev, clk);
+ return clk;
+}
+
+struct clk *devm_clk_get_optional(struct udevice *dev, const char *id)
+{
+ struct clk *clk = devm_clk_get(dev, id);
+
+ if (IS_ERR(clk))
+ return NULL;
+
+ return clk;
+}
+
+void devm_clk_put(struct udevice *dev, struct clk *clk)
+{
+ int rc;
+
+ if (!clk)
+ return;
+
+ rc = devres_release(dev, devm_clk_release, devm_clk_match, clk);
+ WARN_ON(rc);
+}
+
UCLASS_DRIVER(clk) = {
.id = UCLASS_CLK,
.name = "clk",
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
index 96b27e6e5a..883948355c 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c
@@ -3,36 +3,6 @@
#include <common.h>
#include "brcmnand_compat.h"
-struct clk *devm_clk_get(struct udevice *dev, const char *id)
-{
- struct clk *clk;
- int ret;
-
- clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
- if (!clk) {
- debug("%s: can't allocate clock\n", __func__);
- return ERR_PTR(-ENOMEM);
- }
-
- ret = clk_get_by_name(dev, id, clk);
- if (ret < 0) {
- debug("%s: can't get clock (ret = %d)!\n", __func__, ret);
- return ERR_PTR(ret);
- }
-
- return clk;
-}
-
-int clk_prepare_enable(struct clk *clk)
-{
- return clk_enable(clk);
-}
-
-void clk_disable_unprepare(struct clk *clk)
-{
- clk_disable(clk);
-}
-
static char *devm_kvasprintf(struct udevice *dev, gfp_t gfp, const char *fmt,
va_list ap)
{
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
index 02cab0f828..6f9bec7085 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h
@@ -6,10 +6,6 @@
#include <clk.h>
#include <dm.h>
-struct clk *devm_clk_get(struct udevice *dev, const char *id);
-int clk_prepare_enable(struct clk *clk);
-void clk_disable_unprepare(struct clk *clk);
-
char *devm_kasprintf(struct udevice *dev, gfp_t gfp, const char *fmt, ...);
#endif /* __BRCMNAND_COMPAT_H */
diff --git a/include/clk.h b/include/clk.h
index 6568865d40..9be3264113 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -155,6 +155,37 @@ int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk);
int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
/**
+ * devm_clk_get - lookup and obtain a managed reference to a clock producer.
+ * @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.)
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * devm_clk_get should not be called from within interrupt context.
+ *
+ * The clock will automatically be freed when the device is unbound
+ * from the bus.
+ */
+struct clk *devm_clk_get(struct udevice *dev, const char *id);
+
+/**
+ * devm_clk_get_optional - lookup and obtain a managed reference to an optional
+ * clock producer.
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as devm_clk_get() except where there is no clock producer.
+ * In this case, instead of returning -ENOENT, the function returns NULL.
+ */
+struct clk *devm_clk_get_optional(struct udevice *dev, const char *id);
+
+/**
* clk_release_all() - Disable (turn off)/Free an array of previously
* requested clocks.
*
@@ -168,6 +199,19 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
*/
int clk_release_all(struct clk *clk, int count);
+/**
+ * devm_clk_put - "free" a managed clock source
+ * @dev: device used to acquire the clock
+ * @clk: clock source acquired with devm_clk_get()
+ *
+ * Note: drivers must ensure that all clk_enable calls made on this
+ * clock source are balanced by clk_disable calls prior to calling
+ * this function.
+ *
+ * clk_put should not be called from within interrupt context.
+ */
+void devm_clk_put(struct udevice *dev, struct clk *clk);
+
#else
static inline int clk_get_by_index(struct udevice *dev, int index,
struct clk *clk)
@@ -379,3 +423,6 @@ int clk_get_by_id(ulong id, struct clk **clkp);
*/
bool clk_dev_binded(struct clk *clk);
#endif
+
+#define clk_prepare_enable(clk) clk_enable(clk)
+#define clk_disable_unprepare(clk) clk_disable(clk)