diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2012-04-09 21:50:06 +0200 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2012-07-12 02:58:45 +0200 |
commit | 766e6a4ec602d0c107553b91b3434fe9c03474f4 (patch) | |
tree | aa9bbba36954d927e931cc50c6a28ef9cced571c /drivers/clk/clkdev.c | |
parent | ARM: integrator: convert to common clock (diff) | |
download | linux-766e6a4ec602d0c107553b91b3434fe9c03474f4.tar.xz linux-766e6a4ec602d0c107553b91b3434fe9c03474f4.zip |
clk: add DT clock binding support
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>
Diffstat (limited to 'drivers/clk/clkdev.c')
-rw-r--r-- | drivers/clk/clkdev.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index c535cf8c5770..20649b3c88fe 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -19,10 +19,80 @@ #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); } |