arm: thermal: Removed nonTEGRA_THERMAL_SYSFS logic
[linux-3.10.git] / arch / arm / mach-tegra / tegra3_throttle.c
1 /*
2  * arch/arm/mach-tegra/tegra3_throttle.c
3  *
4  * Copyright (c) 2011, NVIDIA Corporation.
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 as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/cpufreq.h>
22 #include <linux/delay.h>
23 #include <linux/init.h>
24 #include <linux/err.h>
25 #include <linux/clk.h>
26 #include <linux/debugfs.h>
27 #include <linux/seq_file.h>
28 #include <linux/uaccess.h>
29 #include <linux/thermal.h>
30
31 #include "clock.h"
32 #include "cpu-tegra.h"
33 #include "dvfs.h"
34
35 /* tegra throttling require frequencies in the table to be in ascending order */
36 static struct cpufreq_frequency_table *cpu_freq_table;
37
38 static struct {
39         unsigned int cpu_freq;
40         int core_cap_level;
41 } throttle_table[] = {
42         {      0, 1000 },       /* placeholder for cpu floor rate */
43         { 640000, 1000 },
44         { 640000, 1000 },
45         { 640000, 1000 },
46         { 640000, 1000 },
47         { 640000, 1000 },
48         { 760000, 1000 },
49         { 760000, 1050 },
50         {1000000, 1050 },
51         {1000000, 1100 },
52 };
53
54 static int is_throttling;
55 static int throttle_index;
56 static struct thermal_cooling_device *cdev;
57
58 static unsigned int clip_to_table(unsigned int cpu_freq)
59 {
60         int i;
61
62         for (i = 0; cpu_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
63                 if (cpu_freq_table[i].frequency > cpu_freq)
64                         break;
65         }
66         i = (i == 0) ? 0 : i-1;
67         return cpu_freq_table[i].frequency;
68 }
69
70 unsigned int tegra_throttle_governor_speed(unsigned int requested_speed)
71 {
72         return is_throttling ?
73                 min(requested_speed, throttle_table[throttle_index].cpu_freq) :
74                 requested_speed;
75 }
76
77 bool tegra_is_throttling(void)
78 {
79         return is_throttling;
80 }
81
82 static int
83 tegra_throttle_get_max_state(struct thermal_cooling_device *cdev,
84                                 unsigned long *max_state)
85 {
86         *max_state = ARRAY_SIZE(throttle_table);
87         return 0;
88 }
89
90 static int
91 tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev,
92                                 unsigned long *cur_state)
93 {
94         *cur_state = is_throttling ?
95                         (ARRAY_SIZE(throttle_table) - throttle_index) :
96                         0;
97
98         return 0;
99 }
100
101 static int
102 tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
103                                 unsigned long cur_state)
104 {
105         int core_level;
106
107         if (cur_state == 0) {
108                 /* restore speed requested by governor */
109                 if (is_throttling) {
110                         tegra_dvfs_core_cap_enable(false);
111                         is_throttling = false;
112                 }
113
114                 tegra_cpu_set_speed_cap(NULL);
115         } else {
116                 if (!is_throttling) {
117                         tegra_dvfs_core_cap_enable(true);
118                         is_throttling = true;
119                 }
120
121                 throttle_index = ARRAY_SIZE(throttle_table) - cur_state;
122                 core_level = throttle_table[throttle_index].core_cap_level;
123                 tegra_dvfs_core_cap_level_set(core_level);
124
125                 tegra_cpu_set_speed_cap(NULL);
126         }
127
128
129         return 0;
130 }
131
132 struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
133         .get_max_state = tegra_throttle_get_max_state,
134         .get_cur_state = tegra_throttle_get_cur_state,
135         .set_cur_state = tegra_throttle_set_cur_state,
136 };
137
138 int __init tegra_throttle_init(struct mutex *cpu_lock)
139 {
140         int i;
141         struct tegra_cpufreq_table_data *table_data =
142                 tegra_cpufreq_table_get();
143         if (IS_ERR_OR_NULL(table_data))
144                 return -EINVAL;
145
146         cpu_freq_table = table_data->freq_table;
147         throttle_table[0].cpu_freq =
148                 cpu_freq_table[table_data->throttle_lowest_index].frequency;
149
150         for (i = 0; i < ARRAY_SIZE(throttle_table); i++) {
151                 unsigned int cpu_freq = throttle_table[i].cpu_freq;
152                 throttle_table[i].cpu_freq = clip_to_table(cpu_freq);
153         }
154
155         cdev = thermal_cooling_device_register("Throttle", NULL,
156                                                 &tegra_throttle_cooling_ops);
157
158         if (IS_ERR(cdev)) {
159                 cdev = NULL;
160                 return -ENODEV;
161         }
162
163         return 0;
164 }
165
166 void tegra_throttle_exit(void)
167 {
168         if (cdev) {
169                 thermal_cooling_device_unregister(cdev);
170                 cdev = NULL;
171         }
172 }
173
174 #ifdef CONFIG_DEBUG_FS
175 static int table_show(struct seq_file *s, void *data)
176 {
177         int i;
178
179         for (i = 0; i < ARRAY_SIZE(throttle_table); i++)
180                 seq_printf(s, "[%d] = %7u %4d\n",
181                         i, throttle_table[i].cpu_freq,
182                         throttle_table[i].core_cap_level);
183         return 0;
184 }
185
186 static int table_open(struct inode *inode, struct file *file)
187 {
188         return single_open(file, table_show, inode->i_private);
189 }
190
191 static ssize_t table_write(struct file *file,
192         const char __user *userbuf, size_t count, loff_t *ppos)
193 {
194         char buf[80];
195         int table_idx;
196         unsigned int cpu_freq;
197         int core_cap_level;
198
199         if (sizeof(buf) <= count)
200                 return -EINVAL;
201
202         if (copy_from_user(buf, userbuf, count))
203                 return -EFAULT;
204
205         /* terminate buffer and trim - white spaces may be appended
206          *  at the end when invoked from shell command line */
207         buf[count] = '\0';
208         strim(buf);
209
210         if (sscanf(buf, "[%d] = %u %d",
211                    &table_idx, &cpu_freq, &core_cap_level) != 3)
212                 return -1;
213
214         if ((table_idx < 0) || (table_idx >= ARRAY_SIZE(throttle_table)))
215                 return -EINVAL;
216
217         /* round new settings before updating table */
218         throttle_table[table_idx].cpu_freq = clip_to_table(cpu_freq);
219         throttle_table[table_idx].core_cap_level = (core_cap_level / 50) * 50;
220
221         return count;
222 }
223
224 static const struct file_operations table_fops = {
225         .open           = table_open,
226         .read           = seq_read,
227         .write          = table_write,
228         .llseek         = seq_lseek,
229         .release        = single_release,
230 };
231
232
233 int __init tegra_throttle_debug_init(struct dentry *cpu_tegra_debugfs_root)
234 {
235         if (!debugfs_create_file("throttle_table", 0644, cpu_tegra_debugfs_root,
236                                  NULL, &table_fops))
237                 return -ENOMEM;
238
239         return 0;
240 }
241 #endif /* CONFIG_DEBUG_FS */
242