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 | ||
9bd5ef0b SN |
55 | static int __devm_clk_bulk_get(struct device *dev, int num_clks, |
56 | struct clk_bulk_data *clks, bool optional) | |
618aee02 DA |
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 | ||
9bd5ef0b SN |
66 | if (optional) |
67 | ret = clk_bulk_get_optional(dev, num_clks, clks); | |
68 | else | |
69 | ret = clk_bulk_get(dev, num_clks, clks); | |
618aee02 DA |
70 | if (!ret) { |
71 | devres->clks = clks; | |
72 | devres->num_clks = num_clks; | |
73 | devres_add(dev, devres); | |
74 | } else { | |
75 | devres_free(devres); | |
76 | } | |
77 | ||
78 | return ret; | |
79 | } | |
9bd5ef0b SN |
80 | |
81 | int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, | |
82 | struct clk_bulk_data *clks) | |
83 | { | |
84 | return __devm_clk_bulk_get(dev, num_clks, clks, false); | |
85 | } | |
618aee02 DA |
86 | EXPORT_SYMBOL_GPL(devm_clk_bulk_get); |
87 | ||
9bd5ef0b SN |
88 | int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, |
89 | struct clk_bulk_data *clks) | |
90 | { | |
91 | return __devm_clk_bulk_get(dev, num_clks, clks, true); | |
92 | } | |
93 | EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional); | |
94 | ||
f08c2e28 DA |
95 | int __must_check devm_clk_bulk_get_all(struct device *dev, |
96 | struct clk_bulk_data **clks) | |
97 | { | |
98 | struct clk_bulk_devres *devres; | |
99 | int ret; | |
100 | ||
101 | devres = devres_alloc(devm_clk_bulk_release, | |
102 | sizeof(*devres), GFP_KERNEL); | |
103 | if (!devres) | |
104 | return -ENOMEM; | |
105 | ||
106 | ret = clk_bulk_get_all(dev, &devres->clks); | |
107 | if (ret > 0) { | |
108 | *clks = devres->clks; | |
109 | devres->num_clks = ret; | |
110 | devres_add(dev, devres); | |
111 | } else { | |
112 | devres_free(devres); | |
113 | } | |
114 | ||
115 | return ret; | |
116 | } | |
117 | EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); | |
118 | ||
8ef997b6 LPC |
119 | static int devm_clk_match(struct device *dev, void *res, void *data) |
120 | { | |
121 | struct clk **c = res; | |
122 | if (!c || !*c) { | |
123 | WARN_ON(!c || !*c); | |
124 | return 0; | |
125 | } | |
126 | return *c == data; | |
127 | } | |
128 | ||
129 | void devm_clk_put(struct device *dev, struct clk *clk) | |
130 | { | |
131 | int ret; | |
132 | ||
20332ff3 | 133 | ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); |
8ef997b6 LPC |
134 | |
135 | WARN_ON(ret); | |
136 | } | |
137 | EXPORT_SYMBOL(devm_clk_put); | |
71a2f115 KM |
138 | |
139 | struct clk *devm_get_clk_from_child(struct device *dev, | |
140 | struct device_node *np, const char *con_id) | |
141 | { | |
142 | struct clk **ptr, *clk; | |
143 | ||
144 | ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); | |
145 | if (!ptr) | |
146 | return ERR_PTR(-ENOMEM); | |
147 | ||
148 | clk = of_clk_get_by_name(np, con_id); | |
149 | if (!IS_ERR(clk)) { | |
150 | *ptr = clk; | |
151 | devres_add(dev, ptr); | |
152 | } else { | |
153 | devres_free(ptr); | |
154 | } | |
155 | ||
156 | return clk; | |
157 | } | |
158 | EXPORT_SYMBOL(devm_get_clk_from_child); |