clk: tegra: dfll: Fix drvdata overwriting issue
authorNicolin Chen <nicoleotsuka@gmail.com>
Thu, 12 Oct 2017 23:09:59 +0000 (16:09 -0700)
committerThierry Reding <treding@nvidia.com>
Wed, 1 Nov 2017 14:00:06 +0000 (15:00 +0100)
Both tegra124-dfll and clk-dfll are using platform_set_drvdata
to set drvdata of the exact same pdev while they use different
pointers for the drvdata. Once the drvdata has been overwritten
by tegra124-dfll, clk-dfll will never get its td pointer as it
expects.

Since tegra124-dfll merely needs its soc pointer in its remove
function, this patch fixes the bug by removing the overwriting
in the tegra124-dfll file and letting the tegra_dfll_unregister
return an soc pointer for it.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
Acked-By: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/clk/tegra/clk-dfll.c
drivers/clk/tegra/clk-dfll.h
drivers/clk/tegra/clk-tegra124-dfll-fcpu.c

index 2c44aeb..0a7deee 100644 (file)
@@ -1728,10 +1728,10 @@ EXPORT_SYMBOL(tegra_dfll_register);
  * @pdev: DFLL platform_device *
  *
  * Unbind this driver from the DFLL hardware device represented by
- * @pdev. The DFLL must be disabled for this to succeed. Returns 0
- * upon success or -EBUSY if the DFLL is still active.
+ * @pdev. The DFLL must be disabled for this to succeed. Returns a
+ * soc pointer upon success or -EBUSY if the DFLL is still active.
  */
-int tegra_dfll_unregister(struct platform_device *pdev)
+struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev)
 {
        struct tegra_dfll *td = platform_get_drvdata(pdev);
 
@@ -1739,7 +1739,7 @@ int tegra_dfll_unregister(struct platform_device *pdev)
        if (td->mode != DFLL_DISABLED) {
                dev_err(&pdev->dev,
                        "must disable DFLL before removing driver\n");
-               return -EBUSY;
+               return ERR_PTR(-EBUSY);
        }
 
        debugfs_remove_recursive(td->debugfs_dir);
@@ -1753,6 +1753,6 @@ int tegra_dfll_unregister(struct platform_device *pdev)
 
        reset_control_assert(td->dvco_rst);
 
-       return 0;
+       return td->soc;
 }
 EXPORT_SYMBOL(tegra_dfll_unregister);
index ed2ad88..83352c8 100644 (file)
@@ -43,7 +43,7 @@ struct tegra_dfll_soc_data {
 
 int tegra_dfll_register(struct platform_device *pdev,
                        struct tegra_dfll_soc_data *soc);
-int tegra_dfll_unregister(struct platform_device *pdev);
+struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
 int tegra_dfll_runtime_suspend(struct device *dev);
 int tegra_dfll_runtime_resume(struct device *dev);
 
index ad1c1cc..269d359 100644 (file)
@@ -125,19 +125,17 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
                return err;
        }
 
-       platform_set_drvdata(pdev, soc);
-
        return 0;
 }
 
 static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
 {
-       struct tegra_dfll_soc_data *soc = platform_get_drvdata(pdev);
-       int err;
+       struct tegra_dfll_soc_data *soc;
 
-       err = tegra_dfll_unregister(pdev);
-       if (err < 0)
-               dev_err(&pdev->dev, "failed to unregister DFLL: %d\n", err);
+       soc = tegra_dfll_unregister(pdev);
+       if (IS_ERR(soc))
+               dev_err(&pdev->dev, "failed to unregister DFLL: %ld\n",
+                       PTR_ERR(soc));
 
        tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq);