clk: tegra: Add super clock mux/divider
Add a super clock type which implements both mux and divider. This is used for aclk. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com> Tested-by: Mikko Perttunen <mperttunen@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
6cfc8bc9ee
commit
e827ba1840
|
@ -121,9 +121,50 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_super_mux_ops = {
|
||||
.get_parent = clk_super_get_parent,
|
||||
.set_parent = clk_super_set_parent,
|
||||
};
|
||||
|
||||
static long clk_super_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
|
||||
struct clk_hw *div_hw = &super->frac_div.hw;
|
||||
|
||||
__clk_hw_set_clk(div_hw, hw);
|
||||
|
||||
return super->div_ops->round_rate(div_hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
static unsigned long clk_super_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
|
||||
struct clk_hw *div_hw = &super->frac_div.hw;
|
||||
|
||||
__clk_hw_set_clk(div_hw, hw);
|
||||
|
||||
return super->div_ops->recalc_rate(div_hw, parent_rate);
|
||||
}
|
||||
|
||||
static int clk_super_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
|
||||
struct clk_hw *div_hw = &super->frac_div.hw;
|
||||
|
||||
__clk_hw_set_clk(div_hw, hw);
|
||||
|
||||
return super->div_ops->set_rate(div_hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
const struct clk_ops tegra_clk_super_ops = {
|
||||
.get_parent = clk_super_get_parent,
|
||||
.set_parent = clk_super_set_parent,
|
||||
.set_rate = clk_super_set_rate,
|
||||
.round_rate = clk_super_round_rate,
|
||||
.recalc_rate = clk_super_recalc_rate,
|
||||
};
|
||||
|
||||
struct clk *tegra_clk_register_super_mux(const char *name,
|
||||
|
@ -136,13 +177,11 @@ struct clk *tegra_clk_register_super_mux(const char *name,
|
|||
struct clk_init_data init;
|
||||
|
||||
super = kzalloc(sizeof(*super), GFP_KERNEL);
|
||||
if (!super) {
|
||||
pr_err("%s: could not allocate super clk\n", __func__);
|
||||
if (!super)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &tegra_clk_super_ops;
|
||||
init.ops = &tegra_clk_super_mux_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
@ -163,3 +202,43 @@ struct clk *tegra_clk_register_super_mux(const char *name,
|
|||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *tegra_clk_register_super_clk(const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
struct tegra_clk_super_mux *super;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
super = kzalloc(sizeof(*super), GFP_KERNEL);
|
||||
if (!super)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &tegra_clk_super_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
super->reg = reg;
|
||||
super->lock = lock;
|
||||
super->width = 4;
|
||||
super->flags = clk_super_flags;
|
||||
super->frac_div.reg = reg + 4;
|
||||
super->frac_div.shift = 16;
|
||||
super->frac_div.width = 8;
|
||||
super->frac_div.frac_width = 1;
|
||||
super->frac_div.lock = lock;
|
||||
super->div_ops = &tegra_clk_frac_div_ops;
|
||||
|
||||
/* Data in .init is copied by clk_register(), so stack variable OK */
|
||||
super->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &super->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(super);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
|
|
@ -686,6 +686,8 @@ struct tegra_periph_init_data {
|
|||
struct tegra_clk_super_mux {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
struct tegra_clk_frac_div frac_div;
|
||||
const struct clk_ops *div_ops;
|
||||
u8 width;
|
||||
u8 flags;
|
||||
u8 div2_index;
|
||||
|
@ -702,7 +704,10 @@ struct clk *tegra_clk_register_super_mux(const char *name,
|
|||
const char **parent_names, u8 num_parents,
|
||||
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
|
||||
u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock);
|
||||
|
||||
struct clk *tegra_clk_register_super_clk(const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags, void __iomem *reg, u8 clk_super_flags,
|
||||
spinlock_t *lock);
|
||||
/**
|
||||
* struct clk_init_table - clock initialization table
|
||||
* @clk_id: clock id as mentioned in device tree bindings
|
||||
|
|
Loading…
Reference in New Issue