]> git.karo-electronics.de Git - linux-beck.git/commitdiff
clk: add DT clock binding support
authorGrant Likely <grant.likely@secretlab.ca>
Mon, 9 Apr 2012 19:50:06 +0000 (14:50 -0500)
committerMike Turquette <mturquette@linaro.org>
Thu, 12 Jul 2012 00:58:45 +0000 (17:58 -0700)
Based on work 1st by Ben Herrenschmidt and Jeremy Kerr, then by Grant
Likely, this patch adds support to clk_get to allow drivers to retrieve
clock data from the device tree.

Platforms scan for clocks in DT with of_clk_init and a match table, and
the register a provider through of_clk_add_provider. The provider's
clk_src_get function will be called when a device references the
provider's OF node for a clock reference.

v6 (Rob Herring):
    - Return error values instead of NULL to match clock framework
      expectations

v5 (Rob Herring):
    - Move from drivers/of into common clock subsystem
    - Squashed "dt/clock: add a simple provider get function" and
      "dt/clock: add function to get parent clock name"
    - Rebase to 3.4-rc1
    - Drop CONFIG_OF_CLOCK and just use CONFIG_OF
    - Add missing EXPORT_SYMBOL to various functions
    - s/clock-output-name/clock-output-names/
    - Define that fixed-clock binding is a single output

v4 (Rob Herring):
    - Rework for common clk subsystem
    - Add of_clk_get_parent_name function

v3: - Clarified documentation

v2: - fixed errant ';' causing compile error
    - Editorial fixes from Shawn Guo
    - merged in adding lookup to clkdev
    - changed property names to match established convention. After
      working with the binding a bit it really made more sense to follow the
      lead of 'reg', 'gpios' and 'interrupts' by making the input simply
      'clocks' & 'clock-names' instead of 'clock-input-*', and to only use
      clock-output* for the producer nodes. (Sorry Shawn, this will mean
      you need to change some code, but it should be trivial)
    - Add ability to inherit clocks from parent nodes by using an empty
      'clock-ranges' property.  Useful for busses.  I could use some feedback
      on the new property name, 'clock-ranges' doesn't feel right to me.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Reviewed-by: Shawn Guo <shawn.guo@freescale.com>
Cc: Sascha Hauer <kernel@pengutronix.de>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Documentation/devicetree/bindings/clock/clock-bindings.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/fixed-clock.txt [new file with mode: 0644]
drivers/clk/clk.c
drivers/clk/clkdev.c
include/linux/clk-provider.h
include/linux/clk.h

