}
if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
- _calc_rate(hw, &cfg, rate, parent_rate)) {
+ pll->params->calc_rate(hw, &cfg, rate, parent_rate)) {
pr_err("%s: Failed to set %s rate %lu\n", __func__,
clk_hw_get_name(hw), rate);
WARN_ON(1);
return clk_hw_get_rate(hw);
if (_get_table_rate(hw, &cfg, rate, *prate) &&
- _calc_rate(hw, &cfg, rate, *prate))
+ pll->params->calc_rate(hw, &cfg, rate, *prate))
return -EINVAL;
return cfg.output_rate;
static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate)
{
+ u16 mdiv = parent_rate / pll_params->cf_min;
+
+ if (pll_params->flags & TEGRA_MDIV_NEW)
+ return (!pll_params->mdiv_default ? mdiv :
+ min(mdiv, pll_params->mdiv_default));
+
+ if (pll_params->mdiv_default)
+ return pll_params->mdiv_default;
+
if (parent_rate > pll_params->cf_max)
return 2;
else
return 1;
}
+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+ return (u16)_pll_fixed_mdiv(pll->params, input_rate);
+}
+
static unsigned long _clip_vco_min(unsigned long vco_min,
unsigned long parent_rate)
{
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
+ /* Default to _calc_rate if unspecified */
+ if (!pll->params->calc_rate)
+ pll->params->calc_rate = _calc_rate;
+
/* Data in .init is copied by clk_register(), so stack variable OK */
pll->hw.init = &init;
* @div_nmp: offsets and widths on n, m and p fields
* @freq_table: array of frequencies supported by PLL
* @fixed_rate: PLL rate if it is fixed
+ * @mdiv_default: Default value for fixed mdiv for this PLL
+ * @round_p_to_pdiv: Callback used to round p to the closed pdiv
* @set_gain: Callback to adjust N div for SDM enabled
* PLL's based on fractional divider value.
+ * @calc_rate: Callback used to change how out of table
+ * rates (dividers and multipler) are calculated.
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
* base register.
* TEGRA_PLL_BYPASS - PLL has bypass bit
* TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring
+ * TEGRA_MDIV_NEW - Switch to new method for calculating fixed mdiv
+ * it may be more accurate (especially if SDM present)
*/
struct tegra_clk_pll_params {
unsigned long input_min;
struct div_nmp *div_nmp;
struct tegra_clk_pll_freq_table *freq_table;
unsigned long fixed_rate;
+ u16 mdiv_default;
+ u32 (*round_p_to_pdiv)(u32 p, u32 *pdiv);
void (*set_gain)(struct tegra_clk_pll_freq_table *cfg);
+ int (*calc_rate)(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate);
};
#define TEGRA_PLL_USE_LOCK BIT(0)
#define TEGRA_PLL_LOCK_MISC BIT(8)
#define TEGRA_PLL_BYPASS BIT(9)
#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
+#define TEGRA_MDIV_NEW BIT(11)
/**
* struct tegra_clk_pll - Tegra PLL clock
typedef void (*tegra_clk_apply_init_table_func)(void);
extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll);
+u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate);
#endif /* TEGRA_CLK_H */