struct clk **best_parent_p)
{
struct clk *npll = clk_get(NULL, "clk_npll");
- unsigned long div, prate, best;
+ unsigned long div, prate, best, *p_prate;
+ static unsigned long rk3368_pll_rates[] = {1188*MHZ, 0};
- *best_parent_p = npll;
+ if (best_parent_p)
+ *best_parent_p = npll;
+ /* first get parent_rate from table */
+ p_prate = rk3368_pll_rates;
+
+ while (*p_prate) {
+ if (!(*p_prate % (rate*2)) || (*p_prate == rate)) {
+ clk_debug("%s: get rate from table\n", __func__);
+ *best_parent_rate = *p_prate;
+ best = rate;
+ return best;
+ }
+ p_prate++;
+ }
+
+ /* if not suitable parent_rate found in table, then auto calc rate */
div = RK3368_LIMIT_NPLL/rate;
/* div should be even */
if (div % 2)
_RK3368_APLL_SET_CLKS(0, 1, 32, 16, 2, 1, 1),
};
+static const struct pll_clk_set rk3368_pll_table_low_jitter[] = {
+ /* _khz, nr, nf, no, nb */
+ _RK3188PLUS_PLL_SET_CLKS_NB(1188000, 1, 99, 2, 1),
+ _RK3188PLUS_PLL_SET_CLKS( 0, 0, 0, 0),
+};
+
static void pll_wait_lock(struct clk_hw *hw)
{
struct clk_pll *pll = to_clk_pll(hw);
.is_enabled = clk_pll_is_enabled_3188plus,
};
+static long clk_pll_round_rate_3368_low_jitter(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long best;
+ struct pll_clk_set *p_clk_set;
+
+ p_clk_set = (struct pll_clk_set *)(rk3368_pll_table_low_jitter);
+
+ while (p_clk_set->rate) {
+ if (p_clk_set->rate == rate)
+ break;
+ p_clk_set++;
+ }
+
+ if (p_clk_set->rate == rate) {
+ clk_debug("get rate from table\n");
+ return rate;
+ }
+
+ for (best = rate; best > 0; best--) {
+ if (!pll_clk_get_best_set(*prate, best, NULL, NULL, NULL))
+ return best;
+ }
+
+ clk_err("%s: can't round rate %lu\n", __func__, rate);
+ return 0;
+}
+
+
+static int clk_pll_set_rate_3368_low_jitter(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned long best;
+ u32 nr, nf, no;
+ struct pll_clk_set clk_set, *p_clk_set;
+ int ret;
+
+ p_clk_set = (struct pll_clk_set *)(rk3368_pll_table_low_jitter);
+
+ while (p_clk_set->rate) {
+ if (p_clk_set->rate == rate)
+ break;
+ p_clk_set++;
+ }
+
+ if (p_clk_set->rate == rate) {
+ clk_debug("get rate from table\n");
+ goto set_rate;
+ }
+
+ best = clk_pll_round_rate_3188plus_auto(hw, rate, &parent_rate);
+
+ if (!best)
+ return -EINVAL;
+
+ pll_clk_get_best_set(parent_rate, best, &nr, &nf, &no);
+
+ /* prepare clk_set */
+ clk_set.rate = best;
+ clk_set.pllcon0 = RK3188PLUS_PLL_CLKR_SET(nr)|RK3188PLUS_PLL_CLKOD_SET(no);
+ clk_set.pllcon1 = RK3188PLUS_PLL_CLKF_SET(nf);
+ clk_set.pllcon2 = RK3188PLUS_PLL_CLK_BWADJ_SET(nf >> 1);
+ clk_set.rst_dly = ((nr*500)/24+1);
+
+ p_clk_set = &clk_set;
+
+set_rate:
+ ret = _pll_clk_set_rate_3188plus(p_clk_set, hw);
+ clk_debug("pll %s set rate=%lu OK!\n", __clk_get_name(hw->clk),
+ p_clk_set->rate);
+
+ return ret;
+}
+
+static const struct clk_ops clk_pll_ops_3368_low_jitter = {
+ .recalc_rate = clk_pll_recalc_rate_3188plus_auto,
+ .round_rate = clk_pll_round_rate_3368_low_jitter,
+ .set_rate = clk_pll_set_rate_3368_low_jitter,
+ .enable = clk_pll_enable_3188plus,
+ .disable = clk_pll_disable_3188plus,
+ .is_enabled = clk_pll_is_enabled_3188plus,
+};
/* CLK_PLL_3188PLUS_APLL type ops */
static unsigned long clk_pll_recalc_rate_3188plus_apll(struct clk_hw *hw,
case CLK_PLL_3368_APLLL:
return &clk_pll_ops_3368_aplll;
+ case CLK_PLL_3368_LOW_JITTER:
+ return &clk_pll_ops_3368_low_jitter;
+
default:
clk_err("%s: unknown pll_flags!\n", __func__);
return NULL;
.rst_dly = ((nr*500)/24+1),\
}
+#define _RK3188PLUS_PLL_SET_CLKS_NB(_mhz, nr, nf, no, nb) \
+{ \
+ .rate = (_mhz) * KHZ, \
+ .pllcon0 = RK3188PLUS_PLL_CLKR_SET(nr)|RK3188PLUS_PLL_CLKOD_SET(no), \
+ .pllcon1 = RK3188PLUS_PLL_CLKF_SET(nf),\
+ .pllcon2 = RK3188PLUS_PLL_CLK_BWADJ_SET(nb-1),\
+ .rst_dly = ((nr*500)/24+1),\
+}
+
#define _RK3188_APLL_SET_CLKS(_mhz, nr, nf, no, _periph_div, _aclk_div) \
{ \
.rate = _mhz * MHZ, \