diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 |
| commit | 5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0 (patch) | |
| tree | 7851ef1c93aa1aba7ef327ca4b75fd35e6d10f29 /drivers/net/wireless/wl12xx/wl1271_sdio.c | |
| parent | 02f36038c568111ad4fc433f6fa760ff5e38fab4 (diff) | |
| parent | ec37a48d1d16c30b655ac5280209edf52a6775d4 (diff) | |
| download | talos-op-linux-5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0.tar.gz talos-op-linux-5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0.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: (1699 commits)
bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL.
vlan: Calling vlan_hwaccel_do_receive() is always valid.
tproxy: use the interface primary IP address as a default value for --on-ip
tproxy: added IPv6 support to the socket match
cxgb3: function namespace cleanup
tproxy: added IPv6 support to the TPROXY target
tproxy: added IPv6 socket lookup function to nf_tproxy_core
be2net: Changes to use only priority codes allowed by f/w
tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled
tproxy: added tproxy sockopt interface in the IPV6 layer
tproxy: added udp6_lib_lookup function
tproxy: added const specifiers to udp lookup functions
tproxy: split off ipv6 defragmentation to a separate module
l2tp: small cleanup
nf_nat: restrict ICMP translation for embedded header
can: mcp251x: fix generation of error frames
can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set
can-raw: add msg_flags to distinguish local traffic
9p: client code cleanup
rds: make local functions/variables static
...
Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and
drivers/net/wireless/ath/ath9k/debug.c as per David
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 7059b5cccf0f..784ef3432641 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) |

