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/clk.c | |
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/clk.c')
-rw-r--r-- | drivers/clk/clk.c | 140 |
1 files changed, 140 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 | ||