diff options
Diffstat (limited to 'drivers/mmc/core/sdio_bus.c')
| -rw-r--r-- | drivers/mmc/core/sdio_bus.c | 111 | 
1 files changed, 53 insertions, 58 deletions
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 2716c7ab6bb..4fa8fef9147 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -13,10 +13,13 @@  #include <linux/device.h>  #include <linux/err.h> +#include <linux/export.h>  #include <linux/slab.h>  #include <linux/pm_runtime.h> +#include <linux/acpi.h>  #include <linux/mmc/card.h> +#include <linux/mmc/host.h>  #include <linux/mmc/sdio_func.h>  #include "sdio_cis.h" @@ -31,7 +34,8 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf)				\  									\  	func = dev_to_sdio_func (dev);					\  	return sprintf (buf, format_string, func->field);		\ -} +}									\ +static DEVICE_ATTR_RO(field)  sdio_config_attr(class, "0x%02x\n");  sdio_config_attr(vendor, "0x%04x\n"); @@ -44,14 +48,16 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,  	return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",  			func->class, func->vendor, func->device);  } - -static struct device_attribute sdio_dev_attrs[] = { -	__ATTR_RO(class), -	__ATTR_RO(vendor), -	__ATTR_RO(device), -	__ATTR_RO(modalias), -	__ATTR_NULL, +static DEVICE_ATTR_RO(modalias); + +static struct attribute *sdio_dev_attrs[] = { +	&dev_attr_class.attr, +	&dev_attr_vendor.attr, +	&dev_attr_device.attr, +	&dev_attr_modalias.attr, +	NULL,  }; +ATTRIBUTE_GROUPS(sdio_dev);  static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,  	const struct sdio_device_id *id) @@ -132,9 +138,11 @@ static int sdio_bus_probe(struct device *dev)  	 * it should call pm_runtime_put_noidle() in its probe routine and  	 * pm_runtime_get_noresume() in its remove routine.  	 */ -	ret = pm_runtime_get_sync(dev); -	if (ret < 0) -		goto out; +	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { +		ret = pm_runtime_get_sync(dev); +		if (ret < 0) +			goto disable_runtimepm; +	}  	/* Set the default block size so the driver is sure it's something  	 * sensible. */ @@ -151,8 +159,8 @@ static int sdio_bus_probe(struct device *dev)  	return 0;  disable_runtimepm: -	pm_runtime_put_noidle(dev); -out: +	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) +		pm_runtime_put_noidle(dev);  	return ret;  } @@ -160,17 +168,16 @@ static int sdio_bus_remove(struct device *dev)  {  	struct sdio_driver *drv = to_sdio_driver(dev->driver);  	struct sdio_func *func = dev_to_sdio_func(dev); -	int ret; +	int ret = 0;  	/* Make sure card is powered before invoking ->remove() */ -	ret = pm_runtime_get_sync(dev); -	if (ret < 0) -		goto out; +	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) +		pm_runtime_get_sync(dev);  	drv->remove(func);  	if (func->irq_handler) { -		printk(KERN_WARNING "WARNING: driver %s did not remove " +		pr_warning("WARNING: driver %s did not remove "  			"its interrupt handler!\n", drv->name);  		sdio_claim_host(func);  		sdio_release_irq(func); @@ -178,65 +185,38 @@ static int sdio_bus_remove(struct device *dev)  	}  	/* First, undo the increment made directly above */ -	pm_runtime_put_noidle(dev); +	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) +		pm_runtime_put_noidle(dev);  	/* Then undo the runtime PM settings in sdio_bus_probe() */ -	pm_runtime_put_noidle(dev); +	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) +		pm_runtime_put_sync(dev); -out:  	return ret;  } -#ifdef CONFIG_PM_RUNTIME - -static int sdio_bus_pm_prepare(struct device *dev) -{ -	/* -	 * Resume an SDIO device which was suspended at run time at this -	 * point, in order to allow standard SDIO suspend/resume paths -	 * to keep working as usual. -	 * -	 * Ultimately, the SDIO driver itself will decide (in its -	 * suspend handler, or lack thereof) whether the card should be -	 * removed or kept, and if kept, at what power state. -	 * -	 * At this point, PM core have increased our use count, so it's -	 * safe to directly resume the device. After system is resumed -	 * again, PM core will drop back its runtime PM use count, and if -	 * needed device will be suspended again. -	 * -	 * The end result is guaranteed to be a power state that is -	 * coherent with the device's runtime PM use count. -	 * -	 * The return value of pm_runtime_resume is deliberately unchecked -	 * since there is little point in failing system suspend if a -	 * device can't be resumed. -	 */ -	pm_runtime_resume(dev); - -	return 0; -} +#ifdef CONFIG_PM  static const struct dev_pm_ops sdio_bus_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)  	SET_RUNTIME_PM_OPS(  		pm_generic_runtime_suspend,  		pm_generic_runtime_resume, -		pm_generic_runtime_idle +		NULL  	) -	.prepare = sdio_bus_pm_prepare,  };  #define SDIO_PM_OPS_PTR	(&sdio_bus_pm_ops) -#else /* !CONFIG_PM_RUNTIME */ +#else /* !CONFIG_PM */  #define SDIO_PM_OPS_PTR	NULL -#endif /* !CONFIG_PM_RUNTIME */ +#endif /* !CONFIG_PM */  static struct bus_type sdio_bus_type = {  	.name		= "sdio", -	.dev_attrs	= sdio_dev_attrs, +	.dev_groups	= sdio_dev_groups,  	.match		= sdio_bus_match,  	.uevent		= sdio_bus_uevent,  	.probe		= sdio_bus_probe, @@ -283,8 +263,7 @@ static void sdio_release_func(struct device *dev)  	sdio_free_func_cis(func); -	if (func->info) -		kfree(func->info); +	kfree(func->info);  	kfree(func);  } @@ -311,6 +290,18 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)  	return func;  } +#ifdef CONFIG_ACPI +static void sdio_acpi_set_handle(struct sdio_func *func) +{ +	struct mmc_host *host = func->card->host; +	u64 addr = (host->slotno << 16) | func->num; + +	acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); +} +#else +static inline void sdio_acpi_set_handle(struct sdio_func *func) {} +#endif +  /*   * Register a new SDIO function with the driver model.   */ @@ -320,9 +311,12 @@ int sdio_add_func(struct sdio_func *func)  	dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); +	sdio_acpi_set_handle(func);  	ret = device_add(&func->dev); -	if (ret == 0) +	if (ret == 0) {  		sdio_func_set_present(func); +		acpi_dev_pm_attach(&func->dev, false); +	}  	return ret;  } @@ -338,6 +332,7 @@ void sdio_remove_func(struct sdio_func *func)  	if (!sdio_func_present(func))  		return; +	acpi_dev_pm_detach(&func->dev, false);  	device_del(&func->dev);  	put_device(&func->dev);  }  | 