diff --git a/Documentation/devicetree/bindings/clock/clock-bindings.txt b/Documentation/devicetree/bindings/clock/clock-bindings.txt
new file mode 100644 (file)
index 0000000..eb65d41
--- /dev/null
@@ -0,0 +1,117 @@
+This binding is a work-in-progress, and are based on some experimental
+work by benh[1].
+
+Sources of clock signal can be represented by any node in the device
+tree.  Those nodes are designated as clock providers.  Clock consumer
+nodes use a phandle and clock specifier pair to connect clock provider
+outputs to clock inputs.  Similar to the gpio specifiers, a clock
+specifier is an array of one more more cells identifying the clock
+output on a device.  The length of a clock specifier is defined by the
+value of a #clock-cells property in the clock provider node.
+
+[1] http://patchwork.ozlabs.org/patch/31551/
+
+==Clock providers==
+
+Required properties:
+#clock-cells:     Number of cells in a clock specifier; Typically 0 for nodes
+                  with a single clock output and 1 for nodes with multiple
+                  clock outputs.
+
+Optional properties:
+clock-output-names: Recommended to be a list of strings of clock output signal
+                   names indexed by the first cell in the clock specifier.
+                   However, the meaning of clock-output-names is domain
+                   specific to the clock provider, and is only provided to
+                   encourage using the same meaning for the majority of clock
+                   providers.  This format may not work for clock providers
+                   using a complex clock specifier format.  In those cases it
+                   is recommended to omit this property and create a binding
+                   specific names property.
+
+                   Clock consumer nodes must never directly reference
+                   the provider's clock-output-names property.
+
+For example:
+
+    oscillator {
+        #clock-cells = <1>;
+        clock-output-names = "ckil", "ckih";
+    };
+
+- this node defines a device with two clock outputs, the first named
+  "ckil" and the second named "ckih".  Consumer nodes always reference
+  clocks by index. The names should reflect the clock output signal
+  names for the device.
+
+==Clock consumers==
+
+Required properties:
+clocks:                List of phandle and clock specifier pairs, one pair
+               for each clock input to the device.  Note: if the
+               clock provider specifies '0' for #clock-cells, then
+               only the phandle portion of the pair will appear.
+
+Optional properties:
+clock-names:   List of clock input name strings sorted in the same
+               order as the clocks property.  Consumers drivers
+               will use clock-names to match clock input names
+               with clocks specifiers.
+clock-ranges:  Empty property indicating that child nodes can inherit named
+               clocks from this node. Useful for bus nodes to provide a
+               clock to their children.
+
+For example:
+
+    device {
+        clocks = <&osc 1>, <&ref 0>;
+        clock-names = "baud", "register";
+    };
+
+
+This represents a device with two clock inputs, named "baud" and "register".
+The baud clock is connected to output 1 of the &osc device, and the register
+clock is connected to output 0 of the &ref.
+
+==Example==
+
+    /* external oscillator */
+    osc: oscillator {
+        compatible = "fixed-clock";
+        #clock-cells = <1>;
+        clock-frequency  = <32678>;
+        clock-output-names = "osc";
+    };
+
+    /* phase-locked-loop device, generates a higher frequency clock
+     * from the external oscillator reference */
+    pll: pll@4c000 {
+        compatible = "vendor,some-pll-interface"
+        #clock-cells = <1>;
+        clocks = <&osc 0>;
+        clock-names = "ref";
+        reg = <0x4c000 0x1000>;
+        clock-output-names = "pll", "pll-switched";
+    };
+
+    /* UART, using the low frequency oscillator for the baud clock,
+     * and the high frequency switched PLL output for register
+     * clocking */
+    uart@a000 {
+        compatible = "fsl,imx-uart";
+        reg = <0xa000 0x1000>;
+        interrupts = <33>;
+        clocks = <&osc 0>, <&pll 1>;
+        clock-names = "baud", "register";
+    };
+
+This DT fragment defines three devices: an external oscillator to provide a
+low-frequency reference clock, a PLL device to generate a higher frequency
+clock signal, and a UART.
+
+* The oscillator is fixed-frequency, and provides one clock output, named "osc".
+* The PLL is both a clock provider and a clock consumer. It uses the clock
+  signal generated by the external oscillator, and provides two output signals
+  ("pll" and "pll-switched").
+* The UART has its baud clock connected the external oscillator and its
+  register clock connected to the PLL clock (the "pll-switched" signal)
diff --git a/Documentation/devicetree/bindings/clock/fixed-clock.txt b/Documentation/devicetree/bindings/clock/fixed-clock.txt
new file mode 100644 (file)
index 0000000..0b1fe78
--- /dev/null
@@ -0,0 +1,21 @@
+Binding for simple fixed-rate clock sources.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "fixed-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clock-frequency : frequency of clock in Hz. Should be a single cell.
+
+Optional properties:
+- gpios : From common gpio binding; gpio connection to clock enable pin.
+- clock-output-names : From common clock binding.
+
+Example:
+       clock {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <1000000000>;
+       };
index 46317cbc088f64c92bfd6d3a7dc4efcb10f75c08..c87fdd7105609d7bddd836dd9fa2e640753bb22a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/err.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 static DEFINE_SPINLOCK(enable_lock);
 static DEFINE_MUTEX(prepare_lock);
@@ -1550,3 +1551,142 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
        return ret;
 }
 EXPORT_SYMBOL_GPL(clk_notifier_unregister);
