Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.5 61 lines 1.8 kB view raw
1#include <linux/kernel.h> 2#include <linux/clk-provider.h> 3#include <linux/of_address.h> 4#include <linux/init.h> 5#include <linux/io.h> 6 7static struct clk *out[2]; 8static struct clk_onecell_data clk_data = { out, 2 }; 9 10#define SYSCLK_CTRL 0x20 11#define CPUCLK_CTRL 0x24 12#define LEGACY_DIV 0x3c 13 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) 18 19static void __init make_pll(int idx, const char *parent, void __iomem *base) 20{ 21 char name[8]; 22 u32 val, mul, div; 23 24 sprintf(name, "pll%d", idx); 25 val = readl_relaxed(base + idx*8); 26 mul = PLL_N(val) + 1; 27 div = (PLL_M(val) + 1) << PLL_K(val); 28 clk_register_fixed_factor(NULL, name, parent, 0, mul, div); 29} 30 31static int __init get_div(void __iomem *base) 32{ 33 u8 sysclk_tab[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 }; 34 int idx = DIV_INDEX(readl_relaxed(base + LEGACY_DIV)); 35 36 return sysclk_tab[idx]; 37} 38 39static void __init tango4_clkgen_setup(struct device_node *np) 40{ 41 int div, ret; 42 void __iomem *base = of_iomap(np, 0); 43 const char *parent = of_clk_get_parent_name(np, 0); 44 45 if (!base) 46 panic("%s: invalid address\n", np->full_name); 47 48 make_pll(0, parent, base); 49 make_pll(1, parent, base); 50 51 out[0] = clk_register_divider(NULL, "cpuclk", "pll0", 0, 52 base + CPUCLK_CTRL, 8, 8, CLK_DIVIDER_ONE_BASED, NULL); 53 54 div = readl_relaxed(base + SYSCLK_CTRL) & BIT(23) ? get_div(base) : 4; 55 out[1] = clk_register_fixed_factor(NULL, "sysclk", "pll1", 0, 1, div); 56 57 ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 58 if (IS_ERR(out[0]) || IS_ERR(out[1]) || ret < 0) 59 panic("%s: clk registration failed\n", np->full_name); 60} 61CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);