|
@@ -3,7 +3,7 @@
|
|
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
|
|
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
|
|
* clock framework.
|
|
* 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
|
|
* 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
|
|
* 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);
|
|
return icst_clk_setup(dev, desc, name, parent_name, map);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(icst_clk_register);
|
|
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
|