diff mbox

libertas: Fix sd8686 firmware reload

Message ID 20101013191402.7C6ED9D401B@zog.reactivated.net (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Daniel Drake Oct. 13, 2010, 7:14 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 87b6349..d2e5193 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -704,28 +704,54 @@  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 == IF_SDIO_MODEL_8686) && (scratch & 0x7fff)) {
+		lbs_deb_sdio("firmware may be running\n");
+		goto success;
 	}
 
 	ret = if_sdio_prog_helper(card);
 	if (ret)
 		goto out;
 
+	lbs_deb_sdio("Helper firmware loaded\n");
+
 	ret = if_sdio_prog_real(card);
 	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);
@@ -1083,8 +1109,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);
 
 	/*
@@ -1105,6 +1129,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
 	 */