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:
Peter De Schrijver 2017-02-28 16:37:21 +02:00 committed by Thierry Reding
parent 6cfc8bc9ee
commit e827ba1840
2 changed files with 89 additions and 5 deletions

View File

@ -121,9 +121,50 @@ out:
return err; 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 = { const struct clk_ops tegra_clk_super_ops = {
.get_parent = clk_super_get_parent, .get_parent = clk_super_get_parent,
.set_parent = clk_super_set_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, 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; struct clk_init_data init;
super = kzalloc(sizeof(*super), GFP_KERNEL); super = kzalloc(sizeof(*super), GFP_KERNEL);
if (!super) { if (!super)
pr_err("%s: could not allocate super clk\n", __func__);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
init.name = name; init.name = name;
init.ops = &tegra_clk_super_ops; init.ops = &tegra_clk_super_mux_ops;
init.flags = flags; init.flags = flags;
init.parent_names = parent_names; init.parent_names = parent_names;
init.num_parents = num_parents; init.num_parents = num_parents;
@ -163,3 +202,43 @@ struct clk *tegra_clk_register_super_mux(const char *name,
return clk; 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;
}

View File

@ -686,6 +686,8 @@ struct tegra_periph_init_data {
struct tegra_clk_super_mux { struct tegra_clk_super_mux {
struct clk_hw hw; struct clk_hw hw;
void __iomem *reg; void __iomem *reg;
struct tegra_clk_frac_div frac_div;
const struct clk_ops *div_ops;
u8 width; u8 width;
u8 flags; u8 flags;
u8 div2_index; u8 div2_index;
@ -702,7 +704,10 @@ struct clk *tegra_clk_register_super_mux(const char *name,
const char **parent_names, u8 num_parents, const char **parent_names, u8 num_parents,
unsigned long flags, void __iomem *reg, u8 clk_super_flags, unsigned long flags, void __iomem *reg, u8 clk_super_flags,
u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock); 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 * struct clk_init_table - clock initialization table
* @clk_id: clock id as mentioned in device tree bindings * @clk_id: clock id as mentioned in device tree bindings