2 * Copyright (C) 2011-2014 MediaTek Inc.
4 * This program is free software: you can redistribute it and/or modify it under the terms of the
5 * GNU General Public License version 2 as published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9 * See the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License along with this program.
12 * If not, see <http://www.gnu.org/licenses/>.
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20 #include <linux/version.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/printk.h>
24 #include <linux/types.h>
25 #include <linux/kobject.h>
26 #include <linux/proc_fs.h>
27 #include <linux/seq_file.h>
28 #include <asm/uaccess.h>
29 #include <linux/err.h>
30 #include <linux/syscalls.h>
31 #include <asm/system.h>
33 #include "mach/mtk_thermal_monitor.h"
34 #include <mach/system.h>
37 /* Extern two API functions from battery driver to limit max charging current. */
40 * return value means charging current in mA
42 * Implementation in mt_battery.c and mt_battery_fan5405.c
44 extern int get_bat_charging_current_level(void);
47 * current_limit means limit of charging current in mA
49 * Implementation in mt_battery.c and mt_battery_fan5405.c
51 extern int set_bat_charging_current_limit(int current_limit
);
54 extern struct proc_dir_entry
* mtk_thermal_get_proc_drv_therm_dir_entry(void);
56 #define mtk_cooler_bcct_dprintk_always(fmt, args...) \
57 do { pr_debug("thermal/cooler/bcct " fmt, ##args); } while (0)
59 #define mtk_cooler_bcct_dprintk(fmt, args...) \
61 if (1 == cl_bcct_klog_on) { \
62 pr_debug("thermal/cooler/bcct " fmt, ##args); \
66 #define MAX_NUM_INSTANCE_MTK_COOLER_BCCT 3
68 #define MTK_CL_BCCT_GET_LIMIT(limit, state) \
69 do { (limit) = (short) (((unsigned long) (state))>>16); } while (0)
71 #define MTK_CL_BCCT_SET_LIMIT(limit, state) \
72 do { state = ((((unsigned long) (state))&0xFFFF) | ((short) limit<<16)); } while (0)
74 #define MTK_CL_BCCT_GET_CURR_STATE(curr_state, state) \
75 do { curr_state = (((unsigned long) (state))&0xFFFF); } while (0)
77 #define MTK_CL_BCCT_SET_CURR_STATE(curr_state, state) \
78 do { if (0 == curr_state) \
84 static int cl_bcct_klog_on
;
85 static struct thermal_cooling_device
*cl_bcct_dev
[MAX_NUM_INSTANCE_MTK_COOLER_BCCT
] = { 0 };
86 static unsigned long cl_bcct_state
[MAX_NUM_INSTANCE_MTK_COOLER_BCCT
] = { 0 };
88 static int cl_bcct_cur_limit
= 65535;
90 static void mtk_cl_bcct_set_bcct_limit(void)
94 int min_limit
= 65535;
95 for (; i
< MAX_NUM_INSTANCE_MTK_COOLER_BCCT
; i
++) {
96 unsigned long curr_state
;
98 MTK_CL_BCCT_GET_CURR_STATE(curr_state
, cl_bcct_state
[i
]);
99 if (1 == curr_state
) {
101 MTK_CL_BCCT_GET_LIMIT(limit
, cl_bcct_state
[i
]);
102 if ((min_limit
> limit
) && (limit
> 0))
107 if (min_limit
!= cl_bcct_cur_limit
) {
108 cl_bcct_cur_limit
= min_limit
;
110 if (65535 <= cl_bcct_cur_limit
) {
111 set_bat_charging_current_limit(-1);
112 mtk_cooler_bcct_dprintk_always("%s limit=-1\n", __func__
);
114 set_bat_charging_current_limit(cl_bcct_cur_limit
);
115 mtk_cooler_bcct_dprintk_always("%s limit=%d\n", __func__
,
119 mtk_cooler_bcct_dprintk_always("%s real limit=%d\n", __func__
,
120 get_bat_charging_current_level() / 100);
125 static int mtk_cl_bcct_get_max_state(struct thermal_cooling_device
*cdev
, unsigned long *state
)
128 mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__
, cdev
->type
, *state
);
132 static int mtk_cl_bcct_get_cur_state(struct thermal_cooling_device
*cdev
, unsigned long *state
)
134 MTK_CL_BCCT_GET_CURR_STATE(*state
, *((unsigned long *)cdev
->devdata
));
135 mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__
, cdev
->type
, *state
);
136 mtk_cooler_bcct_dprintk("%s %s limit=%d\n", __func__
, cdev
->type
,
137 get_bat_charging_current_level() / 100);
141 static int mtk_cl_bcct_set_cur_state(struct thermal_cooling_device
*cdev
, unsigned long state
)
143 mtk_cooler_bcct_dprintk("%s %s %lu\n", __func__
, cdev
->type
, state
);
144 MTK_CL_BCCT_SET_CURR_STATE(state
, *((unsigned long *)cdev
->devdata
));
145 mtk_cl_bcct_set_bcct_limit();
146 mtk_cooler_bcct_dprintk("%s %s limit=%d\n", __func__
, cdev
->type
,
147 get_bat_charging_current_level() / 100);
152 /* bind fan callbacks to fan device */
153 static struct thermal_cooling_device_ops mtk_cl_bcct_ops
= {
154 .get_max_state
= mtk_cl_bcct_get_max_state
,
155 .get_cur_state
= mtk_cl_bcct_get_cur_state
,
156 .set_cur_state
= mtk_cl_bcct_set_cur_state
,
159 static int mtk_cooler_bcct_register_ltf(void)
162 mtk_cooler_bcct_dprintk("register ltf\n");
164 for (i
= MAX_NUM_INSTANCE_MTK_COOLER_BCCT
; i
-- > 0;) {
165 char temp
[20] = { 0 };
166 sprintf(temp
, "mtk-cl-bcct%02d", i
);
167 cl_bcct_dev
[i
] = mtk_thermal_cooling_device_register(temp
, (void *)&cl_bcct_state
[i
], /* put bcct state to cooler devdata */
174 static void mtk_cooler_bcct_unregister_ltf(void)
177 mtk_cooler_bcct_dprintk("unregister ltf\n");
179 for (i
= MAX_NUM_INSTANCE_MTK_COOLER_BCCT
; i
-- > 0;) {
180 if (cl_bcct_dev
[i
]) {
181 mtk_thermal_cooling_device_unregister(cl_bcct_dev
[i
]);
182 cl_bcct_dev
[i
] = NULL
;
183 cl_bcct_state
[i
] = 0;
189 static int _mtk_cl_bcct_proc_read(char *buf
, char **start
, off_t off
, int count
, int *eof
,
195 mtk_cooler_bcct_dprintk("[_mtk_cl_bcct_proc_read] invoked.\n");
198 * The format to print out:
199 * kernel_log <0 or 1>
200 * <mtk-cl-bcct<ID>> <bcc limit>
204 mtk_cooler_bcct_dprintk("[_mtk_cl_bcct_proc_read] null data\n");
208 p
+= sprintf(p
, "klog %d\n", cl_bcct_klog_on
);
209 p
+= sprintf(p
, "curr_limit %d\n", cl_bcct_cur_limit
);
211 for (; i
< MAX_NUM_INSTANCE_MTK_COOLER_BCCT
; i
++) {
213 unsigned int curr_state
;
215 MTK_CL_BCCT_GET_LIMIT(limit
, cl_bcct_state
[i
]);
216 MTK_CL_BCCT_GET_CURR_STATE(curr_state
, cl_bcct_state
[i
]);
218 p
+= sprintf(p
, "mtk-cl-bcct%02d %d mA, state %d\n", i
, limit
, curr_state
);
230 return len
< count
? len
: count
;
233 static ssize_t
_mtk_cl_bcct_proc_write(struct file
*file
, const char *buffer
, unsigned long count
,
238 int klog_on
, limit0
, limit1
, limit2
;
240 len
= (count
< (sizeof(desc
) - 1)) ? count
: (sizeof(desc
) - 1);
241 if (copy_from_user(desc
, buffer
, len
)) {
247 * sscanf format <klog_on> <mtk-cl-bcct00 limit> <mtk-cl-bcct01 limit> ...
248 * <klog_on> can only be 0 or 1
249 * <mtk-cl-bcct00 limit> can only be positive integer or -1 to denote no limit
253 mtk_cooler_bcct_dprintk("[_mtk_cl_bcct_proc_write] null data\n");
256 /* WARNING: Modify here if MTK_THERMAL_MONITOR_COOLER_MAX_EXTRA_CONDITIONS is changed to other than 3 */
257 #if (3 == MAX_NUM_INSTANCE_MTK_COOLER_BCCT)
258 MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state
[0]);
259 MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state
[1]);
260 MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state
[2]);
262 if (1 <= sscanf(desc
, "%d %d %d %d", &klog_on
, &limit0
, &limit1
, &limit2
)) {
263 if (klog_on
== 0 || klog_on
== 1) {
264 cl_bcct_klog_on
= klog_on
;
268 MTK_CL_BCCT_SET_LIMIT(limit0
, cl_bcct_state
[0]);
270 MTK_CL_BCCT_SET_LIMIT(limit1
, cl_bcct_state
[1]);
272 MTK_CL_BCCT_SET_LIMIT(limit2
, cl_bcct_state
[2]);
277 #error "Change correspondent part when changing MAX_NUM_INSTANCE_MTK_COOLER_BCCT!"
280 mtk_cooler_bcct_dprintk("[_mtk_cl_bcct_proc_write] bad argument\n");
287 static ssize_t
_cl_bcct_write(struct file
*filp
, const char __user
*buf
, size_t len
, loff_t
*data
)
290 char tmp
[128] = { 0 };
291 int klog_on
, limit0
, limit1
, limit2
;
293 len
= (len
< 127) ? len
: 127;
294 /* write data to the buffer */
295 if (copy_from_user(tmp
, buf
, len
)) {
300 * sscanf format <klog_on> <mtk-cl-bcct00 limit> <mtk-cl-bcct01 limit> ...
301 * <klog_on> can only be 0 or 1
302 * <mtk-cl-bcct00 limit> can only be positive integer or -1 to denote no limit
306 mtk_cooler_bcct_dprintk("%s null data\n", __func__
);
309 /* WARNING: Modify here if MTK_THERMAL_MONITOR_COOLER_MAX_EXTRA_CONDITIONS is changed to other than 3 */
310 #if (3 == MAX_NUM_INSTANCE_MTK_COOLER_BCCT)
311 MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state
[0]);
312 MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state
[1]);
313 MTK_CL_BCCT_SET_LIMIT(-1, cl_bcct_state
[2]);
315 if (1 <= sscanf(tmp
, "%d %d %d %d", &klog_on
, &limit0
, &limit1
, &limit2
)) {
316 if (klog_on
== 0 || klog_on
== 1) {
317 cl_bcct_klog_on
= klog_on
;
321 MTK_CL_BCCT_SET_LIMIT(limit0
, cl_bcct_state
[0]);
323 MTK_CL_BCCT_SET_LIMIT(limit1
, cl_bcct_state
[1]);
325 MTK_CL_BCCT_SET_LIMIT(limit2
, cl_bcct_state
[2]);
330 #error "Change correspondent part when changing MAX_NUM_INSTANCE_MTK_COOLER_BCCT!"
333 mtk_cooler_bcct_dprintk("%s bad arg\n", __func__
);
339 static int _cl_bcct_read(struct seq_file
*m
, void *v
)
342 * The format to print out:
343 * kernel_log <0 or 1>
344 * <mtk-cl-bcct<ID>> <bcc limit>
351 seq_printf(m
, "klog %d\n", cl_bcct_klog_on
);
352 seq_printf(m
, "curr_limit %d\n", cl_bcct_cur_limit
);
354 for (; i
< MAX_NUM_INSTANCE_MTK_COOLER_BCCT
; i
++) {
356 unsigned int curr_state
;
358 MTK_CL_BCCT_GET_LIMIT(limit
, cl_bcct_state
[i
]);
359 MTK_CL_BCCT_GET_CURR_STATE(curr_state
, cl_bcct_state
[i
]);
361 seq_printf(m
, "mtk-cl-bcct%02d %d mA, state %d\n", i
, limit
, curr_state
);
368 static int _cl_bcct_open(struct inode
*inode
, struct file
*file
)
370 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
371 return single_open(file
, _cl_bcct_read
, PDE_DATA(inode
));
373 return single_open(file
, _cl_bcct_read
, PDE(inode
)->data
);
377 static const struct file_operations _cl_bcct_fops
= {
378 .owner
= THIS_MODULE
,
379 .open
= _cl_bcct_open
,
382 .write
= _cl_bcct_write
,
383 .release
= single_release
,
387 static int __init
mtk_cooler_bcct_init(void)
392 for (i
= MAX_NUM_INSTANCE_MTK_COOLER_BCCT
; i
-- > 0;) {
393 cl_bcct_dev
[i
] = NULL
;
394 cl_bcct_state
[i
] = 0;
397 mtk_cooler_bcct_dprintk("%s\n", __func__
);
399 err
= mtk_cooler_bcct_register_ltf();
403 /* create a proc file */
405 struct proc_dir_entry
*entry
= NULL
;
406 struct proc_dir_entry
*dir_entry
= NULL
;
408 dir_entry
= mtk_thermal_get_proc_drv_therm_dir_entry();
410 mtk_cooler_bcct_dprintk("[%s]: mkdir /proc/driver/thermal failed\n", __func__
);
414 proc_create("clbcct", S_IRUGO
| S_IWUSR
| S_IWGRP
, dir_entry
,
417 mtk_cooler_bcct_dprintk_always("%s clbcct creation failed\n",
420 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
421 proc_set_user(entry
, 0, 1000);
430 mtk_cooler_bcct_unregister_ltf();
434 static void __exit
mtk_cooler_bcct_exit(void)
436 mtk_cooler_bcct_dprintk("exit\n");
438 /* remove the proc file */
439 remove_proc_entry("driver/mtk-cl-bcct", NULL
);
441 mtk_cooler_bcct_unregister_ltf();
443 module_init(mtk_cooler_bcct_init
);
444 module_exit(mtk_cooler_bcct_exit
);