aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBing Zhao <bzhao@marvell.com>2009-05-19 22:48:20 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-22 14:06:01 -0400
commitd26285f873c3066fefe648b47b9ecf3ec18bcfbc (patch)
treec98fd544dcf32c71ff13bbb8cdf0e80602b460b7
parentb136a1414c94b4bda1057b4ffde26253d2527628 (diff)
libertas: implement function init/shutdown commands for SD8688
SD8688 is a WLAN/Bluetooth combo chip and both functions are supported in a single firmware image. FUNC_INIT and FUNC_SHUTDOWN commands are implemented to utilize the multiple function feature. When SD8688 card is inserted, the firmware image should be downloaded only once through either WLAN function (Libertas driver) or Bluetooth function (Bluetooth driver). This patch adds function init/shutdown for SD8688 WLAN function only. Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/libertas/dev.h2
-rw-r--r--drivers/net/wireless/libertas/host.h2
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c41
-rw-r--r--drivers/net/wireless/libertas/main.c20
4 files changed, 62 insertions, 3 deletions
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index cbaafa653b6a..a4455ec7c354 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -321,6 +321,8 @@ struct lbs_private {
321 321
322 u32 monitormode; 322 u32 monitormode;
323 u8 fw_ready; 323 u8 fw_ready;
324 u8 fn_init_required;
325 u8 fn_shutdown_required;
324}; 326};
325 327
326extern struct cmd_confirm_sleep confirm_sleep; 328extern struct cmd_confirm_sleep confirm_sleep;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 8ff8ac9d817e..fe8f0cb737bc 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -86,6 +86,8 @@
86#define CMD_MESH_CONFIG_OLD 0x00a3 86#define CMD_MESH_CONFIG_OLD 0x00a3
87#define CMD_MESH_CONFIG 0x00ac 87#define CMD_MESH_CONFIG 0x00ac
88#define CMD_SET_BOOT2_VER 0x00a5 88#define CMD_SET_BOOT2_VER 0x00a5
89#define CMD_FUNC_INIT 0x00a9
90#define CMD_FUNC_SHUTDOWN 0x00aa
89#define CMD_802_11_BEACON_CTRL 0x00b0 91#define CMD_802_11_BEACON_CTRL 0x00b0
90 92
91/* For the IEEE Power Save */ 93/* For the IEEE Power Save */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index e998c123e0c5..478d766abf8c 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);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 89575e448015..a58a12352672 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1002,9 +1002,17 @@ static int lbs_setup_firmware(struct lbs_private *priv)
1002{ 1002{
1003 int ret = -1; 1003 int ret = -1;
1004 s16 curlevel = 0, minlevel = 0, maxlevel = 0; 1004 s16 curlevel = 0, minlevel = 0, maxlevel = 0;
1005 struct cmd_header cmd;
1005 1006
1006 lbs_deb_enter(LBS_DEB_FW); 1007 lbs_deb_enter(LBS_DEB_FW);
1007 1008
1009 if (priv->fn_init_required) {
1010 memset(&cmd, 0, sizeof(cmd));
1011 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
1012 lbs_cmd_copyback, (unsigned long) &cmd))
1013 lbs_pr_alert("CMD_FUNC_INIT command failed\n");
1014 }
1015
1008 /* Read MAC address from firmware */ 1016 /* Read MAC address from firmware */
1009 memset(priv->current_addr, 0xff, ETH_ALEN); 1017 memset(priv->current_addr, 0xff, ETH_ALEN);
1010 ret = lbs_update_hw_spec(priv); 1018 ret = lbs_update_hw_spec(priv);
@@ -1192,6 +1200,9 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
1192 priv->mesh_open = 0; 1200 priv->mesh_open = 0;
1193 priv->infra_open = 0; 1201 priv->infra_open = 0;
1194 1202
1203 priv->fn_init_required = 0;
1204 priv->fn_shutdown_required = 0;
1205
1195 /* Setup the OS Interface to our functions */ 1206 /* Setup the OS Interface to our functions */
1196 dev->netdev_ops = &lbs_netdev_ops; 1207 dev->netdev_ops = &lbs_netdev_ops;
1197 dev->watchdog_timeo = 5 * HZ; 1208 dev->watchdog_timeo = 5 * HZ;
@@ -1373,11 +1384,20 @@ void lbs_stop_card(struct lbs_private *priv)
1373 struct net_device *dev; 1384 struct net_device *dev;
1374 struct cmd_ctrl_node *cmdnode; 1385 struct cmd_ctrl_node *cmdnode;
1375 unsigned long flags; 1386 unsigned long flags;
1387 struct cmd_header cmd;
1376 1388
1377 lbs_deb_enter(LBS_DEB_MAIN); 1389 lbs_deb_enter(LBS_DEB_MAIN);
1378 1390
1379 if (!priv) 1391 if (!priv)
1380 goto out; 1392 goto out;
1393
1394 if (priv->fn_shutdown_required) {
1395 memset(&cmd, 0, sizeof(cmd));
1396 if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd),
1397 lbs_cmd_copyback, (unsigned long) &cmd))
1398 lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n");
1399 }
1400
1381 dev = priv->dev; 1401 dev = priv->dev;
1382 1402
1383 netif_stop_queue(dev); 1403 netif_stop_queue(dev);