This is a note to let you know that I've just added the patch titled clk-divider: Fix READ_ONLY when divider > 1 to the 3.17-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-divider-fix-read_only-when-divider-1.patch and it can be found in the queue-3.17 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From e6d5e7d90be92cee626d7ec16ca9b06f1eed710b Mon Sep 17 00:00:00 2001 From: James Hogan <james.hogan@xxxxxxxxxx> Date: Fri, 14 Nov 2014 15:32:09 +0000 Subject: clk-divider: Fix READ_ONLY when divider > 1 From: James Hogan <james.hogan@xxxxxxxxxx> commit e6d5e7d90be92cee626d7ec16ca9b06f1eed710b upstream. Commit 79c6ab509558 (clk: divider: add CLK_DIVIDER_READ_ONLY flag) in v3.16 introduced the CLK_DIVIDER_READ_ONLY flag which caused the recalc_rate() and round_rate() clock callbacks to be omitted. However using this flag has the unfortunate side effect of causing the clock recalculation code when a clock rate change is attempted to always treat it as a pass-through clock, i.e. with a fixed divide of 1, which may not be the case. Child clock rates are then recalculated using the wrong parent rate. Therefore instead of dropping the recalc_rate() and round_rate() callbacks, alter clk_divider_bestdiv() to always report the current divider as the best divider so that it is never altered. For me the read only clock was the system clock, which divided the PLL rate by 2, from which both the UART and the SPI clocks were divided. Initial setting of the UART rate set it correctly, but when the SPI clock was set, the other child clocks were miscalculated. The UART clock was recalculated using the PLL rate as the parent rate, resulting in a UART new_rate of double what it should be, and a UART which spewed forth garbage when the rate changes were propagated. Signed-off-by: James Hogan <james.hogan@xxxxxxxxxx> Cc: Thomas Abraham <thomas.ab@xxxxxxxxxxx> Cc: Tomasz Figa <t.figa@xxxxxxxxxxx> Cc: Max Schwarz <max.schwarz@xxxxxxxxx> Acked-by: Haojian Zhuang <haojian.zhuang@xxxxxxxxx> Signed-off-by: Michael Turquette <mturquette@xxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/clk/clk-divider.c | 18 +++++++++--------- drivers/clk/rockchip/clk.c | 4 +--- include/linux/clk-provider.h | 1 - 3 files changed, 10 insertions(+), 13 deletions(-) --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -263,6 +263,14 @@ static int clk_divider_bestdiv(struct cl if (!rate) rate = 1; + /* if read only, just return current value */ + if (divider->flags & CLK_DIVIDER_READ_ONLY) { + bestdiv = readl(divider->reg) >> divider->shift; + bestdiv &= div_mask(divider); + bestdiv = _get_div(divider, bestdiv); + return bestdiv; + } + maxdiv = _get_maxdiv(divider); if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { @@ -361,11 +369,6 @@ const struct clk_ops clk_divider_ops = { }; EXPORT_SYMBOL_GPL(clk_divider_ops); -const struct clk_ops clk_divider_ro_ops = { - .recalc_rate = clk_divider_recalc_rate, -}; -EXPORT_SYMBOL_GPL(clk_divider_ro_ops); - static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -391,10 +394,7 @@ static struct clk *_register_divider(str } init.name = name; - if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) - init.ops = &clk_divider_ro_ops; - else - init.ops = &clk_divider_ops; + init.ops = &clk_divider_ops; init.flags = flags | CLK_IS_BASIC; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -89,9 +89,7 @@ struct clk *rockchip_clk_register_branch div->width = div_width; div->lock = lock; div->table = div_table; - div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) - ? &clk_divider_ro_ops - : &clk_divider_ops; + div_ops = &clk_divider_ops; } clk = clk_register_composite(NULL, name, parent_names, num_parents, --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -341,7 +341,6 @@ struct clk_divider { #define CLK_DIVIDER_READ_ONLY BIT(5) extern const struct clk_ops clk_divider_ops; -extern const struct clk_ops clk_divider_ro_ops; struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, Patches currently in stable-queue which might be from james.hogan@xxxxxxxxxx are queue-3.17/mips-cpu-probe-set-the-ftlb-probability-bit-on-supported-cores.patch queue-3.17/mips-loongson3-fix-__node_distances-undefined-error.patch queue-3.17/clk-divider-fix-read_only-when-divider-1.patch queue-3.17/mips-ip27-fix-__node_distances-undefined-error.patch queue-3.17/mips-tlbex-fix-potential-htw-race-on-tlbl-m-s-handlers.patch -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html