Skip to content

Commit

Permalink
libertas: implement if_spi runtime power management
Browse files Browse the repository at this point in the history
The SPI card is now fully powered down when the network
interface is brought down.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
  • Loading branch information
anarsoul committed Jan 5, 2012
1 parent fc856fb commit 66bd025
Showing 1 changed file with 44 additions and 36 deletions.
80 changes: 44 additions & 36 deletions drivers/net/wireless/libertas/if_spi.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1112,21 +1112,39 @@ static void if_spi_resume_worker(struct work_struct *work)
card = container_of(work, struct if_spi_card, resume_work); card = container_of(work, struct if_spi_card, resume_work);


if (card->suspended) { 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); lbs_resume(card->priv);


card->suspended = 0; card->suspended = 0;
} }
} }


static int if_spi_power_save(struct lbs_private *priv)
{
struct if_spi_card *card = priv->card;

flush_workqueue(card->workqueue);
disable_irq(card->spi->irq);
card->pdata->teardown(card->spi);
priv->fw_ready = 0;

return 0;
}

static int if_spi_power_restore(struct lbs_private *priv)
{
struct if_spi_card *card = priv->card;
int ret;

card->pdata->setup(card->spi);
ret = if_spi_init_card(card);
if (ret)
return ret;
enable_irq(card->spi->irq);
priv->fw_ready = 1;

return 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;
Expand All @@ -1141,17 +1159,11 @@ static int __devinit if_spi_probe(struct spi_device *spi)
goto out; goto out;
} }


if (pdata->setup) {
err = pdata->setup(spi);
if (err)
goto out;
}

/* Allocate card structure to represent this specific device */ /* Allocate card structure to represent this specific device */
card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL); card = kzalloc(sizeof(struct if_spi_card), GFP_KERNEL);
if (!card) { if (!card) {
err = -ENOMEM; err = -ENOMEM;
goto teardown; goto out;
} }
spi_set_drvdata(spi, card); spi_set_drvdata(spi, card);
card->pdata = pdata; card->pdata = pdata;
Expand All @@ -1162,13 +1174,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
INIT_LIST_HEAD(&card->data_packet_list); INIT_LIST_HEAD(&card->data_packet_list);
spin_lock_init(&card->buffer_lock); spin_lock_init(&card->buffer_lock);


/* Initialize the SPI Interface Unit */

/* Firmware load */
err = if_spi_init_card(card);
if (err)
goto free_card;

/* /*
* Register our card with libertas. * Register our card with libertas.
* This will call alloc_etherdev. * This will call alloc_etherdev.
Expand All @@ -1179,13 +1184,16 @@ 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;
if (pdata->setup && pdata->teardown) {
priv->power_save = if_spi_power_save;
priv->power_restore = if_spi_power_restore;
}
priv->enter_deep_sleep = NULL; priv->enter_deep_sleep = NULL;
priv->exit_deep_sleep = NULL; priv->exit_deep_sleep = NULL;
priv->reset_deep_sleep_wakeup = NULL; priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1; priv->disable_on_suspend = 1;


/* Initialize interrupt handling stuff. */ /* Initialize interrupt handling stuff. */
card->workqueue = create_workqueue("libertas_spi"); card->workqueue = create_workqueue("libertas_spi");
Expand All @@ -1199,20 +1207,30 @@ static int __devinit if_spi_probe(struct spi_device *spi)
goto terminate_workqueue; goto terminate_workqueue;
} }


/* Disable IRQ, hw is not ready yet */
disable_irq(spi->irq);

err = if_spi_power_restore(priv);
if (err)
goto release_irq;

/* /*
* Start the card. * Start the card.
* This will call register_netdev, and we'll start * This will call register_netdev, and we'll start
* getting interrupts... * getting interrupts...
*/ */
err = lbs_start_card(priv); err = lbs_start_card(priv);
if (err) if (err)
goto release_irq; goto teardown;
if_spi_power_save(priv);


lbs_deb_spi("Finished initializing WLAN module.\n"); lbs_deb_spi("Finished initializing WLAN module.\n");


/* successful exit */ /* successful exit */
goto out; goto out;


teardown:
if_spi_power_save(priv);
release_irq: release_irq:
free_irq(spi->irq, card); free_irq(spi->irq, card);
terminate_workqueue: terminate_workqueue:
Expand All @@ -1221,9 +1239,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
lbs_remove_card(priv); /* will call free_netdev */ lbs_remove_card(priv); /* will call free_netdev */
free_card: free_card:
free_if_spi_card(card); free_if_spi_card(card);
teardown:
if (pdata->teardown)
pdata->teardown(spi);
out: out:
lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
return err; return err;
Expand All @@ -1246,8 +1261,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
cancel_work_sync(&card->packet_work); cancel_work_sync(&card->packet_work);
flush_workqueue(card->workqueue); flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue); destroy_workqueue(card->workqueue);
if (card->pdata->teardown)
card->pdata->teardown(spi);
free_if_spi_card(card); free_if_spi_card(card);
lbs_deb_leave(LBS_DEB_SPI); lbs_deb_leave(LBS_DEB_SPI);
return 0; return 0;
Expand All @@ -1260,11 +1273,6 @@ static int if_spi_suspend(struct device *dev)


if (!card->suspended) { if (!card->suspended) {
lbs_suspend(card->priv); lbs_suspend(card->priv);
flush_workqueue(card->workqueue);
disable_irq(spi->irq);

if (card->pdata->teardown)
card->pdata->teardown(spi);
card->suspended = 1; card->suspended = 1;
} }


Expand Down

0 comments on commit 66bd025

Please sign in to comment.