+
+#ifdef CONFIG_OF
+/**
+ * struct of_clk_provider - Clock provider registration structure
+ * @link: Entry in global list of clock providers
+ * @node: Pointer to device tree node of clock provider
+ * @get: Get clock callback.  Returns NULL or a struct clk for the
+ *       given clock specifier
+ * @data: context pointer to be passed into @get callback
+ */
+struct of_clk_provider {
+       struct list_head link;
+
+       struct device_node *node;
+       struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
+       void *data;
+};
+
+static LIST_HEAD(of_clk_providers);
+static DEFINE_MUTEX(of_clk_lock);
+
+struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
+                                    void *data)
+{
+       return data;
+}
+EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
+
+/**
+ * of_clk_add_provider() - Register a clock provider for a node
+ * @np: Device node pointer associated with clock provider
+ * @clk_src_get: callback for decoding clock
+ * @data: context pointer for @clk_src_get callback.
+ */
+int of_clk_add_provider(struct device_node *np,
+                       struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,
+                                                  void *data),
+                       void *data)
+{
+       struct of_clk_provider *cp;
+
+       cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
+       if (!cp)
+               return -ENOMEM;
+
+       cp->node = of_node_get(np);
+       cp->data = data;
+       cp->get = clk_src_get;
+
+       mutex_lock(&of_clk_lock);
+       list_add(&cp->link, &of_clk_providers);
+       mutex_unlock(&of_clk_lock);
+       pr_debug("Added clock from %s\n", np->full_name);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_clk_add_provider);
+
+/**
+ * of_clk_del_provider() - Remove a previously registered clock provider
+ * @np: Device node pointer associated with clock provider
+ */
+void of_clk_del_provider(struct device_node *np)
+{
+       struct of_clk_provider *cp;
+
+       mutex_lock(&of_clk_lock);
+       list_for_each_entry(cp, &of_clk_providers, link) {
+               if (cp->node == np) {
+                       list_del(&cp->link);
+                       of_node_put(cp->node);
+                       kfree(cp);
+                       break;
+               }
+       }
+       mutex_unlock(&of_clk_lock);
+}
+EXPORT_SYMBOL_GPL(of_clk_del_provider);
+
+struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
+{
+       struct of_clk_provider *provider;
+       struct clk *clk = ERR_PTR(-ENOENT);
+
+       /* Check if we have such a provider in our array */
+       mutex_lock(&of_clk_lock);
+       list_for_each_entry(provider, &of_clk_providers, link) {
+               if (provider->node == clkspec->np)
+                       clk = provider->get(clkspec, provider->data);
+               if (!IS_ERR(clk))
+                       break;
+       }
+       mutex_unlock(&of_clk_lock);
+
+       return clk;
+}
+
+const char *of_clk_get_parent_name(struct device_node *np, int index)
+{
+       struct of_phandle_args clkspec;
+       const char *clk_name;
+       int rc;
+
+       if (index < 0)
+               return NULL;
+
+       rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
+                                       &clkspec);
+       if (rc)
+               return NULL;
+
+       if (of_property_read_string_index(clkspec.np, "clock-output-names",
+                                         clkspec.args_count ? clkspec.args[0] : 0,
+                                         &clk_name) < 0)
+               clk_name = clkspec.np->name;
+
+       of_node_put(clkspec.np);
+       return clk_name;
+}
+EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
+
+/**
+ * of_clk_init() - Scan and init clock providers from the DT
+ * @matches: array of compatible values and init functions for providers.
+ *
+ * This function scans the device tree for matching clock providers and
+ * calls their initialization functions
+ */
+void __init of_clk_init(const struct of_device_id *matches)
+{
+       struct device_node *np;
+
+       for_each_matching_node(np, matches) {
+               const struct of_device_id *match = of_match_node(matches, np);
+               of_clk_init_cb_t clk_init_cb = match->data;
+               clk_init_cb(np);
+       }
+}
+#endif
index c535cf8c5770f2bd154f391ade6fcd9f7fa888d2..20649b3c88fe4bca95f6b39506db76fc5c733eb9 100644 (file)
 #include <linux/mutex.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/of.h>
 
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 
+#ifdef CONFIG_OF
+struct clk *of_clk_get(struct device_node *np, int index)
+{
+       struct of_phandle_args clkspec;
+       struct clk *clk;
+       int rc;
+
+       if (index < 0)
+               return ERR_PTR(-EINVAL);
+
+       rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
+                                       &clkspec);
+       if (rc)
+               return ERR_PTR(rc);
+
+       clk = of_clk_get_from_provider(&clkspec);
+       of_node_put(clkspec.np);
+       return clk;
+}
+EXPORT_SYMBOL(of_clk_get);
+
+/**
+ * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
+ * @np: pointer to clock consumer node
+ * @name: name of consumer's clock input, or NULL for the first clock reference
+ *
+ * This function parses the clocks and clock-names properties,
+ * and uses them to look up the struct clk from the registered list of clock
+ * providers.
+ */
+struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+{
+       struct clk *clk = ERR_PTR(-ENOENT);
+
+       /* Walk up the tree of devices looking for a clock that matches */
+       while (np) {
+               int index = 0;
+
+               /*
+                * For named clocks, first look up the name in the
+                * "clock-names" property.  If it cannot be found, then
+                * index will be an error code, and of_clk_get() will fail.
+                */
+               if (name)
+                       index = of_property_match_string(np, "clock-names", name);
+               clk = of_clk_get(np, index);
+               if (!IS_ERR(clk))
+                       break;
+               else if (name && index >= 0) {
+                       pr_err("ERROR: could not get clock %s:%s(%i)\n",
+                               np->full_name, name ? name : "", index);
+                       return clk;
+               }
+
+               /*
+                * No matching clock found on this node.  If the parent node
+                * has a "clock-ranges" property, then we can try one of its
+                * clocks.
+                */
+               np = np->parent;
+               if (np && !of_get_property(np, "clock-ranges", NULL))
+                       break;
+       }
+
+       return clk;
+}
+EXPORT_SYMBOL(of_clk_get_by_name);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
@@ -83,6 +153,13 @@ EXPORT_SYMBOL(clk_get_sys);
 struct clk *clk_get(struct device *dev, const char *con_id)
 {
        const char *dev_id = dev ? dev_name(dev) : NULL;
+       struct clk *clk;
+
+       if (dev) {
+               clk = of_clk_get_by_name(dev->of_node, con_id);
+               if (clk && __clk_get(clk))
+                       return clk;
+       }
 
        return clk_get_sys(dev_id, con_id);
 }
