diff options
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..d423c9bdd71a 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 | #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) | ||
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 (!IS_ERR(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 | } |