xref: /linux-6.15/drivers/clk/clk-devres.c (revision abae8e57)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/clk.h>
3 #include <linux/device.h>
4 #include <linux/export.h>
5 #include <linux/gfp.h>
6 
7 struct devm_clk_state {
8 	struct clk *clk;
9 	void (*exit)(struct clk *clk);
10 };
11 
12 static void devm_clk_release(struct device *dev, void *res)
13 {
14 	struct devm_clk_state *state = *(struct devm_clk_state **)res;
15 
16 	if (state->exit)
17 		state->exit(state->clk);
18 
19 	clk_put(state->clk);
20 }
21 
22 static struct clk *__devm_clk_get(struct device *dev, const char *id,
23 				  struct clk *(*get)(struct device *dev, const char *id),
24 				  int (*init)(struct clk *clk),
25 				  void (*exit)(struct clk *clk))
26 {
27 	struct devm_clk_state *state;
28 	struct clk *clk;
29 	int ret;
30 
31 	state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
32 	if (!state)
33 		return ERR_PTR(-ENOMEM);
34 
35 	clk = get(dev, id);
36 	if (IS_ERR(clk)) {
37 		ret = PTR_ERR(clk);
38 		goto err_clk_get;
39 	}
40 
41 	if (init) {
42 		ret = init(clk);
43 		if (ret)
44 			goto err_clk_init;
45 	}
46 
47 	state->clk = clk;
48 	state->exit = exit;
49 
50 	devres_add(dev, state);
51 
52 	return clk;
53 
54 err_clk_init:
55 
56 	clk_put(clk);
57 err_clk_get:
58 
59 	devres_free(state);
60 	return ERR_PTR(ret);
61 }
62 
63 struct clk *devm_clk_get(struct device *dev, const char *id)
64 {
65 	return __devm_clk_get(dev, id, clk_get, NULL, NULL);
66 }
67 EXPORT_SYMBOL(devm_clk_get);
68 
69 struct clk *devm_clk_get_optional(struct device *dev, const char *id)
70 {
71 	return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
72 }
73 EXPORT_SYMBOL(devm_clk_get_optional);
74 
75 struct clk_bulk_devres {
76 	struct clk_bulk_data *clks;
77 	int num_clks;
78 };
79 
80 static void devm_clk_bulk_release(struct device *dev, void *res)
81 {
82 	struct clk_bulk_devres *devres = res;
83 
84 	clk_bulk_put(devres->num_clks, devres->clks);
85 }
86 
87 static int __devm_clk_bulk_get(struct device *dev, int num_clks,
88 			       struct clk_bulk_data *clks, bool optional)
89 {
90 	struct clk_bulk_devres *devres;
91 	int ret;
92 
93 	devres = devres_alloc(devm_clk_bulk_release,
94 			      sizeof(*devres), GFP_KERNEL);
95 	if (!devres)
96 		return -ENOMEM;
97 
98 	if (optional)
99 		ret = clk_bulk_get_optional(dev, num_clks, clks);
100 	else
101 		ret = clk_bulk_get(dev, num_clks, clks);
102 	if (!ret) {
103 		devres->clks = clks;
104 		devres->num_clks = num_clks;
105 		devres_add(dev, devres);
106 	} else {
107 		devres_free(devres);
108 	}
109 
110 	return ret;
111 }
112 
113 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
114 		      struct clk_bulk_data *clks)
115 {
116 	return __devm_clk_bulk_get(dev, num_clks, clks, false);
117 }
118 EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
119 
120 int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
121 		      struct clk_bulk_data *clks)
122 {
123 	return __devm_clk_bulk_get(dev, num_clks, clks, true);
124 }
125 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
126 
127 static void devm_clk_bulk_release_all(struct device *dev, void *res)
128 {
129 	struct clk_bulk_devres *devres = res;
130 
131 	clk_bulk_put_all(devres->num_clks, devres->clks);
132 }
133 
134 int __must_check devm_clk_bulk_get_all(struct device *dev,
135 				       struct clk_bulk_data **clks)
136 {
137 	struct clk_bulk_devres *devres;
138 	int ret;
139 
140 	devres = devres_alloc(devm_clk_bulk_release_all,
141 			      sizeof(*devres), GFP_KERNEL);
142 	if (!devres)
143 		return -ENOMEM;
144 
145 	ret = clk_bulk_get_all(dev, &devres->clks);
146 	if (ret > 0) {
147 		*clks = devres->clks;
148 		devres->num_clks = ret;
149 		devres_add(dev, devres);
150 	} else {
151 		devres_free(devres);
152 	}
153 
154 	return ret;
155 }
156 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
157 
158 static int devm_clk_match(struct device *dev, void *res, void *data)
159 {
160 	struct clk **c = res;
161 	if (!c || !*c) {
162 		WARN_ON(!c || !*c);
163 		return 0;
164 	}
165 	return *c == data;
166 }
167 
168 void devm_clk_put(struct device *dev, struct clk *clk)
169 {
170 	int ret;
171 
172 	ret = devres_release(dev, devm_clk_release, devm_clk_match, clk);
173 
174 	WARN_ON(ret);
175 }
176 EXPORT_SYMBOL(devm_clk_put);
177 
178 struct clk *devm_get_clk_from_child(struct device *dev,
179 				    struct device_node *np, const char *con_id)
180 {
181 	struct clk **ptr, *clk;
182 
183 	ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
184 	if (!ptr)
185 		return ERR_PTR(-ENOMEM);
186 
187 	clk = of_clk_get_by_name(np, con_id);
188 	if (!IS_ERR(clk)) {
189 		*ptr = clk;
190 		devres_add(dev, ptr);
191 	} else {
192 		devres_free(ptr);
193 	}
194 
195 	return clk;
196 }
197 EXPORT_SYMBOL(devm_get_clk_from_child);
198