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