summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Fox <pgf@laptop.org>2010-10-29 14:57:28 +0100
committerJohn W. Linville <linville@tuxdriver.com>2010-10-29 14:33:25 -0400
commit731b2034999bbfe86c9074f1b0d611940bf7c323 (patch)
tree6ef7cf2f32e0352242fb06fad132722546eb1980
parent4fc4fbd1d9a05fa4f348b499aca3a6f8d3c9bbe6 (diff)
libertas: Fix sd8686 firmware reload
For the SD8686, we cannot rely on the scratch register to read the firmware load status, because the same register is used for storing RX packet length. Broaden the check to account for this. The module can now be unloaded/reloaded successfully. Based on the implementation from libertas_tf. Signed-off-by: Daniel Drake <dsd@laptop.org> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: Steve deRosier <steve@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 296fd00a512..e5685dc317a 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -684,18 +684,40 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
lbs_deb_enter(LBS_DEB_SDIO);
+ /*
+ * Disable interrupts
+ */
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, 0x00, IF_SDIO_H_INT_MASK, &ret);
+ sdio_release_host(card->func);
+
sdio_claim_host(card->func);
scratch = if_sdio_read_scratch(card, &ret);
sdio_release_host(card->func);
+ lbs_deb_sdio("firmware status = %#x\n", scratch);
+ lbs_deb_sdio("scratch ret = %d\n", ret);
+
if (ret)
goto out;
- lbs_deb_sdio("firmware status = %#x\n", scratch);
+ /*
+ * The manual clearly describes that FEDC is the right code to use
+ * to detect firmware presence, but for SD8686 it is not that simple.
+ * Scratch is also used to store the RX packet length, so we lose
+ * the FEDC value early on. So we use a non-zero check in order
+ * to validate firmware presence.
+ * Additionally, the SD8686 in the Gumstix always has the high scratch
+ * bit set, even when the firmware is not loaded. So we have to
+ * exclude that from the test.
+ */
if (scratch == IF_SDIO_FIRMWARE_OK) {
lbs_deb_sdio("firmware already loaded\n");
goto success;
+ } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) {
+ lbs_deb_sdio("firmware may be running\n");
+ goto success;
}
ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
@@ -709,10 +731,14 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
if (ret)
goto out;
+ lbs_deb_sdio("Helper firmware loaded\n");
+
ret = if_sdio_prog_real(card, mainfw);
if (ret)
goto out;
+ lbs_deb_sdio("Firmware loaded\n");
+
success:
sdio_claim_host(card->func);
sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
@@ -1042,8 +1068,6 @@ static int if_sdio_probe(struct sdio_func *func,
priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
- priv->fw_ready = 1;
-
sdio_claim_host(func);
/*
@@ -1064,6 +1088,8 @@ static int if_sdio_probe(struct sdio_func *func,
if (ret)
goto reclaim;
+ priv->fw_ready = 1;
+
/*
* FUNC_INIT is required for SD8688 WLAN/BT multiple functions
*/