aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2016-04-08 09:16:28 -0400
committerThierry Reding <treding@nvidia.com>2016-04-28 06:41:54 -0400
commitf7c42d98621739d416cc4a739b721574fcbe910c (patch)
treecbd6f61c1a1b90780e63e7be5c3c4d3bd0988b5e /drivers/clk
parente8f6a68c508b5d1cc4612ada028d87c74ab279d5 (diff)
clk: tegra: dfll: Properly clean up on failure and removal
Upon failure to probe the DFLL, the OPP table will not be cleaned up properly. Fix this and while at it make sure the OPP table will also be cleared upon driver removal. Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/tegra/clk-dfll.h2
-rw-r--r--drivers/clk/tegra/clk-tegra124-dfll-fcpu.c31
-rw-r--r--drivers/clk/tegra/cvb.c16
-rw-r--r--drivers/clk/tegra/cvb.h3
4 files changed, 48 insertions, 4 deletions
diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h
index d192982b1f96..ed2ad888268f 100644
--- a/drivers/clk/tegra/clk-dfll.h
+++ b/drivers/clk/tegra/clk-dfll.h
@@ -25,6 +25,7 @@
25/** 25/**
26 * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver 26 * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver
27 * @dev: struct device * that holds the OPP table for the DFLL 27 * @dev: struct device * that holds the OPP table for the DFLL
28 * @max_freq: maximum frequency supported on this SoC
28 * @cvb: CPU frequency table for this SoC 29 * @cvb: CPU frequency table for this SoC
29 * @init_clock_trimmers: callback to initialize clock trimmers 30 * @init_clock_trimmers: callback to initialize clock trimmers
30 * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage 31 * @set_clock_trimmers_high: callback to tune clock trimmers for high voltage
@@ -32,6 +33,7 @@
32 */ 33 */
33struct tegra_dfll_soc_data { 34struct tegra_dfll_soc_data {
34 struct device *dev; 35 struct device *dev;
36 unsigned long max_freq;
35 const struct cvb_table *cvb; 37 const struct cvb_table *cvb;
36 38
37 void (*init_clock_trimmers)(void); 39 void (*init_clock_trimmers)(void);
diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
index c7ffd4fd2231..d052d9fa8230 100644
--- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
+++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c
@@ -84,7 +84,7 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = {
84 84
85static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) 85static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
86{ 86{
87 int process_id, speedo_id, speedo_value; 87 int process_id, speedo_id, speedo_value, err;
88 struct tegra_dfll_soc_data *soc; 88 struct tegra_dfll_soc_data *soc;
89 89
90 process_id = tegra_sku_info.cpu_process_id; 90 process_id = tegra_sku_info.cpu_process_id;
@@ -107,18 +107,41 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
107 return -ENODEV; 107 return -ENODEV;
108 } 108 }
109 109
110 soc->max_freq = cpu_max_freq_table[speedo_id];
111
110 soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables, 112 soc->cvb = tegra_cvb_add_opp_table(soc->dev, tegra124_cpu_cvb_tables,
111 ARRAY_SIZE(tegra124_cpu_cvb_tables), 113 ARRAY_SIZE(tegra124_cpu_cvb_tables),
112 process_id, speedo_id, speedo_value, 114 process_id, speedo_id, speedo_value,
113 cpu_max_freq_table[speedo_id]); 115 soc->max_freq);
114 if (IS_ERR(soc->cvb)) { 116 if (IS_ERR(soc->cvb)) {
115 dev_err(&pdev->dev, "couldn't add OPP table: %ld\n", 117 dev_err(&pdev->dev, "couldn't add OPP table: %ld\n",
116 PTR_ERR(soc->cvb)); 118 PTR_ERR(soc->cvb));
117 return PTR_ERR(soc->cvb); 119 return PTR_ERR(soc->cvb);
118 } 120 }
119 121
122 err = tegra_dfll_register(pdev, soc);
123 if (err < 0) {
124 tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq);
125 return err;
126 }
127
128 platform_set_drvdata(pdev, soc);
129
130 return 0;
131}
132
133static int tegra124_dfll_fcpu_remove(struct platform_device *pdev)
134{
135 struct tegra_dfll_soc_data *soc = platform_get_drvdata(pdev);
136 int err;
137
138 err = tegra_dfll_unregister(pdev);
139 if (err < 0)
140 dev_err(&pdev->dev, "failed to unregister DFLL: %d\n", err);
141
142 tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq);
120 143
121 return tegra_dfll_register(pdev, soc); 144 return 0;
122} 145}
123 146
124static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { 147static const struct of_device_id tegra124_dfll_fcpu_of_match[] = {
@@ -134,7 +157,7 @@ static const struct dev_pm_ops tegra124_dfll_pm_ops = {
134 157
135static struct platform_driver tegra124_dfll_fcpu_driver = { 158static struct platform_driver tegra124_dfll_fcpu_driver = {
136 .probe = tegra124_dfll_fcpu_probe, 159 .probe = tegra124_dfll_fcpu_probe,
137 .remove = tegra_dfll_unregister, 160 .remove = tegra124_dfll_fcpu_remove,
138 .driver = { 161 .driver = {
139 .name = "tegra124-dfll", 162 .name = "tegra124-dfll",
140 .of_match_table = tegra124_dfll_fcpu_of_match, 163 .of_match_table = tegra124_dfll_fcpu_of_match,
diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c
index 7a099b18c368..624115e82ff9 100644
--- a/drivers/clk/tegra/cvb.c
+++ b/drivers/clk/tegra/cvb.c
@@ -130,3 +130,19 @@ tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables,
130 130
131 return ERR_PTR(-EINVAL); 131 return ERR_PTR(-EINVAL);
132} 132}
133
134void tegra_cvb_remove_opp_table(struct device *dev,
135 const struct cvb_table *table,
136 unsigned long max_freq)
137{
138 unsigned int i;
139
140 for (i = 0; i < MAX_DVFS_FREQS; i++) {
141 const struct cvb_table_freq_entry *entry = &table->entries[i];
142
143 if (!entry->freq || (entry->freq > max_freq))
144 break;
145
146 dev_pm_opp_remove(dev, entry->freq);
147 }
148}
diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h
index e6bf8581badd..c1f077993b2a 100644
--- a/drivers/clk/tegra/cvb.h
+++ b/drivers/clk/tegra/cvb.h
@@ -61,5 +61,8 @@ const struct cvb_table *
61tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables, 61tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables,
62 size_t count, int process_id, int speedo_id, 62 size_t count, int process_id, int speedo_id,
63 int speedo_value, unsigned long max_freq); 63 int speedo_value, unsigned long max_freq);
64void tegra_cvb_remove_opp_table(struct device *dev,
65 const struct cvb_table *table,
66 unsigned long max_freq);
64 67
65#endif 68#endif