diff options
Diffstat (limited to 'drivers/mfd/mfd-core.c')
| -rw-r--r-- | drivers/mfd/mfd-core.c | 118 | 
1 files changed, 24 insertions, 94 deletions
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 23276a80e3b4..f5a73af60dd4 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -26,54 +26,28 @@ static struct device_type mfd_dev_type = {  int mfd_cell_enable(struct platform_device *pdev)  {  	const struct mfd_cell *cell = mfd_get_cell(pdev); -	int err = 0; -	/* only call enable hook if the cell wasn't previously enabled */ -	if (atomic_inc_return(cell->usage_count) == 1) -		err = cell->enable(pdev); - -	/* if the enable hook failed, decrement counter to allow retries */ -	if (err) -		atomic_dec(cell->usage_count); +	if (!cell->enable) { +		dev_dbg(&pdev->dev, "No .enable() call-back registered\n"); +		return 0; +	} -	return err; +	return cell->enable(pdev);  }  EXPORT_SYMBOL(mfd_cell_enable);  int mfd_cell_disable(struct platform_device *pdev)  {  	const struct mfd_cell *cell = mfd_get_cell(pdev); -	int err = 0; - -	/* only disable if no other clients are using it */ -	if (atomic_dec_return(cell->usage_count) == 0) -		err = cell->disable(pdev); - -	/* if the disable hook failed, increment to allow retries */ -	if (err) -		atomic_inc(cell->usage_count); - -	/* sanity check; did someone call disable too many times? */ -	WARN_ON(atomic_read(cell->usage_count) < 0); -	return err; -} -EXPORT_SYMBOL(mfd_cell_disable); - -static int mfd_platform_add_cell(struct platform_device *pdev, -				 const struct mfd_cell *cell, -				 atomic_t *usage_count) -{ -	if (!cell) +	if (!cell->disable) { +		dev_dbg(&pdev->dev, "No .disable() call-back registered\n");  		return 0; +	} -	pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL); -	if (!pdev->mfd_cell) -		return -ENOMEM; - -	pdev->mfd_cell->usage_count = usage_count; -	return 0; +	return cell->disable(pdev);  } +EXPORT_SYMBOL(mfd_cell_disable);  #if IS_ENABLED(CONFIG_ACPI)  static void mfd_acpi_add_device(const struct mfd_cell *cell, @@ -134,7 +108,7 @@ static inline void mfd_acpi_add_device(const struct mfd_cell *cell,  #endif  static int mfd_add_device(struct device *parent, int id, -			  const struct mfd_cell *cell, atomic_t *usage_count, +			  const struct mfd_cell *cell,  			  struct resource *mem_base,  			  int irq_base, struct irq_domain *domain)  { @@ -154,6 +128,10 @@ static int mfd_add_device(struct device *parent, int id,  	if (!pdev)  		goto fail_alloc; +	pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL); +	if (!pdev->mfd_cell) +		goto fail_device; +  	res = kcalloc(cell->num_resources, sizeof(*res), GFP_KERNEL);  	if (!res)  		goto fail_device; @@ -174,6 +152,11 @@ static int mfd_add_device(struct device *parent, int id,  	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)) { +				if (!of_device_is_available(np)) { +					/* Ignore disabled devices error free */ +					ret = 0; +					goto fail_alias; +				}  				pdev->dev.of_node = np;  				pdev->dev.fwnode = &np->fwnode;  				break; @@ -196,10 +179,6 @@ static int mfd_add_device(struct device *parent, int id,  			goto fail_alias;  	} -	ret = mfd_platform_add_cell(pdev, cell, usage_count); -	if (ret) -		goto fail_alias; -  	for (r = 0; r < cell->num_resources; r++) {  		res[r].name = cell->resources[r].name;  		res[r].flags = cell->resources[r].flags; @@ -286,16 +265,9 @@ int mfd_add_devices(struct device *parent, int id,  {  	int i;  	int ret; -	atomic_t *cnts; - -	/* initialize reference counting for all cells */ -	cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL); -	if (!cnts) -		return -ENOMEM;  	for (i = 0; i < n_devs; i++) { -		atomic_set(&cnts[i], 0); -		ret = mfd_add_device(parent, id, cells + i, cnts + i, mem_base, +		ret = mfd_add_device(parent, id, cells + i, mem_base,  				     irq_base, domain);  		if (ret)  			goto fail; @@ -306,17 +278,15 @@ int mfd_add_devices(struct device *parent, int id,  fail:  	if (i)  		mfd_remove_devices(parent); -	else -		kfree(cnts); +  	return ret;  }  EXPORT_SYMBOL(mfd_add_devices); -static int mfd_remove_devices_fn(struct device *dev, void *c) +static int mfd_remove_devices_fn(struct device *dev, void *data)  {  	struct platform_device *pdev;  	const struct mfd_cell *cell; -	atomic_t **usage_count = c;  	if (dev->type != &mfd_dev_type)  		return 0; @@ -327,20 +297,13 @@ static int mfd_remove_devices_fn(struct device *dev, void *c)  	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; -  	platform_device_unregister(pdev);  	return 0;  }  void mfd_remove_devices(struct device *parent)  { -	atomic_t *cnts = NULL; - -	device_for_each_child_reverse(parent, &cnts, mfd_remove_devices_fn); -	kfree(cnts); +	device_for_each_child_reverse(parent, NULL, mfd_remove_devices_fn);  }  EXPORT_SYMBOL(mfd_remove_devices); @@ -382,38 +345,5 @@ int devm_mfd_add_devices(struct device *dev, int id,  }  EXPORT_SYMBOL(devm_mfd_add_devices); -int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) -{ -	struct mfd_cell cell_entry; -	struct device *dev; -	struct platform_device *pdev; -	int i; - -	/* fetch the parent cell's device (should already be registered!) */ -	dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); -	if (!dev) { -		printk(KERN_ERR "failed to find device for cell %s\n", cell); -		return -ENODEV; -	} -	pdev = to_platform_device(dev); -	memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry)); - -	WARN_ON(!cell_entry.enable); - -	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, -				   cell_entry.usage_count, NULL, 0, NULL)) -			dev_err(dev, "failed to create platform device '%s'\n", -					clones[i]); -	} - -	put_device(dev); - -	return 0; -} -EXPORT_SYMBOL(mfd_clone_cell); -  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");  |