Commit | Line | Data |
---|---|---|
ebafb63d | 1 | // SPDX-License-Identifier: GPL-2.0 |
8ef997b6 LPC |
2 | #include <linux/clk.h> |
3 | #include <linux/device.h> | |
4 | #include <linux/export.h> | |
5 | #include <linux/gfp.h> | |
6 | ||
7 | static void devm_clk_release(struct device *dev, void *res) | |
8 | { | |
9 | clk_put(*(struct clk **)res); | |
10 | } | |
11 | ||
12 | struct clk *devm_clk_get(struct device *dev, const char *id) | |
13 | { | |
14 | struct clk **ptr, *clk; | |
15 | ||
16 | ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); | |
17 | if (!ptr) | |
18 | return ERR_PTR(-ENOMEM); | |
19 | ||
20 | clk = clk_get(dev, id); | |
21 | if (!IS_ERR(clk)) { | |
22 | *ptr = clk; | |
23 | devres_add(dev, ptr); | |
24 | } else { | |
25 | devres_free(ptr); | |
26 | } | |
27 | ||
28 | return clk; | |
29 | } | |
30 | EXPORT_SYMBOL(devm_clk_get); | |
31 | ||
60b8f0dd PE |
32 | struct clk *devm_clk_get_optional(struct device *dev, const char *id) |
33 | { | |
34 | struct clk *clk = devm_clk_get(dev, id); | |
35 | ||
36 | if (clk == ERR_PTR(-ENOENT)) | |
37 | return NULL; | |
38 | ||
39 | return clk; | |
40 | } | |
41 | EXPORT_SYMBOL(devm_clk_get_optional); | |
42 | ||
618aee02 DA |
43 | struct clk_bulk_devres { |
44 | struct clk_bulk_data *clks; | |
45 | int num_clks; | |
46 | }; | |
47 | ||
48 | static void devm_clk_bulk_release(struct device *dev, void *res) | |
49 | { | |
50 | struct clk_bulk_devres *devres = res; | |
51 | ||
52 | clk_bulk_put(devres->num_clks, devres->clks); | |
53 | } | |
54 | ||
55 | int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, | |
56 | struct clk_bulk_data *clks) | |
57 | { | |
58 | struct clk_bulk_devres *devres; | |
59 | int ret; | |
60 | ||
61 | devres = devres_alloc(devm_clk_bulk_release, | |
62 | sizeof(*devres), GFP_KERNEL); | |
63 | if (!devres) | |
64 | return -ENOMEM; | |
65 | ||
66 | ret = clk_bulk_get(dev, num_clks, clks); | |
67 | if (!ret) { | |
68 | devres->clks = clks; | |
69 | devres->num_clks = num_clks; | |
70 | devres_add(dev, devres); | |
71 | } else { | |
72 | devres_free(devres); | |
73 | } | |
74 | ||
75 | return ret; | |
76 | } | |
77 | EXPORT_SYMBOL_GPL(devm_clk_bulk_get); | |
78 | ||
f08c2e28 DA |
79 | int __must_check devm_clk_bulk_get_all(struct device *dev, |
80 | struct clk_bulk_data **clks) | |
81 | { | |
82 | struct clk_bulk_devres *devres; | |
83 | int ret; | |
84 | ||
85 | devres = devres_alloc(devm_clk_bulk_release, | |
86 | sizeof(*devres), GFP_KERNEL); | |
87 | if (!devres) | |
88 | return -ENOMEM; | |
89 | ||
90 | ret = clk_bulk_get_all(dev, &devres->clks); | |
91 | if (ret > 0) { | |
92 | *clks = devres->clks; | |
93 | devres->num_clks = ret; | |
94 | devres_add(dev, devres); | |
95 | } else { | |
96 | devres_free(devres); | |
97 | } | |
98 | ||
99 | return ret; | |
100 | } | |
101 | EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); | |
102 | ||
8ef997b6 LPC |
103 | static int devm_clk_match(struct device *dev, void *res, void *data) |
104 | { | |
105 | struct clk **c = res; | |
106 | if (!c || !*c) { | |
107 | WARN_ON(!c || !*c); | |
108 | return 0; | |
109 | } | |
110 | return *c == data; | |
111 | } | |
112 | ||
113 | void devm_clk_put(struct device *dev, struct clk *clk) | |
114 | { | |
115 | int ret; | |
116 | ||
20332ff3 | 117 | ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); |
8ef997b6 LPC |
118 | |
119 | WARN_ON(ret); | |
120 | } | |
121 | EXPORT_SYMBOL(devm_clk_put); | |
71a2f115 KM |
122 | |
123 | struct clk *devm_get_clk_from_child(struct device *dev, | |
124 | struct device_node *np, const char *con_id) | |
125 | { | |
126 | struct clk **ptr, *clk; | |
127 | ||
128 | ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); | |
129 | if (!ptr) | |
130 | return ERR_PTR(-ENOMEM); | |
131 | ||
132 | clk = of_clk_get_by_name(np, con_id); | |
133 | if (!IS_ERR(clk)) { | |
134 | *ptr = clk; | |
135 | devres_add(dev, ptr); | |
136 | } else { | |
137 | devres_free(ptr); | |
138 | } | |
139 | ||
140 | return clk; | |
141 | } | |
142 | EXPORT_SYMBOL(devm_get_clk_from_child); |