diff options
author | Sameer Pujar <spujar@nvidia.com> | 2019-03-13 00:41:58 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2019-03-28 12:24:57 -0400 |
commit | 0d7dab926130e194decf1b4dabbf66de6e68bf0c (patch) | |
tree | 258bea564fa18df6380a72c60c8a2bfa9eaed5b1 | |
parent | 9e98c678c2d6ae3a17cb2de55d17f69dddaa231b (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.c | 64 |
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 | ||
17 | struct tegra_aconnect { | ||
18 | struct clk *ape_clk; | ||
19 | struct clk *apb2ape_clk; | ||
20 | }; | ||
21 | |||
18 | static int tegra_aconnect_probe(struct platform_device *pdev) | 22 | static 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 | |||
45 | clk_destroy: | ||
46 | pm_clk_destroy(&pdev->dev); | ||
47 | |||
48 | return ret; | ||
49 | } | 54 | } |
50 | 55 | ||
51 | static int tegra_aconnect_remove(struct platform_device *pdev) | 56 | static 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 | ||
60 | static int tegra_aconnect_runtime_resume(struct device *dev) | 63 | static 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 | ||
65 | static int tegra_aconnect_runtime_suspend(struct device *dev) | 84 | static 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 | ||
70 | static const struct dev_pm_ops tegra_aconnect_pm_ops = { | 94 | static const struct dev_pm_ops tegra_aconnect_pm_ops = { |