mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-29 16:10:24 +09:00
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>
This commit is contained in:
parent
8a1661f20e
commit
52720c536f
@ -625,6 +625,54 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
|
|||||||
return false;
|
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) = {
|
UCLASS_DRIVER(clk) = {
|
||||||
.id = UCLASS_CLK,
|
.id = UCLASS_CLK,
|
||||||
.name = "clk",
|
.name = "clk",
|
||||||
|
@ -3,36 +3,6 @@
|
|||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include "brcmnand_compat.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,
|
static char *devm_kvasprintf(struct udevice *dev, gfp_t gfp, const char *fmt,
|
||||||
va_list ap)
|
va_list ap)
|
||||||
{
|
{
|
||||||
|
@ -6,10 +6,6 @@
|
|||||||
#include <clk.h>
|
#include <clk.h>
|
||||||
#include <dm.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, ...);
|
char *devm_kasprintf(struct udevice *dev, gfp_t gfp, const char *fmt, ...);
|
||||||
|
|
||||||
#endif /* __BRCMNAND_COMPAT_H */
|
#endif /* __BRCMNAND_COMPAT_H */
|
||||||
|
@ -154,6 +154,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);
|
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
|
* clk_release_all() - Disable (turn off)/Free an array of previously
|
||||||
* requested clocks.
|
* 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);
|
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
|
#else
|
||||||
static inline int clk_get_by_index(struct udevice *dev, int index,
|
static inline int clk_get_by_index(struct udevice *dev, int index,
|
||||||
struct clk *clk)
|
struct clk *clk)
|
||||||
@ -379,3 +423,6 @@ int clk_get_by_id(ulong id, struct clk **clkp);
|
|||||||
*/
|
*/
|
||||||
bool clk_dev_binded(struct clk *clk);
|
bool clk_dev_binded(struct clk *clk);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define clk_prepare_enable(clk) clk_enable(clk)
|
||||||
|
#define clk_disable_unprepare(clk) clk_disable(clk)
|
||||||
|
Loading…
Reference in New Issue
Block a user