aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches/0127-clk-qcom-Add-support-for-setting-rates-on-PLLs.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ipq806x/patches/0127-clk-qcom-Add-support-for-setting-rates-on-PLLs.patch')
-rw-r--r--target/linux/ipq806x/patches/0127-clk-qcom-Add-support-for-setting-rates-on-PLLs.patch155
1 files changed, 155 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches/0127-clk-qcom-Add-support-for-setting-rates-on-PLLs.patch b/target/linux/ipq806x/patches/0127-clk-qcom-Add-support-for-setting-rates-on-PLLs.patch
new file mode 100644
index 0000000000..2983b8444b
--- /dev/null
+++ b/target/linux/ipq806x/patches/0127-clk-qcom-Add-support-for-setting-rates-on-PLLs.patch
@@ -0,0 +1,155 @@
+From fd06a2cc719296f65a280cb1533b125f63cfcb34 Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Mon, 28 Apr 2014 15:58:11 -0700
+Subject: [PATCH 127/182] clk: qcom: Add support for setting rates on PLLs
+
+Some PLLs may require changing their rate at runtime. Add support
+for these PLLs.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/qcom/clk-pll.c | 68 +++++++++++++++++++++++++++++++++++++++++++-
+ drivers/clk/qcom/clk-pll.h | 20 +++++++++++++
+ 2 files changed, 87 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
+index 0f927c5..80c7a76 100644
+--- a/drivers/clk/qcom/clk-pll.c
++++ b/drivers/clk/qcom/clk-pll.c
+@@ -97,7 +97,7 @@ static unsigned long
+ clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+ {
+ struct clk_pll *pll = to_clk_pll(hw);
+- u32 l, m, n;
++ u32 l, m, n, config;
+ unsigned long rate;
+ u64 tmp;
+
+@@ -116,13 +116,79 @@ clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+ do_div(tmp, n);
+ rate += tmp;
+ }
++ if (pll->post_div_width) {
++ regmap_read(pll->clkr.regmap, pll->config_reg, &config);
++ config >>= pll->post_div_shift;
++ config &= BIT(pll->post_div_width) - 1;
++ rate /= config + 1;
++ }
++
+ return rate;
+ }
+
++static const
++struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
++{
++ if (!f)
++ return NULL;
++
++ for (; f->freq; f++)
++ if (rate <= f->freq)
++ return f;
++
++ return NULL;
++}
++
++static long
++clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *p_rate, struct clk **p)
++{
++ struct clk_pll *pll = to_clk_pll(hw);
++ const struct pll_freq_tbl *f;
++
++ f = find_freq(pll->freq_tbl, rate);
++ if (!f)
++ return clk_pll_recalc_rate(hw, *p_rate);
++
++ return f->freq;
++}
++
++static int
++clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
++{
++ struct clk_pll *pll = to_clk_pll(hw);
++ const struct pll_freq_tbl *f;
++ bool enabled;
++ u32 mode;
++ u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N;
++
++ f = find_freq(pll->freq_tbl, rate);
++ if (!f)
++ return -EINVAL;
++
++ regmap_read(pll->clkr.regmap, pll->mode_reg, &mode);
++ enabled = (mode & enable_mask) == enable_mask;
++
++ if (enabled)
++ clk_pll_disable(hw);
++
++ regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l);
++ regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m);
++ regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n);
++ regmap_write(pll->clkr.regmap, pll->config_reg, f->ibits);
++
++ if (enabled)
++ clk_pll_enable(hw);
++
++ return 0;
++}
++
+ const struct clk_ops clk_pll_ops = {
+ .enable = clk_pll_enable,
+ .disable = clk_pll_disable,
+ .recalc_rate = clk_pll_recalc_rate,
++ .determine_rate = clk_pll_determine_rate,
++ .set_rate = clk_pll_set_rate,
+ };
+ EXPORT_SYMBOL_GPL(clk_pll_ops);
+
+diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h
+index 0775a99..5f9928b 100644
+--- a/drivers/clk/qcom/clk-pll.h
++++ b/drivers/clk/qcom/clk-pll.h
+@@ -18,6 +18,21 @@
+ #include "clk-regmap.h"
+
+ /**
++ * struct pll_freq_tbl - PLL frequency table
++ * @l: L value
++ * @m: M value
++ * @n: N value
++ * @ibits: internal values
++ */
++struct pll_freq_tbl {
++ unsigned long freq;
++ u16 l;
++ u16 m;
++ u16 n;
++ u32 ibits;
++};
++
++/**
+ * struct clk_pll - phase locked loop (PLL)
+ * @l_reg: L register
+ * @m_reg: M register
+@@ -26,6 +41,7 @@
+ * @mode_reg: mode register
+ * @status_reg: status register
+ * @status_bit: ANDed with @status_reg to determine if PLL is enabled
++ * @freq_tbl: PLL frequency table
+ * @hw: handle between common and hardware-specific interfaces
+ */
+ struct clk_pll {
+@@ -36,6 +52,10 @@ struct clk_pll {
+ u32 mode_reg;
+ u32 status_reg;
+ u8 status_bit;
++ u8 post_div_width;
++ u8 post_div_shift;
++
++ const struct pll_freq_tbl *freq_tbl;
+
+ struct clk_regmap clkr;
+ };
+--
+1.7.10.4
+