Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: tegra-apb: Really fix runtime-pm usage

Commit edd3bdbe9db1 ("dmaengine: tegra-apb: Correct runtime-pm usage")
added pm_runtime_get/put() calls to the tegra-apb DMA system suspend
callbacks. Runtime PM is disabled during system suspend and so these
APIs cannot be used. Fix the suspend handling for the tegra-apb DMA by
moving the save and restore of the DMA register context into the
runtime PM suspend and resume callbacks, and then use the
pm_runtime_force_suspend/resume() APIs to invoke the runtime PM
callbacks during system suspend.

Fixes: edd3bdbe9db1 ("dmaengine: tegra-apb: Correct runtime-pm usage")
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by

Jon Hunter and committed by
Vinod Koul
65a5c3dd 5f54d3e8

+10 -40
+10 -40
drivers/dma/tegra20-apb-dma.c
··· 1494 1494 static int tegra_dma_runtime_suspend(struct device *dev) 1495 1495 { 1496 1496 struct tegra_dma *tdma = dev_get_drvdata(dev); 1497 - 1498 - clk_disable_unprepare(tdma->dma_clk); 1499 - return 0; 1500 - } 1501 - 1502 - static int tegra_dma_runtime_resume(struct device *dev) 1503 - { 1504 - struct tegra_dma *tdma = dev_get_drvdata(dev); 1505 - int ret; 1506 - 1507 - ret = clk_prepare_enable(tdma->dma_clk); 1508 - if (ret < 0) { 1509 - dev_err(dev, "clk_enable failed: %d\n", ret); 1510 - return ret; 1511 - } 1512 - return 0; 1513 - } 1514 - 1515 - #ifdef CONFIG_PM_SLEEP 1516 - static int tegra_dma_pm_suspend(struct device *dev) 1517 - { 1518 - struct tegra_dma *tdma = dev_get_drvdata(dev); 1519 1497 int i; 1520 - int ret; 1521 - 1522 - /* Enable clock before accessing register */ 1523 - ret = pm_runtime_get_sync(dev); 1524 - if (ret < 0) 1525 - return ret; 1526 1498 1527 1499 tdma->reg_gen = tdma_read(tdma, TEGRA_APBDMA_GENERAL); 1528 1500 for (i = 0; i < tdma->chip_data->nr_channels; i++) { ··· 1515 1543 TEGRA_APBDMA_CHAN_WCOUNT); 1516 1544 } 1517 1545 1518 - /* Disable clock */ 1519 - pm_runtime_put(dev); 1546 + clk_disable_unprepare(tdma->dma_clk); 1547 + 1520 1548 return 0; 1521 1549 } 1522 1550 1523 - static int tegra_dma_pm_resume(struct device *dev) 1551 + static int tegra_dma_runtime_resume(struct device *dev) 1524 1552 { 1525 1553 struct tegra_dma *tdma = dev_get_drvdata(dev); 1526 - int i; 1527 - int ret; 1554 + int i, ret; 1528 1555 1529 - /* Enable clock before accessing register */ 1530 - ret = pm_runtime_get_sync(dev); 1531 - if (ret < 0) 1556 + ret = clk_prepare_enable(tdma->dma_clk); 1557 + if (ret < 0) { 1558 + dev_err(dev, "clk_enable failed: %d\n", ret); 1532 1559 return ret; 1560 + } 1533 1561 1534 1562 tdma_write(tdma, TEGRA_APBDMA_GENERAL, tdma->reg_gen); 1535 1563 tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0); ··· 1554 1582 (ch_reg->csr & ~TEGRA_APBDMA_CSR_ENB)); 1555 1583 } 1556 1584 1557 - /* Disable clock */ 1558 - pm_runtime_put(dev); 1559 1585 return 0; 1560 1586 } 1561 - #endif 1562 1587 1563 1588 static const struct dev_pm_ops tegra_dma_dev_pm_ops = { 1564 1589 SET_RUNTIME_PM_OPS(tegra_dma_runtime_suspend, tegra_dma_runtime_resume, 1565 1590 NULL) 1566 - SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume) 1591 + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 1592 + pm_runtime_force_resume) 1567 1593 }; 1568 1594 1569 1595 static const struct of_device_id tegra_dma_of_match[] = {