• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cw00.choi@samsung.com>
7   */
8  
9  #include "extcon.h"
10  
devm_extcon_dev_match(struct device * dev,void * res,void * data)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  
devm_extcon_dev_release(struct device * dev,void * res)21  static void devm_extcon_dev_release(struct device *dev, void *res)
22  {
23  	extcon_dev_free(*(struct extcon_dev **)res);
24  }
25  
26  
devm_extcon_dev_unreg(struct device * dev,void * res)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  
devm_extcon_dev_notifier_unreg(struct device * dev,void * res)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  
devm_extcon_dev_notifier_all_unreg(struct device * dev,void * res)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   */
devm_extcon_dev_allocate(struct device * dev,const unsigned int * supported_cable)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   */
devm_extcon_dev_free(struct device * dev,struct extcon_dev * edev)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   */
devm_extcon_dev_register(struct device * dev,struct extcon_dev * edev)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   */
devm_extcon_dev_unregister(struct device * dev,struct extcon_dev * edev)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   */
devm_extcon_register_notifier(struct device * dev,struct extcon_dev * edev,unsigned int id,struct notifier_block * nb)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   */
devm_extcon_unregister_notifier(struct device * dev,struct extcon_dev * edev,unsigned int id,struct notifier_block * nb)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   */
devm_extcon_register_notifier_all(struct device * dev,struct extcon_dev * edev,struct notifier_block * nb)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   */
devm_extcon_unregister_notifier_all(struct device * dev,struct extcon_dev * edev,struct notifier_block * nb)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