|
@@ -61,6 +61,7 @@ struct if_sdio_model {
|
|
|
int model;
|
|
|
const char *helper;
|
|
|
const char *firmware;
|
|
|
+ struct if_sdio_card *card;
|
|
|
};
|
|
|
|
|
|
static struct if_sdio_model if_sdio_models[] = {
|
|
@@ -69,18 +70,21 @@ static struct if_sdio_model if_sdio_models[] = {
|
|
|
.model = IF_SDIO_MODEL_8385,
|
|
|
.helper = "sd8385_helper.bin",
|
|
|
.firmware = "sd8385.bin",
|
|
|
+ .card = NULL,
|
|
|
},
|
|
|
{
|
|
|
/* 8686 */
|
|
|
.model = IF_SDIO_MODEL_8686,
|
|
|
.helper = "sd8686_helper.bin",
|
|
|
.firmware = "sd8686.bin",
|
|
|
+ .card = NULL,
|
|
|
},
|
|
|
{
|
|
|
/* 8688 */
|
|
|
.model = IF_SDIO_MODEL_8688,
|
|
|
.helper = "sd8688_helper.bin",
|
|
|
.firmware = "sd8688.bin",
|
|
|
+ .card = NULL,
|
|
|
},
|
|
|
};
|
|
|
|
|
@@ -539,7 +543,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
|
|
|
ret = 0;
|
|
|
|
|
|
release:
|
|
|
- sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
|
|
|
sdio_release_host(card->func);
|
|
|
kfree(chunk_buffer);
|
|
|
release_fw:
|
|
@@ -675,7 +678,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
|
|
|
ret = 0;
|
|
|
|
|
|
release:
|
|
|
- sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
|
|
|
sdio_release_host(card->func);
|
|
|
kfree(chunk_buffer);
|
|
|
release_fw:
|
|
@@ -718,6 +720,9 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
|
|
|
goto out;
|
|
|
|
|
|
success:
|
|
|
+ sdio_claim_host(card->func);
|
|
|
+ sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
|
|
|
+ sdio_release_host(card->func);
|
|
|
ret = 0;
|
|
|
|
|
|
out:
|
|
@@ -903,6 +908,8 @@ static int if_sdio_probe(struct sdio_func *func,
|
|
|
goto free;
|
|
|
}
|
|
|
|
|
|
+ if_sdio_models[i].card = card;
|
|
|
+
|
|
|
card->helper = if_sdio_models[i].helper;
|
|
|
card->firmware = if_sdio_models[i].firmware;
|
|
|
|
|
@@ -985,6 +992,12 @@ static int if_sdio_probe(struct sdio_func *func,
|
|
|
if (ret)
|
|
|
goto reclaim;
|
|
|
|
|
|
+ /*
|
|
|
+ * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
|
|
|
+ */
|
|
|
+ priv->fn_init_required =
|
|
|
+ (card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
|
|
|
+
|
|
|
ret = lbs_start_card(priv);
|
|
|
if (ret)
|
|
|
goto err_activate_card;
|
|
@@ -1025,23 +1038,30 @@ static void if_sdio_remove(struct sdio_func *func)
|
|
|
{
|
|
|
struct if_sdio_card *card;
|
|
|
struct if_sdio_packet *packet;
|
|
|
+ int ret;
|
|
|
|
|
|
lbs_deb_enter(LBS_DEB_SDIO);
|
|
|
|
|
|
card = sdio_get_drvdata(func);
|
|
|
|
|
|
+ lbs_stop_card(card->priv);
|
|
|
+
|
|
|
card->priv->surpriseremoved = 1;
|
|
|
|
|
|
lbs_deb_sdio("call remove card\n");
|
|
|
- lbs_stop_card(card->priv);
|
|
|
lbs_remove_card(card->priv);
|
|
|
|
|
|
flush_workqueue(card->workqueue);
|
|
|
destroy_workqueue(card->workqueue);
|
|
|
|
|
|
sdio_claim_host(func);
|
|
|
+
|
|
|
+ /* Disable interrupts */
|
|
|
+ sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret);
|
|
|
+
|
|
|
sdio_release_irq(func);
|
|
|
sdio_disable_func(func);
|
|
|
+
|
|
|
sdio_release_host(func);
|
|
|
|
|
|
while (card->packets) {
|
|
@@ -1084,8 +1104,23 @@ static int __init if_sdio_init_module(void)
|
|
|
|
|
|
static void __exit if_sdio_exit_module(void)
|
|
|
{
|
|
|
+ int i;
|
|
|
+ struct if_sdio_card *card;
|
|
|
+
|
|
|
lbs_deb_enter(LBS_DEB_SDIO);
|
|
|
|
|
|
+ for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) {
|
|
|
+ card = if_sdio_models[i].card;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
|
|
|
+ * multiple functions
|
|
|
+ */
|
|
|
+ if (card && card->priv)
|
|
|
+ card->priv->fn_shutdown_required =
|
|
|
+ (card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
|
|
|
+ }
|
|
|
+
|
|
|
sdio_unregister_driver(&if_sdio_driver);
|
|
|
|
|
|
lbs_deb_leave(LBS_DEB_SDIO);
|