aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/if_sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/libertas/if_sdio.c')
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index e998c123e0c..478d766abf8 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -61,6 +61,7 @@ struct if_sdio_model {
61 int model; 61 int model;
62 const char *helper; 62 const char *helper;
63 const char *firmware; 63 const char *firmware;
64 struct if_sdio_card *card;
64}; 65};
65 66
66static struct if_sdio_model if_sdio_models[] = { 67static struct if_sdio_model if_sdio_models[] = {
@@ -69,18 +70,21 @@ static struct if_sdio_model if_sdio_models[] = {
69 .model = IF_SDIO_MODEL_8385, 70 .model = IF_SDIO_MODEL_8385,
70 .helper = "sd8385_helper.bin", 71 .helper = "sd8385_helper.bin",
71 .firmware = "sd8385.bin", 72 .firmware = "sd8385.bin",
73 .card = NULL,
72 }, 74 },
73 { 75 {
74 /* 8686 */ 76 /* 8686 */
75 .model = IF_SDIO_MODEL_8686, 77 .model = IF_SDIO_MODEL_8686,
76 .helper = "sd8686_helper.bin", 78 .helper = "sd8686_helper.bin",
77 .firmware = "sd8686.bin", 79 .firmware = "sd8686.bin",
80 .card = NULL,
78 }, 81 },
79 { 82 {
80 /* 8688 */ 83 /* 8688 */
81 .model = IF_SDIO_MODEL_8688, 84 .model = IF_SDIO_MODEL_8688,
82 .helper = "sd8688_helper.bin", 85 .helper = "sd8688_helper.bin",
83 .firmware = "sd8688.bin", 86 .firmware = "sd8688.bin",
87 .card = NULL,
84 }, 88 },
85}; 89};
86 90
@@ -539,7 +543,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
539 ret = 0; 543 ret = 0;
540 544
541release: 545release:
542 sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
543 sdio_release_host(card->func); 546 sdio_release_host(card->func);
544 kfree(chunk_buffer); 547 kfree(chunk_buffer);
545release_fw: 548release_fw:
@@ -675,7 +678,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
675 ret = 0; 678 ret = 0;
676 679
677release: 680release:
678 sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
679 sdio_release_host(card->func); 681 sdio_release_host(card->func);
680 kfree(chunk_buffer); 682 kfree(chunk_buffer);
681release_fw: 683release_fw:
@@ -718,6 +720,9 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
718 goto out; 720 goto out;
719 721
720success: 722success:
723 sdio_claim_host(card->func);
724 sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE);
725 sdio_release_host(card->func);
721 ret = 0; 726 ret = 0;
722 727
723out: 728out:
@@ -903,6 +908,8 @@ static int if_sdio_probe(struct sdio_func *func,
903 goto free; 908 goto free;
904 } 909 }
905 910
911 if_sdio_models[i].card = card;
912
906 card->helper = if_sdio_models[i].helper; 913 card->helper = if_sdio_models[i].helper;
907 card->firmware = if_sdio_models[i].firmware; 914 card->firmware = if_sdio_models[i].firmware;
908 915
@@ -985,6 +992,12 @@ static int if_sdio_probe(struct sdio_func *func,
985 if (ret) 992 if (ret)
986 goto reclaim; 993 goto reclaim;
987 994
995 /*
996 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
997 */
998 priv->fn_init_required =
999 (card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
1000
988 ret = lbs_start_card(priv); 1001 ret = lbs_start_card(priv);
989 if (ret) 1002 if (ret)
990 goto err_activate_card; 1003 goto err_activate_card;
@@ -1025,23 +1038,30 @@ static void if_sdio_remove(struct sdio_func *func)
1025{ 1038{
1026 struct if_sdio_card *card; 1039 struct if_sdio_card *card;
1027 struct if_sdio_packet *packet; 1040 struct if_sdio_packet *packet;
1041 int ret;
1028 1042
1029 lbs_deb_enter(LBS_DEB_SDIO); 1043 lbs_deb_enter(LBS_DEB_SDIO);
1030 1044
1031 card = sdio_get_drvdata(func); 1045 card = sdio_get_drvdata(func);
1032 1046
1047 lbs_stop_card(card->priv);
1048
1033 card->priv->surpriseremoved = 1; 1049 card->priv->surpriseremoved = 1;
1034 1050
1035 lbs_deb_sdio("call remove card\n"); 1051 lbs_deb_sdio("call remove card\n");
1036 lbs_stop_card(card->priv);
1037 lbs_remove_card(card->priv); 1052 lbs_remove_card(card->priv);
1038 1053
1039 flush_workqueue(card->workqueue); 1054 flush_workqueue(card->workqueue);
1040 destroy_workqueue(card->workqueue); 1055 destroy_workqueue(card->workqueue);
1041 1056
1042 sdio_claim_host(func); 1057 sdio_claim_host(func);
1058
1059 /* Disable interrupts */
1060 sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret);
1061
1043 sdio_release_irq(func); 1062 sdio_release_irq(func);
1044 sdio_disable_func(func); 1063 sdio_disable_func(func);
1064
1045 sdio_release_host(func); 1065 sdio_release_host(func);
1046 1066
1047 while (card->packets) { 1067 while (card->packets) {
@@ -1084,8 +1104,23 @@ static int __init if_sdio_init_module(void)
1084 1104
1085static void __exit if_sdio_exit_module(void) 1105static void __exit if_sdio_exit_module(void)
1086{ 1106{
1107 int i;
1108 struct if_sdio_card *card;
1109
1087 lbs_deb_enter(LBS_DEB_SDIO); 1110 lbs_deb_enter(LBS_DEB_SDIO);
1088 1111
1112 for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) {
1113 card = if_sdio_models[i].card;
1114
1115 /*
1116 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
1117 * multiple functions
1118 */
1119 if (card && card->priv)
1120 card->priv->fn_shutdown_required =
1121 (card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
1122 }
1123
1089 sdio_unregister_driver(&if_sdio_driver); 1124 sdio_unregister_driver(&if_sdio_driver);
1090 1125
1091 lbs_deb_leave(LBS_DEB_SDIO); 1126 lbs_deb_leave(LBS_DEB_SDIO);