mtk_thermal_platform.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. #include <asm/uaccess.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>
  4. #include <linux/dmi.h>
  5. #include <linux/acpi.h>
  6. #include <linux/thermal.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/types.h>
  9. #include <linux/delay.h>
  10. #include <linux/proc_fs.h>
  11. #include <linux/err.h>
  12. #include <linux/syscalls.h>
  13. #include <linux/time.h>
  14. #include <linux/string.h>
  15. #include <linux/mutex.h>
  16. #include <linux/bug.h>
  17. #include <linux/workqueue.h>
  18. #include <mtk_thermal_typedefs.h>
  19. #include "mt-plat/mtk_mdm_monitor.h"
  20. #include <mach/mt_thermal.h>
  21. #include <mt-plat/aee.h>
  22. #include <mtk_gpu_utility.h>
  23. #include <mt-plat/mtk_thermal_platform.h>
  24. #include <mt_gpufreq.h>
  25. /* ************************************ */
  26. /* Definition */
  27. /* ************************************ */
  28. /* Number of CPU CORE */
  29. #define NUMBER_OF_CORE (8)
  30. /* This function pointer is for GPU LKM to register a function to get GPU loading. */
  31. unsigned long (*mtk_thermal_get_gpu_loading_fp)(void) = NULL;
  32. EXPORT_SYMBOL(mtk_thermal_get_gpu_loading_fp);
  33. bool __attribute__ ((weak))
  34. mtk_get_gpu_loading(unsigned int *pLoading)
  35. {
  36. pr_err("E_WF: %s doesn't exist\n", __func__);
  37. return 0;
  38. }
  39. int __attribute__ ((weak))
  40. force_get_tbat(void)
  41. {
  42. pr_err("E_WF: %s doesn't exist\n", __func__);
  43. return 30;
  44. }
  45. /* ************************************ */
  46. /* Global Variable */
  47. /* ************************************ */
  48. static bool enable_ThermalMonitor;
  49. static DEFINE_MUTEX(MTM_SYSINFO_LOCK);
  50. /* ************************************ */
  51. /* Macro */
  52. /* ************************************ */
  53. #define THRML_LOG(fmt, args...) \
  54. do { \
  55. if (enable_ThermalMonitor)\
  56. pr_debug("THERMAL/PLATFORM" fmt, ##args); \
  57. } while (0)
  58. #define THRML_ERROR_LOG(fmt, args...) \
  59. pr_err("THERMAL/PLATFORM" fmt, ##args)
  60. /* ************************************ */
  61. /* Define */
  62. /* ************************************ */
  63. /* ********************************************* */
  64. /* System Information Monitor */
  65. /* ********************************************* */
  66. static mm_segment_t oldfs;
  67. /*
  68. * Read Battery Information.
  69. *
  70. * "cat /sys/devices/platform/mt6575-battery/FG_Battery_CurrentConsumption"
  71. * "cat /sys/class/power_supply/battery/batt_vol"
  72. * "cat /sys/class/power_supply/battery/batt_temp"
  73. */
  74. static int get_sys_battery_info(char *dev)
  75. {
  76. int fd;
  77. long nRet;
  78. int eCheck;
  79. int nReadSize;
  80. char buf[64];
  81. oldfs = get_fs();
  82. set_fs(KERNEL_DS);
  83. fd = sys_open(dev, O_RDONLY, 0);
  84. if (fd < 0) {
  85. THRML_LOG("[get_sys_battery_info] open fail dev:%s fd:%d\n", dev, fd);
  86. set_fs(oldfs);
  87. return fd;
  88. }
  89. nReadSize = sys_read(fd, buf, sizeof(buf) - 1);
  90. THRML_LOG("[get_sys_battery_info] nReadSize:%d\n", nReadSize);
  91. eCheck = kstrtol(buf, 10, &nRet);
  92. set_fs(oldfs);
  93. sys_close(fd);
  94. if (eCheck == 0)
  95. return (int) nRet;
  96. else
  97. return 0;
  98. }
  99. /* ********************************************* */
  100. /* Get Wifi Tx throughput */
  101. /* ********************************************* */
  102. static int get_sys_node(char *dev, int nRetryNr)
  103. {
  104. int fd;
  105. int nRet;
  106. int eCheck;
  107. int nReadSize;
  108. int nRetryCnt = 0;
  109. char buf[32];
  110. oldfs = get_fs();
  111. set_fs(KERNEL_DS);
  112. /* If sys_open fail, it will retry "nRetryNr" times. */
  113. do {
  114. fd = sys_open(dev, O_RDONLY, 0);
  115. if (nRetryCnt > nRetryNr) {
  116. THRML_LOG("[get_sys_node] open fail dev:%s fd:%d\n", dev, fd);
  117. set_fs(oldfs);
  118. return fd;
  119. }
  120. nRetryCnt++;
  121. } while (fd < 0);
  122. if (nRetryCnt > 1)
  123. THRML_LOG("[get_sys_node] open fail nRetryCnt:%d\n", nRetryCnt);
  124. nReadSize = sys_read(fd, buf, sizeof(buf) - 1);
  125. THRML_LOG("[get_sys_node] nReadSize:%d\n", nReadSize);
  126. eCheck = kstrtoint(buf, 10, &nRet);
  127. set_fs(oldfs);
  128. sys_close(fd);
  129. if (eCheck == 0)
  130. return nRet;
  131. else
  132. return 0;
  133. }
  134. /* ********************************************* */
  135. /* For get_sys_cpu_usage_info_ex() */
  136. /* ********************************************* */
  137. #define CPU_USAGE_CURRENT_FIELD (0)
  138. #define CPU_USAGE_SAVE_FIELD (1)
  139. #define CPU_USAGE_FRAME_FIELD (2)
  140. struct cpu_index_st {
  141. unsigned long u[3];
  142. unsigned long s[3];
  143. unsigned long n[3];
  144. unsigned long i[3];
  145. unsigned long w[3];
  146. unsigned long q[3];
  147. unsigned long sq[3];
  148. unsigned long tot_frme;
  149. unsigned long tz;
  150. int usage;
  151. int freq;
  152. };
  153. struct gpu_index_st {
  154. int usage;
  155. int freq;
  156. };
  157. #define NO_CPU_CORES (8)
  158. static struct cpu_index_st cpu_index_list[NO_CPU_CORES]; /* /< 4-Core is maximum */
  159. static int cpufreqs[NO_CPU_CORES];
  160. static int cpuloadings[NO_CPU_CORES];
  161. #define SEEK_BUFF(x, c) \
  162. do { \
  163. while (*x != c)\
  164. x++; \
  165. x++; \
  166. } while (0)
  167. #define TRIMz_ex(tz, x) ((tz = (unsigned long long)(x)) < 0 ? 0 : tz)
  168. /* ********************************************* */
  169. /* CPU Index */
  170. /* ********************************************* */
  171. #include <linux/kernel_stat.h>
  172. #include <linux/cpumask.h>
  173. #include <asm/cputime.h>
  174. #include <linux/sched.h>
  175. #include <linux/tick.h>
  176. #include <linux/time.h>
  177. #ifdef arch_idle_time
  178. static cputime64_t get_idle_time(int cpu)
  179. {
  180. cputime64_t idle;
  181. idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
  182. if (cpu_online(cpu) && !nr_iowait_cpu(cpu))
  183. idle += arch_idle_time(cpu);
  184. return idle;
  185. }
  186. static cputime64_t get_iowait_time(int cpu)
  187. {
  188. cputime64_t iowait;
  189. iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
  190. if (cpu_online(cpu) && nr_iowait_cpu(cpu))
  191. iowait += arch_idle_time(cpu);
  192. return iowait;
  193. }
  194. #else
  195. static u64 get_idle_time(int cpu)
  196. {
  197. u64 idle, idle_time = -1ULL;
  198. if (cpu_online(cpu))
  199. idle_time = get_cpu_idle_time_us(cpu, NULL);
  200. if (idle_time == -1ULL)
  201. /* !NO_HZ or cpu offline so we can rely on cpustat.idle */
  202. idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
  203. else
  204. idle = usecs_to_cputime64(idle_time);
  205. return idle;
  206. }
  207. static u64 get_iowait_time(int cpu)
  208. {
  209. u64 iowait, iowait_time = -1ULL;
  210. if (cpu_online(cpu))
  211. iowait_time = get_cpu_iowait_time_us(cpu, NULL);
  212. if (iowait_time == -1ULL)
  213. /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */
  214. iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
  215. else
  216. iowait = usecs_to_cputime64(iowait_time);
  217. return iowait;
  218. }
  219. #endif
  220. static int get_sys_cpu_usage_info_ex(void)
  221. {
  222. int nCoreIndex = 0, i;
  223. for (i = 0; i < NO_CPU_CORES; i++)
  224. cpuloadings[i] = 0;
  225. for_each_online_cpu(nCoreIndex) {
  226. /* Get CPU Info */
  227. cpu_index_list[nCoreIndex].u[CPU_USAGE_CURRENT_FIELD] =
  228. kcpustat_cpu(nCoreIndex).cpustat[CPUTIME_USER];
  229. cpu_index_list[nCoreIndex].n[CPU_USAGE_CURRENT_FIELD] =
  230. kcpustat_cpu(nCoreIndex).cpustat[CPUTIME_NICE];
  231. cpu_index_list[nCoreIndex].s[CPU_USAGE_CURRENT_FIELD] =
  232. kcpustat_cpu(nCoreIndex).cpustat[CPUTIME_SYSTEM];
  233. cpu_index_list[nCoreIndex].i[CPU_USAGE_CURRENT_FIELD] = get_idle_time(nCoreIndex);
  234. cpu_index_list[nCoreIndex].w[CPU_USAGE_CURRENT_FIELD] = get_iowait_time(nCoreIndex);
  235. cpu_index_list[nCoreIndex].q[CPU_USAGE_CURRENT_FIELD] =
  236. kcpustat_cpu(nCoreIndex).cpustat[CPUTIME_IRQ];
  237. cpu_index_list[nCoreIndex].sq[CPU_USAGE_CURRENT_FIELD] =
  238. kcpustat_cpu(nCoreIndex).cpustat[CPUTIME_SOFTIRQ];
  239. /* Frame */
  240. cpu_index_list[nCoreIndex].u[CPU_USAGE_FRAME_FIELD] =
  241. cpu_index_list[nCoreIndex].u[CPU_USAGE_CURRENT_FIELD] -
  242. cpu_index_list[nCoreIndex].u[CPU_USAGE_SAVE_FIELD];
  243. cpu_index_list[nCoreIndex].n[CPU_USAGE_FRAME_FIELD] =
  244. cpu_index_list[nCoreIndex].n[CPU_USAGE_CURRENT_FIELD] -
  245. cpu_index_list[nCoreIndex].n[CPU_USAGE_SAVE_FIELD];
  246. cpu_index_list[nCoreIndex].s[CPU_USAGE_FRAME_FIELD] =
  247. cpu_index_list[nCoreIndex].s[CPU_USAGE_CURRENT_FIELD] -
  248. cpu_index_list[nCoreIndex].s[CPU_USAGE_SAVE_FIELD];
  249. cpu_index_list[nCoreIndex].i[CPU_USAGE_FRAME_FIELD] =
  250. TRIMz_ex(cpu_index_list[nCoreIndex].tz,
  251. (cpu_index_list[nCoreIndex].i[CPU_USAGE_CURRENT_FIELD] -
  252. cpu_index_list[nCoreIndex].i[CPU_USAGE_SAVE_FIELD]));
  253. cpu_index_list[nCoreIndex].w[CPU_USAGE_FRAME_FIELD] =
  254. cpu_index_list[nCoreIndex].w[CPU_USAGE_CURRENT_FIELD] -
  255. cpu_index_list[nCoreIndex].w[CPU_USAGE_SAVE_FIELD];
  256. cpu_index_list[nCoreIndex].q[CPU_USAGE_FRAME_FIELD] =
  257. cpu_index_list[nCoreIndex].q[CPU_USAGE_CURRENT_FIELD] -
  258. cpu_index_list[nCoreIndex].q[CPU_USAGE_SAVE_FIELD];
  259. cpu_index_list[nCoreIndex].sq[CPU_USAGE_FRAME_FIELD] =
  260. cpu_index_list[nCoreIndex].sq[CPU_USAGE_CURRENT_FIELD] -
  261. cpu_index_list[nCoreIndex].sq[CPU_USAGE_SAVE_FIELD];
  262. /* Total Frame */
  263. cpu_index_list[nCoreIndex].tot_frme =
  264. cpu_index_list[nCoreIndex].u[CPU_USAGE_FRAME_FIELD] +
  265. cpu_index_list[nCoreIndex].n[CPU_USAGE_FRAME_FIELD] +
  266. cpu_index_list[nCoreIndex].s[CPU_USAGE_FRAME_FIELD] +
  267. cpu_index_list[nCoreIndex].i[CPU_USAGE_FRAME_FIELD] +
  268. cpu_index_list[nCoreIndex].w[CPU_USAGE_FRAME_FIELD] +
  269. cpu_index_list[nCoreIndex].q[CPU_USAGE_FRAME_FIELD] +
  270. cpu_index_list[nCoreIndex].sq[CPU_USAGE_FRAME_FIELD];
  271. /* CPU Usage */
  272. if (cpu_index_list[nCoreIndex].tot_frme > 0) {
  273. cpuloadings[nCoreIndex] =
  274. (100 -
  275. (((int)cpu_index_list[nCoreIndex].i[CPU_USAGE_FRAME_FIELD] * 100) /
  276. (int)cpu_index_list[nCoreIndex].tot_frme));
  277. } else {
  278. /* CPU unplug case */
  279. cpuloadings[nCoreIndex] = 0;
  280. }
  281. cpu_index_list[nCoreIndex].u[CPU_USAGE_SAVE_FIELD] =
  282. cpu_index_list[nCoreIndex].u[CPU_USAGE_CURRENT_FIELD];
  283. cpu_index_list[nCoreIndex].n[CPU_USAGE_SAVE_FIELD] =
  284. cpu_index_list[nCoreIndex].n[CPU_USAGE_CURRENT_FIELD];
  285. cpu_index_list[nCoreIndex].s[CPU_USAGE_SAVE_FIELD] =
  286. cpu_index_list[nCoreIndex].s[CPU_USAGE_CURRENT_FIELD];
  287. cpu_index_list[nCoreIndex].i[CPU_USAGE_SAVE_FIELD] =
  288. cpu_index_list[nCoreIndex].i[CPU_USAGE_CURRENT_FIELD];
  289. cpu_index_list[nCoreIndex].w[CPU_USAGE_SAVE_FIELD] =
  290. cpu_index_list[nCoreIndex].w[CPU_USAGE_CURRENT_FIELD];
  291. cpu_index_list[nCoreIndex].q[CPU_USAGE_SAVE_FIELD] =
  292. cpu_index_list[nCoreIndex].q[CPU_USAGE_CURRENT_FIELD];
  293. cpu_index_list[nCoreIndex].sq[CPU_USAGE_SAVE_FIELD] =
  294. cpu_index_list[nCoreIndex].sq[CPU_USAGE_CURRENT_FIELD];
  295. THRML_LOG("CPU%d Frame:%lu USAGE:%d\n", nCoreIndex,
  296. cpu_index_list[nCoreIndex].tot_frme, cpuloadings[nCoreIndex]);
  297. for (i = 0; i < 3; i++) {
  298. THRML_LOG
  299. ("Index %d [u:%lu] [n:%lu] [s:%lu] [i:%lu] [w:%lu] [q:%lu] [sq:%lu]\n",
  300. i, cpu_index_list[nCoreIndex].u[i], cpu_index_list[nCoreIndex].n[i],
  301. cpu_index_list[nCoreIndex].s[i], cpu_index_list[nCoreIndex].i[i],
  302. cpu_index_list[nCoreIndex].w[i], cpu_index_list[nCoreIndex].q[i],
  303. cpu_index_list[nCoreIndex].sq[i]);
  304. }
  305. }
  306. return 0;
  307. }
  308. static bool dmips_limit_warned;
  309. static int check_dmips_limit;
  310. #include <linux/cpufreq.h>
  311. static int get_sys_all_cpu_freq_info(void)
  312. {
  313. int i;
  314. int cpu_total_dmips = 0;
  315. for (i = 0; i < NO_CPU_CORES; i++) {
  316. cpufreqs[i] = cpufreq_quick_get(i) / 1000; /* MHz */
  317. cpu_total_dmips += cpufreqs[i];
  318. }
  319. cpu_total_dmips /= 1000;
  320. /* TODO: think a way to easy start and stop, and start for only once */
  321. if (1 == check_dmips_limit) {
  322. if (cpu_total_dmips > mtktscpu_limited_dmips) {
  323. THRML_ERROR_LOG("cpu %d over limit %d\n", cpu_total_dmips,
  324. mtktscpu_limited_dmips);
  325. if (dmips_limit_warned == false) {
  326. #ifdef CONFIG_MTK_AEE_FEATURE
  327. aee_kernel_warning("thermal", "cpu %d over limit %d\n",
  328. cpu_total_dmips, mtktscpu_limited_dmips);
  329. #endif
  330. dmips_limit_warned = true;
  331. }
  332. }
  333. }
  334. return 0;
  335. }
  336. static int mtk_thermal_validation_rd(struct seq_file *m, void *v)
  337. {
  338. seq_printf(m, "%d\n", check_dmips_limit);
  339. return 0;
  340. }
  341. static ssize_t mtk_thermal_validation_wr(struct file *file, const char __user *buffer,
  342. size_t count, loff_t *data)
  343. {
  344. char desc[32];
  345. int check_switch;
  346. int len = 0;
  347. len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1);
  348. if (copy_from_user(desc, buffer, len))
  349. return 0;
  350. desc[len] = '\0';
  351. if (kstrtoint(desc, 10, &check_switch) == 0) {
  352. if (1 == check_switch) {
  353. dmips_limit_warned = false;
  354. check_dmips_limit = check_switch;
  355. } else if (0 == check_switch) {
  356. check_dmips_limit = check_switch;
  357. }
  358. return count;
  359. }
  360. THRML_ERROR_LOG("[mtk_thermal_validation_wr] bad argument\n");
  361. return -EINVAL;
  362. }
  363. static int mtk_thermal_validation_open(struct inode *inode, struct file *file)
  364. {
  365. return single_open(file, mtk_thermal_validation_rd, NULL);
  366. }
  367. static const struct file_operations mtk_thermal_validation_fops = {
  368. .owner = THIS_MODULE,
  369. .open = mtk_thermal_validation_open,
  370. .read = seq_read,
  371. .llseek = seq_lseek,
  372. .write = mtk_thermal_validation_wr,
  373. .release = single_release,
  374. };
  375. /* Init */
  376. static int __init mtk_thermal_platform_init(void)
  377. {
  378. int err = 0;
  379. struct proc_dir_entry *entry;
  380. entry = proc_create("driver/tm_validation", S_IRUGO | S_IWUSR, NULL,
  381. &mtk_thermal_validation_fops);
  382. if (!entry) {
  383. THRML_ERROR_LOG
  384. ("[mtk_thermal_platform_init] Can not create /proc/driver/tm_validation\n");
  385. }
  386. return err;
  387. }
  388. /* Exit */
  389. static void __exit mtk_thermal_platform_exit(void)
  390. {
  391. }
  392. int mtk_thermal_get_cpu_info(int *nocores, int **cpufreq, int **cpuloading)
  393. {
  394. /* ****************** */
  395. /* CPU Usage */
  396. /* ****************** */
  397. mutex_lock(&MTM_SYSINFO_LOCK);
  398. /* Read CPU Usage Information */
  399. get_sys_cpu_usage_info_ex();
  400. get_sys_all_cpu_freq_info();
  401. mutex_unlock(&MTM_SYSINFO_LOCK);
  402. if (nocores)
  403. *nocores = NO_CPU_CORES;
  404. if (cpufreq)
  405. *cpufreq = cpufreqs;
  406. if (cpuloading)
  407. *cpuloading = cpuloadings;
  408. return 0;
  409. }
  410. EXPORT_SYMBOL(mtk_thermal_get_cpu_info);
  411. #define NO_GPU_CORES (1)
  412. static int gpufreqs[NO_GPU_CORES];
  413. static int gpuloadings[NO_GPU_CORES];
  414. int mtk_thermal_get_gpu_info(int *nocores, int **gpufreq, int **gpuloading)
  415. {
  416. /* ****************** */
  417. /* GPU Index */
  418. /* ****************** */
  419. THRML_LOG("[mtk_thermal_get_gpu_info]\n");
  420. if (nocores)
  421. *nocores = NO_GPU_CORES;
  422. if (gpufreq) {
  423. gpufreqs[0] = mt_gpufreq_get_cur_freq() / 1000; /* MHz */
  424. *gpufreq = gpufreqs;
  425. }
  426. if (gpuloading) {
  427. unsigned int rd_gpu_loading = 0;
  428. if (mtk_get_gpu_loading(&rd_gpu_loading)) {
  429. gpuloadings[0] = (int)rd_gpu_loading;
  430. *gpuloading = gpuloadings;
  431. }
  432. }
  433. return 0;
  434. }
  435. EXPORT_SYMBOL(mtk_thermal_get_gpu_info);
  436. int mtk_thermal_get_batt_info(int *batt_voltage, int *batt_current, int *batt_temp)
  437. {
  438. /* ****************** */
  439. /* Battery */
  440. /* ****************** */
  441. /* Read Battery Information */
  442. if (batt_current) {
  443. *batt_current =
  444. get_sys_battery_info
  445. ("/sys/devices/platform/battery/FG_Battery_CurrentConsumption");
  446. /* the return value is 0.1mA */
  447. if (*batt_current % 10 < 5)
  448. *batt_current /= 10;
  449. else
  450. *batt_current = 1 + (*batt_current / 10);
  451. #if defined(CONFIG_MTK_SMART_BATTERY)
  452. if (KAL_TRUE == gFG_Is_Charging)
  453. *batt_current *= -1;
  454. #endif
  455. }
  456. if (batt_voltage)
  457. *batt_voltage = get_sys_battery_info("/sys/class/power_supply/battery/batt_vol");
  458. if (batt_temp)
  459. *batt_temp = get_sys_battery_info("/sys/class/power_supply/battery/batt_temp");
  460. return 0;
  461. }
  462. EXPORT_SYMBOL(mtk_thermal_get_batt_info);
  463. /* ********************************************* */
  464. /* Get Extra Info */
  465. /* ********************************************* */
  466. #define MIN(_a_, _b_) ((_a_) < (_b_) ? (_a_) : (_b_))
  467. static unsigned int ma_len = 5; /* max 60 */
  468. static unsigned int ma_counter;
  469. static unsigned int ma[60];
  470. static unsigned int get_sma(unsigned int latest_val)
  471. {
  472. unsigned int ret = 0;
  473. int i = 0;
  474. ma[(ma_counter) % (ma_len)] = latest_val;
  475. ma_counter++;
  476. for (i = 0; i < MIN(ma_counter, ma_len); i++)
  477. ret += ma[i];
  478. ret = ret / (MIN(ma_counter, ma_len));
  479. return ret;
  480. }
  481. enum {
  482. /* TXPWR_MD1 = 0,
  483. TXPWR_MD2 =1,
  484. RFTEMP_2G_MD1 =2,
  485. RFTEMP_2G_MD2 = 3,
  486. RFTEMP_3G_MD1 = 4,
  487. RFTEMP_3G_MD2 = 5, */
  488. WiFi_TP = 6,
  489. Mobile_TP = 7,
  490. NO_EXTRA_THERMAL_ATTR
  491. };
  492. static char *extra_attr_names[NO_EXTRA_THERMAL_ATTR] = { 0 };
  493. static int extra_attr_values[NO_EXTRA_THERMAL_ATTR] = { 0 };
  494. static char *extra_attr_units[NO_EXTRA_THERMAL_ATTR] = { 0 };
  495. int mtk_thermal_get_extra_info(int *no_extra_attr,
  496. char ***attr_names, int **attr_values, char ***attr_units)
  497. {
  498. int size, i = 0;
  499. if (no_extra_attr)
  500. *no_extra_attr = NO_EXTRA_THERMAL_ATTR;
  501. /* ****************** */
  502. /* Modem Index */
  503. /* ****************** */
  504. THRML_LOG("[mtk_thermal_get_extra_info] mtk_mdm_get_md_info\n");
  505. {
  506. struct md_info *p_info;
  507. mtk_mdm_get_md_info(&p_info, &size);
  508. THRML_LOG("[mtk_thermal_get_extra_info] mtk_mdm_get_md_info size %d\n", size);
  509. if (size <= NO_EXTRA_THERMAL_ATTR - 2) {
  510. for (i = 0; i < size; i++) {
  511. extra_attr_names[i] = p_info[i].attribute;
  512. extra_attr_values[i] = p_info[i].value;
  513. extra_attr_units[i] = p_info[i].unit;
  514. }
  515. }
  516. }
  517. /* Get Mobile Tx throughput */
  518. {
  519. extra_attr_names[Mobile_TP] = "Mobile_TP";
  520. extra_attr_values[Mobile_TP] = get_sys_node("/proc/mobile_tm/tx_thro", 3);
  521. THRML_LOG("[mtk_thermal_get_extra_info] /proc/mobile_tm/tx_thro = %d\n", extra_attr_values[Mobile_TP]);
  522. extra_attr_values[Mobile_TP] = get_sma(extra_attr_values[Mobile_TP]);
  523. THRML_LOG("[mtk_thermal_get_extra_info] /proc/mobile_tm/tx_thro SMA = %d\n",
  524. extra_attr_values[Mobile_TP]);
  525. extra_attr_units[Mobile_TP] = "Kbps";
  526. }
  527. /* ****************** */
  528. /* Wifi Index */
  529. /* ****************** */
  530. /* Get Wi-Fi Tx throughput */
  531. extra_attr_names[WiFi_TP] = "WiFi_TP";
  532. extra_attr_values[WiFi_TP] = get_sys_node("/proc/driver/thermal/wifi_tx_thro", 3);
  533. extra_attr_units[WiFi_TP] = "Kbps";
  534. if (attr_names)
  535. *attr_names = extra_attr_names;
  536. if (attr_values)
  537. *attr_values = extra_attr_values;
  538. if (attr_units)
  539. *attr_units = extra_attr_units;
  540. return 0;
  541. }
  542. EXPORT_SYMBOL(mtk_thermal_get_extra_info);
  543. int mtk_thermal_force_get_batt_temp(void)
  544. {
  545. int ret = 0;
  546. ret = force_get_tbat();
  547. return ret;
  548. }
  549. EXPORT_SYMBOL(mtk_thermal_force_get_batt_temp);
  550. static unsigned int _thermal_scen;
  551. unsigned int mtk_thermal_set_user_scenarios(unsigned int mask)
  552. {
  553. if ((mask & MTK_THERMAL_SCEN_CALL)) { /* only one scen is handled now... */
  554. set_taklking_flag(true); /* make mtk_ts_cpu.c aware of call scenario */
  555. _thermal_scen |= (unsigned int)MTK_THERMAL_SCEN_CALL;
  556. }
  557. return _thermal_scen;
  558. }
  559. EXPORT_SYMBOL(mtk_thermal_set_user_scenarios);
  560. unsigned int mtk_thermal_clear_user_scenarios(unsigned int mask)
  561. {
  562. if ((mask & MTK_THERMAL_SCEN_CALL)) { /* only one scen is handled now... */
  563. set_taklking_flag(false); /* make mtk_ts_cpu.c aware of call scenario */
  564. _thermal_scen &= ~((unsigned int)MTK_THERMAL_SCEN_CALL);
  565. }
  566. return _thermal_scen;
  567. }
  568. EXPORT_SYMBOL(mtk_thermal_clear_user_scenarios);
  569. module_init(mtk_thermal_platform_init);
  570. module_exit(mtk_thermal_platform_exit);