Merge tag 'asoc-fix-v5.0-rc2' of https://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / clk / clk-devres.c
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 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
32 struct clk_bulk_devres {
33         struct clk_bulk_data *clks;
34         int num_clks;
35 };
36
37 static void devm_clk_bulk_release(struct device *dev, void *res)
38 {
39         struct clk_bulk_devres *devres = res;
40
41         clk_bulk_put(devres->num_clks, devres->clks);
42 }
43
44 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
45                       struct clk_bulk_data *clks)
46 {
47         struct clk_bulk_devres *devres;
48         int ret;
49
50         devres = devres_alloc(devm_clk_bulk_release,
51                               sizeof(*devres), GFP_KERNEL);
52         if (!devres)
53                 return -ENOMEM;
54
55         ret = clk_bulk_get(dev, num_clks, clks);
56         if (!ret) {
57                 devres->clks = clks;
58                 devres->num_clks = num_clks;
59                 devres_add(dev, devres);
60         } else {
61                 devres_free(devres);
62         }
63
64         return ret;
65 }
66 EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
67
68 int __must_check devm_clk_bulk_get_all(struct device *dev,
69                                        struct clk_bulk_data **clks)
70 {
71         struct clk_bulk_devres *devres;
72         int ret;
73
74         devres = devres_alloc(devm_clk_bulk_release,
75                               sizeof(*devres), GFP_KERNEL);
76         if (!devres)
77                 return -ENOMEM;
78
79         ret = clk_bulk_get_all(dev, &devres->clks);
80         if (ret > 0) {
81                 *clks = devres->clks;
82                 devres->num_clks = ret;
83                 devres_add(dev, devres);
84         } else {
85                 devres_free(devres);
86         }
87
88         return ret;
89 }
90 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
91
92 static int devm_clk_match(struct device *dev, void *res, void *data)
93 {
94         struct clk **c = res;
95         if (!c || !*c) {
96                 WARN_ON(!c || !*c);
97                 return 0;
98         }
99         return *c == data;
100 }
101
102 void devm_clk_put(struct device *dev, struct clk *clk)
103 {
104         int ret;
105
106         ret = devres_release(dev, devm_clk_release, devm_clk_match, clk);
107
108         WARN_ON(ret);
109 }
110 EXPORT_SYMBOL(devm_clk_put);
111
112 struct clk *devm_get_clk_from_child(struct device *dev,
113                                     struct device_node *np, const char *con_id)
114 {
115         struct clk **ptr, *clk;
116
117         ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
118         if (!ptr)
119                 return ERR_PTR(-ENOMEM);
120
121         clk = of_clk_get_by_name(np, con_id);
122         if (!IS_ERR(clk)) {
123                 *ptr = clk;
124                 devres_add(dev, ptr);
125         } else {
126                 devres_free(ptr);
127         }
128
129         return clk;
130 }
131 EXPORT_SYMBOL(devm_get_clk_from_child);