diff options
| author | Laxman Dewangan <ldewangan@nvidia.com> | 2013-04-24 05:54:27 -0400 |
|---|---|---|
| committer | Vinod Koul <vinod.koul@intel.com> | 2013-05-02 12:49:20 -0400 |
| commit | 3065c194670b61e213656ce25976d7c8a95e3c93 (patch) | |
| tree | f2d9b86bbe35623d9885f517f38c965f569675af | |
| parent | b2396f7984ea09e83d489cfca6d5da62cc22945a (diff) | |
dma: tegra: implement suspend/resume callbacks
Implement suspend/resume callbacks to store APB DMA channel's
register on suspend and restore APB DMA channel's register on
resume.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
| -rw-r--r-- | drivers/dma/tegra20-apb-dma.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 5a0b66c2a60c..ce193409ebd3 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/of.h> | 30 | #include <linux/of.h> |
| 31 | #include <linux/of_device.h> | 31 | #include <linux/of_device.h> |
| 32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
| 33 | #include <linux/pm.h> | ||
| 33 | #include <linux/pm_runtime.h> | 34 | #include <linux/pm_runtime.h> |
| 34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
| 35 | #include <linux/clk/tegra.h> | 36 | #include <linux/clk/tegra.h> |
| @@ -199,6 +200,7 @@ struct tegra_dma_channel { | |||
| 199 | 200 | ||
| 200 | /* Channel-slave specific configuration */ | 201 | /* Channel-slave specific configuration */ |
| 201 | struct dma_slave_config dma_sconfig; | 202 | struct dma_slave_config dma_sconfig; |
| 203 | struct tegra_dma_channel_regs channel_reg; | ||
| 202 | }; | 204 | }; |
| 203 | 205 | ||
| 204 | /* tegra_dma: Tegra DMA specific information */ | 206 | /* tegra_dma: Tegra DMA specific information */ |
| @@ -1440,11 +1442,74 @@ static int tegra_dma_runtime_resume(struct device *dev) | |||
| 1440 | return 0; | 1442 | return 0; |
| 1441 | } | 1443 | } |
| 1442 | 1444 | ||
| 1445 | #ifdef CONFIG_PM_SLEEP | ||
| 1446 | static int tegra_dma_pm_suspend(struct device *dev) | ||
| 1447 | { | ||
| 1448 | struct tegra_dma *tdma = dev_get_drvdata(dev); | ||
| 1449 | int i; | ||
| 1450 | int ret; | ||
| 1451 | |||
| 1452 | /* Enable clock before accessing register */ | ||
| 1453 | ret = tegra_dma_runtime_resume(dev); | ||
| 1454 | if (ret < 0) | ||
| 1455 | return ret; | ||
| 1456 | |||
| 1457 | tdma->reg_gen = tdma_read(tdma, TEGRA_APBDMA_GENERAL); | ||
| 1458 | for (i = 0; i < tdma->chip_data->nr_channels; i++) { | ||
| 1459 | struct tegra_dma_channel *tdc = &tdma->channels[i]; | ||
| 1460 | struct tegra_dma_channel_regs *ch_reg = &tdc->channel_reg; | ||
| 1461 | |||
| 1462 | ch_reg->csr = tdc_read(tdc, TEGRA_APBDMA_CHAN_CSR); | ||
| 1463 | ch_reg->ahb_ptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBPTR); | ||
| 1464 | ch_reg->apb_ptr = tdc_read(tdc, TEGRA_APBDMA_CHAN_APBPTR); | ||
| 1465 | ch_reg->ahb_seq = tdc_read(tdc, TEGRA_APBDMA_CHAN_AHBSEQ); | ||
| 1466 | ch_reg->apb_seq = tdc_read(tdc, TEGRA_APBDMA_CHAN_APBSEQ); | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | /* Disable clock */ | ||
| 1470 | tegra_dma_runtime_suspend(dev); | ||
| 1471 | return 0; | ||
| 1472 | } | ||
| 1473 | |||
| 1474 | static int tegra_dma_pm_resume(struct device *dev) | ||
| 1475 | { | ||
| 1476 | struct tegra_dma *tdma = dev_get_drvdata(dev); | ||
| 1477 | int i; | ||
| 1478 | int ret; | ||
| 1479 | |||
| 1480 | /* Enable clock before accessing register */ | ||
| 1481 | ret = tegra_dma_runtime_resume(dev); | ||
| 1482 | if (ret < 0) | ||
| 1483 | return ret; | ||
| 1484 | |||
| 1485 | tdma_write(tdma, TEGRA_APBDMA_GENERAL, tdma->reg_gen); | ||
| 1486 | tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0); | ||
| 1487 | tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul); | ||
| 1488 | |||
| 1489 | for (i = 0; i < tdma->chip_data->nr_channels; i++) { | ||
| 1490 | struct tegra_dma_channel *tdc = &tdma->channels[i]; | ||
| 1491 | struct tegra_dma_channel_regs *ch_reg = &tdc->channel_reg; | ||
| 1492 | |||
| 1493 | tdc_write(tdc, TEGRA_APBDMA_CHAN_APBSEQ, ch_reg->apb_seq); | ||
| 1494 | tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_reg->apb_ptr); | ||
| 1495 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_reg->ahb_seq); | ||
| 1496 | tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, ch_reg->ahb_ptr); | ||
| 1497 | tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, | ||
| 1498 | (ch_reg->csr & ~TEGRA_APBDMA_CSR_ENB)); | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | /* Disable clock */ | ||
| 1502 | tegra_dma_runtime_suspend(dev); | ||
| 1503 | return 0; | ||
| 1504 | } | ||
| 1505 | #endif | ||
| 1506 | |||
| 1443 | static const struct dev_pm_ops tegra_dma_dev_pm_ops = { | 1507 | static const struct dev_pm_ops tegra_dma_dev_pm_ops = { |
| 1444 | #ifdef CONFIG_PM_RUNTIME | 1508 | #ifdef CONFIG_PM_RUNTIME |
| 1445 | .runtime_suspend = tegra_dma_runtime_suspend, | 1509 | .runtime_suspend = tegra_dma_runtime_suspend, |
| 1446 | .runtime_resume = tegra_dma_runtime_resume, | 1510 | .runtime_resume = tegra_dma_runtime_resume, |
| 1447 | #endif | 1511 | #endif |
| 1512 | SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume) | ||
| 1448 | }; | 1513 | }; |
| 1449 | 1514 | ||
| 1450 | static struct platform_driver tegra_dmac_driver = { | 1515 | static struct platform_driver tegra_dmac_driver = { |
