mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
Merge back thermal cotntrol material for v6.10.
This commit is contained in:
commit
0021102527
@ -13,11 +13,13 @@ description: Binding for Amlogic Thermal
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- amlogic,g12a-cpu-thermal
|
||||
- amlogic,g12a-ddr-thermal
|
||||
- const: amlogic,g12a-thermal
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- amlogic,g12a-cpu-thermal
|
||||
- amlogic,g12a-ddr-thermal
|
||||
- const: amlogic,g12a-thermal
|
||||
- const: amlogic,a1-cpu-thermal
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -18,13 +18,15 @@ properties:
|
||||
oneOf:
|
||||
- enum:
|
||||
- loongson,ls2k1000-thermal
|
||||
- loongson,ls2k2000-thermal
|
||||
- items:
|
||||
- enum:
|
||||
- loongson,ls2k2000-thermal
|
||||
- loongson,ls2k0500-thermal
|
||||
- const: loongson,ls2k1000-thermal
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
@ -38,6 +40,24 @@ required:
|
||||
- interrupts
|
||||
- '#thermal-sensor-cells'
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- loongson,ls2k2000-thermal
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -19,6 +19,9 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt7988-lvts-ap
|
||||
- mediatek,mt8186-lvts
|
||||
- mediatek,mt8188-lvts-ap
|
||||
- mediatek,mt8188-lvts-mcu
|
||||
- mediatek,mt8192-lvts-ap
|
||||
- mediatek,mt8192-lvts-mcu
|
||||
- mediatek,mt8195-lvts-ap
|
||||
@ -60,6 +63,8 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt8188-lvts-ap
|
||||
- mediatek,mt8188-lvts-mcu
|
||||
- mediatek,mt8192-lvts-ap
|
||||
- mediatek,mt8192-lvts-mcu
|
||||
then:
|
||||
@ -75,6 +80,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt8186-lvts
|
||||
- mediatek,mt8195-lvts-ap
|
||||
- mediatek,mt8195-lvts-mcu
|
||||
then:
|
||||
|
@ -17,10 +17,14 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc8180x-lmh
|
||||
- qcom,sdm845-lmh
|
||||
- qcom,sm8150-lmh
|
||||
oneOf:
|
||||
- enum:
|
||||
- qcom,sc8180x-lmh
|
||||
- qcom,sdm845-lmh
|
||||
- qcom,sm8150-lmh
|
||||
- items:
|
||||
- const: qcom,qcm2290-lmh
|
||||
- const: qcom,sm8150-lmh
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/st,stih407-thermal.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STi digital thermal sensor (DTS)
|
||||
|
||||
maintainers:
|
||||
- Patrice Chotard <patrice.chotard@foss.st.com>
|
||||
- Lee Jones <lee@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: thermal-sensor.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,stih407-thermal
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: thermal
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
For thermal sensors for which no interrupt has been defined, a polling
|
||||
delay of 1000ms will be used to read the temperature from device.
|
||||
maxItems: 1
|
||||
|
||||
'#thermal-sensor-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
temperature-sensor@91a0000 {
|
||||
compatible = "st,stih407-thermal";
|
||||
reg = <0x91a0000 0x28>;
|
||||
clock-names = "thermal";
|
||||
clocks = <&CLK_SYSIN>;
|
||||
interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
...
|
@ -1,32 +0,0 @@
|
||||
Binding for Thermal Sensor driver for STMicroelectronics STi series of SoCs.
|
||||
|
||||
Required parameters:
|
||||
-------------------
|
||||
|
||||
compatible : Should be "st,stih407-thermal"
|
||||
|
||||
clock-names : Should be "thermal".
|
||||
See: Documentation/devicetree/bindings/resource-names.txt
|
||||
clocks : Phandle of the clock used by the thermal sensor.
|
||||
See: Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Optional parameters:
|
||||
-------------------
|
||||
|
||||
reg : For non-sysconf based sensors, this should be the physical base
|
||||
address and length of the sensor's registers.
|
||||
interrupts : Standard way to define interrupt number.
|
||||
NB: For thermal sensor's for which no interrupt has been
|
||||
defined, a polling delay of 1000ms will be used to read the
|
||||
temperature from device.
|
||||
|
||||
Example:
|
||||
|
||||
temp0@91a0000 {
|
||||
compatible = "st,stih407-thermal";
|
||||
reg = <0x91a0000 0x28>;
|
||||
clock-names = "thermal";
|
||||
clocks = <&CLK_SYSIN>;
|
||||
interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>;
|
||||
st,passive_cooling_temp = <110>;
|
||||
};
|
@ -220,6 +220,12 @@ static const struct amlogic_thermal_data amlogic_thermal_g12a_ddr_param = {
|
||||
.regmap_config = &amlogic_thermal_regmap_config_g12a,
|
||||
};
|
||||
|
||||
static const struct amlogic_thermal_data amlogic_thermal_a1_cpu_param = {
|
||||
.u_efuse_off = 0x114,
|
||||
.calibration_parameters = &amlogic_thermal_g12a,
|
||||
.regmap_config = &amlogic_thermal_regmap_config_g12a,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_amlogic_thermal_match[] = {
|
||||
{
|
||||
.compatible = "amlogic,g12a-ddr-thermal",
|
||||
@ -229,6 +235,10 @@ static const struct of_device_id of_amlogic_thermal_match[] = {
|
||||
.compatible = "amlogic,g12a-cpu-thermal",
|
||||
.data = &amlogic_thermal_g12a_cpu_param,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,a1-cpu-thermal",
|
||||
.data = &amlogic_thermal_a1_cpu_param,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_amlogic_thermal_match);
|
||||
|
@ -763,7 +763,6 @@ static void armada_set_sane_name(struct platform_device *pdev,
|
||||
struct armada_thermal_priv *priv)
|
||||
{
|
||||
const char *name = dev_name(&pdev->dev);
|
||||
char *insane_char;
|
||||
|
||||
if (strlen(name) > THERMAL_NAME_LENGTH) {
|
||||
/*
|
||||
@ -781,12 +780,8 @@ static void armada_set_sane_name(struct platform_device *pdev,
|
||||
/* Save the name locally */
|
||||
strscpy(priv->zone_name, name, THERMAL_NAME_LENGTH);
|
||||
|
||||
/* Then check there are no '-' or hwmon core will complain */
|
||||
do {
|
||||
insane_char = strpbrk(priv->zone_name, "-");
|
||||
if (insane_char)
|
||||
*insane_char = '_';
|
||||
} while (insane_char);
|
||||
/* Then ensure there are no '-' or hwmon core will complain */
|
||||
strreplace(priv->zone_name, '-', '_');
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -17,10 +17,13 @@
|
||||
|
||||
static int get_trip_level(struct thermal_zone_device *tz)
|
||||
{
|
||||
const struct thermal_trip *trip, *level_trip = NULL;
|
||||
const struct thermal_trip *level_trip = NULL;
|
||||
const struct thermal_trip_desc *td;
|
||||
int trip_level = -1;
|
||||
|
||||
for_each_trip(tz, trip) {
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
|
||||
if (trip->temperature >= tz->temperature)
|
||||
continue;
|
||||
|
||||
|
@ -496,9 +496,11 @@ static void get_governor_trips(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *first_passive = NULL;
|
||||
const struct thermal_trip *last_passive = NULL;
|
||||
const struct thermal_trip *last_active = NULL;
|
||||
const struct thermal_trip *trip;
|
||||
const struct thermal_trip_desc *td;
|
||||
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
|
||||
for_each_trip(tz, trip) {
|
||||
switch (trip->type) {
|
||||
case THERMAL_TRIP_PASSIVE:
|
||||
if (!first_passive) {
|
||||
|
@ -32,7 +32,6 @@ static unsigned long get_target_state(struct thermal_instance *instance,
|
||||
{
|
||||
struct thermal_cooling_device *cdev = instance->cdev;
|
||||
unsigned long cur_state;
|
||||
unsigned long next_target;
|
||||
|
||||
/*
|
||||
* We keep this instance the way it is by default.
|
||||
@ -40,32 +39,26 @@ static unsigned long get_target_state(struct thermal_instance *instance,
|
||||
* cdev in use to determine the next_target.
|
||||
*/
|
||||
cdev->ops->get_cur_state(cdev, &cur_state);
|
||||
next_target = instance->target;
|
||||
dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state);
|
||||
|
||||
if (!instance->initialized) {
|
||||
if (throttle) {
|
||||
next_target = clamp((cur_state + 1), instance->lower, instance->upper);
|
||||
} else {
|
||||
next_target = THERMAL_NO_TARGET;
|
||||
}
|
||||
if (throttle)
|
||||
return clamp(cur_state + 1, instance->lower, instance->upper);
|
||||
|
||||
return next_target;
|
||||
return THERMAL_NO_TARGET;
|
||||
}
|
||||
|
||||
if (throttle) {
|
||||
if (trend == THERMAL_TREND_RAISING)
|
||||
next_target = clamp((cur_state + 1), instance->lower, instance->upper);
|
||||
} else {
|
||||
if (trend == THERMAL_TREND_DROPPING) {
|
||||
if (cur_state <= instance->lower)
|
||||
next_target = THERMAL_NO_TARGET;
|
||||
else
|
||||
next_target = clamp((cur_state - 1), instance->lower, instance->upper);
|
||||
}
|
||||
return clamp(cur_state + 1, instance->lower, instance->upper);
|
||||
} else if (trend == THERMAL_TREND_DROPPING) {
|
||||
if (cur_state <= instance->lower)
|
||||
return THERMAL_NO_TARGET;
|
||||
|
||||
return clamp(cur_state - 1, instance->lower, instance->upper);
|
||||
}
|
||||
|
||||
return next_target;
|
||||
return instance->target;
|
||||
}
|
||||
|
||||
static void thermal_zone_trip_update(struct thermal_zone_device *tz,
|
||||
@ -99,15 +92,13 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz,
|
||||
if (instance->initialized && old_target == instance->target)
|
||||
continue;
|
||||
|
||||
if (old_target == THERMAL_NO_TARGET &&
|
||||
instance->target != THERMAL_NO_TARGET) {
|
||||
/* Activate a passive thermal instance */
|
||||
if (trip->type == THERMAL_TRIP_PASSIVE)
|
||||
if (trip->type == THERMAL_TRIP_PASSIVE) {
|
||||
/* If needed, update the status of passive polling. */
|
||||
if (old_target == THERMAL_NO_TARGET &&
|
||||
instance->target != THERMAL_NO_TARGET)
|
||||
tz->passive++;
|
||||
} else if (old_target != THERMAL_NO_TARGET &&
|
||||
instance->target == THERMAL_NO_TARGET) {
|
||||
/* Deactivate a passive thermal instance */
|
||||
if (trip->type == THERMAL_TRIP_PASSIVE)
|
||||
else if (old_target != THERMAL_NO_TARGET &&
|
||||
instance->target == THERMAL_NO_TARGET)
|
||||
tz->passive--;
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ static int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **ps
|
||||
|
||||
if (knob->type == ACPI_TYPE_STRING) {
|
||||
memset(&psvt->limit, 0, sizeof(u64));
|
||||
strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length);
|
||||
strscpy(psvt->limit.string, psvt_ptr->limit.str_ptr, ACPI_LIMIT_STR_MAX_LEN);
|
||||
} else {
|
||||
psvt->limit.integer = psvt_ptr->limit.integer;
|
||||
}
|
||||
@ -468,7 +468,7 @@ static int fill_psvt(char __user *ubuf)
|
||||
psvt_user[i].unlimit_coeff = psvts[i].unlimit_coeff;
|
||||
psvt_user[i].control_knob_type = psvts[i].control_knob_type;
|
||||
if (psvt_user[i].control_knob_type == ACPI_TYPE_STRING)
|
||||
strncpy(psvt_user[i].limit.string, psvts[i].limit.string,
|
||||
strscpy(psvt_user[i].limit.string, psvts[i].limit.string,
|
||||
ACPI_LIMIT_STR_MAX_LEN);
|
||||
else
|
||||
psvt_user[i].limit.integer = psvts[i].limit.integer;
|
||||
|
@ -159,6 +159,7 @@ struct hfi_cpu_info {
|
||||
static DEFINE_PER_CPU(struct hfi_cpu_info, hfi_cpu_info) = { .index = -1 };
|
||||
|
||||
static int max_hfi_instances;
|
||||
static int hfi_clients_nr;
|
||||
static struct hfi_instance *hfi_instances;
|
||||
|
||||
static struct hfi_features hfi_features;
|
||||
@ -477,8 +478,11 @@ void intel_hfi_online(unsigned int cpu)
|
||||
enable:
|
||||
cpumask_set_cpu(cpu, hfi_instance->cpus);
|
||||
|
||||
/* Enable this HFI instance if this is its first online CPU. */
|
||||
if (cpumask_weight(hfi_instance->cpus) == 1) {
|
||||
/*
|
||||
* Enable this HFI instance if this is its first online CPU and
|
||||
* there are user-space clients of thermal events.
|
||||
*/
|
||||
if (cpumask_weight(hfi_instance->cpus) == 1 && hfi_clients_nr > 0) {
|
||||
hfi_set_hw_table(hfi_instance);
|
||||
hfi_enable();
|
||||
}
|
||||
@ -573,18 +577,33 @@ static __init int hfi_parse_features(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hfi_do_enable(void)
|
||||
/*
|
||||
* If concurrency is not prevented by other means, the HFI enable/disable
|
||||
* routines must be called under hfi_instance_lock."
|
||||
*/
|
||||
static void hfi_enable_instance(void *ptr)
|
||||
{
|
||||
hfi_set_hw_table(ptr);
|
||||
hfi_enable();
|
||||
}
|
||||
|
||||
static void hfi_disable_instance(void *ptr)
|
||||
{
|
||||
hfi_disable();
|
||||
}
|
||||
|
||||
static void hfi_syscore_resume(void)
|
||||
{
|
||||
/* This code runs only on the boot CPU. */
|
||||
struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0);
|
||||
struct hfi_instance *hfi_instance = info->hfi_instance;
|
||||
|
||||
/* No locking needed. There is no concurrency with CPU online. */
|
||||
hfi_set_hw_table(hfi_instance);
|
||||
hfi_enable();
|
||||
if (hfi_clients_nr > 0)
|
||||
hfi_enable_instance(hfi_instance);
|
||||
}
|
||||
|
||||
static int hfi_do_disable(void)
|
||||
static int hfi_syscore_suspend(void)
|
||||
{
|
||||
/* No locking needed. There is no concurrency with CPU offline. */
|
||||
hfi_disable();
|
||||
@ -593,8 +612,58 @@ static int hfi_do_disable(void)
|
||||
}
|
||||
|
||||
static struct syscore_ops hfi_pm_ops = {
|
||||
.resume = hfi_do_enable,
|
||||
.suspend = hfi_do_disable,
|
||||
.resume = hfi_syscore_resume,
|
||||
.suspend = hfi_syscore_suspend,
|
||||
};
|
||||
|
||||
static int hfi_thermal_notify(struct notifier_block *nb, unsigned long state,
|
||||
void *_notify)
|
||||
{
|
||||
struct thermal_genl_notify *notify = _notify;
|
||||
struct hfi_instance *hfi_instance;
|
||||
smp_call_func_t func = NULL;
|
||||
unsigned int cpu;
|
||||
int i;
|
||||
|
||||
if (notify->mcgrp != THERMAL_GENL_EVENT_GROUP)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (state != THERMAL_NOTIFY_BIND && state != THERMAL_NOTIFY_UNBIND)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
mutex_lock(&hfi_instance_lock);
|
||||
|
||||
switch (state) {
|
||||
case THERMAL_NOTIFY_BIND:
|
||||
if (++hfi_clients_nr == 1)
|
||||
func = hfi_enable_instance;
|
||||
break;
|
||||
case THERMAL_NOTIFY_UNBIND:
|
||||
if (--hfi_clients_nr == 0)
|
||||
func = hfi_disable_instance;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!func)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < max_hfi_instances; i++) {
|
||||
hfi_instance = &hfi_instances[i];
|
||||
if (cpumask_empty(hfi_instance->cpus))
|
||||
continue;
|
||||
|
||||
cpu = cpumask_any(hfi_instance->cpus);
|
||||
smp_call_function_single(cpu, func, hfi_instance, true);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&hfi_instance_lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block hfi_thermal_nb = {
|
||||
.notifier_call = hfi_thermal_notify,
|
||||
};
|
||||
|
||||
void __init intel_hfi_init(void)
|
||||
@ -628,10 +697,22 @@ void __init intel_hfi_init(void)
|
||||
if (!hfi_updates_wq)
|
||||
goto err_nomem;
|
||||
|
||||
/*
|
||||
* Both thermal core and Intel HFI can not be build as modules.
|
||||
* As kernel build-in drivers they are initialized before user-space
|
||||
* starts, hence we can not miss BIND/UNBIND events when applications
|
||||
* add/remove thermal multicast group to/from a netlink socket.
|
||||
*/
|
||||
if (thermal_genl_register_notifier(&hfi_thermal_nb))
|
||||
goto err_nl_notif;
|
||||
|
||||
register_syscore_ops(&hfi_pm_ops);
|
||||
|
||||
return;
|
||||
|
||||
err_nl_notif:
|
||||
destroy_workqueue(hfi_updates_wq);
|
||||
|
||||
err_nomem:
|
||||
for (j = 0; j < i; ++j) {
|
||||
hfi_instance = &hfi_instances[j];
|
||||
|
@ -78,7 +78,6 @@ static const int k3_adc_to_temp[] = {
|
||||
|
||||
struct k3_bandgap {
|
||||
void __iomem *base;
|
||||
const struct k3_bandgap_data *conf;
|
||||
};
|
||||
|
||||
/* common data structures */
|
||||
|
@ -14,58 +14,81 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "thermal_hwmon.h"
|
||||
|
||||
#define LOONGSON2_MAX_SENSOR_SEL_NUM 3
|
||||
#define LOONGSON2_MAX_SENSOR_SEL_NUM 3
|
||||
|
||||
#define LOONGSON2_THSENS_CTRL_HI_REG 0x0
|
||||
#define LOONGSON2_THSENS_CTRL_LOW_REG 0x8
|
||||
#define LOONGSON2_THSENS_STATUS_REG 0x10
|
||||
#define LOONGSON2_THSENS_OUT_REG 0x14
|
||||
#define LOONGSON2_THSENS_CTRL_HI_REG 0x0
|
||||
#define LOONGSON2_THSENS_CTRL_LOW_REG 0x8
|
||||
#define LOONGSON2_THSENS_STATUS_REG 0x10
|
||||
#define LOONGSON2_THSENS_OUT_REG 0x14
|
||||
|
||||
#define LOONGSON2_THSENS_INT_LO BIT(0)
|
||||
#define LOONGSON2_THSENS_INT_HIGH BIT(1)
|
||||
#define LOONGSON2_THSENS_OUT_MASK 0xFF
|
||||
#define LOONGSON2_THSENS_INT_LO BIT(0)
|
||||
#define LOONGSON2_THSENS_INT_HIGH BIT(1)
|
||||
#define LOONGSON2_THSENS_INT_EN (LOONGSON2_THSENS_INT_LO | \
|
||||
LOONGSON2_THSENS_INT_HIGH)
|
||||
#define LOONGSON2_THSENS_OUT_MASK 0xFF
|
||||
|
||||
/*
|
||||
* This flag is used to indicate the temperature reading
|
||||
* method of the Loongson-2K2000
|
||||
*/
|
||||
#define LS2K2000_THSENS_OUT_FLAG BIT(0)
|
||||
|
||||
struct loongson2_thermal_chip_data {
|
||||
unsigned int thermal_sensor_sel;
|
||||
unsigned int thermal_sensor_sel;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct loongson2_thermal_data {
|
||||
void __iomem *regs;
|
||||
void __iomem *ctrl_reg;
|
||||
void __iomem *temp_reg;
|
||||
const struct loongson2_thermal_chip_data *chip_data;
|
||||
};
|
||||
|
||||
static int loongson2_thermal_set(struct loongson2_thermal_data *data,
|
||||
int low, int high, bool enable)
|
||||
static void loongson2_set_ctrl_regs(struct loongson2_thermal_data *data,
|
||||
int ctrl_data, bool low, bool enable)
|
||||
{
|
||||
u64 reg_ctrl = 0;
|
||||
int reg_off = data->chip_data->thermal_sensor_sel * 2;
|
||||
int reg_ctrl = 0;
|
||||
int reg_off = data->chip_data->thermal_sensor_sel * 2;
|
||||
int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;
|
||||
|
||||
low = clamp(-40, low, high);
|
||||
high = clamp(125, low, high);
|
||||
|
||||
low += HECTO;
|
||||
high += HECTO;
|
||||
|
||||
reg_ctrl = low;
|
||||
reg_ctrl = ctrl_data + HECTO;
|
||||
reg_ctrl |= enable ? 0x100 : 0;
|
||||
writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_LOW_REG + reg_off);
|
||||
writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off);
|
||||
}
|
||||
|
||||
reg_ctrl = high;
|
||||
reg_ctrl |= enable ? 0x100 : 0;
|
||||
writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_HI_REG + reg_off);
|
||||
static int loongson2_thermal_set(struct loongson2_thermal_data *data,
|
||||
int low, int high, bool enable)
|
||||
{
|
||||
/* Set low temperature threshold */
|
||||
loongson2_set_ctrl_regs(data, clamp(-40, low, high), true, enable);
|
||||
|
||||
/* Set high temperature threshold */
|
||||
loongson2_set_ctrl_regs(data, clamp(125, low, high), false, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson2_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
u32 reg_val;
|
||||
int val;
|
||||
struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
|
||||
|
||||
reg_val = readl(data->regs + LOONGSON2_THSENS_OUT_REG);
|
||||
*temp = ((reg_val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;
|
||||
val = readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG);
|
||||
*temp = ((val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
int val;
|
||||
struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
|
||||
|
||||
val = readl(data->temp_reg);
|
||||
*temp = ((val & 0xffff) * 820 / 0x4000 - 311) * KILO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -75,8 +98,7 @@ static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
|
||||
struct thermal_zone_device *tzd = dev;
|
||||
struct loongson2_thermal_data *data = thermal_zone_device_priv(tzd);
|
||||
|
||||
writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs +
|
||||
LOONGSON2_THSENS_STATUS_REG);
|
||||
writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG);
|
||||
|
||||
thermal_zone_device_update(tzd, THERMAL_EVENT_UNSPECIFIED);
|
||||
|
||||
@ -90,8 +112,8 @@ static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low,
|
||||
return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops loongson2_of_thermal_ops = {
|
||||
.get_temp = loongson2_thermal_get_temp,
|
||||
static struct thermal_zone_device_ops loongson2_of_thermal_ops = {
|
||||
.get_temp = loongson2_2k1000_get_temp,
|
||||
.set_trips = loongson2_thermal_set_trips,
|
||||
};
|
||||
|
||||
@ -108,22 +130,30 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
|
||||
|
||||
data->chip_data = device_get_match_data(dev);
|
||||
|
||||
data->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->regs))
|
||||
return PTR_ERR(data->regs);
|
||||
data->ctrl_reg = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->ctrl_reg))
|
||||
return PTR_ERR(data->ctrl_reg);
|
||||
|
||||
/* The temperature output register is separate for Loongson-2K2000 */
|
||||
if (data->chip_data->flags & LS2K2000_THSENS_OUT_FLAG) {
|
||||
data->temp_reg = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(data->temp_reg))
|
||||
return PTR_ERR(data->temp_reg);
|
||||
|
||||
loongson2_of_thermal_ops.get_temp = loongson2_2k2000_get_temp;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs +
|
||||
LOONGSON2_THSENS_STATUS_REG);
|
||||
writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG);
|
||||
|
||||
loongson2_thermal_set(data, 0, 0, false);
|
||||
|
||||
for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
|
||||
tzd = devm_thermal_of_zone_register(dev, i, data,
|
||||
&loongson2_of_thermal_ops);
|
||||
&loongson2_of_thermal_ops);
|
||||
|
||||
if (!IS_ERR(tzd))
|
||||
break;
|
||||
@ -135,7 +165,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,
|
||||
IRQF_ONESHOT, "loongson2_thermal", tzd);
|
||||
IRQF_ONESHOT, "loongson2_thermal", tzd);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "failed to request alarm irq\n");
|
||||
|
||||
@ -146,6 +176,12 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = {
|
||||
.thermal_sensor_sel = 0,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = {
|
||||
.thermal_sensor_sel = 0,
|
||||
.flags = LS2K2000_THSENS_OUT_FLAG,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_loongson2_thermal_match[] = {
|
||||
@ -153,6 +189,10 @@ static const struct of_device_id of_loongson2_thermal_match[] = {
|
||||
.compatible = "loongson,ls2k1000-thermal",
|
||||
.data = &loongson2_thermal_ls2k1000_data,
|
||||
},
|
||||
{
|
||||
.compatible = "loongson,ls2k2000-thermal",
|
||||
.data = &loongson2_thermal_ls2k2000_data,
|
||||
},
|
||||
{ /* end */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_loongson2_thermal_match);
|
||||
@ -167,4 +207,5 @@ static struct platform_driver loongson2_thermal_driver = {
|
||||
module_platform_driver(loongson2_thermal_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Loongson2 thermal driver");
|
||||
MODULE_AUTHOR("Loongson Technology Corporation Limited");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -91,9 +91,7 @@
|
||||
#define LVTS_MSR_READ_TIMEOUT_US 400
|
||||
#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
|
||||
|
||||
#define LVTS_HW_SHUTDOWN_MT7988 105000
|
||||
#define LVTS_HW_SHUTDOWN_MT8192 105000
|
||||
#define LVTS_HW_SHUTDOWN_MT8195 105000
|
||||
#define LVTS_HW_TSHUT_TEMP 105000
|
||||
|
||||
#define LVTS_MINIMUM_THRESHOLD 20000
|
||||
|
||||
@ -102,22 +100,36 @@ static int golden_temp_offset;
|
||||
|
||||
struct lvts_sensor_data {
|
||||
int dt_id;
|
||||
u8 cal_offsets[3];
|
||||
};
|
||||
|
||||
struct lvts_ctrl_data {
|
||||
struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX];
|
||||
int cal_offset[LVTS_SENSOR_MAX];
|
||||
int hw_tshut_temp;
|
||||
int num_lvts_sensor;
|
||||
u8 valid_sensor_mask;
|
||||
int offset;
|
||||
int mode;
|
||||
};
|
||||
|
||||
#define VALID_SENSOR_MAP(s0, s1, s2, s3) \
|
||||
.valid_sensor_mask = (((s0) ? BIT(0) : 0) | \
|
||||
((s1) ? BIT(1) : 0) | \
|
||||
((s2) ? BIT(2) : 0) | \
|
||||
((s3) ? BIT(3) : 0))
|
||||
|
||||
#define lvts_for_each_valid_sensor(i, lvts_ctrl_data) \
|
||||
for ((i) = 0; (i) < LVTS_SENSOR_MAX; (i)++) \
|
||||
if (!((lvts_ctrl_data)->valid_sensor_mask & BIT(i))) \
|
||||
continue; \
|
||||
else
|
||||
|
||||
struct lvts_data {
|
||||
const struct lvts_ctrl_data *lvts_ctrl;
|
||||
int num_lvts_ctrl;
|
||||
int temp_factor;
|
||||
int temp_offset;
|
||||
int gt_calib_bit_offset;
|
||||
};
|
||||
|
||||
struct lvts_sensor {
|
||||
@ -135,7 +147,6 @@ struct lvts_ctrl {
|
||||
const struct lvts_data *lvts_data;
|
||||
u32 calibration[LVTS_SENSOR_MAX];
|
||||
u32 hw_tshut_raw_temp;
|
||||
int num_lvts_sensor;
|
||||
int mode;
|
||||
void __iomem *base;
|
||||
int low_thresh;
|
||||
@ -347,7 +358,7 @@ static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high)
|
||||
if (high > lvts_ctrl->high_thresh)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++)
|
||||
lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl)
|
||||
if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
|
||||
&& lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
|
||||
return false;
|
||||
@ -551,6 +562,7 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
||||
const struct lvts_ctrl_data *lvts_ctrl_data)
|
||||
{
|
||||
struct lvts_sensor *lvts_sensor = lvts_ctrl->sensors;
|
||||
|
||||
void __iomem *msr_regs[] = {
|
||||
LVTS_MSR0(lvts_ctrl->base),
|
||||
LVTS_MSR1(lvts_ctrl->base),
|
||||
@ -567,7 +579,7 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) {
|
||||
lvts_for_each_valid_sensor(i, lvts_ctrl_data) {
|
||||
|
||||
int dt_id = lvts_ctrl_data->lvts_sensor[i].dt_id;
|
||||
|
||||
@ -607,8 +619,6 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
||||
lvts_sensor[i].high_thresh = INT_MIN;
|
||||
};
|
||||
|
||||
lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -668,18 +678,31 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
||||
* <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8----->
|
||||
* 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48
|
||||
*
|
||||
* The data description gives the offset of the calibration data in
|
||||
* this bytes stream for each sensor.
|
||||
* Note: In some cases, values don't strictly follow a little endian ordering.
|
||||
* The data description gives byte offsets constituting each calibration value
|
||||
* for each sensor.
|
||||
*/
|
||||
static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
||||
const struct lvts_ctrl_data *lvts_ctrl_data,
|
||||
u8 *efuse_calibration)
|
||||
u8 *efuse_calibration,
|
||||
size_t calib_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++)
|
||||
memcpy(&lvts_ctrl->calibration[i],
|
||||
efuse_calibration + lvts_ctrl_data->cal_offset[i], 2);
|
||||
lvts_for_each_valid_sensor(i, lvts_ctrl_data) {
|
||||
const struct lvts_sensor_data *sensor =
|
||||
&lvts_ctrl_data->lvts_sensor[i];
|
||||
|
||||
if (sensor->cal_offsets[0] >= calib_len ||
|
||||
sensor->cal_offsets[1] >= calib_len ||
|
||||
sensor->cal_offsets[2] >= calib_len)
|
||||
return -EINVAL;
|
||||
|
||||
lvts_ctrl->calibration[i] =
|
||||
(efuse_calibration[sensor->cal_offsets[0]] << 0) +
|
||||
(efuse_calibration[sensor->cal_offsets[1]] << 8) +
|
||||
(efuse_calibration[sensor->cal_offsets[2]] << 16);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -734,16 +757,21 @@ static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lvts_golden_temp_init(struct device *dev, u32 *value, int temp_offset)
|
||||
static int lvts_golden_temp_init(struct device *dev, u8 *calib,
|
||||
const struct lvts_data *lvts_data)
|
||||
{
|
||||
u32 gt;
|
||||
|
||||
gt = (*value) >> 24;
|
||||
/*
|
||||
* The golden temp information is contained in the first 32-bit
|
||||
* word of efuse data at a specific bit offset.
|
||||
*/
|
||||
gt = (((u32 *)calib)[0] >> lvts_data->gt_calib_bit_offset) & 0xff;
|
||||
|
||||
if (gt && gt < LVTS_GOLDEN_TEMP_MAX)
|
||||
golden_temp = gt;
|
||||
|
||||
golden_temp_offset = golden_temp * 500 + temp_offset;
|
||||
golden_temp_offset = golden_temp * 500 + lvts_data->temp_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -762,11 +790,7 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The golden temp information is contained in the first chunk
|
||||
* of efuse data.
|
||||
*/
|
||||
ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib, lvts_data->temp_offset);
|
||||
ret = lvts_golden_temp_init(dev, lvts_td->calib, lvts_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -786,7 +810,8 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
|
||||
|
||||
ret = lvts_calibration_init(dev, &lvts_ctrl[i],
|
||||
&lvts_data->lvts_ctrl[i],
|
||||
lvts_td->calib);
|
||||
lvts_td->calib,
|
||||
lvts_td->calib_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -801,7 +826,7 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
|
||||
* after initializing the calibration.
|
||||
*/
|
||||
lvts_ctrl[i].hw_tshut_raw_temp =
|
||||
lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp,
|
||||
lvts_temp_to_raw(LVTS_HW_TSHUT_TEMP,
|
||||
lvts_data->temp_factor);
|
||||
|
||||
lvts_ctrl[i].low_thresh = INT_MIN;
|
||||
@ -1089,7 +1114,7 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
|
||||
u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ?
|
||||
sensor_imm_bitmap : sensor_filt_bitmap;
|
||||
|
||||
for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) {
|
||||
lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl) {
|
||||
|
||||
int dt_id = lvts_sensors[i].dt_id;
|
||||
|
||||
@ -1302,28 +1327,32 @@ static void lvts_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x00, 0x04, 0x08, 0x0c },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT7988_CPU_0 },
|
||||
{ .dt_id = MT7988_CPU_1 },
|
||||
{ .dt_id = MT7988_ETH2P5G_0 },
|
||||
{ .dt_id = MT7988_ETH2P5G_1 }
|
||||
{ .dt_id = MT7988_CPU_0,
|
||||
.cal_offsets = { 0x00, 0x01, 0x02 } },
|
||||
{ .dt_id = MT7988_CPU_1,
|
||||
.cal_offsets = { 0x04, 0x05, 0x06 } },
|
||||
{ .dt_id = MT7988_ETH2P5G_0,
|
||||
.cal_offsets = { 0x08, 0x09, 0x0a } },
|
||||
{ .dt_id = MT7988_ETH2P5G_1,
|
||||
.cal_offsets = { 0x0c, 0x0d, 0x0e } }
|
||||
},
|
||||
.num_lvts_sensor = 4,
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT7988_TOPS_0},
|
||||
{ .dt_id = MT7988_TOPS_1},
|
||||
{ .dt_id = MT7988_ETHWARP_0},
|
||||
{ .dt_id = MT7988_ETHWARP_1}
|
||||
{ .dt_id = MT7988_TOPS_0,
|
||||
.cal_offsets = { 0x14, 0x15, 0x16 } },
|
||||
{ .dt_id = MT7988_TOPS_1,
|
||||
.cal_offsets = { 0x18, 0x19, 0x1a } },
|
||||
{ .dt_id = MT7988_ETHWARP_0,
|
||||
.cal_offsets = { 0x1c, 0x1d, 0x1e } },
|
||||
{ .dt_id = MT7988_ETHWARP_1,
|
||||
.cal_offsets = { 0x20, 0x21, 0x22 } }
|
||||
},
|
||||
.num_lvts_sensor = 4,
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
|
||||
}
|
||||
};
|
||||
|
||||
@ -1359,164 +1388,301 @@ static int lvts_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The MT8186 calibration data is stored as packed 3-byte little-endian
|
||||
* values using a weird layout that makes sense only when viewed as a 32-bit
|
||||
* hexadecimal word dump. Let's suppose SxBy where x = sensor number and
|
||||
* y = byte number where the LSB is y=0. We then have:
|
||||
*
|
||||
* [S0B2-S0B1-S0B0-S1B2] [S1B1-S1B0-S2B2-S2B1] [S2B0-S3B2-S3B1-S3B0]
|
||||
*
|
||||
* However, when considering a byte stream, those appear as follows:
|
||||
*
|
||||
* [S1B2] [S0B0[ [S0B1] [S0B2] [S2B1] [S2B2] [S1B0] [S1B1] [S3B0] [S3B1] [S3B2] [S2B0]
|
||||
*
|
||||
* Hence the rather confusing offsets provided below.
|
||||
*/
|
||||
static const struct lvts_ctrl_data mt8186_lvts_data_ctrl[] = {
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8186_LITTLE_CPU0,
|
||||
.cal_offsets = { 5, 6, 7 } },
|
||||
{ .dt_id = MT8186_LITTLE_CPU1,
|
||||
.cal_offsets = { 10, 11, 4 } },
|
||||
{ .dt_id = MT8186_LITTLE_CPU2,
|
||||
.cal_offsets = { 15, 8, 9 } },
|
||||
{ .dt_id = MT8186_CAM,
|
||||
.cal_offsets = { 12, 13, 14 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x0,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8186_BIG_CPU0,
|
||||
.cal_offsets = { 22, 23, 16 } },
|
||||
{ .dt_id = MT8186_BIG_CPU1,
|
||||
.cal_offsets = { 27, 20, 21 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x100,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8186_NNA,
|
||||
.cal_offsets = { 29, 30, 31 } },
|
||||
{ .dt_id = MT8186_ADSP,
|
||||
.cal_offsets = { 34, 35, 28 } },
|
||||
{ .dt_id = MT8186_MFG,
|
||||
.cal_offsets = { 39, 32, 33 } }
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 0),
|
||||
.offset = 0x200,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8188_lvts_mcu_data_ctrl[] = {
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8188_MCU_LITTLE_CPU0,
|
||||
.cal_offsets = { 22, 23, 24 } },
|
||||
{ .dt_id = MT8188_MCU_LITTLE_CPU1,
|
||||
.cal_offsets = { 25, 26, 27 } },
|
||||
{ .dt_id = MT8188_MCU_LITTLE_CPU2,
|
||||
.cal_offsets = { 28, 29, 30 } },
|
||||
{ .dt_id = MT8188_MCU_LITTLE_CPU3,
|
||||
.cal_offsets = { 31, 32, 33 } },
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x0,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8188_MCU_BIG_CPU0,
|
||||
.cal_offsets = { 34, 35, 36 } },
|
||||
{ .dt_id = MT8188_MCU_BIG_CPU1,
|
||||
.cal_offsets = { 37, 38, 39 } },
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x100,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8188_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.lvts_sensor = {
|
||||
|
||||
{ /* unused */ },
|
||||
{ .dt_id = MT8188_AP_APU,
|
||||
.cal_offsets = { 40, 41, 42 } },
|
||||
},
|
||||
VALID_SENSOR_MAP(0, 1, 0, 0),
|
||||
.offset = 0x0,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8188_AP_GPU1,
|
||||
.cal_offsets = { 43, 44, 45 } },
|
||||
{ .dt_id = MT8188_AP_GPU2,
|
||||
.cal_offsets = { 46, 47, 48 } },
|
||||
{ .dt_id = MT8188_AP_SOC1,
|
||||
.cal_offsets = { 49, 50, 51 } },
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 1, 0),
|
||||
.offset = 0x100,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8188_AP_SOC2,
|
||||
.cal_offsets = { 52, 53, 54 } },
|
||||
{ .dt_id = MT8188_AP_SOC3,
|
||||
.cal_offsets = { 55, 56, 57 } },
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x200,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8188_AP_CAM1,
|
||||
.cal_offsets = { 58, 59, 60 } },
|
||||
{ .dt_id = MT8188_AP_CAM2,
|
||||
.cal_offsets = { 61, 62, 63 } },
|
||||
},
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x300,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x04, 0x08 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU0 },
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU1 }
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU0,
|
||||
.cal_offsets = { 0x04, 0x05, 0x06 } },
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU1,
|
||||
.cal_offsets = { 0x08, 0x09, 0x0a } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x0c, 0x10 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU2 },
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU3 }
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU2,
|
||||
.cal_offsets = { 0x0c, 0x0d, 0x0e } },
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU3,
|
||||
.cal_offsets = { 0x10, 0x11, 0x12 } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU0 },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU1 },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU2 },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU3 }
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU0,
|
||||
.cal_offsets = { 0x14, 0x15, 0x16 } },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU1,
|
||||
.cal_offsets = { 0x18, 0x19, 0x1a } },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU2,
|
||||
.cal_offsets = { 0x1c, 0x1d, 0x1e } },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU3,
|
||||
.cal_offsets = { 0x20, 0x21, 0x22 } }
|
||||
},
|
||||
.num_lvts_sensor = 4,
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x200,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8192_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x24, 0x28 },
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_VPU0 },
|
||||
{ .dt_id = MT8192_AP_VPU1 }
|
||||
{ .dt_id = MT8192_AP_VPU0,
|
||||
.cal_offsets = { 0x24, 0x25, 0x26 } },
|
||||
{ .dt_id = MT8192_AP_VPU1,
|
||||
.cal_offsets = { 0x28, 0x29, 0x2a } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x2c, 0x30 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_GPU0 },
|
||||
{ .dt_id = MT8192_AP_GPU1 }
|
||||
{ .dt_id = MT8192_AP_GPU0,
|
||||
.cal_offsets = { 0x2c, 0x2d, 0x2e } },
|
||||
{ .dt_id = MT8192_AP_GPU1,
|
||||
.cal_offsets = { 0x30, 0x31, 0x32 } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x34, 0x38 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_INFRA },
|
||||
{ .dt_id = MT8192_AP_CAM },
|
||||
{ .dt_id = MT8192_AP_INFRA,
|
||||
.cal_offsets = { 0x34, 0x35, 0x36 } },
|
||||
{ .dt_id = MT8192_AP_CAM,
|
||||
.cal_offsets = { 0x38, 0x39, 0x3a } },
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x200,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x3c, 0x40, 0x44 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_MD0 },
|
||||
{ .dt_id = MT8192_AP_MD1 },
|
||||
{ .dt_id = MT8192_AP_MD2 }
|
||||
{ .dt_id = MT8192_AP_MD0,
|
||||
.cal_offsets = { 0x3c, 0x3d, 0x3e } },
|
||||
{ .dt_id = MT8192_AP_MD1,
|
||||
.cal_offsets = { 0x40, 0x41, 0x42 } },
|
||||
{ .dt_id = MT8192_AP_MD2,
|
||||
.cal_offsets = { 0x44, 0x45, 0x46 } }
|
||||
},
|
||||
.num_lvts_sensor = 3,
|
||||
VALID_SENSOR_MAP(1, 1, 1, 0),
|
||||
.offset = 0x300,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x04, 0x07 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU0 },
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU1 }
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU0,
|
||||
.cal_offsets = { 0x04, 0x05, 0x06 } },
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU1,
|
||||
.cal_offsets = { 0x07, 0x08, 0x09 } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x0d, 0x10 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU2 },
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU3 }
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU2,
|
||||
.cal_offsets = { 0x0d, 0x0e, 0x0f } },
|
||||
{ .dt_id = MT8195_MCU_BIG_CPU3,
|
||||
.cal_offsets = { 0x10, 0x11, 0x12 } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x16, 0x19, 0x1c, 0x1f },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU0 },
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU1 },
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU2 },
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU3 }
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU0,
|
||||
.cal_offsets = { 0x16, 0x17, 0x18 } },
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU1,
|
||||
.cal_offsets = { 0x19, 0x1a, 0x1b } },
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU2,
|
||||
.cal_offsets = { 0x1c, 0x1d, 0x1e } },
|
||||
{ .dt_id = MT8195_MCU_LITTLE_CPU3,
|
||||
.cal_offsets = { 0x1f, 0x20, 0x21 } }
|
||||
},
|
||||
.num_lvts_sensor = 4,
|
||||
VALID_SENSOR_MAP(1, 1, 1, 1),
|
||||
.offset = 0x200,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x25, 0x28 },
|
||||
{
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8195_AP_VPU0 },
|
||||
{ .dt_id = MT8195_AP_VPU1 }
|
||||
{ .dt_id = MT8195_AP_VPU0,
|
||||
.cal_offsets = { 0x25, 0x26, 0x27 } },
|
||||
{ .dt_id = MT8195_AP_VPU1,
|
||||
.cal_offsets = { 0x28, 0x29, 0x2a } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x2e, 0x31 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8195_AP_GPU0 },
|
||||
{ .dt_id = MT8195_AP_GPU1 }
|
||||
{ .dt_id = MT8195_AP_GPU0,
|
||||
.cal_offsets = { 0x2e, 0x2f, 0x30 } },
|
||||
{ .dt_id = MT8195_AP_GPU1,
|
||||
.cal_offsets = { 0x31, 0x32, 0x33 } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x37, 0x3a, 0x3d },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8195_AP_VDEC },
|
||||
{ .dt_id = MT8195_AP_IMG },
|
||||
{ .dt_id = MT8195_AP_INFRA },
|
||||
{ .dt_id = MT8195_AP_VDEC,
|
||||
.cal_offsets = { 0x37, 0x38, 0x39 } },
|
||||
{ .dt_id = MT8195_AP_IMG,
|
||||
.cal_offsets = { 0x3a, 0x3b, 0x3c } },
|
||||
{ .dt_id = MT8195_AP_INFRA,
|
||||
.cal_offsets = { 0x3d, 0x3e, 0x3f } }
|
||||
},
|
||||
.num_lvts_sensor = 3,
|
||||
VALID_SENSOR_MAP(1, 1, 1, 0),
|
||||
.offset = 0x200,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x43, 0x46 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8195_AP_CAM0 },
|
||||
{ .dt_id = MT8195_AP_CAM1 }
|
||||
{ .dt_id = MT8195_AP_CAM0,
|
||||
.cal_offsets = { 0x43, 0x44, 0x45 } },
|
||||
{ .dt_id = MT8195_AP_CAM1,
|
||||
.cal_offsets = { 0x46, 0x47, 0x48 } }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
VALID_SENSOR_MAP(1, 1, 0, 0),
|
||||
.offset = 0x300,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195,
|
||||
}
|
||||
};
|
||||
|
||||
@ -1525,16 +1691,47 @@ static const struct lvts_data mt7988_lvts_ap_data = {
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT7988,
|
||||
.temp_offset = LVTS_COEFF_B_MT7988,
|
||||
.gt_calib_bit_offset = 24,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8186_lvts_data = {
|
||||
.lvts_ctrl = mt8186_lvts_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8186_lvts_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT7988,
|
||||
.temp_offset = LVTS_COEFF_B_MT7988,
|
||||
.gt_calib_bit_offset = 24,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8188_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8188_lvts_mcu_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_mcu_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 20,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8188_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8188_lvts_ap_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_ap_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 20,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8192_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8192_lvts_mcu_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8192_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8192_lvts_ap_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8195_lvts_mcu_data = {
|
||||
@ -1542,6 +1739,7 @@ static const struct lvts_data mt8195_lvts_mcu_data = {
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8195_lvts_ap_data = {
|
||||
@ -1549,10 +1747,14 @@ static const struct lvts_data mt8195_lvts_ap_data = {
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
};
|
||||
|
||||
static const struct of_device_id lvts_of_match[] = {
|
||||
{ .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data },
|
||||
{ .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data },
|
||||
{ .compatible = "mediatek,mt8188-lvts-ap", .data = &mt8188_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data },
|
||||
{ .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
|
||||
|
@ -95,6 +95,9 @@ static int lmh_probe(struct platform_device *pdev)
|
||||
unsigned int enable_alg;
|
||||
u32 node_id;
|
||||
|
||||
if (!qcom_scm_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
lmh_data = devm_kzalloc(dev, sizeof(*lmh_data), GFP_KERNEL);
|
||||
if (!lmh_data)
|
||||
return -ENOMEM;
|
||||
|
@ -74,7 +74,6 @@ struct qpnp_tm_chip {
|
||||
long temp;
|
||||
unsigned int thresh;
|
||||
unsigned int stage;
|
||||
unsigned int prev_stage;
|
||||
unsigned int base;
|
||||
/* protects .thresh, .stage and chip registers */
|
||||
struct mutex lock;
|
||||
|
@ -107,6 +107,7 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
|
||||
static const struct tsens_ops ops_generic_v2 = {
|
||||
.init = init_common,
|
||||
.get_temp = get_temp_tsens_valid,
|
||||
.resume = tsens_resume_common,
|
||||
};
|
||||
|
||||
struct tsens_plat_data data_tsens_v2 = {
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/thermal.h>
|
||||
#include "../thermal_hwmon.h"
|
||||
#include "tsens.h"
|
||||
@ -264,7 +265,7 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
dev_dbg(priv->dev,
|
||||
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
|
||||
__func__, i, p1[i], p2[i]);
|
||||
__func__, i, p1[i], p2 ? p2[i] : 0);
|
||||
|
||||
if (!priv->sensor[i].slope)
|
||||
priv->sensor[i].slope = SLOPE_DEFAULT;
|
||||
@ -1193,6 +1194,36 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
static int tsens_reinit(struct tsens_priv *priv)
|
||||
{
|
||||
if (tsens_version(priv) >= VER_2_X) {
|
||||
/*
|
||||
* Re-enable the watchdog, unmask the bark.
|
||||
* Disable cycle completion monitoring
|
||||
*/
|
||||
if (priv->feat->has_watchdog) {
|
||||
regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
|
||||
regmap_field_write(priv->rf[CC_MON_MASK], 1);
|
||||
}
|
||||
|
||||
/* Re-enable interrupts */
|
||||
tsens_enable_irq(priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsens_resume_common(struct tsens_priv *priv)
|
||||
{
|
||||
if (pm_suspend_target_state == PM_SUSPEND_MEM)
|
||||
tsens_reinit(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_SUSPEND */
|
||||
|
||||
static int tsens_register(struct tsens_priv *priv)
|
||||
{
|
||||
int i, ret;
|
||||
|
@ -634,6 +634,11 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mo
|
||||
int init_common(struct tsens_priv *priv);
|
||||
int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp);
|
||||
int get_temp_common(const struct tsens_sensor *s, int *temp);
|
||||
#ifdef CONFIG_SUSPEND
|
||||
int tsens_resume_common(struct tsens_priv *priv);
|
||||
#else
|
||||
#define tsens_resume_common NULL
|
||||
#endif
|
||||
|
||||
/* TSENS target */
|
||||
extern struct tsens_plat_data data_8960;
|
||||
|
@ -65,26 +65,29 @@
|
||||
|
||||
#define TSC_MAX_NUM 5
|
||||
|
||||
/* Structure for thermal temperature calculation */
|
||||
struct equation_coefs {
|
||||
int a1;
|
||||
int b1;
|
||||
int a2;
|
||||
int b2;
|
||||
};
|
||||
|
||||
struct rcar_gen3_thermal_priv;
|
||||
|
||||
struct rcar_thermal_info {
|
||||
int ths_tj_1;
|
||||
int scale;
|
||||
int adj_below;
|
||||
int adj_above;
|
||||
void (*read_fuses)(struct rcar_gen3_thermal_priv *priv);
|
||||
};
|
||||
|
||||
struct equation_set_coef {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
struct rcar_gen3_thermal_tsc {
|
||||
struct rcar_gen3_thermal_priv *priv;
|
||||
void __iomem *base;
|
||||
struct thermal_zone_device *zone;
|
||||
struct equation_coefs coef;
|
||||
int tj_t;
|
||||
/* Different coefficients are used depending on a threshold. */
|
||||
struct {
|
||||
struct equation_set_coef below;
|
||||
struct equation_set_coef above;
|
||||
} coef;
|
||||
int thcode[3];
|
||||
};
|
||||
|
||||
@ -93,6 +96,7 @@ struct rcar_gen3_thermal_priv {
|
||||
struct thermal_zone_device_ops ops;
|
||||
unsigned int num_tscs;
|
||||
int ptat[3];
|
||||
int tj_t;
|
||||
const struct rcar_thermal_info *info;
|
||||
};
|
||||
|
||||
@ -111,84 +115,75 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
|
||||
/*
|
||||
* Linear approximation for temperature
|
||||
*
|
||||
* [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
|
||||
* [temp] = ((thadj - [reg]) * a) / b + adj
|
||||
* [reg] = thadj - ([temp] - adj) * b / a
|
||||
*
|
||||
* The constants a and b are calculated using two triplets of int values PTAT
|
||||
* and THCODE. PTAT and THCODE can either be read from hardware or use hard
|
||||
* coded values from driver. The formula to calculate a and b are taken from
|
||||
* BSP and sparsely documented and understood.
|
||||
* coded values from the driver. The formula to calculate a and b are taken from
|
||||
* the datasheet. Different calculations are needed for a and b depending on
|
||||
* if the input variables ([temp] or [reg]) are above or below a threshold. The
|
||||
* threshold is also calculated from PTAT and THCODE using formulas from the
|
||||
* datasheet.
|
||||
*
|
||||
* Examining the linear formula and the formula used to calculate constants a
|
||||
* and b while knowing that the span for PTAT and THCODE values are between
|
||||
* 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
|
||||
* Integer also needs to be signed so that leaves 7 bits for binary
|
||||
* fixed point scaling.
|
||||
* The constant thadj is one of the THCODE values, which one to use depends on
|
||||
* the threshold and input value.
|
||||
*
|
||||
* The constants adj is taken verbatim from the datasheet. Two values exists,
|
||||
* which one to use depends on the input value and the calculated threshold.
|
||||
* Furthermore different SoC models supported by the driver have different sets
|
||||
* of values. The values for each model are stored in the device match data.
|
||||
*/
|
||||
|
||||
#define FIXPT_SHIFT 7
|
||||
#define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)
|
||||
#define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)
|
||||
#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
|
||||
#define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)
|
||||
|
||||
#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
|
||||
|
||||
/* no idea where these constants come from */
|
||||
#define TJ_3 -41
|
||||
|
||||
static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_priv *priv,
|
||||
struct rcar_gen3_thermal_tsc *tsc,
|
||||
int ths_tj_1)
|
||||
static void rcar_gen3_thermal_shared_coefs(struct rcar_gen3_thermal_priv *priv)
|
||||
{
|
||||
/* TODO: Find documentation and document constant calculation formula */
|
||||
|
||||
/*
|
||||
* Division is not scaled in BSP and if scaled it might overflow
|
||||
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
|
||||
*/
|
||||
tsc->tj_t = (FIXPT_INT((priv->ptat[1] - priv->ptat[2]) * (ths_tj_1 - TJ_3))
|
||||
/ (priv->ptat[0] - priv->ptat[2])) + FIXPT_INT(TJ_3);
|
||||
|
||||
tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[2]),
|
||||
tsc->tj_t - FIXPT_INT(TJ_3));
|
||||
tsc->coef.b1 = FIXPT_INT(tsc->thcode[2]) - tsc->coef.a1 * TJ_3;
|
||||
|
||||
tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[0]),
|
||||
tsc->tj_t - FIXPT_INT(ths_tj_1));
|
||||
tsc->coef.b2 = FIXPT_INT(tsc->thcode[0]) - tsc->coef.a2 * ths_tj_1;
|
||||
priv->tj_t =
|
||||
DIV_ROUND_CLOSEST((priv->ptat[1] - priv->ptat[2]) * priv->info->scale,
|
||||
priv->ptat[0] - priv->ptat[2])
|
||||
+ priv->info->adj_below;
|
||||
}
|
||||
|
||||
static int rcar_gen3_thermal_round(int temp)
|
||||
static void rcar_gen3_thermal_tsc_coefs(struct rcar_gen3_thermal_priv *priv,
|
||||
struct rcar_gen3_thermal_tsc *tsc)
|
||||
{
|
||||
int result, round_offs;
|
||||
tsc->coef.below.a = priv->info->scale * (priv->ptat[2] - priv->ptat[1]);
|
||||
tsc->coef.above.a = priv->info->scale * (priv->ptat[0] - priv->ptat[1]);
|
||||
|
||||
round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
|
||||
-RCAR3_THERMAL_GRAN / 2;
|
||||
result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
|
||||
return result * RCAR3_THERMAL_GRAN;
|
||||
tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]);
|
||||
tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]);
|
||||
}
|
||||
|
||||
static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct rcar_gen3_thermal_tsc *tsc = thermal_zone_device_priv(tz);
|
||||
int mcelsius, val;
|
||||
int reg;
|
||||
struct rcar_gen3_thermal_priv *priv = tsc->priv;
|
||||
const struct equation_set_coef *coef;
|
||||
int adj, decicelsius, reg, thcode;
|
||||
|
||||
/* Read register and convert to mili Celsius */
|
||||
reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
|
||||
|
||||
if (reg <= tsc->thcode[1])
|
||||
val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1,
|
||||
tsc->coef.a1);
|
||||
else
|
||||
val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2,
|
||||
tsc->coef.a2);
|
||||
mcelsius = FIXPT_TO_MCELSIUS(val);
|
||||
if (reg < tsc->thcode[1]) {
|
||||
adj = priv->info->adj_below;
|
||||
coef = &tsc->coef.below;
|
||||
thcode = tsc->thcode[2];
|
||||
} else {
|
||||
adj = priv->info->adj_above;
|
||||
coef = &tsc->coef.above;
|
||||
thcode = tsc->thcode[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* The dividend can't be grown as it might overflow, instead shorten the
|
||||
* divisor to convert to decidegree Celsius. If we convert after the
|
||||
* division precision is lost as we will scale up from whole degrees
|
||||
* Celsius.
|
||||
*/
|
||||
decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10);
|
||||
|
||||
/* Guaranteed operating range is -40C to 125C. */
|
||||
|
||||
/* Round value to device granularity setting */
|
||||
*temp = rcar_gen3_thermal_round(mcelsius);
|
||||
/* Reporting is done in millidegree Celsius */
|
||||
*temp = decicelsius * 100 + adj * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -196,15 +191,22 @@ static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
|
||||
int mcelsius)
|
||||
{
|
||||
int celsius, val;
|
||||
struct rcar_gen3_thermal_priv *priv = tsc->priv;
|
||||
const struct equation_set_coef *coef;
|
||||
int adj, celsius, thcode;
|
||||
|
||||
celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
|
||||
if (celsius <= INT_FIXPT(tsc->tj_t))
|
||||
val = celsius * tsc->coef.a1 + tsc->coef.b1;
|
||||
else
|
||||
val = celsius * tsc->coef.a2 + tsc->coef.b2;
|
||||
if (celsius < priv->tj_t) {
|
||||
coef = &tsc->coef.below;
|
||||
adj = priv->info->adj_below;
|
||||
thcode = tsc->thcode[2];
|
||||
} else {
|
||||
coef = &tsc->coef.above;
|
||||
adj = priv->info->adj_above;
|
||||
thcode = tsc->thcode[0];
|
||||
}
|
||||
|
||||
return INT_FIXPT(val);
|
||||
return thcode - DIV_ROUND_CLOSEST((celsius - adj) * coef->b, coef->a);
|
||||
}
|
||||
|
||||
static int rcar_gen3_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
|
||||
@ -369,17 +371,23 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv,
|
||||
}
|
||||
|
||||
static const struct rcar_thermal_info rcar_m3w_thermal_info = {
|
||||
.ths_tj_1 = 116,
|
||||
.scale = 157,
|
||||
.adj_below = -41,
|
||||
.adj_above = 116,
|
||||
.read_fuses = rcar_gen3_thermal_read_fuses_gen3,
|
||||
};
|
||||
|
||||
static const struct rcar_thermal_info rcar_gen3_thermal_info = {
|
||||
.ths_tj_1 = 126,
|
||||
.scale = 167,
|
||||
.adj_below = -41,
|
||||
.adj_above = 126,
|
||||
.read_fuses = rcar_gen3_thermal_read_fuses_gen3,
|
||||
};
|
||||
|
||||
static const struct rcar_thermal_info rcar_gen4_thermal_info = {
|
||||
.ths_tj_1 = 126,
|
||||
.scale = 167,
|
||||
.adj_below = -41,
|
||||
.adj_above = 126,
|
||||
.read_fuses = rcar_gen3_thermal_read_fuses_gen4,
|
||||
};
|
||||
|
||||
@ -516,6 +524,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||
goto error_unregister;
|
||||
}
|
||||
|
||||
tsc->priv = priv;
|
||||
tsc->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(tsc->base)) {
|
||||
ret = PTR_ERR(tsc->base);
|
||||
@ -530,11 +539,13 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||
if (!rcar_gen3_thermal_read_fuses(priv))
|
||||
dev_info(dev, "No calibration values fused, fallback to driver values\n");
|
||||
|
||||
rcar_gen3_thermal_shared_coefs(priv);
|
||||
|
||||
for (i = 0; i < priv->num_tscs; i++) {
|
||||
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
|
||||
|
||||
rcar_gen3_thermal_init(priv, tsc);
|
||||
rcar_gen3_thermal_calc_coefs(priv, tsc, priv->info->ths_tj_1);
|
||||
rcar_gen3_thermal_tsc_coefs(priv, tsc);
|
||||
|
||||
zone = devm_thermal_of_zone_register(dev, i, tsc, &priv->ops);
|
||||
if (IS_ERR(zone)) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/list_sort.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/string.h>
|
||||
@ -361,49 +362,48 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
|
||||
}
|
||||
|
||||
static void handle_thermal_trip(struct thermal_zone_device *tz,
|
||||
struct thermal_trip *trip)
|
||||
struct thermal_trip_desc *td,
|
||||
struct list_head *way_up_list,
|
||||
struct list_head *way_down_list)
|
||||
{
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
int old_threshold;
|
||||
|
||||
if (trip->temperature == THERMAL_TEMP_INVALID)
|
||||
return;
|
||||
|
||||
if (tz->last_temperature == THERMAL_TEMP_INVALID) {
|
||||
/* Initialization. */
|
||||
trip->threshold = trip->temperature;
|
||||
if (tz->temperature >= trip->threshold)
|
||||
trip->threshold -= trip->hysteresis;
|
||||
} else if (tz->last_temperature < trip->threshold) {
|
||||
/*
|
||||
* If the trip temperature or hysteresis has been updated recently,
|
||||
* the threshold needs to be computed again using the new values.
|
||||
* However, its initial value still reflects the old ones and that
|
||||
* is what needs to be compared with the previous zone temperature
|
||||
* to decide which action to take.
|
||||
*/
|
||||
old_threshold = td->threshold;
|
||||
td->threshold = trip->temperature;
|
||||
|
||||
if (tz->last_temperature >= old_threshold &&
|
||||
tz->last_temperature != THERMAL_TEMP_INVALID) {
|
||||
/*
|
||||
* The trip threshold is equal to the trip temperature, unless
|
||||
* the latter has changed in the meantime. In either case,
|
||||
* the trip is crossed if the current zone temperature is at
|
||||
* least equal to its temperature, but otherwise ensure that
|
||||
* the threshold and the trip temperature will be equal.
|
||||
*/
|
||||
if (tz->temperature >= trip->temperature) {
|
||||
thermal_notify_tz_trip_up(tz, trip);
|
||||
thermal_debug_tz_trip_up(tz, trip);
|
||||
trip->threshold = trip->temperature - trip->hysteresis;
|
||||
} else {
|
||||
trip->threshold = trip->temperature;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The previous zone temperature was above or equal to the trip
|
||||
* threshold, which would be equal to the "low temperature" of
|
||||
* the trip (its temperature minus its hysteresis), unless the
|
||||
* trip temperature or hysteresis had changed. In either case,
|
||||
* the trip is crossed if the current zone temperature is below
|
||||
* the low temperature of the trip, but otherwise ensure that
|
||||
* the trip threshold will be equal to the low temperature of
|
||||
* the trip.
|
||||
* Mitigation is under way, so it needs to stop if the zone
|
||||
* temperature falls below the low temperature of the trip.
|
||||
* In that case, the trip temperature becomes the new threshold.
|
||||
*/
|
||||
if (tz->temperature < trip->temperature - trip->hysteresis) {
|
||||
thermal_notify_tz_trip_down(tz, trip);
|
||||
thermal_debug_tz_trip_down(tz, trip);
|
||||
trip->threshold = trip->temperature;
|
||||
list_add(&td->notify_list_node, way_down_list);
|
||||
td->notify_temp = trip->temperature - trip->hysteresis;
|
||||
} else {
|
||||
trip->threshold = trip->temperature - trip->hysteresis;
|
||||
td->threshold -= trip->hysteresis;
|
||||
}
|
||||
} else if (tz->temperature >= trip->temperature) {
|
||||
/*
|
||||
* There is no mitigation under way, so it needs to be started
|
||||
* if the zone temperature exceeds the trip one. The new
|
||||
* threshold is then set to the low temperature of the trip.
|
||||
*/
|
||||
list_add_tail(&td->notify_list_node, way_up_list);
|
||||
td->notify_temp = trip->temperature;
|
||||
td->threshold -= trip->hysteresis;
|
||||
}
|
||||
|
||||
if (trip->type == THERMAL_TRIP_CRITICAL || trip->type == THERMAL_TRIP_HOT)
|
||||
@ -455,10 +455,24 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz)
|
||||
pos->initialized = false;
|
||||
}
|
||||
|
||||
static int thermal_trip_notify_cmp(void *ascending, const struct list_head *a,
|
||||
const struct list_head *b)
|
||||
{
|
||||
struct thermal_trip_desc *tda = container_of(a, struct thermal_trip_desc,
|
||||
notify_list_node);
|
||||
struct thermal_trip_desc *tdb = container_of(b, struct thermal_trip_desc,
|
||||
notify_list_node);
|
||||
int ret = tdb->notify_temp - tda->notify_temp;
|
||||
|
||||
return ascending ? ret : -ret;
|
||||
}
|
||||
|
||||
void __thermal_zone_device_update(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event event)
|
||||
{
|
||||
struct thermal_trip *trip;
|
||||
struct thermal_trip_desc *td;
|
||||
LIST_HEAD(way_down_list);
|
||||
LIST_HEAD(way_up_list);
|
||||
|
||||
if (tz->suspended)
|
||||
return;
|
||||
@ -472,8 +486,20 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz,
|
||||
|
||||
tz->notify_event = event;
|
||||
|
||||
for_each_trip(tz, trip)
|
||||
handle_thermal_trip(tz, trip);
|
||||
for_each_trip_desc(tz, td)
|
||||
handle_thermal_trip(tz, td, &way_up_list, &way_down_list);
|
||||
|
||||
list_sort(&way_up_list, &way_up_list, thermal_trip_notify_cmp);
|
||||
list_for_each_entry(td, &way_up_list, notify_list_node) {
|
||||
thermal_notify_tz_trip_up(tz, &td->trip);
|
||||
thermal_debug_tz_trip_up(tz, &td->trip);
|
||||
}
|
||||
|
||||
list_sort(NULL, &way_down_list, thermal_trip_notify_cmp);
|
||||
list_for_each_entry(td, &way_down_list, notify_list_node) {
|
||||
thermal_notify_tz_trip_down(tz, &td->trip);
|
||||
thermal_debug_tz_trip_down(tz, &td->trip);
|
||||
}
|
||||
|
||||
monitor_thermal_zone(tz);
|
||||
}
|
||||
@ -766,7 +792,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
||||
if (trip_index < 0 || trip_index >= tz->num_trips)
|
||||
return -EINVAL;
|
||||
|
||||
return thermal_bind_cdev_to_trip(tz, &tz->trips[trip_index], cdev,
|
||||
return thermal_bind_cdev_to_trip(tz, &tz->trips[trip_index].trip, cdev,
|
||||
upper, lower, weight);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_bind_cooling_device);
|
||||
@ -825,7 +851,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
|
||||
if (trip_index < 0 || trip_index >= tz->num_trips)
|
||||
return -EINVAL;
|
||||
|
||||
return thermal_unbind_cdev_from_trip(tz, &tz->trips[trip_index], cdev);
|
||||
return thermal_unbind_cdev_from_trip(tz, &tz->trips[trip_index].trip, cdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_unbind_cooling_device);
|
||||
|
||||
@ -1221,16 +1247,19 @@ static void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms
|
||||
|
||||
int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
int i, ret = -EINVAL;
|
||||
const struct thermal_trip_desc *td;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (tz->ops.get_crit_temp)
|
||||
return tz->ops.get_crit_temp(tz, temp);
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
|
||||
for (i = 0; i < tz->num_trips; i++) {
|
||||
if (tz->trips[i].type == THERMAL_TRIP_CRITICAL) {
|
||||
*temp = tz->trips[i].temperature;
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
|
||||
if (trip->type == THERMAL_TRIP_CRITICAL) {
|
||||
*temp = trip->temperature;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@ -1274,7 +1303,9 @@ thermal_zone_device_register_with_trips(const char *type,
|
||||
const struct thermal_zone_params *tzp,
|
||||
int passive_delay, int polling_delay)
|
||||
{
|
||||
const struct thermal_trip *trip = trips;
|
||||
struct thermal_zone_device *tz;
|
||||
struct thermal_trip_desc *td;
|
||||
int id;
|
||||
int result;
|
||||
struct thermal_governor *governor;
|
||||
@ -1339,7 +1370,8 @@ thermal_zone_device_register_with_trips(const char *type,
|
||||
tz->device.class = thermal_class;
|
||||
tz->devdata = devdata;
|
||||
tz->num_trips = num_trips;
|
||||
memcpy(tz->trips, trips, num_trips * sizeof(*trips));
|
||||
for_each_trip_desc(tz, td)
|
||||
td->trip = *trip++;
|
||||
|
||||
thermal_set_delay_jiffies(&tz->passive_delay_jiffies, passive_delay);
|
||||
thermal_set_delay_jiffies(&tz->polling_delay_jiffies, polling_delay);
|
||||
|
@ -15,6 +15,118 @@
|
||||
#include "thermal_netlink.h"
|
||||
#include "thermal_debugfs.h"
|
||||
|
||||
struct thermal_trip_desc {
|
||||
struct thermal_trip trip;
|
||||
struct list_head notify_list_node;
|
||||
int notify_temp;
|
||||
int threshold;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct thermal_governor - structure that holds thermal governor information
|
||||
* @name: name of the governor
|
||||
* @bind_to_tz: callback called when binding to a thermal zone. If it
|
||||
* returns 0, the governor is bound to the thermal zone,
|
||||
* otherwise it fails.
|
||||
* @unbind_from_tz: callback called when a governor is unbound from a
|
||||
* thermal zone.
|
||||
* @throttle: callback called for every trip point even if temperature is
|
||||
* below the trip point temperature
|
||||
* @update_tz: callback called when thermal zone internals have changed, e.g.
|
||||
* thermal cooling instance was added/removed
|
||||
* @governor_list: node in thermal_governor_list (in thermal_core.c)
|
||||
*/
|
||||
struct thermal_governor {
|
||||
const char *name;
|
||||
int (*bind_to_tz)(struct thermal_zone_device *tz);
|
||||
void (*unbind_from_tz)(struct thermal_zone_device *tz);
|
||||
int (*throttle)(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip);
|
||||
void (*update_tz)(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event reason);
|
||||
struct list_head governor_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct thermal_zone_device - structure for a thermal zone
|
||||
* @id: unique id number for each thermal zone
|
||||
* @type: the thermal zone device type
|
||||
* @device: &struct device for this thermal zone
|
||||
* @removal: removal completion
|
||||
* @trip_temp_attrs: attributes for trip points for sysfs: trip temperature
|
||||
* @trip_type_attrs: attributes for trip points for sysfs: trip type
|
||||
* @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis
|
||||
* @mode: current mode of this thermal zone
|
||||
* @devdata: private pointer for device private data
|
||||
* @num_trips: number of trip points the thermal zone supports
|
||||
* @passive_delay_jiffies: number of jiffies to wait between polls when
|
||||
* performing passive cooling.
|
||||
* @polling_delay_jiffies: number of jiffies to wait between polls when
|
||||
* checking whether trip points have been crossed (0 for
|
||||
* interrupt driven systems)
|
||||
* @temperature: current temperature. This is only for core code,
|
||||
* drivers should use thermal_zone_get_temp() to get the
|
||||
* current temperature
|
||||
* @last_temperature: previous temperature read
|
||||
* @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
|
||||
* @passive: 1 if you've crossed a passive trip point, 0 otherwise.
|
||||
* @prev_low_trip: the low current temperature if you've crossed a passive
|
||||
trip point.
|
||||
* @prev_high_trip: the above current temperature if you've crossed a
|
||||
passive trip point.
|
||||
* @need_update: if equals 1, thermal_zone_device_update needs to be invoked.
|
||||
* @ops: operations this &thermal_zone_device supports
|
||||
* @tzp: thermal zone parameters
|
||||
* @governor: pointer to the governor for this thermal zone
|
||||
* @governor_data: private pointer for governor data
|
||||
* @thermal_instances: list of &struct thermal_instance of this thermal zone
|
||||
* @ida: &struct ida to generate unique id for this zone's cooling
|
||||
* devices
|
||||
* @lock: lock to protect thermal_instances list
|
||||
* @node: node in thermal_tz_list (in thermal_core.c)
|
||||
* @poll_queue: delayed work for polling
|
||||
* @notify_event: Last notification event
|
||||
* @suspended: thermal zone suspend indicator
|
||||
* @trips: array of struct thermal_trip objects
|
||||
*/
|
||||
struct thermal_zone_device {
|
||||
int id;
|
||||
char type[THERMAL_NAME_LENGTH];
|
||||
struct device device;
|
||||
struct completion removal;
|
||||
struct attribute_group trips_attribute_group;
|
||||
struct thermal_attr *trip_temp_attrs;
|
||||
struct thermal_attr *trip_type_attrs;
|
||||
struct thermal_attr *trip_hyst_attrs;
|
||||
enum thermal_device_mode mode;
|
||||
void *devdata;
|
||||
int num_trips;
|
||||
unsigned long passive_delay_jiffies;
|
||||
unsigned long polling_delay_jiffies;
|
||||
int temperature;
|
||||
int last_temperature;
|
||||
int emul_temperature;
|
||||
int passive;
|
||||
int prev_low_trip;
|
||||
int prev_high_trip;
|
||||
atomic_t need_update;
|
||||
struct thermal_zone_device_ops ops;
|
||||
struct thermal_zone_params *tzp;
|
||||
struct thermal_governor *governor;
|
||||
void *governor_data;
|
||||
struct list_head thermal_instances;
|
||||
struct ida ida;
|
||||
struct mutex lock;
|
||||
struct list_head node;
|
||||
struct delayed_work poll_queue;
|
||||
enum thermal_notify_event notify_event;
|
||||
bool suspended;
|
||||
#ifdef CONFIG_THERMAL_DEBUGFS
|
||||
struct thermal_debugfs *debugfs;
|
||||
#endif
|
||||
struct thermal_trip_desc trips[] __counted_by(num_trips);
|
||||
};
|
||||
|
||||
/* Default Thermal Governor */
|
||||
#if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
|
||||
#define DEFAULT_THERMAL_GOVERNOR "step_wise"
|
||||
@ -120,8 +232,11 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event reason);
|
||||
|
||||
/* Helpers */
|
||||
#define for_each_trip(__tz, __trip) \
|
||||
for (__trip = __tz->trips; __trip - __tz->trips < __tz->num_trips; __trip++)
|
||||
#define for_each_trip_desc(__tz, __td) \
|
||||
for (__td = __tz->trips; __td - __tz->trips < __tz->num_trips; __td++)
|
||||
|
||||
#define trip_to_trip_desc(__trip) \
|
||||
container_of(__trip, struct thermal_trip_desc, trip)
|
||||
|
||||
void __thermal_zone_set_trips(struct thermal_zone_device *tz);
|
||||
int thermal_zone_trip_id(const struct thermal_zone_device *tz,
|
||||
|
@ -753,7 +753,7 @@ static int tze_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct thermal_debugfs *thermal_dbg = s->private;
|
||||
struct thermal_zone_device *tz = thermal_dbg->tz_dbg.tz;
|
||||
struct thermal_trip *trip;
|
||||
struct thermal_trip_desc *td;
|
||||
struct tz_episode *tze;
|
||||
const char *type;
|
||||
int trip_id;
|
||||
@ -766,7 +766,9 @@ static int tze_seq_show(struct seq_file *s, void *v)
|
||||
|
||||
seq_printf(s, "| trip | type | temp(°mC) | hyst(°mC) | duration | avg(°mC) | min(°mC) | max(°mC) |\n");
|
||||
|
||||
for_each_trip(tz, trip) {
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
|
||||
/*
|
||||
* There is no possible mitigation happening at the
|
||||
* critical trip point, so the stats will be always
|
||||
|
@ -50,7 +50,7 @@ get_thermal_instance(struct thermal_zone_device *tz,
|
||||
mutex_lock(&tz->lock);
|
||||
mutex_lock(&cdev->lock);
|
||||
|
||||
trip = &tz->trips[trip_index];
|
||||
trip = &tz->trips[trip_index].trip;
|
||||
|
||||
list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
|
||||
if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
|
||||
@ -82,7 +82,7 @@ EXPORT_SYMBOL(get_thermal_instance);
|
||||
*/
|
||||
int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
const struct thermal_trip *trip;
|
||||
const struct thermal_trip_desc *td;
|
||||
int crit_temp = INT_MAX;
|
||||
int ret = -EINVAL;
|
||||
|
||||
@ -91,7 +91,9 @@ int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
ret = tz->ops.get_temp(tz, temp);
|
||||
|
||||
if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
|
||||
for_each_trip(tz, trip) {
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
|
||||
if (trip->type == THERMAL_TRIP_CRITICAL) {
|
||||
crit_temp = trip->temperature;
|
||||
break;
|
||||
|
@ -7,17 +7,13 @@
|
||||
* Generic netlink for thermal management framework
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <uapi/linux/thermal.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
enum thermal_genl_multicast_groups {
|
||||
THERMAL_GENL_SAMPLING_GROUP = 0,
|
||||
THERMAL_GENL_EVENT_GROUP = 1,
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group thermal_genl_mcgrps[] = {
|
||||
[THERMAL_GENL_SAMPLING_GROUP] = { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, },
|
||||
[THERMAL_GENL_EVENT_GROUP] = { .name = THERMAL_GENL_EVENT_GROUP_NAME, },
|
||||
@ -74,11 +70,12 @@ struct param {
|
||||
|
||||
typedef int (*cb_t)(struct param *);
|
||||
|
||||
static struct genl_family thermal_gnl_family;
|
||||
static struct genl_family thermal_genl_family;
|
||||
static BLOCKING_NOTIFIER_HEAD(thermal_genl_chain);
|
||||
|
||||
static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group)
|
||||
{
|
||||
return genl_has_listeners(&thermal_gnl_family, &init_net, group);
|
||||
return genl_has_listeners(&thermal_genl_family, &init_net, group);
|
||||
}
|
||||
|
||||
/************************** Sampling encoding *******************************/
|
||||
@ -95,7 +92,7 @@ int thermal_genl_sampling_temp(int id, int temp)
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0,
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0,
|
||||
THERMAL_GENL_SAMPLING_TEMP);
|
||||
if (!hdr)
|
||||
goto out_free;
|
||||
@ -108,7 +105,7 @@ int thermal_genl_sampling_temp(int id, int temp)
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
|
||||
genlmsg_multicast(&thermal_gnl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL);
|
||||
genlmsg_multicast(&thermal_genl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
out_cancel:
|
||||
@ -282,7 +279,7 @@ static int thermal_genl_send_event(enum thermal_genl_event event,
|
||||
return -ENOMEM;
|
||||
p->msg = msg;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event);
|
||||
hdr = genlmsg_put(msg, 0, 0, &thermal_genl_family, 0, event);
|
||||
if (!hdr)
|
||||
goto out_free_msg;
|
||||
|
||||
@ -292,7 +289,7 @@ static int thermal_genl_send_event(enum thermal_genl_event event,
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast(&thermal_gnl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL);
|
||||
genlmsg_multicast(&thermal_genl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -445,7 +442,7 @@ out_cancel_nest:
|
||||
static int thermal_genl_cmd_tz_get_trip(struct param *p)
|
||||
{
|
||||
struct sk_buff *msg = p->msg;
|
||||
const struct thermal_trip *trip;
|
||||
const struct thermal_trip_desc *td;
|
||||
struct thermal_zone_device *tz;
|
||||
struct nlattr *start_trip;
|
||||
int id;
|
||||
@ -465,7 +462,9 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p)
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
|
||||
for_each_trip(tz, trip) {
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
|
||||
if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID,
|
||||
thermal_zone_trip_id(tz, trip)) ||
|
||||
nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) ||
|
||||
@ -593,7 +592,7 @@ static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
|
||||
int ret;
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd);
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, cmd);
|
||||
if (!hdr)
|
||||
return -EMSGSIZE;
|
||||
|
||||
@ -625,7 +624,7 @@ static int thermal_genl_cmd_doit(struct sk_buff *skb,
|
||||
return -ENOMEM;
|
||||
p.msg = msg;
|
||||
|
||||
hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd);
|
||||
hdr = genlmsg_put_reply(msg, info, &thermal_genl_family, 0, cmd);
|
||||
if (!hdr)
|
||||
goto out_free_msg;
|
||||
|
||||
@ -645,6 +644,27 @@ out_free_msg:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int thermal_genl_bind(int mcgrp)
|
||||
{
|
||||
struct thermal_genl_notify n = { .mcgrp = mcgrp };
|
||||
|
||||
if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP))
|
||||
return -EINVAL;
|
||||
|
||||
blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_BIND, &n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thermal_genl_unbind(int mcgrp)
|
||||
{
|
||||
struct thermal_genl_notify n = { .mcgrp = mcgrp };
|
||||
|
||||
if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP))
|
||||
return;
|
||||
|
||||
blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_UNBIND, &n);
|
||||
}
|
||||
|
||||
static const struct genl_small_ops thermal_genl_ops[] = {
|
||||
{
|
||||
.cmd = THERMAL_GENL_CMD_TZ_GET_ID,
|
||||
@ -673,12 +693,14 @@ static const struct genl_small_ops thermal_genl_ops[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family thermal_gnl_family __ro_after_init = {
|
||||
static struct genl_family thermal_genl_family __ro_after_init = {
|
||||
.hdrsize = 0,
|
||||
.name = THERMAL_GENL_FAMILY_NAME,
|
||||
.version = THERMAL_GENL_VERSION,
|
||||
.maxattr = THERMAL_GENL_ATTR_MAX,
|
||||
.policy = thermal_genl_policy,
|
||||
.bind = thermal_genl_bind,
|
||||
.unbind = thermal_genl_unbind,
|
||||
.small_ops = thermal_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(thermal_genl_ops),
|
||||
.resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1,
|
||||
@ -686,12 +708,22 @@ static struct genl_family thermal_gnl_family __ro_after_init = {
|
||||
.n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),
|
||||
};
|
||||
|
||||
int thermal_genl_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&thermal_genl_chain, nb);
|
||||
}
|
||||
|
||||
int thermal_genl_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&thermal_genl_chain, nb);
|
||||
}
|
||||
|
||||
int __init thermal_netlink_init(void)
|
||||
{
|
||||
return genl_register_family(&thermal_gnl_family);
|
||||
return genl_register_family(&thermal_genl_family);
|
||||
}
|
||||
|
||||
void __init thermal_netlink_exit(void)
|
||||
{
|
||||
genl_unregister_family(&thermal_gnl_family);
|
||||
genl_unregister_family(&thermal_genl_family);
|
||||
}
|
||||
|
@ -10,6 +10,19 @@ struct thermal_genl_cpu_caps {
|
||||
int efficiency;
|
||||
};
|
||||
|
||||
enum thermal_genl_multicast_groups {
|
||||
THERMAL_GENL_SAMPLING_GROUP = 0,
|
||||
THERMAL_GENL_EVENT_GROUP = 1,
|
||||
THERMAL_GENL_MAX_GROUP = THERMAL_GENL_EVENT_GROUP,
|
||||
};
|
||||
|
||||
#define THERMAL_NOTIFY_BIND 0
|
||||
#define THERMAL_NOTIFY_UNBIND 1
|
||||
|
||||
struct thermal_genl_notify {
|
||||
int mcgrp;
|
||||
};
|
||||
|
||||
struct thermal_zone_device;
|
||||
struct thermal_trip;
|
||||
struct thermal_cooling_device;
|
||||
@ -18,6 +31,9 @@ struct thermal_cooling_device;
|
||||
#ifdef CONFIG_THERMAL_NETLINK
|
||||
int __init thermal_netlink_init(void);
|
||||
void __init thermal_netlink_exit(void);
|
||||
int thermal_genl_register_notifier(struct notifier_block *nb);
|
||||
int thermal_genl_unregister_notifier(struct notifier_block *nb);
|
||||
|
||||
int thermal_notify_tz_create(const struct thermal_zone_device *tz);
|
||||
int thermal_notify_tz_delete(const struct thermal_zone_device *tz);
|
||||
int thermal_notify_tz_enable(const struct thermal_zone_device *tz);
|
||||
@ -48,6 +64,16 @@ static inline int thermal_notify_tz_create(const struct thermal_zone_device *tz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_genl_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_genl_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_notify_tz_delete(const struct thermal_zone_device *tz)
|
||||
{
|
||||
return 0;
|
||||
|
@ -88,7 +88,7 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
|
||||
if (sscanf(attr->attr.name, "trip_point_%d_type", &trip_id) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
switch (tz->trips[trip_id].type) {
|
||||
switch (tz->trips[trip_id].trip.type) {
|
||||
case THERMAL_TRIP_CRITICAL:
|
||||
return sprintf(buf, "critical\n");
|
||||
case THERMAL_TRIP_HOT:
|
||||
@ -120,7 +120,7 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
|
||||
trip = &tz->trips[trip_id];
|
||||
trip = &tz->trips[trip_id].trip;
|
||||
|
||||
if (temp != trip->temperature) {
|
||||
if (tz->ops.set_trip_temp) {
|
||||
@ -150,7 +150,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
|
||||
if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "%d\n", tz->trips[trip_id].temperature);
|
||||
return sprintf(buf, "%d\n", tz->trips[trip_id].trip.temperature);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -171,7 +171,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
|
||||
trip = &tz->trips[trip_id];
|
||||
trip = &tz->trips[trip_id].trip;
|
||||
|
||||
if (hyst != trip->hysteresis) {
|
||||
trip->hysteresis = hyst;
|
||||
@ -194,7 +194,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
|
||||
if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "%d\n", tz->trips[trip_id].hysteresis);
|
||||
return sprintf(buf, "%d\n", tz->trips[trip_id].trip.hysteresis);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -393,7 +393,7 @@ static const struct attribute_group *thermal_zone_attribute_groups[] = {
|
||||
*/
|
||||
static int create_trip_attrs(struct thermal_zone_device *tz)
|
||||
{
|
||||
const struct thermal_trip *trip;
|
||||
const struct thermal_trip_desc *td;
|
||||
struct attribute **attrs;
|
||||
|
||||
/* This function works only for zones with at least one trip */
|
||||
@ -429,8 +429,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for_each_trip(tz, trip) {
|
||||
int indx = thermal_zone_trip_id(tz, trip);
|
||||
for_each_trip_desc(tz, td) {
|
||||
int indx = thermal_zone_trip_id(tz, &td->trip);
|
||||
|
||||
/* create trip type attribute */
|
||||
snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
|
||||
@ -452,7 +452,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz)
|
||||
tz->trip_temp_attrs[indx].name;
|
||||
tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
|
||||
tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
|
||||
if (trip->flags & THERMAL_TRIP_FLAG_RW_TEMP) {
|
||||
if (td->trip.flags & THERMAL_TRIP_FLAG_RW_TEMP) {
|
||||
tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
|
||||
tz->trip_temp_attrs[indx].attr.store =
|
||||
trip_point_temp_store;
|
||||
@ -467,7 +467,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz)
|
||||
tz->trip_hyst_attrs[indx].name;
|
||||
tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
|
||||
tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
|
||||
if (trip->flags & THERMAL_TRIP_FLAG_RW_HYST) {
|
||||
if (td->trip.flags & THERMAL_TRIP_FLAG_RW_HYST) {
|
||||
tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
|
||||
tz->trip_hyst_attrs[indx].attr.store =
|
||||
trip_point_hyst_store;
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
TRACE_DEFINE_ENUM(THERMAL_TRIP_CRITICAL);
|
||||
TRACE_DEFINE_ENUM(THERMAL_TRIP_HOT);
|
||||
TRACE_DEFINE_ENUM(THERMAL_TRIP_PASSIVE);
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
TRACE_EVENT(thermal_power_allocator,
|
||||
TP_PROTO(struct thermal_zone_device *tz, u32 total_req_power,
|
||||
u32 total_granted_power, int num_actors, u32 power_range,
|
||||
|
@ -13,11 +13,11 @@ int for_each_thermal_trip(struct thermal_zone_device *tz,
|
||||
int (*cb)(struct thermal_trip *, void *),
|
||||
void *data)
|
||||
{
|
||||
struct thermal_trip *trip;
|
||||
struct thermal_trip_desc *td;
|
||||
int ret;
|
||||
|
||||
for_each_trip(tz, trip) {
|
||||
ret = cb(trip, data);
|
||||
for_each_trip_desc(tz, td) {
|
||||
ret = cb(&td->trip, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -63,7 +63,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
|
||||
*/
|
||||
void __thermal_zone_set_trips(struct thermal_zone_device *tz)
|
||||
{
|
||||
const struct thermal_trip *trip;
|
||||
const struct thermal_trip_desc *td;
|
||||
int low = -INT_MAX, high = INT_MAX;
|
||||
int ret;
|
||||
|
||||
@ -72,7 +72,8 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
|
||||
if (!tz->ops.set_trips)
|
||||
return;
|
||||
|
||||
for_each_trip(tz, trip) {
|
||||
for_each_trip_desc(tz, td) {
|
||||
const struct thermal_trip *trip = &td->trip;
|
||||
int trip_low;
|
||||
|
||||
trip_low = trip->temperature - trip->hysteresis;
|
||||
@ -110,7 +111,7 @@ int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip)
|
||||
return -EINVAL;
|
||||
|
||||
*trip = tz->trips[trip_id];
|
||||
*trip = tz->trips[trip_id].trip;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__thermal_zone_get_trip);
|
||||
@ -135,7 +136,7 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz,
|
||||
* Assume the trip to be located within the bounds of the thermal
|
||||
* zone's trips[] table.
|
||||
*/
|
||||
return trip - tz->trips;
|
||||
return trip_to_trip_desc(trip) - tz->trips;
|
||||
}
|
||||
void thermal_zone_trip_updated(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
|
@ -16,6 +16,32 @@
|
||||
#define MT7988_ETHWARP_0 6
|
||||
#define MT7988_ETHWARP_1 7
|
||||
|
||||
#define MT8186_LITTLE_CPU0 0
|
||||
#define MT8186_LITTLE_CPU1 1
|
||||
#define MT8186_LITTLE_CPU2 2
|
||||
#define MT8186_CAM 3
|
||||
#define MT8186_BIG_CPU0 4
|
||||
#define MT8186_BIG_CPU1 5
|
||||
#define MT8186_NNA 6
|
||||
#define MT8186_ADSP 7
|
||||
#define MT8186_MFG 8
|
||||
|
||||
#define MT8188_MCU_LITTLE_CPU0 0
|
||||
#define MT8188_MCU_LITTLE_CPU1 1
|
||||
#define MT8188_MCU_LITTLE_CPU2 2
|
||||
#define MT8188_MCU_LITTLE_CPU3 3
|
||||
#define MT8188_MCU_BIG_CPU0 4
|
||||
#define MT8188_MCU_BIG_CPU1 5
|
||||
|
||||
#define MT8188_AP_APU 0
|
||||
#define MT8188_AP_GPU1 1
|
||||
#define MT8188_AP_GPU2 2
|
||||
#define MT8188_AP_SOC1 3
|
||||
#define MT8188_AP_SOC2 4
|
||||
#define MT8188_AP_SOC3 5
|
||||
#define MT8188_AP_CAM1 6
|
||||
#define MT8188_AP_CAM2 7
|
||||
|
||||
#define MT8195_MCU_BIG_CPU0 0
|
||||
#define MT8195_MCU_BIG_CPU1 1
|
||||
#define MT8195_MCU_BIG_CPU2 2
|
||||
|
@ -61,7 +61,6 @@ enum thermal_notify_event {
|
||||
* struct thermal_trip - representation of a point in temperature domain
|
||||
* @temperature: temperature value in miliCelsius
|
||||
* @hysteresis: relative hysteresis in miliCelsius
|
||||
* @threshold: trip crossing notification threshold miliCelsius
|
||||
* @type: trip point type
|
||||
* @priv: pointer to driver data associated with this trip
|
||||
* @flags: flags representing binary properties of the trip
|
||||
@ -69,7 +68,6 @@ enum thermal_notify_event {
|
||||
struct thermal_trip {
|
||||
int temperature;
|
||||
int hysteresis;
|
||||
int threshold;
|
||||
enum thermal_trip_type type;
|
||||
u8 flags;
|
||||
void *priv;
|
||||
@ -81,6 +79,8 @@ struct thermal_trip {
|
||||
#define THERMAL_TRIP_FLAG_RW (THERMAL_TRIP_FLAG_RW_TEMP | \
|
||||
THERMAL_TRIP_FLAG_RW_HYST)
|
||||
|
||||
struct thermal_zone_device;
|
||||
|
||||
struct thermal_zone_device_ops {
|
||||
int (*bind) (struct thermal_zone_device *,
|
||||
struct thermal_cooling_device *);
|
||||
@ -126,111 +126,6 @@ struct thermal_cooling_device {
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* struct thermal_zone_device - structure for a thermal zone
|
||||
* @id: unique id number for each thermal zone
|
||||
* @type: the thermal zone device type
|
||||
* @device: &struct device for this thermal zone
|
||||
* @removal: removal completion
|
||||
* @trip_temp_attrs: attributes for trip points for sysfs: trip temperature
|
||||
* @trip_type_attrs: attributes for trip points for sysfs: trip type
|
||||
* @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis
|
||||
* @mode: current mode of this thermal zone
|
||||
* @devdata: private pointer for device private data
|
||||
* @num_trips: number of trip points the thermal zone supports
|
||||
* @passive_delay_jiffies: number of jiffies to wait between polls when
|
||||
* performing passive cooling.
|
||||
* @polling_delay_jiffies: number of jiffies to wait between polls when
|
||||
* checking whether trip points have been crossed (0 for
|
||||
* interrupt driven systems)
|
||||
* @temperature: current temperature. This is only for core code,
|
||||
* drivers should use thermal_zone_get_temp() to get the
|
||||
* current temperature
|
||||
* @last_temperature: previous temperature read
|
||||
* @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
|
||||
* @passive: 1 if you've crossed a passive trip point, 0 otherwise.
|
||||
* @prev_low_trip: the low current temperature if you've crossed a passive
|
||||
trip point.
|
||||
* @prev_high_trip: the above current temperature if you've crossed a
|
||||
passive trip point.
|
||||
* @need_update: if equals 1, thermal_zone_device_update needs to be invoked.
|
||||
* @ops: operations this &thermal_zone_device supports
|
||||
* @tzp: thermal zone parameters
|
||||
* @governor: pointer to the governor for this thermal zone
|
||||
* @governor_data: private pointer for governor data
|
||||
* @thermal_instances: list of &struct thermal_instance of this thermal zone
|
||||
* @ida: &struct ida to generate unique id for this zone's cooling
|
||||
* devices
|
||||
* @lock: lock to protect thermal_instances list
|
||||
* @node: node in thermal_tz_list (in thermal_core.c)
|
||||
* @poll_queue: delayed work for polling
|
||||
* @notify_event: Last notification event
|
||||
* @suspended: thermal zone suspend indicator
|
||||
* @trips: array of struct thermal_trip objects
|
||||
*/
|
||||
struct thermal_zone_device {
|
||||
int id;
|
||||
char type[THERMAL_NAME_LENGTH];
|
||||
struct device device;
|
||||
struct completion removal;
|
||||
struct attribute_group trips_attribute_group;
|
||||
struct thermal_attr *trip_temp_attrs;
|
||||
struct thermal_attr *trip_type_attrs;
|
||||
struct thermal_attr *trip_hyst_attrs;
|
||||
enum thermal_device_mode mode;
|
||||
void *devdata;
|
||||
int num_trips;
|
||||
unsigned long passive_delay_jiffies;
|
||||
unsigned long polling_delay_jiffies;
|
||||
int temperature;
|
||||
int last_temperature;
|
||||
int emul_temperature;
|
||||
int passive;
|
||||
int prev_low_trip;
|
||||
int prev_high_trip;
|
||||
atomic_t need_update;
|
||||
struct thermal_zone_device_ops ops;
|
||||
struct thermal_zone_params *tzp;
|
||||
struct thermal_governor *governor;
|
||||
void *governor_data;
|
||||
struct list_head thermal_instances;
|
||||
struct ida ida;
|
||||
struct mutex lock;
|
||||
struct list_head node;
|
||||
struct delayed_work poll_queue;
|
||||
enum thermal_notify_event notify_event;
|
||||
bool suspended;
|
||||
#ifdef CONFIG_THERMAL_DEBUGFS
|
||||
struct thermal_debugfs *debugfs;
|
||||
#endif
|
||||
struct thermal_trip trips[] __counted_by(num_trips);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct thermal_governor - structure that holds thermal governor information
|
||||
* @name: name of the governor
|
||||
* @bind_to_tz: callback called when binding to a thermal zone. If it
|
||||
* returns 0, the governor is bound to the thermal zone,
|
||||
* otherwise it fails.
|
||||
* @unbind_from_tz: callback called when a governor is unbound from a
|
||||
* thermal zone.
|
||||
* @throttle: callback called for every trip point even if temperature is
|
||||
* below the trip point temperature
|
||||
* @update_tz: callback called when thermal zone internals have changed, e.g.
|
||||
* thermal cooling instance was added/removed
|
||||
* @governor_list: node in thermal_governor_list (in thermal_core.c)
|
||||
*/
|
||||
struct thermal_governor {
|
||||
const char *name;
|
||||
int (*bind_to_tz)(struct thermal_zone_device *tz);
|
||||
void (*unbind_from_tz)(struct thermal_zone_device *tz);
|
||||
int (*throttle)(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip);
|
||||
void (*update_tz)(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event reason);
|
||||
struct list_head governor_list;
|
||||
};
|
||||
|
||||
/* Structure to define Thermal Zone parameters */
|
||||
struct thermal_zone_params {
|
||||
const char *governor_name;
|
||||
|
Loading…
Reference in New Issue
Block a user