Patch "clk: qcom: Properly change rates for ahbix clock" has been added to the 4.0-stable tree
This is a note to let you know that I've just added the patch titled
clk: qcom: Properly change rates for ahbix clock
to the 4.0-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
clk-qcom-properly-change-rates-for-ahbix-clock.patch
and it can be found in the queue-4.0 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
9d3745d44a7faa7d24db7facb1949a1378162f3eMon Sep 17 00:00:00 2001
From: Stephen Boyd <[email protected]>
Date: Fri, 6 Mar 2015 15:41:53 -0800
Subject: clk: qcom: Properly change rates for ahbix clock
From: Stephen Boyd <[email protected]>
commit 9d3745d44a7faa7d24db7facb1949a1378162f3e upstream.
The ahbix clock can never be turned off in practice. To change the rates we need to switch the mux off the M/N counter to an always on source (XO), reprogram the M/N counter to get the rate we want and finally switch back to the M/N counter. Add a new ops structure for this type of clock so that we can set the rate properly.
--- drivers/clk/qcom/clk-rcg.c | 62 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-rcg.h | 1 drivers/clk/qcom/lcc-ipq806x.c | 5 +-- 3 files changed, 65 insertions(+), 3 deletions(-)
drivers/clk/qcom/clk-rcg.c +62 -0
@@ -495,6 +495,57 @@ static int clk_rcg_bypass_set_rate(strucreturn __clk_rcg_set_rate (rcg, rcg->freq_tbl); } +/* +* This type of clock has a glitch-free mux that switches between the output of +* the M/N counter and an always on clock source (XO). When clk_set_rate() is +* called we need to make sure that we don't switch to the M/N counter if it +* isn't clocking because the mux will get stuck and the clock will stop +* outputting a clock. This can happen if the framework isn't aware that this +* clock is on and so clk_set_rate() doesn't turn on the new parent. To fix +* this we switch the mux in the enable/disable ops and reprogram the M/N +* counter in the set_rate op. We also make sure to switch away from the M/N +* counter in set_rate if software thinks the clock is off. +*/ +static int clk_rcg_lcc_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct clk_rcg *rcg =to_clk_rcg (hw); +const struct freq_tbl *f; +int ret; +u32 gfm =BIT (10 ); + + f =qcom_find_freq (rcg->freq_tbl, rate); +if (!f) +return -EINVAL ; + +/* Switch to XO to avoid glitches */ +regmap_update_bits (rcg->clkr.regmap, rcg->ns_reg, gfm,0 ); + ret =__clk_rcg_set_rate (rcg, f); +/* Switch back to M/N if it's clocking */ +if (__clk_is_enabled (hw->clk)) +regmap_update_bits (rcg->clkr.regmap, rcg->ns_reg, gfm, gfm); + +return ret; +} + +static int clk_rcg_lcc_enable (struct clk_hw *hw) +{ +struct clk_rcg *rcg =to_clk_rcg (hw); +u32 gfm =BIT (10 ); + +/* Use M/N */ +return regmap_update_bits (rcg->clkr.regmap, rcg->ns_reg, gfm, gfm); +} + +static void clk_rcg_lcc_disable (struct clk_hw *hw) +{ +struct clk_rcg *rcg =to_clk_rcg (hw); +u32 gfm =BIT (10 ); + +/* Use XO */ +regmap_update_bits (rcg->clkr.regmap, rcg->ns_reg, gfm,0 ); +} +static int __clk_dyn_rcg_set_rate (struct clk_hw *hw,unsigned long rate) {struct clk_dyn_rcg *rcg =to_clk_dyn_rcg (hw);
@@ -543,6 +594,17 @@ const struct clk_ops clk_rcg_bypass_ops };EXPORT_SYMBOL_GPL (clk_rcg_bypass_ops); +const struct clk_ops clk_rcg_lcc_ops = { + .enable = clk_rcg_lcc_enable, + .disable = clk_rcg_lcc_disable, + .get_parent = clk_rcg_get_parent, + .set_parent = clk_rcg_set_parent, + .recalc_rate = clk_rcg_recalc_rate, + .determine_rate = clk_rcg_determine_rate, + .set_rate = clk_rcg_lcc_set_rate, +}; +EXPORT_SYMBOL_GPL (clk_rcg_lcc_ops); +const struct clk_ops clk_dyn_rcg_ops = { .enable = clk_enable_regmap, .is_enabled = clk_is_enabled_regmap,
drivers/clk/qcom/clk-rcg.h +1 -0
@@ -96,6 +96,7 @@ struct clk_rcg {extern const struct clk_ops clk_rcg_ops;extern const struct clk_ops clk_rcg_bypass_ops; +extern const struct clk_ops clk_rcg_lcc_ops;#define to_clk_rcg (_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr)
drivers/clk/qcom/lcc-ipq806x.c +2 -3
@@ -386,13 +386,12 @@ static struct clk_rcg ahbix_clk = { .freq_tbl = clk_tbl_ahbix, .clkr = { .enable_reg = 0x38, - .enable_mask = BIT(10), /* toggle the gfmux to select mn/pxo */ + .enable_mask = BIT(11), .hw.init = &(struct clk_init_data ){ .name ="ahbix" , .parent_names = lcc_pxo_pll4, .num_parents =2 , - .ops = &clk_rcg_ops, - .flags =CLK_SET_RATE_GATE , + .ops = &clk_rcg_lcc_ops, }, }, };
Patches currently in stable-queue which might be from [email protected] are
queue-4.0/clk-qcom-fix-ipq806x-lcc-frequency-tables.patch queue-4.0/clk-qcom-fix-i2c-frequency-table.patch queue-4.0/clk-qcom-properly-change-rates-for-ahbix-clock.patch queue-4.0/clk-qcom-fix-rcg-m-n-counter-configuration.patch