diff options
Diffstat (limited to 'drivers/mfd/mfd-core.c')
| -rw-r--r-- | drivers/mfd/mfd-core.c | 54 | 
1 files changed, 37 insertions, 17 deletions
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index f421586f29f..892d343193a 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -20,6 +20,7 @@  #include <linux/module.h>  #include <linux/irqdomain.h>  #include <linux/of.h> +#include <linux/regulator/consumer.h>  static struct device_type mfd_dev_type = {  	.name	= "mfd_device", @@ -63,7 +64,8 @@ int mfd_cell_disable(struct platform_device *pdev)  EXPORT_SYMBOL(mfd_cell_disable);  static int mfd_platform_add_cell(struct platform_device *pdev, -				 const struct mfd_cell *cell) +				 const struct mfd_cell *cell, +				 atomic_t *usage_count)  {  	if (!cell)  		return 0; @@ -72,11 +74,12 @@ static int mfd_platform_add_cell(struct platform_device *pdev,  	if (!pdev->mfd_cell)  		return -ENOMEM; +	pdev->mfd_cell->usage_count = usage_count;  	return 0;  }  static int mfd_add_device(struct device *parent, int id, -			  const struct mfd_cell *cell, +			  const struct mfd_cell *cell, atomic_t *usage_count,  			  struct resource *mem_base,  			  int irq_base, struct irq_domain *domain)  { @@ -99,6 +102,13 @@ static int mfd_add_device(struct device *parent, int id,  	pdev->dev.dma_mask = parent->dma_mask;  	pdev->dev.dma_parms = parent->dma_parms; +	ret = regulator_bulk_register_supply_alias( +			&pdev->dev, cell->parent_supplies, +			parent, cell->parent_supplies, +			cell->num_parent_supplies); +	if (ret < 0) +		goto fail_res; +  	if (parent->of_node && cell->of_compatible) {  		for_each_child_of_node(parent->of_node, np) {  			if (of_device_is_compatible(np, cell->of_compatible)) { @@ -112,12 +122,12 @@ static int mfd_add_device(struct device *parent, int id,  		ret = platform_device_add_data(pdev,  					cell->platform_data, cell->pdata_size);  		if (ret) -			goto fail_res; +			goto fail_alias;  	} -	ret = mfd_platform_add_cell(pdev, cell); +	ret = mfd_platform_add_cell(pdev, cell, usage_count);  	if (ret) -		goto fail_res; +		goto fail_alias;  	for (r = 0; r < cell->num_resources; r++) {  		res[r].name = cell->resources[r].name; @@ -152,17 +162,17 @@ static int mfd_add_device(struct device *parent, int id,  		if (!cell->ignore_resource_conflicts) {  			ret = acpi_check_resource_conflict(&res[r]);  			if (ret) -				goto fail_res; +				goto fail_alias;  		}  	}  	ret = platform_device_add_resources(pdev, res, cell->num_resources);  	if (ret) -		goto fail_res; +		goto fail_alias;  	ret = platform_device_add(pdev);  	if (ret) -		goto fail_res; +		goto fail_alias;  	if (cell->pm_runtime_no_callbacks)  		pm_runtime_no_callbacks(&pdev->dev); @@ -171,6 +181,10 @@ static int mfd_add_device(struct device *parent, int id,  	return 0; +fail_alias: +	regulator_bulk_unregister_supply_alias(&pdev->dev, +					       cell->parent_supplies, +					       cell->num_parent_supplies);  fail_res:  	kfree(res);  fail_device: @@ -180,12 +194,12 @@ fail_alloc:  }  int mfd_add_devices(struct device *parent, int id, -		    struct mfd_cell *cells, int n_devs, +		    const struct mfd_cell *cells, int n_devs,  		    struct resource *mem_base,  		    int irq_base, struct irq_domain *domain)  {  	int i; -	int ret = 0; +	int ret;  	atomic_t *cnts;  	/* initialize reference counting for all cells */ @@ -195,16 +209,19 @@ int mfd_add_devices(struct device *parent, int id,  	for (i = 0; i < n_devs; i++) {  		atomic_set(&cnts[i], 0); -		cells[i].usage_count = &cnts[i]; -		ret = mfd_add_device(parent, id, cells + i, mem_base, +		ret = mfd_add_device(parent, id, cells + i, cnts + i, mem_base,  				     irq_base, domain);  		if (ret) -			break; +			goto fail;  	} -	if (ret) -		mfd_remove_devices(parent); +	return 0; +fail: +	if (i) +		mfd_remove_devices(parent); +	else +		kfree(cnts);  	return ret;  }  EXPORT_SYMBOL(mfd_add_devices); @@ -221,6 +238,9 @@ static int mfd_remove_devices_fn(struct device *dev, void *c)  	pdev = to_platform_device(dev);  	cell = mfd_get_cell(pdev); +	regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies, +					       cell->num_parent_supplies); +  	/* find the base address of usage_count pointers (for freeing) */  	if (!*usage_count || (cell->usage_count < *usage_count))  		*usage_count = cell->usage_count; @@ -259,8 +279,8 @@ int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones)  	for (i = 0; i < n_clones; i++) {  		cell_entry.name = clones[i];  		/* don't give up if a single call fails; just report error */ -		if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0, -				   NULL)) +		if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, +				   cell_entry.usage_count, NULL, 0, NULL))  			dev_err(dev, "failed to create platform device '%s'\n",  					clones[i]);  	}  | 
