diff options
author | Vasily Khoruzhick <anarsoul@gmail.com> | 2011-03-16 10:41:46 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-03-30 14:15:17 -0400 |
commit | f39de992540cf68cc865498242f963f70f7e97b3 (patch) | |
tree | f9ce8bc9c8f71796ea5e1c56e8a46a1d53bdeb0c /drivers/net/wireless/libertas | |
parent | 5e6e3a92b9a4c9416b17f468fa5c7fa2233b8b4e (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.c | 65 |
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 | ||
73 | static void free_if_spi_card(struct if_spi_card *card) | 77 | static 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 | ||
1064 | static 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 | |||
1060 | static int __devinit if_spi_probe(struct spi_device *spi) | 1086 | static 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 | ||
1207 | static 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 | |||
1225 | static 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 | |||
1236 | static const struct dev_pm_ops if_spi_pm_ops = { | ||
1237 | .suspend = if_spi_suspend, | ||
1238 | .resume = if_spi_resume, | ||
1239 | }; | ||
1240 | |||
1177 | static struct spi_driver libertas_spi_driver = { | 1241 | static 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 | ||