From cdeae3e8b6e70fed6ecf365b48a4cf899436a377 Mon Sep 17 00:00:00 2001 From: Tellen Yu Date: Thu, 20 Jul 2017 09:18:09 +0000 Subject: HIDL: add thermal HAL [3/3] PD# NONE add a new HAL:thermal that was used by powerUI Change-Id: I5fd72c05a590134d069f202e1a74773ed5f09324 --- diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..3cb56a6 --- a/dev/null +++ b/Android.mk @@ -0,0 +1,31 @@ +# Copyright (C) 2015 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26 && echo OK),OK) +LOCAL_PROPRIETARY_MODULE := true +endif + +LOCAL_MODULE := thermal.amlogic +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_SRC_FILES := thermal.cpp +LOCAL_SHARED_LIBRARIES := liblog libcutils +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := -Wno-unused-parameter + +include $(BUILD_SHARED_LIBRARY) diff --git a/Kconfig b/Kconfig deleted file mode 100755 index 6757715..0000000 --- a/Kconfig +++ b/dev/null @@ -1,28 +0,0 @@ -# Amlogic Thermal - - -config AML_VIRTUAL_THERMAL - bool "Amlogic virtual thermal interface" - default n - help - Say Y if you want use amlogic virtual thermal interface - -config AML_PLATFORM_THERMAL - bool "Amlogic platform thermal interface" - default n - help - Say Y if you want use amlogic platform thermal interface - -config AMLOGIC_THERMAL - tristate "amlogic thermal support" - select THERMAL - select CPU_THERMAL - select GPU_THERMAL - select CPUCORE_THERMAL - select GPUCORE_THERMAL - select AML_VIRTUAL_THERMAL - select AML_PLATFORM_THERMAL - depends on CPU_FREQ - default n - help - This is the Amlogic Thermal interface driver diff --git a/Makefile b/Makefile deleted file mode 100755 index 189834c..0000000 --- a/Makefile +++ b/dev/null @@ -1,30 +0,0 @@ -# -#Makefile for the thermal dirver -# -#$(obj)/aml_thermal.o: -# $(obj)/aml_thermal.o $(obj)/aml_thermal_f.o FORCE - -$(obj)/thermal_clean: - $(call cmd,clean) - -KBUILD_CFLAGS += -Wno-error=date-time -CONFIG_AMLOGIC_THERMAL=m -obj-$(CONFIG_AMLOGIC_THERMAL)+= aml_thermal.o - -$(obj)/amlogic_thermal.o: $(obj)/thermal_clean FORCE - -aml_thermal-objs = -aml_thermal-objs += amlogic_thermal.o -aml_thermal-objs += amlogic_thermal_module.o - -clean: - @find $(srctree) \ - -name "*.mod.*" \ - -o -name ".*.rej" \ - -o -name "*%" \ - -o -name ".*.cmd" \ - -o -name "*.bak" \ - -o -name "Module.symvers" \ - -o -name "modules.order" \ - -o -name "*.o" \ - -o -name "*.ko" | xargs rm -f diff --git a/amlogic_thermal.h b/amlogic_thermal.h deleted file mode 100644 index 13a6ca7..0000000 --- a/amlogic_thermal.h +++ b/dev/null @@ -1,114 +0,0 @@ - -#ifndef __AMLOGIC_THERMAL_H__ -#define __AMLOGIC_THERMAL_H__ - -struct record_buf { - int idx; - int max; - unsigned long cool_flag; - unsigned int *op; -}; - -struct cpu_stat_monitor { - unsigned int total_cpu_freq; - unsigned int total_gpu_freq; - unsigned int total_cpu_cores; - unsigned int total_gpu_cores; - unsigned int avg_cpu_freq; - unsigned int avg_gpu_freq; - unsigned int avg_cpu_cores; - unsigned int avg_gpu_cores; - unsigned int filter_temp; -}; - -struct aml_virtual_thermal { - unsigned int freq; - unsigned int temp_time[4]; -}; - -struct aml_virtual_thermal_device { - int count; - struct aml_virtual_thermal *thermal; -}; - -struct temp_trip{ - unsigned int temperature; - unsigned int cpu_upper_freq; - unsigned int cpu_lower_freq; - int cpu_upper_level; - int cpu_lower_level; - unsigned int gpu_upper_freq; - unsigned int gpu_lower_freq; - int gpu_upper_level; - int gpu_lower_level; - int cpu_core_num; - int cpu_core_upper; - int gpu_core_num; - int gpu_core_upper; -}; - -struct amlogic_thermal_platform_data { - const char *name; - struct temp_trip *tmp_trip; - unsigned int temp_trip_count; - unsigned int temp_valid; - unsigned int current_temp; - unsigned int idle_interval; - unsigned int trim_flag; - unsigned int virtual_thermal_en; - unsigned int keep_mode; - unsigned int keep_mode_threshold; - unsigned int keep_mode_ini_state[4]; - unsigned int keep_mode_cur_state[4]; - unsigned int keep_mode_max_state[4]; - unsigned int keep_mode_min_state[4]; - unsigned int keep_mode_max_range[4]; - unsigned int keep_mode_min_range[4]; - unsigned int keep_min_exist; - unsigned int freq_sample_period; - struct record_buf op_buf; - struct cpu_stat_monitor monitor; - struct thermal_zone_device *therm_dev; - struct thermal_cooling_device *cpu_cool_dev; - struct thermal_cooling_device *gpu_cool_dev; - struct thermal_cooling_device *cpucore_cool_dev; - struct thermal_cooling_device *gpucore_cool_dev; - enum thermal_device_mode mode; - struct mutex lock; - struct delayed_work thermal_work; -}; - -struct temp_level{ - unsigned int temperature; - int cpu_high_freq; - int cpu_low_freq; - int gpu_high_freq; - int gpu_low_freq; - int cpu_core_num; - int gpu_core_num; -}; - -struct freq_trip_table { - unsigned int freq_state; -}; - -void *thermal_alloc(size_t len); -extern int thermal_debug_enable; -extern int high_temp_protect; -extern atomic_t freq_update_flag; - -void thermal_atomic_set(atomic_t *a, int); -void thermal_lock(struct mutex *lock); -void thermal_unlock(struct mutex *lock); -void keep_mode_set_mode(struct amlogic_thermal_platform_data *); -void keep_mode_bind(struct amlogic_thermal_platform_data *, unsigned long , int ); -void keep_mode_work(struct amlogic_thermal_platform_data *, int); -void keep_mode_update_threshold(struct amlogic_thermal_platform_data *, int ); -void keep_mode_temp_level_init(struct amlogic_thermal_platform_data *, struct temp_level *); -void *aml_get_cdevdata(struct thermal_cooling_device *cdev); -void aml_set_cdev_update(struct thermal_cooling_device *cdev, bool update); -void aml_cdev_lockop(struct thermal_cooling_device *cdev, bool lock); -void aml_cdev_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *ret); -int gpu_get_freq_level(int freq); - -#endif /* __AMLOGIC_THERMAL_H__ */ diff --git a/amlogic_thermal.o_shipped b/amlogic_thermal.o_shipped deleted file mode 100644 index f6c0f4d..0000000 --- a/amlogic_thermal.o_shipped +++ b/dev/null @@ -1,166 +0,0 @@ -ELF -@¹!|@“ -€¹ -€¹ -@¹bj@¹? -@¹ˆ@¹! - - -‡* -¥ - -‡* -  -  - - - - - - - - - - - - - - - - - - - - - -" -  - -Œ - 8 -Y= - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -•" -2'Z% - - -Ý - -— -Ò - -H -^ - -j - : ;  - - - - - - - - s  !z #"!!/11"0v  .>=5",0!L=Lå -ÓAÞÝ  -ÔÓAÕAÞÝ  -ÕAÓÔAÝÞ  -” •–—˜W -ÔÓAÖÕAØ×AÞÝ  - AÔÓAÖÕAÞÝ -˜ ™šI - AÔÓAÖÕAØ×AÚÙAÞÝ - - - - - - - - - - - - - -I - - - - - - - - - - - - - - - - - - -) - - - - - - - -$ -& - - -6 -9 - - - - - - -R - - - - - - - - -@ - - -y - diff --git a/amlogic_thermal_module.c b/amlogic_thermal_module.c deleted file mode 100644 index f9cdafb..0000000 --- a/amlogic_thermal_module.c +++ b/dev/null @@ -1,1108 +0,0 @@ -/* - * amlogic_thermal.c - Samsung amlogic thermal (Thermal Management Unit) - * - * Copyright (C) 2011 Samsung Electronics - * Donggeun Kim - * Amit Daniel Kachhap - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 10, 33) -#include -#else -#include -#endif -#include -#include "amlogic_thermal.h" - -#define DBG_VIRTUAL 0 -#define MIN_TEMP (-273) -int thermal_debug_enable = 0; -int high_temp_protect = 0; -atomic_t freq_update_flag; -EXPORT_SYMBOL(thermal_debug_enable); -EXPORT_SYMBOL(high_temp_protect); -EXPORT_SYMBOL(freq_update_flag); - -#define THERMAL_DBG(format,args...) \ - if (thermal_debug_enable) { \ - printk("[THERMAL]"format, ##args); \ - } - -static struct device *dbg_dev; - -#define THERMAL_ERR(format, args...) \ - {if (dbg_dev) \ - dev_err(dbg_dev, format, ##args); \ - } - -#define THERMAL_INFO(format, args...) \ - {if (dbg_dev) \ - dev_info(dbg_dev, format, ##args); \ - } - -static struct aml_virtual_thermal_device cpu_virtual_thermal = {}; -static struct aml_virtual_thermal_device gpu_virtual_thermal = {}; -static unsigned int report_interval[4] = {}; -static int (*gpu_freq_level)(int ) = NULL; - -/* CPU Zone information */ -#define PANIC_ZONE 4 -#define WARN_ZONE 3 -#define MONITOR_ZONE 2 -#define SAFE_ZONE 1 - -#define GET_ZONE(trip) (trip + 2) -#define GET_TRIP(zone) (zone - 2) - -static void amlogic_unregister_thermal(struct amlogic_thermal_platform_data *pdata); -static int amlogic_register_thermal(struct amlogic_thermal_platform_data *pdata, struct platform_device *pdev); - -void thermal_lock(struct mutex *lock) -{ - mutex_lock(lock); -} -EXPORT_SYMBOL(thermal_lock); - -void thermal_unlock(struct mutex *lock) -{ - mutex_unlock(lock); -} -EXPORT_SYMBOL(thermal_unlock); - -/* Get mode callback functions for thermal zone */ -static int amlogic_get_mode(struct thermal_zone_device *thermal, - enum thermal_device_mode *mode) -{ - struct amlogic_thermal_platform_data *pdata= thermal->devdata; - - if (pdata) - *mode = pdata->mode; - return 0; -} - -/* Set mode callback functions for thermal zone */ -static int amlogic_set_mode(struct thermal_zone_device *thermal, - enum thermal_device_mode mode) -{ - struct amlogic_thermal_platform_data *pdata= thermal->devdata; - struct cpucore_cooling_device *cpucore_device =NULL; - struct gpucore_cooling_device *gpucore_device = NULL; - if(!pdata) - return -EINVAL; - - //mutex_lock(&pdata->therm_dev->lock); - - if (mode == THERMAL_DEVICE_ENABLED){ - pdata->therm_dev->polling_delay = pdata->idle_interval; - if(pdata->cpucore_cool_dev){ - cpucore_device=pdata->cpucore_cool_dev->devdata; - cpucore_device->stop_flag=0; - } - if(pdata->gpucore_cool_dev){ - gpucore_device=pdata->gpucore_cool_dev->devdata; - gpucore_device->stop_flag=0; - } - if (pdata->keep_mode) { // start work - schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100)); - } - } - else{ - pdata->therm_dev->polling_delay = 0; - if (pdata->keep_mode) { - cancel_delayed_work_sync(&pdata->thermal_work); - keep_mode_set_mode(pdata); - } - if(pdata->cpucore_cool_dev) - pdata->cpucore_cool_dev->ops->set_cur_state(pdata->cpucore_cool_dev,(0|CPU_STOP)); - if(pdata->gpucore_cool_dev) - pdata->gpucore_cool_dev->ops->set_cur_state(pdata->gpucore_cool_dev,(0|GPU_STOP)); - } - - //mutex_unlock(&pdata->therm_dev->lock); - - pdata->mode = mode; - thermal_zone_device_update(pdata->therm_dev); - THERMAL_INFO("thermal polling set for duration=%d msec\n", - pdata->therm_dev->polling_delay); - return 0; -} - -/* Get trip type callback functions for thermal zone */ -static int amlogic_get_trip_type(struct thermal_zone_device *thermal, int trip, - enum thermal_trip_type *type) -{ - if(trip < thermal->trips-1) - *type = THERMAL_TRIP_ACTIVE; - else if(trip == thermal->trips-1) - *type = THERMAL_TRIP_CRITICAL; - else - return -EINVAL; - return 0; -} - -/* Get trip temperature callback functions for thermal zone */ -static int amlogic_get_trip_temp(struct thermal_zone_device *thermal, int trip, - unsigned long *temp) -{ - struct amlogic_thermal_platform_data *pdata= thermal->devdata; - - if(trip > pdata->temp_trip_count ||trip<0) - return -EINVAL; - mutex_lock(&pdata->lock); - *temp =pdata->tmp_trip[trip].temperature; - /* convert the temperature into millicelsius */ - mutex_unlock(&pdata->lock); - - return 0; -} - -static int amlogic_set_trip_temp(struct thermal_zone_device *thermal, int trip, - unsigned long temp) -{ - struct amlogic_thermal_platform_data *pdata= thermal->devdata; - - if(trip > pdata->temp_trip_count ||trip<0) - return -EINVAL; - mutex_lock(&pdata->lock); - pdata->tmp_trip[trip].temperature=temp; - /* convert the temperature into millicelsius */ - mutex_unlock(&pdata->lock); - return 0; -} - -/* Get critical temperature callback functions for thermal zone */ -static int amlogic_get_crit_temp(struct thermal_zone_device *thermal, - unsigned long *temp) -{ - int ret; - /* Panic zone */ - ret =amlogic_get_trip_temp(thermal, thermal->trips-1, temp); - - return ret; -} - -int gpu_get_freq_level(int freq) -{ - if (gpu_freq_level) - return gpu_freq_level(freq); - else - return -1; -} - -/* Bind callback functions for thermal zone */ -static int amlogic_bind(struct thermal_zone_device *thermal, - struct thermal_cooling_device *cdev) -{ - int ret = 0, i; - struct amlogic_thermal_platform_data *pdata= thermal->devdata; - int id; - char type[THERMAL_NAME_LENGTH]; - unsigned long max; - - if (!sscanf(cdev->type, "thermal-%7s-%d", type,&id)) - return -EINVAL; - if(!strcmp(type,"cpufreq")){ - /* Bind the thermal zone to the cpufreq cooling device */ - for (i = 0; i < pdata->temp_trip_count; i++) { - if(pdata->tmp_trip[0].cpu_upper_level==THERMAL_CSTATE_INVALID) - { - ret = -EINVAL; - goto out; - } - if (thermal_zone_bind_cooling_device(thermal, i, cdev, - pdata->tmp_trip[i].cpu_upper_level, - pdata->tmp_trip[i].cpu_lower_level)) { - THERMAL_ERR("error binding cdev inst %d\n", i); - ret = -EINVAL; - goto out; - } - } - if (pdata->keep_mode) { - cdev->ops->get_max_state(cdev, &max); - keep_mode_bind(pdata, max, 0); - } - } - - if(!strcmp(type,"gpufreq")){ - struct gpufreq_cooling_device *gpufreq_dev= - (struct gpufreq_cooling_device *)cdev->devdata; - /* Bind the thermal zone to the cpufreq cooling device */ - for (i = 0; i < pdata->temp_trip_count; i++) { - if(!gpufreq_dev->get_gpu_freq_level){ - ret = -EINVAL; - THERMAL_ERR("invalidate pointer %p\n",gpufreq_dev->get_gpu_freq_level); - goto out; - } else { - gpu_freq_level = gpufreq_dev->get_gpu_freq_level; - } - pdata->tmp_trip[i].gpu_lower_level=gpufreq_dev->get_gpu_freq_level(pdata->tmp_trip[i].gpu_upper_freq); - pdata->tmp_trip[i].gpu_upper_level=gpufreq_dev->get_gpu_freq_level(pdata->tmp_trip[i].gpu_lower_freq); - if(pdata->tmp_trip[0].gpu_lower_level==THERMAL_CSTATE_INVALID) - { - ret = -EINVAL; - goto out; - } - if (thermal_zone_bind_cooling_device(thermal, i, cdev, - pdata->tmp_trip[i].gpu_upper_level, - pdata->tmp_trip[i].gpu_lower_level)) { - THERMAL_ERR("error binding cdev inst %d\n", i); - ret = -EINVAL; - goto out; - } - } - pdata->gpu_cool_dev=cdev; - if (pdata->keep_mode) { - cdev->ops->get_max_state(cdev, &max); - keep_mode_bind(pdata, max, 1); - } - } - - if(!strcmp(type,"cpucore")){ - /* Bind the thermal zone to the cpufreq cooling device */ - struct cpucore_cooling_device *cpucore_dev= - (struct cpucore_cooling_device *)cdev->devdata; - for (i = 0; i < pdata->temp_trip_count; i++) { - if(pdata->tmp_trip[0].cpu_core_num==THERMAL_CSTATE_INVALID) - { - ret = -EINVAL; - goto out; - } - if(pdata->tmp_trip[i].cpu_core_num !=-1) - pdata->tmp_trip[i].cpu_core_upper=cpucore_dev->max_cpu_core_num-pdata->tmp_trip[i].cpu_core_num; - else - pdata->tmp_trip[i].cpu_core_upper=pdata->tmp_trip[i].cpu_core_num; - if (thermal_zone_bind_cooling_device(thermal, i, cdev, - pdata->tmp_trip[i].cpu_core_upper, - pdata->tmp_trip[i].cpu_core_upper)) { - THERMAL_ERR("error binding cdev inst %d\n", i); - ret = -EINVAL; - goto out; - } - } - if (pdata->keep_mode) { - cdev->ops->get_max_state(cdev, &max); - keep_mode_bind(pdata, max, 2); - } - } - - if(!strcmp(type,"gpucore")){ - /* Bind the thermal zone to the cpufreq cooling device */ - struct gpucore_cooling_device *gpucore_dev= - (struct gpucore_cooling_device *)cdev->devdata; - for (i = 0; i < pdata->temp_trip_count; i++) { - if(pdata->tmp_trip[0].cpu_core_num==THERMAL_CSTATE_INVALID) - { - ret = -EINVAL; - goto out; - } - if(pdata->tmp_trip[i].gpu_core_num != -1) - pdata->tmp_trip[i].gpu_core_upper=gpucore_dev->max_gpu_core_num-pdata->tmp_trip[i].gpu_core_num; - else - pdata->tmp_trip[i].gpu_core_upper=pdata->tmp_trip[i].gpu_core_num; - - if (thermal_zone_bind_cooling_device(thermal, i, cdev, - pdata->tmp_trip[i].gpu_core_upper, - pdata->tmp_trip[i].gpu_core_upper)) { - THERMAL_ERR("error binding cdev inst %d\n", i); - ret = -EINVAL; - goto out; - } - } - pdata->gpucore_cool_dev=cdev; - if (pdata->keep_mode) { - cdev->ops->get_max_state(cdev, &max); - keep_mode_bind(pdata, max, 3); - } - } - return ret; -out: - return ret; -} - -/* Unbind callback functions for thermal zone */ -static int amlogic_unbind(struct thermal_zone_device *thermal, - struct thermal_cooling_device *cdev) -{ - int i; - if(thermal && cdev){ - struct amlogic_thermal_platform_data *pdata= thermal->devdata; - for (i = 0; i < pdata->temp_trip_count; i++) { - if (thermal_zone_unbind_cooling_device(thermal, i, cdev)) { - THERMAL_ERR(" error %d \n", i); - return -EINVAL; - } - return 0; - } - }else{ - return -EINVAL; - } - return -EINVAL; -} -#define ABS(a) ((a) > 0 ? (a) : -(a)) - -void *thermal_alloc(size_t len) -{ - return kzalloc(len, GFP_KERNEL); -} -EXPORT_SYMBOL(thermal_alloc); - -static void thermal_work(struct work_struct *work) -{ - struct amlogic_thermal_platform_data *pdata; - int cpu_freq = cpufreq_quick_get(0); - - pdata = container_of((struct delayed_work *)work, struct amlogic_thermal_platform_data, thermal_work); - if (pdata->temp_valid) - keep_mode_work(pdata, cpu_freq); - if (pdata->mode == THERMAL_DEVICE_ENABLED) { // no need to do this work again if thermal disabled - schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100)); - } -} - -static int aml_virtaul_thermal_probe(struct platform_device *pdev, struct amlogic_thermal_platform_data *pdata) -{ - int ret, len, cells; - struct property *prop; - void *buf; - - if (!of_property_read_bool(pdev->dev.of_node, "use_virtual_thermal")) { - pdata->virtual_thermal_en = 0; - return 0; - } - - ret = of_property_read_u32(pdev->dev.of_node, - "freq_sample_period", - &pdata->freq_sample_period); - if (ret) { - pdata->freq_sample_period = 30; - } - ret = of_property_read_u32_array(pdev->dev.of_node, - "report_time", - report_interval, sizeof(report_interval) / sizeof(u32)); - if (ret) { - goto error; - } - /* - * read cpu_virtal - */ - prop = of_find_property(pdev->dev.of_node, "cpu_virtual", &len); - if (!prop) { - goto error; - } - cells = len / sizeof(struct aml_virtual_thermal); - buf = kzalloc(len, GFP_KERNEL); - if (!buf) { - THERMAL_ERR("%s, no memory\n", __func__); - return -ENOMEM; - } - ret = of_property_read_u32_array(pdev->dev.of_node, - "cpu_virtual", - buf, len/sizeof(u32)); - if (ret) { - kfree(buf); - goto error; - } - cpu_virtual_thermal.count = cells; - cpu_virtual_thermal.thermal = buf; - - /* - * read gpu_virtal - */ - prop = of_find_property(pdev->dev.of_node, "gpu_virtual", &len); - if (!prop) { - goto error; - } - cells = len / sizeof(struct aml_virtual_thermal); - buf = kzalloc(len, GFP_KERNEL); - if (!buf) { - return -ENOMEM; - } - ret = of_property_read_u32_array(pdev->dev.of_node, - "gpu_virtual", - buf, len/sizeof(u32)); - if (ret) { - kfree(buf); - goto error; - } - gpu_virtual_thermal.count = cells; - gpu_virtual_thermal.thermal = buf; - - pdata->virtual_thermal_en = 1; - return 0; - -error: - pdata->virtual_thermal_en = 0; - return -1; -} - -static void aml_virtual_thermal_remove(struct amlogic_thermal_platform_data *pdata) -{ - kfree(cpu_virtual_thermal.thermal); - kfree(gpu_virtual_thermal.thermal); - pdata->virtual_thermal_en = 0; -} - -static int check_freq_level(struct aml_virtual_thermal_device *dev, unsigned int freq) -{ - int i = 0; - - if (freq >= dev->thermal[dev->count-1].freq) { - return dev->count - 1; - } - for (i = 0; i < dev->count - 1; i++) { - if (freq > dev->thermal[i].freq && freq <= dev->thermal[i + 1].freq) { - return i + 1; - } - } - return 0; -} - -static int check_freq_level_cnt(unsigned int cnt) -{ - int i; - - if (cnt >= report_interval[3]) { - return 3; - } - for (i = 0; i < 3; i++) { - if (cnt >= report_interval[i] && cnt < report_interval[i + 1]) { - return i; - } - } - return 0; -} - -static unsigned long aml_cal_virtual_temp(struct amlogic_thermal_platform_data *pdata) -{ - static unsigned int cpu_freq_level_cnt = 0, gpu_freq_level_cnt = 0; - static unsigned int last_cpu_freq_level = 0, last_gpu_freq_level = 0; - static unsigned int cpu_temp = 40, gpu_temp = 40; // default set to 40 when at homescreen - unsigned int curr_cpu_avg_freq, curr_gpu_avg_freq; - int curr_cpu_freq_level, curr_gpu_freq_level; - int cnt_level, level_diff; - int temp_update = 0, final_temp; - - /* - * CPU temp - */ - if (atomic_read(&freq_update_flag)) { - curr_cpu_avg_freq = pdata->monitor.avg_cpu_freq; - curr_cpu_freq_level = check_freq_level(&cpu_virtual_thermal, curr_cpu_avg_freq); - level_diff = curr_cpu_freq_level - last_cpu_freq_level; - if (ABS(level_diff) <= 1) { // freq change is not large - cpu_freq_level_cnt++; - cnt_level = check_freq_level_cnt(cpu_freq_level_cnt); - cpu_temp = cpu_virtual_thermal.thermal[curr_cpu_freq_level].temp_time[cnt_level]; - } else { // level not match - cpu_temp = cpu_virtual_thermal.thermal[curr_cpu_freq_level].temp_time[0]; - cpu_freq_level_cnt = 0; - } - last_cpu_freq_level = curr_cpu_freq_level; - - curr_gpu_avg_freq = pdata->monitor.avg_gpu_freq; - curr_gpu_freq_level = check_freq_level(&gpu_virtual_thermal, curr_gpu_avg_freq); - level_diff = curr_gpu_freq_level - last_gpu_freq_level; - if (ABS(level_diff) <= 1) { // freq change is not large - gpu_freq_level_cnt++; - cnt_level = check_freq_level_cnt(gpu_freq_level_cnt); - gpu_temp = gpu_virtual_thermal.thermal[curr_gpu_freq_level].temp_time[cnt_level]; - } else { // level not match - gpu_temp = gpu_virtual_thermal.thermal[curr_gpu_freq_level].temp_time[0]; - gpu_freq_level_cnt = 0; - } - last_gpu_freq_level = curr_gpu_freq_level; - - atomic_set(&freq_update_flag, 0); - temp_update = 1; - } - - if (cpu_temp <= 0 && gpu_temp <= 0) { - final_temp = 40; - } - final_temp = (cpu_temp >= gpu_temp ? cpu_temp : gpu_temp); - return final_temp; -} - -/* Get temperature callback functions for thermal zone */ -static int amlogic_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) -{ - struct amlogic_thermal_platform_data *pdata = thermal->devdata; - int tmp; - - if (pdata->trim_flag) { - tmp = get_cpu_temp(); - if (tmp < MIN_TEMP) { - pdata->temp_valid = 0; - return -EINVAL; - } - pdata->temp_valid = 1; - *temp = (unsigned long)get_cpu_temp(); - pdata->current_temp = *temp; - } else if (pdata->virtual_thermal_en) { - *temp = aml_cal_virtual_temp(pdata); - } else { - *temp = 45; // fix cpu temperature to 45 if not trimed && disable virtual thermal - } - return 0; -} - -/* Get the temperature trend */ -static int amlogic_get_trend(struct thermal_zone_device *thermal, - int trip, enum thermal_trend *trend) -{ - return 1; -} -/* Operation callback functions for thermal zone */ -static struct thermal_zone_device_ops amlogic_dev_ops = { - .bind = amlogic_bind, - .unbind = amlogic_unbind, - .get_temp = amlogic_get_temp, - .get_trend = amlogic_get_trend, - .get_mode = amlogic_get_mode, - .set_mode = amlogic_set_mode, - .get_trip_type = amlogic_get_trip_type, - .get_trip_temp = amlogic_get_trip_temp, - .set_trip_temp = amlogic_set_trip_temp, - .get_crit_temp = amlogic_get_crit_temp, -}; - -/* - * sysfs for keep_mode - */ -#ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG // for DEBUG -extern unsigned int max_cpu_num; -static ssize_t max_cpu_num_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", max_cpu_num); -} -#endif - -static ssize_t thermal_debug_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", thermal_debug_enable); -} - -static ssize_t thermal_debug_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - int32_t data = simple_strtol(buf, NULL, 10); - - if (data) { - thermal_debug_enable = 1; - } else { - thermal_debug_enable = 0; - } - return count; -} - -static ssize_t keep_mode_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device); - struct amlogic_thermal_platform_data *pdata = tz->devdata; - - return sprintf(buf, "%s\n", pdata->keep_mode ? "enabled": "disabled"); -} - -static ssize_t keep_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device); - struct amlogic_thermal_platform_data *pdata = tz->devdata; - if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) { - pdata->keep_mode = 1; - } else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) { - pdata->keep_mode = 0; - } - return count; -} - -static ssize_t keep_mode_threshold_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device); - struct amlogic_thermal_platform_data *pdata = tz->devdata; - - return sprintf(buf, "%d\n", pdata->keep_mode_threshold); -} - -static ssize_t keep_mode_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device); - struct amlogic_thermal_platform_data *pdata = tz->devdata; - int32_t data = simple_strtol(buf, NULL, 10); - - if (data > 200) { - THERMAL_INFO("input is %d, seems too large, invalid\n", data); - } - keep_mode_update_threshold(pdata, data); - THERMAL_INFO("set keep_mode_threshold to %d\n", data); - return count; -} - -static ssize_t high_temp_protect_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", high_temp_protect); -} - -static ssize_t high_temp_protect_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device); - struct amlogic_thermal_platform_data *pdata = tz->devdata; - int32_t data = simple_strtol(buf, NULL, 10); - - high_temp_protect = data ? 1 : 0; - if (high_temp_protect) { - pdata->tmp_trip[1].temperature = pdata->keep_mode_threshold + 25; - } else { - pdata->tmp_trip[1].temperature = 260; - } - THERMAL_INFO("high temperature protect %s\n", high_temp_protect ? "enabled" : "disabled"); - return count; -} - -static struct device_attribute amlogic_thermal_attr[] = { -#ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG - __ATTR(max_cpu_num, 0444, max_cpu_num_show, NULL), -#endif - __ATTR(thermal_debug, 0644, thermal_debug_show, thermal_debug_store), - __ATTR(keep_mode, 0644, keep_mode_show, keep_mode_store), - __ATTR(keep_mode_threshold, 0644, keep_mode_threshold_show, keep_mode_threshold_store), - __ATTR(high_temp_protect, 0644, high_temp_protect_show, high_temp_protect_store) -}; - -/* Register with the in-kernel thermal management */ -static int amlogic_register_thermal(struct amlogic_thermal_platform_data *pdata, struct platform_device *pdev) -{ - int ret=0, j; - struct cpumask mask_val; - - memset(&mask_val,0,sizeof(struct cpumask)); - cpumask_set_cpu(0, &mask_val); - pdata->cpu_cool_dev= cpufreq_cooling_register(&mask_val); - if (IS_ERR(pdata->cpu_cool_dev)) { - THERMAL_ERR("Failed to register cpufreq cooling device\n"); - ret = -EINVAL; - goto err_unregister; - } - pdata->cpucore_cool_dev = cpucore_cooling_register(); - if (IS_ERR(pdata->cpucore_cool_dev)) { - THERMAL_ERR("Failed to register cpufreq cooling device\n"); - ret = -EINVAL; - goto err_unregister; - } - - pdata->therm_dev = thermal_zone_device_register(pdata->name, - pdata->temp_trip_count, - ((1 << pdata->temp_trip_count) - 1), - pdata, - &amlogic_dev_ops, - NULL, - 0, - pdata->idle_interval); - - if (IS_ERR(pdata->therm_dev)) { - THERMAL_ERR("Failed to register thermal zone device, err:%p\n", pdata->therm_dev); - ret = -EINVAL; - goto err_unregister; - } - - if (pdata->keep_mode) { // create sysfs for keep_mode - for (j = 0; j < ARRAY_SIZE(amlogic_thermal_attr); j++) { - device_create_file(&pdata->therm_dev->device, &amlogic_thermal_attr[j]); - } - } - - return 0; - -err_unregister: - amlogic_unregister_thermal(pdata); - return ret; -} - -/* Un-Register with the in-kernel thermal management */ -static void amlogic_unregister_thermal(struct amlogic_thermal_platform_data *pdata) -{ - if (pdata->therm_dev) - thermal_zone_device_unregister(pdata->therm_dev); - if (pdata->cpu_cool_dev) - cpufreq_cooling_unregister(pdata->cpu_cool_dev); - -} - -int get_desend(void) -{ - int i; - unsigned int freq = CPUFREQ_ENTRY_INVALID; - int descend = -1; - struct cpufreq_frequency_table *table = - cpufreq_frequency_get_table(0); - - if (!table) - return -EINVAL; - - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - /* ignore invalid entries */ - if (table[i].frequency == CPUFREQ_ENTRY_INVALID) - continue; - - /* ignore duplicate entry */ - if (freq == table[i].frequency) - continue; - - /* get the frequency order */ - if (freq != CPUFREQ_ENTRY_INVALID && descend == -1){ - descend = !!(freq > table[i].frequency); - break; - } - - freq = table[i].frequency; - } - return descend; -} -int fix_to_freq(int freqold,int descend) -{ - int i; - unsigned int freq = CPUFREQ_ENTRY_INVALID; - struct cpufreq_frequency_table *table = - cpufreq_frequency_get_table(0); - - if (!table) - return -EINVAL; - - for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { - /* ignore invalid entry */ - if (table[i].frequency == CPUFREQ_ENTRY_INVALID) - continue; - - /* ignore duplicate entry */ - if (freq == table[i].frequency) - continue; - freq = table[i].frequency; - if(descend){ - if(freqold>=table[i+1].frequency && freqold<=table[i].frequency) - return table[i+1].frequency; - } - else{ - if(freqold>=table[i].frequency && freqold<=table[i+1].frequency) - return table[i].frequency; - } - } - return -EINVAL; -} - -void thermal_atomic_set(atomic_t *a, int value) -{ - atomic_set(a, 1); -} -EXPORT_SYMBOL(thermal_atomic_set); - -static struct amlogic_thermal_platform_data * amlogic_thermal_init_from_dts(struct platform_device *pdev, int trim_flag) -{ - int i = 0, ret = -1, val = 0, cells, descend, error = 0; - struct property *prop; - struct temp_level *tmp_level = NULL; - struct amlogic_thermal_platform_data *pdata = NULL; - - if(!of_property_read_u32(pdev->dev.of_node, "trip_point", &val)){ - //INIT FROM DTS - pdata=kzalloc(sizeof(*pdata),GFP_KERNEL); - if(!pdata){ - goto err; - } - memset((void* )pdata,0,sizeof(*pdata)); - ret=of_property_read_u32(pdev->dev.of_node, "#thermal-cells", &val); - if(ret){ - dev_err(&pdev->dev, "dt probe #thermal-cells failed: %d\n", ret); - goto err; - } - cells=val; - - /* - * process for KEEP_MODE and virtual thermal - * Logic: If virtual thermal is enabled, then ignore keep_mode - * - */ - pdata->trim_flag = trim_flag; - if (!pdata->trim_flag) { // chip is not trimmed, use virtual thermal - aml_virtaul_thermal_probe(pdev, pdata); - } else if (of_property_read_bool(pdev->dev.of_node, "keep_mode")) { - if (of_property_read_u32(pdev->dev.of_node, "keep_mode_threshold", &pdata->keep_mode_threshold)) { - error = 1; - } - if (of_property_read_u32_array(pdev->dev.of_node, - "keep_mode_max_range", - pdata->keep_mode_max_range, - sizeof(pdata->keep_mode_max_range)/sizeof(u32))) { - error = 1; - } - if (!error && pdata->trim_flag) { // keep mode should not used for virtual thermal right now - THERMAL_INFO("keep_mode_max_range: [%7d, %3d, %d, %d]\n", - pdata->keep_mode_max_range[0], pdata->keep_mode_max_range[1], - pdata->keep_mode_max_range[2], pdata->keep_mode_max_range[3]); - pdata->keep_mode = 1; - pdata->freq_sample_period = 5; - } - if (!of_property_read_u32_array(pdev->dev.of_node, - "keep_mode_min_range", - pdata->keep_mode_min_range, - sizeof(pdata->keep_mode_min_range)/sizeof(u32))) { - pdata->keep_min_exist = 1; - THERMAL_INFO("keep_mode_min_range: [%7d, %3d, %d, %d]\n", - pdata->keep_mode_min_range[0], pdata->keep_mode_min_range[1], - pdata->keep_mode_min_range[2], pdata->keep_mode_min_range[3]); - } - } else { - THERMAL_INFO("keep_mode is disabled\n"); - } - if(pdata->keep_mode || !pdata->trim_flag){ - INIT_DELAYED_WORK(&pdata->thermal_work, thermal_work); - schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100)); - atomic_set(&freq_update_flag, 0); - } - - prop = of_find_property(pdev->dev.of_node, "trip_point", &val); - if (!prop){ - dev_err(&pdev->dev, "read %s length error\n","trip_point"); - goto err; - } - if (pdata->keep_mode) { - pdata->temp_trip_count = 2; - } else { - pdata->temp_trip_count=val/cells/sizeof(u32); - } - tmp_level=kzalloc(sizeof(*tmp_level)*pdata->temp_trip_count,GFP_KERNEL); - pdata->tmp_trip=kzalloc(sizeof(struct temp_trip)*pdata->temp_trip_count,GFP_KERNEL); - if(!tmp_level){ - goto err; - } - - if (pdata->keep_mode) { // keep mode only need one point - keep_mode_temp_level_init(pdata, tmp_level); - } else { - ret=of_property_read_u32_array(pdev->dev.of_node,"trip_point",(u32 *)tmp_level,val/sizeof(u32)); - if (ret){ - dev_err(&pdev->dev, "read %s data error\n","trip_point"); - goto err; - } - } - descend=get_desend(); - for (i = 0; i < pdata->temp_trip_count; i++) { - pdata->tmp_trip[i].temperature=tmp_level[i].temperature; - tmp_level[i].cpu_high_freq=fix_to_freq(tmp_level[i].cpu_high_freq,descend); - pdata->tmp_trip[i].cpu_lower_level=cpufreq_cooling_get_level(0,tmp_level[i].cpu_high_freq); - - tmp_level[i].cpu_low_freq=fix_to_freq(tmp_level[i].cpu_low_freq,descend); - pdata->tmp_trip[i].cpu_upper_level=cpufreq_cooling_get_level(0,tmp_level[i].cpu_low_freq); - pdata->tmp_trip[i].gpu_lower_freq=tmp_level[i].gpu_low_freq; - pdata->tmp_trip[i].gpu_upper_freq=tmp_level[i].gpu_high_freq; - - pdata->tmp_trip[i].cpu_core_num=tmp_level[i].cpu_core_num; - pdata->tmp_trip[i].gpu_core_num=tmp_level[i].gpu_core_num; - } - - ret= of_property_read_u32(pdev->dev.of_node, "idle_interval", &val); - if (ret){ - dev_err(&pdev->dev, "read %s error\n","idle_interval"); - goto err; - } - pdata->idle_interval=val; - ret=of_property_read_string(pdev->dev.of_node,"dev_name",&pdata->name); - if (ret){ - dev_err(&pdev->dev, "read %s error\n","dev_name"); - goto err; - } - pdata->mode=THERMAL_DEVICE_ENABLED; - if(tmp_level) - kfree(tmp_level); - return pdata; - } -err: - if(tmp_level) - kfree(tmp_level); - if(pdata) - kfree(pdata); - pdata= NULL; - return pdata; -} - -static struct amlogic_thermal_platform_data * amlogic_thermal_initialize(struct platform_device *pdev, int trim_flag) -{ - struct amlogic_thermal_platform_data *pdata=NULL; - pdata=amlogic_thermal_init_from_dts(pdev, trim_flag); - return pdata; -} - -static const struct of_device_id amlogic_thermal_match[] = { - { - .compatible = "amlogic, amlogic-thermal", - }, - {}, -}; - -#ifdef CONFIG_HIBERNATION -static int amlogic_thermal_freeze(struct device *dev) -{ - return 0; -} - -static int amlogic_thermal_thaw(struct device *dev) -{ - return 0; -} - -static int amlogic_thermal_restore(struct device *dev) -{ - thermal_firmware_init(); - - return 0; -} - -static struct dev_pm_ops amlogic_theraml_pm = { - .freeze = amlogic_thermal_freeze, - .thaw = amlogic_thermal_thaw, - .restore = amlogic_thermal_restore, -}; -#endif - -static int amlogic_thermal_probe(struct platform_device *pdev) -{ - int ret, trim_flag; - struct amlogic_thermal_platform_data *pdata=NULL; - - device_rename(&pdev->dev, "thermal"); - dbg_dev = &pdev->dev; - ret = thermal_firmware_init(); - if (ret < 0) { - THERMAL_INFO("this chip is not trimmed, can't use thermal\n"); - trim_flag = 0; - return -ENODEV; - } else { - THERMAL_INFO("this chip is trimmed, use thermal\n"); - trim_flag = 1; - } - - pdata = amlogic_thermal_initialize(pdev, trim_flag); - if (!pdata) { - dev_err(&pdev->dev, "Failed to initialize thermal\n"); - goto err; - } - mutex_init(&pdata->lock); - pdev->dev.platform_data=pdata; - platform_set_drvdata(pdev, pdata); - ret = amlogic_register_thermal(pdata, pdev); - if (ret) { - dev_err(&pdev->dev, "Failed to register thermal interface\n"); - goto err; - } - return 0; -err: - platform_set_drvdata(pdev, NULL); - return ret; -} - -static int amlogic_thermal_remove(struct platform_device *pdev) -{ - struct amlogic_thermal_platform_data *pdata = platform_get_drvdata(pdev); - - aml_virtual_thermal_remove(pdata); - - amlogic_unregister_thermal(pdata); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -struct platform_driver amlogic_thermal_driver = { - .driver = { - .name = "amlogic-thermal", - .owner = THIS_MODULE, - #ifdef CONFIG_HIBERNATION - .pm = &amlogic_theraml_pm, - #endif - .of_match_table = of_match_ptr(amlogic_thermal_match), - }, - .probe = amlogic_thermal_probe, - .remove = amlogic_thermal_remove, -}; - -void *aml_get_cdevdata(struct thermal_cooling_device *cdev) -{ - return cdev->devdata; -} -EXPORT_SYMBOL(aml_get_cdevdata); - -void aml_set_cdev_update(struct thermal_cooling_device *cdev, bool update) -{ - cdev->updated = update; -} -EXPORT_SYMBOL(aml_set_cdev_update); - -void aml_cdev_lockop(struct thermal_cooling_device *cdev, bool lock) -{ - if (lock) { - thermal_lock(&cdev->lock); - } else { - thermal_unlock(&cdev->lock); - } -} -EXPORT_SYMBOL(aml_cdev_lockop); - -void aml_cdev_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *ret) -{ - cdev->ops->get_cur_state(cdev, ret); -} -EXPORT_SYMBOL(aml_cdev_get_cur_state); - -static int __init amlogic_thermal_driver_init(void) -{ - return platform_driver_register(&(amlogic_thermal_driver)); -} -late_initcall(amlogic_thermal_driver_init); -static void __exit amlogic_thermal_driver_exit(void) -{ - platform_driver_unregister(&(amlogic_thermal_driver) ); -} -module_exit(amlogic_thermal_driver_exit); - -MODULE_DESCRIPTION("amlogic thermal Driver"); -MODULE_AUTHOR("Amlogic SH platform team"); -MODULE_ALIAS("platform:amlogic-thermal"); -MODULE_LICENSE("GPL"); - diff --git a/thermal.cpp b/thermal.cpp new file mode 100644 index 0000000..a138165 --- a/dev/null +++ b/thermal.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * @author Tellen Yu + * @version 1.0 + * @date 2017/7/19 + * @par function description: + * - 1 thermal HAL + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "ThermalHAL" +#include + +#include +#include + +#define TEMPERATURE_TYPE_CPU "CPU" +#define TEMPERATURE_TYPE_GPU "GPU" + +#define CPU_LABEL_0 "CPU0" +#define CPU_LABEL_1 "CPU1" +#define CPU_LABEL_2 "CPU2" +#define CPU_LABEL_3 "CPU3" +#define MAX_LENGTH 100 +#define VALUE_LENGTH 64 + +#define CPU_USAGE_FILE "/proc/stat" +#define TEMPERATURE_DIR "/sys/class/thermal" +#define THERMAL_DIR "thermal_zone" +#define CPU_ONLINE_FILE_FORMAT "/sys/devices/system/cpu/cpu%d/online" +#define UNKNOWN_LABEL "UNKNOWN" + +namespace android { +namespace amlogic { + +/*--------------------------------------------------------------- +* FUNCTION NAME: readSysValue +* DESCRIPTION: +* read value from sysfs +* ARGUMENTS: +* const char *path:sysfs patch +* Return: +* -1:fail, >=0: success +* Note: +* +*---------------------------------------------------------------*/ +static int readSysValue(const char *path) { + int fd, len; + char* end; + char value[VALUE_LENGTH] = {0}; + + if ((fd = open(path, O_RDONLY)) < 0) { + ALOGE("readSysValue, open %s fail.", path); + return -1; + } + + len = read(fd, value, VALUE_LENGTH); + if (len < 0) { + ALOGE("read error: %s, %s\n", path, strerror(errno)); + } + + close(fd); + + if ((0x0A == value[len-1]) || (0x0D == value[len-1])) { + value[len-1] = '\0'; + } + + //ALOGI("readSysValue, path: %s, value: %s\n", path, value); + int val = (int) strtol(value, &end, 0); + if (end == value || *end != '\0' || val == INT_MAX || val == INT_MIN) { + //ALOGI("readSysValue, end: %p, value: %p\n", end, value); + return -1; + } + + return val; +} + +static ssize_t getTemperatures(thermal_module_t *module, temperature_t *list, size_t size) { + char path[MAX_LENGTH]; + float temp; + float throttlingThreshold; + float shutdownThreshold; + size_t idx = 0; + DIR *dir; + struct dirent *de; + + /** Read all available temperatures from + * /sys/class/thermal/thermal_zone[0-9]+/temp files. + * Don't guarantee that all temperatures are in Celsius. */ + dir = opendir(TEMPERATURE_DIR); + if (dir == 0) { + ALOGE("%s: failed to open directory %s: %s", __func__, TEMPERATURE_DIR, strerror(-errno)); + return -errno; + } + + while ((de = readdir(dir))) { + if (!strncmp(de->d_name, THERMAL_DIR, strlen(THERMAL_DIR))) { + int val; + + snprintf(path, MAX_LENGTH, "%s/%s/temp", TEMPERATURE_DIR, de->d_name); + val = readSysValue(path); + if (val < 0) { + continue; + } + + temp = (float)val/1000; + if (list != NULL && idx < size) { + snprintf(path, MAX_LENGTH, "%s/%s/trip_point_1_temp", TEMPERATURE_DIR, de->d_name); + val = readSysValue(path); + if (val >= 0) { + throttlingThreshold = (float)val/1000; + } + + snprintf(path, MAX_LENGTH, "%s/%s/trip_point_3_temp", TEMPERATURE_DIR, de->d_name); + val = readSysValue(path); + if (val >= 0) { + shutdownThreshold = (float)val/1000; + } + + list[idx] = (temperature_t) { + .name = TEMPERATURE_TYPE_CPU, + .type = DEVICE_TEMPERATURE_CPU, + .current_value = temp, + .throttling_threshold = throttlingThreshold, + .shutdown_threshold = shutdownThreshold, + .vr_throttling_threshold = UNKNOWN_TEMPERATURE, + }; + } + + idx++; + } + } + closedir(dir); + + ALOGI("current temperature:%f, throttling_threshold:%f, shutdown_threshold:%f", temp, throttlingThreshold, shutdownThreshold); + return idx; +} + +static ssize_t getCpuUsages(thermal_module_t *module, cpu_usage_t *list) { + int vals, cpu_num, online; + ssize_t read; + uint64_t user, nice, system, idle, active, total; + char *line = NULL; + size_t len = 0; + size_t size = 0; + char file_name[MAX_LENGTH]; + FILE *cpu_file; + FILE *file = fopen(CPU_USAGE_FILE, "r"); + + if (file == NULL) { + ALOGE("%s: failed to open: %s", __func__, strerror(errno)); + return -errno; + } + + /* sample: + cpu 6604 1513 6140 156891 1251 0 9 0 0 0 + cpu0 1399 423 1667 38709 346 0 5 0 0 0 + cpu1 1521 325 1211 39586 157 0 3 0 0 0 + cpu2 1980 399 1931 38470 381 0 0 0 0 0 + cpu3 1704 366 1331 40126 367 0 1 0 0 0 + */ + while ((read = getline(&line, &len, file)) != -1) { + // Skip non "cpu[0-9]" lines. + if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) { + free(line); + line = NULL; + len = 0; + continue; + } + vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user, + &nice, &system, &idle); + + free(line); + line = NULL; + len = 0; + + if (vals != 5) { + ALOGE("%s: failed to read CPU information from file: %s", __func__, strerror(errno)); + fclose(file); + return errno ? -errno : -EIO; + } + + active = user + nice + system; + total = active + idle; + + // Read online CPU information. + snprintf(file_name, MAX_LENGTH, CPU_ONLINE_FILE_FORMAT, cpu_num); + cpu_file = fopen(file_name, "r"); + online = 0; + if (cpu_file == NULL) { + ALOGE("%s: failed to open file: %s (%s)", __func__, file_name, strerror(errno)); + // /sys/devices/system/cpu/cpu0/online is missing on some systems, because cpu0 can't + // be offline. + online = cpu_num == 0; + } else if (1 != fscanf(cpu_file, "%d", &online)) { + ALOGE("%s: failed to read CPU online information from file: %s (%s)", __func__, + file_name, strerror(errno)); + fclose(file); + fclose(cpu_file); + return errno ? -errno : -EIO; + } else { + fclose(cpu_file); + } + + if (list != NULL) { + const char *cpuName = CPU_LABEL_0; + if (0 == cpu_num) + cpuName = CPU_LABEL_0; + else if (1 == cpu_num) + cpuName = CPU_LABEL_1; + else if (2 == cpu_num) + cpuName = CPU_LABEL_2; + else if (3 == cpu_num) + cpuName = CPU_LABEL_3; + list[size] = (cpu_usage_t) { + .name = cpuName, + .active = active, + .total = total, + .is_online = (1 == online)?true:false + }; + } + + size++; + } + + //if (list != NULL) { + // for (size_t i = 0; i < size; ++i) + // ALOGI("index:%d: cpu name:%s", i, list[i].name); + //} + + fclose(file); + return size; +} + +static ssize_t getCoolingDevices(thermal_module_t *module, cooling_device_t *list, size_t size) { + return 0; +} + +} // namespace amlogic +} // namespace android + + +static struct hw_module_methods_t thermal_module_methods = { + .open = NULL, +}; + +thermal_module_t HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = THERMAL_HARDWARE_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = THERMAL_HARDWARE_MODULE_ID, + .name = "AML Thermal HAL", + .author = "aml", + .methods = &thermal_module_methods, + }, + + .getTemperatures = android::amlogic::getTemperatures, + .getCpuUsages = android::amlogic::getCpuUsages, + .getCoolingDevices = android::amlogic::getCoolingDevices, +}; -- cgit