clk: versatile-icst: add device tree support

This adds support for the ARM syscon ICST clocks to initialized
directly from the device tree syscon node on ARM Integrator,
Versatile and RealView reference designs.

Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-clk@vger.kernel.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Linus Walleij 2015-10-13 14:29:54 +02:00
parent 384d977d74
commit d430819d69
1 changed files with 88 additions and 1 deletions

View File

@ -3,7 +3,7 @@
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
* clock framework.
*
* Copyright (C) 2012 Linus Walleij
* Copyright (C) 2012-2015 Linus Walleij
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -206,3 +206,90 @@ struct clk *icst_clk_register(struct device *dev,
return icst_clk_setup(dev, desc, name, parent_name, map);
}
EXPORT_SYMBOL_GPL(icst_clk_register);
#ifdef CONFIG_OF
/*
* In a device tree, an memory-mapped ICST clock appear as a child
* of a syscon node. Assume this and probe it only as a child of a
* syscon.
*/
static const struct icst_params icst525_params = {
.vco_max = ICST525_VCO_MAX_5V,
.vco_min = ICST525_VCO_MIN,
.vd_min = 8,
.vd_max = 263,
.rd_min = 3,
.rd_max = 65,
.s2div = icst525_s2div,
.idx2s = icst525_idx2s,
};
static const struct icst_params icst307_params = {
.vco_max = ICST307_VCO_MAX,
.vco_min = ICST307_VCO_MIN,
.vd_min = 4 + 8,
.vd_max = 511 + 8,
.rd_min = 1 + 2,
.rd_max = 127 + 2,
.s2div = icst307_s2div,
.idx2s = icst307_idx2s,
};
static void __init of_syscon_icst_setup(struct device_node *np)
{
struct device_node *parent;
struct regmap *map;
struct clk_icst_desc icst_desc;
const char *name = np->name;
const char *parent_name;
struct clk *regclk;
/* We do not release this reference, we are using it perpetually */
parent = of_get_parent(np);
if (!parent) {
pr_err("no parent node for syscon ICST clock\n");
return;
}
map = syscon_node_to_regmap(parent);
if (IS_ERR(map)) {
pr_err("no regmap for syscon ICST clock parent\n");
return;
}
if (of_property_read_u32(np, "vco-offset", &icst_desc.vco_offset)) {
pr_err("no VCO register offset for ICST clock\n");
return;
}
if (of_property_read_u32(np, "lock-offset", &icst_desc.lock_offset)) {
pr_err("no lock register offset for ICST clock\n");
return;
}
if (of_device_is_compatible(np, "arm,syscon-icst525"))
icst_desc.params = &icst525_params;
else if (of_device_is_compatible(np, "arm,syscon-icst307"))
icst_desc.params = &icst307_params;
else {
pr_err("unknown ICST clock %s\n", name);
return;
}
/* Parent clock name is not the same as node parent */
parent_name = of_clk_get_parent_name(np, 0);
regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map);
if (IS_ERR(regclk)) {
pr_err("error setting up syscon ICST clock %s\n", name);
return;
}
of_clk_add_provider(np, of_clk_src_simple_get, regclk);
pr_debug("registered syscon ICST clock %s\n", name);
}
CLK_OF_DECLARE(arm_syscon_icst525_clk,
"arm,syscon-icst525", of_syscon_icst_setup);
CLK_OF_DECLARE(arm_syscon_icst307_clk,
"arm,syscon-icst307", of_syscon_icst_setup);
#endif