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
This commit is contained in:
Родитель
40ee6fbef7
Коммит
38b0b219fb
|
@ -571,6 +571,77 @@ void of_platform_depopulate(struct device *parent)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(of_platform_depopulate);
|
||||
|
||||
static void devm_of_platform_populate_release(struct device *dev, void *res)
|
||||
{
|
||||
of_platform_depopulate(*(struct device **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_of_platform_populate() - Populate platform_devices from device tree data
|
||||
* @dev: device that requested to populate from device tree data
|
||||
*
|
||||
* Similar to of_platform_populate(), but will automatically call
|
||||
* of_platform_depopulate() when the device is unbound from the bus.
|
||||
*
|
||||
* Returns 0 on success, < 0 on failure.
|
||||
*/
|
||||
int devm_of_platform_populate(struct device *dev)
|
||||
{
|
||||
struct device **ptr;
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
ptr = devres_alloc(devm_of_platform_populate_release,
|
||||
sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
devres_free(ptr);
|
||||
} else {
|
||||
*ptr = dev;
|
||||
devres_add(dev, ptr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_of_platform_populate);
|
||||
|
||||
static int devm_of_platform_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct device **ptr = res;
|
||||
|
||||
if (!ptr) {
|
||||
WARN_ON(!ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return *ptr == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_of_platform_depopulate() - Remove devices populated from device tree
|
||||
* @dev: device that requested to depopulate from device tree data
|
||||
*
|
||||
* Complementary to devm_of_platform_populate(), this function removes children
|
||||
* of the given device (and, recurrently, their children) that have been
|
||||
* created from their respective device tree nodes (and only those,
|
||||
* leaving others - eg. manually created - unharmed).
|
||||
*/
|
||||
void devm_of_platform_depopulate(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = devres_release(dev, devm_of_platform_populate_release,
|
||||
devm_of_platform_match, dev);
|
||||
|
||||
WARN_ON(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_of_platform_depopulate);
|
||||
|
||||
#ifdef CONFIG_OF_DYNAMIC
|
||||
static int of_platform_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *arg)
|
||||
|
|
|
@ -76,6 +76,10 @@ extern int of_platform_default_populate(struct device_node *root,
|
|||
const struct of_dev_auxdata *lookup,
|
||||
struct device *parent);
|
||||
extern void of_platform_depopulate(struct device *parent);
|
||||
|
||||
extern int devm_of_platform_populate(struct device *dev);
|
||||
|
||||
extern void devm_of_platform_depopulate(struct device *dev);
|
||||
#else
|
||||
static inline int of_platform_populate(struct device_node *root,
|
||||
const struct of_device_id *matches,
|
||||
|
@ -91,6 +95,13 @@ static inline int of_platform_default_populate(struct device_node *root,
|
|||
return -ENODEV;
|
||||
}
|
||||
static inline void of_platform_depopulate(struct device *parent) { }
|
||||
|
||||
static inline int devm_of_platform_populate(struct device *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void devm_of_platform_depopulate(struct device *dev) { }
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF_DYNAMIC) && defined(CONFIG_OF_ADDRESS)
|
||||
|
|
Загрузка…
Ссылка в новой задаче