diff options
-rw-r--r-- | drivers/extcon/extcon-class.c | 70 | ||||
-rw-r--r-- | include/linux/extcon.h | 11 |
2 files changed, 69 insertions, 12 deletions
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c index 654ed52e17c2..18d42c0e4581 100644 --- a/drivers/extcon/extcon-class.c +++ b/drivers/extcon/extcon-class.c | |||
@@ -601,6 +601,64 @@ void extcon_dev_free(struct extcon_dev *edev) | |||
601 | } | 601 | } |
602 | EXPORT_SYMBOL_GPL(extcon_dev_free); | 602 | EXPORT_SYMBOL_GPL(extcon_dev_free); |
603 | 603 | ||
604 | static int devm_extcon_dev_match(struct device *dev, void *res, void *data) | ||
605 | { | ||
606 | struct extcon_dev **r = res; | ||
607 | |||
608 | if (WARN_ON(!r || !*r)) | ||
609 | return 0; | ||
610 | |||
611 | return *r == data; | ||
612 | } | ||
613 | |||
614 | static void devm_extcon_dev_release(struct device *dev, void *res) | ||
615 | { | ||
616 | extcon_dev_free(*(struct extcon_dev **)res); | ||
617 | } | ||
618 | |||
619 | /** | ||
620 | * devm_extcon_dev_allocate - Allocate managed extcon device | ||
621 | * @dev: device owning the extcon device being created | ||
622 | * @supported_cable: Array of supported cable names ending with NULL. | ||
623 | * If supported_cable is NULL, cable name related APIs | ||
624 | * are disabled. | ||
625 | * | ||
626 | * This function manages automatically the memory of extcon device using device | ||
627 | * resource management and simplify the control of freeing the memory of extcon | ||
628 | * device. | ||
629 | * | ||
630 | * Returns the pointer memory of allocated extcon_dev if success | ||
631 | * or ERR_PTR(err) if fail | ||
632 | */ | ||
633 | struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, | ||
634 | const char **supported_cable) | ||
635 | { | ||
636 | struct extcon_dev **ptr, *edev; | ||
637 | |||
638 | ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL); | ||
639 | if (!ptr) | ||
640 | return ERR_PTR(-ENOMEM); | ||
641 | |||
642 | edev = extcon_dev_allocate(supported_cable); | ||
643 | if (IS_ERR(edev)) { | ||
644 | devres_free(ptr); | ||
645 | return edev; | ||
646 | } | ||
647 | |||
648 | *ptr = edev; | ||
649 | devres_add(dev, ptr); | ||
650 | |||
651 | return edev; | ||
652 | } | ||
653 | EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate); | ||
654 | |||
655 | void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev) | ||
656 | { | ||
657 | WARN_ON(devres_release(dev, devm_extcon_dev_release, | ||
658 | devm_extcon_dev_match, edev)); | ||
659 | } | ||
660 | EXPORT_SYMBOL_GPL(devm_extcon_dev_free); | ||
661 | |||
604 | /** | 662 | /** |
605 | * extcon_dev_register() - Register a new extcon device | 663 | * extcon_dev_register() - Register a new extcon device |
606 | * @edev : the new extcon device (should be allocated before calling) | 664 | * @edev : the new extcon device (should be allocated before calling) |
@@ -860,18 +918,6 @@ static void devm_extcon_dev_unreg(struct device *dev, void *res) | |||
860 | extcon_dev_unregister(*(struct extcon_dev **)res); | 918 | extcon_dev_unregister(*(struct extcon_dev **)res); |
861 | } | 919 | } |
862 | 920 | ||
863 | static int devm_extcon_dev_match(struct device *dev, void *res, void *data) | ||
864 | { | ||
865 | struct extcon_dev **r = res; | ||
866 | |||
867 | if (!r || !*r) { | ||
868 | WARN_ON(!r || !*r); | ||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | return *r == data; | ||
873 | } | ||
874 | |||
875 | /** | 921 | /** |
876 | * devm_extcon_dev_register() - Resource-managed extcon_dev_register() | 922 | * devm_extcon_dev_register() - Resource-managed extcon_dev_register() |
877 | * @dev: device to allocate extcon device | 923 | * @dev: device to allocate extcon device |
diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 15361a2f2f19..36f49c405dfb 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h | |||
@@ -196,6 +196,9 @@ extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name); | |||
196 | */ | 196 | */ |
197 | extern struct extcon_dev *extcon_dev_allocate(const char **cables); | 197 | extern struct extcon_dev *extcon_dev_allocate(const char **cables); |
198 | extern void extcon_dev_free(struct extcon_dev *edev); | 198 | extern void extcon_dev_free(struct extcon_dev *edev); |
199 | extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, | ||
200 | const char **cables); | ||
201 | extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); | ||
199 | 202 | ||
200 | /* | 203 | /* |
201 | * get/set/update_state access the 32b encoded state value, which represents | 204 | * get/set/update_state access the 32b encoded state value, which represents |
@@ -280,6 +283,14 @@ static inline struct extcon_dev *extcon_dev_allocate(const char **cables) | |||
280 | 283 | ||
281 | static inline void extcon_dev_free(struct extcon_dev *edev) { } | 284 | static inline void extcon_dev_free(struct extcon_dev *edev) { } |
282 | 285 | ||
286 | static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, | ||
287 | const char **cables) | ||
288 | { | ||
289 | return ERR_PTR(-ENOSYS); | ||
290 | } | ||
291 | |||
292 | static inline void devm_extcon_dev_free(struct extcon_dev *edev) { } | ||
293 | |||
283 | static inline u32 extcon_get_state(struct extcon_dev *edev) | 294 | static inline u32 extcon_get_state(struct extcon_dev *edev) |
284 | { | 295 | { |
285 | return 0; | 296 | return 0; |