Port of_clk_set_defautls() from Linux kernel in order to support DT
configurations that require it (e. g. Vybrid).

Signed-off-by: Andrey Smirnov <[email protected]>
---
 drivers/clk/Makefile         |   2 +-
 drivers/clk/clk-conf.c       | 144 +++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/clk.c            |   2 +
 include/linux/clk/clk-conf.h |  22 +++++++
 4 files changed, 169 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/clk-conf.c
 create mode 100644 include/linux/clk/clk-conf.h

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 47ed7b1..0fe8f1e 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_COMMON_CLK)       += clk.o clk-fixed.o clk-divider.o 
clk-fixed-factor.o \
                                clk-mux.o clk-gate.o clk-composite.o \
-                               clk-fractional-divider.o
+                               clk-fractional-divider.o clk-conf.o
 obj-$(CONFIG_CLKDEV_LOOKUP)    += clkdev.o
 
 obj-$(CONFIG_ARCH_MVEBU)       += mvebu/
diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
new file mode 100644
index 0000000..961fad8
--- /dev/null
+++ b/drivers/clk/clk-conf.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <[email protected]>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clk/clk-conf.h>
+
+static int __set_clk_parents(struct device_node *node, bool clk_supplier)
+{
+       struct of_phandle_args clkspec;
+       int index, rc, num_parents;
+       struct clk *clk, *pclk;
+
+       num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
+                                                "#clock-cells");
+       if (num_parents == -EINVAL)
+               pr_err("clk: invalid value of clock-parents property at %s\n",
+                      node->full_name);
+
+       for (index = 0; index < num_parents; index++) {
+               rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
+                                       "#clock-cells", index, &clkspec);
+               if (rc < 0) {
+                       /* skip empty (null) phandles */
+                       if (rc == -ENOENT)
+                               continue;
+                       else
+                               return rc;
+               }
+               if (clkspec.np == node && !clk_supplier)
+                       return 0;
+               pclk = of_clk_get_from_provider(&clkspec);
+               if (IS_ERR(pclk)) {
+                       pr_warn("clk: couldn't get parent clock %d for %s\n",
+                               index, node->full_name);
+                       return PTR_ERR(pclk);
+               }
+
+               rc = of_parse_phandle_with_args(node, "assigned-clocks",
+                                       "#clock-cells", index, &clkspec);
+               if (rc < 0)
+                       goto err;
+               if (clkspec.np == node && !clk_supplier) {
+                       rc = 0;
+                       goto err;
+               }
+               clk = of_clk_get_from_provider(&clkspec);
+               if (IS_ERR(clk)) {
+                       pr_warn("clk: couldn't get parent clock %d for %s\n",
+                               index, node->full_name);
+                       rc = PTR_ERR(clk);
+                       goto err;
+               }
+
+               rc = clk_set_parent(clk, pclk);
+               if (rc < 0)
+                       pr_err("clk: failed to reparent %s to %s: %d\n",
+                              __clk_get_name(clk), __clk_get_name(pclk), rc);
+               clk_put(clk);
+               clk_put(pclk);
+       }
+       return 0;
+err:
+       clk_put(pclk);
+       return rc;
+}
+
+static int __set_clk_rates(struct device_node *node, bool clk_supplier)
+{
+       struct of_phandle_args clkspec;
+       struct property *prop;
+       const __be32 *cur;
+       int rc, index = 0;
+       struct clk *clk;
+       u32 rate;
+
+       of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) 
{
+               if (rate) {
+                       rc = of_parse_phandle_with_args(node, "assigned-clocks",
+                                       "#clock-cells", index, &clkspec);
+                       if (rc < 0) {
+                               /* skip empty (null) phandles */
+                               if (rc == -ENOENT)
+                                       continue;
+                               else
+                                       return rc;
+                       }
+                       if (clkspec.np == node && !clk_supplier)
+                               return 0;
+
+                       clk = of_clk_get_from_provider(&clkspec);
+                       if (IS_ERR(clk)) {
+                               pr_warn("clk: couldn't get clock %d for %s\n",
+                                       index, node->full_name);
+                               return PTR_ERR(clk);
+                       }
+
+                       rc = clk_set_rate(clk, rate);
+                       if (rc < 0)
+                               pr_err("clk: couldn't set %s clk rate to %d 
(%d), current rate: %ld\n",
+                                      __clk_get_name(clk), rate, rc,
+                                      clk_get_rate(clk));
+                       clk_put(clk);
+               }
+               index++;
+       }
+       return 0;
+}
+
+/**
+ * of_clk_set_defaults() - parse and set assigned clocks configuration
+ * @node: device node to apply clock settings for
+ * @clk_supplier: true if clocks supplied by @node should also be considered
+ *
+ * This function parses 'assigned-{clocks/clock-parents/clock-rates}' 
properties
+ * and sets any specified clock parents and rates. The @clk_supplier argument
+ * should be set to true if @node may be also a clock supplier of any clock
+ * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties.
+ * If @clk_supplier is false the function exits returning 0 as soon as it
+ * determines the @node is also a supplier of any of the clocks.
+ */
+int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
+{
+       int rc;
+
+       if (!node)
+               return 0;
+
+       rc = __set_clk_parents(node, clk_supplier);
+       if (rc < 0)
+               return rc;
+
+       return __set_clk_rates(node, clk_supplier);
+}
+EXPORT_SYMBOL_GPL(of_clk_set_defaults);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index a38f339..28a1be5 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -19,6 +19,7 @@
 #include <malloc.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/clk/clk-conf.h>
 
 static LIST_HEAD(clks);
 
@@ -525,6 +526,7 @@ int of_clk_init(struct device_node *root, const struct 
of_device_id *matches)
                        if (force || parent_ready(clk_provider->np)) {
 
                                clk_provider->clk_init_cb(clk_provider->np);
+                               of_clk_set_defaults(clk_provider->np, true);
 
                                list_del(&clk_provider->node);
                                free(clk_provider);
diff --git a/include/linux/clk/clk-conf.h b/include/linux/clk/clk-conf.h
new file mode 100644
index 0000000..2c0a39e
--- /dev/null
+++ b/include/linux/clk/clk-conf.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <[email protected]>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+
+struct device_node;
+
+#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK)
+int of_clk_set_defaults(struct device_node *node, bool clk_supplier);
+#else
+static inline int of_clk_set_defaults(struct device_node *node,
+                                     bool clk_supplier)
+{
+       return 0;
+}
+#endif
-- 
2.5.5


_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to