21
21
#include <linux/err.h>
22
22
#include <linux/init.h>
23
23
#include <linux/module.h>
24
- #include <linux/of .h>
24
+ #include <linux/platform_device .h>
25
25
#include <linux/types.h>
26
26
27
27
static struct cpufreq_frequency_table freq_table [] = {
@@ -36,15 +36,20 @@ static struct cpufreq_frequency_table freq_table[] = {
36
36
{ .frequency = CPUFREQ_TABLE_END },
37
37
};
38
38
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
+ };
43
47
44
48
static unsigned int tegra_get_intermediate (struct cpufreq_policy * policy ,
45
49
unsigned int index )
46
50
{
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 ;
48
53
49
54
/*
50
55
* Don't switch to intermediate freq if:
@@ -60,6 +65,7 @@ static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy,
60
65
static int tegra_target_intermediate (struct cpufreq_policy * policy ,
61
66
unsigned int index )
62
67
{
68
+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
63
69
int ret ;
64
70
65
71
/*
@@ -72,138 +78,159 @@ static int tegra_target_intermediate(struct cpufreq_policy *policy,
72
78
* Also, we wouldn't be using pll_x anymore and must not take extra
73
79
* reference to it, as it can be disabled now to save some power.
74
80
*/
75
- clk_prepare_enable (pll_x_clk );
81
+ clk_prepare_enable (cpufreq -> pll_x_clk );
76
82
77
- ret = clk_set_parent (cpu_clk , pll_p_clk );
83
+ ret = clk_set_parent (cpufreq -> cpu_clk , cpufreq -> pll_p_clk );
78
84
if (ret )
79
- clk_disable_unprepare (pll_x_clk );
85
+ clk_disable_unprepare (cpufreq -> pll_x_clk );
80
86
else
81
- pll_x_prepared = true;
87
+ cpufreq -> pll_x_prepared = true;
82
88
83
89
return ret ;
84
90
}
85
91
86
92
static int tegra_target (struct cpufreq_policy * policy , unsigned int index )
87
93
{
94
+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
88
95
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 ;
90
97
int ret ;
91
98
92
99
/*
93
100
* target freq == pll_p, don't need to take extra reference to pll_x_clk
94
101
* as it isn't used anymore.
95
102
*/
96
103
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 );
98
105
99
- ret = clk_set_rate (pll_x_clk , rate * 1000 );
106
+ ret = clk_set_rate (cpufreq -> pll_x_clk , rate * 1000 );
100
107
/* Restore to earlier frequency on error, i.e. pll_x */
101
108
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 );
103
110
104
- ret = clk_set_parent (cpu_clk , pll_x_clk );
111
+ ret = clk_set_parent (cpufreq -> cpu_clk , cpufreq -> pll_x_clk );
105
112
/* This shouldn't fail while changing or restoring */
106
113
WARN_ON (ret );
107
114
108
115
/*
109
116
* Drop count to pll_x clock only if we switched to intermediate freq
110
117
* earlier while transitioning to a target frequency.
111
118
*/
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;
115
122
}
116
123
117
124
return ret ;
118
125
}
119
126
120
127
static int tegra_cpu_init (struct cpufreq_policy * policy )
121
128
{
129
+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
122
130
int ret ;
123
131
124
- clk_prepare_enable (cpu_clk );
132
+ clk_prepare_enable (cpufreq -> cpu_clk );
125
133
126
134
/* FIXME: what's the actual transition time? */
127
135
ret = cpufreq_generic_init (policy , freq_table , 300 * 1000 );
128
136
if (ret ) {
129
- clk_disable_unprepare (cpu_clk );
137
+ clk_disable_unprepare (cpufreq -> cpu_clk );
130
138
return ret ;
131
139
}
132
140
133
- policy -> clk = cpu_clk ;
141
+ policy -> clk = cpufreq -> cpu_clk ;
134
142
policy -> suspend_freq = freq_table [0 ].frequency ;
135
143
return 0 ;
136
144
}
137
145
138
146
static int tegra_cpu_exit (struct cpufreq_policy * policy )
139
147
{
140
- clk_disable_unprepare (cpu_clk );
148
+ struct tegra20_cpufreq * cpufreq = cpufreq_get_driver_data ();
149
+
150
+ clk_disable_unprepare (cpufreq -> cpu_clk );
141
151
return 0 ;
142
152
}
143
153
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 )
159
155
{
156
+ struct tegra20_cpufreq * cpufreq ;
160
157
int err ;
161
158
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 ;
164
162
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 );
168
166
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 );
172
170
goto put_cpu ;
173
171
}
174
172
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 );
178
176
goto put_pll_x ;
179
177
}
180
178
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 );
182
194
if (err )
183
195
goto put_pll_p ;
184
196
197
+ platform_set_drvdata (pdev , cpufreq );
198
+
185
199
return 0 ;
186
200
187
201
put_pll_p :
188
- clk_put (pll_p_clk );
202
+ clk_put (cpufreq -> pll_p_clk );
189
203
put_pll_x :
190
- clk_put (pll_x_clk );
204
+ clk_put (cpufreq -> pll_x_clk );
191
205
put_cpu :
192
- clk_put (cpu_clk );
206
+ clk_put (cpufreq -> cpu_clk );
193
207
194
208
return err ;
195
209
}
196
210
197
- static void __exit tegra_cpufreq_exit ( void )
211
+ static int tegra20_cpufreq_remove ( struct platform_device * pdev )
198
212
{
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 ;
203
222
}
204
223
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" );
205
234
MODULE_AUTHOR (
"Colin Cross <[email protected] >" );
206
235
MODULE_DESCRIPTION ("NVIDIA Tegra20 cpufreq driver" );
207
236
MODULE_LICENSE ("GPL" );
208
- module_init (tegra_cpufreq_init );
209
- module_exit (tegra_cpufreq_exit );
0 commit comments