devres.c 7.3 KB

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