Skip to content

Commit

Permalink
Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
torvalds committed Mar 15, 2015
2 parents 6981e2a + aaa6d06 commit 1ee89c5
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 29 deletions.
5 changes: 3 additions & 2 deletions arch/arm/mach-imx/mach-imx6q.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
29 changes: 14 additions & 15 deletions drivers/clk/clk-divider.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
27 changes: 26 additions & 1 deletion drivers/clk/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions drivers/clk/qcom/gcc-msm8960.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion drivers/clk/qcom/lcc-ipq806x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
};
Expand Down
7 changes: 3 additions & 4 deletions drivers/clk/qcom/lcc-msm8960.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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;
Expand All @@ -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,
},
};
Expand Down
6 changes: 3 additions & 3 deletions drivers/clk/ti/fapll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

Expand All @@ -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,
Expand Down
18 changes: 18 additions & 0 deletions include/linux/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

/**
Expand Down
4 changes: 2 additions & 2 deletions sound/soc/fsl/fsl_spdif.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/kirkwood/kirkwood-i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 1ee89c5

Please sign in to comment.