Merge branch 'clk-parent-rewrite' (early part) into clk-next
* 'clk-parent-rewrite' (early part): clk: Move of_clk_*() APIs into clk.c from clkdev.c clk: Inform the core about consumer devices clk: Introduce of_clk_get_hw_from_clkspec() clk: core: clarify the check for runtime PM clk: Combine __clk_get() and __clk_create_clk()
This commit is contained in:
Коммит
5dc7e84268
|
@ -57,6 +57,7 @@ struct clk_core {
|
|||
struct clk_core *new_child;
|
||||
unsigned long flags;
|
||||
bool orphan;
|
||||
bool rpm_enabled;
|
||||
unsigned int enable_count;
|
||||
unsigned int prepare_count;
|
||||
unsigned int protect_count;
|
||||
|
@ -81,6 +82,7 @@ struct clk_core {
|
|||
|
||||
struct clk {
|
||||
struct clk_core *core;
|
||||
struct device *dev;
|
||||
const char *dev_id;
|
||||
const char *con_id;
|
||||
unsigned long min_rate;
|
||||
|
@ -92,9 +94,9 @@ struct clk {
|
|||
/*** runtime pm ***/
|
||||
static int clk_pm_runtime_get(struct clk_core *core)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (!core->dev)
|
||||
if (!core->rpm_enabled)
|
||||
return 0;
|
||||
|
||||
ret = pm_runtime_get_sync(core->dev);
|
||||
|
@ -103,7 +105,7 @@ static int clk_pm_runtime_get(struct clk_core *core)
|
|||
|
||||
static void clk_pm_runtime_put(struct clk_core *core)
|
||||
{
|
||||
if (!core->dev)
|
||||
if (!core->rpm_enabled)
|
||||
return;
|
||||
|
||||
pm_runtime_put_sync(core->dev);
|
||||
|
@ -223,7 +225,7 @@ static bool clk_core_is_enabled(struct clk_core *core)
|
|||
* taking enable spinlock, but the below check is needed if one tries
|
||||
* to call it from other places.
|
||||
*/
|
||||
if (core->dev) {
|
||||
if (core->rpm_enabled) {
|
||||
pm_runtime_get_noresume(core->dev);
|
||||
if (!pm_runtime_active(core->dev)) {
|
||||
ret = false;
|
||||
|
@ -233,7 +235,7 @@ static bool clk_core_is_enabled(struct clk_core *core)
|
|||
|
||||
ret = core->ops->is_enabled(core->hw);
|
||||
done:
|
||||
if (core->dev)
|
||||
if (core->rpm_enabled)
|
||||
pm_runtime_put(core->dev);
|
||||
|
||||
return ret;
|
||||
|
@ -3212,42 +3214,105 @@ unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
|
||||
/**
|
||||
* clk_core_link_consumer - Add a clk consumer to the list of consumers in a clk_core
|
||||
* @core: clk to add consumer to
|
||||
* @clk: consumer to link to a clk
|
||||
*/
|
||||
static void clk_core_link_consumer(struct clk_core *core, struct clk *clk)
|
||||
{
|
||||
clk_prepare_lock();
|
||||
hlist_add_head(&clk->clks_node, &core->clks);
|
||||
clk_prepare_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_core_unlink_consumer - Remove a clk consumer from the list of consumers in a clk_core
|
||||
* @clk: consumer to unlink
|
||||
*/
|
||||
static void clk_core_unlink_consumer(struct clk *clk)
|
||||
{
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
hlist_del(&clk->clks_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_clk - Allocate a clk consumer, but leave it unlinked to the clk_core
|
||||
* @core: clk to allocate a consumer for
|
||||
* @dev_id: string describing device name
|
||||
* @con_id: connection ID string on device
|
||||
*
|
||||
* Returns: clk consumer left unlinked from the consumer list
|
||||
*/
|
||||
static struct clk *alloc_clk(struct clk_core *core, const char *dev_id,
|
||||
const char *con_id)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
/* This is to allow this function to be chained to others */
|
||||
if (IS_ERR_OR_NULL(hw))
|
||||
return ERR_CAST(hw);
|
||||
|
||||
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
|
||||
if (!clk)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clk->core = hw->core;
|
||||
clk->core = core;
|
||||
clk->dev_id = dev_id;
|
||||
clk->con_id = kstrdup_const(con_id, GFP_KERNEL);
|
||||
clk->max_rate = ULONG_MAX;
|
||||
|
||||
clk_prepare_lock();
|
||||
hlist_add_head(&clk->clks_node, &hw->core->clks);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/* keep in sync with __clk_put */
|
||||
void __clk_free_clk(struct clk *clk)
|
||||
/**
|
||||
* free_clk - Free a clk consumer
|
||||
* @clk: clk consumer to free
|
||||
*
|
||||
* Note, this assumes the clk has been unlinked from the clk_core consumer
|
||||
* list.
|
||||
*/
|
||||
static void free_clk(struct clk *clk)
|
||||
{
|
||||
clk_prepare_lock();
|
||||
hlist_del(&clk->clks_node);
|
||||
clk_prepare_unlock();
|
||||
|
||||
kfree_const(clk->con_id);
|
||||
kfree(clk);
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_hw_create_clk: Allocate and link a clk consumer to a clk_core given
|
||||
* a clk_hw
|
||||
* @dev: clk consumer device
|
||||
* @hw: clk_hw associated with the clk being consumed
|
||||
* @dev_id: string describing device name
|
||||
* @con_id: connection ID string on device
|
||||
*
|
||||
* This is the main function used to create a clk pointer for use by clk
|
||||
* consumers. It connects a consumer to the clk_core and clk_hw structures
|
||||
* used by the framework and clk provider respectively.
|
||||
*/
|
||||
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||
const char *dev_id, const char *con_id)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_core *core;
|
||||
|
||||
/* This is to allow this function to be chained to others */
|
||||
if (IS_ERR_OR_NULL(hw))
|
||||
return ERR_CAST(hw);
|
||||
|
||||
core = hw->core;
|
||||
clk = alloc_clk(core, dev_id, con_id);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
clk->dev = dev;
|
||||
|
||||
if (!try_module_get(core->owner)) {
|
||||
free_clk(clk);
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
kref_get(&core->ref);
|
||||
clk_core_link_consumer(core, clk);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_register - allocate a new clock, register it and return an opaque cookie
|
||||
* @dev: device that is registering this clock
|
||||
|
@ -3283,7 +3348,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
|||
core->ops = hw->init->ops;
|
||||
|
||||
if (dev && pm_runtime_enabled(dev))
|
||||
core->dev = dev;
|
||||
core->rpm_enabled = true;
|
||||
core->dev = dev;
|
||||
if (dev && dev->driver)
|
||||
core->owner = dev->driver->owner;
|
||||
core->hw = hw;
|
||||
|
@ -3323,17 +3389,27 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
|||
|
||||
INIT_HLIST_HEAD(&core->clks);
|
||||
|
||||
hw->clk = __clk_create_clk(hw, NULL, NULL);
|
||||
/*
|
||||
* Don't call clk_hw_create_clk() here because that would pin the
|
||||
* provider module to itself and prevent it from ever being removed.
|
||||
*/
|
||||
hw->clk = alloc_clk(core, NULL, NULL);
|
||||
if (IS_ERR(hw->clk)) {
|
||||
ret = PTR_ERR(hw->clk);
|
||||
goto fail_parents;
|
||||
}
|
||||
|
||||
clk_core_link_consumer(hw->core, hw->clk);
|
||||
|
||||
ret = __clk_core_init(core);
|
||||
if (!ret)
|
||||
return hw->clk;
|
||||
|
||||
__clk_free_clk(hw->clk);
|
||||
clk_prepare_lock();
|
||||
clk_core_unlink_consumer(hw->clk);
|
||||
clk_prepare_unlock();
|
||||
|
||||
free_clk(hw->clk);
|
||||
hw->clk = NULL;
|
||||
|
||||
fail_parents:
|
||||
|
@ -3604,20 +3680,7 @@ EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
|
|||
/*
|
||||
* clkdev helpers
|
||||
*/
|
||||
int __clk_get(struct clk *clk)
|
||||
{
|
||||
struct clk_core *core = !clk ? NULL : clk->core;
|
||||
|
||||
if (core) {
|
||||
if (!try_module_get(core->owner))
|
||||
return 0;
|
||||
|
||||
kref_get(&core->ref);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* keep in sync with __clk_free_clk */
|
||||
void __clk_put(struct clk *clk)
|
||||
{
|
||||
struct module *owner;
|
||||
|
@ -3651,8 +3714,7 @@ void __clk_put(struct clk *clk)
|
|||
|
||||
module_put(owner);
|
||||
|
||||
kfree_const(clk->con_id);
|
||||
kfree(clk);
|
||||
free_clk(clk);
|
||||
}
|
||||
|
||||
/*** clk rate change notifiers ***/
|
||||
|
@ -4009,6 +4071,49 @@ void devm_of_clk_del_provider(struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(devm_of_clk_del_provider);
|
||||
|
||||
/*
|
||||
* Beware the return values when np is valid, but no clock provider is found.
|
||||
* If name == NULL, the function returns -ENOENT.
|
||||
* If name != NULL, the function returns -EINVAL. This is because
|
||||
* of_parse_phandle_with_args() is called even if of_property_match_string()
|
||||
* returns an error.
|
||||
*/
|
||||
static int of_parse_clkspec(const struct device_node *np, int index,
|
||||
const char *name, struct of_phandle_args *out_args)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
|
||||
/* Walk up the tree of devices looking for a clock property that matches */
|
||||
while (np) {
|
||||
/*
|
||||
* For named clocks, first look up the name in the
|
||||
* "clock-names" property. If it cannot be found, then index
|
||||
* will be an error code and of_parse_phandle_with_args() will
|
||||
* return -EINVAL.
|
||||
*/
|
||||
if (name)
|
||||
index = of_property_match_string(np, "clock-names", name);
|
||||
ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells",
|
||||
index, out_args);
|
||||
if (!ret)
|
||||
break;
|
||||
if (name && index >= 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* No matching clock found on this node. If the parent node
|
||||
* has a "clock-ranges" property, then we can try one of its
|
||||
* clocks.
|
||||
*/
|
||||
np = np->parent;
|
||||
if (np && !of_get_property(np, "clock-ranges", NULL))
|
||||
break;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct clk_hw *
|
||||
__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
|
||||
struct of_phandle_args *clkspec)
|
||||
|
@ -4024,36 +4129,26 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider,
|
|||
return __clk_get_hw(clk);
|
||||
}
|
||||
|
||||
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
|
||||
const char *dev_id, const char *con_id)
|
||||
static struct clk_hw *
|
||||
of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec)
|
||||
{
|
||||
struct of_clk_provider *provider;
|
||||
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
|
||||
struct clk_hw *hw;
|
||||
struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
if (!clkspec)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Check if we have such a provider in our array */
|
||||
mutex_lock(&of_clk_mutex);
|
||||
list_for_each_entry(provider, &of_clk_providers, link) {
|
||||
if (provider->node == clkspec->np) {
|
||||
hw = __of_clk_get_hw_from_provider(provider, clkspec);
|
||||
clk = __clk_create_clk(hw, dev_id, con_id);
|
||||
}
|
||||
|
||||
if (!IS_ERR(clk)) {
|
||||
if (!__clk_get(clk)) {
|
||||
__clk_free_clk(clk);
|
||||
clk = ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
break;
|
||||
if (!IS_ERR(hw))
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&of_clk_mutex);
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4066,10 +4161,62 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
|
|||
*/
|
||||
struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
|
||||
{
|
||||
return __of_clk_get_from_provider(clkspec, NULL, __func__);
|
||||
struct clk_hw *hw = of_clk_get_hw_from_clkspec(clkspec);
|
||||
|
||||
return clk_hw_create_clk(NULL, hw, NULL, __func__);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_get_from_provider);
|
||||
|
||||
struct clk_hw *of_clk_get_hw(struct device_node *np, int index,
|
||||
const char *con_id)
|
||||
{
|
||||
int ret;
|
||||
struct clk_hw *hw;
|
||||
struct of_phandle_args clkspec;
|
||||
|
||||
ret = of_parse_clkspec(np, index, con_id, &clkspec);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
hw = of_clk_get_hw_from_clkspec(&clkspec);
|
||||
of_node_put(clkspec.np);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
static struct clk *__of_clk_get(struct device_node *np,
|
||||
int index, const char *dev_id,
|
||||
const char *con_id)
|
||||
{
|
||||
struct clk_hw *hw = of_clk_get_hw(np, index, con_id);
|
||||
|
||||
return clk_hw_create_clk(NULL, hw, dev_id, con_id);
|
||||
}
|
||||
|
||||
struct clk *of_clk_get(struct device_node *np, int index)
|
||||
{
|
||||
return __of_clk_get(np, index, np->full_name, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(of_clk_get);
|
||||
|
||||
/**
|
||||
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
|
||||
* @np: pointer to clock consumer node
|
||||
* @name: name of consumer's clock input, or NULL for the first clock reference
|
||||
*
|
||||
* This function parses the clocks and clock-names properties,
|
||||
* and uses them to look up the struct clk from the registered list of clock
|
||||
* providers.
|
||||
*/
|
||||
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
|
||||
{
|
||||
if (!np)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return __of_clk_get(np, -1, np->full_name, name);
|
||||
}
|
||||
EXPORT_SYMBOL(of_clk_get_by_name);
|
||||
|
||||
/**
|
||||
* of_clk_get_parent_count() - Count the number of clocks a device node has
|
||||
* @np: device node to count
|
||||
|
|
|
@ -5,31 +5,36 @@
|
|||
*/
|
||||
|
||||
struct clk_hw;
|
||||
struct device;
|
||||
struct of_phandle_args;
|
||||
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
|
||||
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
|
||||
const char *dev_id, const char *con_id);
|
||||
struct clk_hw *of_clk_get_hw(struct device_node *np,
|
||||
int index, const char *con_id);
|
||||
#else /* !CONFIG_COMMON_CLK || !CONFIG_OF */
|
||||
static inline struct clk_hw *of_clk_get_hw(struct device_node *np,
|
||||
int index, const char *con_id)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
|
||||
const char *con_id);
|
||||
void __clk_free_clk(struct clk *clk);
|
||||
int __clk_get(struct clk *clk);
|
||||
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||
const char *dev_id, const char *con_id);
|
||||
void __clk_put(struct clk *clk);
|
||||
#else
|
||||
/* All these casts to avoid ifdefs in clkdev... */
|
||||
static inline struct clk *
|
||||
__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
|
||||
clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id,
|
||||
const char *con_id)
|
||||
{
|
||||
return (struct clk *)hw;
|
||||
}
|
||||
static inline void __clk_free_clk(struct clk *clk) { }
|
||||
static struct clk_hw *__clk_get_hw(struct clk *clk)
|
||||
{
|
||||
return (struct clk_hw *)clk;
|
||||
}
|
||||
static inline int __clk_get(struct clk *clk) { return 1; }
|
||||
static inline void __clk_put(struct clk *clk) { }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,105 +27,6 @@
|
|||
static LIST_HEAD(clocks);
|
||||
static DEFINE_MUTEX(clocks_mutex);
|
||||
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
|
||||
static struct clk *__of_clk_get(struct device_node *np, int index,
|
||||
const char *dev_id, const char *con_id)
|
||||
{
|
||||
struct of_phandle_args clkspec;
|
||||
struct clk *clk;
|
||||
int rc;
|
||||
|
||||
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
|
||||
&clkspec);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
|
||||
clk = __of_clk_get_from_provider(&clkspec, dev_id, con_id);
|
||||
of_node_put(clkspec.np);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *of_clk_get(struct device_node *np, int index)
|
||||
{
|
||||
return __of_clk_get(np, index, np->full_name, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(of_clk_get);
|
||||
|
||||
/*
|
||||
* Beware the return values when np is valid, but no clock provider is found.
|
||||
* If name == NULL, the function returns -ENOENT.
|
||||
* If name != NULL, the function returns -EINVAL. This is because __of_clk_get()
|
||||
* is called even if of_property_match_string() returns an error.
|
||||
*/
|
||||
static struct clk *__of_clk_get_by_name(struct device_node *np,
|
||||
const char *dev_id,
|
||||
const char *name)
|
||||
{
|
||||
struct clk *clk = ERR_PTR(-ENOENT);
|
||||
|
||||
/* Walk up the tree of devices looking for a clock that matches */
|
||||
while (np) {
|
||||
int index = 0;
|
||||
|
||||
/*
|
||||
* For named clocks, first look up the name in the
|
||||
* "clock-names" property. If it cannot be found, then
|
||||
* index will be an error code, and of_clk_get() will fail.
|
||||
*/
|
||||
if (name)
|
||||
index = of_property_match_string(np, "clock-names", name);
|
||||
clk = __of_clk_get(np, index, dev_id, name);
|
||||
if (!IS_ERR(clk)) {
|
||||
break;
|
||||
} else if (name && index >= 0) {
|
||||
if (PTR_ERR(clk) != -EPROBE_DEFER)
|
||||
pr_err("ERROR: could not get clock %pOF:%s(%i)\n",
|
||||
np, name ? name : "", index);
|
||||
return clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* No matching clock found on this node. If the parent node
|
||||
* has a "clock-ranges" property, then we can try one of its
|
||||
* clocks.
|
||||
*/
|
||||
np = np->parent;
|
||||
if (np && !of_get_property(np, "clock-ranges", NULL))
|
||||
break;
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
|
||||
* @np: pointer to clock consumer node
|
||||
* @name: name of consumer's clock input, or NULL for the first clock reference
|
||||
*
|
||||
* This function parses the clocks and clock-names properties,
|
||||
* and uses them to look up the struct clk from the registered list of clock
|
||||
* providers.
|
||||
*/
|
||||
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
|
||||
{
|
||||
if (!np)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return __of_clk_get_by_name(np, np->full_name, name);
|
||||
}
|
||||
EXPORT_SYMBOL(of_clk_get_by_name);
|
||||
|
||||
#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */
|
||||
|
||||
static struct clk *__of_clk_get_by_name(struct device_node *np,
|
||||
const char *dev_id,
|
||||
const char *name)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find the correct struct clk for the device and connection ID.
|
||||
* We do slightly fuzzy matching here:
|
||||
|
@ -169,7 +70,8 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
|
|||
return cl;
|
||||
}
|
||||
|
||||
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
|
||||
static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
|
||||
const char *con_id)
|
||||
{
|
||||
struct clk_lookup *cl;
|
||||
struct clk *clk = NULL;
|
||||
|
@ -180,35 +82,33 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id)
|
|||
if (!cl)
|
||||
goto out;
|
||||
|
||||
clk = __clk_create_clk(cl->clk_hw, dev_id, con_id);
|
||||
clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id);
|
||||
if (IS_ERR(clk))
|
||||
goto out;
|
||||
|
||||
if (!__clk_get(clk)) {
|
||||
__clk_free_clk(clk);
|
||||
cl = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&clocks_mutex);
|
||||
|
||||
return cl ? clk : ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
|
||||
{
|
||||
return __clk_get_sys(NULL, dev_id, con_id);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_sys);
|
||||
|
||||
struct clk *clk_get(struct device *dev, const char *con_id)
|
||||
{
|
||||
const char *dev_id = dev ? dev_name(dev) : NULL;
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
|
||||
if (dev && dev->of_node) {
|
||||
clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);
|
||||
if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
|
||||
return clk;
|
||||
hw = of_clk_get_hw(dev->of_node, 0, con_id);
|
||||
if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER)
|
||||
return clk_hw_create_clk(dev, hw, dev_id, con_id);
|
||||
}
|
||||
|
||||
return clk_get_sys(dev_id, con_id);
|
||||
return __clk_get_sys(dev, dev_id, con_id);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче