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

bus: tegra-aconnect: use devm_clk_*() helpers

aconnect bus driver is using pm_clk_*() interface for managing clocks.
With this, clocks seem to be always ON. This happens on Tegra devices
which use BPMP co-processor to manage clock resources, where clocks
are enabled during prepare phase. This is necessary because calls to
BPMP are always blocking. When pm_clk_*() interface is used on such
Tegra devices, clock prepare count is not balanced till driver remove()
gets executed and hence clocks are seen ON always. Thus this patch
replaces pm_clk_*() with devm_clk_*() framework.

Suggested-by: Mohan Kumar D <mkumard@nvidia.com>
Reviewed-by: Jonathan Hunter <jonathanh@nvidia.com>
Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Sameer Pujar and committed by
Thierry Reding
0d7dab92 9e98c678

+44 -20
+44 -20
drivers/bus/tegra-aconnect.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/of_platform.h> 14 14 #include <linux/platform_device.h> 15 - #include <linux/pm_clock.h> 16 15 #include <linux/pm_runtime.h> 16 + 17 + struct tegra_aconnect { 18 + struct clk *ape_clk; 19 + struct clk *apb2ape_clk; 20 + }; 17 21 18 22 static int tegra_aconnect_probe(struct platform_device *pdev) 19 23 { 20 - int ret; 24 + struct tegra_aconnect *aconnect; 21 25 22 26 if (!pdev->dev.of_node) 23 27 return -EINVAL; 24 28 25 - ret = pm_clk_create(&pdev->dev); 26 - if (ret) 27 - return ret; 29 + aconnect = devm_kzalloc(&pdev->dev, sizeof(struct tegra_aconnect), 30 + GFP_KERNEL); 31 + if (!aconnect) 32 + return -ENOMEM; 28 33 29 - ret = of_pm_clk_add_clk(&pdev->dev, "ape"); 30 - if (ret) 31 - goto clk_destroy; 34 + aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape"); 35 + if (IS_ERR(aconnect->ape_clk)) { 36 + dev_err(&pdev->dev, "Can't retrieve ape clock\n"); 37 + return PTR_ERR(aconnect->ape_clk); 38 + } 32 39 33 - ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape"); 34 - if (ret) 35 - goto clk_destroy; 40 + aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape"); 41 + if (IS_ERR(aconnect->apb2ape_clk)) { 42 + dev_err(&pdev->dev, "Can't retrieve apb2ape clock\n"); 43 + return PTR_ERR(aconnect->apb2ape_clk); 44 + } 36 45 46 + dev_set_drvdata(&pdev->dev, aconnect); 37 47 pm_runtime_enable(&pdev->dev); 38 48 39 49 of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); ··· 51 41 dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n"); 52 42 53 43 return 0; 54 - 55 - clk_destroy: 56 - pm_clk_destroy(&pdev->dev); 57 - 58 - return ret; 59 44 } 60 45 61 46 static int tegra_aconnect_remove(struct platform_device *pdev) 62 47 { 63 48 pm_runtime_disable(&pdev->dev); 64 49 65 - pm_clk_destroy(&pdev->dev); 66 - 67 50 return 0; 68 51 } 69 52 70 53 static int tegra_aconnect_runtime_resume(struct device *dev) 71 54 { 72 - return pm_clk_resume(dev); 55 + struct tegra_aconnect *aconnect = dev_get_drvdata(dev); 56 + int ret; 57 + 58 + ret = clk_prepare_enable(aconnect->ape_clk); 59 + if (ret) { 60 + dev_err(dev, "ape clk_enable failed: %d\n", ret); 61 + return ret; 62 + } 63 + 64 + ret = clk_prepare_enable(aconnect->apb2ape_clk); 65 + if (ret) { 66 + clk_disable_unprepare(aconnect->ape_clk); 67 + dev_err(dev, "apb2ape clk_enable failed: %d\n", ret); 68 + return ret; 69 + } 70 + 71 + return 0; 73 72 } 74 73 75 74 static int tegra_aconnect_runtime_suspend(struct device *dev) 76 75 { 77 - return pm_clk_suspend(dev); 76 + struct tegra_aconnect *aconnect = dev_get_drvdata(dev); 77 + 78 + clk_disable_unprepare(aconnect->ape_clk); 79 + clk_disable_unprepare(aconnect->apb2ape_clk); 80 + 81 + return 0; 78 82 } 79 83 80 84 static const struct dev_pm_ops tegra_aconnect_pm_ops = {