Commit 7e0a6fd5 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'amba' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-2.6-arm

* 'amba' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-2.6-arm:
  ARM: 7079/1: spi: Fix builderror in spi-pl022.c
  PM: add runtime PM support to MMCI
  PM: add runtime PM support to core Primecell driver
parents ca906662 6cfa6279
...@@ -365,6 +365,40 @@ static int amba_pm_restore_noirq(struct device *dev) ...@@ -365,6 +365,40 @@ static int amba_pm_restore_noirq(struct device *dev)
#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #endif /* !CONFIG_HIBERNATE_CALLBACKS */
#ifdef CONFIG_PM_RUNTIME
/*
* Hooks to provide runtime PM of the pclk (bus clock). It is safe to
* enable/disable the bus clock at runtime PM suspend/resume as this
* does not result in loss of context. However, disabling vcore power
* would do, so we leave that to the driver.
*/
static int amba_pm_runtime_suspend(struct device *dev)
{
struct amba_device *pcdev = to_amba_device(dev);
int ret = pm_generic_runtime_suspend(dev);
if (ret == 0 && dev->driver)
clk_disable(pcdev->pclk);
return ret;
}
static int amba_pm_runtime_resume(struct device *dev)
{
struct amba_device *pcdev = to_amba_device(dev);
int ret;
if (dev->driver) {
ret = clk_enable(pcdev->pclk);
/* Failure is probably fatal to the system, but... */
if (ret)
return ret;
}
return pm_generic_runtime_resume(dev);
}
#endif
#ifdef CONFIG_PM #ifdef CONFIG_PM
static const struct dev_pm_ops amba_pm = { static const struct dev_pm_ops amba_pm = {
...@@ -383,8 +417,8 @@ static const struct dev_pm_ops amba_pm = { ...@@ -383,8 +417,8 @@ static const struct dev_pm_ops amba_pm = {
.poweroff_noirq = amba_pm_poweroff_noirq, .poweroff_noirq = amba_pm_poweroff_noirq,
.restore_noirq = amba_pm_restore_noirq, .restore_noirq = amba_pm_restore_noirq,
SET_RUNTIME_PM_OPS( SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend, amba_pm_runtime_suspend,
pm_generic_runtime_resume, amba_pm_runtime_resume,
pm_generic_runtime_idle pm_generic_runtime_idle
) )
}; };
...@@ -494,10 +528,18 @@ static int amba_probe(struct device *dev) ...@@ -494,10 +528,18 @@ static int amba_probe(struct device *dev)
if (ret) if (ret)
break; break;
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
ret = pcdrv->probe(pcdev, id); ret = pcdrv->probe(pcdev, id);
if (ret == 0) if (ret == 0)
break; break;
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
amba_put_disable_pclk(pcdev); amba_put_disable_pclk(pcdev);
amba_put_disable_vcore(pcdev); amba_put_disable_vcore(pcdev);
} while (0); } while (0);
...@@ -509,7 +551,16 @@ static int amba_remove(struct device *dev) ...@@ -509,7 +551,16 @@ static int amba_remove(struct device *dev)
{ {
struct amba_device *pcdev = to_amba_device(dev); struct amba_device *pcdev = to_amba_device(dev);
struct amba_driver *drv = to_amba_driver(dev->driver); struct amba_driver *drv = to_amba_driver(dev->driver);
int ret = drv->remove(pcdev); int ret;
pm_runtime_get_sync(dev);
ret = drv->remove(pcdev);
pm_runtime_put_noidle(dev);
/* Undo the runtime PM settings in amba_probe() */
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
amba_put_disable_pclk(pcdev); amba_put_disable_pclk(pcdev);
amba_put_disable_vcore(pcdev); amba_put_disable_vcore(pcdev);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/amba/mmci.h> #include <linux/amba/mmci.h>
#include <linux/pm_runtime.h>
#include <asm/div64.h> #include <asm/div64.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -170,6 +171,7 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) ...@@ -170,6 +171,7 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
* back into the driver... * back into the driver...
*/ */
spin_unlock(&host->lock); spin_unlock(&host->lock);
pm_runtime_put(mmc_dev(host->mmc));
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
spin_lock(&host->lock); spin_lock(&host->lock);
} }
...@@ -984,6 +986,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -984,6 +986,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
return; return;
} }
pm_runtime_get_sync(mmc_dev(mmc));
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
host->mrq = mrq; host->mrq = mrq;
...@@ -1327,6 +1331,8 @@ static int __devinit mmci_probe(struct amba_device *dev, ...@@ -1327,6 +1331,8 @@ static int __devinit mmci_probe(struct amba_device *dev,
mmci_dma_setup(host); mmci_dma_setup(host);
pm_runtime_put(&dev->dev);
mmc_add_host(mmc); mmc_add_host(mmc);
return 0; return 0;
...@@ -1364,6 +1370,12 @@ static int __devexit mmci_remove(struct amba_device *dev) ...@@ -1364,6 +1370,12 @@ static int __devexit mmci_remove(struct amba_device *dev)
if (mmc) { if (mmc) {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
/*
* Undo pm_runtime_put() in probe. We use the _sync
* version here so that we can access the primecell.
*/
pm_runtime_get_sync(&dev->dev);
mmc_remove_host(mmc); mmc_remove_host(mmc);
writel(0, host->base + MMCIMASK0); writel(0, host->base + MMCIMASK0);
......
...@@ -515,9 +515,6 @@ static void giveback(struct pl022 *pl022) ...@@ -515,9 +515,6 @@ static void giveback(struct pl022 *pl022)
if (msg->complete) if (msg->complete)
msg->complete(msg->context); msg->complete(msg->context);
/* This message is completed, so let's turn off the clocks & power */ /* This message is completed, so let's turn off the clocks & power */
clk_disable(pl022->clk);
amba_pclk_disable(pl022->adev);
amba_vcore_disable(pl022->adev);
pm_runtime_put(&pl022->adev->dev); pm_runtime_put(&pl022->adev->dev);
} }
...@@ -1545,9 +1542,6 @@ static void pump_messages(struct work_struct *work) ...@@ -1545,9 +1542,6 @@ static void pump_messages(struct work_struct *work)
* (poll/interrupt/DMA) * (poll/interrupt/DMA)
*/ */
pm_runtime_get_sync(&pl022->adev->dev); pm_runtime_get_sync(&pl022->adev->dev);
amba_vcore_enable(pl022->adev);
amba_pclk_enable(pl022->adev);
clk_enable(pl022->clk);
restore_state(pl022); restore_state(pl022);
flush(pl022); flush(pl022);
...@@ -2186,8 +2180,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2186,8 +2180,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
} }
printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n", printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
adev->res.start, pl022->virtbase); adev->res.start, pl022->virtbase);
pm_runtime_enable(dev);
pm_runtime_resume(dev);
pl022->clk = clk_get(&adev->dev, NULL); pl022->clk = clk_get(&adev->dev, NULL);
if (IS_ERR(pl022->clk)) { if (IS_ERR(pl022->clk)) {
...@@ -2195,7 +2187,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2195,7 +2187,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
goto err_no_clk; goto err_no_clk;
} }
/* Disable SSP */ /* Disable SSP */
writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
SSP_CR1(pl022->virtbase)); SSP_CR1(pl022->virtbase));
...@@ -2235,12 +2226,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2235,12 +2226,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
goto err_spi_register; goto err_spi_register;
} }
dev_dbg(dev, "probe succeeded\n"); dev_dbg(dev, "probe succeeded\n");
/*
* Disable the silicon block pclk and any voltage domain and just /* let runtime pm put suspend */
* power it up and clock it when it's needed pm_runtime_put(dev);
*/
amba_pclk_disable(adev);
amba_vcore_disable(adev);
return 0; return 0;
err_spi_register: err_spi_register:
...@@ -2249,7 +2237,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2249,7 +2237,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
destroy_queue(pl022); destroy_queue(pl022);
pl022_dma_remove(pl022); pl022_dma_remove(pl022);
free_irq(adev->irq[0], pl022); free_irq(adev->irq[0], pl022);
pm_runtime_disable(&adev->dev);
err_no_irq: err_no_irq:
clk_put(pl022->clk); clk_put(pl022->clk);
err_no_clk: err_no_clk:
...@@ -2271,6 +2258,12 @@ pl022_remove(struct amba_device *adev) ...@@ -2271,6 +2258,12 @@ pl022_remove(struct amba_device *adev)
if (!pl022) if (!pl022)
return 0; return 0;
/*
* undo pm_runtime_put() in probe. I assume that we're not
* accessing the primecell here.
*/
pm_runtime_get_noresume(&adev->dev);
/* Remove the queue */ /* Remove the queue */
if (destroy_queue(pl022) != 0) if (destroy_queue(pl022) != 0)
dev_err(&adev->dev, "queue remove failed\n"); dev_err(&adev->dev, "queue remove failed\n");
...@@ -2288,46 +2281,70 @@ pl022_remove(struct amba_device *adev) ...@@ -2288,46 +2281,70 @@ pl022_remove(struct amba_device *adev)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_SUSPEND
static int pl022_suspend(struct amba_device *adev, pm_message_t state) static int pl022_suspend(struct device *dev)
{ {
struct pl022 *pl022 = amba_get_drvdata(adev); struct pl022 *pl022 = dev_get_drvdata(dev);
int status = 0; int status = 0;
status = stop_queue(pl022); status = stop_queue(pl022);
if (status) { if (status) {
dev_warn(&adev->dev, "suspend cannot stop queue\n"); dev_warn(dev, "suspend cannot stop queue\n");
return status; return status;
} }
amba_vcore_enable(adev); amba_vcore_enable(pl022->adev);
amba_pclk_enable(adev); amba_pclk_enable(pl022->adev);
load_ssp_default_config(pl022); load_ssp_default_config(pl022);
amba_pclk_disable(adev); amba_pclk_disable(pl022->adev);
amba_vcore_disable(adev); amba_vcore_disable(pl022->adev);
dev_dbg(&adev->dev, "suspended\n"); dev_dbg(dev, "suspended\n");
return 0; return 0;
} }
static int pl022_resume(struct amba_device *adev) static int pl022_resume(struct device *dev)
{ {
struct pl022 *pl022 = amba_get_drvdata(adev); struct pl022 *pl022 = dev_get_drvdata(dev);
int status = 0; int status = 0;
/* Start the queue running */ /* Start the queue running */
status = start_queue(pl022); status = start_queue(pl022);
if (status) if (status)
dev_err(&adev->dev, "problem starting queue (%d)\n", status); dev_err(dev, "problem starting queue (%d)\n", status);
else else
dev_dbg(&adev->dev, "resumed\n"); dev_dbg(dev, "resumed\n");
return status; return status;
} }
#else
#define pl022_suspend NULL
#define pl022_resume NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
#ifdef CONFIG_PM_RUNTIME
static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
clk_disable(pl022->clk);
amba_vcore_disable(pl022->adev);
return 0;
}
static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
amba_vcore_enable(pl022->adev);
clk_enable(pl022->clk);
return 0;
}
#endif
static const struct dev_pm_ops pl022_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
};
static struct vendor_data vendor_arm = { static struct vendor_data vendor_arm = {
.fifodepth = 8, .fifodepth = 8,
.max_bpw = 16, .max_bpw = 16,
...@@ -2407,12 +2424,11 @@ static struct amba_id pl022_ids[] = { ...@@ -2407,12 +2424,11 @@ static struct amba_id pl022_ids[] = {
static struct amba_driver pl022_driver = { static struct amba_driver pl022_driver = {
.drv = { .drv = {
.name = "ssp-pl022", .name = "ssp-pl022",
.pm = &pl022_dev_pm_ops,
}, },
.id_table = pl022_ids, .id_table = pl022_ids,
.probe = pl022_probe, .probe = pl022_probe,
.remove = __devexit_p(pl022_remove), .remove = __devexit_p(pl022_remove),
.suspend = pl022_suspend,
.resume = pl022_resume,
}; };
......
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