diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 13:43:21 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 13:43:21 -0700 | 
| commit | 06f4e926d256d902dd9a53dcb400fd74974ce087 (patch) | |
| tree | 0b438b67f5f0eff6fd617bc497a9dace6164a488 /drivers/net/wireless/wl12xx/sdio.c | |
| parent | 8e7bfcbab3825d1b404d615cb1b54f44ff81f981 (diff) | |
| parent | d93515611bbc70c2fe4db232e5feb448ed8e4cc9 (diff) | |
| download | olio-linux-3.10-06f4e926d256d902dd9a53dcb400fd74974ce087.tar.xz olio-linux-3.10-06f4e926d256d902dd9a53dcb400fd74974ce087.zip  | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits)
  macvlan: fix panic if lowerdev in a bond
  tg3: Add braces around 5906 workaround.
  tg3: Fix NETIF_F_LOOPBACK error
  macvlan: remove one synchronize_rcu() call
  networking: NET_CLS_ROUTE4 depends on INET
  irda: Fix error propagation in ircomm_lmp_connect_response()
  irda: Kill set but unused variable 'bytes' in irlan_check_command_param()
  irda: Kill set but unused variable 'clen' in ircomm_connect_indication()
  rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport()
  be2net: Kill set but unused variable 'req' in lancer_fw_download()
  irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication()
  atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined.
  rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer().
  rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler()
  rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection()
  rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window()
  pkt_sched: Kill set but unused variable 'protocol' in tc_classify()
  isdn: capi: Use pr_debug() instead of ifdefs.
  tg3: Update version to 3.119
  tg3: Apply rx_discards fix to 5719/5720
  ...
Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c
as per Davem.
Diffstat (limited to 'drivers/net/wireless/wl12xx/sdio.c')
| -rw-r--r-- | drivers/net/wireless/wl12xx/sdio.c | 95 | 
1 files changed, 91 insertions, 4 deletions
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index b1c7d031c39..536e5065454 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -51,6 +51,13 @@ static const struct sdio_device_id wl1271_devices[] = {  };  MODULE_DEVICE_TABLE(sdio, wl1271_devices); +static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz) +{ +	sdio_claim_host(wl->if_priv); +	sdio_set_block_size(wl->if_priv, blksz); +	sdio_release_host(wl->if_priv); +} +  static inline struct sdio_func *wl_to_func(struct wl1271 *wl)  {  	return wl->if_priv; @@ -75,6 +82,16 @@ static irqreturn_t wl1271_hardirq(int irq, void *cookie)  		complete(wl->elp_compl);  		wl->elp_compl = NULL;  	} + +	if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { +		/* don't enqueue a work right now. mark it as pending */ +		set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); +		wl1271_debug(DEBUG_IRQ, "should not enqueue work"); +		disable_irq_nosync(wl->irq); +		pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0); +		spin_unlock_irqrestore(&wl->wl_lock, flags); +		return IRQ_HANDLED; +	}  	spin_unlock_irqrestore(&wl->wl_lock, flags);  	return IRQ_WAKE_THREAD; @@ -203,7 +220,8 @@ static struct wl1271_if_operations sdio_ops = {  	.power		= wl1271_sdio_set_power,  	.dev		= wl1271_sdio_wl_to_dev,  	.enable_irq	= wl1271_sdio_enable_interrupts, -	.disable_irq	= wl1271_sdio_disable_interrupts +	.disable_irq	= wl1271_sdio_disable_interrupts, +	.set_block_size = wl1271_sdio_set_block_size,  };  static int __devinit wl1271_probe(struct sdio_func *func, @@ -212,6 +230,8 @@ static int __devinit wl1271_probe(struct sdio_func *func,  	struct ieee80211_hw *hw;  	const struct wl12xx_platform_data *wlan_data;  	struct wl1271 *wl; +	unsigned long irqflags; +	mmc_pm_flag_t mmcflags;  	int ret;  	/* We are only able to handle the wlan function */ @@ -230,6 +250,9 @@ static int __devinit wl1271_probe(struct sdio_func *func,  	/* Grab access to FN0 for ELP reg. */  	func->card->quirks |= MMC_QUIRK_LENIENT_FN0; +	/* Use block mode for transferring over one block size of data */ +	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; +  	wlan_data = wl12xx_get_platform_data();  	if (IS_ERR(wlan_data)) {  		ret = PTR_ERR(wlan_data); @@ -239,17 +262,34 @@ static int __devinit wl1271_probe(struct sdio_func *func,  	wl->irq = wlan_data->irq;  	wl->ref_clock = wlan_data->board_ref_clock; +	wl->tcxo_clock = wlan_data->board_tcxo_clock; +	wl->platform_quirks = wlan_data->platform_quirks; + +	if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) +		irqflags = IRQF_TRIGGER_RISING; +	else +		irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;  	ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, -				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT, +				   irqflags,  				   DRIVER_NAME, wl);  	if (ret < 0) {  		wl1271_error("request_irq() failed: %d", ret);  		goto out_free;  	} +	enable_irq_wake(wl->irq); +	device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); +  	disable_irq(wl->irq); +	/* if sdio can keep power while host is suspended, enable wow */ +	mmcflags = sdio_get_host_pm_caps(func); +	wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); + +	if (mmcflags & MMC_PM_KEEP_POWER) +		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; +  	ret = wl1271_init_ieee80211(wl);  	if (ret)  		goto out_irq; @@ -284,19 +324,61 @@ static void __devexit wl1271_remove(struct sdio_func *func)  	pm_runtime_get_noresume(&func->dev);  	wl1271_unregister_hw(wl); +	device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0); +	disable_irq_wake(wl->irq);  	free_irq(wl->irq, wl);  	wl1271_free_hw(wl);  } +#ifdef CONFIG_PM  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; +	struct sdio_func *func = dev_to_sdio_func(dev); +	struct wl1271 *wl = sdio_get_drvdata(func); +	mmc_pm_flag_t sdio_flags; +	int ret = 0; + +	wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d", +		     wl->wow_enabled); + +	/* check whether sdio should keep power */ +	if (wl->wow_enabled) { +		sdio_flags = sdio_get_host_pm_caps(func); + +		if (!(sdio_flags & MMC_PM_KEEP_POWER)) { +			wl1271_error("can't keep power while host " +				     "is suspended"); +			ret = -EINVAL; +			goto out; +		} + +		/* keep power while host suspended */ +		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); +		if (ret) { +			wl1271_error("error while trying to keep power"); +			goto out; +		} + +		/* release host */ +		sdio_release_host(func); +	} +out: +	return ret;  }  static int wl1271_resume(struct device *dev)  { +	struct sdio_func *func = dev_to_sdio_func(dev); +	struct wl1271 *wl = sdio_get_drvdata(func); + +	wl1271_debug(DEBUG_MAC80211, "wl1271 resume"); +	if (wl->wow_enabled) { +		/* claim back host */ +		sdio_claim_host(func); +	} +  	return 0;  } @@ -304,15 +386,18 @@ static const struct dev_pm_ops wl1271_sdio_pm_ops = {  	.suspend	= wl1271_suspend,  	.resume		= wl1271_resume,  }; +#endif  static struct sdio_driver wl1271_sdio_driver = {  	.name		= "wl1271_sdio",  	.id_table	= wl1271_devices,  	.probe		= wl1271_probe,  	.remove		= __devexit_p(wl1271_remove), +#ifdef CONFIG_PM  	.drv = {  		.pm = &wl1271_sdio_pm_ops,  	}, +#endif  };  static int __init wl1271_init(void) @@ -343,4 +428,6 @@ MODULE_LICENSE("GPL");  MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");  MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");  MODULE_FIRMWARE(WL1271_FW_NAME); -MODULE_FIRMWARE(WL1271_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME); +MODULE_FIRMWARE(WL127X_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_AP_FW_NAME);  |