• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
devm_extcon_dev_match(struct device * dev,void * res,void * data)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  
devm_extcon_dev_release(struct device * dev,void * res)29  static void devm_extcon_dev_release(struct device *dev, void *res)
30  {
31  	extcon_dev_free(*(struct extcon_dev **)res);
32  }
33  
34  
devm_extcon_dev_unreg(struct device * dev,void * res)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  
devm_extcon_dev_notifier_unreg(struct device * dev,void * res)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  
devm_extcon_dev_notifier_all_unreg(struct device * dev,void * res)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   */
devm_extcon_dev_allocate(struct device * dev,const unsigned int * supported_cable)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   */
devm_extcon_dev_free(struct device * dev,struct extcon_dev * edev)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   */
devm_extcon_dev_register(struct device * dev,struct extcon_dev * edev)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   */
devm_extcon_dev_unregister(struct device * dev,struct extcon_dev * edev)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   */
devm_extcon_register_notifier(struct device * dev,struct extcon_dev * edev,unsigned int id,struct notifier_block * nb)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   */
devm_extcon_unregister_notifier(struct device * dev,struct extcon_dev * edev,unsigned int id,struct notifier_block * nb)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   */
devm_extcon_register_notifier_all(struct device * dev,struct extcon_dev * edev,struct notifier_block * nb)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   */
devm_extcon_unregister_notifier_all(struct device * dev,struct extcon_dev * edev,struct notifier_block * nb)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);
276