ARM: tegra30: clocks: add AHB and APB clocks

Adding the AHB and APB bus clock for Tegra30.

Signed-off-by: Joseph Lo <josephl@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
This commit is contained in:
Joseph Lo 2012-10-29 18:25:29 +08:00 committed by Stephen Warren
parent 25804d8123
commit d534b5d4a5
4 changed files with 157 additions and 0 deletions

View file

@ -104,6 +104,10 @@ static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = {
{ "clk_m", NULL, 0, true },
{ "pll_p", "clk_m", 408000000, true },
{ "pll_p_out1", "pll_p", 9600000, true },
{ "pll_p_out4", "pll_p", 102000000, true },
{ "sclk", "pll_p_out4", 102000000, true },
{ "hclk", "sclk", 102000000, true },
{ "pclk", "hclk", 51000000, true },
{ NULL, NULL, 0, 0},
};
#endif

View file

@ -791,6 +791,112 @@ struct clk_ops tegra30_twd_ops = {
.recalc_rate = tegra30_twd_clk_recalc_rate,
};
/* bus clock functions */
static int tegra30_bus_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
return c->state;
}
static int tegra30_bus_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
val = clk_readl(c->reg);
val &= ~(BUS_CLK_DISABLE << c->reg_shift);
clk_writel(val, c->reg);
return 0;
}
static void tegra30_bus_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
val = clk_readl(c->reg);
val |= BUS_CLK_DISABLE << c->reg_shift;
clk_writel(val, c->reg);
}
static unsigned long tegra30_bus_clk_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
u64 rate = prate;
c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
c->mul = 1;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static int tegra30_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
int ret = -EINVAL;
u32 val;
int i;
val = clk_readl(c->reg);
for (i = 1; i <= 4; i++) {
if (rate == parent_rate / i) {
val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
val |= (i - 1) << c->reg_shift;
clk_writel(val, c->reg);
c->div = i;
c->mul = 1;
ret = 0;
break;
}
}
return ret;
}
static long tegra30_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
unsigned long parent_rate = *prate;
s64 divider;
if (rate >= parent_rate)
return parent_rate;
divider = parent_rate;
divider += rate - 1;
do_div(divider, rate);
if (divider < 0)
return divider;
if (divider > 4)
divider = 4;
do_div(parent_rate, divider);
return parent_rate;
}
struct clk_ops tegra30_bus_ops = {
.is_enabled = tegra30_bus_clk_is_enabled,
.enable = tegra30_bus_clk_enable,
.disable = tegra30_bus_clk_disable,
.set_rate = tegra30_bus_clk_set_rate,
.round_rate = tegra30_bus_clk_round_rate,
.recalc_rate = tegra30_bus_clk_recalc_rate,
};
/* Blink output functions */
static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)
{

View file

@ -34,6 +34,7 @@ extern struct clk_ops tegra_clk_out_ops;
extern struct clk_ops tegra30_super_ops;
extern struct clk_ops tegra30_blink_clk_ops;
extern struct clk_ops tegra30_twd_ops;
extern struct clk_ops tegra30_bus_ops;
extern struct clk_ops tegra30_periph_clk_ops;
extern struct clk_ops tegra30_dsib_clk_ops;
extern struct clk_ops tegra_nand_clk_ops;

View file

@ -711,6 +711,50 @@ static struct clk tegra_clk_sclk = {
.num_parents = ARRAY_SIZE(mux_sclk),
};
static const char *tegra_hclk_parent_names[] = {
"tegra_sclk",
};
static struct clk *tegra_hclk_parents[] = {
&tegra_clk_sclk,
};
static struct clk tegra_hclk;
static struct clk_tegra tegra_hclk_hw = {
.hw = {
.clk = &tegra_hclk,
},
.flags = DIV_BUS,
.reg = 0x30,
.reg_shift = 4,
.max_rate = 378000000,
.min_rate = 12000000,
};
DEFINE_CLK_TEGRA(hclk, 0, &tegra30_bus_ops, 0, tegra_hclk_parent_names,
tegra_hclk_parents, &tegra_clk_sclk);
static const char *tegra_pclk_parent_names[] = {
"tegra_hclk",
};
static struct clk *tegra_pclk_parents[] = {
&tegra_hclk,
};
static struct clk tegra_pclk;
static struct clk_tegra tegra_pclk_hw = {
.hw = {
.clk = &tegra_pclk,
},
.flags = DIV_BUS,
.reg = 0x30,
.reg_shift = 0,
.max_rate = 167000000,
.min_rate = 12000000,
};
DEFINE_CLK_TEGRA(pclk, 0, &tegra30_bus_ops, 0, tegra_pclk_parent_names,
tegra_pclk_parents, &tegra_hclk);
static const char *mux_blink[] = {
"clk_32k",
};
@ -1325,6 +1369,8 @@ struct clk *tegra_ptr_clks[] = {
&tegra_cml1,
&tegra_pciex,
&tegra_clk_sclk,
&tegra_hclk,
&tegra_pclk,
&tegra_clk_blink,
&tegra30_clk_twd,
};