devres.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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 <linux/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. /**
  43. * devm_extcon_dev_allocate - Allocate managed extcon device
  44. * @dev: device owning the extcon device being created
  45. * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
  46. * If supported_cable is NULL, cable name related APIs
  47. * are disabled.
  48. *
  49. * This function manages automatically the memory of extcon device using device
  50. * resource management and simplify the control of freeing the memory of extcon
  51. * device.
  52. *
  53. * Returns the pointer memory of allocated extcon_dev if success
  54. * or ERR_PTR(err) if fail
  55. */
  56. struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
  57. const unsigned int *supported_cable)
  58. {
  59. struct extcon_dev **ptr, *edev;
  60. ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
  61. if (!ptr)
  62. return ERR_PTR(-ENOMEM);
  63. edev = extcon_dev_allocate(supported_cable);
  64. if (IS_ERR(edev)) {
  65. devres_free(ptr);
  66. return edev;
  67. }
  68. edev->dev.parent = dev;
  69. *ptr = edev;
  70. devres_add(dev, ptr);
  71. return edev;
  72. }
  73. EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
  74. /**
  75. * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister()
  76. * @dev: device the extcon belongs to
  77. * @edev: the extcon device to unregister
  78. *
  79. * Free the memory that is allocated with devm_extcon_dev_allocate()
  80. * function.
  81. */
  82. void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
  83. {
  84. WARN_ON(devres_release(dev, devm_extcon_dev_release,
  85. devm_extcon_dev_match, edev));
  86. }
  87. EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
  88. /**
  89. * devm_extcon_dev_register() - Resource-managed extcon_dev_register()
  90. * @dev: device to allocate extcon device
  91. * @edev: the new extcon device to register
  92. *
  93. * Managed extcon_dev_register() function. If extcon device is attached with
  94. * this function, that extcon device is automatically unregistered on driver
  95. * detach. Internally this function calls extcon_dev_register() function.
  96. * To get more information, refer that function.
  97. *
  98. * If extcon device is registered with this function and the device needs to be
  99. * unregistered separately, devm_extcon_dev_unregister() should be used.
  100. *
  101. * Returns 0 if success or negaive error number if failure.
  102. */
  103. int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
  104. {
  105. struct extcon_dev **ptr;
  106. int ret;
  107. ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
  108. if (!ptr)
  109. return -ENOMEM;
  110. ret = extcon_dev_register(edev);
  111. if (ret) {
  112. devres_free(ptr);
  113. return ret;
  114. }
  115. *ptr = edev;
  116. devres_add(dev, ptr);
  117. return 0;
  118. }
  119. EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
  120. /**
  121. * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
  122. * @dev: device the extcon belongs to
  123. * @edev: the extcon device to unregister
  124. *
  125. * Unregister extcon device that is registered with devm_extcon_dev_register()
  126. * function.
  127. */
  128. void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
  129. {
  130. WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
  131. devm_extcon_dev_match, edev));
  132. }
  133. EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
  134. /**
  135. * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier()
  136. * @dev: device to allocate extcon device
  137. * @edev: the extcon device that has the external connecotr.
  138. * @id: the unique id of each external connector in extcon enumeration.
  139. * @nb: a notifier block to be registered.
  140. *
  141. * This function manages automatically the notifier of extcon device using
  142. * device resource management and simplify the control of unregistering
  143. * the notifier of extcon device.
  144. *
  145. * Note that the second parameter given to the callback of nb (val) is
  146. * "old_state", not the current state. The current state can be retrieved
  147. * by looking at the third pameter (edev pointer)'s state value.
  148. *
  149. * Returns 0 if success or negaive error number if failure.
  150. */
  151. int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev,
  152. unsigned int id, struct notifier_block *nb)
  153. {
  154. struct extcon_dev_notifier_devres *ptr;
  155. int ret;
  156. ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr),
  157. GFP_KERNEL);
  158. if (!ptr)
  159. return -ENOMEM;
  160. ret = extcon_register_notifier(edev, id, nb);
  161. if (ret) {
  162. devres_free(ptr);
  163. return ret;
  164. }
  165. ptr->edev = edev;
  166. ptr->id = id;
  167. ptr->nb = nb;
  168. devres_add(dev, ptr);
  169. return 0;
  170. }
  171. EXPORT_SYMBOL(devm_extcon_register_notifier);
  172. /**
  173. * devm_extcon_unregister_notifier()
  174. - Resource-managed extcon_unregister_notifier()
  175. * @dev: device to allocate extcon device
  176. * @edev: the extcon device that has the external connecotr.
  177. * @id: the unique id of each external connector in extcon enumeration.
  178. * @nb: a notifier block to be registered.
  179. */
  180. void devm_extcon_unregister_notifier(struct device *dev,
  181. struct extcon_dev *edev, unsigned int id,
  182. struct notifier_block *nb)
  183. {
  184. WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg,
  185. devm_extcon_dev_match, edev));
  186. }
  187. EXPORT_SYMBOL(devm_extcon_unregister_notifier);