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

clk: tango4: improve clkgen driver

Add support for USB and SDIO clocks.
Report unsupported setups and panic.

Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Marc Gonzalez and committed by
Stephen Boyd
fefe0535 cb0ceaf7

+48 -25
+48 -25
drivers/clk/clk-tango4.c
··· 4 4 #include <linux/init.h> 5 5 #include <linux/io.h> 6 6 7 - static struct clk *out[2]; 8 - static struct clk_onecell_data clk_data = { out, 2 }; 7 + #define CLK_COUNT 4 /* cpu_clk, sys_clk, usb_clk, sdio_clk */ 8 + static struct clk *clks[CLK_COUNT]; 9 + static struct clk_onecell_data clk_data = { clks, CLK_COUNT }; 9 10 10 - #define SYSCLK_CTRL 0x20 11 - #define CPUCLK_CTRL 0x24 12 - #define LEGACY_DIV 0x3c 11 + #define SYSCLK_DIV 0x20 12 + #define CPUCLK_DIV 0x24 13 + #define DIV_BYPASS BIT(23) 13 14 14 - #define PLL_N(val) (((val) >> 0) & 0x7f) 15 - #define PLL_K(val) (((val) >> 13) & 0x7) 16 - #define PLL_M(val) (((val) >> 16) & 0x7) 17 - #define DIV_INDEX(val) (((val) >> 8) & 0xf) 15 + /*** CLKGEN_PLL ***/ 16 + #define extract_pll_n(val) ((val >> 0) & ((1u << 7) - 1)) 17 + #define extract_pll_k(val) ((val >> 13) & ((1u << 3) - 1)) 18 + #define extract_pll_m(val) ((val >> 16) & ((1u << 3) - 1)) 19 + #define extract_pll_isel(val) ((val >> 24) & ((1u << 3) - 1)) 18 20 19 21 static void __init make_pll(int idx, const char *parent, void __iomem *base) 20 22 { ··· 24 22 u32 val, mul, div; 25 23 26 24 sprintf(name, "pll%d", idx); 27 - val = readl_relaxed(base + idx*8); 28 - mul = PLL_N(val) + 1; 29 - div = (PLL_M(val) + 1) << PLL_K(val); 25 + val = readl(base + idx * 8); 26 + mul = extract_pll_n(val) + 1; 27 + div = (extract_pll_m(val) + 1) << extract_pll_k(val); 30 28 clk_register_fixed_factor(NULL, name, parent, 0, mul, div); 29 + if (extract_pll_isel(val) != 1) 30 + panic("%s: input not set to XTAL_IN\n", name); 31 31 } 32 32 33 - static int __init get_div(void __iomem *base) 33 + static void __init make_cd(int idx, void __iomem *base) 34 34 { 35 - u8 sysclk_tab[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 }; 36 - int idx = DIV_INDEX(readl_relaxed(base + LEGACY_DIV)); 35 + char name[8]; 36 + u32 val, mul, div; 37 37 38 - return sysclk_tab[idx]; 38 + sprintf(name, "cd%d", idx); 39 + val = readl(base + idx * 8); 40 + mul = 1 << 27; 41 + div = (2 << 27) + val; 42 + clk_register_fixed_factor(NULL, name, "pll2", 0, mul, div); 43 + if (val > 0xf0000000) 44 + panic("%s: unsupported divider %x\n", name, val); 39 45 } 40 46 41 47 static void __init tango4_clkgen_setup(struct device_node *np) 42 48 { 43 - int div, ret; 49 + struct clk **pp = clk_data.clks; 44 50 void __iomem *base = of_iomap(np, 0); 45 51 const char *parent = of_clk_get_parent_name(np, 0); 46 52 47 53 if (!base) 48 - panic("%s: invalid address\n", np->full_name); 54 + panic("%s: invalid address\n", np->name); 55 + 56 + if (readl(base + CPUCLK_DIV) & DIV_BYPASS) 57 + panic("%s: unsupported cpuclk setup\n", np->name); 58 + 59 + if (readl(base + SYSCLK_DIV) & DIV_BYPASS) 60 + panic("%s: unsupported sysclk setup\n", np->name); 61 + 62 + writel(0x100, base + CPUCLK_DIV); /* disable frequency ramping */ 49 63 50 64 make_pll(0, parent, base); 51 65 make_pll(1, parent, base); 66 + make_pll(2, parent, base); 67 + make_cd(2, base + 0x80); 68 + make_cd(6, base + 0x80); 52 69 53 - out[0] = clk_register_divider(NULL, "cpuclk", "pll0", 0, 54 - base + CPUCLK_CTRL, 8, 8, CLK_DIVIDER_ONE_BASED, NULL); 70 + pp[0] = clk_register_divider(NULL, "cpu_clk", "pll0", 0, 71 + base + CPUCLK_DIV, 8, 8, CLK_DIVIDER_ONE_BASED, NULL); 72 + pp[1] = clk_register_fixed_factor(NULL, "sys_clk", "pll1", 0, 1, 4); 73 + pp[2] = clk_register_fixed_factor(NULL, "usb_clk", "cd2", 0, 1, 2); 74 + pp[3] = clk_register_fixed_factor(NULL, "sdio_clk", "cd6", 0, 1, 2); 55 75 56 - div = readl_relaxed(base + SYSCLK_CTRL) & BIT(23) ? get_div(base) : 4; 57 - out[1] = clk_register_fixed_factor(NULL, "sysclk", "pll1", 0, 1, div); 76 + if (IS_ERR(pp[0]) || IS_ERR(pp[1]) || IS_ERR(pp[2]) || IS_ERR(pp[3])) 77 + panic("%s: clk registration failed\n", np->name); 58 78 59 - ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 60 - if (IS_ERR(out[0]) || IS_ERR(out[1]) || ret < 0) 61 - panic("%s: clk registration failed\n", np->full_name); 79 + if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) 80 + panic("%s: clk provider registration failed\n", np->name); 62 81 } 63 82 CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);