soc: qcom: Snapshot of thermal/LMH drivers

This snapshot is taken as of msm-3.18 commit e70ad0c (Promotion of
kernel.lnx.3.18-151201.)

Include necessary thermal_core changes to convert long to int inline with
upstream kernel changes.

Change-Id: I642b666518fe72385794b743989a0f5e5120ec03

Conflicts:
	drivers/thermal/Makefile
This commit is contained in:
Mahesh Sivasubramanian 2016-01-11 14:27:35 -07:00 committed by David Keitel
parent 3da2a8c7d1
commit b68798fafa
11 changed files with 10838 additions and 10 deletions

View file

@ -175,6 +175,36 @@ config THERMAL_EMULATION
because userland can easily disable the thermal policy by simply
flooding this sysfs node with low temperature values.
config LIMITS_MONITOR
bool "LMH monitor driver"
depends on THERMAL
help
Enable this to manage the limits hardware for interrupts, throttling
intensities, and LMH device profiles. This driver also registers the
Limits hardware's monitoring entities as sensors with the thermal
framework.
config LIMITS_LITE_HW
bool "LMH Lite hardware driver"
depends on LIMITS_MONITOR
help
Enable this option for interacting with LMH Lite hardware. This
implements the APIs required for getting the details about sensors
supported by LMH Lite, their throttling intensity and the operating
profiles.
config THERMAL_MONITOR
bool "Monitor thermal state and limit CPU Frequency"
depends on THERMAL_TSENS8974
depends on CPU_FREQ || CPU_FREQ_MSM
depends on PM_OPP
default n
help
This enables thermal monitoring capability in the kernel in the
absence of a system wide thermal monitoring entity or until such an
entity starts running in the userspace. Monitors TSENS temperature
and limits the max frequency of the cores.
config HISI_THERMAL
tristate "Hisilicon thermal driver"
depends on (ARCH_HISI && CPU_THERMAL && OF) || COMPILE_TEST

View file

@ -51,3 +51,6 @@ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_THERMAL_QPNP) += qpnp-temp-alarm.o
obj-$(CONFIG_THERMAL_QPNP_ADC_TM) += qpnp-adc-tm.o
obj-$(CONFIG_THERMAL_TSENS8974) += msm8974-tsens.o
obj-$(CONFIG_THERMAL_MONITOR) += msm_thermal.o msm_thermal-dev.o
obj-$(CONFIG_LIMITS_MONITOR) += lmh_interface.o
obj-$(CONFIG_LIMITS_LITE_HW) += lmh_lite.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef __LMH_INTERFACE_H
#define __LMH_INTERFACE_H
#define LMH_NAME_MAX 20
#define LMH_POLLING_MSEC 30
#define LMH_READ_LINE_LENGTH 10
enum lmh_trip_type {
LMH_LOW_TRIP,
LMH_HIGH_TRIP,
LMH_TRIP_MAX,
};
enum lmh_monitor_state {
LMH_ISR_DISABLED,
LMH_ISR_MONITOR,
LMH_ISR_POLLING,
LMH_ISR_NR,
};
struct lmh_sensor_ops {
int (*read)(struct lmh_sensor_ops *, long *);
int (*enable_hw_log)(uint32_t, uint32_t);
int (*disable_hw_log)(void);
void (*new_value_notify)(struct lmh_sensor_ops *, long);
};
struct lmh_device_ops {
int (*get_available_levels)(struct lmh_device_ops *, int *);
int (*get_curr_level)(struct lmh_device_ops *, int *);
int (*set_level)(struct lmh_device_ops *, int);
};
struct lmh_debug_ops {
int (*debug_read)(struct lmh_debug_ops *, uint32_t **);
int (*debug_config_read)(struct lmh_debug_ops *, uint32_t *, int);
int (*debug_config_lmh)(struct lmh_debug_ops *, uint32_t *, int);
int (*debug_get_types)(struct lmh_debug_ops *, bool, uint32_t **);
};
static int lmh_poll_interval = LMH_POLLING_MSEC;
#ifdef CONFIG_LIMITS_MONITOR
int lmh_get_all_dev_levels(char *, int *);
int lmh_set_dev_level(char *, int);
int lmh_get_curr_level(char *, int *);
int lmh_sensor_register(char *, struct lmh_sensor_ops *);
void lmh_sensor_deregister(struct lmh_sensor_ops *);
int lmh_device_register(char *, struct lmh_device_ops *);
void lmh_device_deregister(struct lmh_device_ops *);
int lmh_debug_register(struct lmh_debug_ops *);
void lmh_debug_deregister(struct lmh_debug_ops *ops);
#else
static inline int lmh_get_all_dev_levels(char *device_name, int *level)
{
return -ENOSYS;
}
static inline int lmh_set_dev_level(char *device_name, int level)
{
return -ENOSYS;
}
static inline int lmh_get_curr_level(char *device_name, int *level)
{
return -ENOSYS;
}
static inline int lmh_sensor_register(char *sensor_name,
struct lmh_sensor_ops *ops)
{
return -ENOSYS;
}
static inline void lmh_sensor_deregister(struct lmh_sensor_ops *ops)
{
return;
}
static inline int lmh_device_register(char *device_name,
struct lmh_device_ops *ops)
{
return -ENOSYS;
}
static inline void lmh_device_deregister(struct lmh_device_ops *ops)
{
return;
}
static inline int lmh_debug_register(struct lmh_debug_ops *)
{
return -ENOSYS;
}
static inline void lmh_debug_deregister(struct lmh_debug_ops *ops)
{ }
#endif
#endif /*__LMH_INTERFACE_H*/

