diff options
author | Peter De Schrijver <pdeschrijver@nvidia.com> | 2013-04-03 16:40:39 +0200 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2013-04-05 00:10:45 +0200 |
commit | 0b6525acd13f2d33cd3be86d0dbd2ddd1ffeda8f (patch) | |
tree | 989c920b532d4d5d7372c275ed828356cff9c581 /drivers/clk/tegra/clk-pll.c | |
parent | clk: tegra: introduce TEGRA_PLL_HAS_LOCK_ENABLE (diff) | |
download | linux-0b6525acd13f2d33cd3be86d0dbd2ddd1ffeda8f.tar.xz linux-0b6525acd13f2d33cd3be86d0dbd2ddd1ffeda8f.zip |
clk: tegra: Add PLL post divider table
Some PLLs in Tegra114 don't use a power of 2 mapping for the post divider.
Introduce a table based approach and switch PLLU to it.
Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'drivers/clk/tegra/clk-pll.c')
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index eaab060cda24..ccb367ee7e78 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -266,6 +266,7 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, unsigned long rate, unsigned long parent_rate) { struct tegra_clk_pll *pll = to_clk_pll(hw); + struct pdiv_map *p_tohw = pll->params->pdiv_tohw; unsigned long cfreq; u32 p_div = 0; @@ -299,7 +300,6 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, cfg->output_rate <<= 1) p_div++; - cfg->p = p_div; cfg->m = parent_rate / cfreq; cfg->n = cfg->output_rate / cfreq; cfg->cpcon = OUT_OF_TABLE_CPCON; @@ -312,8 +312,19 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, return -EINVAL; } - if (pll->flags & TEGRA_PLLU) - cfg->p ^= 1; + if (p_tohw) { + p_div = 1 << p_div; + while (p_tohw->pdiv) { + if (p_div <= p_tohw->pdiv) { + cfg->p = p_tohw->hw_val; + break; + } + p_tohw++; + } + if (!p_tohw->pdiv) + return -EINVAL; + } else + cfg->p = p_div; return 0; } @@ -460,8 +471,10 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, { struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table cfg; + struct pdiv_map *p_tohw = pll->params->pdiv_tohw; u32 val; u64 rate = parent_rate; + int pdiv; val = pll_readl_base(pll); @@ -480,10 +493,23 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, _get_pll_mnp(pll, &cfg); - if (pll->flags & TEGRA_PLLU) - cfg.p ^= 1; + if (p_tohw) { + while (p_tohw->pdiv) { + if (cfg.p == p_tohw->hw_val) { + pdiv = p_tohw->pdiv; + break; + } + p_tohw++; + } + + if (!p_tohw->pdiv) { + WARN_ON(1); + pdiv = 1; + } + } else + pdiv = 1 << cfg.p; - cfg.m *= 1 << cfg.p; + cfg.m *= pdiv; rate *= cfg.n; do_div(rate, cfg.m); |