Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

of: add devm_ functions for populate and depopulate

Lots of calls to of_platform_populate() are not unbalanced by a call
to of_platform_depopulate(). This create issues while drivers are
bind/unbind.

In way to solve those issues is to add devm_of_platform_populate()
which will call of_platform_depopulate() when the device is unbound
from the bus.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1487952874-23635-2-git-send-email-benjamin.gaignard@linaro.org

authored by

Benjamin Gaignard and committed by
Daniel Vetter
38b0b219 40ee6fbe

+82
+71
drivers/of/platform.c
··· 571 571 } 572 572 EXPORT_SYMBOL_GPL(of_platform_depopulate); 573 573 574 + static void devm_of_platform_populate_release(struct device *dev, void *res) 575 + { 576 + of_platform_depopulate(*(struct device **)res); 577 + } 578 + 579 + /** 580 + * devm_of_platform_populate() - Populate platform_devices from device tree data 581 + * @dev: device that requested to populate from device tree data 582 + * 583 + * Similar to of_platform_populate(), but will automatically call 584 + * of_platform_depopulate() when the device is unbound from the bus. 585 + * 586 + * Returns 0 on success, < 0 on failure. 587 + */ 588 + int devm_of_platform_populate(struct device *dev) 589 + { 590 + struct device **ptr; 591 + int ret; 592 + 593 + if (!dev) 594 + return -EINVAL; 595 + 596 + ptr = devres_alloc(devm_of_platform_populate_release, 597 + sizeof(*ptr), GFP_KERNEL); 598 + if (!ptr) 599 + return -ENOMEM; 600 + 601 + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 602 + if (ret) { 603 + devres_free(ptr); 604 + } else { 605 + *ptr = dev; 606 + devres_add(dev, ptr); 607 + } 608 + 609 + return ret; 610 + } 611 + EXPORT_SYMBOL_GPL(devm_of_platform_populate); 612 + 613 + static int devm_of_platform_match(struct device *dev, void *res, void *data) 614 + { 615 + struct device **ptr = res; 616 + 617 + if (!ptr) { 618 + WARN_ON(!ptr); 619 + return 0; 620 + } 621 + 622 + return *ptr == data; 623 + } 624 + 625 + /** 626 + * devm_of_platform_depopulate() - Remove devices populated from device tree 627 + * @dev: device that requested to depopulate from device tree data 628 + * 629 + * Complementary to devm_of_platform_populate(), this function removes children 630 + * of the given device (and, recurrently, their children) that have been 631 + * created from their respective device tree nodes (and only those, 632 + * leaving others - eg. manually created - unharmed). 633 + */ 634 + void devm_of_platform_depopulate(struct device *dev) 635 + { 636 + int ret; 637 + 638 + ret = devres_release(dev, devm_of_platform_populate_release, 639 + devm_of_platform_match, dev); 640 + 641 + WARN_ON(ret); 642 + } 643 + EXPORT_SYMBOL_GPL(devm_of_platform_depopulate); 644 + 574 645 #ifdef CONFIG_OF_DYNAMIC 575 646 static int of_platform_notify(struct notifier_block *nb, 576 647 unsigned long action, void *arg)
+11
include/linux/of_platform.h
··· 76 76 const struct of_dev_auxdata *lookup, 77 77 struct device *parent); 78 78 extern void of_platform_depopulate(struct device *parent); 79 + 80 + extern int devm_of_platform_populate(struct device *dev); 81 + 82 + extern void devm_of_platform_depopulate(struct device *dev); 79 83 #else 80 84 static inline int of_platform_populate(struct device_node *root, 81 85 const struct of_device_id *matches, ··· 95 91 return -ENODEV; 96 92 } 97 93 static inline void of_platform_depopulate(struct device *parent) { } 94 + 95 + static inline int devm_of_platform_populate(struct device *dev) 96 + { 97 + return -ENODEV; 98 + } 99 + 100 + static inline void devm_of_platform_depopulate(struct device *dev) { } 98 101 #endif 99 102 100 103 #if defined(CONFIG_OF_DYNAMIC) && defined(CONFIG_OF_ADDRESS)