1408
drivers/thermal/lmh_lite.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,425 @@
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/msm_thermal_ioctl.h>
#include <linux/msm_thermal.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/semaphore.h>
#include <linux/module.h>
struct msm_thermal_ioctl_dev {
struct semaphore sem;
struct cdev char_dev;
};
static int msm_thermal_major;
static struct class *thermal_class;
static struct msm_thermal_ioctl_dev *msm_thermal_dev;
static unsigned int freq_table_len[NR_CPUS], freq_table_set[NR_CPUS];
static unsigned int voltage_table_set[NR_CPUS];
static unsigned int *freq_table_ptr[NR_CPUS];
static uint32_t *voltage_table_ptr[NR_CPUS];
static int msm_thermal_ioctl_open(struct inode *node, struct file *filep)
{
int ret = 0;
struct msm_thermal_ioctl_dev *dev;
dev = container_of(node->i_cdev, struct msm_thermal_ioctl_dev,
char_dev);
filep->private_data = dev;
return ret;
}
static int msm_thermal_ioctl_release(struct inode *node, struct file *filep)
{
pr_debug("%s: IOCTL: release\n", KBUILD_MODNAME);
return 0;
}
static long validate_and_copy(unsigned int *cmd, unsigned long *arg,
struct msm_thermal_ioctl *query)
{
long ret = 0, err_val = 0;
if ((_IOC_TYPE(*cmd) != MSM_THERMAL_MAGIC_NUM) ||
(_IOC_NR(*cmd) >= MSM_CMD_MAX_NR)) {
ret = -ENOTTY;
goto validate_exit;
}
if (_IOC_DIR(*cmd) & _IOC_READ) {
err_val = !access_ok(VERIFY_WRITE, (void __user *)*arg,
_IOC_SIZE(*cmd));
} else if (_IOC_DIR(*cmd) & _IOC_WRITE) {
err_val = !access_ok(VERIFY_READ, (void __user *)*arg,
_IOC_SIZE(*cmd));
}
if (err_val) {
ret = -EFAULT;
goto validate_exit;
}
if (copy_from_user(query, (void __user *)(*arg),
sizeof(struct msm_thermal_ioctl))) {
ret = -EACCES;
goto validate_exit;
}
if (query->size != sizeof(struct msm_thermal_ioctl)) {
pr_err("%s: Invalid input argument size\n", __func__);
ret = -EINVAL;
goto validate_exit;
}
switch (*cmd) {
case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
if (query->cpu_freq.cpu_num >= num_possible_cpus()) {
pr_err("%s: Invalid CPU number: %u\n", __func__,
query->cpu_freq.cpu_num);
ret = -EINVAL;
goto validate_exit;
}
break;
default:
break;
}
validate_exit:
return ret;
}
static long msm_thermal_process_freq_table_req(struct msm_thermal_ioctl *query,
unsigned long *arg)
{
long ret = 0;
uint32_t table_idx, idx = 0, cluster_id = query->clock_freq.cluster_num;
struct clock_plan_arg *clock_freq = &(query->clock_freq);
if (!freq_table_len[cluster_id]) {
ret = msm_thermal_get_freq_plan_size(cluster_id,
&freq_table_len[cluster_id]);
if (ret) {
pr_err("%s: Cluster%d freq table length get err:%ld\n",
KBUILD_MODNAME, cluster_id, ret);
goto process_freq_exit;
}
if (!freq_table_len[cluster_id]) {
pr_err("%s: Cluster%d freq table empty\n",
KBUILD_MODNAME, cluster_id);
ret = -EAGAIN;
goto process_freq_exit;
}
freq_table_set[cluster_id] = freq_table_len[cluster_id]
/ MSM_IOCTL_FREQ_SIZE;
if (freq_table_len[cluster_id] % MSM_IOCTL_FREQ_SIZE)
freq_table_set[cluster_id]++;
if (!freq_table_ptr[cluster_id]) {
freq_table_ptr[cluster_id] = kzalloc(
sizeof(unsigned int) *
freq_table_len[cluster_id], GFP_KERNEL);
if (!freq_table_ptr[cluster_id]) {
pr_err("%s: memory alloc failed\n",
KBUILD_MODNAME);
freq_table_len[cluster_id] = 0;
ret = -ENOMEM;
goto process_freq_exit;
}
}
ret = msm_thermal_get_cluster_freq_plan(cluster_id,
freq_table_ptr[cluster_id]);
if (ret) {
pr_err("%s: Error getting frequency table. err:%ld\n",
KBUILD_MODNAME, ret);
freq_table_len[cluster_id] = 0;
freq_table_set[cluster_id] = 0;
kfree(freq_table_ptr[cluster_id]);
freq_table_ptr[cluster_id] = NULL;
goto process_freq_exit;
}
}
if (!clock_freq->freq_table_len) {
clock_freq->freq_table_len = freq_table_len[cluster_id];
goto copy_and_return;
}
if (clock_freq->set_idx >= freq_table_set[cluster_id]) {
pr_err("%s: Invalid freq table set%d for cluster%d\n",
KBUILD_MODNAME, clock_freq->set_idx,
cluster_id);
ret = -EINVAL;
goto process_freq_exit;
}
table_idx = MSM_IOCTL_FREQ_SIZE * clock_freq->set_idx;
for (; table_idx < freq_table_len[cluster_id]
&& idx < MSM_IOCTL_FREQ_SIZE; idx++, table_idx++) {
clock_freq->freq_table[idx] =
freq_table_ptr[cluster_id][table_idx];
}
clock_freq->freq_table_len = idx;
copy_and_return:
ret = copy_to_user((void __user *)(*arg), query,
sizeof(struct msm_thermal_ioctl));
if (ret) {
pr_err("%s: copy_to_user error:%ld.\n", KBUILD_MODNAME, ret);
goto process_freq_exit;
}
process_freq_exit:
return ret;
}
static long msm_thermal_process_voltage_table_req(
struct msm_thermal_ioctl *query,
unsigned long *arg)
{
long ret = 0;
uint32_t table_idx = 0, idx = 0;
uint32_t cluster_id = query->voltage.cluster_num;
struct voltage_plan_arg *voltage = &(query->voltage);
if (!voltage_table_ptr[cluster_id]) {
if (!freq_table_len[cluster_id]) {
ret = msm_thermal_get_freq_plan_size(cluster_id,
&freq_table_len[cluster_id]);
if (ret) {
pr_err(
"%s: Cluster%d freq table len err:%ld\n",
KBUILD_MODNAME, cluster_id, ret);
goto process_volt_exit;
}
if (!freq_table_len[cluster_id]) {
pr_err("%s: Cluster%d freq table empty\n",
KBUILD_MODNAME, cluster_id);
ret = -EAGAIN;
goto process_volt_exit;
}
}
voltage_table_ptr[cluster_id] = kzalloc(
sizeof(uint32_t) *
freq_table_len[cluster_id], GFP_KERNEL);
if (!voltage_table_ptr[cluster_id]) {
pr_err("%s: memory alloc failed\n",
KBUILD_MODNAME);
ret = -ENOMEM;
goto process_volt_exit;
}
ret = msm_thermal_get_cluster_voltage_plan(cluster_id,
voltage_table_ptr[cluster_id]);
if (ret) {
pr_err("%s: Error getting voltage table. err:%ld\n",
KBUILD_MODNAME, ret);
kfree(voltage_table_ptr[cluster_id]);
voltage_table_ptr[cluster_id] = NULL;
goto process_volt_exit;
}
}
if (!voltage->voltage_table_len) {
voltage->voltage_table_len = freq_table_len[cluster_id];
goto copy_and_return;
}
voltage_table_set[cluster_id] = freq_table_len[cluster_id]
/ MSM_IOCTL_FREQ_SIZE;
if (freq_table_len[cluster_id] % MSM_IOCTL_FREQ_SIZE)
voltage_table_set[cluster_id]++;
if (voltage->set_idx >= voltage_table_set[cluster_id]) {
pr_err("%s: Invalid voltage table set%d for cluster%d\n",
KBUILD_MODNAME, voltage->set_idx,
cluster_id);
ret = -EINVAL;
goto process_volt_exit;
}
table_idx = MSM_IOCTL_FREQ_SIZE * voltage->set_idx;
for (; table_idx < freq_table_len[cluster_id]
&& idx < MSM_IOCTL_FREQ_SIZE; idx++, table_idx++) {
voltage->voltage_table[idx] =
voltage_table_ptr[cluster_id][table_idx];
}
voltage->voltage_table_len = idx;
copy_and_return:
ret = copy_to_user((void __user *)(*arg), query,
sizeof(struct msm_thermal_ioctl));
if (ret) {
pr_err("%s: copy_to_user error:%ld.\n", KBUILD_MODNAME, ret);
goto process_volt_exit;
}
process_volt_exit:
return ret;
}
static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd,
unsigned long arg)
{
long ret = 0;
struct msm_thermal_ioctl query;
pr_debug("%s: IOCTL: processing cmd:%u\n", KBUILD_MODNAME, cmd);
ret = validate_and_copy(&cmd, &arg, &query);
if (ret)
goto process_exit;
switch (cmd) {
case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
query.cpu_freq.freq_req, true);
break;
case MSM_THERMAL_SET_CPU_MIN_FREQUENCY:
ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
query.cpu_freq.freq_req, false);
break;
case MSM_THERMAL_SET_CLUSTER_MAX_FREQUENCY:
ret = msm_thermal_set_cluster_freq(query.cpu_freq.cpu_num,
query.cpu_freq.freq_req, true);
break;
case MSM_THERMAL_SET_CLUSTER_MIN_FREQUENCY:
ret = msm_thermal_set_cluster_freq(query.cpu_freq.cpu_num,
query.cpu_freq.freq_req, false);
break;
case MSM_THERMAL_GET_CLUSTER_FREQUENCY_PLAN:
ret = msm_thermal_process_freq_table_req(&query, &arg);
break;
case MSM_THERMAL_GET_CLUSTER_VOLTAGE_PLAN:
ret = msm_thermal_process_voltage_table_req(&query, &arg);
break;
default:
ret = -ENOTTY;
goto process_exit;
}
process_exit:
return ret;
}
#ifdef CONFIG_COMPAT
static long msm_thermal_compat_ioctl_process(struct file *filep,
unsigned int cmd, unsigned long arg)
{
arg = (unsigned long)compat_ptr(arg);
return msm_thermal_ioctl_process(filep, cmd, arg);
}
#endif /* CONFIG_COMPAT */
static const struct file_operations msm_thermal_fops = {
.owner = THIS_MODULE,
.open = msm_thermal_ioctl_open,
.unlocked_ioctl = msm_thermal_ioctl_process,
#ifdef CONFIG_COMPAT
.compat_ioctl = msm_thermal_compat_ioctl_process,
#endif /* CONFIG_COMPAT */
.release = msm_thermal_ioctl_release,
};
int msm_thermal_ioctl_init()
{
int ret = 0;
dev_t thermal_dev;
struct device *therm_device;
ret = alloc_chrdev_region(&thermal_dev, 0, 1,
MSM_THERMAL_IOCTL_NAME);
if (ret < 0) {
pr_err("%s: Error in allocating char device region. Err:%d\n",
KBUILD_MODNAME, ret);
goto ioctl_init_exit;
}
msm_thermal_major = MAJOR(thermal_dev);
thermal_class = class_create(THIS_MODULE, "msm_thermal");
if (IS_ERR(thermal_class)) {
pr_err("%s: Error in creating class\n",
KBUILD_MODNAME);
ret = PTR_ERR(thermal_class);
goto ioctl_class_fail;
}
therm_device = device_create(thermal_class, NULL, thermal_dev, NULL,
MSM_THERMAL_IOCTL_NAME);
if (IS_ERR(therm_device)) {
pr_err("%s: Error in creating character device\n",
KBUILD_MODNAME);
ret = PTR_ERR(therm_device);
goto ioctl_dev_fail;
}
msm_thermal_dev = kmalloc(sizeof(struct msm_thermal_ioctl_dev),
GFP_KERNEL);
if (!msm_thermal_dev) {
pr_err("%s: Error allocating memory\n",
KBUILD_MODNAME);
ret = -ENOMEM;
goto ioctl_clean_all;
}
memset(msm_thermal_dev, 0, sizeof(struct msm_thermal_ioctl_dev));
sema_init(&msm_thermal_dev->sem, 1);
cdev_init(&msm_thermal_dev->char_dev, &msm_thermal_fops);
ret = cdev_add(&msm_thermal_dev->char_dev, thermal_dev, 1);
if (ret < 0) {
pr_err("%s: Error in adding character device\n",
KBUILD_MODNAME);
goto ioctl_clean_all;
}
return ret;
ioctl_clean_all:
device_destroy(thermal_class, thermal_dev);
ioctl_dev_fail:
class_destroy(thermal_class);
ioctl_class_fail:
unregister_chrdev_region(thermal_dev, 1);
ioctl_init_exit:
return ret;
}
void msm_thermal_ioctl_cleanup()
{
uint32_t idx = 0;
dev_t thermal_dev = MKDEV(msm_thermal_major, 0);
if (!msm_thermal_dev) {
pr_err("%s: Thermal IOCTL cleanup already done\n",
KBUILD_MODNAME);
return;
}
for (; idx < num_possible_cpus(); idx++) {
kfree(freq_table_ptr[idx]);
kfree(voltage_table_ptr[idx]);
}
device_destroy(thermal_class, thermal_dev);
class_destroy(thermal_class);
cdev_del(&msm_thermal_dev->char_dev);
unregister_chrdev_region(thermal_dev, 1);
kfree(msm_thermal_dev);
msm_thermal_dev = NULL;
thermal_class = NULL;
}

