devres.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. #include "extcon.h"
  17. static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
  18. {
  19. struct extcon_dev **r = res;
  20. if (WARN_ON(!r || !*r))
  21. return 0;
  22. return *r == data;
  23. }
  24. static void devm_extcon_dev_release(struct device *dev, void *res)
  25. {
  26. extcon_dev_free(*(struct extcon_dev **)res);
  27. }
  28. static void devm_extcon_dev_unreg(struct device *dev, void *res)
  29. {
  30. extcon_dev_unregister(*(struct extcon_dev **)res);
  31. }
  32. struct extcon_dev_notifier_devres {
  33. struct extcon_dev *edev;
  34. unsigned int id;
  35. struct notifier_block *nb;
  36. };
  37. static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res)
  38. {
  39. struct extcon_dev_notifier_devres *this = res;
  40. extcon_unregister_notifier(this->edev, this->id, this->nb);
  41. }
  42. static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res)
  43. {
  44. struct extcon_dev_notifier_devres *this = res;
  45. extcon_unregister_notifier_all(this->edev, this->nb);
  46. }
  47. /**
  48. * devm_extcon_dev_allocate - Allocate managed extcon device
  49. * @dev: device owning the extcon device being created
  50. * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
  51. * If supported_cable is NULL, cable name related APIs
  52. * are disabled.
  53. *
  54. * This function manages automatically the memory of extcon device using device
  55. * resource management and simplify the control of freeing the memory of extcon
  56. * device.
  57. *
  58. * Returns the pointer memory of allocated extcon_dev if success
  59. * or ERR_PTR(err) if fail
  60. */
  61. struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
  62. const unsigned int *supported_cable)
  63. {
  64. struct extcon_dev **ptr, *edev;
  65. ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
  66. if (!ptr)
  67. return ERR_PTR(-ENOMEM);
  68. edev = extcon_dev_allocate(supported_cable);
  69. if (IS_ERR(edev)) {
  70. devres_free(ptr);
  71. return edev;
  72. }
  73. edev->dev.parent = dev;
  74. *ptr = edev;
  75. devres_add(dev, ptr);
  76. return edev;
  77. }
  78. EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
  79. /**
  80. * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()
  81. * @dev: device the extcon belongs to
  82. * @edev: the extcon device to unregister
  83. *
  84. * Free the memory that is allocated with devm_extcon_dev_allocate()
  85. * function.
  86. */
  87. void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
  88. {
  89. WARN_ON(devres_release(dev, devm_extcon_dev_release,
  90. devm_extcon_dev_match, edev));
  91. }
  92. EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
  93. /**
  94. * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
  95. * @dev: device to allocate extcon device
  96. * @edev: the new extcon device to register
  97. *
  98. * Managed extcon_dev_register() function. If extcon device is attached with
  99. * this function, that extcon device is automatically unregistered on driver
  100. * detach. Internally this function calls extcon_dev_register() function.
  101. * To get more information, refer that function.
  102. *
  103. * If extcon device is registered with this function and the device needs to be
  104. * unregistered separately, devm_extcon_dev_unregister() should be used.
  105. *
  106. * Returns 0 if success or negaive error number if failure.
  107. */
  108. int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
  109. {
  110. struct extcon_dev **ptr;
  111. int ret;
  112. ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
  113. if (!ptr)
  114. return -ENOMEM;
  115. ret = extcon_dev_register(edev);
  116. if (ret) {
  117. devres_free(ptr);
  118. return ret;
  119. }
  120. *ptr = edev;
  121. devres_add(dev, ptr);
  122. return 0;
  123. }
  124. EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
  125. /**
  126. * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
  127. * @dev: device the extcon belongs to
  128. * @edev: the extcon device to unregister
  129. *
  130. * Unregister extcon device that is registered with devm_extcon_dev_register()
  131. * function.
  132. */
  133. void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
  134. {
  135. WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
  136. devm_extcon_dev_match, edev));
  137. }
  138. EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
  139. /**
  140. * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier()
  141. * @dev: device to allocate extcon device
  142. * @edev: the extcon device that has the external connecotr.
  143. * @id: the unique id of each external connector in extcon enumeration.
  144. * @nb: a notifier block to be registered.
  145. *
  146. * This function manages automatically the notifier of extcon device using
  147. * device resource management and simplify the control of unregistering
  148. * the notifier of extcon device.
  149. *
  150. * Note that the second parameter given to the callback of nb (val) is
  151. * "old_state", not the current state. The current state can be retrieved
  152. * by looking at the third pameter (edev pointer)'s state value.
  153. *
  154. * Returns 0 if success or negaive error number if failure.
  155. */
  156. int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev,
  157. unsigned int id, struct notifier_block *nb)
  158. {
  159. struct extcon_dev_notifier_devres *ptr;
  160. int ret;
  161. ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr),
  162. GFP_KERNEL);
  163. if (!ptr)
  164. return -ENOMEM;
  165. ret = extcon_register_notifier(edev, id, nb);
  166. if (ret) {
  167. devres_free(ptr);
  168. return ret;
  169. }
  170. ptr->edev = edev;
  171. ptr->id = id;
  172. ptr->nb = nb;
  173. devres_add(dev, ptr);
  174. return 0;
  175. }
  176. EXPORT_SYMBOL(devm_extcon_register_notifier);
  177. /**
  178. * devm_extcon_unregister_notifier()
  179. - Resource-managed extcon_unregister_notifier()
  180. * @dev: device to allocate extcon device
  181. * @edev: the extcon device that has the external connecotr.
  182. * @id: the unique id of each external connector in extcon enumeration.
  183. * @nb: a notifier block to be registered.
  184. */
  185. void devm_extcon_unregister_notifier(struct device *dev,
  186. struct extcon_dev *edev, unsigned int id,
  187. struct notifier_block *nb)
  188. {
  189. WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg,
  190. devm_extcon_dev_match, edev));
  191. }
  192. EXPORT_SYMBOL(devm_extcon_unregister_notifier);
  193. /**
  194. * devm_extcon_register_notifier_all()
  195. * - Resource-managed extcon_register_notifier_all()
  196. * @dev: device to allocate extcon device
  197. * @edev: the extcon device that has the external connecotr.
  198. * @nb: a notifier block to be registered.
  199. *
  200. * This function manages automatically the notifier of extcon device using
  201. * device resource management and simplify the control of unregistering
  202. * the notifier of extcon device. To get more information, refer that function.
  203. *
  204. * Returns 0 if success or negaive error number if failure.
  205. */
  206. int devm_extcon_register_notifier_all(struct device *dev, struct extcon_dev *edev,
  207. struct notifier_block *nb)
  208. {
  209. struct extcon_dev_notifier_devres *ptr;
  210. int ret;
  211. ptr = devres_alloc(devm_extcon_dev_notifier_all_unreg, sizeof(*ptr),
  212. GFP_KERNEL);
  213. if (!ptr)
  214. return -ENOMEM;
  215. ret = extcon_register_notifier_all(edev, nb);
  216. if (ret) {
  217. devres_free(ptr);
  218. return ret;
  219. }
  220. ptr->edev = edev;
  221. ptr->nb = nb;
  222. devres_add(dev, ptr);
  223. return 0;
  224. }
  225. EXPORT_SYMBOL(devm_extcon_register_notifier_all);
  226. /**
  227. * devm_extcon_unregister_notifier_all()
  228. * - Resource-managed extcon_unregister_notifier_all()
  229. * @dev: device to allocate extcon device
  230. * @edev: the extcon device that has the external connecotr.
  231. * @nb: a notifier block to be registered.
  232. */
  233. void devm_extcon_unregister_notifier_all(struct device *dev,
  234. struct extcon_dev *edev,
  235. struct notifier_block *nb)
  236. {
  237. WARN_ON(devres_release(dev, devm_extcon_dev_notifier_all_unreg,
  238. devm_extcon_dev_match, edev));
  239. }
  240. EXPORT_SYMBOL(devm_extcon_unregister_notifier_all);