mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
Merge branch 'clk-parent-rewrite-1' into clk-next
- Rewrite how clk parents can be specified to be DT/clkdev based instead of just string based * clk-parent-rewrite-1: clk: Cache core in clk_fetch_parent_index() without names clk: fixed-factor: Initialize clk_init_data on stack clk: fixed-factor: Let clk framework find parent clk: Allow parents to be specified via clkspec index clk: Look for parents with clkdev based clk_lookups clk: Allow parents to be specified without string names clk: Add of_clk_hw_register() API for early clk drivers driver core: Let dev_of_node() accept a NULL dev clk: Prepare for clk registration API that uses DT nodes clkdev: Move clk creation outside of 'clocks_mutex'
This commit is contained in:
commit
c1157f60d7
@ -64,12 +64,14 @@ const struct clk_ops clk_fixed_factor_ops = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
|
||||
|
||||
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
||||
const char *name, const char *parent_name, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
static struct clk_hw *
|
||||
__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
|
||||
const char *name, const char *parent_name, int index,
|
||||
unsigned long flags, unsigned int mult, unsigned int div)
|
||||
{
|
||||
struct clk_fixed_factor *fix;
|
||||
struct clk_init_data init;
|
||||
struct clk_init_data init = { };
|
||||
struct clk_parent_data pdata = { .index = index };
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
@ -85,11 +87,17 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
||||
init.name = name;
|
||||
init.ops = &clk_fixed_factor_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = &parent_name;
|
||||
if (parent_name)
|
||||
init.parent_names = &parent_name;
|
||||
else
|
||||
init.parent_data = &pdata;
|
||||
init.num_parents = 1;
|
||||
|
||||
hw = &fix->hw;
|
||||
ret = clk_hw_register(dev, hw);
|
||||
if (dev)
|
||||
ret = clk_hw_register(dev, hw);
|
||||
else
|
||||
ret = of_clk_hw_register(np, hw);
|
||||
if (ret) {
|
||||
kfree(fix);
|
||||
hw = ERR_PTR(ret);
|
||||
@ -97,6 +105,14 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
||||
const char *name, const char *parent_name, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
{
|
||||
return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, -1,
|
||||
flags, mult, div);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
|
||||
|
||||
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
|
||||
@ -143,11 +159,10 @@ static const struct of_device_id set_rate_parent_matches[] = {
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
|
||||
static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *hw;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
unsigned long flags = 0;
|
||||
u32 div, mult;
|
||||
int ret;
|
||||
@ -165,30 +180,28 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
|
||||
}
|
||||
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
|
||||
if (of_match_node(set_rate_parent_matches, node))
|
||||
flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
|
||||
mult, div);
|
||||
if (IS_ERR(clk)) {
|
||||
hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, 0,
|
||||
flags, mult, div);
|
||||
if (IS_ERR(hw)) {
|
||||
/*
|
||||
* If parent clock is not registered, registration would fail.
|
||||
* Clear OF_POPULATED flag so that clock registration can be
|
||||
* attempted again from probe function.
|
||||
*/
|
||||
of_node_clear_flag(node, OF_POPULATED);
|
||||
return clk;
|
||||
return ERR_CAST(hw);
|
||||
}
|
||||
|
||||
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
|
||||
if (ret) {
|
||||
clk_unregister(clk);
|
||||
clk_hw_unregister_fixed_factor(hw);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return clk;
|
||||
return hw;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,17 +216,17 @@ CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
|
||||
|
||||
static int of_fixed_factor_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk = platform_get_drvdata(pdev);
|
||||
struct clk_hw *clk = platform_get_drvdata(pdev);
|
||||
|
||||
of_clk_del_provider(pdev->dev.of_node);
|
||||
clk_unregister_fixed_factor(clk);
|
||||
clk_hw_unregister_fixed_factor(clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int of_fixed_factor_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_hw *clk;
|
||||
|
||||
/*
|
||||
* This function is not executed when of_fixed_factor_clk_setup
|
||||
|
@ -39,15 +39,23 @@ static LIST_HEAD(clk_notifier_list);
|
||||
|
||||
/*** private data structures ***/
|
||||
|
||||
struct clk_parent_map {
|
||||
const struct clk_hw *hw;
|
||||
struct clk_core *core;
|
||||
const char *fw_name;
|
||||
const char *name;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct clk_core {
|
||||
const char *name;
|
||||
const struct clk_ops *ops;
|
||||
struct clk_hw *hw;
|
||||
struct module *owner;
|
||||
struct device *dev;
|
||||
struct device_node *of_node;
|
||||
struct clk_core *parent;
|
||||
const char **parent_names;
|
||||
struct clk_core **parents;
|
||||
struct clk_parent_map *parents;
|
||||
u8 num_parents;
|
||||
u8 new_parent_index;
|
||||
unsigned long rate;
|
||||
@ -316,17 +324,102 @@ static struct clk_core *clk_core_lookup(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_core_get - Find the clk_core parent of a clk
|
||||
* @core: clk to find parent of
|
||||
* @p_index: parent index to search for
|
||||
*
|
||||
* This is the preferred method for clk providers to find the parent of a
|
||||
* clk when that parent is external to the clk controller. The parent_names
|
||||
* array is indexed and treated as a local name matching a string in the device
|
||||
* node's 'clock-names' property or as the 'con_id' matching the device's
|
||||
* dev_name() in a clk_lookup. This allows clk providers to use their own
|
||||
* namespace instead of looking for a globally unique parent string.
|
||||
*
|
||||
* For example the following DT snippet would allow a clock registered by the
|
||||
* clock-controller@c001 that has a clk_init_data::parent_data array
|
||||
* with 'xtal' in the 'name' member to find the clock provided by the
|
||||
* clock-controller@f00abcd without needing to get the globally unique name of
|
||||
* the xtal clk.
|
||||
*
|
||||
* parent: clock-controller@f00abcd {
|
||||
* reg = <0xf00abcd 0xabcd>;
|
||||
* #clock-cells = <0>;
|
||||
* };
|
||||
*
|
||||
* clock-controller@c001 {
|
||||
* reg = <0xc001 0xf00d>;
|
||||
* clocks = <&parent>;
|
||||
* clock-names = "xtal";
|
||||
* #clock-cells = <1>;
|
||||
* };
|
||||
*
|
||||
* Returns: -ENOENT when the provider can't be found or the clk doesn't
|
||||
* exist in the provider. -EINVAL when the name can't be found. NULL when the
|
||||
* provider knows about the clk but it isn't provided on this system.
|
||||
* A valid clk_core pointer when the clk can be found in the provider.
|
||||
*/
|
||||
static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
|
||||
{
|
||||
const char *name = core->parents[p_index].fw_name;
|
||||
int index = core->parents[p_index].index;
|
||||
struct clk_hw *hw = ERR_PTR(-ENOENT);
|
||||
struct device *dev = core->dev;
|
||||
const char *dev_id = dev ? dev_name(dev) : NULL;
|
||||
struct device_node *np = core->of_node;
|
||||
|
||||
if (np && index >= 0)
|
||||
hw = of_clk_get_hw(np, index, name);
|
||||
|
||||
/*
|
||||
* If the DT search above couldn't find the provider or the provider
|
||||
* didn't know about this clk, fallback to looking up via clkdev based
|
||||
* clk_lookups
|
||||
*/
|
||||
if (PTR_ERR(hw) == -ENOENT && name)
|
||||
hw = clk_find_hw(dev_id, name);
|
||||
|
||||
if (IS_ERR(hw))
|
||||
return ERR_CAST(hw);
|
||||
|
||||
return hw->core;
|
||||
}
|
||||
|
||||
static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
|
||||
{
|
||||
struct clk_parent_map *entry = &core->parents[index];
|
||||
struct clk_core *parent = ERR_PTR(-ENOENT);
|
||||
|
||||
if (entry->hw) {
|
||||
parent = entry->hw->core;
|
||||
/*
|
||||
* We have a direct reference but it isn't registered yet?
|
||||
* Orphan it and let clk_reparent() update the orphan status
|
||||
* when the parent is registered.
|
||||
*/
|
||||
if (!parent)
|
||||
parent = ERR_PTR(-EPROBE_DEFER);
|
||||
} else {
|
||||
parent = clk_core_get(core, index);
|
||||
if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT)
|
||||
parent = clk_core_lookup(entry->name);
|
||||
}
|
||||
|
||||
/* Only cache it if it's not an error */
|
||||
if (!IS_ERR(parent))
|
||||
entry->core = parent;
|
||||
}
|
||||
|
||||
static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
|
||||
u8 index)
|
||||
{
|
||||
if (!core || index >= core->num_parents)
|
||||
if (!core || index >= core->num_parents || !core->parents)
|
||||
return NULL;
|
||||
|
||||
if (!core->parents[index])
|
||||
core->parents[index] =
|
||||
clk_core_lookup(core->parent_names[index]);
|
||||
if (!core->parents[index].core)
|
||||
clk_core_fill_parent_index(core, index);
|
||||
|
||||
return core->parents[index];
|
||||
return core->parents[index].core;
|
||||
}
|
||||
|
||||
struct clk_hw *
|
||||
@ -1520,20 +1613,37 @@ static int clk_fetch_parent_index(struct clk_core *core,
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < core->num_parents; i++) {
|
||||
if (core->parents[i] == parent)
|
||||
/* Found it first try! */
|
||||
if (core->parents[i].core == parent)
|
||||
return i;
|
||||
|
||||
if (core->parents[i])
|
||||
/* Something else is here, so keep looking */
|
||||
if (core->parents[i].core)
|
||||
continue;
|
||||
|
||||
/* Fallback to comparing globally unique names */
|
||||
if (!strcmp(parent->name, core->parent_names[i])) {
|
||||
core->parents[i] = parent;
|
||||
return i;
|
||||
/* Maybe core hasn't been cached but the hw is all we know? */
|
||||
if (core->parents[i].hw) {
|
||||
if (core->parents[i].hw == parent->hw)
|
||||
break;
|
||||
|
||||
/* Didn't match, but we're expecting a clk_hw */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Maybe it hasn't been cached (clk_set_parent() path) */
|
||||
if (parent == clk_core_get(core, i))
|
||||
break;
|
||||
|
||||
/* Fallback to comparing globally unique names */
|
||||
if (!strcmp(parent->name, core->parents[i].name))
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
if (i == core->num_parents)
|
||||
return -EINVAL;
|
||||
|
||||
core->parents[i].core = parent;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2294,6 +2404,7 @@ void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent)
|
||||
bool clk_has_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
struct clk_core *core, *parent_core;
|
||||
int i;
|
||||
|
||||
/* NULL clocks should be nops, so return success if either is NULL. */
|
||||
if (!clk || !parent)
|
||||
@ -2306,8 +2417,11 @@ bool clk_has_parent(struct clk *clk, struct clk *parent)
|
||||
if (core->parent == parent_core)
|
||||
return true;
|
||||
|
||||
return match_string(core->parent_names, core->num_parents,
|
||||
parent_core->name) >= 0;
|
||||
for (i = 0; i < core->num_parents; i++)
|
||||
if (!strcmp(core->parents[i].name, parent_core->name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_has_parent);
|
||||
|
||||
@ -2889,9 +3003,9 @@ static int possible_parents_show(struct seq_file *s, void *data)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < core->num_parents - 1; i++)
|
||||
seq_printf(s, "%s ", core->parent_names[i]);
|
||||
seq_printf(s, "%s ", core->parents[i].name);
|
||||
|
||||
seq_printf(s, "%s\n", core->parent_names[i]);
|
||||
seq_printf(s, "%s\n", core->parents[i].name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3025,7 +3139,7 @@ static inline void clk_debug_unregister(struct clk_core *core)
|
||||
*/
|
||||
static int __clk_core_init(struct clk_core *core)
|
||||
{
|
||||
int i, ret;
|
||||
int ret;
|
||||
struct clk_core *orphan;
|
||||
struct hlist_node *tmp2;
|
||||
unsigned long rate;
|
||||
@ -3079,12 +3193,6 @@ static int __clk_core_init(struct clk_core *core)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* throw a WARN if any entries in parent_names are NULL */
|
||||
for (i = 0; i < core->num_parents; i++)
|
||||
WARN(!core->parent_names[i],
|
||||
"%s: invalid NULL in %s's .parent_names\n",
|
||||
__func__, core->name);
|
||||
|
||||
core->parent = __clk_init_parent(core);
|
||||
|
||||
/*
|
||||
@ -3313,22 +3421,104 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_register - allocate a new clock, register it and return an opaque cookie
|
||||
* @dev: device that is registering this clock
|
||||
* @hw: link to hardware-specific clock data
|
||||
*
|
||||
* clk_register is the *deprecated* interface for populating the clock tree with
|
||||
* new clock nodes. Use clk_hw_register() instead.
|
||||
*
|
||||
* Returns: a pointer to the newly allocated struct clk which
|
||||
* cannot be dereferenced by driver code but may be used in conjunction with the
|
||||
* rest of the clock API. In the event of an error clk_register will return an
|
||||
* error code; drivers must test for an error code after calling clk_register.
|
||||
*/
|
||||
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||
static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist)
|
||||
{
|
||||
int i, ret;
|
||||
const char *dst;
|
||||
|
||||
if (!src) {
|
||||
if (must_exist)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*dst_p = dst = kstrdup_const(src, GFP_KERNEL);
|
||||
if (!dst)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_core_populate_parent_map(struct clk_core *core)
|
||||
{
|
||||
const struct clk_init_data *init = core->hw->init;
|
||||
u8 num_parents = init->num_parents;
|
||||
const char * const *parent_names = init->parent_names;
|
||||
const struct clk_hw **parent_hws = init->parent_hws;
|
||||
const struct clk_parent_data *parent_data = init->parent_data;
|
||||
int i, ret = 0;
|
||||
struct clk_parent_map *parents, *parent;
|
||||
|
||||
if (!num_parents)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Avoid unnecessary string look-ups of clk_core's possible parents by
|
||||
* having a cache of names/clk_hw pointers to clk_core pointers.
|
||||
*/
|
||||
parents = kcalloc(num_parents, sizeof(*parents), GFP_KERNEL);
|
||||
core->parents = parents;
|
||||
if (!parents)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Copy everything over because it might be __initdata */
|
||||
for (i = 0, parent = parents; i < num_parents; i++, parent++) {
|
||||
parent->index = -1;
|
||||
if (parent_names) {
|
||||
/* throw a WARN if any entries are NULL */
|
||||
WARN(!parent_names[i],
|
||||
"%s: invalid NULL in %s's .parent_names\n",
|
||||
__func__, core->name);
|
||||
ret = clk_cpy_name(&parent->name, parent_names[i],
|
||||
true);
|
||||
} else if (parent_data) {
|
||||
parent->hw = parent_data[i].hw;
|
||||
parent->index = parent_data[i].index;
|
||||
ret = clk_cpy_name(&parent->fw_name,
|
||||
parent_data[i].fw_name, false);
|
||||
if (!ret)
|
||||
ret = clk_cpy_name(&parent->name,
|
||||
parent_data[i].name,
|
||||
false);
|
||||
} else if (parent_hws) {
|
||||
parent->hw = parent_hws[i];
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
WARN(1, "Must specify parents if num_parents > 0\n");
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
do {
|
||||
kfree_const(parents[i].name);
|
||||
kfree_const(parents[i].fw_name);
|
||||
} while (--i >= 0);
|
||||
kfree(parents);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_core_free_parent_map(struct clk_core *core)
|
||||
{
|
||||
int i = core->num_parents;
|
||||
|
||||
if (!core->num_parents)
|
||||
return;
|
||||
|
||||
while (--i >= 0) {
|
||||
kfree_const(core->parents[i].name);
|
||||
kfree_const(core->parents[i].fw_name);
|
||||
}
|
||||
|
||||
kfree(core->parents);
|
||||
}
|
||||
|
||||
static struct clk *
|
||||
__clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
|
||||
{
|
||||
int ret;
|
||||
struct clk_core *core;
|
||||
|
||||
core = kzalloc(sizeof(*core), GFP_KERNEL);
|
||||
@ -3352,6 +3542,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||
if (dev && pm_runtime_enabled(dev))
|
||||
core->rpm_enabled = true;
|
||||
core->dev = dev;
|
||||
core->of_node = np;
|
||||
if (dev && dev->driver)
|
||||
core->owner = dev->driver->owner;
|
||||
core->hw = hw;
|
||||
@ -3361,33 +3552,9 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||
core->max_rate = ULONG_MAX;
|
||||
hw->core = core;
|
||||
|
||||
/* allocate local copy in case parent_names is __initdata */
|
||||
core->parent_names = kcalloc(core->num_parents, sizeof(char *),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!core->parent_names) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_parent_names;
|
||||
}
|
||||
|
||||
|
||||
/* copy each string name in case parent_names is __initdata */
|
||||
for (i = 0; i < core->num_parents; i++) {
|
||||
core->parent_names[i] = kstrdup_const(hw->init->parent_names[i],
|
||||
GFP_KERNEL);
|
||||
if (!core->parent_names[i]) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_parent_names_copy;
|
||||
}
|
||||
}
|
||||
|
||||
/* avoid unnecessary string look-ups of clk_core's possible parents. */
|
||||
core->parents = kcalloc(core->num_parents, sizeof(*core->parents),
|
||||
GFP_KERNEL);
|
||||
if (!core->parents) {
|
||||
ret = -ENOMEM;
|
||||
ret = clk_core_populate_parent_map(core);
|
||||
if (ret)
|
||||
goto fail_parents;
|
||||
};
|
||||
|
||||
INIT_HLIST_HEAD(&core->clks);
|
||||
|
||||
@ -3398,7 +3565,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||
hw->clk = alloc_clk(core, NULL, NULL);
|
||||
if (IS_ERR(hw->clk)) {
|
||||
ret = PTR_ERR(hw->clk);
|
||||
goto fail_parents;
|
||||
goto fail_create_clk;
|
||||
}
|
||||
|
||||
clk_core_link_consumer(hw->core, hw->clk);
|
||||
@ -3414,13 +3581,9 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||
free_clk(hw->clk);
|
||||
hw->clk = NULL;
|
||||
|
||||
fail_create_clk:
|
||||
clk_core_free_parent_map(core);
|
||||
fail_parents:
|
||||
kfree(core->parents);
|
||||
fail_parent_names_copy:
|
||||
while (--i >= 0)
|
||||
kfree_const(core->parent_names[i]);
|
||||
kfree(core->parent_names);
|
||||
fail_parent_names:
|
||||
fail_ops:
|
||||
kfree_const(core->name);
|
||||
fail_name:
|
||||
@ -3428,6 +3591,24 @@ fail_name:
|
||||
fail_out:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_register - allocate a new clock, register it and return an opaque cookie
|
||||
* @dev: device that is registering this clock
|
||||
* @hw: link to hardware-specific clock data
|
||||
*
|
||||
* clk_register is the *deprecated* interface for populating the clock tree with
|
||||
* new clock nodes. Use clk_hw_register() instead.
|
||||
*
|
||||
* Returns: a pointer to the newly allocated struct clk which
|
||||
* cannot be dereferenced by driver code but may be used in conjunction with the
|
||||
* rest of the clock API. In the event of an error clk_register will return an
|
||||
* error code; drivers must test for an error code after calling clk_register.
|
||||
*/
|
||||
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||
{
|
||||
return __clk_register(dev, dev_of_node(dev), hw);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register);
|
||||
|
||||
/**
|
||||
@ -3442,23 +3623,35 @@ EXPORT_SYMBOL_GPL(clk_register);
|
||||
*/
|
||||
int clk_hw_register(struct device *dev, struct clk_hw *hw)
|
||||
{
|
||||
return PTR_ERR_OR_ZERO(clk_register(dev, hw));
|
||||
return PTR_ERR_OR_ZERO(__clk_register(dev, dev_of_node(dev), hw));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_register);
|
||||
|
||||
/*
|
||||
* of_clk_hw_register - register a clk_hw and return an error code
|
||||
* @node: device_node of device that is registering this clock
|
||||
* @hw: link to hardware-specific clock data
|
||||
*
|
||||
* of_clk_hw_register() is the primary interface for populating the clock tree
|
||||
* with new clock nodes when a struct device is not available, but a struct
|
||||
* device_node is. It returns an integer equal to zero indicating success or
|
||||
* less than zero indicating failure. Drivers must test for an error code after
|
||||
* calling of_clk_hw_register().
|
||||
*/
|
||||
int of_clk_hw_register(struct device_node *node, struct clk_hw *hw)
|
||||
{
|
||||
return PTR_ERR_OR_ZERO(__clk_register(NULL, node, hw));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_hw_register);
|
||||
|
||||
/* Free memory allocated for a clock. */
|
||||
static void __clk_release(struct kref *ref)
|
||||
{
|
||||
struct clk_core *core = container_of(ref, struct clk_core, ref);
|
||||
int i = core->num_parents;
|
||||
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
|
||||
kfree(core->parents);
|
||||
while (--i >= 0)
|
||||
kfree_const(core->parent_names[i]);
|
||||
|
||||
kfree(core->parent_names);
|
||||
clk_core_free_parent_map(core);
|
||||
kfree_const(core->name);
|
||||
kfree(core);
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ static inline struct clk_hw *of_clk_get_hw(struct device_node *np,
|
||||
}
|
||||
#endif
|
||||
|
||||
struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id);
|
||||
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||
const char *dev_id, const char *con_id);
|
||||
|
@ -72,25 +72,26 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
|
||||
return cl;
|
||||
}
|
||||
|
||||
struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id)
|
||||
{
|
||||
struct clk_lookup *cl;
|
||||
struct clk_hw *hw = ERR_PTR(-ENOENT);
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
cl = clk_find(dev_id, con_id);
|
||||
if (cl)
|
||||
hw = cl->clk_hw;
|
||||
mutex_unlock(&clocks_mutex);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
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;
|
||||
struct clk_hw *hw = clk_find_hw(dev_id, con_id);
|
||||
|
||||
mutex_lock(&clocks_mutex);
|
||||
|
||||
cl = clk_find(dev_id, con_id);
|
||||
if (!cl)
|
||||
goto out;
|
||||
|
||||
clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id);
|
||||
if (IS_ERR(clk))
|
||||
cl = NULL;
|
||||
out:
|
||||
mutex_unlock(&clocks_mutex);
|
||||
|
||||
return cl ? clk : ERR_PTR(-ENOENT);
|
||||
return clk_hw_create_clk(dev, hw, dev_id, con_id);
|
||||
}
|
||||
|
||||
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
|
||||
|
@ -250,6 +250,20 @@ struct clk_ops {
|
||||
void (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_parent_data - clk parent information
|
||||
* @hw: parent clk_hw pointer (used for clk providers with internal clks)
|
||||
* @fw_name: parent name local to provider registering clk
|
||||
* @name: globally unique parent name (used as a fallback)
|
||||
* @index: parent index local to provider registering clk (if @fw_name absent)
|
||||
*/
|
||||
struct clk_parent_data {
|
||||
const struct clk_hw *hw;
|
||||
const char *fw_name;
|
||||
const char *name;
|
||||
int index;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_init_data - holds init data that's common to all clocks and is
|
||||
* shared between the clock provider and the common clock framework.
|
||||
@ -257,13 +271,20 @@ struct clk_ops {
|
||||
* @name: clock name
|
||||
* @ops: operations this clock supports
|
||||
* @parent_names: array of string names for all possible parents
|
||||
* @parent_data: array of parent data for all possible parents (when some
|
||||
* parents are external to the clk controller)
|
||||
* @parent_hws: array of pointers to all possible parents (when all parents
|
||||
* are internal to the clk controller)
|
||||
* @num_parents: number of possible parents
|
||||
* @flags: framework-level hints and quirks
|
||||
*/
|
||||
struct clk_init_data {
|
||||
const char *name;
|
||||
const struct clk_ops *ops;
|
||||
/* Only one of the following three should be assigned */
|
||||
const char * const *parent_names;
|
||||
const struct clk_parent_data *parent_data;
|
||||
const struct clk_hw **parent_hws;
|
||||
u8 num_parents;
|
||||
unsigned long flags;
|
||||
};
|
||||
@ -776,6 +797,7 @@ struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
|
||||
|
||||
int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw);
|
||||
int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw);
|
||||
int __must_check of_clk_hw_register(struct device_node *node, struct clk_hw *hw);
|
||||
|
||||
void clk_unregister(struct clk *clk);
|
||||
void devm_clk_unregister(struct device *dev, struct clk *clk);
|
||||
|
@ -1229,7 +1229,7 @@ static inline void device_lock_assert(struct device *dev)
|
||||
|
||||
static inline struct device_node *dev_of_node(struct device *dev)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_OF))
|
||||
if (!IS_ENABLED(CONFIG_OF) || !dev)
|
||||
return NULL;
|
||||
return dev->of_node;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user