From d430819d69a51dc4798bb98d841afa9af2f5c83a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 13 Oct 2015 14:29:54 +0200 Subject: [PATCH] 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 Cc: Stephen Boyd Cc: linux-clk@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/clk/versatile/clk-icst.c | 89 +++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 87bd4667b126..e62f8cb2c9b5 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -3,7 +3,7 @@ * We wrap the custom interface from 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 -- 2.20.1