diff options
author | Jon Hunter <jonathanh@nvidia.com> | 2015-11-13 11:39:38 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2015-12-05 05:43:08 -0500 |
commit | edd3bdbe9db1415f744bb5da0752675ddbd9eee0 (patch) | |
tree | 58551c86b816e5ecb5555c6936c8930d6a1d4086 /drivers/dma | |
parent | 8005c49d9aea74d382f474ce11afbbc7d7130bec (diff) |
dmaengine: tegra-apb: Correct runtime-pm usage
The tegra-apb DMA driver enables runtime-pm but never calls
pm_runtime_get/put and hence the runtime-pm callbacks are never invoked.
The driver manages the clocks by directly calling clk_prepare_enable()
and clk_unprepare_disable().
Fix this by replacing the clk_prepare_enable() and clk_disable_unprepare()
with pm_runtime_get_sync() and pm_runtime_put(), respectively. Note that
the consequence of this is that if runtime-pm is disabled, then the clocks
will remain on the entire time the driver is loaded. However, if
runtime-pm is disabled, then power is not most likely not a concern.
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/tegra20-apb-dma.c | 43 |
1 files changed, 18 insertions, 25 deletions
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index c8f79dcaaee8..f68bccf55a24 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c | |||
@@ -1186,10 +1186,12 @@ static int tegra_dma_alloc_chan_resources(struct dma_chan *dc) | |||
1186 | 1186 | ||
1187 | dma_cookie_init(&tdc->dma_chan); | 1187 | dma_cookie_init(&tdc->dma_chan); |
1188 | tdc->config_init = false; | 1188 | tdc->config_init = false; |
1189 | ret = clk_prepare_enable(tdma->dma_clk); | 1189 | |
1190 | ret = pm_runtime_get_sync(tdma->dev); | ||
1190 | if (ret < 0) | 1191 | if (ret < 0) |
1191 | dev_err(tdc2dev(tdc), "clk_prepare_enable failed: %d\n", ret); | 1192 | return ret; |
1192 | return ret; | 1193 | |
1194 | return 0; | ||
1193 | } | 1195 | } |
1194 | 1196 | ||
1195 | static void tegra_dma_free_chan_resources(struct dma_chan *dc) | 1197 | static void tegra_dma_free_chan_resources(struct dma_chan *dc) |
@@ -1232,7 +1234,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc) | |||
1232 | list_del(&sg_req->node); | 1234 | list_del(&sg_req->node); |
1233 | kfree(sg_req); | 1235 | kfree(sg_req); |
1234 | } | 1236 | } |
1235 | clk_disable_unprepare(tdma->dma_clk); | 1237 | pm_runtime_put(tdma->dev); |
1236 | 1238 | ||
1237 | tdc->slave_id = 0; | 1239 | tdc->slave_id = 0; |
1238 | } | 1240 | } |
@@ -1356,20 +1358,14 @@ static int tegra_dma_probe(struct platform_device *pdev) | |||
1356 | spin_lock_init(&tdma->global_lock); | 1358 | spin_lock_init(&tdma->global_lock); |
1357 | 1359 | ||
1358 | pm_runtime_enable(&pdev->dev); | 1360 | pm_runtime_enable(&pdev->dev); |
1359 | if (!pm_runtime_enabled(&pdev->dev)) { | 1361 | if (!pm_runtime_enabled(&pdev->dev)) |
1360 | ret = tegra_dma_runtime_resume(&pdev->dev); | 1362 | ret = tegra_dma_runtime_resume(&pdev->dev); |
1361 | if (ret) { | 1363 | else |
1362 | dev_err(&pdev->dev, "dma_runtime_resume failed %d\n", | 1364 | ret = pm_runtime_get_sync(&pdev->dev); |
1363 | ret); | ||
1364 | goto err_pm_disable; | ||
1365 | } | ||
1366 | } | ||
1367 | 1365 | ||
1368 | /* Enable clock before accessing registers */ | ||
1369 | ret = clk_prepare_enable(tdma->dma_clk); | ||
1370 | if (ret < 0) { | 1366 | if (ret < 0) { |
1371 | dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); | 1367 | pm_runtime_disable(&pdev->dev); |
1372 | goto err_pm_disable; | 1368 | return ret; |
1373 | } | 1369 | } |
1374 | 1370 | ||
1375 | /* Reset DMA controller */ | 1371 | /* Reset DMA controller */ |
@@ -1382,7 +1378,7 @@ static int tegra_dma_probe(struct platform_device *pdev) | |||
1382 | tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0); | 1378 | tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0); |
1383 | tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul); | 1379 | tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul); |
1384 | 1380 | ||
1385 | clk_disable_unprepare(tdma->dma_clk); | 1381 | pm_runtime_put(&pdev->dev); |
1386 | 1382 | ||
1387 | INIT_LIST_HEAD(&tdma->dma_dev.channels); | 1383 | INIT_LIST_HEAD(&tdma->dma_dev.channels); |
1388 | for (i = 0; i < cdata->nr_channels; i++) { | 1384 | for (i = 0; i < cdata->nr_channels; i++) { |
@@ -1485,7 +1481,6 @@ err_irq: | |||
1485 | tasklet_kill(&tdc->tasklet); | 1481 | tasklet_kill(&tdc->tasklet); |
1486 | } | 1482 | } |
1487 | 1483 | ||
1488 | err_pm_disable: | ||
1489 | pm_runtime_disable(&pdev->dev); | 1484 | pm_runtime_disable(&pdev->dev); |
1490 | if (!pm_runtime_status_suspended(&pdev->dev)) | 1485 | if (!pm_runtime_status_suspended(&pdev->dev)) |
1491 | tegra_dma_runtime_suspend(&pdev->dev); | 1486 | tegra_dma_runtime_suspend(&pdev->dev); |
@@ -1543,7 +1538,7 @@ static int tegra_dma_pm_suspend(struct device *dev) | |||
1543 | int ret; | 1538 | int ret; |
1544 | 1539 | ||
1545 | /* Enable clock before accessing register */ | 1540 | /* Enable clock before accessing register */ |
1546 | ret = tegra_dma_runtime_resume(dev); | 1541 | ret = pm_runtime_get_sync(dev); |
1547 | if (ret < 0) | 1542 | if (ret < 0) |
1548 | return ret; | 1543 | return ret; |
1549 | 1544 | ||
@@ -1560,7 +1555,7 @@ static int tegra_dma_pm_suspend(struct device *dev) | |||
1560 | } | 1555 | } |
1561 | 1556 | ||
1562 | /* Disable clock */ | 1557 | /* Disable clock */ |
1563 | tegra_dma_runtime_suspend(dev); | 1558 | pm_runtime_put(dev); |
1564 | return 0; | 1559 | return 0; |
1565 | } | 1560 | } |
1566 | 1561 | ||
@@ -1571,7 +1566,7 @@ static int tegra_dma_pm_resume(struct device *dev) | |||
1571 | int ret; | 1566 | int ret; |
1572 | 1567 | ||
1573 | /* Enable clock before accessing register */ | 1568 | /* Enable clock before accessing register */ |
1574 | ret = tegra_dma_runtime_resume(dev); | 1569 | ret = pm_runtime_get_sync(dev); |
1575 | if (ret < 0) | 1570 | if (ret < 0) |
1576 | return ret; | 1571 | return ret; |
1577 | 1572 | ||
@@ -1592,16 +1587,14 @@ static int tegra_dma_pm_resume(struct device *dev) | |||
1592 | } | 1587 | } |
1593 | 1588 | ||
1594 | /* Disable clock */ | 1589 | /* Disable clock */ |
1595 | tegra_dma_runtime_suspend(dev); | 1590 | pm_runtime_put(dev); |
1596 | return 0; | 1591 | return 0; |
1597 | } | 1592 | } |
1598 | #endif | 1593 | #endif |
1599 | 1594 | ||
1600 | static const struct dev_pm_ops tegra_dma_dev_pm_ops = { | 1595 | static const struct dev_pm_ops tegra_dma_dev_pm_ops = { |
1601 | #ifdef CONFIG_PM | 1596 | SET_RUNTIME_PM_OPS(tegra_dma_runtime_suspend, tegra_dma_runtime_resume, |
1602 | .runtime_suspend = tegra_dma_runtime_suspend, | 1597 | NULL) |
1603 | .runtime_resume = tegra_dma_runtime_resume, | ||
1604 | #endif | ||
1605 | SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume) | 1598 | SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume) |
1606 | }; | 1599 | }; |
1607 | 1600 | ||