mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 23:27:06 +00:00
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
This commit is contained in:
commit
7e0a6fd5a4
3 changed files with 116 additions and 37 deletions
|
@ -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 = {
|
||||||
.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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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 @@
|
||||||
#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)
|
||||||
* 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)
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
* (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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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[] = {
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue