Commit | Line | Data |
---|---|---|
8a67f0ef VK |
1 | /* |
2 | * Generic big.LITTLE CPUFreq Interface driver | |
3 | * | |
4 | * It provides necessary ops to arm_big_little cpufreq driver and gets | |
5 | * Frequency information from Device Tree. Freq table in DT must be in KHz. | |
6 | * | |
7 | * Copyright (C) 2013 Linaro. | |
8 | * Viresh Kumar <viresh.kumar@linaro.org> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
15 | * kind, whether express or implied; without even the implied warranty | |
16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | */ | |
19 | ||
20 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
21 | ||
92a9b5c2 | 22 | #include <linux/cpu.h> |
8a67f0ef VK |
23 | #include <linux/cpufreq.h> |
24 | #include <linux/device.h> | |
25 | #include <linux/export.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/of.h> | |
28 | #include <linux/opp.h> | |
9076eaca | 29 | #include <linux/platform_device.h> |
8a67f0ef VK |
30 | #include <linux/slab.h> |
31 | #include <linux/types.h> | |
32 | #include "arm_big_little.h" | |
33 | ||
92a9b5c2 VK |
34 | /* get cpu node with valid operating-points */ |
35 | static struct device_node *get_cpu_node_with_valid_op(int cpu) | |
8a67f0ef | 36 | { |
92a9b5c2 VK |
37 | struct device_node *np = NULL, *parent; |
38 | int count = 0; | |
8a67f0ef | 39 | |
763f8c3f VK |
40 | parent = of_find_node_by_path("/cpus"); |
41 | if (!parent) { | |
42 | pr_err("failed to find OF /cpus\n"); | |
92a9b5c2 | 43 | return NULL; |
763f8c3f VK |
44 | } |
45 | ||
46 | for_each_child_of_node(parent, np) { | |
92a9b5c2 | 47 | if (count++ != cpu) |
8a67f0ef | 48 | continue; |
763f8c3f | 49 | if (!of_get_property(np, "operating-points", NULL)) { |
92a9b5c2 VK |
50 | of_node_put(np); |
51 | np = NULL; | |
763f8c3f | 52 | } |
763f8c3f | 53 | |
92a9b5c2 | 54 | break; |
8a67f0ef VK |
55 | } |
56 | ||
92a9b5c2 VK |
57 | of_node_put(parent); |
58 | return np; | |
59 | } | |
60 | ||
61 | static int dt_init_opp_table(struct device *cpu_dev) | |
62 | { | |
63 | struct device_node *np; | |
64 | int ret; | |
65 | ||
66 | np = get_cpu_node_with_valid_op(cpu_dev->id); | |
67 | if (!np) | |
68 | return -ENODATA; | |
69 | ||
70 | cpu_dev->of_node = np; | |
71 | ret = of_init_opp_table(cpu_dev); | |
72 | of_node_put(np); | |
73 | ||
74 | return ret; | |
8a67f0ef VK |
75 | } |
76 | ||
77 | static int dt_get_transition_latency(struct device *cpu_dev) | |
78 | { | |
92a9b5c2 | 79 | struct device_node *np; |
8a67f0ef | 80 | u32 transition_latency = CPUFREQ_ETERNAL; |
8a67f0ef | 81 | |
92a9b5c2 VK |
82 | np = get_cpu_node_with_valid_op(cpu_dev->id); |
83 | if (!np) | |
3c792e0f | 84 | return CPUFREQ_ETERNAL; |
763f8c3f | 85 | |
92a9b5c2 VK |
86 | of_property_read_u32(np, "clock-latency", &transition_latency); |
87 | of_node_put(np); | |
8a67f0ef | 88 | |
92a9b5c2 VK |
89 | pr_debug("%s: clock-latency: %d\n", __func__, transition_latency); |
90 | return transition_latency; | |
8a67f0ef VK |
91 | } |
92 | ||
93 | static struct cpufreq_arm_bL_ops dt_bL_ops = { | |
94 | .name = "dt-bl", | |
95 | .get_transition_latency = dt_get_transition_latency, | |
96 | .init_opp_table = dt_init_opp_table, | |
97 | }; | |
98 | ||
9076eaca | 99 | static int generic_bL_probe(struct platform_device *pdev) |
8a67f0ef | 100 | { |
92a9b5c2 VK |
101 | struct device_node *np; |
102 | ||
103 | np = get_cpu_node_with_valid_op(0); | |
104 | if (!np) | |
105 | return -ENODEV; | |
106 | ||
107 | of_node_put(np); | |
8a67f0ef VK |
108 | return bL_cpufreq_register(&dt_bL_ops); |
109 | } | |
8a67f0ef | 110 | |
9076eaca | 111 | static int generic_bL_remove(struct platform_device *pdev) |
8a67f0ef | 112 | { |
9076eaca VK |
113 | bL_cpufreq_unregister(&dt_bL_ops); |
114 | return 0; | |
8a67f0ef | 115 | } |
9076eaca VK |
116 | |
117 | static struct platform_driver generic_bL_platdrv = { | |
118 | .driver = { | |
119 | .name = "arm-bL-cpufreq-dt", | |
120 | .owner = THIS_MODULE, | |
121 | }, | |
122 | .probe = generic_bL_probe, | |
123 | .remove = generic_bL_remove, | |
124 | }; | |
125 | module_platform_driver(generic_bL_platdrv); | |
8a67f0ef VK |
126 | |
127 | MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>"); | |
128 | MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT"); | |
129 | MODULE_LICENSE("GPL"); |