scsi: hisi_sas: Reduce HISI_SAS_SGE_PAGE_CNT in size
[linux-2.6-microblaze.git] / drivers / extcon / devres.c
1 /*
2  * drivers/extcon/devres.c - EXTCON device's resource management
3  *
4  * Copyright (C) 2016 Samsung Electronics
5  * Author: Chanwoo Choi <cw00.choi@samsung.com>
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include "extcon.h"
18
19 static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
20 {
21         struct extcon_dev **r = res;
22
23         if (WARN_ON(!r || !*r))
24                 return 0;
25
26         return *r == data;
27 }
28
29 static void devm_extcon_dev_release(struct device *dev, void *res)
30 {
31         extcon_dev_free(*(struct extcon_dev **)res);
32 }
33
34
35 static void devm_extcon_dev_unreg(struct device *dev, void *res)
36 {
37         extcon_dev_unregister(*(struct extcon_dev **)res);
38 }
39
40 struct extcon_dev_notifier_devres {
41         struct extcon_dev *edev;
42         unsigned int id;
43         struct notifier_block *nb;
44 };
45
46 static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
47 {
48         struct extcon_dev_notifier_devres *this = res;
49
50         extcon_unregister_notifier(this->edev, this->id, this->nb);
51 }
52
53 static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
54 {
55         struct extcon_dev_notifier_devres *this = res;
56
57         extcon_unregister_notifier_all(this->edev, this->nb);
58 }
59
60 /**
61  * devm_extcon_dev_allocate - Allocate managed extcon device
62  * @dev:                the device owning the extcon device being created
63  * @supported_cable:    the array of the supported external connectors
64  *                      ending with EXTCON_NONE.
65  *
66  * This function manages automatically the memory of extcon device using device
67  * resource management and simplify the control of freeing the memory of extcon
68  * device.
69  *
70  * Returns the pointer memory of allocated extcon_dev if success
71  * or ERR_PTR(err) if fail
72  */
73 struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
74                                         const unsigned int *supported_cable)
75 {
76         struct extcon_dev **ptr, *edev;
77
78         ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
79         if (!ptr)
80                 return ERR_PTR(-ENOMEM);
81
82         edev = extcon_dev_allocate(supported_cable);
83         if (IS_ERR(edev)) {
84                 devres_free(ptr);
85                 return edev;
86         }
87
88         edev->dev.parent = dev;
89
90         *ptr = edev;
91         devres_add(dev, ptr);
92
93         return edev;
94 }
95 EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
96
97 /**
98  * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()
99  * @dev:        the device owning the extcon device being created
100  * @edev:       the extcon device to be freed
101  *
102  * Free the memory that is allocated with devm_extcon_dev_allocate()
103  * function.
104  */
105 void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
106 {
107         WARN_ON(devres_release(dev, devm_extcon_dev_release,
108                                devm_extcon_dev_match, edev));
109 }
110 EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
111
112 /**
113  * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
114  * @dev:        the device owning the extcon device being created
115  * @edev:       the extcon device to be registered
116  *
117  * this function, that extcon device is automatically unregistered on driver
118  * detach. Internally this function calls extcon_dev_register() function.
119  * To get more information, refer that function.
120  *
121  * If extcon device is registered with this function and the device needs to be
122  * unregistered separately, devm_extcon_dev_unregister() should be used.
123  *
124  * Returns 0 if success or negaive error number if failure.
125  */
126 int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
127 {
128         struct extcon_dev **ptr;
129         int ret;
130
131         ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
132         if (!ptr)
133                 return -ENOMEM;
134
135         ret = extcon_dev_register(edev);
136         if (ret) {
137                 devres_free(ptr);
138                 return ret;
139         }
140
141         *ptr = edev;
142         devres_add(dev, ptr);
143
144         return 0;
145 }
146 EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
147
148 /**
149  * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
150  * @dev:        the device owning the extcon device being created
151  * @edev:       the extcon device to unregistered
152  *
153  * Unregister extcon device that is registered with devm_extcon_dev_register()
154  * function.
155  */
156 void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
157 {
158         WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
159                                devm_extcon_dev_match, edev));
160 }
161 EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
162
163 /**
164  * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier()
165  * @dev:        the device owning the extcon device being created
166  * @edev:       the extcon device
167  * @id:         the unique id among the extcon enumeration
168  * @nb:         a notifier block to be registered
169  *
170  * This function manages automatically the notifier of extcon device using
171  * device resource management and simplify the control of unregistering
172  * the notifier of extcon device.
173  *
174  * Note that the second parameter given to the callback of nb (val) is
175  * "old_state", not the current state. The current state can be retrieved
176  * by looking at the third pameter (edev pointer)'s state value.
177  *
178  * Returns 0 if success or negaive error number if failure.
179  */
180 int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev,
181                                 unsigned int id, struct notifier_block *nb)
182 {
183         struct extcon_dev_notifier_devres *ptr;
184         int ret;
185
186         ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr),
187                                 GFP_KERNEL);
188         if (!ptr)
189                 return -ENOMEM;
190
191         ret = extcon_register_notifier(edev, id, nb);
192         if (ret) {
193                 devres_free(ptr);
194                 return ret;
195         }
196
197         ptr->edev = edev;
198         ptr->id = id;
199         ptr->nb = nb;
200         devres_add(dev, ptr);
201
202         return 0;
203 }
204 EXPORT_SYMBOL(devm_extcon_register_notifier);
205
206 /**
207  * devm_extcon_unregister_notifier()
208  *                      - Resource-managed extcon_unregister_notifier()
209  * @dev:        the device owning the extcon device being created
210  * @edev:       the extcon device
211  * @id:         the unique id among the extcon enumeration
212  * @nb:         a notifier block to be registered
213  */
214 void devm_extcon_unregister_notifier(struct device *dev,
215                                 struct extcon_dev *edev, unsigned int id,
216                                 struct notifier_block *nb)
217 {
218         WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg,
219                                devm_extcon_dev_match, edev));
220 }
221 EXPORT_SYMBOL(devm_extcon_unregister_notifier);
222
223 /**
224  * devm_extcon_register_notifier_all()
225  *              - Resource-managed extcon_register_notifier_all()
226  * @dev:        the device owning the extcon device being created
227  * @edev:       the extcon device
228  * @nb:         a notifier block to be registered
229  *
230  * This function manages automatically the notifier of extcon device using
231  * device resource management and simplify the control of unregistering
232  * the notifier of extcon device. To get more information, refer that function.
233  *
234  * Returns 0 if success or negaive error number if failure.
235  */
236 int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
237                                 struct notifier_block *nb)
238 {
239         struct extcon_dev_notifier_devres *ptr;
240         int ret;
241
242         ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
243                                 GFP_KERNEL);
244         if (!ptr)
245                 return -ENOMEM;
246
247         ret = extcon_register_notifier_all(edev, nb);
248         if (ret) {
249                 devres_free(ptr);
250                 return ret;
251         }
252
253         ptr->edev = edev;
254         ptr->nb = nb;
255         devres_add(dev, ptr);
256
257         return 0;
258 }
259 EXPORT_SYMBOL(devm_extcon_register_notifier_all);
260
261 /**
262  * devm_extcon_unregister_notifier_all()
263  *              - Resource-managed extcon_unregister_notifier_all()
264  * @dev:        the device owning the extcon device being created
265  * @edev:       the extcon device
266  * @nb:         a notifier block to be registered
267  */
268 void devm_extcon_unregister_notifier_all(struct device *dev,
269                                 struct extcon_dev *edev,
270                                 struct notifier_block *nb)
271 {
272         WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
273                                devm_extcon_dev_match, edev));
274 }
275 EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);