diff options
author | Pi-Cheng Chen <pi-cheng.chen@linaro.org> | 2015-12-09 22:48:13 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-12-11 20:27:16 -0500 |
commit | 89b56047f6f9b15fa3e9df3e34fa391835972ab7 (patch) | |
tree | 6bb8490762da6fd7905d586aebb4cad80a2988d1 | |
parent | 63d1d656a5232f2f189b217b50542eadcf9d74ae (diff) |
cpufreq: mt8173: Move resources allocation into ->probe()
Since the return value of ->init() of cpufreq driver is not propagated
to the device driver model now, move resources allocation into
->probe() to handle -EPROBE_DEFER properly.
Signed-off-by: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/cpufreq/mt8173-cpufreq.c | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index 9d0fe37b4c3e..fd601b92f5ec 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c | |||
@@ -41,16 +41,35 @@ | |||
41 | * the original PLL becomes stable at target frequency. | 41 | * the original PLL becomes stable at target frequency. |
42 | */ | 42 | */ |
43 | struct mtk_cpu_dvfs_info { | 43 | struct mtk_cpu_dvfs_info { |
44 | struct cpumask cpus; | ||
44 | struct device *cpu_dev; | 45 | struct device *cpu_dev; |
45 | struct regulator *proc_reg; | 46 | struct regulator *proc_reg; |
46 | struct regulator *sram_reg; | 47 | struct regulator *sram_reg; |
47 | struct clk *cpu_clk; | 48 | struct clk *cpu_clk; |
48 | struct clk *inter_clk; | 49 | struct clk *inter_clk; |
49 | struct thermal_cooling_device *cdev; | 50 | struct thermal_cooling_device *cdev; |
51 | struct list_head list_head; | ||
50 | int intermediate_voltage; | 52 | int intermediate_voltage; |
51 | bool need_voltage_tracking; | 53 | bool need_voltage_tracking; |
52 | }; | 54 | }; |
53 | 55 | ||
56 | static LIST_HEAD(dvfs_info_list); | ||
57 | |||
58 | static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu) | ||
59 | { | ||
60 | struct mtk_cpu_dvfs_info *info; | ||
61 | struct list_head *list; | ||
62 | |||
63 | list_for_each(list, &dvfs_info_list) { | ||
64 | info = list_entry(list, struct mtk_cpu_dvfs_info, list_head); | ||
65 | |||
66 | if (cpumask_test_cpu(cpu, &info->cpus)) | ||
67 | return info; | ||
68 | } | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
54 | static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, | 73 | static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, |
55 | int new_vproc) | 74 | int new_vproc) |
56 | { | 75 | { |
@@ -402,6 +421,9 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) | |||
402 | */ | 421 | */ |
403 | info->need_voltage_tracking = !IS_ERR(sram_reg); | 422 | info->need_voltage_tracking = !IS_ERR(sram_reg); |
404 | 423 | ||
424 | /* CPUs in the same cluster share a clock and power domain. */ | ||
425 | cpumask_copy(&info->cpus, &cpu_topology[cpu].core_sibling); | ||
426 | |||
405 | return 0; | 427 | return 0; |
406 | 428 | ||
407 | out_free_opp_table: | 429 | out_free_opp_table: |
@@ -440,22 +462,18 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) | |||
440 | struct cpufreq_frequency_table *freq_table; | 462 | struct cpufreq_frequency_table *freq_table; |
441 | int ret; | 463 | int ret; |
442 | 464 | ||
443 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 465 | info = mtk_cpu_dvfs_info_lookup(policy->cpu); |
444 | if (!info) | 466 | if (!info) { |
445 | return -ENOMEM; | 467 | pr_err("dvfs info for cpu%d is not initialized.\n", |
446 | 468 | policy->cpu); | |
447 | ret = mtk_cpu_dvfs_info_init(info, policy->cpu); | 469 | return -EINVAL; |
448 | if (ret) { | ||
449 | pr_err("%s failed to initialize dvfs info for cpu%d\n", | ||
450 | __func__, policy->cpu); | ||
451 | goto out_free_dvfs_info; | ||
452 | } | 470 | } |
453 | 471 | ||
454 | ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table); | 472 | ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table); |
455 | if (ret) { | 473 | if (ret) { |
456 | pr_err("failed to init cpufreq table for cpu%d: %d\n", | 474 | pr_err("failed to init cpufreq table for cpu%d: %d\n", |
457 | policy->cpu, ret); | 475 | policy->cpu, ret); |
458 | goto out_release_dvfs_info; | 476 | return ret; |
459 | } | 477 | } |
460 | 478 | ||
461 | ret = cpufreq_table_validate_and_show(policy, freq_table); | 479 | ret = cpufreq_table_validate_and_show(policy, freq_table); |
@@ -464,8 +482,7 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) | |||
464 | goto out_free_cpufreq_table; | 482 | goto out_free_cpufreq_table; |
465 | } | 483 | } |
466 | 484 | ||
467 | /* CPUs in the same cluster share a clock and power domain. */ | 485 | cpumask_copy(policy->cpus, &info->cpus); |
468 | cpumask_copy(policy->cpus, &cpu_topology[policy->cpu].core_sibling); | ||
469 | policy->driver_data = info; | 486 | policy->driver_data = info; |
470 | policy->clk = info->cpu_clk; | 487 | policy->clk = info->cpu_clk; |
471 | 488 | ||
@@ -473,13 +490,6 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) | |||
473 | 490 | ||
474 | out_free_cpufreq_table: | 491 | out_free_cpufreq_table: |
475 | dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table); | 492 | dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table); |
476 | |||
477 | out_release_dvfs_info: | ||
478 | mtk_cpu_dvfs_info_release(info); | ||
479 | |||
480 | out_free_dvfs_info: | ||
481 | kfree(info); | ||
482 | |||
483 | return ret; | 493 | return ret; |
484 | } | 494 | } |
485 | 495 | ||
@@ -489,8 +499,6 @@ static int mtk_cpufreq_exit(struct cpufreq_policy *policy) | |||
489 | 499 | ||
490 | cpufreq_cooling_unregister(info->cdev); | 500 | cpufreq_cooling_unregister(info->cdev); |
491 | dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); | 501 | dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); |
492 | mtk_cpu_dvfs_info_release(info); | ||
493 | kfree(info); | ||
494 | 502 | ||
495 | return 0; | 503 | return 0; |
496 | } | 504 | } |
@@ -510,11 +518,47 @@ static struct cpufreq_driver mt8173_cpufreq_driver = { | |||
510 | 518 | ||
511 | static int mt8173_cpufreq_probe(struct platform_device *pdev) | 519 | static int mt8173_cpufreq_probe(struct platform_device *pdev) |
512 | { | 520 | { |
513 | int ret; | 521 | struct mtk_cpu_dvfs_info *info; |
522 | struct list_head *list, *tmp; | ||
523 | int cpu, ret; | ||
524 | |||
525 | for_each_possible_cpu(cpu) { | ||
526 | info = mtk_cpu_dvfs_info_lookup(cpu); | ||
527 | if (info) | ||
528 | continue; | ||
529 | |||
530 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | ||
531 | if (!info) { | ||
532 | ret = -ENOMEM; | ||
533 | goto release_dvfs_info_list; | ||
534 | } | ||
535 | |||
536 | ret = mtk_cpu_dvfs_info_init(info, cpu); | ||
537 | if (ret) { | ||
538 | dev_err(&pdev->dev, | ||
539 | "failed to initialize dvfs info for cpu%d\n", | ||
540 | cpu); | ||
541 | goto release_dvfs_info_list; | ||
542 | } | ||
543 | |||
544 | list_add(&info->list_head, &dvfs_info_list); | ||
545 | } | ||
514 | 546 | ||
515 | ret = cpufreq_register_driver(&mt8173_cpufreq_driver); | 547 | ret = cpufreq_register_driver(&mt8173_cpufreq_driver); |
516 | if (ret) | 548 | if (ret) { |
517 | pr_err("failed to register mtk cpufreq driver\n"); | 549 | dev_err(&pdev->dev, "failed to register mtk cpufreq driver\n"); |
550 | goto release_dvfs_info_list; | ||
551 | } | ||
552 | |||
553 | return 0; | ||
554 | |||
555 | release_dvfs_info_list: | ||
556 | list_for_each_safe(list, tmp, &dvfs_info_list) { | ||
557 | info = list_entry(list, struct mtk_cpu_dvfs_info, list_head); | ||
558 | |||
559 | mtk_cpu_dvfs_info_release(info); | ||
560 | list_del(list); | ||
561 | } | ||
518 | 562 | ||
519 | return ret; | 563 | return ret; |
520 | } | 564 | } |