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);
|
EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
|
||||||
|
|
||||||
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
static struct clk_hw *
|
||||||
const char *name, const char *parent_name, unsigned long flags,
|
__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
|
||||||
unsigned int mult, unsigned int div)
|
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_fixed_factor *fix;
|
||||||
struct clk_init_data init;
|
struct clk_init_data init = { };
|
||||||
|
struct clk_parent_data pdata = { .index = index };
|
||||||
struct clk_hw *hw;
|
struct clk_hw *hw;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -85,11 +87,17 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
||||||
init.name = name;
|
init.name = name;
|
||||||
init.ops = &clk_fixed_factor_ops;
|
init.ops = &clk_fixed_factor_ops;
|
||||||
init.flags = flags;
|
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;
|
init.num_parents = 1;
|
||||||
|
|
||||||
hw = &fix->hw;
|
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) {
|
if (ret) {
|
||||||
kfree(fix);
|
kfree(fix);
|
||||||
hw = ERR_PTR(ret);
|
hw = ERR_PTR(ret);
|
||||||
|
@ -97,6 +105,14 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
|
||||||
|
|
||||||
return hw;
|
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);
|
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
|
||||||
|
|
||||||
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
|
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 */ },
|
{ /* 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 *clk_name = node->name;
|
||||||
const char *parent_name;
|
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
u32 div, mult;
|
u32 div, mult;
|
||||||
int ret;
|
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);
|
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))
|
if (of_match_node(set_rate_parent_matches, node))
|
||||||
flags |= CLK_SET_RATE_PARENT;
|
flags |= CLK_SET_RATE_PARENT;
|
||||||
|
|
||||||
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
|
hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, 0,
|
||||||
mult, div);
|
flags, mult, div);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(hw)) {
|
||||||
/*
|
/*
|
||||||
* If parent clock is not registered, registration would fail.
|
|
||||||
* Clear OF_POPULATED flag so that clock registration can be
|
* Clear OF_POPULATED flag so that clock registration can be
|
||||||
* attempted again from probe function.
|
* attempted again from probe function.
|
||||||
*/
|
*/
|
||||||
of_node_clear_flag(node, OF_POPULATED);
|
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) {
|
if (ret) {
|
||||||
clk_unregister(clk);
|
clk_hw_unregister_fixed_factor(hw);
|
||||||
return ERR_PTR(ret);
|
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)
|
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);
|
of_clk_del_provider(pdev->dev.of_node);
|
||||||
clk_unregister_fixed_factor(clk);
|
clk_hw_unregister_fixed_factor(clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int of_fixed_factor_clk_probe(struct platform_device *pdev)
|
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
|
* This function is not executed when of_fixed_factor_clk_setup
|
||||||
|
|
|
@ -39,15 +39,23 @@ static LIST_HEAD(clk_notifier_list);
|
||||||
|
|
||||||
/*** private data structures ***/
|
/*** 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 {
|
struct clk_core {
|
||||||
const char *name;
|
const char *name;
|
||||||
const struct clk_ops *ops;
|
const struct clk_ops *ops;
|
||||||
struct clk_hw *hw;
|
struct clk_hw *hw;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
struct device_node *of_node;
|
||||||
struct clk_core *parent;
|
struct clk_core *parent;
|
||||||
const char **parent_names;
|
struct clk_parent_map *parents;
|
||||||
struct clk_core **parents;
|
|
||||||
u8 num_parents;
|
u8 num_parents;
|
||||||
u8 new_parent_index;
|
u8 new_parent_index;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
|
@ -316,17 +324,102 @@ static struct clk_core *clk_core_lookup(const char *name)
|
||||||
return NULL;
|
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,
|
static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
|
||||||
u8 index)
|
u8 index)
|
||||||
{
|
{
|
||||||
if (!core || index >= core->num_parents)
|
if (!core || index >= core->num_parents || !core->parents)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!core->parents[index])
|
if (!core->parents[index].core)
|
||||||
core->parents[index] =
|
clk_core_fill_parent_index(core, index);
|
||||||
clk_core_lookup(core->parent_names[index]);
|
|
||||||
|
|
||||||
return core->parents[index];
|
return core->parents[index].core;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct clk_hw *
|
struct clk_hw *
|
||||||
|
@ -1520,20 +1613,37 @@ static int clk_fetch_parent_index(struct clk_core *core,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
for (i = 0; i < core->num_parents; i++) {
|
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;
|
return i;
|
||||||
|
|
||||||
if (core->parents[i])
|
/* Something else is here, so keep looking */
|
||||||
|
if (core->parents[i].core)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Fallback to comparing globally unique names */
|
/* Maybe core hasn't been cached but the hw is all we know? */
|
||||||
if (!strcmp(parent->name, core->parent_names[i])) {
|
if (core->parents[i].hw) {
|
||||||
core->parents[i] = parent;
|
if (core->parents[i].hw == parent->hw)
|
||||||
return i;
|
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)
|
bool clk_has_parent(struct clk *clk, struct clk *parent)
|
||||||
{
|
{
|
||||||
struct clk_core *core, *parent_core;
|
struct clk_core *core, *parent_core;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* NULL clocks should be nops, so return success if either is NULL. */
|
/* NULL clocks should be nops, so return success if either is NULL. */
|
||||||
if (!clk || !parent)
|
if (!clk || !parent)
|
||||||
|
@ -2306,8 +2417,11 @@ bool clk_has_parent(struct clk *clk, struct clk *parent)
|
||||||
if (core->parent == parent_core)
|
if (core->parent == parent_core)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return match_string(core->parent_names, core->num_parents,
|
for (i = 0; i < core->num_parents; i++)
|
||||||
parent_core->name) >= 0;
|
if (!strcmp(core->parents[i].name, parent_core->name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clk_has_parent);
|
EXPORT_SYMBOL_GPL(clk_has_parent);
|
||||||
|
|
||||||
|
@ -2889,9 +3003,9 @@ static int possible_parents_show(struct seq_file *s, void *data)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < core->num_parents - 1; 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;
|
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)
|
static int __clk_core_init(struct clk_core *core)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int ret;
|
||||||
struct clk_core *orphan;
|
struct clk_core *orphan;
|
||||||
struct hlist_node *tmp2;
|
struct hlist_node *tmp2;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
|
@ -3079,12 +3193,6 @@ static int __clk_core_init(struct clk_core *core)
|
||||||
goto out;
|
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);
|
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;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
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;
|
struct clk_core *core;
|
||||||
|
|
||||||
core = kzalloc(sizeof(*core), GFP_KERNEL);
|
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))
|
if (dev && pm_runtime_enabled(dev))
|
||||||
core->rpm_enabled = true;
|
core->rpm_enabled = true;
|
||||||
core->dev = dev;
|
core->dev = dev;
|
||||||
|
core->of_node = np;
|
||||||
if (dev && dev->driver)
|
if (dev && dev->driver)
|
||||||
core->owner = dev->driver->owner;
|
core->owner = dev->driver->owner;
|
||||||
core->hw = hw;
|
core->hw = hw;
|
||||||
|
@ -3361,33 +3552,9 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
||||||
core->max_rate = ULONG_MAX;
|
core->max_rate = ULONG_MAX;
|
||||||
hw->core = core;
|
hw->core = core;
|
||||||
|
|
||||||
/* allocate local copy in case parent_names is __initdata */
|
ret = clk_core_populate_parent_map(core);
|
||||||
core->parent_names = kcalloc(core->num_parents, sizeof(char *),
|
if (ret)
|
||||||
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;
|
|
||||||
goto fail_parents;
|
goto fail_parents;
|
||||||
};
|
|
||||||
|
|
||||||
INIT_HLIST_HEAD(&core->clks);
|
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);
|
hw->clk = alloc_clk(core, NULL, NULL);
|
||||||
if (IS_ERR(hw->clk)) {
|
if (IS_ERR(hw->clk)) {
|
||||||
ret = PTR_ERR(hw->clk);
|
ret = PTR_ERR(hw->clk);
|
||||||
goto fail_parents;
|
goto fail_create_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
clk_core_link_consumer(hw->core, hw->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);
|
free_clk(hw->clk);
|
||||||
hw->clk = NULL;
|
hw->clk = NULL;
|
||||||
|
|
||||||
|
fail_create_clk:
|
||||||
|
clk_core_free_parent_map(core);
|
||||||
fail_parents:
|
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:
|
fail_ops:
|
||||||
kfree_const(core->name);
|
kfree_const(core->name);
|
||||||
fail_name:
|
fail_name:
|
||||||
|
@ -3428,6 +3591,24 @@ fail_name:
|
||||||
fail_out:
|
fail_out:
|
||||||
return ERR_PTR(ret);
|
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);
|
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)
|
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);
|
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. */
|
/* Free memory allocated for a clock. */
|
||||||
static void __clk_release(struct kref *ref)
|
static void __clk_release(struct kref *ref)
|
||||||
{
|
{
|
||||||
struct clk_core *core = container_of(ref, struct clk_core, ref);
|
struct clk_core *core = container_of(ref, struct clk_core, ref);
|
||||||
int i = core->num_parents;
|
|
||||||
|
|
||||||
lockdep_assert_held(&prepare_lock);
|
lockdep_assert_held(&prepare_lock);
|
||||||
|
|
||||||
kfree(core->parents);
|
clk_core_free_parent_map(core);
|
||||||
while (--i >= 0)
|
|
||||||
kfree_const(core->parent_names[i]);
|
|
||||||
|
|
||||||
kfree(core->parent_names);
|
|
||||||
kfree_const(core->name);
|
kfree_const(core->name);
|
||||||
kfree(core);
|
kfree(core);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ static inline struct clk_hw *of_clk_get_hw(struct device_node *np,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id);
|
||||||
|
|
||||||
#ifdef CONFIG_COMMON_CLK
|
#ifdef CONFIG_COMMON_CLK
|
||||||
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||||
const char *dev_id, const char *con_id);
|
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;
|
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,
|
static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
|
||||||
const char *con_id)
|
const char *con_id)
|
||||||
{
|
{
|
||||||
struct clk_lookup *cl;
|
struct clk_hw *hw = clk_find_hw(dev_id, con_id);
|
||||||
struct clk *clk = NULL;
|
|
||||||
|
|
||||||
mutex_lock(&clocks_mutex);
|
return clk_hw_create_clk(dev, hw, dev_id, con_id);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct clk *clk_get_sys(const char *dev_id, const char *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);
|
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
|
* 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.
|
* shared between the clock provider and the common clock framework.
|
||||||
|
@ -257,13 +271,20 @@ struct clk_ops {
|
||||||
* @name: clock name
|
* @name: clock name
|
||||||
* @ops: operations this clock supports
|
* @ops: operations this clock supports
|
||||||
* @parent_names: array of string names for all possible parents
|
* @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
|
* @num_parents: number of possible parents
|
||||||
* @flags: framework-level hints and quirks
|
* @flags: framework-level hints and quirks
|
||||||
*/
|
*/
|
||||||
struct clk_init_data {
|
struct clk_init_data {
|
||||||
const char *name;
|
const char *name;
|
||||||
const struct clk_ops *ops;
|
const struct clk_ops *ops;
|
||||||
|
/* Only one of the following three should be assigned */
|
||||||
const char * const *parent_names;
|
const char * const *parent_names;
|
||||||
|
const struct clk_parent_data *parent_data;
|
||||||
|
const struct clk_hw **parent_hws;
|
||||||
u8 num_parents;
|
u8 num_parents;
|
||||||
unsigned long flags;
|
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 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 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 clk_unregister(struct clk *clk);
|
||||||
void devm_clk_unregister(struct device *dev, 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)
|
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 NULL;
|
||||||
return dev->of_node;
|
return dev->of_node;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue