blob: 00df613b1bad2d196544cd6ff8e30019a5607255 [file] [log] [blame]
Praveen Chidambaram0c6ab952013-02-07 17:47:16 -07001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/module.h>
Jennifer Liu4ff40942013-07-30 15:25:46 -070017#include <linux/kthread.h>
Praveen Chidambaramf248bb72012-01-20 11:38:44 -070018#include <linux/mutex.h>
19#include <linux/msm_tsens.h>
20#include <linux/workqueue.h>
Jennifer Liu4ff40942013-07-30 15:25:46 -070021#include <linux/completion.h>
Eugene Seah7d6d2732012-03-09 17:48:42 -070022#include <linux/cpu.h>
Praveen Chidambaram91814362012-05-25 17:36:07 -060023#include <linux/cpufreq.h>
24#include <linux/msm_tsens.h>
25#include <linux/msm_thermal.h>
Eugene Seahb77b0c42012-07-02 19:28:50 -060026#include <linux/platform_device.h>
27#include <linux/of.h>
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070028#include <linux/err.h>
29#include <linux/slab.h>
30#include <linux/of.h>
31#include <linux/sysfs.h>
32#include <linux/types.h>
Archana Sathyakumar143b0b52013-04-09 14:24:32 -060033#include <linux/android_alarm.h>
Jennifer Liu4ff40942013-07-30 15:25:46 -070034#include <linux/thermal.h>
Praveen Chidambaram91814362012-05-25 17:36:07 -060035#include <mach/cpufreq.h>
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070036#include <mach/rpm-regulator.h>
37#include <mach/rpm-regulator-smd.h>
38#include <linux/regulator/consumer.h>
Praveen Chidambaramf248bb72012-01-20 11:38:44 -070039
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070040#define MAX_RAILS 5
41
Praveen Chidambaram91814362012-05-25 17:36:07 -060042static struct msm_thermal_data msm_thermal_info;
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -070043static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
Praveen Chidambaramf248bb72012-01-20 11:38:44 -070044static struct delayed_work check_temp_work;
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -070045static bool core_control_enabled;
46static uint32_t cpus_offlined;
47static DEFINE_MUTEX(core_control_mutex);
Archana Sathyakumar143b0b52013-04-09 14:24:32 -060048static uint32_t wakeup_ms;
49static struct alarm thermal_rtc;
50static struct kobject *tt_kobj;
Jennifer Liu4ff40942013-07-30 15:25:46 -070051static struct kobject *cc_kobj;
Archana Sathyakumar143b0b52013-04-09 14:24:32 -060052static struct work_struct timer_work;
Jennifer Liu4ff40942013-07-30 15:25:46 -070053static struct task_struct *hotplug_task;
54static struct completion hotplug_notify_complete;
Praveen Chidambaramf248bb72012-01-20 11:38:44 -070055
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070056static int enabled;
57static int rails_cnt;
Jennifer Liu907922c2013-03-26 11:18:00 -070058static int psm_rails_cnt;
Eugene Seah2ee4a5d2012-06-25 18:16:41 -060059static int limit_idx;
60static int limit_idx_low;
61static int limit_idx_high;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070062static int max_tsens_num;
Eugene Seah2ee4a5d2012-06-25 18:16:41 -060063static struct cpufreq_frequency_table *table;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070064static uint32_t usefreq;
65static int freq_table_get;
66static bool vdd_rstr_enabled;
67static bool vdd_rstr_nodes_called;
68static bool vdd_rstr_probed;
Jennifer Liu907922c2013-03-26 11:18:00 -070069static bool psm_enabled;
70static bool psm_nodes_called;
71static bool psm_probed;
Jennifer Liu5a3518c2013-04-17 11:53:51 -070072static int *tsens_id_map;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070073static DEFINE_MUTEX(vdd_rstr_mutex);
Jennifer Liu907922c2013-03-26 11:18:00 -070074static DEFINE_MUTEX(psm_mutex);
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070075
Jennifer Liu4ff40942013-07-30 15:25:46 -070076struct cpu_info {
77 uint32_t cpu;
78 bool offline;
79 bool user_offline;
80 const char *sensor_type;
81 struct sensor_threshold thresh[2];
82};
83
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070084struct rail {
85 const char *name;
86 uint32_t freq_req;
87 uint32_t min_level;
88 uint32_t num_levels;
Jennifer Liu273d2962013-04-19 11:43:04 -070089 int32_t curr_level;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -070090 uint32_t levels[3];
91 struct kobj_attribute value_attr;
92 struct kobj_attribute level_attr;
93 struct regulator *reg;
94 struct attribute_group attr_gp;
95};
Jennifer Liu907922c2013-03-26 11:18:00 -070096
97struct psm_rail {
98 const char *name;
99 uint8_t init;
100 uint8_t mode;
101 struct kobj_attribute mode_attr;
102 struct rpm_regulator *reg;
103 struct attribute_group attr_gp;
104};
105
106static struct psm_rail *psm_rails;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700107static struct rail *rails;
Jennifer Liu4ff40942013-07-30 15:25:46 -0700108static struct cpu_info cpus[NR_CPUS];
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700109
110struct vdd_rstr_enable {
111 struct kobj_attribute ko_attr;
112 uint32_t enabled;
113};
114
Jennifer Liu907922c2013-03-26 11:18:00 -0700115/* For SMPS only*/
116enum PMIC_SW_MODE {
117 PMIC_AUTO_MODE = RPM_REGULATOR_MODE_AUTO,
118 PMIC_IPEAK_MODE = RPM_REGULATOR_MODE_IPEAK,
119 PMIC_PWM_MODE = RPM_REGULATOR_MODE_HPM,
120};
121
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700122#define VDD_RES_RO_ATTRIB(_rail, ko_attr, j, _name) \
123 ko_attr.attr.name = __stringify(_name); \
124 ko_attr.attr.mode = 444; \
125 ko_attr.show = vdd_rstr_reg_##_name##_show; \
126 ko_attr.store = NULL; \
Stephen Boyd1205f7f2013-04-25 10:16:28 -0700127 sysfs_attr_init(&ko_attr.attr); \
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700128 _rail.attr_gp.attrs[j] = &ko_attr.attr;
129
130#define VDD_RES_RW_ATTRIB(_rail, ko_attr, j, _name) \
131 ko_attr.attr.name = __stringify(_name); \
132 ko_attr.attr.mode = 644; \
133 ko_attr.show = vdd_rstr_reg_##_name##_show; \
134 ko_attr.store = vdd_rstr_reg_##_name##_store; \
Stephen Boyd1205f7f2013-04-25 10:16:28 -0700135 sysfs_attr_init(&ko_attr.attr); \
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700136 _rail.attr_gp.attrs[j] = &ko_attr.attr;
137
138#define VDD_RSTR_ENABLE_FROM_ATTRIBS(attr) \
139 (container_of(attr, struct vdd_rstr_enable, ko_attr));
140
141#define VDD_RSTR_REG_VALUE_FROM_ATTRIBS(attr) \
142 (container_of(attr, struct rail, value_attr));
143
144#define VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr) \
145 (container_of(attr, struct rail, level_attr));
Jennifer Liu907922c2013-03-26 11:18:00 -0700146
147#define PSM_RW_ATTRIB(_rail, ko_attr, j, _name) \
148 ko_attr.attr.name = __stringify(_name); \
149 ko_attr.attr.mode = 644; \
150 ko_attr.show = psm_reg_##_name##_show; \
151 ko_attr.store = psm_reg_##_name##_store; \
Stephen Boyd1205f7f2013-04-25 10:16:28 -0700152 sysfs_attr_init(&ko_attr.attr); \
Jennifer Liu907922c2013-03-26 11:18:00 -0700153 _rail.attr_gp.attrs[j] = &ko_attr.attr;
154
155#define PSM_REG_MODE_FROM_ATTRIBS(attr) \
156 (container_of(attr, struct psm_rail, mode_attr));
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700157/* If freq table exists, then we can send freq request */
158static int check_freq_table(void)
159{
160 int ret = 0;
161 struct cpufreq_frequency_table *table = NULL;
162
163 table = cpufreq_frequency_get_table(0);
164 if (!table) {
165 pr_debug("%s: error reading cpufreq table\n", __func__);
166 return -EINVAL;
167 }
168 freq_table_get = 1;
169
170 return ret;
171}
172
173static int update_cpu_min_freq_all(uint32_t min)
174{
175 int cpu = 0;
176 int ret = 0;
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700177 struct cpufreq_policy *policy = NULL;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700178
179 if (!freq_table_get) {
180 ret = check_freq_table();
181 if (ret) {
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700182 pr_err("%s:Fail to get freq table\n", __func__);
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700183 return ret;
184 }
185 }
186 /* If min is larger than allowed max */
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700187 if (min != MSM_CPUFREQ_NO_LIMIT &&
188 min > table[limit_idx_high].frequency)
189 min = table[limit_idx_high].frequency;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700190
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700191 for_each_possible_cpu(cpu) {
192 ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
193 if (ret) {
194 pr_err("%s:Fail to set limits for cpu%d\n",
195 __func__, cpu);
196 return ret;
197 }
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700198
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700199 if (cpu_online(cpu)) {
200 policy = cpufreq_cpu_get(cpu);
201 if (!policy)
202 continue;
203 cpufreq_driver_target(policy, policy->cur,
204 CPUFREQ_RELATION_L);
205 cpufreq_cpu_put(policy);
206 }
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700207 }
208
209 return ret;
210}
211
212static int vdd_restriction_apply_freq(struct rail *r, int level)
213{
214 int ret = 0;
215
Jennifer Liu273d2962013-04-19 11:43:04 -0700216 if (level == r->curr_level)
217 return ret;
218
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700219 /* level = -1: disable, level = 0,1,2..n: enable */
220 if (level == -1) {
221 ret = update_cpu_min_freq_all(r->min_level);
222 if (ret)
223 return ret;
224 else
225 r->curr_level = -1;
226 } else if (level >= 0 && level < (r->num_levels)) {
227 ret = update_cpu_min_freq_all(r->levels[level]);
228 if (ret)
229 return ret;
230 else
231 r->curr_level = level;
232 } else {
233 pr_err("level input:%d is not within range\n", level);
234 return -EINVAL;
235 }
236
237 return ret;
238}
239
240static int vdd_restriction_apply_voltage(struct rail *r, int level)
241{
242 int ret = 0;
243
244 if (r->reg == NULL) {
245 pr_info("Do not have regulator handle:%s, can't apply vdd\n",
246 r->name);
247 return -EFAULT;
248 }
Jennifer Liu273d2962013-04-19 11:43:04 -0700249 if (level == r->curr_level)
250 return ret;
251
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700252 /* level = -1: disable, level = 0,1,2..n: enable */
253 if (level == -1) {
254 ret = regulator_set_voltage(r->reg, r->min_level,
255 r->levels[r->num_levels - 1]);
256 if (!ret)
257 r->curr_level = -1;
258 } else if (level >= 0 && level < (r->num_levels)) {
259 ret = regulator_set_voltage(r->reg, r->levels[level],
260 r->levels[r->num_levels - 1]);
261 if (!ret)
262 r->curr_level = level;
263 } else {
264 pr_err("level input:%d is not within range\n", level);
265 return -EINVAL;
266 }
267
268 return ret;
269}
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700270
Jennifer Liu907922c2013-03-26 11:18:00 -0700271/* Setting all rails the same mode */
272static int psm_set_mode_all(int mode)
273{
274 int i = 0;
275 int fail_cnt = 0;
276 int ret = 0;
277
278 for (i = 0; i < psm_rails_cnt; i++) {
279 if (psm_rails[i].mode != mode) {
280 ret = rpm_regulator_set_mode(psm_rails[i].reg, mode);
281 if (ret) {
282 pr_err("Cannot set mode:%d for %s",
283 mode, psm_rails[i].name);
284 fail_cnt++;
285 } else
286 psm_rails[i].mode = mode;
287 }
288 }
289
290 return fail_cnt ? (-EFAULT) : ret;
291}
292
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700293static int vdd_rstr_en_show(
294 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
295{
296 struct vdd_rstr_enable *en = VDD_RSTR_ENABLE_FROM_ATTRIBS(attr);
297
298 return snprintf(buf, PAGE_SIZE, "%d\n", en->enabled);
299}
300
301static ssize_t vdd_rstr_en_store(struct kobject *kobj,
302 struct kobj_attribute *attr, const char *buf, size_t count)
303{
304 int ret = 0;
305 int i = 0;
306 uint8_t en_cnt = 0;
307 uint8_t dis_cnt = 0;
308 uint32_t val = 0;
309 struct kernel_param kp;
310 struct vdd_rstr_enable *en = VDD_RSTR_ENABLE_FROM_ATTRIBS(attr);
311
312 mutex_lock(&vdd_rstr_mutex);
313 kp.arg = &val;
314 ret = param_set_bool(buf, &kp);
315 if (ret) {
316 pr_err("Invalid input %s for enabled\n", buf);
317 goto done_vdd_rstr_en;
318 }
319
320 if ((val == 0) && (en->enabled == 0))
321 goto done_vdd_rstr_en;
322
323 for (i = 0; i < rails_cnt; i++) {
324 if (rails[i].freq_req == 1 && freq_table_get)
325 ret = vdd_restriction_apply_freq(&rails[i],
326 (val) ? 0 : -1);
327 else
328 ret = vdd_restriction_apply_voltage(&rails[i],
329 (val) ? 0 : -1);
330
Jennifer Liu273d2962013-04-19 11:43:04 -0700331 /*
332 * Even if fail to set one rail, still try to set the
333 * others. Continue the loop
334 */
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700335 if (ret)
336 pr_err("Set vdd restriction for %s failed\n",
337 rails[i].name);
338 else {
339 if (val)
340 en_cnt++;
341 else
342 dis_cnt++;
343 }
344 }
345 /* As long as one rail is enabled, vdd rstr is enabled */
346 if (val && en_cnt)
347 en->enabled = 1;
348 else if (!val && (dis_cnt == rails_cnt))
349 en->enabled = 0;
350
351done_vdd_rstr_en:
352 mutex_unlock(&vdd_rstr_mutex);
353 return count;
354}
355
356static struct vdd_rstr_enable vdd_rstr_en = {
357 .ko_attr.attr.name = __stringify(enabled),
358 .ko_attr.attr.mode = 644,
359 .ko_attr.show = vdd_rstr_en_show,
360 .ko_attr.store = vdd_rstr_en_store,
361 .enabled = 1,
362};
363
364static struct attribute *vdd_rstr_en_attribs[] = {
365 &vdd_rstr_en.ko_attr.attr,
366 NULL,
367};
368
369static struct attribute_group vdd_rstr_en_attribs_gp = {
370 .attrs = vdd_rstr_en_attribs,
371};
372
373static int vdd_rstr_reg_value_show(
374 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
375{
376 int val = 0;
377 struct rail *reg = VDD_RSTR_REG_VALUE_FROM_ATTRIBS(attr);
378 /* -1:disabled, -2:fail to get regualtor handle */
379 if (reg->curr_level < 0)
380 val = reg->curr_level;
381 else
382 val = reg->levels[reg->curr_level];
383
Jennifer Liu273d2962013-04-19 11:43:04 -0700384 return snprintf(buf, PAGE_SIZE, "%d\n", val);
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700385}
386
387static int vdd_rstr_reg_level_show(
388 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
389{
390 struct rail *reg = VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr);
391 return snprintf(buf, PAGE_SIZE, "%d\n", reg->curr_level);
392}
393
394static ssize_t vdd_rstr_reg_level_store(struct kobject *kobj,
395 struct kobj_attribute *attr, const char *buf, size_t count)
396{
397 int ret = 0;
398 int val = 0;
399
400 struct rail *reg = VDD_RSTR_REG_LEVEL_FROM_ATTRIBS(attr);
401
402 mutex_lock(&vdd_rstr_mutex);
403 if (vdd_rstr_en.enabled == 0)
404 goto done_store_level;
405
Archana Sathyakumar143b0b52013-04-09 14:24:32 -0600406 ret = kstrtouint(buf, 10, &val);
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700407 if (ret) {
408 pr_err("Invalid input %s for level\n", buf);
409 goto done_store_level;
410 }
411
412 if (val < 0 || val > reg->num_levels - 1) {
413 pr_err(" Invalid number %d for level\n", val);
414 goto done_store_level;
415 }
416
417 if (val != reg->curr_level) {
418 if (reg->freq_req == 1 && freq_table_get)
419 update_cpu_min_freq_all(reg->levels[val]);
420 else {
421 ret = vdd_restriction_apply_voltage(reg, val);
422 if (ret) {
423 pr_err( \
424 "Set vdd restriction for regulator %s failed\n",
425 reg->name);
426 goto done_store_level;
427 }
428 }
429 reg->curr_level = val;
430 }
431
432done_store_level:
433 mutex_unlock(&vdd_rstr_mutex);
434 return count;
435}
Eugene Seah2ee4a5d2012-06-25 18:16:41 -0600436
Jennifer Liu907922c2013-03-26 11:18:00 -0700437static int psm_reg_mode_show(
438 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
439{
440 struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
441 return snprintf(buf, PAGE_SIZE, "%d\n", reg->mode);
442}
443
444static ssize_t psm_reg_mode_store(struct kobject *kobj,
445 struct kobj_attribute *attr, const char *buf, size_t count)
446{
447 int ret = 0;
448 int val = 0;
449 struct psm_rail *reg = PSM_REG_MODE_FROM_ATTRIBS(attr);
450
451 mutex_lock(&psm_mutex);
452 ret = kstrtoint(buf, 10, &val);
453 if (ret) {
454 pr_err("Invalid input %s for mode\n", buf);
455 goto done_psm_store;
456 }
457
458 if ((val != PMIC_PWM_MODE) && (val != PMIC_AUTO_MODE)) {
459 pr_err(" Invalid number %d for mode\n", val);
460 goto done_psm_store;
461 }
462
463 if (val != reg->mode) {
464 ret = rpm_regulator_set_mode(reg->reg, val);
465 if (ret) {
466 pr_err( \
467 "Fail to set PMIC SW Mode:%d for %s\n",
468 val, reg->name);
469 goto done_psm_store;
470 }
471 reg->mode = val;
472 }
473
474done_psm_store:
475 mutex_unlock(&psm_mutex);
476 return count;
477}
478
Jennifer Liu5a3518c2013-04-17 11:53:51 -0700479static int check_sensor_id(int sensor_id)
480{
481 int i = 0;
482 bool hw_id_found;
483 int ret = 0;
484
485 for (i = 0; i < max_tsens_num; i++) {
486 if (sensor_id == tsens_id_map[i]) {
487 hw_id_found = true;
488 break;
489 }
490 }
491 if (!hw_id_found) {
492 pr_err("%s: Invalid sensor hw id :%d\n", __func__, sensor_id);
493 return -EINVAL;
494 }
495
496 return ret;
497}
498
499static int create_sensor_id_map(void)
500{
501 int i = 0;
502 int ret = 0;
503
504 tsens_id_map = kzalloc(sizeof(int) * max_tsens_num,
505 GFP_KERNEL);
506 if (!tsens_id_map) {
507 pr_err("%s: Cannot allocate memory for tsens_id_map\n",
508 __func__);
509 return -ENOMEM;
510 }
511
512 for (i = 0; i < max_tsens_num; i++) {
513 ret = tsens_get_hw_id_mapping(i, &tsens_id_map[i]);
514 /* If return -ENXIO, hw_id is default in sequence */
515 if (ret) {
516 if (ret == -ENXIO) {
517 tsens_id_map[i] = i;
518 ret = 0;
519 } else {
520 pr_err( \
521 "%s: Failed to get hw id for sw id %d\n",
522 __func__, i);
523 goto fail;
524 }
525 }
526 }
527
528 return ret;
529fail:
530 kfree(tsens_id_map);
531 return ret;
532}
533
Jennifer Liu273d2962013-04-19 11:43:04 -0700534/* 1:enable, 0:disable */
535static int vdd_restriction_apply_all(int en)
536{
537 int i = 0;
538 int en_cnt = 0;
539 int dis_cnt = 0;
540 int fail_cnt = 0;
541 int ret = 0;
542
543 for (i = 0; i < rails_cnt; i++) {
544 if (rails[i].freq_req == 1 && freq_table_get)
545 ret = vdd_restriction_apply_freq(&rails[i],
546 en ? 0 : -1);
547 else
548 ret = vdd_restriction_apply_voltage(&rails[i],
549 en ? 0 : -1);
550 if (ret) {
551 pr_err("Cannot set voltage for %s", rails[i].name);
552 fail_cnt++;
553 } else {
554 if (en)
555 en_cnt++;
556 else
557 dis_cnt++;
558 }
559 }
560
561 /* As long as one rail is enabled, vdd rstr is enabled */
562 if (en && en_cnt)
563 vdd_rstr_en.enabled = 1;
564 else if (!en && (dis_cnt == rails_cnt))
565 vdd_rstr_en.enabled = 0;
566
567 /*
568 * Check fail_cnt again to make sure all of the rails are applied
569 * restriction successfully or not
570 */
571 if (fail_cnt)
572 return -EFAULT;
573 return ret;
574}
575
Eugene Seah2ee4a5d2012-06-25 18:16:41 -0600576static int msm_thermal_get_freq_table(void)
577{
578 int ret = 0;
579 int i = 0;
580
581 table = cpufreq_frequency_get_table(0);
582 if (table == NULL) {
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700583 pr_debug("%s: error reading cpufreq table\n", KBUILD_MODNAME);
Eugene Seah2ee4a5d2012-06-25 18:16:41 -0600584 ret = -EINVAL;
585 goto fail;
586 }
587
588 while (table[i].frequency != CPUFREQ_TABLE_END)
589 i++;
590
591 limit_idx_low = 0;
592 limit_idx_high = limit_idx = i - 1;
593 BUG_ON(limit_idx_high <= 0 || limit_idx_high <= limit_idx_low);
594fail:
595 return ret;
596}
597
Praveen Chidambaram91814362012-05-25 17:36:07 -0600598static int update_cpu_max_freq(int cpu, uint32_t max_freq)
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700599{
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700600 int ret = 0;
601
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700602 ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
603 if (ret)
604 return ret;
605
606 limited_max_freq = max_freq;
607 if (max_freq != MSM_CPUFREQ_NO_LIMIT)
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700608 pr_info("%s: Limiting cpu%d max frequency to %d\n",
609 KBUILD_MODNAME, cpu, max_freq);
Praveen Chidambaram91814362012-05-25 17:36:07 -0600610 else
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700611 pr_info("%s: Max frequency reset for cpu%d\n",
612 KBUILD_MODNAME, cpu);
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700613
614 if (cpu_online(cpu)) {
615 struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
616 if (!policy)
617 return ret;
618 ret = cpufreq_driver_target(policy, policy->cur,
619 CPUFREQ_RELATION_H);
620 cpufreq_cpu_put(policy);
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600621 }
Eugene Seah2ee4a5d2012-06-25 18:16:41 -0600622
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700623 return ret;
624}
625
Anji Jonnala822b5c42013-05-21 20:09:24 +0530626#ifdef CONFIG_SMP
Anji Jonnala7e3c5082013-05-02 00:46:12 +0530627static void __ref do_core_control(long temp)
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700628{
629 int i = 0;
630 int ret = 0;
631
632 if (!core_control_enabled)
633 return;
634
635 mutex_lock(&core_control_mutex);
636 if (msm_thermal_info.core_control_mask &&
637 temp >= msm_thermal_info.core_limit_temp_degC) {
638 for (i = num_possible_cpus(); i > 0; i--) {
639 if (!(msm_thermal_info.core_control_mask & BIT(i)))
640 continue;
641 if (cpus_offlined & BIT(i) && !cpu_online(i))
642 continue;
643 pr_info("%s: Set Offline: CPU%d Temp: %ld\n",
644 KBUILD_MODNAME, i, temp);
645 ret = cpu_down(i);
646 if (ret)
647 pr_err("%s: Error %d offline core %d\n",
648 KBUILD_MODNAME, ret, i);
649 cpus_offlined |= BIT(i);
650 break;
651 }
652 } else if (msm_thermal_info.core_control_mask && cpus_offlined &&
653 temp <= (msm_thermal_info.core_limit_temp_degC -
654 msm_thermal_info.core_temp_hysteresis_degC)) {
655 for (i = 0; i < num_possible_cpus(); i++) {
656 if (!(cpus_offlined & BIT(i)))
657 continue;
658 cpus_offlined &= ~BIT(i);
659 pr_info("%s: Allow Online CPU%d Temp: %ld\n",
660 KBUILD_MODNAME, i, temp);
Jennifer Liu273d2962013-04-19 11:43:04 -0700661 /*
662 * If this core is already online, then bring up the
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700663 * next offlined core.
664 */
665 if (cpu_online(i))
666 continue;
667 ret = cpu_up(i);
668 if (ret)
669 pr_err("%s: Error %d online core %d\n",
670 KBUILD_MODNAME, ret, i);
671 break;
672 }
673 }
674 mutex_unlock(&core_control_mutex);
675}
Jennifer Liu4ff40942013-07-30 15:25:46 -0700676/* Call with core_control_mutex locked */
677static int __ref update_offline_cores(int val)
678{
679 int cpu = 0;
680 int ret = 0;
681
682 if (!core_control_enabled)
683 return 0;
684
685 cpus_offlined = msm_thermal_info.core_control_mask & val;
686
687 for_each_possible_cpu(cpu) {
688 if (!(cpus_offlined & BIT(cpu)))
689 continue;
690 if (!cpu_online(cpu))
691 continue;
692 ret = cpu_down(cpu);
693 if (ret)
694 pr_err("%s: Unable to offline cpu%d\n",
695 KBUILD_MODNAME, cpu);
696 }
697 return ret;
698}
699
700static __ref int do_hotplug(void *data)
701{
702 int ret = 0;
703 int cpu = 0;
704 uint32_t mask = 0;
705
706 if (!core_control_enabled)
707 return -EINVAL;
708
709 while (!kthread_should_stop()) {
710 wait_for_completion(&hotplug_notify_complete);
711 INIT_COMPLETION(hotplug_notify_complete);
712 mask = 0;
713
714 mutex_lock(&core_control_mutex);
715 for_each_possible_cpu(cpu) {
716 if (cpus[cpu].offline || cpus[cpu].user_offline)
717 mask |= BIT(cpu);
718 }
719 if (mask != cpus_offlined)
720 update_offline_cores(mask);
721 mutex_unlock(&core_control_mutex);
722 sysfs_notify(cc_kobj, NULL, "cpus_offlined");
723 }
724
725 return ret;
726}
Anji Jonnala822b5c42013-05-21 20:09:24 +0530727#else
728static void do_core_control(long temp)
729{
730 return;
731}
Jennifer Liu4ff40942013-07-30 15:25:46 -0700732
733static __ref int do_hotplug(void *data)
734{
735 return 0;
736}
Anji Jonnala822b5c42013-05-21 20:09:24 +0530737#endif
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700738
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700739static int do_vdd_restriction(void)
740{
741 struct tsens_device tsens_dev;
742 long temp = 0;
743 int ret = 0;
744 int i = 0;
745 int dis_cnt = 0;
746
747 if (!vdd_rstr_enabled)
748 return ret;
749
750 if (usefreq && !freq_table_get) {
751 if (check_freq_table())
752 return ret;
753 }
754
755 mutex_lock(&vdd_rstr_mutex);
756 for (i = 0; i < max_tsens_num; i++) {
Jennifer Liu5a3518c2013-04-17 11:53:51 -0700757 tsens_dev.sensor_num = tsens_id_map[i];
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700758 ret = tsens_get_temp(&tsens_dev, &temp);
759 if (ret) {
760 pr_debug("%s: Unable to read TSENS sensor %d\n",
761 __func__, tsens_dev.sensor_num);
762 dis_cnt++;
763 continue;
764 }
Jennifer Liu273d2962013-04-19 11:43:04 -0700765 if (temp <= msm_thermal_info.vdd_rstr_temp_degC) {
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700766 ret = vdd_restriction_apply_all(1);
767 if (ret) {
768 pr_err( \
769 "Enable vdd rstr votlage for all failed\n");
770 goto exit;
771 }
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700772 goto exit;
Jennifer Liu273d2962013-04-19 11:43:04 -0700773 } else if (temp > msm_thermal_info.vdd_rstr_temp_hyst_degC)
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700774 dis_cnt++;
775 }
776 if (dis_cnt == max_tsens_num) {
777 ret = vdd_restriction_apply_all(0);
778 if (ret) {
779 pr_err("Disable vdd rstr votlage for all failed\n");
780 goto exit;
781 }
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700782 }
783exit:
784 mutex_unlock(&vdd_rstr_mutex);
785 return ret;
786}
787
Jennifer Liu907922c2013-03-26 11:18:00 -0700788static int do_psm(void)
789{
790 struct tsens_device tsens_dev;
791 long temp = 0;
792 int ret = 0;
793 int i = 0;
794 int auto_cnt = 0;
795
796 mutex_lock(&psm_mutex);
797 for (i = 0; i < max_tsens_num; i++) {
Jennifer Liu5a3518c2013-04-17 11:53:51 -0700798 tsens_dev.sensor_num = tsens_id_map[i];
Jennifer Liu907922c2013-03-26 11:18:00 -0700799 ret = tsens_get_temp(&tsens_dev, &temp);
800 if (ret) {
801 pr_debug("%s: Unable to read TSENS sensor %d\n",
802 __func__, tsens_dev.sensor_num);
803 auto_cnt++;
804 continue;
805 }
806
Jennifer Liu273d2962013-04-19 11:43:04 -0700807 /*
808 * As long as one sensor is above the threshold, set PWM mode
Jennifer Liu907922c2013-03-26 11:18:00 -0700809 * on all rails, and loop stops. Set auto mode when all rails
Jennifer Liu273d2962013-04-19 11:43:04 -0700810 * are below thershold
811 */
Jennifer Liu907922c2013-03-26 11:18:00 -0700812 if (temp > msm_thermal_info.psm_temp_degC) {
813 ret = psm_set_mode_all(PMIC_PWM_MODE);
814 if (ret) {
815 pr_err("Set pwm mode for all failed\n");
816 goto exit;
817 }
818 break;
819 } else if (temp <= msm_thermal_info.psm_temp_hyst_degC)
820 auto_cnt++;
821 }
822
823 if (auto_cnt == max_tsens_num) {
824 ret = psm_set_mode_all(PMIC_AUTO_MODE);
825 if (ret) {
826 pr_err("Set auto mode for all failed\n");
827 goto exit;
828 }
829 }
830
831exit:
832 mutex_unlock(&psm_mutex);
833 return ret;
834}
835
Anji Jonnala7e3c5082013-05-02 00:46:12 +0530836static void __ref do_freq_control(long temp)
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600837{
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700838 int ret = 0;
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600839 int cpu = 0;
840 uint32_t max_freq = limited_max_freq;
841
842 if (temp >= msm_thermal_info.limit_temp_degC) {
843 if (limit_idx == limit_idx_low)
844 return;
845
846 limit_idx -= msm_thermal_info.freq_step;
847 if (limit_idx < limit_idx_low)
848 limit_idx = limit_idx_low;
849 max_freq = table[limit_idx].frequency;
850 } else if (temp < msm_thermal_info.limit_temp_degC -
851 msm_thermal_info.temp_hysteresis_degC) {
852 if (limit_idx == limit_idx_high)
853 return;
854
855 limit_idx += msm_thermal_info.freq_step;
856 if (limit_idx >= limit_idx_high) {
857 limit_idx = limit_idx_high;
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700858 max_freq = MSM_CPUFREQ_NO_LIMIT;
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600859 } else
860 max_freq = table[limit_idx].frequency;
861 }
862
863 if (max_freq == limited_max_freq)
864 return;
865
866 /* Update new limits */
867 for_each_possible_cpu(cpu) {
868 if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
869 continue;
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700870 ret = update_cpu_max_freq(cpu, max_freq);
871 if (ret)
872 pr_debug(
873 "%s: Unable to limit cpu%d max freq to %d\n",
874 KBUILD_MODNAME, cpu, max_freq);
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600875 }
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -0700876
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600877}
878
Anji Jonnala7e3c5082013-05-02 00:46:12 +0530879static void __ref check_temp(struct work_struct *work)
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700880{
Eugene Seah2ee4a5d2012-06-25 18:16:41 -0600881 static int limit_init;
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700882 struct tsens_device tsens_dev;
Praveen Chidambaram0c6ab952013-02-07 17:47:16 -0700883 long temp = 0;
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700884 int ret = 0;
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600885
Praveen Chidambaram91814362012-05-25 17:36:07 -0600886 tsens_dev.sensor_num = msm_thermal_info.sensor_id;
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700887 ret = tsens_get_temp(&tsens_dev, &temp);
888 if (ret) {
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700889 pr_debug("%s: Unable to read TSENS sensor %d\n",
890 KBUILD_MODNAME, tsens_dev.sensor_num);
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700891 goto reschedule;
892 }
893
Eugene Seah2ee4a5d2012-06-25 18:16:41 -0600894 if (!limit_init) {
895 ret = msm_thermal_get_freq_table();
896 if (ret)
897 goto reschedule;
898 else
899 limit_init = 1;
900 }
Praveen Chidambaram91814362012-05-25 17:36:07 -0600901
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700902 do_core_control(temp);
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -0700903 do_vdd_restriction();
Jennifer Liu907922c2013-03-26 11:18:00 -0700904 do_psm();
Praveen Chidambarama7435ce2013-05-03 12:52:42 -0600905 do_freq_control(temp);
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700906
907reschedule:
908 if (enabled)
909 schedule_delayed_work(&check_temp_work,
Praveen Chidambaram91814362012-05-25 17:36:07 -0600910 msecs_to_jiffies(msm_thermal_info.poll_ms));
Praveen Chidambaramf248bb72012-01-20 11:38:44 -0700911}
912
Anji Jonnala7e3c5082013-05-02 00:46:12 +0530913static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb,
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700914 unsigned long action, void *hcpu)
915{
916 unsigned int cpu = (unsigned long)hcpu;
917
918 if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) {
919 if (core_control_enabled &&
920 (msm_thermal_info.core_control_mask & BIT(cpu)) &&
921 (cpus_offlined & BIT(cpu))) {
Jennifer Liu4ff40942013-07-30 15:25:46 -0700922 pr_debug(
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -0700923 "%s: Preventing cpu%d from coming online.\n",
924 KBUILD_MODNAME, cpu);
925 return NOTIFY_BAD;
926 }
927 }
928
929
930 return NOTIFY_OK;
931}
932
933static struct notifier_block __refdata msm_thermal_cpu_notifier = {
934 .notifier_call = msm_thermal_cpu_callback,
935};
936
Archana Sathyakumar143b0b52013-04-09 14:24:32 -0600937static void thermal_rtc_setup(void)
938{
939 ktime_t wakeup_time;
940 ktime_t curr_time;
941
942 curr_time = alarm_get_elapsed_realtime();
943 wakeup_time = ktime_add_us(curr_time,
944 (wakeup_ms * USEC_PER_MSEC));
945 alarm_start_range(&thermal_rtc, wakeup_time,
946 wakeup_time);
947 pr_debug("%s: Current Time: %ld %ld, Alarm set to: %ld %ld\n",
948 KBUILD_MODNAME,
949 ktime_to_timeval(curr_time).tv_sec,
950 ktime_to_timeval(curr_time).tv_usec,
951 ktime_to_timeval(wakeup_time).tv_sec,
952 ktime_to_timeval(wakeup_time).tv_usec);
953
954}
955
956static void timer_work_fn(struct work_struct *work)
957{
958 sysfs_notify(tt_kobj, NULL, "wakeup_ms");
959}
960
961static void thermal_rtc_callback(struct alarm *al)
962{
963 struct timeval ts;
964 ts = ktime_to_timeval(alarm_get_elapsed_realtime());
965 schedule_work(&timer_work);
966 pr_debug("%s: Time on alarm expiry: %ld %ld\n", KBUILD_MODNAME,
967 ts.tv_sec, ts.tv_usec);
968}
969
Jennifer Liu4ff40942013-07-30 15:25:46 -0700970static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
971{
972 struct cpu_info *cpu_node = (struct cpu_info *)data;
973
974 pr_info("%s: %s reach temp threshold: %d\n", KBUILD_MODNAME,
975 cpu_node->sensor_type, temp);
976
977 if (!(msm_thermal_info.core_control_mask & BIT(cpu_node->cpu)))
978 return 0;
979 switch (type) {
980 case THERMAL_TRIP_CONFIGURABLE_HI:
981 if (!(cpu_node->offline))
982 cpu_node->offline = 1;
983 break;
984 case THERMAL_TRIP_CONFIGURABLE_LOW:
985 if (cpu_node->offline)
986 cpu_node->offline = 0;
987 break;
988 default:
989 break;
990 }
991 if (hotplug_task)
992 complete(&hotplug_notify_complete);
993 else
994 pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
995 return 0;
996}
997/* Adjust cpus offlined bit based on temperature reading. */
998static int hotplug_init_cpu_offlined(void)
999{
1000 struct tsens_device tsens_dev;
1001 long temp = 0;
1002 int cpu = 0;
1003
1004 mutex_lock(&core_control_mutex);
1005 for_each_possible_cpu(cpu) {
1006 if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
1007 continue;
1008 tsens_dev.sensor_num = sensor_get_id(\
1009 (char *)cpus[cpu].sensor_type);
1010 if (tsens_get_temp(&tsens_dev, &temp)) {
1011 pr_err("%s: Unable to read TSENS sensor %d\n",
1012 KBUILD_MODNAME, tsens_dev.sensor_num);
1013 return -EINVAL;
1014 }
1015
1016 if (temp >= msm_thermal_info.hotplug_temp_degC)
1017 cpus[cpu].offline = 1;
1018 else if (temp <= (msm_thermal_info.hotplug_temp_degC -
1019 msm_thermal_info.hotplug_temp_hysteresis_degC))
1020 cpus[cpu].offline = 0;
1021 }
1022 mutex_unlock(&core_control_mutex);
1023
1024 if (hotplug_task)
1025 complete(&hotplug_notify_complete);
1026 else {
1027 pr_err("%s: Hotplug task is not initialized\n",
1028 KBUILD_MODNAME);
1029 return -EINVAL;
1030 }
1031 return 0;
1032}
1033
1034static void hotplug_init(void)
1035{
1036 int cpu = 0;
1037
1038 if (hotplug_task)
1039 return;
1040
1041 for_each_possible_cpu(cpu) {
1042 if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
1043 continue;
1044 cpus[cpu].cpu = (uint32_t)cpu;
1045 cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
1046 cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
1047 cpus[cpu].thresh[0].notify = hotplug_notify;
1048 cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
1049 sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
1050 &cpus[cpu].thresh[0]);
1051
1052 cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
1053 msm_thermal_info.hotplug_temp_hysteresis_degC;
1054 cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
1055 cpus[cpu].thresh[1].notify = hotplug_notify;
1056 cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
1057 sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
1058 &cpus[cpu].thresh[1]);
1059
1060 }
1061 init_completion(&hotplug_notify_complete);
1062 hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
1063 if (IS_ERR(hotplug_task)) {
1064 pr_err("%s: Failed to create do_hotplug thread\n",
1065 KBUILD_MODNAME);
1066 return;
1067 }
1068 /*
1069 * Adjust cpus offlined bit when hotplug intitializes so that the new
1070 * cpus offlined state is based on hotplug threshold range
1071 */
1072 if (hotplug_init_cpu_offlined())
1073 kthread_stop(hotplug_task);
1074}
1075
Jennifer Liu273d2962013-04-19 11:43:04 -07001076/*
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001077 * We will reset the cpu frequencies limits here. The core online/offline
1078 * status will be carried over to the process stopping the msm_thermal, as
1079 * we dont want to online a core and bring in the thermal issues.
1080 */
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301081static void __ref disable_msm_thermal(void)
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001082{
1083 int cpu = 0;
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001084
Eugene Seahcbc07532012-04-11 19:32:27 -06001085 /* make sure check_temp is no longer running */
1086 cancel_delayed_work(&check_temp_work);
1087 flush_scheduled_work();
1088
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -07001089 if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
Praveen Chidambaram91814362012-05-25 17:36:07 -06001090 return;
1091
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -07001092 for_each_possible_cpu(cpu) {
1093 update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001094 }
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001095}
1096
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301097static int __ref set_enabled(const char *val, const struct kernel_param *kp)
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001098{
1099 int ret = 0;
1100
1101 ret = param_set_bool(val, kp);
Jennifer Liu4ff40942013-07-30 15:25:46 -07001102 if (!enabled) {
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001103 disable_msm_thermal();
Jennifer Liu4ff40942013-07-30 15:25:46 -07001104 hotplug_init();
1105 } else
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001106 pr_info("%s: no action for enabled = %d\n",
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -07001107 KBUILD_MODNAME, enabled);
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001108
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001109 pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001110
1111 return ret;
1112}
1113
1114static struct kernel_param_ops module_ops = {
1115 .set = set_enabled,
1116 .get = param_get_bool,
1117};
1118
1119module_param_cb(enabled, &module_ops, &enabled, 0644);
1120MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
1121
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001122static ssize_t show_cc_enabled(struct kobject *kobj,
1123 struct kobj_attribute *attr, char *buf)
1124{
1125 return snprintf(buf, PAGE_SIZE, "%d\n", core_control_enabled);
1126}
1127
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301128static ssize_t __ref store_cc_enabled(struct kobject *kobj,
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001129 struct kobj_attribute *attr, const char *buf, size_t count)
1130{
1131 int ret = 0;
1132 int val = 0;
1133
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001134 ret = kstrtoint(buf, 10, &val);
1135 if (ret) {
1136 pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
1137 goto done_store_cc;
1138 }
1139
1140 if (core_control_enabled == !!val)
1141 goto done_store_cc;
1142
1143 core_control_enabled = !!val;
1144 if (core_control_enabled) {
1145 pr_info("%s: Core control enabled\n", KBUILD_MODNAME);
1146 register_cpu_notifier(&msm_thermal_cpu_notifier);
Jennifer Liu4ff40942013-07-30 15:25:46 -07001147 if (hotplug_task)
1148 complete(&hotplug_notify_complete);
1149 else
1150 pr_err("%s: Hotplug task is not initialized\n",
1151 KBUILD_MODNAME);
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001152 } else {
1153 pr_info("%s: Core control disabled\n", KBUILD_MODNAME);
1154 unregister_cpu_notifier(&msm_thermal_cpu_notifier);
1155 }
1156
1157done_store_cc:
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001158 return count;
1159}
1160
1161static ssize_t show_cpus_offlined(struct kobject *kobj,
1162 struct kobj_attribute *attr, char *buf)
1163{
1164 return snprintf(buf, PAGE_SIZE, "%d\n", cpus_offlined);
1165}
1166
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301167static ssize_t __ref store_cpus_offlined(struct kobject *kobj,
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001168 struct kobj_attribute *attr, const char *buf, size_t count)
1169{
1170 int ret = 0;
1171 uint32_t val = 0;
Jennifer Liu4ff40942013-07-30 15:25:46 -07001172 int cpu;
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001173
1174 mutex_lock(&core_control_mutex);
1175 ret = kstrtouint(buf, 10, &val);
1176 if (ret) {
1177 pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
1178 goto done_cc;
1179 }
1180
1181 if (enabled) {
1182 pr_err("%s: Ignoring request; polling thread is enabled.\n",
1183 KBUILD_MODNAME);
1184 goto done_cc;
1185 }
1186
Jennifer Liu4ff40942013-07-30 15:25:46 -07001187 for_each_possible_cpu(cpu) {
1188 if (!(msm_thermal_info.core_control_mask & BIT(cpu)))
1189 continue;
1190 cpus[cpu].user_offline = !!(val & BIT(cpu));
1191 }
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001192
Jennifer Liu4ff40942013-07-30 15:25:46 -07001193 if (hotplug_task)
1194 complete(&hotplug_notify_complete);
1195 else
1196 pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001197done_cc:
1198 mutex_unlock(&core_control_mutex);
1199 return count;
1200}
1201
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301202static __refdata struct kobj_attribute cc_enabled_attr =
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001203__ATTR(enabled, 0644, show_cc_enabled, store_cc_enabled);
1204
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301205static __refdata struct kobj_attribute cpus_offlined_attr =
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001206__ATTR(cpus_offlined, 0644, show_cpus_offlined, store_cpus_offlined);
1207
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301208static __refdata struct attribute *cc_attrs[] = {
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001209 &cc_enabled_attr.attr,
1210 &cpus_offlined_attr.attr,
1211 NULL,
1212};
1213
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301214static __refdata struct attribute_group cc_attr_group = {
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001215 .attrs = cc_attrs,
1216};
1217
Archana Sathyakumar143b0b52013-04-09 14:24:32 -06001218static ssize_t show_wakeup_ms(struct kobject *kobj,
1219 struct kobj_attribute *attr, char *buf)
1220{
1221 return snprintf(buf, PAGE_SIZE, "%d\n", wakeup_ms);
1222}
1223
1224static ssize_t store_wakeup_ms(struct kobject *kobj,
1225 struct kobj_attribute *attr, const char *buf, size_t count)
1226{
1227 int ret;
1228 ret = kstrtouint(buf, 10, &wakeup_ms);
1229
1230 if (ret) {
1231 pr_err("%s: Trying to set invalid wakeup timer\n",
1232 KBUILD_MODNAME);
1233 return ret;
1234 }
1235
1236 if (wakeup_ms > 0) {
1237 thermal_rtc_setup();
1238 pr_debug("%s: Timer started for %ums\n", KBUILD_MODNAME,
1239 wakeup_ms);
1240 } else {
1241 ret = alarm_cancel(&thermal_rtc);
1242 if (ret)
1243 pr_debug("%s: Timer canceled\n", KBUILD_MODNAME);
1244 else
1245 pr_debug("%s: No active timer present to cancel\n",
1246 KBUILD_MODNAME);
1247
1248 }
1249 return count;
1250}
1251
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301252static __refdata struct kobj_attribute timer_attr =
Archana Sathyakumar143b0b52013-04-09 14:24:32 -06001253__ATTR(wakeup_ms, 0644, show_wakeup_ms, store_wakeup_ms);
1254
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301255static __refdata struct attribute *tt_attrs[] = {
Archana Sathyakumar143b0b52013-04-09 14:24:32 -06001256 &timer_attr.attr,
1257 NULL,
1258};
1259
Anji Jonnala7e3c5082013-05-02 00:46:12 +05301260static __refdata struct attribute_group tt_attr_group = {
Archana Sathyakumar143b0b52013-04-09 14:24:32 -06001261 .attrs = tt_attrs,
1262};
1263
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001264static __init int msm_thermal_add_cc_nodes(void)
1265{
1266 struct kobject *module_kobj = NULL;
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001267 int ret = 0;
1268
1269 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
1270 if (!module_kobj) {
1271 pr_err("%s: cannot find kobject for module\n",
1272 KBUILD_MODNAME);
1273 ret = -ENOENT;
1274 goto done_cc_nodes;
1275 }
1276
1277 cc_kobj = kobject_create_and_add("core_control", module_kobj);
1278 if (!cc_kobj) {
1279 pr_err("%s: cannot create core control kobj\n",
1280 KBUILD_MODNAME);
1281 ret = -ENOMEM;
1282 goto done_cc_nodes;
1283 }
1284
1285 ret = sysfs_create_group(cc_kobj, &cc_attr_group);
1286 if (ret) {
1287 pr_err("%s: cannot create group\n", KBUILD_MODNAME);
1288 goto done_cc_nodes;
1289 }
1290
1291 return 0;
1292
1293done_cc_nodes:
1294 if (cc_kobj)
1295 kobject_del(cc_kobj);
1296 return ret;
1297}
1298
Archana Sathyakumar143b0b52013-04-09 14:24:32 -06001299static __init int msm_thermal_add_timer_nodes(void)
1300{
1301 struct kobject *module_kobj = NULL;
1302 int ret = 0;
1303
1304 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
1305 if (!module_kobj) {
1306 pr_err("%s: cannot find kobject for module\n",
1307 KBUILD_MODNAME);
1308 ret = -ENOENT;
1309 goto failed;
1310 }
1311
1312 tt_kobj = kobject_create_and_add("thermal_timer", module_kobj);
1313 if (!tt_kobj) {
1314 pr_err("%s: cannot create timer kobj\n",
1315 KBUILD_MODNAME);
1316 ret = -ENOMEM;
1317 goto failed;
1318 }
1319
1320 ret = sysfs_create_group(tt_kobj, &tt_attr_group);
1321 if (ret) {
1322 pr_err("%s: cannot create group\n", KBUILD_MODNAME);
1323 goto failed;
1324 }
1325
1326 return 0;
1327
1328failed:
1329 if (tt_kobj)
1330 kobject_del(tt_kobj);
1331 return ret;
1332}
1333
Eugene Seahb77b0c42012-07-02 19:28:50 -06001334int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001335{
1336 int ret = 0;
1337
Praveen Chidambaram91814362012-05-25 17:36:07 -06001338 BUG_ON(!pdata);
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001339 tsens_get_max_sensor_num(&max_tsens_num);
Praveen Chidambaram91814362012-05-25 17:36:07 -06001340 memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
1341
Jennifer Liu5a3518c2013-04-17 11:53:51 -07001342 if (create_sensor_id_map())
1343 return -EINVAL;
1344 if (check_sensor_id(msm_thermal_info.sensor_id))
1345 return -EINVAL;
1346
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001347 enabled = 1;
Jennifer Liu4ff40942013-07-30 15:25:46 -07001348
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001349 INIT_DELAYED_WORK(&check_temp_work, check_temp);
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001350 schedule_delayed_work(&check_temp_work, 0);
1351
Anji Jonnala822b5c42013-05-21 20:09:24 +05301352 if (num_possible_cpus() > 1)
1353 register_cpu_notifier(&msm_thermal_cpu_notifier);
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001354
Praveen Chidambaramf248bb72012-01-20 11:38:44 -07001355 return ret;
1356}
Eugene Seahb77b0c42012-07-02 19:28:50 -06001357
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001358static int vdd_restriction_reg_init(struct platform_device *pdev)
1359{
1360 int ret = 0;
1361 int i;
1362
1363 for (i = 0; i < rails_cnt; i++) {
1364 if (rails[i].freq_req == 1) {
1365 usefreq |= BIT(i);
1366 check_freq_table();
Jennifer Liu273d2962013-04-19 11:43:04 -07001367 /*
1368 * Restrict frequency by default until we have made
1369 * our first temp reading
1370 */
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001371 if (freq_table_get)
1372 ret = vdd_restriction_apply_freq(&rails[i], 0);
1373 else
1374 pr_info("%s:Defer vdd rstr freq init\n",
1375 __func__);
1376 } else {
1377 rails[i].reg = devm_regulator_get(&pdev->dev,
1378 rails[i].name);
1379 if (IS_ERR_OR_NULL(rails[i].reg)) {
1380 ret = PTR_ERR(rails[i].reg);
1381 if (ret != -EPROBE_DEFER) {
1382 pr_err( \
1383 "%s, could not get regulator: %s\n",
1384 rails[i].name, __func__);
1385 rails[i].reg = NULL;
1386 rails[i].curr_level = -2;
1387 return ret;
1388 }
1389 return ret;
1390 }
Jennifer Liu273d2962013-04-19 11:43:04 -07001391 /*
1392 * Restrict votlage by default until we have made
1393 * our first temp reading
1394 */
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001395 ret = vdd_restriction_apply_voltage(&rails[i], 0);
1396 }
1397 }
1398
1399 return ret;
1400}
1401
Jennifer Liu907922c2013-03-26 11:18:00 -07001402static int psm_reg_init(struct platform_device *pdev)
1403{
1404 int ret = 0;
1405 int i = 0;
1406 int j = 0;
1407
1408 for (i = 0; i < psm_rails_cnt; i++) {
1409 psm_rails[i].reg = rpm_regulator_get(&pdev->dev,
1410 psm_rails[i].name);
1411 if (IS_ERR_OR_NULL(psm_rails[i].reg)) {
1412 ret = PTR_ERR(psm_rails[i].reg);
1413 if (ret != -EPROBE_DEFER) {
1414 pr_err("%s, could not get rpm regulator: %s\n",
1415 psm_rails[i].name, __func__);
1416 psm_rails[i].reg = NULL;
1417 goto psm_reg_exit;
1418 }
1419 return ret;
1420 }
1421 /* Apps default vote for PWM mode */
1422 psm_rails[i].init = PMIC_PWM_MODE;
1423 ret = rpm_regulator_set_mode(psm_rails[i].reg,
1424 psm_rails[i].init);
1425 if (ret) {
1426 pr_err("%s: Cannot set PMIC PWM mode\n", __func__);
1427 return ret;
1428 } else
1429 psm_rails[i].mode = PMIC_PWM_MODE;
1430 }
1431
1432 return ret;
1433
1434psm_reg_exit:
1435 if (ret) {
1436 for (j = 0; j < i; j++) {
1437 if (psm_rails[j].reg != NULL)
1438 rpm_regulator_put(psm_rails[j].reg);
1439 }
1440 }
1441
1442 return ret;
1443}
1444
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001445static int msm_thermal_add_vdd_rstr_nodes(void)
1446{
1447 struct kobject *module_kobj = NULL;
1448 struct kobject *vdd_rstr_kobj = NULL;
1449 struct kobject *vdd_rstr_reg_kobj[MAX_RAILS] = {0};
1450 int rc = 0;
1451 int i = 0;
1452
1453 if (!vdd_rstr_probed) {
1454 vdd_rstr_nodes_called = true;
1455 return rc;
1456 }
1457
1458 if (vdd_rstr_probed && rails_cnt == 0)
1459 return rc;
1460
1461 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
1462 if (!module_kobj) {
1463 pr_err("%s: cannot find kobject for module %s\n",
1464 __func__, KBUILD_MODNAME);
1465 rc = -ENOENT;
1466 goto thermal_sysfs_add_exit;
1467 }
1468
1469 vdd_rstr_kobj = kobject_create_and_add("vdd_restriction", module_kobj);
1470 if (!vdd_rstr_kobj) {
1471 pr_err("%s: cannot create vdd_restriction kobject\n", __func__);
1472 rc = -ENOMEM;
1473 goto thermal_sysfs_add_exit;
1474 }
1475
1476 rc = sysfs_create_group(vdd_rstr_kobj, &vdd_rstr_en_attribs_gp);
1477 if (rc) {
1478 pr_err("%s: cannot create kobject attribute group\n", __func__);
1479 rc = -ENOMEM;
1480 goto thermal_sysfs_add_exit;
1481 }
1482
1483 for (i = 0; i < rails_cnt; i++) {
1484 vdd_rstr_reg_kobj[i] = kobject_create_and_add(rails[i].name,
1485 vdd_rstr_kobj);
1486 if (!vdd_rstr_reg_kobj[i]) {
1487 pr_err("%s: cannot create for kobject for %s\n",
1488 __func__, rails[i].name);
1489 rc = -ENOMEM;
1490 goto thermal_sysfs_add_exit;
1491 }
1492
1493 rails[i].attr_gp.attrs = kzalloc(sizeof(struct attribute *) * 3,
1494 GFP_KERNEL);
1495 if (!rails[i].attr_gp.attrs) {
1496 rc = -ENOMEM;
1497 goto thermal_sysfs_add_exit;
1498 }
1499
1500 VDD_RES_RW_ATTRIB(rails[i], rails[i].level_attr, 0, level);
1501 VDD_RES_RO_ATTRIB(rails[i], rails[i].value_attr, 1, value);
1502 rails[i].attr_gp.attrs[2] = NULL;
1503
1504 rc = sysfs_create_group(vdd_rstr_reg_kobj[i],
1505 &rails[i].attr_gp);
1506 if (rc) {
1507 pr_err("%s: cannot create attribute group for %s\n",
1508 __func__, rails[i].name);
1509 goto thermal_sysfs_add_exit;
1510 }
1511 }
1512
1513 return rc;
1514
1515thermal_sysfs_add_exit:
1516 if (rc) {
1517 for (i = 0; i < rails_cnt; i++) {
1518 kobject_del(vdd_rstr_reg_kobj[i]);
1519 kfree(rails[i].attr_gp.attrs);
1520 }
1521 if (vdd_rstr_kobj)
1522 kobject_del(vdd_rstr_kobj);
1523 }
1524 return rc;
1525}
1526
Jennifer Liu907922c2013-03-26 11:18:00 -07001527static int msm_thermal_add_psm_nodes(void)
1528{
1529 struct kobject *module_kobj = NULL;
1530 struct kobject *psm_kobj = NULL;
1531 struct kobject *psm_reg_kobj[MAX_RAILS] = {0};
1532 int rc = 0;
1533 int i = 0;
1534
1535 if (!psm_probed) {
1536 psm_nodes_called = true;
1537 return rc;
1538 }
1539
1540 if (psm_probed && psm_rails_cnt == 0)
1541 return rc;
1542
1543 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
1544 if (!module_kobj) {
1545 pr_err("%s: cannot find kobject for module %s\n",
1546 __func__, KBUILD_MODNAME);
1547 rc = -ENOENT;
1548 goto psm_node_exit;
1549 }
1550
1551 psm_kobj = kobject_create_and_add("pmic_sw_mode", module_kobj);
1552 if (!psm_kobj) {
1553 pr_err("%s: cannot create psm kobject\n", KBUILD_MODNAME);
1554 rc = -ENOMEM;
1555 goto psm_node_exit;
1556 }
1557
1558 for (i = 0; i < psm_rails_cnt; i++) {
1559 psm_reg_kobj[i] = kobject_create_and_add(psm_rails[i].name,
1560 psm_kobj);
1561 if (!psm_reg_kobj[i]) {
1562 pr_err("%s: cannot create for kobject for %s\n",
1563 KBUILD_MODNAME, psm_rails[i].name);
1564 rc = -ENOMEM;
1565 goto psm_node_exit;
1566 }
1567 psm_rails[i].attr_gp.attrs = kzalloc( \
1568 sizeof(struct attribute *) * 2, GFP_KERNEL);
1569 if (!psm_rails[i].attr_gp.attrs) {
1570 rc = -ENOMEM;
1571 goto psm_node_exit;
1572 }
1573
1574 PSM_RW_ATTRIB(psm_rails[i], psm_rails[i].mode_attr, 0, mode);
1575 psm_rails[i].attr_gp.attrs[1] = NULL;
1576
1577 rc = sysfs_create_group(psm_reg_kobj[i], &psm_rails[i].attr_gp);
1578 if (rc) {
1579 pr_err("%s: cannot create attribute group for %s\n",
1580 KBUILD_MODNAME, psm_rails[i].name);
1581 goto psm_node_exit;
1582 }
1583 }
1584
1585 return rc;
1586
1587psm_node_exit:
1588 if (rc) {
1589 for (i = 0; i < psm_rails_cnt; i++) {
1590 kobject_del(psm_reg_kobj[i]);
1591 kfree(psm_rails[i].attr_gp.attrs);
1592 }
1593 if (psm_kobj)
1594 kobject_del(psm_kobj);
1595 }
1596 return rc;
1597}
1598
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001599static int probe_vdd_rstr(struct device_node *node,
1600 struct msm_thermal_data *data, struct platform_device *pdev)
1601{
1602 int ret = 0;
1603 int i = 0;
1604 int arr_size;
1605 char *key = NULL;
1606 struct device_node *child_node = NULL;
1607
Jennifer Liuf4e76492013-05-24 13:23:53 -07001608 rails = NULL;
1609
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001610 key = "qcom,vdd-restriction-temp";
1611 ret = of_property_read_u32(node, key, &data->vdd_rstr_temp_degC);
1612 if (ret)
1613 goto read_node_fail;
1614
1615 key = "qcom,vdd-restriction-temp-hysteresis";
1616 ret = of_property_read_u32(node, key, &data->vdd_rstr_temp_hyst_degC);
1617 if (ret)
1618 goto read_node_fail;
1619
1620 for_each_child_of_node(node, child_node) {
1621 rails_cnt++;
1622 }
1623
1624 if (rails_cnt == 0)
1625 goto read_node_fail;
1626 if (rails_cnt >= MAX_RAILS) {
1627 pr_err("%s: Too many rails.\n", __func__);
1628 return -EFAULT;
1629 }
1630
1631 rails = kzalloc(sizeof(struct rail) * rails_cnt,
1632 GFP_KERNEL);
1633 if (!rails) {
1634 pr_err("%s: Fail to allocate memory for rails.\n", __func__);
1635 return -ENOMEM;
1636 }
1637
1638 i = 0;
1639 for_each_child_of_node(node, child_node) {
1640 key = "qcom,vdd-rstr-reg";
1641 ret = of_property_read_string(child_node, key, &rails[i].name);
1642 if (ret)
1643 goto read_node_fail;
1644
1645 key = "qcom,levels";
1646 if (!of_get_property(child_node, key, &arr_size))
1647 goto read_node_fail;
1648 rails[i].num_levels = arr_size/sizeof(__be32);
1649 if (rails[i].num_levels >
1650 sizeof(rails[i].levels)/sizeof(uint32_t)) {
1651 pr_err("%s: Array size too large\n", __func__);
1652 return -EFAULT;
1653 }
1654 ret = of_property_read_u32_array(child_node, key,
1655 rails[i].levels, rails[i].num_levels);
1656 if (ret)
1657 goto read_node_fail;
1658
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001659 key = "qcom,freq-req";
1660 rails[i].freq_req = of_property_read_bool(child_node, key);
Jennifer Liu95c4a9a2013-05-03 16:57:23 -07001661 if (rails[i].freq_req)
Sridhar Parasuramc473c9d2013-08-01 16:49:51 -07001662 rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
Jennifer Liu95c4a9a2013-05-03 16:57:23 -07001663 else {
1664 key = "qcom,min-level";
1665 ret = of_property_read_u32(child_node, key,
1666 &rails[i].min_level);
1667 if (ret)
1668 goto read_node_fail;
1669 }
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001670
Jennifer Liu4bc738d2013-07-16 16:16:37 -07001671 rails[i].curr_level = -1;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001672 rails[i].reg = NULL;
1673 i++;
1674 }
1675
1676 if (rails_cnt) {
1677 ret = vdd_restriction_reg_init(pdev);
1678 if (ret) {
1679 pr_info("%s:Failed to get regulators. KTM continues.\n",
1680 __func__);
1681 goto read_node_fail;
1682 }
1683 vdd_rstr_enabled = true;
1684 }
1685read_node_fail:
1686 vdd_rstr_probed = true;
1687 if (ret) {
1688 dev_info(&pdev->dev,
1689 "%s:Failed reading node=%s, key=%s. KTM continues\n",
1690 __func__, node->full_name, key);
1691 kfree(rails);
1692 rails_cnt = 0;
1693 }
1694 if (ret == -EPROBE_DEFER)
1695 vdd_rstr_probed = false;
1696 return ret;
1697}
1698
Jennifer Liu907922c2013-03-26 11:18:00 -07001699static int probe_psm(struct device_node *node, struct msm_thermal_data *data,
1700 struct platform_device *pdev)
1701{
1702 int ret = 0;
1703 int j = 0;
1704 char *key = NULL;
1705
Jennifer Liuf4e76492013-05-24 13:23:53 -07001706 psm_rails = NULL;
1707
Jennifer Liu907922c2013-03-26 11:18:00 -07001708 key = "qcom,pmic-sw-mode-temp";
1709 ret = of_property_read_u32(node, key, &data->psm_temp_degC);
1710 if (ret)
1711 goto read_node_fail;
1712
1713 key = "qcom,pmic-sw-mode-temp-hysteresis";
1714 ret = of_property_read_u32(node, key, &data->psm_temp_hyst_degC);
1715 if (ret)
1716 goto read_node_fail;
1717
1718 key = "qcom,pmic-sw-mode-regs";
1719 psm_rails_cnt = of_property_count_strings(node, key);
1720 psm_rails = kzalloc(sizeof(struct psm_rail) * psm_rails_cnt,
1721 GFP_KERNEL);
1722 if (!psm_rails) {
1723 pr_err("%s: Fail to allocate memory for psm rails\n", __func__);
1724 psm_rails_cnt = 0;
1725 return -ENOMEM;
1726 }
1727
1728 for (j = 0; j < psm_rails_cnt; j++) {
1729 ret = of_property_read_string_index(node, key, j,
1730 &psm_rails[j].name);
1731 if (ret)
1732 goto read_node_fail;
1733 }
1734
1735 if (psm_rails_cnt) {
1736 ret = psm_reg_init(pdev);
1737 if (ret) {
1738 pr_info("%s:Failed to get regulators. KTM continues.\n",
1739 __func__);
1740 goto read_node_fail;
1741 }
1742 psm_enabled = true;
1743 }
1744
1745read_node_fail:
1746 psm_probed = true;
1747 if (ret) {
1748 dev_info(&pdev->dev,
1749 "%s:Failed reading node=%s, key=%s. KTM continues\n",
1750 __func__, node->full_name, key);
1751 kfree(psm_rails);
1752 psm_rails_cnt = 0;
1753 }
1754 if (ret == -EPROBE_DEFER)
1755 psm_probed = false;
1756 return ret;
1757}
1758
Jennifer Liu4ff40942013-07-30 15:25:46 -07001759static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
1760 struct platform_device *pdev)
1761{
1762 char *key = NULL;
1763 int cpu_cnt = 0;
1764 int ret = 0;
1765 int cpu = 0;
1766
1767 key = "qcom,core-limit-temp";
1768 ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
1769 if (ret)
1770 goto read_node_fail;
1771
1772 key = "qcom,core-temp-hysteresis";
1773 ret = of_property_read_u32(node, key, &data->core_temp_hysteresis_degC);
1774 if (ret)
1775 goto read_node_fail;
1776
1777 key = "qcom,core-control-mask";
1778 ret = of_property_read_u32(node, key, &data->core_control_mask);
1779 if (ret)
1780 goto read_node_fail;
1781
1782 key = "qcom,hotplug-temp";
1783 ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
1784 if (ret)
1785 goto read_node_fail;
1786
1787 key = "qcom,hotplug-temp-hysteresis";
1788 ret = of_property_read_u32(node, key,
1789 &data->hotplug_temp_hysteresis_degC);
1790 if (ret)
1791 goto read_node_fail;
1792
1793 key = "qcom,cpu-sensors";
1794 cpu_cnt = of_property_count_strings(node, key);
1795 if (cpu_cnt != num_possible_cpus()) {
1796 pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
1797 goto read_node_fail;
1798 }
1799
1800 for_each_possible_cpu(cpu) {
1801 cpus[cpu].cpu = cpu;
1802 cpus[cpu].offline = 0;
1803 cpus[cpu].user_offline = 0;
1804 ret = of_property_read_string_index(node, key, cpu,
1805 &cpus[cpu].sensor_type);
1806 if (ret)
1807 goto read_node_fail;
1808 }
1809
1810 if (num_possible_cpus() > 1)
1811 core_control_enabled = 1;
1812
1813read_node_fail:
1814 if (ret) {
1815 dev_info(&pdev->dev,
1816 "%s:Failed reading node=%s, key=%s. KTM continues\n",
1817 KBUILD_MODNAME, node->full_name, key);
1818 core_control_enabled = 0;
1819 }
1820
1821 return ret;
1822}
1823
Eugene Seahb77b0c42012-07-02 19:28:50 -06001824static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
1825{
1826 int ret = 0;
1827 char *key = NULL;
1828 struct device_node *node = pdev->dev.of_node;
1829 struct msm_thermal_data data;
1830
1831 memset(&data, 0, sizeof(struct msm_thermal_data));
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001832
Eugene Seahb77b0c42012-07-02 19:28:50 -06001833 key = "qcom,sensor-id";
1834 ret = of_property_read_u32(node, key, &data.sensor_id);
1835 if (ret)
1836 goto fail;
Eugene Seahb77b0c42012-07-02 19:28:50 -06001837
1838 key = "qcom,poll-ms";
1839 ret = of_property_read_u32(node, key, &data.poll_ms);
1840 if (ret)
1841 goto fail;
1842
1843 key = "qcom,limit-temp";
1844 ret = of_property_read_u32(node, key, &data.limit_temp_degC);
1845 if (ret)
1846 goto fail;
1847
1848 key = "qcom,temp-hysteresis";
1849 ret = of_property_read_u32(node, key, &data.temp_hysteresis_degC);
1850 if (ret)
1851 goto fail;
1852
1853 key = "qcom,freq-step";
1854 ret = of_property_read_u32(node, key, &data.freq_step);
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001855 if (ret)
1856 goto fail;
Eugene Seahb77b0c42012-07-02 19:28:50 -06001857
Praveen Chidambarama7435ce2013-05-03 12:52:42 -06001858 key = "qcom,freq-control-mask";
1859 ret = of_property_read_u32(node, key, &data.freq_control_mask);
1860
Jennifer Liu4ff40942013-07-30 15:25:46 -07001861 ret = probe_cc(node, &data, pdev);
Jennifer Liu273d2962013-04-19 11:43:04 -07001862 /*
1863 * Probe optional properties below. Call probe_psm before
Jennifer Liu907922c2013-03-26 11:18:00 -07001864 * probe_vdd_rstr because rpm_regulator_get has to be called
Jennifer Liu273d2962013-04-19 11:43:04 -07001865 * before devm_regulator_get
1866 */
Jennifer Liu907922c2013-03-26 11:18:00 -07001867 ret = probe_psm(node, &data, pdev);
1868 if (ret == -EPROBE_DEFER)
1869 goto fail;
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001870 ret = probe_vdd_rstr(node, &data, pdev);
1871 if (ret == -EPROBE_DEFER)
1872 goto fail;
Jennifer Liu907922c2013-03-26 11:18:00 -07001873
Jennifer Liu273d2962013-04-19 11:43:04 -07001874 /*
1875 * In case sysfs add nodes get called before probe function.
1876 * Need to make sure sysfs node is created again
1877 */
Jennifer Liu907922c2013-03-26 11:18:00 -07001878 if (psm_nodes_called) {
1879 msm_thermal_add_psm_nodes();
1880 psm_nodes_called = false;
1881 }
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001882 if (vdd_rstr_nodes_called) {
1883 msm_thermal_add_vdd_rstr_nodes();
1884 vdd_rstr_nodes_called = false;
1885 }
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001886 ret = msm_thermal_init(&data);
1887
1888 return ret;
Eugene Seahb77b0c42012-07-02 19:28:50 -06001889fail:
1890 if (ret)
1891 pr_err("%s: Failed reading node=%s, key=%s\n",
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001892 __func__, node->full_name, key);
1893
Eugene Seahb77b0c42012-07-02 19:28:50 -06001894 return ret;
1895}
1896
Jennifer Liu907922c2013-03-26 11:18:00 -07001897
Eugene Seahb77b0c42012-07-02 19:28:50 -06001898static struct of_device_id msm_thermal_match_table[] = {
1899 {.compatible = "qcom,msm-thermal"},
1900 {},
1901};
1902
1903static struct platform_driver msm_thermal_device_driver = {
1904 .probe = msm_thermal_dev_probe,
1905 .driver = {
1906 .name = "msm-thermal",
1907 .owner = THIS_MODULE,
1908 .of_match_table = msm_thermal_match_table,
1909 },
1910};
1911
1912int __init msm_thermal_device_init(void)
1913{
1914 return platform_driver_register(&msm_thermal_device_driver);
1915}
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001916
1917int __init msm_thermal_late_init(void)
1918{
Anji Jonnala822b5c42013-05-21 20:09:24 +05301919 if (num_possible_cpus() > 1)
1920 msm_thermal_add_cc_nodes();
Jennifer Liu907922c2013-03-26 11:18:00 -07001921 msm_thermal_add_psm_nodes();
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001922 msm_thermal_add_vdd_rstr_nodes();
Archana Sathyakumar143b0b52013-04-09 14:24:32 -06001923 alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
1924 thermal_rtc_callback);
1925 INIT_WORK(&timer_work, timer_work_fn);
1926 msm_thermal_add_timer_nodes();
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001927
1928 return 0;
Praveen Chidambaram5abb7db2013-02-20 17:42:17 -07001929}
1930late_initcall(msm_thermal_late_init);
Jennifer Liu4b4f4cc2013-04-05 15:26:33 -07001931