2121#include <linux/err.h>
2222#include <linux/init.h>
2323#include <linux/module.h>
24- #include <linux/of .h>
24+ #include <linux/platform_device .h>
2525#include <linux/types.h>
2626
2727static struct cpufreq_frequency_table freq_table [] = {
@@ -36,15 +36,20 @@ static struct cpufreq_frequency_table freq_table[] = {
3636 { .frequency = CPUFREQ_TABLE_END },
3737};
3838
39- static struct clk * cpu_clk ;
40- static struct clk * pll_x_clk ;
41- static struct clk * pll_p_clk ;
42- static bool pll_x_prepared ;
39+ struct tegra20_cpufreq {
40+ struct device * dev ;
41+ struct cpufreq_driver driver ;
42+ struct clk * cpu_clk ;
43+ struct clk * pll_x_clk ;
44+ struct clk * pll_p_clk ;
45+ bool pll_x_prepared ;
46+ };
4347
4448static unsigned int tegra_get_intermediate (struct cpufreq_policy * policy ,
4549 unsigned int index )
4650{
47- unsigned int ifreq = clk_get_rate (pll_p_clk ) / 1000 ;
51+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
52+ unsigned int ifreq = clk_get_rate (cpufreq -> pll_p_clk ) / 1000 ;
4853
4954 /*
5055 * Don't switch to intermediate freq if:
@@ -60,6 +65,7 @@ static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy,
6065static int tegra_target_intermediate (struct cpufreq_policy * policy ,
6166 unsigned int index )
6267{
68+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
6369 int ret ;
6470
6571 /*
@@ -72,138 +78,159 @@ static int tegra_target_intermediate(struct cpufreq_policy *policy,
7278 * Also, we wouldn't be using pll_x anymore and must not take extra
7379 * reference to it, as it can be disabled now to save some power.
7480 */
75- clk_prepare_enable (pll_x_clk );
81+ clk_prepare_enable (cpufreq -> pll_x_clk );
7682
77- ret = clk_set_parent (cpu_clk , pll_p_clk );
83+ ret = clk_set_parent (cpufreq -> cpu_clk , cpufreq -> pll_p_clk );
7884 if (ret )
79- clk_disable_unprepare (pll_x_clk );
85+ clk_disable_unprepare (cpufreq -> pll_x_clk );
8086 else
81- pll_x_prepared = true;
87+ cpufreq -> pll_x_prepared = true;
8288
8389 return ret ;
8490}
8591
8692static int tegra_target (struct cpufreq_policy * policy , unsigned int index )
8793{
94+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
8895 unsigned long rate = freq_table [index ].frequency ;
89- unsigned int ifreq = clk_get_rate (pll_p_clk ) / 1000 ;
96+ unsigned int ifreq = clk_get_rate (cpufreq -> pll_p_clk ) / 1000 ;
9097 int ret ;
9198
9299 /*
93100 * target freq == pll_p, don't need to take extra reference to pll_x_clk
94101 * as it isn't used anymore.
95102 */
96103 if (rate == ifreq )
97- return clk_set_parent (cpu_clk , pll_p_clk );
104+ return clk_set_parent (cpufreq -> cpu_clk , cpufreq -> pll_p_clk );
98105
99- ret = clk_set_rate (pll_x_clk , rate * 1000 );
106+ ret = clk_set_rate (cpufreq -> pll_x_clk , rate * 1000 );
100107 /* Restore to earlier frequency on error, i.e. pll_x */
101108 if (ret )
102- pr_err ( "Failed to change pll_x to %lu\n" , rate );
109+ dev_err ( cpufreq -> dev , "Failed to change pll_x to %lu\n" , rate );
103110
104- ret = clk_set_parent (cpu_clk , pll_x_clk );
111+ ret = clk_set_parent (cpufreq -> cpu_clk , cpufreq -> pll_x_clk );
105112 /* This shouldn't fail while changing or restoring */
106113 WARN_ON (ret );
107114
108115 /*
109116 * Drop count to pll_x clock only if we switched to intermediate freq
110117 * earlier while transitioning to a target frequency.
111118 */
112- if (pll_x_prepared ) {
113- clk_disable_unprepare (pll_x_clk );
114- pll_x_prepared = false;
119+ if (cpufreq -> pll_x_prepared ) {
120+ clk_disable_unprepare (cpufreq -> pll_x_clk );
121+ cpufreq -> pll_x_prepared = false;
115122 }
116123
117124 return ret ;
118125}
119126
120127static int tegra_cpu_init (struct cpufreq_policy * policy )
121128{
129+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
122130 int ret ;
123131
124- clk_prepare_enable (cpu_clk );
132+ clk_prepare_enable (cpufreq -> cpu_clk );
125133
126134 /* FIXME: what's the actual transition time? */
127135 ret = cpufreq_generic_init (policy , freq_table , 300 * 1000 );
128136 if (ret ) {
129- clk_disable_unprepare (cpu_clk );
137+ clk_disable_unprepare (cpufreq -> cpu_clk );
130138 return ret ;
131139 }
132140
133- policy -> clk = cpu_clk ;
141+ policy -> clk = cpufreq -> cpu_clk ;
134142 policy -> suspend_freq = freq_table [0 ].frequency ;
135143 return 0 ;
136144}
137145
138146static int tegra_cpu_exit (struct cpufreq_policy * policy )
139147{
140- clk_disable_unprepare (cpu_clk );
148+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
149+
150+ clk_disable_unprepare (cpufreq -> cpu_clk );
141151 return 0 ;
142152}
143153
144- static struct cpufreq_driver tegra_cpufreq_driver = {
145- .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK ,
146- .verify = cpufreq_generic_frequency_table_verify ,
147- .get_intermediate = tegra_get_intermediate ,
148- .target_intermediate = tegra_target_intermediate ,
149- .target_index = tegra_target ,
150- .get = cpufreq_generic_get ,
151- .init = tegra_cpu_init ,
152- .exit = tegra_cpu_exit ,
153- .name = "tegra" ,
154- .attr = cpufreq_generic_attr ,
155- .suspend = cpufreq_generic_suspend ,
156- };
157-
158- static int __init tegra_cpufreq_init (void )
154+ static int tegra20_cpufreq_probe (struct platform_device * pdev )
159155{
156+ struct tegra20_cpufreq * cpufreq ;
160157 int err ;
161158
162- if (!of_machine_is_compatible ("nvidia,tegra20" ))
163- return - ENODEV ;
159+ cpufreq = devm_kzalloc (& pdev -> dev , sizeof (* cpufreq ), GFP_KERNEL );
160+ if (!cpufreq )
161+ return - ENOMEM ;
164162
165- cpu_clk = clk_get_sys (NULL , "cclk" );
166- if (IS_ERR (cpu_clk ))
167- return PTR_ERR (cpu_clk );
163+ cpufreq -> cpu_clk = clk_get_sys (NULL , "cclk" );
164+ if (IS_ERR (cpufreq -> cpu_clk ))
165+ return PTR_ERR (cpufreq -> cpu_clk );
168166
169- pll_x_clk = clk_get_sys (NULL , "pll_x" );
170- if (IS_ERR (pll_x_clk )) {
171- err = PTR_ERR (pll_x_clk );
167+ cpufreq -> pll_x_clk = clk_get_sys (NULL , "pll_x" );
168+ if (IS_ERR (cpufreq -> pll_x_clk )) {
169+ err = PTR_ERR (cpufreq -> pll_x_clk );
172170 goto put_cpu ;
173171 }
174172
175- pll_p_clk = clk_get_sys (NULL , "pll_p" );
176- if (IS_ERR (pll_p_clk )) {
177- err = PTR_ERR (pll_p_clk );
173+ cpufreq -> pll_p_clk = clk_get_sys (NULL , "pll_p" );
174+ if (IS_ERR (cpufreq -> pll_p_clk )) {
175+ err = PTR_ERR (cpufreq -> pll_p_clk );
178176 goto put_pll_x ;
179177 }
180178
181- err = cpufreq_register_driver (& tegra_cpufreq_driver );
179+ cpufreq -> dev = & pdev -> dev ;
180+ cpufreq -> driver .get = cpufreq_generic_get ;
181+ cpufreq -> driver .attr = cpufreq_generic_attr ;
182+ cpufreq -> driver .init = tegra_cpu_init ;
183+ cpufreq -> driver .exit = tegra_cpu_exit ;
184+ cpufreq -> driver .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK ;
185+ cpufreq -> driver .verify = cpufreq_generic_frequency_table_verify ;
186+ cpufreq -> driver .suspend = cpufreq_generic_suspend ;
187+ cpufreq -> driver .driver_data = cpufreq ;
188+ cpufreq -> driver .target_index = tegra_target ;
189+ cpufreq -> driver .get_intermediate = tegra_get_intermediate ;
190+ cpufreq -> driver .target_intermediate = tegra_target_intermediate ;
191+ snprintf (cpufreq -> driver .name , CPUFREQ_NAME_LEN , "tegra" );
192+
193+ err = cpufreq_register_driver (& cpufreq -> driver );
182194 if (err )
183195 goto put_pll_p ;
184196
197+ platform_set_drvdata (pdev , cpufreq );
198+
185199 return 0 ;
186200
187201put_pll_p :
188- clk_put (pll_p_clk );
202+ clk_put (cpufreq -> pll_p_clk );
189203put_pll_x :
190- clk_put (pll_x_clk );
204+ clk_put (cpufreq -> pll_x_clk );
191205put_cpu :
192- clk_put (cpu_clk );
206+ clk_put (cpufreq -> cpu_clk );
193207
194208 return err ;
195209}
196210
197- static void __exit tegra_cpufreq_exit ( void )
211+ static int tegra20_cpufreq_remove ( struct platform_device * pdev )
198212{
199- cpufreq_unregister_driver (& tegra_cpufreq_driver );
200- clk_put (pll_p_clk );
201- clk_put (pll_x_clk );
202- clk_put (cpu_clk );
213+ struct tegra20_cpufreq * cpufreq = platform_get_drvdata (pdev );
214+
215+ cpufreq_unregister_driver (& cpufreq -> driver );
216+
217+ clk_put (cpufreq -> pll_p_clk );
218+ clk_put (cpufreq -> pll_x_clk );
219+ clk_put (cpufreq -> cpu_clk );
220+
221+ return 0 ;
203222}
204223
224+ static struct platform_driver tegra20_cpufreq_driver = {
225+ .probe = tegra20_cpufreq_probe ,
226+ .remove = tegra20_cpufreq_remove ,
227+ .driver = {
228+ .name = "tegra20-cpufreq" ,
229+ },
230+ };
231+ module_platform_driver (tegra20_cpufreq_driver );
232+
233+ MODULE_ALIAS ("platform:tegra20-cpufreq" );
205234MODULE_AUTHOR ("Colin Cross <ccross@android.com>" );
206235MODULE_DESCRIPTION ("NVIDIA Tegra20 cpufreq driver" );
207236MODULE_LICENSE ("GPL" );
208- module_init (tegra_cpufreq_init );
209- module_exit (tegra_cpufreq_exit );
0 commit comments