index 06ad617664a2dc7e883fcd1933b16917317404be..7c9c691102b5ff649b80e4a1565189152e199b39 100644 (file)
@@ -347,5 +347,19 @@ void __clk_unprepare(struct clk *clk);
 void __clk_reparent(struct clk *clk, struct clk *new_parent);
 unsigned long __clk_round_rate(struct clk *clk, unsigned long rate);
 
+struct of_device_id;
+
+typedef void (*of_clk_init_cb_t)(struct device_node *);
+
+int of_clk_add_provider(struct device_node *np,
+                       struct clk *(*clk_src_get)(struct of_phandle_args *args,
+                                                  void *data),
+                       void *data);
+void of_clk_del_provider(struct device_node *np);
+struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
+                                 void *data);
+const char *of_clk_get_parent_name(struct device_node *np, int index);
+void of_clk_init(const struct of_device_id *matches);
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
index ad5c43e8ae8ae7eeca38e0308aa7f77c41bfdc6d..8b70342e7e0b74f8c4444903a4fd1bfb777cd518 100644 (file)
@@ -310,4 +310,23 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id);
 int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
                        struct device *dev);
 
+struct device_node;
+struct of_phandle_args;
+
+#ifdef CONFIG_OF
+struct clk *of_clk_get(struct device_node *np, int index);
+struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
+struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec);
+#else
+static inline struct clk *of_clk_get(struct device_node *np, int index)
+{
+       return NULL;
+}
+static inline struct clk *of_clk_get_by_name(struct device_node *np,
+                                            const char *name)
+{
+       return NULL;
+}
+#endif
+
 #endif