aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorVasily Khoruzhick <anarsoul@gmail.com>2011-03-16 10:41:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-03-30 14:15:17 -0400
commitf39de992540cf68cc865498242f963f70f7e97b3 (patch)
treef9ce8bc9c8f71796ea5e1c56e8a46a1d53bdeb0c /drivers/net/wireless/libertas
parent5e6e3a92b9a4c9416b17f468fa5c7fa2233b8b4e (diff)
libertas_spi: Add support for suspend/resume
Add support for suspend/resume in if_spi. Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/if_spi.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index f6c2cd665f49..078ef43d957d 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -57,6 +57,7 @@ struct if_spi_card {
57 /* Handles all SPI communication (except for FW load) */ 57 /* Handles all SPI communication (except for FW load) */
58 struct workqueue_struct *workqueue; 58 struct workqueue_struct *workqueue;
59 struct work_struct packet_work; 59 struct work_struct packet_work;
60 struct work_struct resume_work;
60 61
61 u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; 62 u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE];
62 63
@@ -68,6 +69,9 @@ struct if_spi_card {
68 69
69 /* Protects cmd_packet_list and data_packet_list */ 70 /* Protects cmd_packet_list and data_packet_list */
70 spinlock_t buffer_lock; 71 spinlock_t buffer_lock;
72
73 /* True is card suspended */
74 u8 suspended;
71}; 75};
72 76
73static void free_if_spi_card(struct if_spi_card *card) 77static void free_if_spi_card(struct if_spi_card *card)
@@ -1057,6 +1061,28 @@ out:
1057 return err; 1061 return err;
1058} 1062}
1059 1063
1064static void if_spi_resume_worker(struct work_struct *work)
1065{
1066 struct if_spi_card *card;
1067
1068 card = container_of(work, struct if_spi_card, resume_work);
1069
1070 if (card->suspended) {
1071 if (card->pdata->setup)
1072 card->pdata->setup(card->spi);
1073
1074 /* Init card ... */
1075 if_spi_init_card(card);
1076
1077 enable_irq(card->spi->irq);
1078
1079 /* And resume it ... */
1080 lbs_resume(card->priv);
1081
1082 card->suspended = 0;
1083 }
1084}
1085
1060static int __devinit if_spi_probe(struct spi_device *spi) 1086static int __devinit if_spi_probe(struct spi_device *spi)
1061{ 1087{
1062 struct if_spi_card *card; 1088 struct if_spi_card *card;
@@ -1107,6 +1133,7 @@ static int __devinit if_spi_probe(struct spi_device *spi)
1107 goto free_card; 1133 goto free_card;
1108 } 1134 }
1109 card->priv = priv; 1135 card->priv = priv;
1136 priv->setup_fw_on_resume = 1;
1110 priv->card = card; 1137 priv->card = card;
1111 priv->hw_host_to_card = if_spi_host_to_card; 1138 priv->hw_host_to_card = if_spi_host_to_card;
1112 priv->enter_deep_sleep = NULL; 1139 priv->enter_deep_sleep = NULL;
@@ -1117,6 +1144,7 @@ static int __devinit if_spi_probe(struct spi_device *spi)
1117 /* Initialize interrupt handling stuff. */ 1144 /* Initialize interrupt handling stuff. */
1118 card->workqueue = create_workqueue("libertas_spi"); 1145 card->workqueue = create_workqueue("libertas_spi");
1119 INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); 1146 INIT_WORK(&card->packet_work, if_spi_host_to_card_worker);
1147 INIT_WORK(&card->resume_work, if_spi_resume_worker);
1120 1148
1121 err = request_irq(spi->irq, if_spi_host_interrupt, 1149 err = request_irq(spi->irq, if_spi_host_interrupt,
1122 IRQF_TRIGGER_FALLING, "libertas_spi", card); 1150 IRQF_TRIGGER_FALLING, "libertas_spi", card);
@@ -1161,6 +1189,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
1161 lbs_deb_spi("libertas_spi_remove\n"); 1189 lbs_deb_spi("libertas_spi_remove\n");
1162 lbs_deb_enter(LBS_DEB_SPI); 1190 lbs_deb_enter(LBS_DEB_SPI);
1163 1191
1192 cancel_work_sync(&card->resume_work);
1193
1164 lbs_stop_card(priv); 1194 lbs_stop_card(priv);
1165 lbs_remove_card(priv); /* will call free_netdev */ 1195 lbs_remove_card(priv); /* will call free_netdev */
1166 1196
@@ -1174,6 +1204,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
1174 return 0; 1204 return 0;
1175} 1205}
1176 1206
1207static int if_spi_suspend(struct device *dev)
1208{
1209 struct spi_device *spi = to_spi_device(dev);
1210 struct if_spi_card *card = spi_get_drvdata(spi);
1211
1212 if (!card->suspended) {
1213 lbs_suspend(card->priv);
1214 flush_workqueue(card->workqueue);
1215 disable_irq(spi->irq);
1216
1217 if (card->pdata->teardown)
1218 card->pdata->teardown(spi);
1219 card->suspended = 1;
1220 }
1221
1222 return 0;
1223}
1224
1225static int if_spi_resume(struct device *dev)
1226{
1227 struct spi_device *spi = to_spi_device(dev);
1228 struct if_spi_card *card = spi_get_drvdata(spi);
1229
1230 /* Schedule delayed work */
1231 schedule_work(&card->resume_work);
1232
1233 return 0;
1234}
1235
1236static const struct dev_pm_ops if_spi_pm_ops = {
1237 .suspend = if_spi_suspend,
1238 .resume = if_spi_resume,
1239};
1240
1177static struct spi_driver libertas_spi_driver = { 1241static struct spi_driver libertas_spi_driver = {
1178 .probe = if_spi_probe, 1242 .probe = if_spi_probe,
1179 .remove = __devexit_p(libertas_spi_remove), 1243 .remove = __devexit_p(libertas_spi_remove),
@@ -1181,6 +1245,7 @@ static struct spi_driver libertas_spi_driver = {
1181 .name = "libertas_spi", 1245 .name = "libertas_spi",
1182 .bus = &spi_bus_type, 1246 .bus = &spi_bus_type,
1183 .owner = THIS_MODULE, 1247 .owner = THIS_MODULE,
1248 .pm = &if_spi_pm_ops,
1184 }, 1249 },
1185}; 1250};
1186 1251