Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: ingenic: Fix bugs with divided dividers

Two fixes in one:

- In the "impose hardware constraints" block, the "logical" divider
value (aka. not translated to the hardware) was clamped to fit in the
register area, but this totally ignored the fact that the divider
value can itself have a fixed divider.

- The code that made sure that the divider value returned by the
function was a multiple of its own fixed divider could result in a
wrong value being calculated, because it was rounded down instead of
rounded up.

Fixes: 4afe2d1a6ed5 ("clk: ingenic: Allow divider value to be divided")
Co-developed-by: Artur Rojek <contact@artur-rojek.eu>
Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Link: https://lore.kernel.org/r/20211001172033.122329-1-paul@crapouillou.net
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Paul Cercueil and committed by
Stephen Boyd
ed84ef1c e2ceaa86

+3 -3
+3 -3
drivers/clk/ingenic/cgu.c
··· 453 453 } 454 454 455 455 /* Impose hardware constraints */ 456 - div = min_t(unsigned, div, 1 << clk_info->div.bits); 457 - div = max_t(unsigned, div, 1); 456 + div = clamp_t(unsigned int, div, clk_info->div.div, 457 + clk_info->div.div << clk_info->div.bits); 458 458 459 459 /* 460 460 * If the divider value itself must be divided before being written to 461 461 * the divider register, we must ensure we don't have any bits set that 462 462 * would be lost as a result of doing so. 463 463 */ 464 - div /= clk_info->div.div; 464 + div = DIV_ROUND_UP(div, clk_info->div.div); 465 465 div *= clk_info->div.div; 466 466 467 467 return div;