From 8a64c0f6b7ec7f758c4ef445e49f479e27fa2236 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 6 Apr 2010 10:52:44 +0200 Subject: libertas/sdio: 8686: set ECSI bit for 1-bit transfers When operating in 1-bit mode, SDAT1 is used as dedicated interrupt line. However, the 8686 will only drive this line when the ECSI bit is set in the CCCR_IF register. Thanks to Alagu Sankar for pointing me in the right direction. Signed-off-by: Daniel Mack Cc: Alagu Sankar Cc: Volker Ernst Cc: Dan Williams Cc: John W. Linville Cc: Holger Schurig Cc: Bing Zhao Cc: libertas-dev@lists.infradead.org Cc: linux-wireless@vger.kernel.org Cc: linux-mmc@vger.kernel.org Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/net/wireless/libertas/if_sdio.c') diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 7a73f625273..33206a98a57 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "host.h" #include "decl.h" @@ -942,6 +944,7 @@ static int if_sdio_probe(struct sdio_func *func, int ret, i; unsigned int model; struct if_sdio_packet *packet; + struct mmc_host *host = func->card->host; lbs_deb_enter(LBS_DEB_SDIO); @@ -1022,6 +1025,25 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto disable; + /* For 1-bit transfers to the 8686 model, we need to enable the + * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 + * bit to allow access to non-vendor registers. */ + if ((card->model == IF_SDIO_MODEL_8686) && + (host->caps & MMC_CAP_SDIO_IRQ) && + (host->ios.bus_width == MMC_BUS_WIDTH_1)) { + u8 reg; + + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); + if (ret) + goto release_int; + + reg |= SDIO_BUS_ECSI; + sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); + if (ret) + goto release_int; + } + card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); if (ret) goto release_int; -- cgit v1.2.3-70-g09d2 From 96021f096e5178582af296a2fbb6df7dbd6b695c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 13:27:44 -0700 Subject: libertas: consolidate SDIO firmware wait code Consolidate a bunch of C&P code that waits for the firmware to be ready. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 98 ++++++++++++--------------------- 1 file changed, 35 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless/libertas/if_sdio.c') diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 33206a98a57..60dc9b64381 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -314,12 +314,28 @@ out: return ret; } +static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition) +{ + u8 status; + unsigned long timeout; + int ret = 0; + + timeout = jiffies + HZ; + while (1) { + status = sdio_readb(card->func, IF_SDIO_STATUS, &ret); + if (ret || (status & condition)) + break; + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + mdelay(1); + } + return ret; +} + static int if_sdio_card_to_host(struct if_sdio_card *card) { int ret; - u8 status; u16 size, type, chunk; - unsigned long timeout; lbs_deb_enter(LBS_DEB_SDIO); @@ -334,19 +350,9 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) goto out; } - timeout = jiffies + HZ; - while (1) { - status = sdio_readb(card->func, IF_SDIO_STATUS, &ret); - if (ret) - goto out; - if (status & IF_SDIO_IO_RDY) - break; - if (time_after(jiffies, timeout)) { - ret = -ETIMEDOUT; - goto out; - } - mdelay(1); - } + ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY); + if (ret) + goto out; /* * The transfer must be in one transaction or the firmware @@ -413,8 +419,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) { struct if_sdio_card *card; struct if_sdio_packet *packet; - unsigned long timeout; - u8 status; int ret; unsigned long flags; @@ -434,25 +438,15 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) sdio_claim_host(card->func); - timeout = jiffies + HZ; - while (1) { - status = sdio_readb(card->func, IF_SDIO_STATUS, &ret); - if (ret) - goto release; - if (status & IF_SDIO_IO_RDY) - break; - if (time_after(jiffies, timeout)) { - ret = -ETIMEDOUT; - goto release; - } - mdelay(1); + ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY); + if (ret == 0) { + ret = sdio_writesb(card->func, card->ioport, + packet->buffer, packet->nb); } - ret = sdio_writesb(card->func, card->ioport, - packet->buffer, packet->nb); if (ret) - goto release; -release: + lbs_pr_err("error %d sending packet to firmware\n", ret); + sdio_release_host(card->func); kfree(packet); @@ -465,10 +459,11 @@ release: /* Firmware */ /********************************************************************/ +#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY) + static int if_sdio_prog_helper(struct if_sdio_card *card) { int ret; - u8 status; const struct firmware *fw; unsigned long timeout; u8 *chunk_buffer; @@ -500,20 +495,9 @@ static int if_sdio_prog_helper(struct if_sdio_card *card) size = fw->size; while (size) { - timeout = jiffies + HZ; - while (1) { - status = sdio_readb(card->func, IF_SDIO_STATUS, &ret); - if (ret) - goto release; - if ((status & IF_SDIO_IO_RDY) && - (status & IF_SDIO_DL_RDY)) - break; - if (time_after(jiffies, timeout)) { - ret = -ETIMEDOUT; - goto release; - } - mdelay(1); - } + ret = if_sdio_wait_status(card, FW_DL_READY_STATUS); + if (ret) + goto release; chunk_size = min(size, (size_t)60); @@ -583,7 +567,6 @@ out: static int if_sdio_prog_real(struct if_sdio_card *card) { int ret; - u8 status; const struct firmware *fw; unsigned long timeout; u8 *chunk_buffer; @@ -615,20 +598,9 @@ static int if_sdio_prog_real(struct if_sdio_card *card) size = fw->size; while (size) { - timeout = jiffies + HZ; - while (1) { - status = sdio_readb(card->func, IF_SDIO_STATUS, &ret); - if (ret) - goto release; - if ((status & IF_SDIO_IO_RDY) && - (status & IF_SDIO_DL_RDY)) - break; - if (time_after(jiffies, timeout)) { - ret = -ETIMEDOUT; - goto release; - } - mdelay(1); - } + ret = if_sdio_wait_status(card, FW_DL_READY_STATUS); + if (ret) + goto release; req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret); if (ret) -- cgit v1.2.3-70-g09d2 From ac1a474d71d6cbf94bf26889da5768f5f2b0ca2b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 13:32:58 -0700 Subject: libertas: Davinci platforms need more time loading helper firmware Davinci platforms apparently need more time in-between helper firmware blocks. Even though this is an increased delay, we only take this hit once at initialization time. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/libertas/if_sdio.c') diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 60dc9b64381..68cc407054e 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -499,6 +499,11 @@ static int if_sdio_prog_helper(struct if_sdio_card *card) if (ret) goto release; + /* On some platforms (like Davinci) the chip needs more time + * between helper blocks. + */ + mdelay(2); + chunk_size = min(size, (size_t)60); *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size); -- cgit v1.2.3-70-g09d2 From ca962557c2f2aa14f8032006ce17ebb4ff73db55 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 28 Apr 2010 12:37:46 -0700 Subject: libertas: fix 8686 firmware loading regression The 'ready' condition was incorrectly evaluated which sometimes lead to failures loading the second-stage firmware on 8686 devices. (This was introduced in "libertas: consolidate SDIO firmware wait code". -- JWL) Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/libertas/if_sdio.c') diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 68cc407054e..094176e92eb 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -323,7 +323,9 @@ static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition) timeout = jiffies + HZ; while (1) { status = sdio_readb(card->func, IF_SDIO_STATUS, &ret); - if (ret || (status & condition)) + if (ret) + return ret; + if ((status & condition) == condition) break; if (time_after(jiffies, timeout)) return -ETIMEDOUT; -- cgit v1.2.3-70-g09d2