Commit f39de992 authored by Vasily Khoruzhick's avatar Vasily Khoruzhick Committed by John W. Linville

libertas_spi: Add support for suspend/resume

Add support for suspend/resume in if_spi.
Signed-off-by: default avatarVasily Khoruzhick <anarsoul@gmail.com>
Acked-by: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5e6e3a92
...@@ -57,6 +57,7 @@ struct if_spi_card { ...@@ -57,6 +57,7 @@ struct if_spi_card {
/* Handles all SPI communication (except for FW load) */ /* Handles all SPI communication (except for FW load) */
struct workqueue_struct *workqueue; struct workqueue_struct *workqueue;
struct work_struct packet_work; struct work_struct packet_work;
struct work_struct resume_work;
u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE];
...@@ -68,6 +69,9 @@ struct if_spi_card { ...@@ -68,6 +69,9 @@ struct if_spi_card {
/* Protects cmd_packet_list and data_packet_list */ /* Protects cmd_packet_list and data_packet_list */
spinlock_t buffer_lock; spinlock_t buffer_lock;
/* True is card suspended */
u8 suspended;
}; };
static void free_if_spi_card(struct if_spi_card *card) static void free_if_spi_card(struct if_spi_card *card)
...@@ -1057,6 +1061,28 @@ static int if_spi_init_card(struct if_spi_card *card) ...@@ -1057,6 +1061,28 @@ static int if_spi_init_card(struct if_spi_card *card)
return err; return err;
} }
static void if_spi_resume_worker(struct work_struct *work)
{
struct if_spi_card *card;
card = container_of(work, struct if_spi_card, resume_work);
if (card->suspended) {
if (card->pdata->setup)
card->pdata->setup(card->spi);
/* Init card ... */
if_spi_init_card(card);
enable_irq(card->spi->irq);
/* And resume it ... */
lbs_resume(card->priv);
card->suspended = 0;
}
}
static int __devinit if_spi_probe(struct spi_device *spi) static int __devinit if_spi_probe(struct spi_device *spi)
{ {
struct if_spi_card *card; struct if_spi_card *card;
...@@ -1107,6 +1133,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) ...@@ -1107,6 +1133,7 @@ static int __devinit if_spi_probe(struct spi_device *spi)
goto free_card; goto free_card;
} }
card->priv = priv; card->priv = priv;
priv->setup_fw_on_resume = 1;
priv->card = card; priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card; priv->hw_host_to_card = if_spi_host_to_card;
priv->enter_deep_sleep = NULL; priv->enter_deep_sleep = NULL;
...@@ -1117,6 +1144,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) ...@@ -1117,6 +1144,7 @@ static int __devinit if_spi_probe(struct spi_device *spi)
/* Initialize interrupt handling stuff. */ /* Initialize interrupt handling stuff. */
card->workqueue = create_workqueue("libertas_spi"); card->workqueue = create_workqueue("libertas_spi");
INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); INIT_WORK(&card->packet_work, if_spi_host_to_card_worker);
INIT_WORK(&card->resume_work, if_spi_resume_worker);
err = request_irq(spi->irq, if_spi_host_interrupt, err = request_irq(spi->irq, if_spi_host_interrupt,
IRQF_TRIGGER_FALLING, "libertas_spi", card); IRQF_TRIGGER_FALLING, "libertas_spi", card);
...@@ -1161,6 +1189,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) ...@@ -1161,6 +1189,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_deb_spi("libertas_spi_remove\n"); lbs_deb_spi("libertas_spi_remove\n");
lbs_deb_enter(LBS_DEB_SPI); lbs_deb_enter(LBS_DEB_SPI);
cancel_work_sync(&card->resume_work);
lbs_stop_card(priv); lbs_stop_card(priv);
lbs_remove_card(priv); /* will call free_netdev */ lbs_remove_card(priv); /* will call free_netdev */
...@@ -1174,6 +1204,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) ...@@ -1174,6 +1204,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
return 0; return 0;
} }
static int if_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct if_spi_card *card = spi_get_drvdata(spi);
if (!card->suspended) {
lbs_suspend(card->priv);
flush_workqueue(card->workqueue);
disable_irq(spi->irq);
if (card->pdata->teardown)
card->pdata->teardown(spi);
card->suspended = 1;
}
return 0;
}
static int if_spi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct if_spi_card *card = spi_get_drvdata(spi);
/* Schedule delayed work */
schedule_work(&card->resume_work);
return 0;
}
static const struct dev_pm_ops if_spi_pm_ops = {
.suspend = if_spi_suspend,
.resume = if_spi_resume,
};
static struct spi_driver libertas_spi_driver = { static struct spi_driver libertas_spi_driver = {
.probe = if_spi_probe, .probe = if_spi_probe,
.remove = __devexit_p(libertas_spi_remove), .remove = __devexit_p(libertas_spi_remove),
...@@ -1181,6 +1245,7 @@ static struct spi_driver libertas_spi_driver = { ...@@ -1181,6 +1245,7 @@ static struct spi_driver libertas_spi_driver = {
.name = "libertas_spi", .name = "libertas_spi",
.bus = &spi_bus_type, .bus = &spi_bus_type,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &if_spi_pm_ops,
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment