summaryrefslogtreecommitdiff
path: root/thermal_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'thermal_common.c')
-rw-r--r--thermal_common.c385
1 files changed, 385 insertions, 0 deletions
diff --git a/thermal_common.c b/thermal_common.c
new file mode 100644
index 0000000..9374929
--- /dev/null
+++ b/thermal_common.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Not a contribution
+ * Copyright (C) 2016 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.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+
+#define LOG_TAG "ThermalHAL-UTIL"
+#include <utils/Log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/thermal.h>
+#include "thermal_common.h"
+
+#define MAX_LENGTH 50
+#define MAX_PATH (256)
+#define CPU_LABEL "CPU%d"
+#define THERMAL_SYSFS "/sys/devices/virtual/thermal"
+#define TZ_DIR_NAME "thermal_zone"
+#define TZ_DIR_FMT "thermal_zone%d"
+#define THERMAL_TYPE "/sys/devices/virtual/thermal/%s/type"
+#define TEMPERATURE_FILE_FORMAT "/sys/class/thermal/thermal_zone%d/temp"
+
+static char **cpu_label;
+static struct vendor_temperature *sensors;
+static unsigned int sensor_cnt;
+
+/**
+ * Get number of cpus of target.
+ *
+ * @return number of cpus on success or 0 on error.
+ */
+size_t get_num_cpus() {
+ ALOGD("Entering %s",__func__);
+ static int ncpus;
+
+ if (!ncpus) {
+ ncpus = (int)sysconf(_SC_NPROCESSORS_CONF);
+ if (ncpus < 1)
+ ALOGE("%s: Error retrieving number of cores", __func__);
+ }
+ return ncpus;
+}
+
+/**
+ * Get cpu label for a given cpu.
+ *
+ * @param cpu_num: cpu number.
+ *
+ * @return cpu label string on success or NULL on error.
+ */
+const char *get_cpu_label(unsigned int cpu_num) {
+ ALOGD("Entering %s",__func__);
+ unsigned int cpu = 0;
+
+ if (cpu_label == NULL) {
+ cpu_label= (char**)calloc(get_num_cpus(), sizeof(char *));
+ if (!cpu_label)
+ return NULL;
+ for(cpu = 0; cpu < get_num_cpus(); cpu++) {
+ cpu_label[cpu] = (char *)calloc(sizeof("CPUN"), sizeof(char));
+ if(!cpu_label[cpu])
+ return NULL;
+ snprintf(cpu_label[cpu], sizeof("CPUN"), CPU_LABEL, cpu);
+ }
+ }
+ if(cpu_num >= get_num_cpus())
+ return NULL;
+
+ return cpu_label[cpu_num];
+}
+
+/**
+ * Read data from a target sysfs file.
+ *
+ * @param path: Absolute path for a file to be read.
+ * @param buf: Char buffer to store data from file.
+ * @param count: Size of data buffer.
+ *
+ * @return number of bytes read on success or negative value on error.
+ */
+int read_line_from_file(const char *path, char *buf, size_t count)
+{
+ char * fgets_ret;
+ FILE * fd;
+ int rv;
+
+ fd = fopen(path, "r");
+ if (fd == NULL)
+ return -1;
+
+ fgets_ret = fgets(buf, (int)count, fd);
+ if (NULL != fgets_ret) {
+ rv = (int)strlen(buf);
+ } else {
+ rv = ferror(fd);
+ }
+
+ fclose(fd);
+
+ return rv;
+}
+
+/**
+ * Function to get thermal zone id from sensor name.
+ *
+ * @param sensor_name: Name of sensor.
+ *
+ * @return positive integer on success or negative value on error.
+ */
+static int get_tzn(const char *sensor_name)
+{
+ DIR *tdir = NULL;
+ struct dirent *tdirent = NULL;
+ int found = -1;
+ int tzn = 0;
+ char name[MAX_PATH] = {0};
+ char cwd[MAX_PATH] = {0};
+ int ret = 0;
+
+ if (!getcwd(cwd, sizeof(cwd)))
+ return found;
+
+ /* Change dir to read the entries. Doesnt work otherwise */
+ ret = chdir(THERMAL_SYSFS);
+ if (ret) {
+ ALOGE("Unable to change to %s\n", THERMAL_SYSFS);
+ return found;
+ }
+ tdir = opendir(THERMAL_SYSFS);
+ if (!tdir) {
+ ALOGE("Unable to open %s\n", THERMAL_SYSFS);
+ return found;
+ }
+
+ while ((tdirent = readdir(tdir))) {
+ char buf[50];
+ struct dirent *tzdirent;
+ DIR *tzdir = NULL;
+
+ if (strncmp(tdirent->d_name, TZ_DIR_NAME,
+ strlen(TZ_DIR_NAME)) != 0)
+ continue;
+
+ tzdir = opendir(tdirent->d_name);
+ if (!tzdir)
+ continue;
+ while ((tzdirent = readdir(tzdir))) {
+ if (strcmp(tzdirent->d_name, "type"))
+ continue;
+ snprintf(name, MAX_PATH, THERMAL_TYPE,
+ tdirent->d_name);
+ ret = read_line_from_file(name, buf, sizeof(buf));
+ if (ret <= 0) {
+ ALOGE("%s: sensor name read error for tz:%s\n",
+ __func__, tdirent->d_name);
+ break;
+ }
+ if (buf[ret - 1] == '\n')
+ buf[ret - 1] = '\0';
+ else
+ buf[ret] = '\0';
+
+ if (!strcmp(buf, sensor_name)) {
+ found = 1;
+ break;
+ }
+ }
+ closedir(tzdir);
+ if (found == 1)
+ break;
+ }
+
+ if (found == 1) {
+ sscanf(tdirent->d_name, TZ_DIR_FMT, &tzn);
+ ALOGD("Sensor %s found at tz: %d\n",
+ sensor_name, tzn);
+ found = tzn;
+ }
+
+ closedir(tdir);
+ /* Restore current working dir */
+ ret = chdir(cwd);
+
+ return found;
+}
+
+/**
+ * Helper function for sensor intialization.
+ *
+ * @param v_sen_t: pointer to a sensor static config.
+ * @param sensor: pointer to a sensor vendor_temperature structure.
+ * @param type: Type of sensor ie cpu, battery, gpu, skin etc.
+ * @param sens_idx: Index for sensor of same type.
+ *
+ * @return 0 on success or negative value -errno on error.
+ */
+static int initialize_sensor(struct target_therm_cfg *v_sen_t,
+ struct vendor_temperature *sensor,
+ enum temperature_type type,
+ int sens_idx)
+{
+ if (v_sen_t == NULL || sensor == NULL ||
+ sens_idx < 0) {
+ ALOGE("%s:Invalid input, sens_idx%d\n", __func__, sens_idx);
+ return -1;
+ }
+
+ sensor->tzn = get_tzn(v_sen_t->sensor_list[sens_idx]);
+ if (sensor->tzn < 0) {
+ ALOGE("No thermal zone for sensor: %s, ret:%d\n",
+ v_sen_t->sensor_list[sens_idx], sensor->tzn);
+ return -1;
+ }
+ if (type == DEVICE_TEMPERATURE_CPU)
+ sensor->t.name = get_cpu_label(sens_idx);
+ else
+ sensor->t.name = v_sen_t->label;
+
+ sensor->t.type = v_sen_t->type;
+ sensor->mult = v_sen_t->mult;
+
+ if (v_sen_t->throt_thresh != 0)
+ sensor->t.throttling_threshold = v_sen_t->throt_thresh;
+ else
+ sensor->t.throttling_threshold = UNKNOWN_TEMPERATURE;
+
+ if (v_sen_t->shutdwn_thresh != 0)
+ sensor->t.shutdown_threshold = v_sen_t->shutdwn_thresh;
+ else
+ sensor->t.shutdown_threshold = UNKNOWN_TEMPERATURE;
+
+ if (v_sen_t->vr_thresh != 0)
+ sensor->t.vr_throttling_threshold = v_sen_t->vr_thresh;
+ else
+ sensor->t.vr_throttling_threshold = UNKNOWN_TEMPERATURE;
+
+ return 0;
+}
+
+/**
+ * Initialize all sensors.
+ *
+ * @param v_sen_t: Base pointer to array of target specific sensor configs.
+ * @param cfg_cnt: Number of set of config for a given target.
+ *
+ * @return number of sensor on success or negative value or zero on error.
+ */
+int thermal_zone_init(struct target_therm_cfg *v_sen_t, int cfg_cnt)
+{
+ unsigned int idx = 0, cpu = 0;
+ int j = 0;
+
+ if (sensors != NULL && sensor_cnt != 0)
+ return sensor_cnt;
+
+ if (v_sen_t == NULL || cfg_cnt == 0) {
+ ALOGE("%s:Invalid input\n", __func__);
+ return -1;
+ }
+ sensors = calloc(get_num_cpus() + cfg_cnt - 1,
+ sizeof(struct vendor_temperature));
+
+ for (j = 0, idx = 0; j < cfg_cnt &&
+ idx < (get_num_cpus() + cfg_cnt - 1); j++) {
+ if (v_sen_t[j].type == DEVICE_TEMPERATURE_CPU) {
+ /* Initialize cpu thermal zone id */
+ for (cpu = 0; cpu < get_num_cpus() &&
+ idx < (get_num_cpus() + cfg_cnt - 1); cpu++, idx++) {
+ if (initialize_sensor(&v_sen_t[j], &sensors[idx],
+ v_sen_t[j].type, cpu)) {
+ free(sensors);
+ return -1;
+ }
+ }
+ } else {
+ /* Initialize misc thermal zone id */
+ if (initialize_sensor(&v_sen_t[j], &sensors[idx],
+ v_sen_t[j].type, 0)) {
+ free(sensors);
+ return -1;
+ }
+ idx++;
+ }
+ }
+ sensor_cnt = idx;
+
+ return sensor_cnt;
+}
+
+/**
+ * Reads sensor temperature.
+ *
+ * @param sensor_num: thermal zone id for the sensor to be read
+ * @param type: Device temperature type.
+ * @param name: Device temperature name.
+ * @param mult: Multiplier used to translate temperature to Celsius.
+ * @param throttling_threshold: Throttling threshold for the sensor.
+ * @param shutdown_threshold: Shutdown threshold for the sensor.
+ * @param out: Pointer to temperature_t structure that will be filled with
+ * temperature values.
+ *
+ * @return 0 on success or negative value -errno on error.
+ */
+static ssize_t read_temperature(int sensor_num, int type, const char *name,
+ float mult, float throttling_threshold, float shutdown_threshold,
+ float vr_throttling_threshold,
+ temperature_t *out) {
+ ALOGD("Entering %s",__func__);
+ char file_name[MAX_LENGTH];
+ float temp;
+ char buf[16] = {0};
+ int ret = 0;
+
+ snprintf(file_name, sizeof(file_name), TEMPERATURE_FILE_FORMAT, sensor_num);
+ ret = read_line_from_file(file_name, buf, sizeof(buf));
+ if (ret <= 0) {
+ ALOGE("Temperature read error: %d for sensor[%d]:%s\n",
+ ret, sensor_num, name);
+ return -1;
+ }
+ temp = atof(buf);
+
+ (*out) = (temperature_t) {
+ .type = type,
+ .name = name,
+ .current_value = temp * mult,
+ .throttling_threshold = throttling_threshold,
+ .shutdown_threshold = shutdown_threshold,
+ .vr_throttling_threshold = vr_throttling_threshold
+ };
+
+ return 0;
+}
+
+/**
+ * Reads all sensor temperature.
+ *
+ * @param list: Base pointer to array of temperature_t structure that will be
+ * filled with temperature values.
+ * @param size: Number of sensor temperature needs to be filled in list.
+ *
+ * @return number of sensor data filled on success or 0 or negative value
+ * -errno on error.
+ */
+ssize_t get_temperature_for_all(temperature_t *list, size_t size)
+{
+ ALOGD("Entering %s",__func__);
+ size_t idx;
+
+ if (sensors == NULL) {
+ ALOGE("No sensor configured\n");
+ return 0;
+ }
+
+ for (idx = 0; idx < sensor_cnt && idx < size; idx++) {
+ ssize_t result = read_temperature(sensors[idx].tzn, sensors[idx].t.type,
+ sensors[idx].t.name, sensors[idx].mult,
+ sensors[idx].t.throttling_threshold,
+ sensors[idx].t.shutdown_threshold,
+ sensors[idx].t.vr_throttling_threshold,
+ &list[idx]);
+ if (result != 0)
+ return result;
+ }
+ return idx;
+}
+