sh: add a reparent function to DIV6 clocks
Add support for reparenting of div6 clocks on SuperH and SH-Mobile SoCs. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
committed by
Paul Mundt
parent
b5272b509a
commit
b3dd51a8a6
@@ -68,6 +68,39 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
|
|||||||
return clk->freq_table[idx].frequency;
|
return clk->freq_table[idx].frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
|
||||||
|
{
|
||||||
|
struct clk_div_mult_table *table = &sh_clk_div6_table;
|
||||||
|
u32 value;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
if (!clk->parent_table || !clk->parent_num)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Search the parent */
|
||||||
|
for (i = 0; i < clk->parent_num; i++)
|
||||||
|
if (clk->parent_table[i] == parent)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == clk->parent_num)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = clk_reparent(clk, parent);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
value = __raw_readl(clk->enable_reg) &
|
||||||
|
~(((1 << clk->src_width) - 1) << clk->src_shift);
|
||||||
|
|
||||||
|
__raw_writel(value | (i << clk->src_shift), clk->enable_reg);
|
||||||
|
|
||||||
|
/* Rebuild the frequency table */
|
||||||
|
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
|
||||||
|
table, &clk->arch_flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int sh_clk_div6_set_rate(struct clk *clk,
|
static int sh_clk_div6_set_rate(struct clk *clk,
|
||||||
unsigned long rate, int algo_id)
|
unsigned long rate, int algo_id)
|
||||||
{
|
{
|
||||||
@@ -117,7 +150,17 @@ static struct clk_ops sh_clk_div6_clk_ops = {
|
|||||||
.disable = sh_clk_div6_disable,
|
.disable = sh_clk_div6_disable,
|
||||||
};
|
};
|
||||||
|
|
||||||
int __init sh_clk_div6_register(struct clk *clks, int nr)
|
static struct clk_ops sh_clk_div6_reparent_clk_ops = {
|
||||||
|
.recalc = sh_clk_div6_recalc,
|
||||||
|
.round_rate = sh_clk_div_round_rate,
|
||||||
|
.set_rate = sh_clk_div6_set_rate,
|
||||||
|
.enable = sh_clk_div6_enable,
|
||||||
|
.disable = sh_clk_div6_disable,
|
||||||
|
.set_parent = sh_clk_div6_set_parent,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
|
||||||
|
struct clk_ops *ops)
|
||||||
{
|
{
|
||||||
struct clk *clkp;
|
struct clk *clkp;
|
||||||
void *freq_table;
|
void *freq_table;
|
||||||
@@ -136,7 +179,7 @@ int __init sh_clk_div6_register(struct clk *clks, int nr)
|
|||||||
for (k = 0; !ret && (k < nr); k++) {
|
for (k = 0; !ret && (k < nr); k++) {
|
||||||
clkp = clks + k;
|
clkp = clks + k;
|
||||||
|
|
||||||
clkp->ops = &sh_clk_div6_clk_ops;
|
clkp->ops = ops;
|
||||||
clkp->id = -1;
|
clkp->id = -1;
|
||||||
clkp->freq_table = freq_table + (k * freq_table_size);
|
clkp->freq_table = freq_table + (k * freq_table_size);
|
||||||
clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
|
clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
|
||||||
@@ -147,6 +190,17 @@ int __init sh_clk_div6_register(struct clk *clks, int nr)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __init sh_clk_div6_register(struct clk *clks, int nr)
|
||||||
|
{
|
||||||
|
return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
|
||||||
|
{
|
||||||
|
return sh_clk_div6_register_ops(clks, nr,
|
||||||
|
&sh_clk_div6_reparent_clk_ops);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned long sh_clk_div4_recalc(struct clk *clk)
|
static unsigned long sh_clk_div4_recalc(struct clk *clk)
|
||||||
{
|
{
|
||||||
struct clk_div4_table *d4t = clk->priv;
|
struct clk_div4_table *d4t = clk->priv;
|
||||||
|
@@ -142,13 +142,22 @@ int sh_clk_div4_enable_register(struct clk *clks, int nr,
|
|||||||
int sh_clk_div4_reparent_register(struct clk *clks, int nr,
|
int sh_clk_div4_reparent_register(struct clk *clks, int nr,
|
||||||
struct clk_div4_table *table);
|
struct clk_div4_table *table);
|
||||||
|
|
||||||
#define SH_CLK_DIV6(_parent, _reg, _flags) \
|
#define SH_CLK_DIV6_EXT(_parent, _reg, _flags, _parents, \
|
||||||
|
_num_parents, _src_shift, _src_width) \
|
||||||
{ \
|
{ \
|
||||||
.parent = _parent, \
|
.parent = _parent, \
|
||||||
.enable_reg = (void __iomem *)_reg, \
|
.enable_reg = (void __iomem *)_reg, \
|
||||||
.flags = _flags, \
|
.flags = _flags, \
|
||||||
|
.parent_table = _parents, \
|
||||||
|
.parent_num = _num_parents, \
|
||||||
|
.src_shift = _src_shift, \
|
||||||
|
.src_width = _src_width, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SH_CLK_DIV6(_parent, _reg, _flags) \
|
||||||
|
SH_CLK_DIV6_EXT(_parent, _reg, _flags, NULL, 0, 0, 0)
|
||||||
|
|
||||||
int sh_clk_div6_register(struct clk *clks, int nr);
|
int sh_clk_div6_register(struct clk *clks, int nr);
|
||||||
|
int sh_clk_div6_reparent_register(struct clk *clks, int nr);
|
||||||
|
|
||||||
#endif /* __SH_CLOCK_H */
|
#endif /* __SH_CLOCK_H */
|
||||||
|
Reference in New Issue
Block a user