24
24
#include <linux/of.h>
25
25
#include <linux/of_device.h>
26
26
#include <linux/platform_device.h>
27
+ #include <linux/pm_domain.h>
27
28
#include <linux/pm_opp.h>
28
29
#include <linux/slab.h>
29
30
#include <linux/soc/qcom/smem.h>
@@ -49,10 +50,12 @@ struct qcom_cpufreq_match_data {
49
50
int (* get_version )(struct device * cpu_dev ,
50
51
struct nvmem_cell * speedbin_nvmem ,
51
52
struct qcom_cpufreq_drv * drv );
53
+ const char * * genpd_names ;
52
54
};
53
55
54
56
struct qcom_cpufreq_drv {
55
57
struct opp_table * * opp_tables ;
58
+ struct opp_table * * genpd_opp_tables ;
56
59
u32 versions ;
57
60
const struct qcom_cpufreq_match_data * data ;
58
61
};
@@ -126,6 +129,12 @@ static const struct qcom_cpufreq_match_data match_data_kryo = {
126
129
.get_version = qcom_cpufreq_kryo_name_version ,
127
130
};
128
131
132
+ static const char * qcs404_genpd_names [] = { "cpr" , NULL };
133
+
134
+ static const struct qcom_cpufreq_match_data match_data_qcs404 = {
135
+ .genpd_names = qcs404_genpd_names ,
136
+ };
137
+
129
138
static int qcom_cpufreq_probe (struct platform_device * pdev )
130
139
{
131
140
struct qcom_cpufreq_drv * drv ;
@@ -188,11 +197,19 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
188
197
goto free_drv ;
189
198
}
190
199
200
+ drv -> genpd_opp_tables = kcalloc (num_possible_cpus (),
201
+ sizeof (* drv -> genpd_opp_tables ),
202
+ GFP_KERNEL );
203
+ if (!drv -> genpd_opp_tables ) {
204
+ ret = - ENOMEM ;
205
+ goto free_opp ;
206
+ }
207
+
191
208
for_each_possible_cpu (cpu ) {
192
209
cpu_dev = get_cpu_device (cpu );
193
210
if (NULL == cpu_dev ) {
194
211
ret = - ENODEV ;
195
- goto free_opp ;
212
+ goto free_genpd_opp ;
196
213
}
197
214
198
215
if (drv -> data -> get_version ) {
@@ -203,7 +220,22 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
203
220
ret = PTR_ERR (drv -> opp_tables [cpu ]);
204
221
dev_err (cpu_dev ,
205
222
"Failed to set supported hardware\n" );
206
- goto free_opp ;
223
+ goto free_genpd_opp ;
224
+ }
225
+ }
226
+
227
+ if (drv -> data -> genpd_names ) {
228
+ drv -> genpd_opp_tables [cpu ] =
229
+ dev_pm_opp_attach_genpd (cpu_dev ,
230
+ drv -> data -> genpd_names ,
231
+ NULL );
232
+ if (IS_ERR (drv -> genpd_opp_tables [cpu ])) {
233
+ ret = PTR_ERR (drv -> genpd_opp_tables [cpu ]);
234
+ if (ret != - EPROBE_DEFER )
235
+ dev_err (cpu_dev ,
236
+ "Could not attach to pm_domain: %d\n" ,
237
+ ret );
238
+ goto free_genpd_opp ;
207
239
}
208
240
}
209
241
}
@@ -218,6 +250,13 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
218
250
ret = PTR_ERR (cpufreq_dt_pdev );
219
251
dev_err (cpu_dev , "Failed to register platform device\n" );
220
252
253
+ free_genpd_opp :
254
+ for_each_possible_cpu (cpu ) {
255
+ if (IS_ERR_OR_NULL (drv -> genpd_opp_tables [cpu ]))
256
+ break ;
257
+ dev_pm_opp_detach_genpd (drv -> genpd_opp_tables [cpu ]);
258
+ }
259
+ kfree (drv -> genpd_opp_tables );
221
260
free_opp :
222
261
for_each_possible_cpu (cpu ) {
223
262
if (IS_ERR_OR_NULL (drv -> opp_tables [cpu ]))
@@ -238,11 +277,15 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)
238
277
239
278
platform_device_unregister (cpufreq_dt_pdev );
240
279
241
- for_each_possible_cpu (cpu )
280
+ for_each_possible_cpu (cpu ) {
242
281
if (drv -> opp_tables [cpu ])
243
282
dev_pm_opp_put_supported_hw (drv -> opp_tables [cpu ]);
283
+ if (drv -> genpd_opp_tables [cpu ])
284
+ dev_pm_opp_detach_genpd (drv -> genpd_opp_tables [cpu ]);
285
+ }
244
286
245
287
kfree (drv -> opp_tables );
288
+ kfree (drv -> genpd_opp_tables );
246
289
kfree (drv );
247
290
248
291
return 0 ;
@@ -259,6 +302,7 @@ static struct platform_driver qcom_cpufreq_driver = {
259
302
static const struct of_device_id qcom_cpufreq_match_list [] __initconst = {
260
303
{ .compatible = "qcom,apq8096" , .data = & match_data_kryo },
261
304
{ .compatible = "qcom,msm8996" , .data = & match_data_kryo },
305
+ { .compatible = "qcom,qcs404" , .data = & match_data_qcs404 },
262
306
{},
263
307
};
264
308
0 commit comments