1 /*
2 * Rockchip CPUFreq Driver
3 *
4 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16 #include <linux/clk.h>
17 #include <linux/cpu.h>
18 #include <linux/cpufreq.h>
19 #include <linux/err.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/mfd/syscon.h>
23 #include <linux/module.h>
24 #include <linux/nvmem-consumer.h>
25 #include <linux/of.h>
26 #include <linux/of_address.h>
27 #include <linux/platform_device.h>
28 #include <linux/pm_opp.h>
29 #include <linux/slab.h>
30 #include <linux/regmap.h>
31 #include <linux/regulator/consumer.h>
32 #include <linux/rockchip/cpu.h>
33 #include <soc/rockchip/rockchip_opp_select.h>
34 #include <soc/rockchip/rockchip_system_monitor.h>
35
36 #include "cpufreq-dt.h"
37 #include "rockchip-cpufreq.h"
38
39 #define CPUFREQ_INTERNAL_VERSION 0x80
40 #define CPUFREQ_LENGTH_MARGIN 0x1
41 #define CPUFREQ_INTERMEDIATE_RATE (CPUFREQ_INTERNAL_VERSION | \
42 CPUFREQ_LENGTH_MARGIN)
43
44 struct cluster_info {
45 struct list_head list_head;
46 struct monitor_dev_info *mdev_info;
47 struct rockchip_opp_info opp_info;
48 cpumask_t cpus;
49 int scale;
50 };
51 static LIST_HEAD(cluster_info_list);
52
px30_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)53 static int px30_get_soc_info(struct device *dev, struct device_node *np,
54 int *bin, int *process)
55 {
56 int ret = 0;
57 u8 value = 0;
58
59 if (!bin)
60 return 0;
61
62 if (of_property_match_string(np, "nvmem-cell-names",
63 "performance") >= 0) {
64 ret = rockchip_nvmem_cell_read_u8(np, "performance", &value);
65 if (ret) {
66 dev_err(dev, "Failed to get soc performance value\n");
67 return ret;
68 }
69 *bin = value;
70 }
71 if (*bin >= 0)
72 dev_info(dev, "bin=%d\n", *bin);
73
74 return ret;
75 }
76
rk3288_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)77 static int rk3288_get_soc_info(struct device *dev, struct device_node *np,
78 int *bin, int *process)
79 {
80 int ret = 0;
81 u8 value = 0;
82 char *name;
83
84 if (!bin)
85 goto next;
86 if (of_property_match_string(np, "nvmem-cell-names", "special") >= 0) {
87 ret = rockchip_nvmem_cell_read_u8(np, "special", &value);
88 if (ret) {
89 dev_err(dev, "Failed to get soc special value\n");
90 goto out;
91 }
92 if (value == 0xc)
93 *bin = 0;
94 else
95 *bin = 1;
96 }
97
98 if (soc_is_rk3288w())
99 name = "performance-w";
100 else
101 name = "performance";
102
103 if (of_property_match_string(np, "nvmem-cell-names", name) >= 0) {
104 ret = rockchip_nvmem_cell_read_u8(np, name, &value);
105 if (ret) {
106 dev_err(dev, "Failed to get soc performance value\n");
107 goto out;
108 }
109 if (value & 0x2)
110 *bin = 3;
111 else if (value & 0x01)
112 *bin = 2;
113 }
114 if (*bin >= 0)
115 dev_info(dev, "bin=%d\n", *bin);
116
117 next:
118 if (!process)
119 goto out;
120 if (of_property_match_string(np, "nvmem-cell-names",
121 "process") >= 0) {
122 ret = rockchip_nvmem_cell_read_u8(np, "process", &value);
123 if (ret) {
124 dev_err(dev, "Failed to get soc process version\n");
125 goto out;
126 }
127 if (soc_is_rk3288() && (value == 0 || value == 1))
128 *process = 0;
129 }
130 if (*process >= 0)
131 dev_info(dev, "process=%d\n", *process);
132
133 out:
134 return ret;
135 }
136
rk3399_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)137 static int rk3399_get_soc_info(struct device *dev, struct device_node *np,
138 int *bin, int *process)
139 {
140 int ret = 0;
141 u8 value = 0;
142
143 if (!bin)
144 return 0;
145
146 if (of_property_match_string(np, "nvmem-cell-names",
147 "specification_serial_number") >= 0) {
148 ret = rockchip_nvmem_cell_read_u8(np,
149 "specification_serial_number",
150 &value);
151 if (ret) {
152 dev_err(dev,
153 "Failed to get specification_serial_number\n");
154 goto out;
155 }
156
157 if (value == 0xb) {
158 *bin = 0;
159 } else if (value == 0x1) {
160 if (of_property_match_string(np, "nvmem-cell-names",
161 "customer_demand") >= 0) {
162 ret = rockchip_nvmem_cell_read_u8(np,
163 "customer_demand",
164 &value);
165 if (ret) {
166 dev_err(dev, "Failed to get customer_demand\n");
167 goto out;
168 }
169 if (value == 0x0)
170 *bin = 0;
171 else
172 *bin = 1;
173 }
174 } else if (value == 0x10) {
175 *bin = 1;
176 }
177 }
178
179 out:
180 if (*bin >= 0)
181 dev_info(dev, "bin=%d\n", *bin);
182
183 return ret;
184 }
185
rk3588_cpu_set_read_margin(struct device * dev,struct rockchip_opp_info * opp_info,unsigned long volt)186 static int rk3588_cpu_set_read_margin(struct device *dev,
187 struct rockchip_opp_info *opp_info,
188 unsigned long volt)
189 {
190 bool is_found = false;
191 u32 rm;
192 int i;
193
194 if (!opp_info->volt_rm_tbl)
195 return 0;
196
197 for (i = 0; opp_info->volt_rm_tbl[i].rm != VOLT_RM_TABLE_END; i++) {
198 if (volt >= opp_info->volt_rm_tbl[i].volt) {
199 rm = opp_info->volt_rm_tbl[i].rm;
200 is_found = true;
201 break;
202 }
203 }
204
205 if (!is_found)
206 return 0;
207 if (rm == opp_info->current_rm)
208 return 0;
209
210 dev_dbg(dev, "set rm to %d\n", rm);
211 if (opp_info->grf) {
212 regmap_write(opp_info->grf, 0x20, 0x001c0000 | (rm << 2));
213 regmap_write(opp_info->grf, 0x28, 0x003c0000 | (rm << 2));
214 regmap_write(opp_info->grf, 0x2c, 0x003c0000 | (rm << 2));
215 regmap_write(opp_info->grf, 0x30, 0x00200020);
216 udelay(1);
217 regmap_write(opp_info->grf, 0x30, 0x00200000);
218 }
219 if (opp_info->dsu_grf) {
220 regmap_write(opp_info->dsu_grf, 0x20, 0x001c0000 | (rm << 2));
221 regmap_write(opp_info->dsu_grf, 0x28, 0x003c0000 | (rm << 2));
222 regmap_write(opp_info->dsu_grf, 0x2c, 0x003c0000 | (rm << 2));
223 regmap_write(opp_info->dsu_grf, 0x30, 0x001c0000 | (rm << 2));
224 regmap_write(opp_info->dsu_grf, 0x38, 0x001c0000 | (rm << 2));
225 regmap_write(opp_info->dsu_grf, 0x18, 0x40004000);
226 udelay(1);
227 regmap_write(opp_info->dsu_grf, 0x18, 0x40000000);
228 }
229
230 opp_info->current_rm = rm;
231
232 return 0;
233 }
234
rv1126_get_soc_info(struct device * dev,struct device_node * np,int * bin,int * process)235 static int rv1126_get_soc_info(struct device *dev, struct device_node *np,
236 int *bin, int *process)
237 {
238 int ret = 0;
239 u8 value = 0;
240
241 if (of_property_match_string(np, "nvmem-cell-names", "performance") >= 0) {
242 ret = rockchip_nvmem_cell_read_u8(np, "performance", &value);
243 if (ret) {
244 dev_err(dev, "Failed to get soc performance value\n");
245 return ret;
246 }
247 if (value == 0x1)
248 *bin = 1;
249 else
250 *bin = 0;
251 }
252 if (*bin >= 0)
253 dev_info(dev, "bin=%d\n", *bin);
254
255 return ret;
256 }
257
258 static const struct rockchip_opp_data px30_cpu_opp_data = {
259 .get_soc_info = px30_get_soc_info,
260 };
261
262 static const struct rockchip_opp_data rk3288_cpu_opp_data = {
263 .get_soc_info = rk3288_get_soc_info,
264 };
265
266 static const struct rockchip_opp_data rk3399_cpu_opp_data = {
267 .get_soc_info = rk3399_get_soc_info,
268 };
269
270 static const struct rockchip_opp_data rk3588_cpu_opp_data = {
271 .set_read_margin = rk3588_cpu_set_read_margin,
272 };
273
274 static const struct rockchip_opp_data rv1126_cpu_opp_data = {
275 .get_soc_info = rv1126_get_soc_info,
276 };
277
278 static const struct of_device_id rockchip_cpufreq_of_match[] = {
279 {
280 .compatible = "rockchip,px30",
281 .data = (void *)&px30_cpu_opp_data,
282 },
283 {
284 .compatible = "rockchip,rk3288",
285 .data = (void *)&rk3288_cpu_opp_data,
286 },
287 {
288 .compatible = "rockchip,rk3288w",
289 .data = (void *)&rk3288_cpu_opp_data,
290 },
291 {
292 .compatible = "rockchip,rk3326",
293 .data = (void *)&px30_cpu_opp_data,
294 },
295 {
296 .compatible = "rockchip,rk3399",
297 .data = (void *)&rk3399_cpu_opp_data,
298 },
299 {
300 .compatible = "rockchip,rk3588",
301 .data = (void *)&rk3588_cpu_opp_data,
302 },
303 {
304 .compatible = "rockchip,rv1109",
305 .data = (void *)&rv1126_cpu_opp_data,
306 },
307 {
308 .compatible = "rockchip,rv1126",
309 .data = (void *)&rv1126_cpu_opp_data,
310 },
311 {},
312 };
313
rockchip_cluster_info_lookup(int cpu)314 static struct cluster_info *rockchip_cluster_info_lookup(int cpu)
315 {
316 struct cluster_info *cluster;
317
318 list_for_each_entry(cluster, &cluster_info_list, list_head) {
319 if (cpumask_test_cpu(cpu, &cluster->cpus))
320 return cluster;
321 }
322
323 return NULL;
324 }
325
rockchip_cpufreq_set_volt(struct device * dev,struct regulator * reg,struct dev_pm_opp_supply * supply,char * reg_name)326 static int rockchip_cpufreq_set_volt(struct device *dev,
327 struct regulator *reg,
328 struct dev_pm_opp_supply *supply,
329 char *reg_name)
330 {
331 int ret;
332
333 dev_dbg(dev, "%s: %s voltages (uV): %lu %lu %lu\n", __func__, reg_name,
334 supply->u_volt_min, supply->u_volt, supply->u_volt_max);
335
336 ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
337 supply->u_volt, supply->u_volt_max);
338 if (ret)
339 dev_err(dev, "%s: failed to set voltage (%lu %lu %lu uV): %d\n",
340 __func__, supply->u_volt_min, supply->u_volt,
341 supply->u_volt_max, ret);
342
343 return ret;
344 }
345
rockchip_cpufreq_set_read_margin(struct device * dev,struct rockchip_opp_info * opp_info,unsigned long volt)346 static int rockchip_cpufreq_set_read_margin(struct device *dev,
347 struct rockchip_opp_info *opp_info,
348 unsigned long volt)
349 {
350 if (opp_info->data && opp_info->data->set_read_margin) {
351 opp_info->data->set_read_margin(dev, opp_info, volt);
352 opp_info->volt_rm = volt;
353 }
354
355 return 0;
356 }
357
358 static int
rockchip_cpufreq_set_intermediate_rate(struct rockchip_opp_info * opp_info,struct clk * clk,unsigned long new_freq)359 rockchip_cpufreq_set_intermediate_rate(struct rockchip_opp_info *opp_info,
360 struct clk *clk, unsigned long new_freq)
361 {
362 if (opp_info->data && opp_info->data->set_read_margin)
363 return clk_set_rate(clk, new_freq | CPUFREQ_INTERMEDIATE_RATE);
364
365 return 0;
366 }
367
cpu_opp_helper(struct dev_pm_set_opp_data * data)368 static int cpu_opp_helper(struct dev_pm_set_opp_data *data)
369 {
370 struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
371 struct dev_pm_opp_supply *old_supply_mem = &data->old_opp.supplies[1];
372 struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
373 struct dev_pm_opp_supply *new_supply_mem = &data->new_opp.supplies[1];
374 struct regulator *vdd_reg = data->regulators[0];
375 struct regulator *mem_reg = data->regulators[1];
376 struct device *dev = data->dev;
377 struct clk *clk = data->clk;
378 struct cluster_info *cluster;
379 struct rockchip_opp_info *opp_info;
380 unsigned long old_freq = data->old_opp.rate;
381 unsigned long new_freq = data->new_opp.rate;
382 int ret = 0;
383
384 cluster = rockchip_cluster_info_lookup(dev->id);
385 if (!cluster)
386 return -EINVAL;
387 opp_info = &cluster->opp_info;
388
389 /* Scaling up? Scale voltage before frequency */
390 if (new_freq >= old_freq) {
391 ret = rockchip_cpufreq_set_intermediate_rate(opp_info, clk,
392 new_freq);
393 if (ret) {
394 dev_err(dev, "%s: failed to set clk rate: %lu\n",
395 __func__, new_freq);
396 return -EINVAL;
397 }
398 ret = rockchip_cpufreq_set_volt(dev, mem_reg, new_supply_mem,
399 "mem");
400 if (ret)
401 goto restore_voltage;
402 ret = rockchip_cpufreq_set_volt(dev, vdd_reg, new_supply_vdd,
403 "vdd");
404 if (ret)
405 goto restore_voltage;
406 rockchip_cpufreq_set_read_margin(dev, opp_info,
407 new_supply_vdd->u_volt);
408 }
409
410 /* Change frequency */
411 dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
412 old_freq, new_freq);
413 ret = clk_set_rate(clk, new_freq);
414 if (ret) {
415 dev_err(dev, "%s: failed to set clk rate: %d\n", __func__, ret);
416 goto restore_rm;
417 }
418
419 /* Scaling down? Scale voltage after frequency */
420 if (new_freq < old_freq) {
421 rockchip_cpufreq_set_read_margin(dev, opp_info,
422 new_supply_vdd->u_volt);
423 ret = rockchip_cpufreq_set_volt(dev, vdd_reg, new_supply_vdd,
424 "vdd");
425 if (ret)
426 goto restore_freq;
427 ret = rockchip_cpufreq_set_volt(dev, mem_reg, new_supply_mem,
428 "mem");
429 if (ret)
430 goto restore_freq;
431 }
432
433 return 0;
434
435 restore_freq:
436 if (clk_set_rate(clk, old_freq))
437 dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
438 __func__, old_freq);
439 restore_rm:
440 rockchip_cpufreq_set_read_margin(dev, opp_info,
441 old_supply_vdd->u_volt);
442 restore_voltage:
443 rockchip_cpufreq_set_volt(dev, mem_reg, old_supply_mem, "mem");
444 rockchip_cpufreq_set_volt(dev, vdd_reg, old_supply_vdd, "vdd");
445
446 return ret;
447 }
448
rockchip_cpufreq_cluster_init(int cpu,struct cluster_info * cluster)449 static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
450 {
451 struct rockchip_opp_info *opp_info = &cluster->opp_info;
452 struct opp_table *pname_table = NULL;
453 struct opp_table *reg_table = NULL;
454 struct opp_table *opp_table;
455 struct device_node *np;
456 struct device *dev;
457 const char * const reg_names[] = {"cpu", "mem"};
458 char *reg_name = NULL;
459 int bin = -EINVAL;
460 int process = -EINVAL;
461 int volt_sel = -EINVAL;
462 int ret = 0;
463
464 dev = get_cpu_device(cpu);
465 if (!dev)
466 return -ENODEV;
467
468 if (of_find_property(dev->of_node, "cpu-supply", NULL))
469 reg_name = "cpu";
470 else if (of_find_property(dev->of_node, "cpu0-supply", NULL))
471 reg_name = "cpu0";
472 else
473 return -ENOENT;
474
475 np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
476 if (!np) {
477 dev_warn(dev, "OPP-v2 not supported\n");
478 return -ENOENT;
479 }
480
481 ret = dev_pm_opp_of_get_sharing_cpus(dev, &cluster->cpus);
482 if (ret) {
483 dev_err(dev, "Failed to get sharing cpus\n");
484 goto np_err;
485 }
486
487 rockchip_get_opp_data(rockchip_cpufreq_of_match, opp_info);
488 if (opp_info->data && opp_info->data->set_read_margin) {
489 opp_info->current_rm = UINT_MAX;
490 opp_info->grf = syscon_regmap_lookup_by_phandle(np,
491 "rockchip,grf");
492 if (IS_ERR(opp_info->grf))
493 opp_info->grf = NULL;
494 opp_info->dsu_grf =
495 syscon_regmap_lookup_by_phandle(np, "rockchip,dsu-grf");
496 if (IS_ERR(opp_info->dsu_grf))
497 opp_info->dsu_grf = NULL;
498 rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
499 &opp_info->volt_rm_tbl);
500 }
501 if (opp_info->data && opp_info->data->get_soc_info)
502 opp_info->data->get_soc_info(dev, np, &bin, &process);
503 rockchip_get_scale_volt_sel(dev, "cpu_leakage", reg_name, bin, process,
504 &cluster->scale, &volt_sel);
505 pname_table = rockchip_set_opp_prop_name(dev, process, volt_sel);
506 if (IS_ERR(pname_table)) {
507 ret = PTR_ERR(pname_table);
508 goto np_err;
509 }
510
511 if (of_find_property(dev->of_node, "cpu-supply", NULL) &&
512 of_find_property(dev->of_node, "mem-supply", NULL)) {
513 reg_table = dev_pm_opp_set_regulators(dev, reg_names,
514 ARRAY_SIZE(reg_names));
515 if (IS_ERR(reg_table)) {
516 ret = PTR_ERR(reg_table);
517 goto pname_opp_table;
518 }
519 opp_table = dev_pm_opp_register_set_opp_helper(dev,
520 cpu_opp_helper);
521 if (IS_ERR(opp_table)) {
522 ret = PTR_ERR(opp_table);
523 goto reg_opp_table;
524 }
525 }
526
527 of_node_put(np);
528
529 return 0;
530
531 reg_opp_table:
532 if (reg_table)
533 dev_pm_opp_put_regulators(reg_table);
534 pname_opp_table:
535 if (pname_table)
536 dev_pm_opp_put_prop_name(pname_table);
537 np_err:
538 of_node_put(np);
539
540 return ret;
541 }
542
rockchip_cpufreq_adjust_power_scale(struct device * dev)543 int rockchip_cpufreq_adjust_power_scale(struct device *dev)
544 {
545 struct cluster_info *cluster;
546
547 cluster = rockchip_cluster_info_lookup(dev->id);
548 if (!cluster)
549 return -EINVAL;
550 rockchip_adjust_power_scale(dev, cluster->scale);
551
552 return 0;
553 }
554 EXPORT_SYMBOL_GPL(rockchip_cpufreq_adjust_power_scale);
555
rockchip_cpufreq_opp_set_rate(struct device * dev,unsigned long target_freq)556 int rockchip_cpufreq_opp_set_rate(struct device *dev, unsigned long target_freq)
557 {
558 struct cluster_info *cluster;
559 int ret = 0;
560
561 cluster = rockchip_cluster_info_lookup(dev->id);
562 if (!cluster)
563 return -EINVAL;
564
565 rockchip_monitor_volt_adjust_lock(cluster->mdev_info);
566 ret = dev_pm_opp_set_rate(dev, target_freq);
567 rockchip_monitor_volt_adjust_unlock(cluster->mdev_info);
568
569 return ret;
570 }
571 EXPORT_SYMBOL_GPL(rockchip_cpufreq_opp_set_rate);
572
rockchip_cpufreq_suspend(struct cpufreq_policy * policy)573 static int rockchip_cpufreq_suspend(struct cpufreq_policy *policy)
574 {
575 int ret = 0;
576
577 ret = cpufreq_generic_suspend(policy);
578 if (!ret)
579 rockchip_monitor_suspend_low_temp_adjust(policy->cpu);
580
581 return ret;
582 }
583
rockchip_cpufreq_notifier(struct notifier_block * nb,unsigned long event,void * data)584 static int rockchip_cpufreq_notifier(struct notifier_block *nb,
585 unsigned long event, void *data)
586 {
587 struct device *dev;
588 struct cpufreq_policy *policy = data;
589 struct cluster_info *cluster;
590 struct monitor_dev_profile *mdevp = NULL;
591 struct monitor_dev_info *mdev_info = NULL;
592
593 dev = get_cpu_device(policy->cpu);
594 if (!dev)
595 return NOTIFY_BAD;
596
597 cluster = rockchip_cluster_info_lookup(policy->cpu);
598 if (!cluster)
599 return NOTIFY_BAD;
600
601 if (event == CPUFREQ_CREATE_POLICY) {
602 mdevp = kzalloc(sizeof(*mdevp), GFP_KERNEL);
603 if (!mdevp)
604 return NOTIFY_BAD;
605 mdevp->type = MONITOR_TPYE_CPU;
606 mdevp->low_temp_adjust = rockchip_monitor_cpu_low_temp_adjust;
607 mdevp->high_temp_adjust = rockchip_monitor_cpu_high_temp_adjust;
608 mdevp->update_volt = rockchip_monitor_check_rate_volt;
609 mdevp->data = (void *)policy;
610 mdevp->opp_info = &cluster->opp_info;
611 cpumask_copy(&mdevp->allowed_cpus, policy->cpus);
612 mdev_info = rockchip_system_monitor_register(dev, mdevp);
613 if (IS_ERR(mdev_info)) {
614 kfree(mdevp);
615 dev_err(dev, "failed to register system monitor\n");
616 return NOTIFY_BAD;
617 }
618 mdev_info->devp = mdevp;
619 cluster->mdev_info = mdev_info;
620 } else if (event == CPUFREQ_REMOVE_POLICY) {
621 if (cluster->mdev_info) {
622 kfree(cluster->mdev_info->devp);
623 rockchip_system_monitor_unregister(cluster->mdev_info);
624 cluster->mdev_info = NULL;
625 }
626 }
627
628 return NOTIFY_OK;
629 }
630
631 static struct notifier_block rockchip_cpufreq_notifier_block = {
632 .notifier_call = rockchip_cpufreq_notifier,
633 };
634
rockchip_cpufreq_driver_init(void)635 static int __init rockchip_cpufreq_driver_init(void)
636 {
637 struct cluster_info *cluster, *pos;
638 struct cpufreq_dt_platform_data pdata = {0};
639 int cpu, ret;
640
641 for_each_possible_cpu(cpu) {
642 cluster = rockchip_cluster_info_lookup(cpu);
643 if (cluster)
644 continue;
645
646 cluster = kzalloc(sizeof(*cluster), GFP_KERNEL);
647 if (!cluster) {
648 ret = -ENOMEM;
649 goto release_cluster_info;
650 }
651
652 ret = rockchip_cpufreq_cluster_init(cpu, cluster);
653 if (ret) {
654 pr_err("Failed to initialize dvfs info cpu%d\n", cpu);
655 goto release_cluster_info;
656 }
657 list_add(&cluster->list_head, &cluster_info_list);
658 }
659
660 pdata.have_governor_per_policy = true;
661 pdata.suspend = rockchip_cpufreq_suspend;
662
663 ret = cpufreq_register_notifier(&rockchip_cpufreq_notifier_block,
664 CPUFREQ_POLICY_NOTIFIER);
665 if (ret) {
666 pr_err("failed to register cpufreq notifier\n");
667 goto release_cluster_info;
668 }
669
670 return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt",
671 -1, (void *)&pdata,
672 sizeof(struct cpufreq_dt_platform_data)));
673
674 release_cluster_info:
675 list_for_each_entry_safe(cluster, pos, &cluster_info_list, list_head) {
676 list_del(&cluster->list_head);
677 kfree(cluster);
678 }
679 return ret;
680 }
681 module_init(rockchip_cpufreq_driver_init);
682
683 MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
684 MODULE_DESCRIPTION("Rockchip cpufreq driver");
685 MODULE_LICENSE("GPL v2");
686