summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2012-06-29 17:20:59 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-07-02 06:20:35 -0700
commitad8fabee431584601e7184da76604ad3dfdd1109 (patch)
tree09dd13ec002d4391a192c13250520e36d6189205 /drivers/spi
parent429d909e14eefa0331b1cd30490bce4d7ff45f33 (diff)
spi: tegra: macro for enable/disable runtime pm inside driver
Add macro in the spi tegra driver for enabling/disabling runtime PM specific to this driver. Setting macro SPI_PM_RUNTIME_ENABLE to 1 will enable the runtime pm and resetting to 0 make runtime pm disable. The dynamic clock management i.e. enabling the clock before transfer and disabling after transfer complete is done in both the cases. When runtime pm is enabled then clock control is done through runtime pm callbacks otherwise it will be directly call the clock control apis. bug 1003103 Change-Id: I2544e8f3b3e5605e0247791653a5a0ed6c36e9b6 Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-on: http://git-master/r/112142 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-tegra.c114
1 files changed, 81 insertions, 33 deletions
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index c0de42bf4299..cf1b7bf40c62 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -42,6 +42,8 @@
#include <mach/dma.h>
#include <mach/clk.h>
+#define SPI_PM_RUNTIME_ENABLE 0
+
#define SLINK_COMMAND 0x000
#define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0)
#define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5)
@@ -174,6 +176,7 @@ struct spi_tegra_data {
struct spi_master *master;
struct platform_device *pdev;
spinlock_t lock;
+ spinlock_t reg_lock;
char port_name[32];
struct clk *clk;
@@ -214,7 +217,7 @@ struct spi_tegra_data {
bool is_curr_dma_xfer;
bool is_clkon_always;
- bool clk_state;
+ int clk_state;
bool is_suspended;
bool is_hw_based_cs;
@@ -252,22 +255,75 @@ static int tegra_spi_runtime_resume(struct device *dev);
static inline unsigned long spi_tegra_readl(struct spi_tegra_data *tspi,
unsigned long reg)
{
- if (!tspi->clk_state)
+ unsigned long flags;
+ unsigned long val;
+
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ if (tspi->clk_state < 1)
BUG();
- return readl(tspi->base + reg);
+ val = readl(tspi->base + reg);
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
+ return val;
}
static inline void spi_tegra_writel(struct spi_tegra_data *tspi,
unsigned long val, unsigned long reg)
{
- if (!tspi->clk_state)
+ unsigned long flags;
+
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ if (tspi->clk_state < 1)
BUG();
writel(val, tspi->base + reg);
/* Synchronize write by reading back the register */
readl(tspi->base + SLINK_MAS_DATA);
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
}
+static int tegra_spi_clk_disable(struct spi_tegra_data *tspi)
+{
+ unsigned long flags;
+
+ /* Flush all write which are in PPSB queue by reading back */
+ spi_tegra_readl(tspi, SLINK_MAS_DATA);
+
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ tspi->clk_state--;
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
+ clk_disable(tspi->clk);
+ clk_disable(tspi->sclk);
+ return 0;
+}
+
+static int tegra_spi_clk_enable(struct spi_tegra_data *tspi)
+{
+ unsigned long flags;
+
+ clk_enable(tspi->sclk);
+ clk_enable(tspi->clk);
+ spin_lock_irqsave(&tspi->reg_lock, flags);
+ tspi->clk_state++;
+ spin_unlock_irqrestore(&tspi->reg_lock, flags);
+ return 0;
+}
+
+#if SPI_PM_RUNTIME_ENABLE
+#define spi_pm_runtime_get_sync(dev) pm_runtime_get_sync(dev)
+#define spi_pm_runtime_put_sync(dev) pm_runtime_put_sync(dev)
+#define spi_pm_runtime_enable(dev) pm_runtime_enable(dev)
+#define spi_pm_runtime_disable(dev) pm_runtime_disable(dev)
+#define spi_pm_runtime_enabled(dev) pm_runtime_enabled(dev)
+#define spi_pm_runtime_status_suspended(dev) pm_runtime_status_suspended(dev)
+#else
+#define spi_pm_runtime_get_sync(dev) tegra_spi_runtime_resume(dev)
+#define spi_pm_runtime_put_sync(dev) tegra_spi_runtime_idle(dev)
+#define spi_pm_runtime_enable(dev) do { } while(0)
+#define spi_pm_runtime_disable(dev) do { } while(0)
+#define spi_pm_runtime_enabled(dev) true
+#define spi_pm_runtime_status_suspended(dev) true
+#endif
+
static void cancel_dma(struct tegra_dma_channel *dma_chan,
struct tegra_dma_req *req)
{
@@ -738,9 +794,9 @@ static void spi_tegra_start_transfer(struct spi_device *spi,
command2 = tspi->def_command2_reg;
if (is_first_of_msg) {
- if ((ret = pm_runtime_get_sync(&tspi->pdev->dev)) < 0) {
+ if ((ret = spi_pm_runtime_get_sync(&tspi->pdev->dev)) < 0) {
dev_err(&tspi->pdev->dev,
- "%s: pm_runtime_get_sync() returns %d\n",
+ "%s: spi_pm_runtime_get_sync() returns %d\n",
__func__, ret);
return;
}
@@ -855,7 +911,7 @@ static int spi_tegra_setup(struct spi_device *spi)
return -EINVAL;
}
- pm_runtime_get_sync(&tspi->pdev->dev);
+ spi_pm_runtime_get_sync(&tspi->pdev->dev);
spin_lock_irqsave(&tspi->lock, flags);
val = tspi->def_command_reg;
@@ -867,7 +923,7 @@ static int spi_tegra_setup(struct spi_device *spi)
spi_tegra_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
spin_unlock_irqrestore(&tspi->lock, flags);
- pm_runtime_put_sync(&tspi->pdev->dev);
+ spi_pm_runtime_put_sync(&tspi->pdev->dev);
return 0;
}
@@ -1017,7 +1073,7 @@ static void spi_tegra_curr_transfer_complete(struct spi_tegra_data *tspi,
/* Provide delay to stablize the signal state */
spin_unlock_irqrestore(&tspi->lock, *irq_flags);
udelay(10);
- pm_runtime_put_sync(&tspi->pdev->dev);
+ spi_pm_runtime_put_sync(&tspi->pdev->dev);
spin_lock_irqsave(&tspi->lock, *irq_flags);
tspi->is_transfer_in_progress = false;
/* Check if any new request has come between
@@ -1317,6 +1373,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
tspi->is_transfer_in_progress = false;
tspi->is_suspended = false;
spin_lock_init(&tspi->lock);
+ spin_lock_init(&tspi->reg_lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
@@ -1422,8 +1479,8 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN;
skip_dma_alloc:
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev)) {
+ spi_pm_runtime_enable(&pdev->dev);
+ if (!spi_pm_runtime_enabled(&pdev->dev)) {
ret = tegra_spi_runtime_resume(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "runtime resume failed %d", ret);
@@ -1433,7 +1490,7 @@ skip_dma_alloc:
/* Enable clock if it is require to be enable always */
if (tspi->is_clkon_always)
- pm_runtime_get_sync(&pdev->dev);
+ spi_pm_runtime_get_sync(&pdev->dev);
master->dev.of_node = pdev->dev.of_node;
ret = spi_register_master(master);
@@ -1459,14 +1516,14 @@ exit_master_unregister:
spi_unregister_master(master);
if (tspi->is_clkon_always)
- pm_runtime_put_sync(&pdev->dev);
+ spi_pm_runtime_put_sync(&pdev->dev);
exit_pm_suspend:
- if (!pm_runtime_status_suspended(&pdev->dev))
+ if (!spi_pm_runtime_status_suspended(&pdev->dev))
tegra_spi_runtime_idle(&pdev->dev);
exit_pm_disable:
- pm_runtime_disable(&pdev->dev);
+ spi_pm_runtime_disable(&pdev->dev);
spi_tegra_deinit_dma_param(tspi, false);
@@ -1496,10 +1553,10 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
/* Disable clock if it is always enabled */
if (tspi->is_clkon_always)
- pm_runtime_put_sync(&pdev->dev);
+ spi_pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
+ spi_pm_runtime_disable(&pdev->dev);
+ if (!spi_pm_runtime_status_suspended(&pdev->dev))
tegra_spi_runtime_idle(&pdev->dev);
destroy_workqueue(tspi->spi_workqueue);
@@ -1555,7 +1612,7 @@ static int spi_tegra_suspend(struct device *dev)
/* Disable clock if it is always enabled */
if (tspi->is_clkon_always)
- pm_runtime_put_sync(dev);
+ spi_pm_runtime_put_sync(dev);
return 0;
}
@@ -1572,11 +1629,11 @@ static int spi_tegra_resume(struct device *dev)
/* Enable clock if it is always enabled */
if (tspi->is_clkon_always)
- pm_runtime_get_sync(dev);
+ spi_pm_runtime_get_sync(dev);
- pm_runtime_get_sync(dev);
+ spi_pm_runtime_get_sync(dev);
spi_tegra_writel(tspi, tspi->command_reg, SLINK_COMMAND);
- pm_runtime_put_sync(dev);
+ spi_pm_runtime_put_sync(dev);
spin_lock_irqsave(&tspi->lock, flags);
@@ -1604,13 +1661,7 @@ static int tegra_spi_runtime_idle(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct spi_tegra_data *tspi = spi_master_get_devdata(master);
- /* Flush all write which are in PPSB queue by reading back */
- spi_tegra_readl(tspi, SLINK_MAS_DATA);
-
- tspi->clk_state = 0;
- clk_disable(tspi->clk);
- clk_disable(tspi->sclk);
- return 0;
+ return tegra_spi_clk_disable(tspi);
}
static int tegra_spi_runtime_resume(struct device *dev)
@@ -1618,10 +1669,7 @@ static int tegra_spi_runtime_resume(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct spi_tegra_data *tspi = spi_master_get_devdata(master);
- clk_enable(tspi->sclk);
- clk_enable(tspi->clk);
- tspi->clk_state = 1;
- return 0;
+ return tegra_spi_clk_enable(tspi);
}
static const struct dev_pm_ops tegra_spi_dev_pm_ops = {