[PATCHv2 3/6] ARM: socfpga: Add support to gate peripheral clocks
Pavel Machek
pavel at denx.de
Fri May 17 07:09:40 EDT 2013
Hi!
> From: Dinh Nguyen <dinguyen at altera.com>
>
> Add support to gate the clocks that directly feed peripherals. For clocks
> with multiple parents, add the ability to determine the correct parent,
> and also set parents. Also add support to calculate and set the clocks'
> rate.
>
> Signed-off-by: Dinh Nguyen <dinguyen at altera.com>
> Reviewed-by: Pavel Machek <pavel at denx.de>
> CC: Mike Turquette <mturquette at linaro.org>
> CC: Arnd Bergmann <arnd at arndb.de>
> CC: Olof Johansson <olof at lixom.net>
> Cc: Pavel Machek <pavel at denx.de>
> CC: <linux at arm.linux.org.uk>
>
> v2:
> - Fix space/indent errors
> - Add streq for strcmp == 0
> ---
> +static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
> +{
> + u32 l4_src;
> + u32 perpll_src;
> + u8 parent;
> +
> + if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
> + l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> + l4_src &= 0x1;
> + parent = l4_src;
> + } else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
> + l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> + l4_src = ((l4_src & 0x2) >> 1);
> + parent = l4_src;
> + } else {
> + perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
> + if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
> + perpll_src &= 0x3;
> + else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
> + streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
> + perpll_src = ((perpll_src & 0xC) >> 2);
> + else /*QSPI clock */
> + perpll_src = ((perpll_src & 0x30) >> 4);
> + parent = perpll_src;
I really don't like the "else" here. If some new clock name appears in
hwclk->init->name or if there's problem somewhere, it will just
silently operate wrong clock. WARN_ON(!streq(...))?
(I tried to append patch to previous email, with suggested
cleanups....)
> + } else {/*QSPI clock */
> + src_reg &= ~0x30;
> + src_reg |= (parent << 4);
> + }
Same here. (And there should be space after /* ).
> + socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
> + if (WARN_ON(!socfpga_clk))
> + return;
> +
> + rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
> + if (rc)
> + clk_gate[0] = 0;
> +
> + rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
> + if (rc)
> + socfpga_clk->fixed_div = 0;
> + else
> + socfpga_clk->fixed_div = fixed_div;
> +
> + if (clk_gate[0]) {
> + socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
> + socfpga_clk->hw.bit_idx = clk_gate[1];
> +
> + gateclk_ops.enable = clk_gate_ops.enable;
> + gateclk_ops.disable = clk_gate_ops.disable;
> + }
> +
Could if (clk_gate[]) be moved one block above? It uses
partially-initialized array, so it would be nice to have code as clear
as possible.
> + of_property_read_string(node, "clock-output-names", &clk_name);
> +
> + init.name = clk_name;
> + init.ops = ops;
> + init.flags = 0;
> + while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =
> + of_clk_get_parent_name(node, i)) != NULL)
> + i++;
I'd suggest explicit loop, like
+ while (i < SOCFGPA_MAX_PARENTS) {
+ char *name = of_clk_get_parent_name(node, i);
+ parent_name[i] = name;
+ if (name == NULL)
+ break;
i++;
+ }
This is a bit too subtle.
> + init.parent_names = parent_name;
> + init.num_parents = i;
> + socfpga_clk->hw.hw.init = &init;
> +
> + clk = clk_register(NULL, &socfpga_clk->hw.hw);
init is local variable, yet pointer passed to it is in globally
alocated structure. What is going on there? Are there some comments
needed?
Thanks,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
More information about the linux-arm-kernel
mailing list