#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
static struct clk *clks[CLK_COUNT];
static struct clk_onecell_data clk_data = { clks, CLK_COUNT };
#define DIV_BYPASS BIT(23)
#define extract_pll_n(val) ((val >> 0) & ((1u << 7) - 1))
#define extract_pll_k(val) ((val >> 13) & ((1u << 3) - 1))
#define extract_pll_m(val) ((val >> 16) & ((1u << 3) - 1))
#define extract_pll_isel(val) ((val >> 24) & ((1u << 3) - 1))
static void __init make_pll(int idx, const char *parent, void __iomem *base)
sprintf(name, "pll%d", idx);
val = readl(base + idx * 8);
mul = extract_pll_n(val) + 1;
div = (extract_pll_m(val) + 1) << extract_pll_k(val);
clk_register_fixed_factor(NULL, name, parent, 0, mul, div);
if (extract_pll_isel(val) != 1)
panic("%s: input not set to XTAL_IN\n", name);
static void __init make_cd(int idx, void __iomem *base)
sprintf(name, "cd%d", idx);
val = readl(base + idx * 8);
clk_register_fixed_factor(NULL, name, "pll2", 0, mul, div);
panic("%s: unsupported divider %x\n", name, val);
static void __init tango4_clkgen_setup(struct device_node *np)
struct clk **pp = clk_data.clks;
void __iomem *base = of_iomap(np, 0);
const char *parent = of_clk_get_parent_name(np, 0);
panic("%pOFn: invalid address\n", np);
if (readl(base + CPUCLK_DIV) & DIV_BYPASS)
panic("%pOFn: unsupported cpuclk setup\n", np);
if (readl(base + SYSCLK_DIV) & DIV_BYPASS)
panic("%pOFn: unsupported sysclk setup\n", np);