The clk fixes for 4.0-rc4 comprise three themes. First are the usual
driver fixes for new regressions since v3.19. Second are fixes to the common clock divider type caused by recent changes to how we round clock rates. This affects many clock drivers that use this common code. Finally there are fixes for drivers that improperly compared struct clk pointers (drivers must not deref these pointers). While some of these drivers have done this for a long time, this did not cause a problem until we started generating unique struct clk pointers for every consumer. A new function, clk_is_match was introduced to get these drivers working again and they are fixed up to no longer deref the pointers themselves. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVBewEAAoJEKI6nJvDJaTUR2gP/2frIXCm/krwkDyofIGxxQ+F RwIXFTn9GG9QEUwKLUcxRUegHbWbZMXYp6W19hUcUdYz3pD+uEJSuH0NI8kW1Ohy 32P5/ALuoTq7OVzBBz/9di9jBDdIM1wusLZGJfOWk9DXBLOS3VHuhN55D47dqWS/ GsszeEpp8r1WBKFVmAkuQ5Jc0CqgS5GxvMOndXXVN3kDMhCT+9pBiqtUT0V3YV/J d5GCvfPlO/Xmjnpjf99MPButkfiW/o6YXt3H0QY6hhskS1Av8alyfabVctk8lqOW py8SQFY7MdRLZ84Zk87sqKCKUc/vHkTBT9vKWYm65l3yJ5OEFv60NaFMYY61HVlJ n6qWU6SbFZvkPnQTJn6Ii/v7BQ92bXjYpLNcBK8UY35jIjmHsPS/YXCbkmArtn1N /yAB4TIfH8uX93smFb3XEmZLSiKFuZAhU8YbjDzYgsGuQ9EwN3aNP9c5mzC7Soou tYnDqVic0i993qQTD2Db5dplGwxelCRJpazO2kK6NW/EJzE8XJaM6XVy1xIBKiDX bbWPdp53/eWV7gbUEZ8zzcS06G/DLw5/N45XyaWIx+2ThDjhOAlVHTAFDY+Oa743 42Dkwtr5GZ6yORyXY1wI5HttUGU0gnPN0kM84GQG8O/GbzGureZSW1e6G7tJJljn JXhROl0w4aIPwUUxry7R =nc5C -----END PGP SIGNATURE----- Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clock framework fixes from Michael Turquette: "The clk fixes for 4.0-rc4 comprise three themes. First are the usual driver fixes for new regressions since v3.19. Second are fixes to the common clock divider type caused by recent changes to how we round clock rates. This affects many clock drivers that use this common code. Finally there are fixes for drivers that improperly compared struct clk pointers (drivers must not deref these pointers). While some of these drivers have done this for a long time, this did not cause a problem until we started generating unique struct clk pointers for every consumer. A new function, clk_is_match was introduced to get these drivers working again and they are fixed up to no longer deref the pointers themselves" * tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: ASoC: kirkwood: fix struct clk pointer comparing ASoC: fsl_spdif: fix struct clk pointer comparing ARM: imx: fix struct clk pointer comparing clk: introduce clk_is_match clk: don't export static symbol clk: divider: fix calculation of initial best divider when rounding to closest clk: divider: fix selection of divider when rounding to closest clk: divider: fix calculation of maximal parent rate for a given divider clk: divider: return real rate instead of divider value clk: qcom: fix platform_no_drv_owner.cocci warnings clk: qcom: fix platform_no_drv_owner.cocci warnings clk: qcom: Add PLL4 vote clock clk: qcom: lcc-msm8960: Fix PLL rate detection clk: qcom: Fix slimbus n and m val offsets clk: ti: Fix FAPLL parent enable bit handling
This commit is contained in:
commit
1ee89c519a
10 changed files with 83 additions and 29 deletions
|
@ -211,8 +211,9 @@ static void __init imx6q_1588_init(void)
|
|||
* set bit IOMUXC_GPR1[21]. Or the PTP clock must be from pad
|
||||
* (external OSC), and we need to clear the bit.
|
||||
*/
|
||||
clksel = ptp_clk == enet_ref ? IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
|
||||
IMX6Q_GPR1_ENET_CLK_SEL_PAD;
|
||||
clksel = clk_is_match(ptp_clk, enet_ref) ?
|
||||
IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
|
||||
IMX6Q_GPR1_ENET_CLK_SEL_PAD;
|
||||
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
|
||||
if (!IS_ERR(gpr))
|
||||
regmap_update_bits(gpr, IOMUXC_GPR1,
|
||||
|
|
|
@ -144,12 +144,6 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
|
|||
divider->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* The reverse of DIV_ROUND_UP: The maximum number which
|
||||
* divided by m is r
|
||||
*/
|
||||
#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
|
||||
|
||||
static bool _is_valid_table_div(const struct clk_div_table *table,
|
||||
unsigned int div)
|
||||
{
|
||||
|
@ -225,19 +219,24 @@ static int _div_round_closest(const struct clk_div_table *table,
|
|||
unsigned long parent_rate, unsigned long rate,
|
||||
unsigned long flags)
|
||||
{
|
||||
int up, down, div;
|
||||
int up, down;
|
||||
unsigned long up_rate, down_rate;
|
||||
|
||||
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
|
||||
up = DIV_ROUND_UP(parent_rate, rate);
|
||||
down = parent_rate / rate;
|
||||
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO) {
|
||||
up = __roundup_pow_of_two(div);
|
||||
down = __rounddown_pow_of_two(div);
|
||||
up = __roundup_pow_of_two(up);
|
||||
down = __rounddown_pow_of_two(down);
|
||||
} else if (table) {
|
||||
up = _round_up_table(table, div);
|
||||
down = _round_down_table(table, div);
|
||||
up = _round_up_table(table, up);
|
||||
down = _round_down_table(table, down);
|
||||
}
|
||||
|
||||
return (up - div) <= (div - down) ? up : down;
|
||||
up_rate = DIV_ROUND_UP(parent_rate, up);
|
||||
down_rate = DIV_ROUND_UP(parent_rate, down);
|
||||
|
||||
return (rate - up_rate) <= (down_rate - rate) ? up : down;
|
||||
}
|
||||
|
||||
static int _div_round(const struct clk_div_table *table,
|
||||
|
@ -313,7 +312,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
|||
return i;
|
||||
}
|
||||
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
|
||||
MULT_ROUND_UP(rate, i));
|
||||
rate * i);
|
||||
now = DIV_ROUND_UP(parent_rate, i);
|
||||
if (_is_best_div(rate, now, best, flags)) {
|
||||
bestdiv = i;
|
||||
|
@ -353,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
bestdiv = readl(divider->reg) >> divider->shift;
|
||||
bestdiv &= div_mask(divider->width);
|
||||
bestdiv = _get_div(divider->table, bestdiv, divider->flags);
|
||||
return bestdiv;
|
||||
return DIV_ROUND_UP(*prate, bestdiv);
|
||||
}
|
||||
|
||||
return divider_round_rate(hw, rate, prate, divider->table,
|
||||
|
|
|
@ -1350,7 +1350,6 @@ static unsigned long clk_core_get_rate(struct clk_core *clk)
|
|||
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_core_get_rate);
|
||||
|
||||
/**
|
||||
* clk_get_rate - return the rate of clk
|
||||
|
@ -2170,6 +2169,32 @@ int clk_get_phase(struct clk *clk)
|
|||
return clk_core_get_phase(clk->core);
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_is_match - check if two clk's point to the same hardware clock
|
||||
* @p: clk compared against q
|
||||
* @q: clk compared against p
|
||||
*
|
||||
* Returns true if the two struct clk pointers both point to the same hardware
|
||||
* clock node. Put differently, returns true if struct clk *p and struct clk *q
|
||||
* share the same struct clk_core object.
|
||||
*
|
||||
* Returns false otherwise. Note that two NULL clks are treated as matching.
|
||||
*/
|
||||
bool clk_is_match(const struct clk *p, const struct clk *q)
|
||||
{
|
||||
/* trivial case: identical struct clk's or both NULL */
|
||||
if (p == q)
|
||||
return true;
|
||||
|
||||
/* true if clk->core pointers match. Avoid derefing garbage */
|
||||
if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
|
||||
if (p->core == q->core)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_is_match);
|
||||
|
||||
/**
|
||||
* __clk_init - initialize the data structures in a struct clk
|
||||
* @dev: device initializing this clk, placeholder for now
|
||||
|
|
|
@ -48,6 +48,17 @@ static struct clk_pll pll3 = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap pll4_vote = {
|
||||
.enable_reg = 0x34c0,
|
||||
.enable_mask = BIT(4),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "pll4_vote",
|
||||
.parent_names = (const char *[]){ "pll4" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_pll_vote_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_pll pll8 = {
|
||||
.l_reg = 0x3144,
|
||||
.m_reg = 0x3148,
|
||||
|
@ -3023,6 +3034,7 @@ static struct clk_branch rpm_msg_ram_h_clk = {
|
|||
|
||||
static struct clk_regmap *gcc_msm8960_clks[] = {
|
||||
[PLL3] = &pll3.clkr,
|
||||
[PLL4_VOTE] = &pll4_vote,
|
||||
[PLL8] = &pll8.clkr,
|
||||
[PLL8_VOTE] = &pll8_vote,
|
||||
[PLL14] = &pll14.clkr,
|
||||
|
@ -3247,6 +3259,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = {
|
|||
|
||||
static struct clk_regmap *gcc_apq8064_clks[] = {
|
||||
[PLL3] = &pll3.clkr,
|
||||
[PLL4_VOTE] = &pll4_vote,
|
||||
[PLL8] = &pll8.clkr,
|
||||
[PLL8_VOTE] = &pll8_vote,
|
||||
[PLL14] = &pll14.clkr,
|
||||
|
|
|
@ -462,7 +462,6 @@ static struct platform_driver lcc_ipq806x_driver = {
|
|||
.remove = lcc_ipq806x_remove,
|
||||
.driver = {
|
||||
.name = "lcc-ipq806x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = lcc_ipq806x_match_table,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -417,8 +417,8 @@ static struct clk_rcg slimbus_src = {
|
|||
.mnctr_en_bit = 8,
|
||||
.mnctr_reset_bit = 7,
|
||||
.mnctr_mode_shift = 5,
|
||||
.n_val_shift = 16,
|
||||
.m_val_shift = 16,
|
||||
.n_val_shift = 24,
|
||||
.m_val_shift = 8,
|
||||
.width = 8,
|
||||
},
|
||||
.p = {
|
||||
|
@ -547,7 +547,7 @@ static int lcc_msm8960_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(regmap);
|
||||
|
||||
/* Use the correct frequency plan depending on speed of PLL4 */
|
||||
val = regmap_read(regmap, 0x4, &val);
|
||||
regmap_read(regmap, 0x4, &val);
|
||||
if (val == 0x12) {
|
||||
slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
|
||||
|
@ -574,7 +574,6 @@ static struct platform_driver lcc_msm8960_driver = {
|
|||
.remove = lcc_msm8960_remove,
|
||||
.driver = {
|
||||
.name = "lcc-msm8960",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = lcc_msm8960_match_table,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -84,7 +84,7 @@ static int ti_fapll_enable(struct clk_hw *hw)
|
|||
struct fapll_data *fd = to_fapll(hw);
|
||||
u32 v = readl_relaxed(fd->base);
|
||||
|
||||
v |= (1 << FAPLL_MAIN_PLLEN);
|
||||
v |= FAPLL_MAIN_PLLEN;
|
||||
writel_relaxed(v, fd->base);
|
||||
|
||||
return 0;
|
||||
|
@ -95,7 +95,7 @@ static void ti_fapll_disable(struct clk_hw *hw)
|
|||
struct fapll_data *fd = to_fapll(hw);
|
||||
u32 v = readl_relaxed(fd->base);
|
||||
|
||||
v &= ~(1 << FAPLL_MAIN_PLLEN);
|
||||
v &= ~FAPLL_MAIN_PLLEN;
|
||||
writel_relaxed(v, fd->base);
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ static int ti_fapll_is_enabled(struct clk_hw *hw)
|
|||
struct fapll_data *fd = to_fapll(hw);
|
||||
u32 v = readl_relaxed(fd->base);
|
||||
|
||||
return v & (1 << FAPLL_MAIN_PLLEN);
|
||||
return v & FAPLL_MAIN_PLLEN;
|
||||
}
|
||||
|
||||
static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
|
||||
|
|
|
@ -125,6 +125,19 @@ int clk_set_phase(struct clk *clk, int degrees);
|
|||
*/
|
||||
int clk_get_phase(struct clk *clk);
|
||||
|
||||
/**
|
||||
* clk_is_match - check if two clk's point to the same hardware clock
|
||||
* @p: clk compared against q
|
||||
* @q: clk compared against p
|
||||
*
|
||||
* Returns true if the two struct clk pointers both point to the same hardware
|
||||
* clock node. Put differently, returns true if struct clk *p and struct clk *q
|
||||
* share the same struct clk_core object.
|
||||
*
|
||||
* Returns false otherwise. Note that two NULL clks are treated as matching.
|
||||
*/
|
||||
bool clk_is_match(const struct clk *p, const struct clk *q);
|
||||
|
||||
#else
|
||||
|
||||
static inline long clk_get_accuracy(struct clk *clk)
|
||||
|
@ -142,6 +155,11 @@ static inline long clk_get_phase(struct clk *clk)
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline bool clk_is_match(const struct clk *p, const struct clk *q)
|
||||
{
|
||||
return p == q;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
@ -1049,7 +1049,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
|
|||
enum spdif_txrate index, bool round)
|
||||
{
|
||||
const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
|
||||
bool is_sysclk = clk == spdif_priv->sysclk;
|
||||
bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
|
||||
u64 rate_ideal, rate_actual, sub;
|
||||
u32 sysclk_dfmin, sysclk_dfmax;
|
||||
u32 txclk_df, sysclk_df, arate;
|
||||
|
@ -1143,7 +1143,7 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
|
|||
spdif_priv->txclk_src[index], rate[index]);
|
||||
dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
|
||||
spdif_priv->txclk_df[index], rate[index]);
|
||||
if (spdif_priv->txclk[index] == spdif_priv->sysclk)
|
||||
if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk))
|
||||
dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
|
||||
spdif_priv->sysclk_df[index], rate[index]);
|
||||
dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n",
|
||||
|
|
|
@ -579,7 +579,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
|||
if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
} else {
|
||||
if (priv->extclk == priv->clk) {
|
||||
if (clk_is_match(priv->extclk, priv->clk)) {
|
||||
devm_clk_put(&pdev->dev, priv->extclk);
|
||||
priv->extclk = ERR_PTR(-EINVAL);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue