diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2012-04-09 15:50:06 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2012-07-11 20:58:45 -0400 |
commit | 766e6a4ec602d0c107553b91b3434fe9c03474f4 (patch) | |
tree | aa9bbba36954d927e931cc50c6a28ef9cced571c /drivers/clk | |
parent | a613163dff04cbfcb7d66b06ef4a5f65498ee59b (diff) |
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')
-rw-r--r-- | drivers/clk/clk.c | 140 | ||||
-rw-r--r-- | drivers/clk/clkdev.c | 77 |
2 files changed, 217 insertions, 0 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 46317cbc088f..c87fdd710560 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/of.h> | ||
19 | 20 | ||
20 | static DEFINE_SPINLOCK(enable_lock); | 21 | static DEFINE_SPINLOCK(enable_lock); |
21 | static DEFINE_MUTEX(prepare_lock); | 22 | static DEFINE_MUTEX(prepare_lock); |
@@ -1550,3 +1551,142 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) | |||
1550 | return ret; | 1551 | return ret; |
1551 | } | 1552 | } |
1552 | EXPORT_SYMBOL_GPL(clk_notifier_unregister); | 1553 | EXPORT_SYMBOL_GPL(clk_notifier_unregister); |
1554 | |||
1555 | #ifdef CONFIG_OF | ||
1556 | /** | ||
1557 | * struct of_clk_provider - Clock provider registration structure | ||
1558 | * @link: Entry in global list of clock providers | ||
1559 | * @node: Pointer to device tree node of clock provider | ||
1560 | * @get: Get clock callback. Returns NULL or a struct clk for the | ||
1561 | * given clock specifier | ||
1562 | * @data: context pointer to be passed into @get callback | ||
1563 | */ | ||
1564 | struct of_clk_provider { | ||
1565 | struct list_head link; | ||
1566 | |||
1567 | struct device_node *node; | ||
1568 | struct clk *(*get)(struct of_phandle_args *clkspec, void *data); | ||
1569 | void *data; | ||
1570 | }; | ||
1571 | |||
1572 | static LIST_HEAD(of_clk_providers); | ||
1573 | static DEFINE_MUTEX(of_clk_lock); | ||
1574 | |||
1575 | struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, | ||
1576 | void *data) | ||
1577 | { | ||
1578 | return data; | ||
1579 | } | ||
1580 | EXPORT_SYMBOL_GPL(of_clk_src_simple_get); | ||
1581 | |||
1582 | /** | ||
1583 | * of_clk_add_provider() - Register a clock provider for a node | ||
1584 | * @np: Device node pointer associated with clock provider | ||
1585 | * @clk_src_get: callback for decoding clock | ||
1586 | * @data: context pointer for @clk_src_get callback. | ||
1587 | */ | ||
1588 | int of_clk_add_provider(struct device_node *np, | ||
1589 | struct clk *(*clk_src_get)(struct of_phandle_args *clkspec, | ||
1590 | void *data), | ||
1591 | void *data) | ||
1592 | { | ||
1593 | struct of_clk_provider *cp; | ||
1594 | |||
1595 | cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL); | ||
1596 | if (!cp) | ||
1597 | return -ENOMEM; | ||
1598 | |||
1599 | cp->node = of_node_get(np); | ||
1600 | cp->data = data; | ||
1601 | cp->get = clk_src_get; | ||
1602 | |||
1603 | mutex_lock(&of_clk_lock); | ||
1604 | list_add(&cp->link, &of_clk_providers); | ||
1605 | mutex_unlock(&of_clk_lock); | ||
1606 | pr_debug("Added clock from %s\n", np->full_name); | ||
1607 | |||
1608 | return 0; | ||
1609 | } | ||
1610 | EXPORT_SYMBOL_GPL(of_clk_add_provider); | ||
1611 | |||
1612 | /** | ||
1613 | * of_clk_del_provider() - Remove a previously registered clock provider | ||
1614 | * @np: Device node pointer associated with clock provider | ||
1615 | */ | ||
1616 | void of_clk_del_provider(struct device_node *np) | ||
1617 | { | ||
1618 | struct of_clk_provider *cp; | ||
1619 | |||
1620 | mutex_lock(&of_clk_lock); | ||
1621 | list_for_each_entry(cp, &of_clk_providers, link) { | ||
1622 | if (cp->node == np) { | ||
1623 | list_del(&cp->link); | ||
1624 | of_node_put(cp->node); | ||
1625 | kfree(cp); | ||
1626 | break; | ||
1627 | } | ||
1628 | } | ||
1629 | mutex_unlock(&of_clk_lock); | ||
1630 | } | ||
1631 | EXPORT_SYMBOL_GPL(of_clk_del_provider); | ||
1632 | |||
1633 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) | ||
1634 | { | ||
1635 | struct of_clk_provider *provider; | ||
1636 | struct clk *clk = ERR_PTR(-ENOENT); | ||
1637 | |||
1638 | /* Check if we have such a provider in our array */ | ||
1639 | mutex_lock(&of_clk_lock); | ||
1640 | list_for_each_entry(provider, &of_clk_providers, link) { | ||
1641 | if (provider->node == clkspec->np) | ||
1642 | clk = provider->get(clkspec, provider->data); | ||
1643 | if (!IS_ERR(clk)) | ||
1644 | break; | ||
1645 | } | ||
1646 | mutex_unlock(&of_clk_lock); | ||
1647 | |||
1648 | return clk; | ||
1649 | } | ||
1650 | |||
1651 | const char *of_clk_get_parent_name(struct device_node *np, int index) | ||
1652 | { | ||
1653 | struct of_phandle_args clkspec; | ||
1654 | const char *clk_name; | ||
1655 | int rc; | ||
1656 | |||
1657 | if (index < 0) | ||
1658 | return NULL; | ||
1659 | |||
1660 | rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index, | ||
1661 | &clkspec); | ||
1662 | if (rc) | ||
1663 | return NULL; | ||
1664 | |||
1665 | if (of_property_read_string_index(clkspec.np, "clock-output-names", | ||
1666 | clkspec.args_count ? clkspec.args[0] : 0, | ||
1667 | &clk_name) < 0) | ||
1668 | clk_name = clkspec.np->name; | ||
1669 | |||
1670 | of_node_put(clkspec.np); | ||
1671 | return clk_name; | ||
1672 | } | ||
1673 | EXPORT_SYMBOL_GPL(of_clk_get_parent_name); | ||
1674 | |||
1675 | /** | ||
1676 | * of_clk_init() - Scan and init clock providers from the DT | ||
1677 | * @matches: array of compatible values and init functions for providers. | ||
1678 | * | ||
1679 | * This function scans the device tree for matching clock providers and | ||
1680 | * calls their initialization functions | ||
1681 | */ | ||
1682 | void __init of_clk_init(const struct of_device_id *matches) | ||
1683 | { | ||
1684 | struct device_node *np; | ||
1685 | |||
1686 | for_each_matching_node(np, matches) { | ||
1687 | const struct of_device_id *match = of_match_node(matches, np); | ||
1688 | of_clk_init_cb_t clk_init_cb = match->data; | ||
1689 | clk_init_cb(np); | ||
1690 | } | ||
1691 | } | ||
1692 | #endif | ||
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 @@ | |||
19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
20 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
21 | #include <linux/clkdev.h> | 21 | #include <linux/clkdev.h> |
22 | #include <linux/of.h> | ||
22 | 23 | ||
23 | static LIST_HEAD(clocks); | 24 | static LIST_HEAD(clocks); |
24 | static DEFINE_MUTEX(clocks_mutex); | 25 | static DEFINE_MUTEX(clocks_mutex); |
25 | 26 | ||
27 | #ifdef CONFIG_OF | ||
28 | struct clk *of_clk_get(struct device_node *np, int index) | ||
29 | { | ||
30 | struct of_phandle_args clkspec; | ||
31 | struct clk *clk; | ||
32 | int rc; | ||
33 | |||
34 | if (index < 0) | ||
35 | return ERR_PTR(-EINVAL); | ||
36 | |||
37 | rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index, | ||
38 | &clkspec); | ||
39 | if (rc) | ||
40 | return ERR_PTR(rc); | ||
41 | |||
42 | clk = of_clk_get_from_provider(&clkspec); | ||
43 | of_node_put(clkspec.np); | ||
44 | return clk; | ||
45 | } | ||
46 | EXPORT_SYMBOL(of_clk_get); | ||
47 | |||
48 | /** | ||
49 | * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node | ||
50 | * @np: pointer to clock consumer node | ||
51 | * @name: name of consumer's clock input, or NULL for the first clock reference | ||
52 | * | ||
53 | * This function parses the clocks and clock-names properties, | ||
54 | * and uses them to look up the struct clk from the registered list of clock | ||
55 | * providers. | ||
56 | */ | ||
57 | struct clk *of_clk_get_by_name(struct device_node *np, const char *name) | ||
58 | { | ||
59 | struct clk *clk = ERR_PTR(-ENOENT); | ||
60 | |||
61 | /* Walk up the tree of devices looking for a clock that matches */ | ||
62 | while (np) { | ||
63 | int index = 0; | ||
64 | |||
65 | /* | ||
66 | * For named clocks, first look up the name in the | ||
67 | * "clock-names" property. If it cannot be found, then | ||
68 | * index will be an error code, and of_clk_get() will fail. | ||
69 | */ | ||
70 | if (name) | ||
71 | index = of_property_match_string(np, "clock-names", name); | ||
72 | clk = of_clk_get(np, index); | ||
73 | if (!IS_ERR(clk)) | ||
74 | break; | ||
75 | else if (name && index >= 0) { | ||
76 | pr_err("ERROR: could not get clock %s:%s(%i)\n", | ||
77 | np->full_name, name ? name : "", index); | ||
78 | return clk; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * No matching clock found on this node. If the parent node | ||
83 | * has a "clock-ranges" property, then we can try one of its | ||
84 | * clocks. | ||
85 | */ | ||
86 | np = np->parent; | ||
87 | if (np && !of_get_property(np, "clock-ranges", NULL)) | ||
88 | break; | ||
89 | } | ||
90 | |||
91 | return clk; | ||
92 | } | ||
93 | EXPORT_SYMBOL(of_clk_get_by_name); | ||
94 | #endif | ||
95 | |||
26 | /* | 96 | /* |
27 | * Find the correct struct clk for the device and connection ID. | 97 | * Find the correct struct clk for the device and connection ID. |
28 | * We do slightly fuzzy matching here: | 98 | * We do slightly fuzzy matching here: |
@@ -83,6 +153,13 @@ EXPORT_SYMBOL(clk_get_sys); | |||
83 | struct clk *clk_get(struct device *dev, const char *con_id) | 153 | struct clk *clk_get(struct device *dev, const char *con_id) |
84 | { | 154 | { |
85 | const char *dev_id = dev ? dev_name(dev) : NULL; | 155 | const char *dev_id = dev ? dev_name(dev) : NULL; |
156 | struct clk *clk; | ||
157 | |||
158 | if (dev) { | ||
159 | clk = of_clk_get_by_name(dev->of_node, con_id); | ||
160 | if (clk && __clk_get(clk)) | ||
161 | return clk; | ||
162 | } | ||
86 | 163 | ||
87 | return clk_get_sys(dev_id, con_id); | 164 | return clk_get_sys(dev_id, con_id); |
88 | } | 165 | } |