diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_sdio.c')
| -rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_sdio.c | 98 | 
1 files changed, 77 insertions, 21 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index 7059b5cccf0..784ef343264 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c @@ -29,14 +29,13 @@  #include <linux/mmc/sdio_ids.h>  #include <linux/mmc/card.h>  #include <linux/gpio.h> +#include <linux/wl12xx.h> +#include <linux/pm_runtime.h>  #include "wl1271.h"  #include "wl12xx_80211.h"  #include "wl1271_io.h" - -#define RX71_WL1271_IRQ_GPIO		42 -  #ifndef SDIO_VENDOR_ID_TI  #define SDIO_VENDOR_ID_TI		0x0097  #endif @@ -107,6 +106,8 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,  	int ret;  	struct sdio_func *func = wl_to_func(wl); +	sdio_claim_host(func); +  	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {  		((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);  		wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", @@ -122,9 +123,10 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,  		wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);  	} +	sdio_release_host(func); +  	if (ret)  		wl1271_error("sdio read failed (%d)", ret); -  }  static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, @@ -133,6 +135,8 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,  	int ret;  	struct sdio_func *func = wl_to_func(wl); +	sdio_claim_host(func); +  	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {  		sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);  		wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", @@ -147,26 +151,49 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,  		else  			ret = sdio_memcpy_toio(func, addr, buf, len);  	} + +	sdio_release_host(func); +  	if (ret)  		wl1271_error("sdio write failed (%d)", ret); +} +static int wl1271_sdio_power_on(struct wl1271 *wl) +{ +	struct sdio_func *func = wl_to_func(wl); +	int ret; + +	/* Power up the card */ +	ret = pm_runtime_get_sync(&func->dev); +	if (ret < 0) +		goto out; + +	sdio_claim_host(func); +	sdio_enable_func(func); +	sdio_release_host(func); + +out: +	return ret;  } -static void wl1271_sdio_set_power(struct wl1271 *wl, bool enable) +static int wl1271_sdio_power_off(struct wl1271 *wl)  {  	struct sdio_func *func = wl_to_func(wl); -	/* Let the SDIO stack handle wlan_enable control, so we -	 * keep host claimed while wlan is in use to keep wl1271 -	 * alive. -	 */ -	if (enable) { -		sdio_claim_host(func); -		sdio_enable_func(func); -	} else { -		sdio_disable_func(func); -		sdio_release_host(func); -	} +	sdio_claim_host(func); +	sdio_disable_func(func); +	sdio_release_host(func); + +	/* Power down the card */ +	return pm_runtime_put_sync(&func->dev); +} + +static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) +{ +	if (enable) +		return wl1271_sdio_power_on(wl); +	else +		return wl1271_sdio_power_off(wl);  }  static struct wl1271_if_operations sdio_ops = { @@ -184,6 +211,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,  				  const struct sdio_device_id *id)  {  	struct ieee80211_hw *hw; +	const struct wl12xx_platform_data *wlan_data;  	struct wl1271 *wl;  	int ret; @@ -203,13 +231,16 @@ static int __devinit wl1271_probe(struct sdio_func *func,  	/* Grab access to FN0 for ELP reg. */  	func->card->quirks |= MMC_QUIRK_LENIENT_FN0; -	wl->irq = gpio_to_irq(RX71_WL1271_IRQ_GPIO); -	if (wl->irq < 0) { -		ret = wl->irq; -		wl1271_error("could not get irq!"); +	wlan_data = wl12xx_get_platform_data(); +	if (IS_ERR(wlan_data)) { +		ret = PTR_ERR(wlan_data); +		wl1271_error("missing wlan platform data: %d", ret);  		goto out_free;  	} +	wl->irq = wlan_data->irq; +	wl->ref_clock = wlan_data->board_ref_clock; +  	ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);  	if (ret < 0) {  		wl1271_error("request_irq() failed: %d", ret); @@ -230,6 +261,9 @@ static int __devinit wl1271_probe(struct sdio_func *func,  	sdio_set_drvdata(func, wl); +	/* Tell PM core that we don't need the card to be powered now */ +	pm_runtime_put_noidle(&func->dev); +  	wl1271_notice("initialized");  	return 0; @@ -248,17 +282,39 @@ static void __devexit wl1271_remove(struct sdio_func *func)  {  	struct wl1271 *wl = sdio_get_drvdata(func); -	free_irq(wl->irq, wl); +	/* Undo decrement done above in wl1271_probe */ +	pm_runtime_get_noresume(&func->dev);  	wl1271_unregister_hw(wl); +	free_irq(wl->irq, wl);  	wl1271_free_hw(wl);  } +static int wl1271_suspend(struct device *dev) +{ +	/* Tell MMC/SDIO core it's OK to power down the card +	 * (if it isn't already), but not to remove it completely */ +	return 0; +} + +static int wl1271_resume(struct device *dev) +{ +	return 0; +} + +static const struct dev_pm_ops wl1271_sdio_pm_ops = { +	.suspend	= wl1271_suspend, +	.resume		= wl1271_resume, +}; +  static struct sdio_driver wl1271_sdio_driver = {  	.name		= "wl1271_sdio",  	.id_table	= wl1271_devices,  	.probe		= wl1271_probe,  	.remove		= __devexit_p(wl1271_remove), +	.drv = { +		.pm = &wl1271_sdio_pm_ops, +	},  };  static int __init wl1271_init(void)  |