irq-gic-pm driver is using pm_clk_*() interface to manage clock resources. With this, clocks always remain ON. This happens on Tegra devices which use BPMP co-processor to manage clocks, 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 devices, clock prepare count is not balanced till driver remove() gets executed and hence clocks are seen ON always. This patch replaces pm_clk_*() with devm_clk_*() framework.
Suggested-by: Mohan Kumar D <mkum...@nvidia.com> Signed-off-by: Sameer Pujar <spu...@nvidia.com> Reviewed-by: Jonathan Hunter <jonath...@nvidia.com> --- drivers/irqchip/irq-gic-pm.c | 52 +++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c index cde9714..b5405df 100644 --- a/drivers/irqchip/irq-gic-pm.c +++ b/drivers/irqchip/irq-gic-pm.c @@ -19,7 +19,6 @@ #include <linux/of_irq.h> #include <linux/irqchip/arm-gic.h> #include <linux/platform_device.h> -#include <linux/pm_clock.h> #include <linux/pm_runtime.h> #include <linux/slab.h> @@ -30,6 +29,8 @@ struct gic_clk_data { struct gic_chip_pm { struct gic_chip_data *chip_data; + const struct gic_clk_data *clk_data; + struct clk **clk_handle; int irq; }; @@ -37,11 +38,19 @@ static int gic_runtime_resume(struct device *dev) { struct gic_chip_pm *chip_pm = dev_get_drvdata(dev); struct gic_chip_data *gic = chip_pm->chip_data; - int ret; + const struct gic_clk_data *data = chip_pm->clk_data; + int ret, i; - ret = pm_clk_resume(dev); - if (ret) - return ret; + for (i = 0; i < data->num_clocks; i++) { + ret = clk_prepare_enable(chip_pm->clk_handle[i]); + if (ret) { + while (--i >= 0) + clk_disable_unprepare(chip_pm->clk_handle[i]); + + dev_err(dev, " clk_enable failed: %d\n", ret); + return ret; + } + } /* * On the very first resume, the pointer to the driver data @@ -62,32 +71,37 @@ static int gic_runtime_suspend(struct device *dev) { struct gic_chip_pm *chip_pm = dev_get_drvdata(dev); struct gic_chip_data *gic = chip_pm->chip_data; + const struct gic_clk_data *data = chip_pm->clk_data; + int i; gic_dist_save(gic); gic_cpu_save(gic); - return pm_clk_suspend(dev); + for (i = 0; i < data->num_clocks; i++) + clk_disable_unprepare(chip_pm->clk_handle[i]); + + return 0; } -static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data) +static int gic_get_clocks(struct device *dev, struct gic_chip_pm *chip_pm) { unsigned int i; - int ret; + const struct gic_clk_data *data = chip_pm->clk_data; if (!dev || !data) return -EINVAL; - ret = pm_clk_create(dev); - if (ret) - return ret; + chip_pm->clk_handle = devm_kzalloc(dev, data->num_clocks * + sizeof(struct clk *), GFP_KERNEL); + if (!chip_pm->clk_handle) + return -ENOMEM; for (i = 0; i < data->num_clocks; i++) { - ret = of_pm_clk_add_clk(dev, data->clocks[i]); - if (ret) { + chip_pm->clk_handle[i] = devm_clk_get(dev, data->clocks[i]); + if (IS_ERR(chip_pm->clk_handle[i])) { dev_err(dev, "failed to add clock %s\n", data->clocks[i]); - pm_clk_destroy(dev); - return ret; + return PTR_ERR(chip_pm->clk_handle[i]); } } @@ -111,6 +125,8 @@ static int gic_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no device match found\n"); return -ENODEV; } + chip_pm->clk_data = data; + platform_set_drvdata(pdev, chip_pm); irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) { @@ -118,7 +134,7 @@ static int gic_probe(struct platform_device *pdev) return -EINVAL; } - ret = gic_get_clocks(dev, data); + ret = gic_get_clocks(dev, chip_pm); if (ret) goto irq_dispose; @@ -132,8 +148,6 @@ static int gic_probe(struct platform_device *pdev) if (ret) goto rpm_put; - platform_set_drvdata(pdev, chip_pm); - pm_runtime_put(dev); chip_pm->irq = irq; @@ -145,7 +159,6 @@ static int gic_probe(struct platform_device *pdev) pm_runtime_put_sync(dev); rpm_disable: pm_runtime_disable(dev); - pm_clk_destroy(dev); irq_dispose: irq_dispose_mapping(irq); @@ -159,7 +172,6 @@ static int gic_remove(struct platform_device *pdev) pm_runtime_force_suspend(&pdev->dev); gic_teardown(gic); - pm_clk_destroy(&pdev->dev); irq_dispose_mapping(chip_pm->irq); return 0; -- 2.7.4