aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2011-08-01 11:43:27 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-09 15:52:03 -0400
commit7e1f79a1f5fef8ac54def967b22a87909c74c8f1 (patch)
tree4decd3a1a18591d8ffb2d3aea4564aef36efd3e8 /drivers/net/wireless/libertas
parentd2e7b3425c474300318e1d28b10a93c2401b9255 (diff)
libertas: implement if_sdio runtime power management
The SDIO card is now fully powered down when the network interface is brought down. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c277
1 files changed, 171 insertions, 106 deletions
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 387786e1b394..c962e21762dc 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -39,6 +39,7 @@
39#include <linux/mmc/sdio_ids.h> 39#include <linux/mmc/sdio_ids.h>
40#include <linux/mmc/sdio.h> 40#include <linux/mmc/sdio.h>
41#include <linux/mmc/host.h> 41#include <linux/mmc/host.h>
42#include <linux/pm_runtime.h>
42 43
43#include "host.h" 44#include "host.h"
44#include "decl.h" 45#include "decl.h"
@@ -47,6 +48,8 @@
47#include "cmd.h" 48#include "cmd.h"
48#include "if_sdio.h" 49#include "if_sdio.h"
49 50
51static void if_sdio_interrupt(struct sdio_func *func);
52
50/* The if_sdio_remove() callback function is called when 53/* The if_sdio_remove() callback function is called when
51 * user removes this module from kernel space or ejects 54 * user removes this module from kernel space or ejects
52 * the card from the slot. The driver handles these 2 cases 55 * the card from the slot. The driver handles these 2 cases
@@ -757,6 +760,136 @@ out:
757 return ret; 760 return ret;
758} 761}
759 762
763/********************************************************************/
764/* Power management */
765/********************************************************************/
766
767static int if_sdio_power_on(struct if_sdio_card *card)
768{
769 struct sdio_func *func = card->func;
770 struct lbs_private *priv = card->priv;
771 struct mmc_host *host = func->card->host;
772 int ret;
773
774 sdio_claim_host(func);
775
776 ret = sdio_enable_func(func);
777 if (ret)
778 goto release;
779
780 /* For 1-bit transfers to the 8686 model, we need to enable the
781 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
782 * bit to allow access to non-vendor registers. */
783 if ((card->model == MODEL_8686) &&
784 (host->caps & MMC_CAP_SDIO_IRQ) &&
785 (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
786 u8 reg;
787
788 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
789 reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
790 if (ret)
791 goto disable;
792
793 reg |= SDIO_BUS_ECSI;
794 sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
795 if (ret)
796 goto disable;
797 }
798
799 card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
800 if (ret)
801 goto disable;
802
803 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
804 if (ret)
805 goto disable;
806
807 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
808 if (ret)
809 goto disable;
810
811 sdio_release_host(func);
812 ret = if_sdio_prog_firmware(card);
813 sdio_claim_host(func);
814 if (ret)
815 goto disable;
816
817 /*
818 * Get rx_unit if the chip is SD8688 or newer.
819 * SD8385 & SD8686 do not have rx_unit.
820 */
821 if ((card->model != MODEL_8385)
822 && (card->model != MODEL_8686))
823 card->rx_unit = if_sdio_read_rx_unit(card);
824 else
825 card->rx_unit = 0;
826
827 /*
828 * Set up the interrupt handler late.
829 *
830 * If we set it up earlier, the (buggy) hardware generates a spurious
831 * interrupt, even before the interrupt has been enabled, with
832 * CCCR_INTx = 0.
833 *
834 * We register the interrupt handler late so that we can handle any
835 * spurious interrupts, and also to avoid generation of that known
836 * spurious interrupt in the first place.
837 */
838 ret = sdio_claim_irq(func, if_sdio_interrupt);
839 if (ret)
840 goto disable;
841
842 /*
843 * Enable interrupts now that everything is set up
844 */
845 sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
846 if (ret)
847 goto release_irq;
848
849 sdio_release_host(func);
850
851 /*
852 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
853 */
854 if (card->model == MODEL_8688) {
855 struct cmd_header cmd;
856
857 memset(&cmd, 0, sizeof(cmd));
858
859 lbs_deb_sdio("send function INIT command\n");
860 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
861 lbs_cmd_copyback, (unsigned long) &cmd))
862 netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
863 }
864
865 priv->fw_ready = 1;
866
867 return 0;
868
869release_irq:
870 sdio_release_irq(func);
871disable:
872 sdio_disable_func(func);
873release:
874 sdio_release_host(func);
875 return ret;
876}
877
878static int if_sdio_power_off(struct if_sdio_card *card)
879{
880 struct sdio_func *func = card->func;
881 struct lbs_private *priv = card->priv;
882
883 priv->fw_ready = 0;
884
885 sdio_claim_host(func);
886 sdio_release_irq(func);
887 sdio_disable_func(func);
888 sdio_release_host(func);
889 return 0;
890}
891
892
760/*******************************************************************/ 893/*******************************************************************/
761/* Libertas callbacks */ 894/* Libertas callbacks */
762/*******************************************************************/ 895/*******************************************************************/
@@ -923,6 +1056,32 @@ static void if_sdio_reset_card(struct lbs_private *priv)
923 schedule_work(&card_reset_work); 1056 schedule_work(&card_reset_work);
924} 1057}
925 1058
1059static int if_sdio_power_save(struct lbs_private *priv)
1060{
1061 struct if_sdio_card *card = priv->card;
1062 int ret;
1063
1064 flush_workqueue(card->workqueue);
1065
1066 ret = if_sdio_power_off(card);
1067
1068 /* Let runtime PM know the card is powered off */
1069 pm_runtime_put_sync(&card->func->dev);
1070
1071 return ret;
1072}
1073
1074static int if_sdio_power_restore(struct lbs_private *priv)
1075{
1076 struct if_sdio_card *card = priv->card;
1077
1078 /* Make sure the card will not be powered off by runtime PM */
1079 pm_runtime_get_sync(&card->func->dev);
1080
1081 return if_sdio_power_on(card);
1082}
1083
1084
926/*******************************************************************/ 1085/*******************************************************************/
927/* SDIO callbacks */ 1086/* SDIO callbacks */
928/*******************************************************************/ 1087/*******************************************************************/
@@ -976,7 +1135,6 @@ static int if_sdio_probe(struct sdio_func *func,
976 int ret, i; 1135 int ret, i;
977 unsigned int model; 1136 unsigned int model;
978 struct if_sdio_packet *packet; 1137 struct if_sdio_packet *packet;
979 struct mmc_host *host = func->card->host;
980 1138
981 lbs_deb_enter(LBS_DEB_SDIO); 1139 lbs_deb_enter(LBS_DEB_SDIO);
982 1140
@@ -1033,45 +1191,6 @@ static int if_sdio_probe(struct sdio_func *func,
1033 goto free; 1191 goto free;
1034 } 1192 }
1035 1193
1036 sdio_claim_host(func);
1037
1038 ret = sdio_enable_func(func);
1039 if (ret)
1040 goto release;
1041
1042 /* For 1-bit transfers to the 8686 model, we need to enable the
1043 * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
1044 * bit to allow access to non-vendor registers. */
1045 if ((card->model == MODEL_8686) &&
1046 (host->caps & MMC_CAP_SDIO_IRQ) &&
1047 (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
1048 u8 reg;
1049
1050 func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
1051 reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
1052 if (ret)
1053 goto release_int;
1054
1055 reg |= SDIO_BUS_ECSI;
1056 sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
1057 if (ret)
1058 goto release_int;
1059 }
1060
1061 card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
1062 if (ret)
1063 goto release_int;
1064
1065 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
1066 if (ret)
1067 goto release_int;
1068
1069 card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
1070 if (ret)
1071 goto release_int;
1072
1073 sdio_release_host(func);
1074
1075 sdio_set_drvdata(func, card); 1194 sdio_set_drvdata(func, card);
1076 1195
1077 lbs_deb_sdio("class = 0x%X, vendor = 0x%X, " 1196 lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
@@ -1079,14 +1198,11 @@ static int if_sdio_probe(struct sdio_func *func,
1079 func->class, func->vendor, func->device, 1198 func->class, func->vendor, func->device,
1080 model, (unsigned)card->ioport); 1199 model, (unsigned)card->ioport);
1081 1200
1082 ret = if_sdio_prog_firmware(card);
1083 if (ret)
1084 goto reclaim;
1085 1201
1086 priv = lbs_add_card(card, &func->dev); 1202 priv = lbs_add_card(card, &func->dev);
1087 if (!priv) { 1203 if (!priv) {
1088 ret = -ENOMEM; 1204 ret = -ENOMEM;
1089 goto reclaim; 1205 goto free;
1090 } 1206 }
1091 1207
1092 card->priv = priv; 1208 card->priv = priv;
@@ -1097,62 +1213,21 @@ static int if_sdio_probe(struct sdio_func *func,
1097 priv->exit_deep_sleep = if_sdio_exit_deep_sleep; 1213 priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
1098 priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; 1214 priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
1099 priv->reset_card = if_sdio_reset_card; 1215 priv->reset_card = if_sdio_reset_card;
1216 priv->power_save = if_sdio_power_save;
1217 priv->power_restore = if_sdio_power_restore;
1100 1218
1101 sdio_claim_host(func); 1219 ret = if_sdio_power_on(card);
1102
1103 /*
1104 * Get rx_unit if the chip is SD8688 or newer.
1105 * SD8385 & SD8686 do not have rx_unit.
1106 */
1107 if ((card->model != MODEL_8385)
1108 && (card->model != MODEL_8686))
1109 card->rx_unit = if_sdio_read_rx_unit(card);
1110 else
1111 card->rx_unit = 0;
1112
1113 /*
1114 * Set up the interrupt handler late.
1115 *
1116 * If we set it up earlier, the (buggy) hardware generates a spurious
1117 * interrupt, even before the interrupt has been enabled, with
1118 * CCCR_INTx = 0.
1119 *
1120 * We register the interrupt handler late so that we can handle any
1121 * spurious interrupts, and also to avoid generation of that known
1122 * spurious interrupt in the first place.
1123 */
1124 ret = sdio_claim_irq(func, if_sdio_interrupt);
1125 if (ret)
1126 goto disable;
1127
1128 /*
1129 * Enable interrupts now that everything is set up
1130 */
1131 sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
1132 sdio_release_host(func);
1133 if (ret) 1220 if (ret)
1134 goto reclaim; 1221 goto err_activate_card;
1135
1136 priv->fw_ready = 1;
1137
1138 /*
1139 * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
1140 */
1141 if (card->model == MODEL_8688) {
1142 struct cmd_header cmd;
1143
1144 memset(&cmd, 0, sizeof(cmd));
1145
1146 lbs_deb_sdio("send function INIT command\n");
1147 if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
1148 lbs_cmd_copyback, (unsigned long) &cmd))
1149 netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
1150 }
1151 1222
1152 ret = lbs_start_card(priv); 1223 ret = lbs_start_card(priv);
1224 if_sdio_power_off(card);
1153 if (ret) 1225 if (ret)
1154 goto err_activate_card; 1226 goto err_activate_card;
1155 1227
1228 /* Tell PM core that we don't need the card to be powered now */
1229 pm_runtime_put_noidle(&func->dev);
1230
1156out: 1231out:
1157 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); 1232 lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
1158 1233
@@ -1161,14 +1236,6 @@ out:
1161err_activate_card: 1236err_activate_card:
1162 flush_workqueue(card->workqueue); 1237 flush_workqueue(card->workqueue);
1163 lbs_remove_card(priv); 1238 lbs_remove_card(priv);
1164reclaim:
1165 sdio_claim_host(func);
1166release_int:
1167 sdio_release_irq(func);
1168disable:
1169 sdio_disable_func(func);
1170release:
1171 sdio_release_host(func);
1172free: 1239free:
1173 destroy_workqueue(card->workqueue); 1240 destroy_workqueue(card->workqueue);
1174 while (card->packets) { 1241 while (card->packets) {
@@ -1195,6 +1262,9 @@ static void if_sdio_remove(struct sdio_func *func)
1195 1262
1196 card = sdio_get_drvdata(func); 1263 card = sdio_get_drvdata(func);
1197 1264
1265 /* Undo decrement done above in if_sdio_probe */
1266 pm_runtime_get_noresume(&func->dev);
1267
1198 if (user_rmmod && (card->model == MODEL_8688)) { 1268 if (user_rmmod && (card->model == MODEL_8688)) {
1199 /* 1269 /*
1200 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT 1270 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
@@ -1219,11 +1289,6 @@ static void if_sdio_remove(struct sdio_func *func)
1219 flush_workqueue(card->workqueue); 1289 flush_workqueue(card->workqueue);
1220 destroy_workqueue(card->workqueue); 1290 destroy_workqueue(card->workqueue);
1221 1291
1222 sdio_claim_host(func);
1223 sdio_release_irq(func);
1224 sdio_disable_func(func);
1225 sdio_release_host(func);
1226
1227 while (card->packets) { 1292 while (card->packets) {
1228 packet = card->packets; 1293 packet = card->packets;
1229 card->packets = card->packets->next; 1294 card->packets = card->packets->next;