I haven't been following this thread so forgive me if this is stale info, but the last time I looked at the dw_spi driver it looked to me that it was not releasing the slave DMA channels when going to D0i3. That will prevent the DMA driver from achieving D0i3 - we had to fix this for the intel_mid_spi_ssp driver - may want to check this one for that issue as well.
>-----Original Message----- >From: [email protected] [mailto:meego-kernel- >[email protected]] On Behalf Of Feng Tang >Sent: Wednesday, March 16, 2011 11:33 PM >To: Kristen Carlson Accardi >Cc: [email protected] >Subject: Re: [Meego-kernel] [PATCH 2/2] dw_spi: add runtime pm support > >Hi Kristen, > >For the logical part about where should we add runtime_put/get hook, >could you try the following patch? > >diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c >index 497ecb3..0c82e49 100644 >--- a/drivers/spi/dw_spi.c >+++ b/drivers/spi/dw_spi.c >@@ -320,6 +320,8 @@ static void giveback(struct dw_spi *dws) > queue_work(dws->workqueue, &dws->pump_messages); > spin_unlock_irqrestore(&dws->lock, flags); > >+ pm_runtime_put(dws->parent_dev); >+ > last_transfer = list_entry(msg->transfers.prev, > struct spi_transfer, > transfer_list); >@@ -670,6 +672,11 @@ static int dw_spi_transfer(struct spi_device *spi, >struct spi_message *msg) > return -ESHUTDOWN; > } > >+ spin_unlock_irqrestore(&dws->lock, flags); >+ /* make sure the HW is up */ >+ pm_runtime_get_sync(dws->parent_dev); >+ spin_lock_irqsave(&dws->lock, flags); >+ > msg->actual_length = 0; > msg->status = -EINPROGRESS; > msg->state = START_STATE; > >use pm_runtime_get_sync will make sure the driver/HW is up >and ready for the spi_message. > >Thanks, >Feng > > >On Thu, 17 Mar 2011 06:54:02 +0800 >Kristen Carlson Accardi <[email protected]> wrote: > >> >> Signed-off-by: Kristen Carlson Accardi <[email protected]> >> --- >> drivers/spi/dw_spi.c | 8 +++++++ >> drivers/spi/dw_spi_mid.c | 4 +++ >> drivers/spi/dw_spi_pci.c | 53 >> ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 >> insertions(+), 0 deletions(-) >> >> diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c >> index 497ecb3..21f9d1d 100644 >> --- a/drivers/spi/dw_spi.c >> +++ b/drivers/spi/dw_spi.c >> @@ -22,6 +22,7 @@ >> #include <linux/highmem.h> >> #include <linux/delay.h> >> #include <linux/slab.h> >> +#include <linux/pm_runtime.h> >> >> #include <linux/spi/dw_spi.h> >> #include <linux/spi/spi.h> >> @@ -630,6 +631,7 @@ static void pump_messages(struct work_struct >> *work) if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) { >> dws->busy = 0; >> spin_unlock_irqrestore(&dws->lock, flags); >> + pm_runtime_put(dws->parent_dev); >> return; >> } >> >> @@ -655,6 +657,7 @@ static void pump_messages(struct work_struct >> *work) >> dws->busy = 1; >> spin_unlock_irqrestore(&dws->lock, flags); >> + pm_runtime_get(dws->parent_dev); >> } >> >> /* spi_device use this to queue in their spi_msg */ >> @@ -663,10 +666,13 @@ static int dw_spi_transfer(struct spi_device >> *spi, struct spi_message *msg) struct dw_spi *dws = >> spi_master_get_devdata(spi->master); unsigned long flags; >> >> + pm_runtime_get(dws->parent_dev); >> + >> spin_lock_irqsave(&dws->lock, flags); >> >> if (dws->run == QUEUE_STOPPED) { >> spin_unlock_irqrestore(&dws->lock, flags); >> + pm_runtime_put(dws->parent_dev); >> return -ESHUTDOWN; >> } >> >> @@ -685,11 +691,13 @@ static int dw_spi_transfer(struct spi_device >> *spi, struct spi_message *msg) /* If no other data transaction in >> air, just go */ spin_unlock_irqrestore(&dws->lock, flags); >> pump_messages(&dws->pump_messages); >> + pm_runtime_put(dws->parent_dev); >> return 0; >> } >> } >> >> spin_unlock_irqrestore(&dws->lock, flags); >> + pm_runtime_put(dws->parent_dev); >> return 0; >> } >> >> diff --git a/drivers/spi/dw_spi_mid.c b/drivers/spi/dw_spi_mid.c >> index e47a6af..c885b7a 100644 >> --- a/drivers/spi/dw_spi_mid.c >> +++ b/drivers/spi/dw_spi_mid.c >> @@ -23,6 +23,7 @@ >> #include <linux/slab.h> >> #include <linux/spi/spi.h> >> #include <linux/spi/dw_spi.h> >> +#include <linux/pm_runtime.h> >> >> #ifdef CONFIG_SPI_DW_MID_DMA >> #include <linux/intel_mid_dma.h> >> @@ -106,6 +107,7 @@ static void dw_spi_dma_done(void *arg) >> if (++dws->dma_chan_done != 2) >> return; >> dw_spi_xfer_done(dws); >> + pm_runtime_put(dws->parent_dev); >> } >> >> static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) >> @@ -115,6 +117,8 @@ static int mid_spi_dma_transfer(struct dw_spi >> *dws, int cs_change) struct dma_slave_config txconf, rxconf; >> u16 dma_ctrl = 0; >> >> + pm_runtime_get(dws->parent_dev); >> + >> /* 1. setup DMA related registers */ >> if (cs_change) { >> spi_enable_chip(dws, 0); >> diff --git a/drivers/spi/dw_spi_pci.c b/drivers/spi/dw_spi_pci.c >> index 076d1f8..ab39bbd 100644 >> --- a/drivers/spi/dw_spi_pci.c >> +++ b/drivers/spi/dw_spi_pci.c >> @@ -20,6 +20,7 @@ >> #include <linux/interrupt.h> >> #include <linux/pci.h> >> #include <linux/slab.h> >> +#include <linux/pm_runtime.h> >> #include <linux/spi/dw_spi.h> >> #include <linux/spi/spi.h> >> >> @@ -86,6 +87,10 @@ static int __devinit spi_pci_probe(struct pci_dev >> *pdev, >> /* PCI hook and SPI hook use the same drv data */ >> pci_set_drvdata(pdev, dwpci); >> + >> + pm_runtime_put_noidle(&pdev->dev); >> + pm_runtime_allow(&pdev->dev); >> + >> return 0; >> >> err_unmap: >> @@ -104,6 +109,10 @@ static void __devexit spi_pci_remove(struct >> pci_dev *pdev) struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); >> >> pci_set_drvdata(pdev, NULL); >> + >> + pm_runtime_forbid(&pdev->dev); >> + pm_runtime_get_noresume(&pdev->dev); >> + >> dw_spi_remove_host(&dwpci->dws); >> iounmap(dwpci->dws.regs); >> pci_release_region(pdev, 0); >> @@ -138,9 +147,45 @@ static int spi_resume(struct pci_dev *pdev) >> return ret; >> return dw_spi_resume_host(&dwpci->dws); >> } >> + >> +static int spi_dw_pci_runtime_suspend(struct device *dev) >> +{ >> + struct pci_dev *pdev = to_pci_dev(dev); >> + struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); >> + >> + dev_dbg(dev, "PCI runtime suspend called\n"); >> + >> + return dw_spi_suspend_host(&dwpci->dws); >> +} >> + >> +static int spi_dw_pci_runtime_resume(struct device *dev) >> +{ >> + struct pci_dev *pdev = to_pci_dev(dev); >> + struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); >> + >> + dev_dbg(dev, "pci_runtime_resume called\n"); >> + >> + return dw_spi_resume_host(&dwpci->dws); >> +} >> + >> +static int spi_dw_pci_runtime_idle(struct device *dev) >> +{ >> + int err; >> + >> + dev_dbg(dev, "pci_runtime_idle called\n"); >> + >> + err = pm_schedule_suspend(dev, 500); >> + if (err != 0) >> + return 0; >> + return -EBUSY; >> +} >> + >> #else >> #define spi_suspend NULL >> #define spi_resume NULL >> +#define spi_dw_pci_runtime_suspend NULL >> +#define spi_dw_pci_runtime_resume NULL >> +#define spi_dw_pci_runtime_idle NULL >> #endif >> >> static const struct pci_device_id pci_ids[] __devinitdata = { >> @@ -148,6 +193,11 @@ static const struct pci_device_id pci_ids[] >> __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, >> {}, >> }; >> +static const struct dev_pm_ops dw_spi_pm_ops = { >> + .runtime_suspend = spi_dw_pci_runtime_suspend, >> + .runtime_resume = spi_dw_pci_runtime_resume, >> + .runtime_idle = spi_dw_pci_runtime_idle, >> +}; >> >> static struct pci_driver dw_spi_driver = { >> .name = DRIVER_NAME, >> @@ -156,6 +206,9 @@ static struct pci_driver dw_spi_driver = { >> .remove = __devexit_p(spi_pci_remove), >> .suspend = spi_suspend, >> .resume = spi_resume, >> + .driver = { >> + .pm = &dw_spi_pm_ops, >> + }, >> }; >> >> static int __init mrst_spi_init(void) >_______________________________________________ >MeeGo-kernel mailing list >[email protected] >http://lists.meego.com/listinfo/meego-kernel _______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
