summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSameer Pujar <spujar@nvidia.com>2019-03-13 00:41:58 -0400
committerThierry Reding <treding@nvidia.com>2019-03-28 12:24:57 -0400
commit0d7dab926130e194decf1b4dabbf66de6e68bf0c (patch)
tree258bea564fa18df6380a72c60c8a2bfa9eaed5b1
parent9e98c678c2d6ae3a17cb2de55d17f69dddaa231b (diff)
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>
-rw-r--r--drivers/bus/tegra-aconnect.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c
index 084ae286fa23..9349157b3a5b 100644
--- a/drivers/bus/tegra-aconnect.c
+++ b/drivers/bus/tegra-aconnect.c
@@ -12,28 +12,38 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/of_platform.h> 13#include <linux/of_platform.h>
14#include <linux/platform_device.h> 14#include <linux/platform_device.h>
15#include <linux/pm_clock.h>
16#include <linux/pm_runtime.h> 15#include <linux/pm_runtime.h>
17 16
17struct tegra_aconnect {
18 struct clk *ape_clk;
19 struct clk *apb2ape_clk;
20};
21
18static int tegra_aconnect_probe(struct platform_device *pdev) 22static int tegra_aconnect_probe(struct platform_device *pdev)
19{ 23{
20 int ret; 24 struct tegra_aconnect *aconnect;
21 25
22 if (!pdev->dev.of_node) 26 if (!pdev->dev.of_node)
23 return -EINVAL; 27 return -EINVAL;
24 28
25 ret = pm_clk_create(&pdev->dev); 29 aconnect = devm_kzalloc(&pdev->dev, sizeof(struct tegra_aconnect),
26 if (ret) 30 GFP_KERNEL);
27 return ret; 31 if (!aconnect)
32 return -ENOMEM;
28 33
29 ret = of_pm_clk_add_clk(&pdev->dev, "ape"); 34 aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape");
30 if (ret) 35 if (IS_ERR(aconnect->ape_clk)) {
31 goto clk_destroy; 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"); 40 aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape");
34 if (ret) 41 if (IS_ERR(aconnect->apb2ape_clk)) {
35 goto clk_destroy; 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 pm_runtime_enable(&pdev->dev); 47 pm_runtime_enable(&pdev->dev);
38 48
39 of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 49 of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
@@ -41,30 +51,44 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
41 dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n"); 51 dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n");
42 52
43 return 0; 53 return 0;
44
45clk_destroy:
46 pm_clk_destroy(&pdev->dev);
47
48 return ret;
49} 54}
50 55
51static int tegra_aconnect_remove(struct platform_device *pdev) 56static int tegra_aconnect_remove(struct platform_device *pdev)
52{ 57{
53 pm_runtime_disable(&pdev->dev); 58 pm_runtime_disable(&pdev->dev);
54 59
55 pm_clk_destroy(&pdev->dev);
56
57 return 0; 60 return 0;
58} 61}
59 62
60static int tegra_aconnect_runtime_resume(struct device *dev) 63static int tegra_aconnect_runtime_resume(struct device *dev)
61{ 64{
62 return pm_clk_resume(dev); 65 struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
66 int ret;
67
68 ret = clk_prepare_enable(aconnect->ape_clk);
69 if (ret) {
70 dev_err(dev, "ape clk_enable failed: %d\n", ret);
71 return ret;
72 }
73
74 ret = clk_prepare_enable(aconnect->apb2ape_clk);
75 if (ret) {
76 clk_disable_unprepare(aconnect->ape_clk);
77 dev_err(dev, "apb2ape clk_enable failed: %d\n", ret);
78 return ret;
79 }
80
81 return 0;
63} 82}
64 83
65static int tegra_aconnect_runtime_suspend(struct device *dev) 84static int tegra_aconnect_runtime_suspend(struct device *dev)
66{ 85{
67 return pm_clk_suspend(dev); 86 struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
87
88 clk_disable_unprepare(aconnect->ape_clk);
89 clk_disable_unprepare(aconnect->apb2ape_clk);
90
91 return 0;
68} 92}
69 93
70static const struct dev_pm_ops tegra_aconnect_pm_ops = { 94static const struct dev_pm_ops tegra_aconnect_pm_ops = {