File diff suppressed because it is too large Load diff

View file

@ -271,8 +271,8 @@ static void init_sensor_trip(struct sensor_info *sensor)
static int __update_sensor_thresholds(struct sensor_info *sensor)
{
long max_of_low_thresh = LONG_MIN;
long min_of_high_thresh = LONG_MAX;
int max_of_low_thresh = INT_MIN;
int min_of_high_thresh = INT_MAX;
struct sensor_threshold *pos, *var;
int ret = 0;
@ -300,7 +300,7 @@ static int __update_sensor_thresholds(struct sensor_info *sensor)
}
}
pr_debug("sensor %d: Thresholds: max of low: %ld min of high: %ld\n",
pr_debug("sensor %d: Thresholds: max of low: %d min of high: %d\n",
sensor->sensor_id, max_of_low_thresh,
min_of_high_thresh);
@ -346,7 +346,7 @@ static int __update_sensor_thresholds(struct sensor_info *sensor)
goto update_done;
}
pr_debug("sensor %d: low: %ld high: %ld\n",
pr_debug("sensor %d: low: %d high: %d\n",
sensor->sensor_id,
sensor->threshold_min, sensor->threshold_max);
@ -422,7 +422,7 @@ int thermal_sensor_trip(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL(thermal_sensor_trip);
int sensor_get_temp(uint32_t sensor_id, long *temp)
int sensor_get_temp(uint32_t sensor_id, int *temp)
{
struct sensor_info *sensor = get_sensor(sensor_id);
int ret = 0;
@ -565,8 +565,8 @@ int sensor_init(struct thermal_zone_device *tz)
sensor->sensor_id = tz->id;
sensor->tz = tz;
sensor->threshold_min = LONG_MIN;
sensor->threshold_max = LONG_MAX;
sensor->threshold_min = INT_MIN;
sensor->threshold_max = INT_MAX;
sensor->max_idx = -1;
sensor->min_idx = -1;
mutex_init(&sensor->lock);

333
include/linux/msm_thermal.h Normal file
View file

@ -0,0 +1,333 @@
/*
* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef __MSM_THERMAL_H
#define __MSM_THERMAL_H
#include <linux/thermal.h>
#define MAX_THRESHOLD 2
#define TSENS_NAME_MAX 20
#define MONITOR_ALL_TSENS -1
#define HOTPLUG_DEVICE "hotplug"
#define CPU0_DEVICE "cpu0"
#define CPU1_DEVICE "cpu1"
#define CPU2_DEVICE "cpu2"
#define CPU3_DEVICE "cpu3"
#define CPU4_DEVICE "cpu4"
#define CPU5_DEVICE "cpu5"
#define CPU6_DEVICE "cpu6"
#define CPU7_DEVICE "cpu7"
#define CPUFREQ_MAX_NO_MITIGATION UINT_MAX
#define CPUFREQ_MIN_NO_MITIGATION 0
#define HOTPLUG_NO_MITIGATION(_mask) cpumask_clear(_mask)
#define IS_HI_THRESHOLD_SET(_val) (_val & 1)
#define IS_LOW_THRESHOLD_SET(_val) (_val & 2)
struct msm_thermal_data {
struct platform_device *pdev;
uint32_t sensor_id;
uint32_t poll_ms;
int32_t limit_temp_degC;
int32_t temp_hysteresis_degC;
uint32_t bootup_freq_step;
uint32_t bootup_freq_control_mask;
int32_t core_limit_temp_degC;
int32_t core_temp_hysteresis_degC;
int32_t hotplug_temp_degC;
int32_t hotplug_temp_hysteresis_degC;
uint32_t core_control_mask;
uint32_t freq_mitig_temp_degc;
uint32_t freq_mitig_temp_hysteresis_degc;
uint32_t freq_mitig_control_mask;
uint32_t freq_limit;
int32_t vdd_rstr_temp_degC;
int32_t vdd_rstr_temp_hyst_degC;
int32_t vdd_mx_min;
int32_t vdd_cx_min;
int32_t psm_temp_degC;
int32_t psm_temp_hyst_degC;
int32_t ocr_temp_degC;
int32_t ocr_temp_hyst_degC;
uint32_t ocr_sensor_id;
int32_t phase_rpm_resource_type;
int32_t phase_rpm_resource_id;
int32_t gfx_phase_warm_temp_degC;
int32_t gfx_phase_warm_temp_hyst_degC;
int32_t gfx_phase_hot_temp_degC;
int32_t gfx_phase_hot_temp_hyst_degC;
int32_t gfx_sensor;
int32_t gfx_phase_request_key;
int32_t cx_phase_hot_temp_degC;
int32_t cx_phase_hot_temp_hyst_degC;
int32_t cx_phase_request_key;
int32_t vdd_mx_temp_degC;
int32_t vdd_mx_temp_hyst_degC;
int32_t therm_reset_temp_degC;
};
enum sensor_id_type {
THERM_ZONE_ID,
THERM_TSENS_ID,
THERM_ID_MAX_NR,
};
struct threshold_info;
struct therm_threshold {
int32_t sensor_id;
enum sensor_id_type id_type;
struct sensor_threshold threshold[MAX_THRESHOLD];
int32_t trip_triggered;
void (*notify)(struct therm_threshold *);
struct threshold_info *parent;
};
struct threshold_info {
uint32_t thresh_ct;
bool thresh_triggered;
struct list_head list_ptr;
struct therm_threshold *thresh_list;
};
enum device_req_type {
DEVICE_REQ_NONE = -1,
HOTPLUG_MITIGATION_REQ,
CPUFREQ_MITIGATION_REQ,
DEVICE_REQ_MAX,
};
/**
* For frequency mitigation request, if client is interested
* only in one, either max_freq or min_freq, update default
* value for other one also for mitigation request.
* Default value for request structure variables:
* max_freq = UINT_MAX;
* min_freq = 0;
* offline_mask = CPU_MASK_NONE;
*/
struct cpufreq_request {
uint32_t max_freq;
uint32_t min_freq;
};
union device_request {
struct cpufreq_request freq;
cpumask_t offline_mask;
};
struct device_clnt_data;
struct device_manager_data {
char device_name[TSENS_NAME_MAX];
union device_request active_req;
struct list_head client_list;
struct list_head dev_ptr;
struct mutex clnt_lock;
int (*request_validate)(struct device_clnt_data *,
union device_request *,
enum device_req_type);
int (*update)(struct device_manager_data *);
void *data;
};
struct device_clnt_data {
struct device_manager_data *dev_mgr;
bool req_active;
union device_request request;
struct list_head clnt_ptr;
void (*callback)(struct device_clnt_data *,
union device_request *req, void *);
void *usr_data;
};
#ifdef CONFIG_THERMAL_MONITOR
extern int msm_thermal_ioctl_init(void);
extern void msm_thermal_ioctl_cleanup(void);
extern int msm_thermal_init(struct msm_thermal_data *pdata);
extern int msm_thermal_device_init(void);
extern int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
bool is_max);
extern int msm_thermal_set_cluster_freq(uint32_t cluster, uint32_t freq,
bool is_max);
extern int msm_thermal_get_freq_plan_size(uint32_t cluster,
unsigned int *table_len);
extern int msm_thermal_get_cluster_freq_plan(uint32_t cluster,
unsigned int *table_ptr);
extern int msm_thermal_get_cluster_voltage_plan(uint32_t cluster,
uint32_t *table_ptr);
/**
* sensor_mgr_init_threshold - Initialize thresholds data structure for
* sensor(s) with high and low thresholds and
* threshold callback.
*
* @thresh_inp: Client threshold data structure.
* @sensor_id: Sensor h/w ID to be monitored. Use MONITOR_ALL_TSENS
* to monitor all temperature sensors.
*
* @high_temp: Trigger threshold value for sensor_id or all sensors.
* @low_temp: Clear threshold value for sensor_id or all sensors.
* @callback: Callback pointer for threshold notification.
*
* Returns which threshold is set on success, negative error number
* on failure. MACRO IS_HI_THRESHOLD_SET/IS_LOW_THRESHOLD_SET can be used
* to decipher which threshold being set.
*/
extern int sensor_mgr_init_threshold(struct threshold_info *thresh_inp,
int sensor_id, int32_t high_temp,
int32_t low_temp,
void (*callback)(struct therm_threshold *));
/**
* sensor_mgr_convert_id_and_set_threshold - It accepts sensor h/w ID, converts
* it to sensor zone id and sets
* thermal threshold for those
* sensors listed in threshold info.
*
* @thresh_inp: Client threshold data structure.
*
* Returns zero on success, negative error number on failure.
*/
extern int sensor_mgr_convert_id_and_set_threshold(
struct threshold_info *thresh_inp);
/**
* sensor_mgr_set_threshold- It sets thermal threshold trips for a sensor.
*
* @zone_id: Thermal zone ID for the sensor.
* @threshold: threshold info for the sensor.
*
* Returns zero on success, negative error number on failure.
*/
extern int sensor_mgr_set_threshold(uint32_t zone_id,
struct sensor_threshold *threshold);
/**
* sensor_mgr_remove_threshold- It cancels threshold notification and
* removes threshold from sensor manager
* threshold list.
*
* @thresh_inp: The threshold info which needs to be removed.
*/
extern void sensor_mgr_remove_threshold(struct threshold_info *thresh_inp);
/**
* devmgr_register_mitigation_client - Register for a device and
* gets a handle for mitigation.
* @dev: Client device structure.
* @device_name: Mitgation device name which the client is interested
* to mitigate.
* @callback: Optional callback pointer for device change notification,
* otherwise pass NULL.
*
* Returns client handle structure for that device on success, or NULL
* with IS_ERR() condition containing error number.
*/
extern struct device_clnt_data *devmgr_register_mitigation_client(
struct device *dev,
const char *device_name,
void (*callback)(struct device_clnt_data *,
union device_request *, void *));
/**
* devmgr_client_request_mitigation - Set a valid mitigation for
* registered device.
* @clnt: Client handle for device.
* @type: Type of device request populated above.
* @req: Valid mitigation request.
*
* Returns zero on successful mitigation update, or negative error number.
*/
extern int devmgr_client_request_mitigation(struct device_clnt_data *clnt,
enum device_req_type type,
union device_request *req);
/**
* devmgr_unregister_mitigation_client - Unregister mitigation device
* @dev: Client device structure.
* @clnt: Client handle for device.
*/
extern void devmgr_unregister_mitigation_client(
struct device *dev,
struct device_clnt_data *clnt);
#else
static inline int msm_thermal_init(struct msm_thermal_data *pdata)
{
return -ENOSYS;
}
static inline int msm_thermal_device_init(void)
{
return -ENOSYS;
}
static inline int msm_thermal_set_frequency(uint32_t cpu, uint32_t freq,
bool is_max)
{
return -ENOSYS;
}
static inline int msm_thermal_set_cluster_freq(uint32_t cluster, uint32_t freq,
bool is_max)
{
return -ENOSYS;
}
static inline int msm_thermal_get_freq_plan_size(uint32_t cluster,
unsigned int *table_len)
{
return -ENOSYS;
}
static inline int msm_thermal_get_cluster_freq_plan(uint32_t cluster,
unsigned int *table_ptr)
{
return -ENOSYS;
}
static inline int msm_thermal_get_cluster_voltage_plan(uint32_t cluster,
uint32_t *table_ptr)
{
return -ENOSYS;
}
static inline int sensor_mgr_init_threshold(struct threshold_info *thresh_inp,
int sensor_id, int32_t high_temp,
int32_t low_temp,
void (*callback)(struct therm_threshold *))
{
return -ENOSYS;
}
static inline int sensor_mgr_convert_id_and_set_threshold(
struct threshold_info *thresh_inp)
{
return -ENOSYS;
}
static inline int sensor_mgr_set_threshold(uint32_t zone_id,
struct sensor_threshold *threshold)
{
return -ENOSYS;
}
static inline void sensor_mgr_remove_threshold(
struct threshold_info *thresh_inp)
{
}
static inline struct device_clnt_data *devmgr_register_mitigation_client(
struct device *dev,
const char *device_name,
void (*callback)(struct device_clnt_data *,
union device_request *, void *))
{
return NULL;
}
static inline int devmgr_client_request_mitigation(
struct device_clnt_data *clnt,
enum device_req_type type,
union device_request *req)
{
return -ENOSYS;
}
static inline void devmgr_unregister_mitigation_client(
struct device *dev,
struct device_clnt_data *clnt)
{
}
#endif
#endif /*__MSM_THERMAL_H*/

View file

@ -165,8 +165,8 @@ struct sensor_threshold {
struct sensor_info {
uint32_t sensor_id;
struct thermal_zone_device *tz;
long threshold_min;
long threshold_max;
int threshold_min;
int threshold_max;
int max_idx;
int min_idx;
struct list_head sensor_list;
@ -450,7 +450,7 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
void thermal_cdev_update(struct thermal_cooling_device *);
void thermal_notify_framework(struct thermal_zone_device *, int);
int sensor_get_temp(uint32_t sensor_id, long *temp);
int sensor_get_temp(uint32_t sensor_id, int *temp);
int sensor_get_id(char *name);
int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);

View file

@ -0,0 +1,92 @@
#ifndef _MSM_THERMAL_IOCTL_H
#define _MSM_THERMAL_IOCTL_H
#include <linux/ioctl.h>
#define MSM_THERMAL_IOCTL_NAME "msm_thermal_query"
#define MSM_IOCTL_FREQ_SIZE 16
struct __attribute__((__packed__)) cpu_freq_arg {
uint32_t cpu_num;
uint32_t freq_req;
};
struct __attribute__((__packed__)) clock_plan_arg {
uint32_t cluster_num;
/*
** A value of zero for freq_table_len, will fetch the length of the
** cluster frequency table. A non-zero value will fetch the frequency
** table contents.
*/
uint32_t freq_table_len;
/*
** For clusters with frequency table length greater than
** MSM_IOCTL_FREQ_SIZE, the frequency table is fetched from kernel
** in multiple sets or iterations. The set_idx variable,
** indicates, which set/part of frequency table the user is requesting.
** The set index value starts from zero. A set index value of 'Z',
** will fetch MSM_IOCTL_FREQ_SIZE or maximum available number of
** frequency values (if it is less than MSM_IOCTL_FREQ_SIZE)
** from the frequency table, starting from the index
** (Z * MSM_IOCTL_FREQ_SIZE).
** For example, in a device supporting 19 different frequencies, a set
** index value of 0 will fetch the first 16 (MSM_IOCTL_FREQ_SIZE)
** frequencies starting from the index 0 and a set value of 1 will fetch
** the remaining 3 frequencies starting from the index 16.
** A successful get, will populate the freq_table_len with the
** number of frequency table entries fetched.
*/
uint32_t set_idx;
unsigned int freq_table[MSM_IOCTL_FREQ_SIZE];
};
struct __attribute__((__packed__)) voltage_plan_arg {
uint32_t cluster_num;
uint32_t voltage_table_len;
uint32_t set_idx;
uint32_t voltage_table[MSM_IOCTL_FREQ_SIZE];
};
struct __attribute__((__packed__)) msm_thermal_ioctl {
uint32_t size;
union {
struct cpu_freq_arg cpu_freq;
struct clock_plan_arg clock_freq;
struct voltage_plan_arg voltage;
};
};
enum {
/*Set CPU Frequency*/
MSM_SET_CPU_MAX_FREQ = 0x00,
MSM_SET_CPU_MIN_FREQ = 0x01,
/*Set cluster frequency*/
MSM_SET_CLUSTER_MAX_FREQ = 0x02,
MSM_SET_CLUSTER_MIN_FREQ = 0x03,
/*Get cluster frequency plan*/
MSM_GET_CLUSTER_FREQ_PLAN = 0x04,
/*Get cluster voltage plan */
MSM_GET_CLUSTER_VOLTAGE_PLAN = 0x05,
MSM_CMD_MAX_NR,
};
#define MSM_THERMAL_MAGIC_NUM 0xCA /*Unique magic number*/
#define MSM_THERMAL_SET_CPU_MAX_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
MSM_SET_CPU_MAX_FREQ, struct msm_thermal_ioctl)
#define MSM_THERMAL_SET_CPU_MIN_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
MSM_SET_CPU_MIN_FREQ, struct msm_thermal_ioctl)
#define MSM_THERMAL_SET_CLUSTER_MAX_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
MSM_SET_CLUSTER_MAX_FREQ, struct msm_thermal_ioctl)
#define MSM_THERMAL_SET_CLUSTER_MIN_FREQUENCY _IOW(MSM_THERMAL_MAGIC_NUM,\
MSM_SET_CLUSTER_MIN_FREQ, struct msm_thermal_ioctl)
#define MSM_THERMAL_GET_CLUSTER_FREQUENCY_PLAN _IOR(MSM_THERMAL_MAGIC_NUM,\
MSM_GET_CLUSTER_FREQ_PLAN, struct msm_thermal_ioctl)
#define MSM_THERMAL_GET_CLUSTER_VOLTAGE_PLAN _IOR(MSM_THERMAL_MAGIC_NUM,\
MSM_GET_CLUSTER_VOLTAGE_PLAN, struct msm_thermal_ioctl)
#endif