- Remove duplicate error message for the amlogic driver (Tang Bin)
- Fix spellos in comments for the tegra and sun8i (Bhaskar Chowdhury) - Add the missing fifth node on the rcar_gen3 sensor (Niklas Söderlund) - Remove duplicate include in ti-bandgap (Zhang Yunkai) - Assign error code in the error path in the function thermal_of_populate_bind_params() (Jia-Ju Bai) - Fix spelling mistake in a comment 'disabed' -> 'disabled' (Colin Ian King) - Use the device name instead of auto-numbering for a better identification of the cooling device (Daniel Lezcano) - Improve a bit the division accuracy in the power allocator governor (Jeson Gao) - Enable the missing third sensor on msm8976 (Konrad Dybcio) - Add QCom tsens driver co-maintainer (Thara Gopinath) - Fix memory leak and use after free errors in the core code (Daniel Lezcano) - Add the MDM9607 compatible bindings (Konrad Dybcio) - Fix trivial spello in the copyright name for Hisilicon (Hao Fang) - Fix negative index array access when converting the frequency to power in the energy model (Brian-sy Yang) - Add support for Gen2 new PMIC support for Qcom SPMI (David Collins) - Update maintainer file for CPU cooling device section (Lukasz Luba) - Fix missing put_device on error in the Qcom tsens driver (Guangqing Zhu) - Add compatible DT binding for sm8350 (Robert Foss) - Add support for the MDM9607's tsens driver (Konrad Dybcio) - Remove duplicate error messages in thermal_mmio and the bcm2835 driver (Ruiqi Gong) - Add the Thermal Temperature Cooling driver (Zhang Rui) - Remove duplicate error messages in the Hisilicon sensor driver (Ye Bin) - Use the devm_platform_ioremap_resource_byname() function instead of a couple of corresponding calls (dingsenjie) - Sort the headers alphabetically in the ti-bandgap driver (Zhen Lei) - Add missing property in the DT thermal sensor binding (Rafał Miłecki) - Remove dead code in the ti-bandgap sensor driver (Lin Ruizhe) - Convert the BRCM DT bindings to the yaml schema (Rafał Miłecki) - Replace the thermal_notify_framework() call by a call to the thermal_zone_device_update() function. Remove the function as well as the corresponding documentation (Thara Gopinath) - Add support for the ipq8064-tsens sensor along with a set of cleanups and code preparation (Ansuel Smith) - Add a lockless __thermal_cdev_update() function to improve the locking scheme in the core code and governors (Lukasz Luba) - Fix multiple cooling device notification changes (Lukasz Luba) - Remove unneeded variable initialization (Colin Ian King) -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAmCRqDIACgkQqDIjiipP 6E8O2Qf5AQvSVoN9WYRBLo1+a4mkGsJ/wHQMEsOA4FVHft5/QVkRtpMNbSiyq00O YTpNuoBqiYm/tSTyzK/5Oh+0ucgm/ef4c4dTyPjZYw2GB+3rYNRAXdX/tB6Ggjl/ oUArUCoSQZjOU6Y573B05rcHp1PVM/XL9LgD1uX76tXA1MaGvsyC0cyPRAdOANke W83BWI0XMhv8B1bZwHVB2Oft5x6HhqWBl3HKbNOmPEMtwkqqBCFAqB0wNEH88ZTf 2hyBjBoZQHdMkJsC0piMvIyAjHZiIjQB47VWz31EvKB3/E28xCqRqPViPq9QbrA5 got0+oDbxI96T024ndXRomc0SSxZnw== =5THg -----END PGP SIGNATURE----- Merge tag 'thermal-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux Pull thermal updates from Daniel Lezcano: - Remove duplicate error message for the amlogic driver (Tang Bin) - Fix spellos in comments for the tegra and sun8i (Bhaskar Chowdhury) - Add the missing fifth node on the rcar_gen3 sensor (Niklas Söderlund) - Remove duplicate include in ti-bandgap (Zhang Yunkai) - Assign error code in the error path in the function thermal_of_populate_bind_params() (Jia-Ju Bai) - Fix spelling mistake in a comment 'disabed' -> 'disabled' (Colin Ian King) - Use the device name instead of auto-numbering for a better identification of the cooling device (Daniel Lezcano) - Improve a bit the division accuracy in the power allocator governor (Jeson Gao) - Enable the missing third sensor on msm8976 (Konrad Dybcio) - Add QCom tsens driver co-maintainer (Thara Gopinath) - Fix memory leak and use after free errors in the core code (Daniel Lezcano) - Add the MDM9607 compatible bindings (Konrad Dybcio) - Fix trivial spello in the copyright name for Hisilicon (Hao Fang) - Fix negative index array access when converting the frequency to power in the energy model (Brian-sy Yang) - Add support for Gen2 new PMIC support for Qcom SPMI (David Collins) - Update maintainer file for CPU cooling device section (Lukasz Luba) - Fix missing put_device on error in the Qcom tsens driver (Guangqing Zhu) - Add compatible DT binding for sm8350 (Robert Foss) - Add support for the MDM9607's tsens driver (Konrad Dybcio) - Remove duplicate error messages in thermal_mmio and the bcm2835 driver (Ruiqi Gong) - Add the Thermal Temperature Cooling driver (Zhang Rui) - Remove duplicate error messages in the Hisilicon sensor driver (Ye Bin) - Use the devm_platform_ioremap_resource_byname() function instead of a couple of corresponding calls (dingsenjie) - Sort the headers alphabetically in the ti-bandgap driver (Zhen Lei) - Add missing property in the DT thermal sensor binding (Rafał Miłecki) - Remove dead code in the ti-bandgap sensor driver (Lin Ruizhe) - Convert the BRCM DT bindings to the yaml schema (Rafał Miłecki) - Replace the thermal_notify_framework() call by a call to the thermal_zone_device_update() function. Remove the function as well as the corresponding documentation (Thara Gopinath) - Add support for the ipq8064-tsens sensor along with a set of cleanups and code preparation (Ansuel Smith) - Add a lockless __thermal_cdev_update() function to improve the locking scheme in the core code and governors (Lukasz Luba) - Fix multiple cooling device notification changes (Lukasz Luba) - Remove unneeded variable initialization (Colin Ian King) * tag 'thermal-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (55 commits) thermal/drivers/mtk_thermal: Remove redundant initializations of several variables thermal/core/power allocator: Use the lockless __thermal_cdev_update() function thermal/core/fair share: Use the lockless __thermal_cdev_update() function thermal/core/fair share: Lock the thermal zone while looping over instances thermal/core/power_allocator: Update once cooling devices when temp is low thermal/core/power_allocator: Maintain the device statistics from going stale thermal/core: Create a helper __thermal_cdev_update() without a lock dt-bindings: thermal: tsens: Document ipq8064 bindings thermal/drivers/tsens: Add support for ipq8064-tsens thermal/drivers/tsens: Drop unused define for msm8960 thermal/drivers/tsens: Replace custom 8960 apis with generic apis thermal/drivers/tsens: Fix bug in sensor enable for msm8960 thermal/drivers/tsens: Use init_common for msm8960 thermal/drivers/tsens: Add VER_0 tsens version thermal/drivers/tsens: Convert msm8960 to reg_field thermal/drivers/tsens: Don't hardcode sensor slope Documentation: driver-api: thermal: Remove thermal_notify_framework from documentation thermal/core: Remove thermal_notify_framework iwlwifi: mvm: tt: Replace thermal_notify_framework dt-bindings: thermal: brcm,ns-thermal: Convert to the json-schema ...
This commit is contained in:
commit
583f2bcf86
@ -1,37 +0,0 @@
|
||||
* Broadcom Northstar Thermal
|
||||
|
||||
This binding describes thermal sensor that is part of Northstar's DMU (Device
|
||||
Management Unit).
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be "brcm,ns-thermal"
|
||||
- reg : iomem address range of PVTMON registers
|
||||
- #thermal-sensor-cells : Should be <0>
|
||||
|
||||
Example:
|
||||
|
||||
thermal: thermal@1800c2c0 {
|
||||
compatible = "brcm,ns-thermal";
|
||||
reg = <0x1800c2c0 0x10>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
cpu_thermal: cpu-thermal {
|
||||
polling-delay-passive = <0>;
|
||||
polling-delay = <1000>;
|
||||
coefficients = <(-556) 418000>;
|
||||
thermal-sensors = <&thermal>;
|
||||
|
||||
trips {
|
||||
cpu-crit {
|
||||
temperature = <125000>;
|
||||
hysteresis = <0>;
|
||||
type = "critical";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/brcm,ns-thermal.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom Northstar Thermal
|
||||
|
||||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
description:
|
||||
Thermal sensor that is part of Northstar's DMU (Device Management Unit).
|
||||
|
||||
allOf:
|
||||
- $ref: thermal-sensor.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,ns-thermal
|
||||
|
||||
reg:
|
||||
description: PVTMON registers range
|
||||
maxItems: 1
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 0
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
thermal: thermal@1800c2c0 {
|
||||
compatible = "brcm,ns-thermal";
|
||||
reg = <0x1800c2c0 0x10>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
cpu-thermal {
|
||||
polling-delay-passive = <0>;
|
||||
polling-delay = <1000>;
|
||||
coefficients = <(-556) 418000>;
|
||||
thermal-sensors = <&thermal>;
|
||||
|
||||
trips {
|
||||
cpu-crit {
|
||||
temperature = <125000>;
|
||||
hysteresis = <0>;
|
||||
type = "critical";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
};
|
||||
};
|
||||
};
|
@ -19,9 +19,15 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: msm9860 TSENS based
|
||||
items:
|
||||
- enum:
|
||||
- qcom,ipq8064-tsens
|
||||
|
||||
- description: v0.1 of TSENS
|
||||
items:
|
||||
- enum:
|
||||
- qcom,mdm9607-tsens
|
||||
- qcom,msm8916-tsens
|
||||
- qcom,msm8939-tsens
|
||||
- qcom,msm8974-tsens
|
||||
@ -43,6 +49,7 @@ properties:
|
||||
- qcom,sdm845-tsens
|
||||
- qcom,sm8150-tsens
|
||||
- qcom,sm8250-tsens
|
||||
- qcom,sm8350-tsens
|
||||
- const: qcom,tsens-v2
|
||||
|
||||
reg:
|
||||
@ -73,7 +80,9 @@ properties:
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: calib
|
||||
- const: calib_sel
|
||||
- enum:
|
||||
- calib_backup
|
||||
- calib_sel
|
||||
|
||||
"#qcom,sensors":
|
||||
description:
|
||||
@ -88,12 +97,21 @@ properties:
|
||||
Number of cells required to uniquely identify the thermal sensors. Since
|
||||
we have multiple sensors this is set to 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- "#thermal-sensor-cells"
|
||||
- "#qcom,sensors"
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq8064-tsens
|
||||
- qcom,mdm9607-tsens
|
||||
- qcom,msm8916-tsens
|
||||
- qcom,msm8974-tsens
|
||||
- qcom,msm8976-tsens
|
||||
@ -114,17 +132,42 @@ allOf:
|
||||
interrupt-names:
|
||||
minItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,tsens-v0_1
|
||||
- qcom,tsens-v1
|
||||
- qcom,tsens-v2
|
||||
|
||||
then:
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#qcom,sensors"
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
// Example msm9860 based SoC (ipq8064):
|
||||
gcc: clock-controller {
|
||||
|
||||
/* ... */
|
||||
|
||||
tsens: thermal-sensor {
|
||||
compatible = "qcom,ipq8064-tsens";
|
||||
|
||||
nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>;
|
||||
nvmem-cell-names = "calib", "calib_backup";
|
||||
interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "uplow";
|
||||
|
||||
#qcom,sensors = <11>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
// Example 1 (legacy: for pre v1 IP):
|
||||
|
@ -28,14 +28,7 @@ properties:
|
||||
- renesas,r8a77980-thermal # R-Car V3H
|
||||
- renesas,r8a779a0-thermal # R-Car V3U
|
||||
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: TSC1 registers
|
||||
- description: TSC2 registers
|
||||
- description: TSC3 registers
|
||||
- description: TSC4 registers
|
||||
reg: true
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
@ -71,8 +64,25 @@ if:
|
||||
enum:
|
||||
- renesas,r8a779a0-thermal
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
items:
|
||||
- description: TSC1 registers
|
||||
- description: TSC2 registers
|
||||
- description: TSC3 registers
|
||||
required:
|
||||
- interrupts
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- description: TSC0 registers
|
||||
- description: TSC1 registers
|
||||
- description: TSC2 registers
|
||||
- description: TSC3 registers
|
||||
- description: TSC4 registers
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -111,3 +121,20 @@ examples:
|
||||
};
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a779a0-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a779a0-sysc.h>
|
||||
|
||||
tsc_r8a779a0: thermal@e6190000 {
|
||||
compatible = "renesas,r8a779a0-thermal";
|
||||
reg = <0xe6190000 0x200>,
|
||||
<0xe6198000 0x200>,
|
||||
<0xe61a0000 0x200>,
|
||||
<0xe61a8000 0x200>,
|
||||
<0xe61b0000 0x200>;
|
||||
clocks = <&cpg CPG_MOD 919>;
|
||||
power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 919>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
@ -36,6 +36,9 @@ properties:
|
||||
containing several internal sensors.
|
||||
enum: [0, 1]
|
||||
|
||||
required:
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
|
@ -730,17 +730,7 @@ This function returns the thermal_instance corresponding to a given
|
||||
{thermal_zone, cooling_device, trip_point} combination. Returns NULL
|
||||
if such an instance does not exist.
|
||||
|
||||
4.3. thermal_notify_framework
|
||||
-----------------------------
|
||||
|
||||
This function handles the trip events from sensor drivers. It starts
|
||||
throttling the cooling devices according to the policy configured.
|
||||
For CRITICAL and HOT trip points, this notifies the respective drivers,
|
||||
and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
|
||||
The throttling policy is based on the configured platform data; if no
|
||||
platform data is provided, this uses the step_wise throttling policy.
|
||||
|
||||
4.4. thermal_cdev_update
|
||||
4.3. thermal_cdev_update
|
||||
------------------------
|
||||
|
||||
This function serves as an arbitrator to set the state of a cooling
|
||||
|
@ -15197,6 +15197,7 @@ F: include/linux/if_rmnet.h
|
||||
|
||||
QUALCOMM TSENS THERMAL DRIVER
|
||||
M: Amit Kucheria <amitk@kernel.org>
|
||||
M: Thara Gopinath <thara.gopinath@linaro.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
@ -18101,7 +18102,7 @@ THERMAL/CPU_COOLING
|
||||
M: Amit Daniel Kachhap <amit.kachhap@gmail.com>
|
||||
M: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
M: Viresh Kumar <viresh.kumar@linaro.org>
|
||||
M: Javi Merino <javi.merino@kernel.org>
|
||||
R: Lukasz Luba <lukasz.luba@arm.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/driver-api/thermal/cpu-cooling-api.rst
|
||||
|
@ -132,7 +132,7 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
|
||||
/* Allow mlxsw thermal zone binding to an external cooling device */
|
||||
for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
|
||||
if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i],
|
||||
sizeof(cdev->type)))
|
||||
strlen(cdev->type)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -146,8 +146,8 @@ void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
||||
if (mvm->tz_device.tzone) {
|
||||
struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device;
|
||||
|
||||
thermal_notify_framework(tz_dev->tzone,
|
||||
tz_dev->fw_trips_index[ths_crossed]);
|
||||
thermal_zone_device_update(tz_dev->tzone,
|
||||
THERMAL_TRIP_VIOLATED);
|
||||
}
|
||||
#endif /* CONFIG_THERMAL */
|
||||
}
|
||||
|
@ -254,10 +254,8 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base)) {
|
||||
dev_err(dev, "failed to get io address\n");
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
}
|
||||
|
||||
pdata->regmap = devm_regmap_init_mmio(dev, base,
|
||||
pdata->data->regmap_config);
|
||||
|
@ -184,7 +184,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
|
||||
data->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(data->regs)) {
|
||||
err = PTR_ERR(data->regs);
|
||||
dev_err(&pdev->dev, "Could not get registers: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,10 @@
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/energy_model.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/slab.h>
|
||||
@ -50,8 +50,6 @@ struct time_in_idle {
|
||||
|
||||
/**
|
||||
* struct cpufreq_cooling_device - data for cooling device with cpufreq
|
||||
* @id: unique integer value corresponding to each cpufreq_cooling_device
|
||||
* registered.
|
||||
* @last_load: load measured by the latest call to cpufreq_get_requested_power()
|
||||
* @cpufreq_state: integer value representing the current state of cpufreq
|
||||
* cooling devices.
|
||||
@ -61,7 +59,6 @@ struct time_in_idle {
|
||||
* @cdev: thermal_cooling_device pointer to keep track of the
|
||||
* registered cooling device.
|
||||
* @policy: cpufreq policy.
|
||||
* @node: list_head to link all cpufreq_cooling_device together.
|
||||
* @idle_time: idle time stats
|
||||
* @qos_req: PM QoS contraint to apply
|
||||
*
|
||||
@ -69,23 +66,17 @@ struct time_in_idle {
|
||||
* cpufreq_cooling_device.
|
||||
*/
|
||||
struct cpufreq_cooling_device {
|
||||
int id;
|
||||
u32 last_load;
|
||||
unsigned int cpufreq_state;
|
||||
unsigned int max_level;
|
||||
struct em_perf_domain *em;
|
||||
struct cpufreq_policy *policy;
|
||||
struct list_head node;
|
||||
#ifndef CONFIG_SMP
|
||||
struct time_in_idle *idle_time;
|
||||
#endif
|
||||
struct freq_qos_request qos_req;
|
||||
};
|
||||
|
||||
static DEFINE_IDA(cpufreq_ida);
|
||||
static DEFINE_MUTEX(cooling_list_lock);
|
||||
static LIST_HEAD(cpufreq_cdev_list);
|
||||
|
||||
#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
|
||||
/**
|
||||
* get_level: Find the level for a particular frequency
|
||||
@ -125,7 +116,7 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = cpufreq_cdev->max_level; i >= 0; i--) {
|
||||
for (i = cpufreq_cdev->max_level; i > 0; i--) {
|
||||
if (power >= cpufreq_cdev->em->table[i].power)
|
||||
break;
|
||||
}
|
||||
@ -528,11 +519,11 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct cpufreq_cooling_device *cpufreq_cdev;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
unsigned int i;
|
||||
struct device *dev;
|
||||
int ret;
|
||||
struct thermal_cooling_device_ops *cooling_ops;
|
||||
char *name;
|
||||
|
||||
dev = get_cpu_device(policy->cpu);
|
||||
if (unlikely(!dev)) {
|
||||
@ -567,16 +558,6 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||
/* max_level is an index, not a counter */
|
||||
cpufreq_cdev->max_level = i - 1;
|
||||
|
||||
ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
cdev = ERR_PTR(ret);
|
||||
goto free_idle_time;
|
||||
}
|
||||
cpufreq_cdev->id = ret;
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
|
||||
cpufreq_cdev->id);
|
||||
|
||||
cooling_ops = &cpufreq_cooling_ops;
|
||||
|
||||
#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
|
||||
@ -591,7 +572,7 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||
pr_err("%s: unsorted frequency tables are not supported\n",
|
||||
__func__);
|
||||
cdev = ERR_PTR(-EINVAL);
|
||||
goto remove_ida;
|
||||
goto free_idle_time;
|
||||
}
|
||||
|
||||
ret = freq_qos_add_request(&policy->constraints,
|
||||
@ -601,24 +582,25 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||
pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
|
||||
ret);
|
||||
cdev = ERR_PTR(ret);
|
||||
goto remove_ida;
|
||||
goto free_idle_time;
|
||||
}
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev,
|
||||
cooling_ops);
|
||||
if (IS_ERR(cdev))
|
||||
cdev = ERR_PTR(-ENOMEM);
|
||||
name = kasprintf(GFP_KERNEL, "cpufreq-%s", dev_name(dev));
|
||||
if (!name)
|
||||
goto remove_qos_req;
|
||||
|
||||
mutex_lock(&cooling_list_lock);
|
||||
list_add(&cpufreq_cdev->node, &cpufreq_cdev_list);
|
||||
mutex_unlock(&cooling_list_lock);
|
||||
cdev = thermal_of_cooling_device_register(np, name, cpufreq_cdev,
|
||||
cooling_ops);
|
||||
kfree(name);
|
||||
|
||||
if (IS_ERR(cdev))
|
||||
goto remove_qos_req;
|
||||
|
||||
return cdev;
|
||||
|
||||
remove_qos_req:
|
||||
freq_qos_remove_request(&cpufreq_cdev->qos_req);
|
||||
remove_ida:
|
||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||
free_idle_time:
|
||||
free_idle_time(cpufreq_cdev);
|
||||
free_cdev:
|
||||
@ -706,13 +688,8 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
|
||||
cpufreq_cdev = cdev->devdata;
|
||||
|
||||
mutex_lock(&cooling_list_lock);
|
||||
list_del(&cpufreq_cdev->node);
|
||||
mutex_unlock(&cooling_list_lock);
|
||||
|
||||
thermal_cooling_device_unregister(cdev);
|
||||
freq_qos_remove_request(&cpufreq_cdev->qos_req);
|
||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||
free_idle_time(cpufreq_cdev);
|
||||
kfree(cpufreq_cdev);
|
||||
}
|
||||
|
@ -9,9 +9,9 @@
|
||||
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/idle_inject.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/thermal.h>
|
||||
@ -26,8 +26,6 @@ struct cpuidle_cooling_device {
|
||||
unsigned long state;
|
||||
};
|
||||
|
||||
static DEFINE_IDA(cpuidle_ida);
|
||||
|
||||
/**
|
||||
* cpuidle_cooling_runtime - Running time computation
|
||||
* @idle_duration_us: CPU idle time to inject in microseconds
|
||||
@ -174,10 +172,11 @@ static int __cpuidle_cooling_register(struct device_node *np,
|
||||
struct idle_inject_device *ii_dev;
|
||||
struct cpuidle_cooling_device *idle_cdev;
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct device *dev;
|
||||
unsigned int idle_duration_us = TICK_USEC;
|
||||
unsigned int latency_us = UINT_MAX;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
int id, ret;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL);
|
||||
if (!idle_cdev) {
|
||||
@ -185,16 +184,10 @@ static int __cpuidle_cooling_register(struct device_node *np,
|
||||
goto out;
|
||||
}
|
||||
|
||||
id = ida_simple_get(&cpuidle_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
ret = id;
|
||||
goto out_kfree;
|
||||
}
|
||||
|
||||
ii_dev = idle_inject_register(drv->cpumask);
|
||||
if (!ii_dev) {
|
||||
ret = -EINVAL;
|
||||
goto out_id;
|
||||
goto out_kfree;
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "duration-us", &idle_duration_us);
|
||||
@ -205,24 +198,32 @@ static int __cpuidle_cooling_register(struct device_node *np,
|
||||
|
||||
idle_cdev->ii_dev = ii_dev;
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-idle-%d", id);
|
||||
dev = get_cpu_device(cpumask_first(drv->cpumask));
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, dev_name, idle_cdev,
|
||||
&cpuidle_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
name = kasprintf(GFP_KERNEL, "idle-%s", dev_name(dev));
|
||||
if (!name) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unregister;
|
||||
}
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, name, idle_cdev,
|
||||
&cpuidle_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
goto out_kfree_name;
|
||||
}
|
||||
|
||||
pr_debug("%s: Idle injection set with idle duration=%u, latency=%u\n",
|
||||
dev_name, idle_duration_us, latency_us);
|
||||
name, idle_duration_us, latency_us);
|
||||
|
||||
kfree(name);
|
||||
|
||||
return 0;
|
||||
|
||||
out_kfree_name:
|
||||
kfree(name);
|
||||
out_unregister:
|
||||
idle_inject_unregister(ii_dev);
|
||||
out_id:
|
||||
ida_simple_remove(&cpuidle_ida, id);
|
||||
out_kfree:
|
||||
kfree(idle_cdev);
|
||||
out:
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <linux/devfreq_cooling.h>
|
||||
#include <linux/energy_model.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/pm_qos.h>
|
||||
@ -25,11 +24,8 @@
|
||||
#define HZ_PER_KHZ 1000
|
||||
#define SCALE_ERROR_MITIGATION 100
|
||||
|
||||
static DEFINE_IDA(devfreq_ida);
|
||||
|
||||
/**
|
||||
* struct devfreq_cooling_device - Devfreq cooling device
|
||||
* @id: unique integer value corresponding to each
|
||||
* devfreq_cooling_device registered.
|
||||
* @cdev: Pointer to associated thermal cooling device.
|
||||
* @devfreq: Pointer to associated devfreq device.
|
||||
@ -51,7 +47,6 @@ static DEFINE_IDA(devfreq_ida);
|
||||
* @em_pd: Energy Model for the associated Devfreq device
|
||||
*/
|
||||
struct devfreq_cooling_device {
|
||||
int id;
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct devfreq *devfreq;
|
||||
unsigned long cooling_state;
|
||||
@ -363,7 +358,7 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct device *dev = df->dev.parent;
|
||||
struct devfreq_cooling_device *dfc;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
char *name;
|
||||
int err, num_opps;
|
||||
|
||||
dfc = kzalloc(sizeof(*dfc), GFP_KERNEL);
|
||||
@ -407,30 +402,27 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
|
||||
if (err < 0)
|
||||
goto free_table;
|
||||
|
||||
err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL);
|
||||
if (err < 0)
|
||||
err = -ENOMEM;
|
||||
name = kasprintf(GFP_KERNEL, "devfreq-%s", dev_name(dev));
|
||||
if (!name)
|
||||
goto remove_qos_req;
|
||||
|
||||
dfc->id = err;
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, dev_name, dfc,
|
||||
cdev = thermal_of_cooling_device_register(np, name, dfc,
|
||||
&devfreq_cooling_ops);
|
||||
kfree(name);
|
||||
|
||||
if (IS_ERR(cdev)) {
|
||||
err = PTR_ERR(cdev);
|
||||
dev_err(dev,
|
||||
"Failed to register devfreq cooling device (%d)\n",
|
||||
err);
|
||||
goto release_ida;
|
||||
goto remove_qos_req;
|
||||
}
|
||||
|
||||
dfc->cdev = cdev;
|
||||
|
||||
return cdev;
|
||||
|
||||
release_ida:
|
||||
ida_simple_remove(&devfreq_ida, dfc->id);
|
||||
remove_qos_req:
|
||||
dev_pm_qos_remove_request(&dfc->req_max_freq);
|
||||
free_table:
|
||||
@ -527,7 +519,6 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
dev = dfc->devfreq->dev.parent;
|
||||
|
||||
thermal_cooling_device_unregister(dfc->cdev);
|
||||
ida_simple_remove(&devfreq_ida, dfc->id);
|
||||
dev_pm_qos_remove_request(&dfc->req_max_freq);
|
||||
|
||||
em_dev_unregister_perf_domain(dev);
|
||||
|
@ -82,6 +82,8 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
|
||||
int total_instance = 0;
|
||||
int cur_trip_level = get_trip_level(tz);
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
|
||||
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
||||
if (instance->trip != trip)
|
||||
continue;
|
||||
@ -105,11 +107,12 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
|
||||
instance->target = get_target_state(tz, cdev, percentage,
|
||||
cur_trip_level);
|
||||
|
||||
mutex_lock(&instance->cdev->lock);
|
||||
instance->cdev->updated = false;
|
||||
mutex_unlock(&instance->cdev->lock);
|
||||
thermal_cdev_update(cdev);
|
||||
mutex_lock(&cdev->lock);
|
||||
__thermal_cdev_update(cdev);
|
||||
mutex_unlock(&cdev->lock);
|
||||
}
|
||||
|
||||
mutex_unlock(&tz->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -301,9 +301,8 @@ power_actor_set_power(struct thermal_cooling_device *cdev,
|
||||
|
||||
instance->target = clamp_val(state, instance->lower, instance->upper);
|
||||
mutex_lock(&cdev->lock);
|
||||
cdev->updated = false;
|
||||
__thermal_cdev_update(cdev);
|
||||
mutex_unlock(&cdev->lock);
|
||||
thermal_cdev_update(cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -374,9 +373,11 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
|
||||
*/
|
||||
extra_power = min(extra_power, capped_extra_power);
|
||||
if (capped_extra_power > 0)
|
||||
for (i = 0; i < num_actors; i++)
|
||||
granted_power[i] += (extra_actor_power[i] *
|
||||
extra_power) / capped_extra_power;
|
||||
for (i = 0; i < num_actors; i++) {
|
||||
u64 extra_range = (u64)extra_actor_power[i] * extra_power;
|
||||
granted_power[i] += DIV_ROUND_CLOSEST_ULL(extra_range,
|
||||
capped_extra_power);
|
||||
}
|
||||
}
|
||||
|
||||
static int allocate_power(struct thermal_zone_device *tz,
|
||||
@ -569,22 +570,33 @@ static void reset_pid_controller(struct power_allocator_params *params)
|
||||
params->prev_err = 0;
|
||||
}
|
||||
|
||||
static void allow_maximum_power(struct thermal_zone_device *tz)
|
||||
static void allow_maximum_power(struct thermal_zone_device *tz, bool update)
|
||||
{
|
||||
struct thermal_instance *instance;
|
||||
struct power_allocator_params *params = tz->governor_data;
|
||||
u32 req_power;
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
||||
struct thermal_cooling_device *cdev = instance->cdev;
|
||||
|
||||
if ((instance->trip != params->trip_max_desired_temperature) ||
|
||||
(!cdev_is_power_actor(instance->cdev)))
|
||||
continue;
|
||||
|
||||
instance->target = 0;
|
||||
mutex_lock(&instance->cdev->lock);
|
||||
instance->cdev->updated = false;
|
||||
/*
|
||||
* Call for updating the cooling devices local stats and avoid
|
||||
* periods of dozen of seconds when those have not been
|
||||
* maintained.
|
||||
*/
|
||||
cdev->ops->get_requested_power(cdev, &req_power);
|
||||
|
||||
if (update)
|
||||
__thermal_cdev_update(instance->cdev);
|
||||
|
||||
mutex_unlock(&instance->cdev->lock);
|
||||
thermal_cdev_update(instance->cdev);
|
||||
}
|
||||
mutex_unlock(&tz->lock);
|
||||
}
|
||||
@ -698,6 +710,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
|
||||
int ret;
|
||||
int switch_on_temp, control_temp;
|
||||
struct power_allocator_params *params = tz->governor_data;
|
||||
bool update;
|
||||
|
||||
/*
|
||||
* We get called for every trip point but we only need to do
|
||||
@ -709,9 +722,10 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
|
||||
ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
|
||||
&switch_on_temp);
|
||||
if (!ret && (tz->temperature < switch_on_temp)) {
|
||||
update = (tz->last_temperature >= switch_on_temp);
|
||||
tz->passive = 0;
|
||||
reset_pid_controller(params);
|
||||
allow_maximum_power(tz);
|
||||
allow_maximum_power(tz, update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hisilicon thermal sensor driver
|
||||
* HiSilicon thermal sensor driver
|
||||
*
|
||||
* Copyright (c) 2014-2015 Hisilicon Limited.
|
||||
* Copyright (c) 2014-2015 HiSilicon Limited.
|
||||
* Copyright (c) 2014-2015 Linaro Limited.
|
||||
*
|
||||
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
|
||||
@ -572,10 +572,8 @@ static int hisi_thermal_probe(struct platform_device *pdev)
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(data->regs)) {
|
||||
dev_err(dev, "failed to get io address\n");
|
||||
if (IS_ERR(data->regs))
|
||||
return PTR_ERR(data->regs);
|
||||
}
|
||||
|
||||
ret = data->ops->probe(data);
|
||||
if (ret)
|
||||
@ -672,5 +670,5 @@ module_platform_driver(hisi_thermal_driver);
|
||||
|
||||
MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
|
||||
MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
|
||||
MODULE_DESCRIPTION("Hisilicon thermal driver");
|
||||
MODULE_DESCRIPTION("HiSilicon thermal driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -79,3 +79,14 @@ config INTEL_PCH_THERMAL
|
||||
Enable this to support thermal reporting on certain intel PCHs.
|
||||
Thermal reporting device will provide temperature reading,
|
||||
programmable trip points and other information.
|
||||
|
||||
config INTEL_TCC_COOLING
|
||||
tristate "Intel TCC offset cooling Driver"
|
||||
depends on X86
|
||||
help
|
||||
Enable this to support system cooling by adjusting the effective TCC
|
||||
activation temperature via the TCC Offset register, which is widely
|
||||
supported on modern Intel platforms.
|
||||
Note that, on different platforms, the behavior might be different
|
||||
on how fast the setting takes effect, and how much the CPU frequency
|
||||
is reduced.
|
||||
|
@ -10,4 +10,5 @@ obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) += intel_quark_dts_thermal.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/
|
||||
obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
|
||||
obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
|
||||
obj-$(CONFIG_INTEL_TCC_COOLING) += intel_tcc_cooling.o
|
||||
obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
|
||||
|
129
drivers/thermal/intel/intel_tcc_cooling.c
Normal file
129
drivers/thermal/intel/intel_tcc_cooling.c
Normal file
@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* cooling device driver that activates the processor throttling by
|
||||
* programming the TCC Offset register.
|
||||
* Copyright (c) 2021, Intel Corporation.
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
|
||||
#define TCC_SHIFT 24
|
||||
#define TCC_MASK (0x3fULL<<24)
|
||||
#define TCC_PROGRAMMABLE BIT(30)
|
||||
|
||||
static struct thermal_cooling_device *tcc_cdev;
|
||||
|
||||
static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
|
||||
*state)
|
||||
{
|
||||
*state = TCC_MASK >> TCC_SHIFT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcc_offset_update(int tcc)
|
||||
{
|
||||
u64 val;
|
||||
int err;
|
||||
|
||||
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val &= ~TCC_MASK;
|
||||
val |= tcc << TCC_SHIFT;
|
||||
|
||||
err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
|
||||
*state)
|
||||
{
|
||||
u64 val;
|
||||
int err;
|
||||
|
||||
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*state = (val & TCC_MASK) >> TCC_SHIFT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
|
||||
state)
|
||||
{
|
||||
return tcc_offset_update(state);
|
||||
}
|
||||
|
||||
static const struct thermal_cooling_device_ops tcc_cooling_ops = {
|
||||
.get_max_state = tcc_get_max_state,
|
||||
.get_cur_state = tcc_get_cur_state,
|
||||
.set_cur_state = tcc_set_cur_state,
|
||||
};
|
||||
|
||||
static const struct x86_cpu_id tcc_ids[] __initconst = {
|
||||
X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
|
||||
|
||||
static int __init tcc_cooling_init(void)
|
||||
{
|
||||
int ret;
|
||||
u64 val;
|
||||
const struct x86_cpu_id *id;
|
||||
|
||||
int err;
|
||||
|
||||
id = x86_match_cpu(tcc_ids);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!(val & TCC_PROGRAMMABLE))
|
||||
return -ENODEV;
|
||||
|
||||
pr_info("Programmable TCC Offset detected\n");
|
||||
|
||||
tcc_cdev =
|
||||
thermal_cooling_device_register("TCC Offset", NULL,
|
||||
&tcc_cooling_ops);
|
||||
if (IS_ERR(tcc_cdev)) {
|
||||
ret = PTR_ERR(tcc_cdev);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(tcc_cooling_init)
|
||||
|
||||
static void __exit tcc_cooling_exit(void)
|
||||
{
|
||||
thermal_cooling_device_unregister(tcc_cdev);
|
||||
}
|
||||
|
||||
module_exit(tcc_cooling_exit)
|
||||
|
||||
MODULE_DESCRIPTION("TCC offset cooling device Driver");
|
||||
MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -573,12 +573,12 @@ static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
|
||||
|
||||
static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
|
||||
{
|
||||
s32 format_1 = 0;
|
||||
s32 format_2 = 0;
|
||||
s32 g_oe = 1;
|
||||
s32 g_gain = 1;
|
||||
s32 g_x_roomt = 0;
|
||||
s32 tmp = 0;
|
||||
s32 format_1;
|
||||
s32 format_2;
|
||||
s32 g_oe;
|
||||
s32 g_gain;
|
||||
s32 g_x_roomt;
|
||||
s32 tmp;
|
||||
|
||||
if (raw == 0)
|
||||
return 0;
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "../thermal_core.h"
|
||||
|
||||
#define QPNP_TM_REG_DIG_MAJOR 0x01
|
||||
#define QPNP_TM_REG_TYPE 0x04
|
||||
#define QPNP_TM_REG_SUBTYPE 0x05
|
||||
#define QPNP_TM_REG_STATUS 0x08
|
||||
@ -38,26 +39,30 @@
|
||||
|
||||
#define ALARM_CTRL_FORCE_ENABLE BIT(7)
|
||||
|
||||
/*
|
||||
* Trip point values based on threshold control
|
||||
* 0 = {105 C, 125 C, 145 C}
|
||||
* 1 = {110 C, 130 C, 150 C}
|
||||
* 2 = {115 C, 135 C, 155 C}
|
||||
* 3 = {120 C, 140 C, 160 C}
|
||||
*/
|
||||
#define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */
|
||||
#define TEMP_STAGE_HYSTERESIS 2000
|
||||
#define THRESH_COUNT 4
|
||||
#define STAGE_COUNT 3
|
||||
|
||||
/* Over-temperature trip point values in mC */
|
||||
static const long temp_map_gen1[THRESH_COUNT][STAGE_COUNT] = {
|
||||
{ 105000, 125000, 145000 },
|
||||
{ 110000, 130000, 150000 },
|
||||
{ 115000, 135000, 155000 },
|
||||
{ 120000, 140000, 160000 },
|
||||
};
|
||||
|
||||
static const long temp_map_gen2_v1[THRESH_COUNT][STAGE_COUNT] = {
|
||||
{ 90000, 110000, 140000 },
|
||||
{ 95000, 115000, 145000 },
|
||||
{ 100000, 120000, 150000 },
|
||||
{ 105000, 125000, 155000 },
|
||||
};
|
||||
|
||||
#define TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */
|
||||
#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
|
||||
|
||||
#define THRESH_MIN 0
|
||||
#define THRESH_MAX 3
|
||||
|
||||
/* Stage 2 Threshold Min: 125 C */
|
||||
#define STAGE2_THRESHOLD_MIN 125000
|
||||
/* Stage 2 Threshold Max: 140 C */
|
||||
#define STAGE2_THRESHOLD_MAX 140000
|
||||
#define TEMP_STAGE_HYSTERESIS 2000
|
||||
|
||||
/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */
|
||||
#define DEFAULT_TEMP 37000
|
||||
@ -77,6 +82,7 @@ struct qpnp_tm_chip {
|
||||
bool initialized;
|
||||
|
||||
struct iio_channel *adc;
|
||||
const long (*temp_map)[THRESH_COUNT][STAGE_COUNT];
|
||||
};
|
||||
|
||||
/* This array maps from GEN2 alarm state to GEN1 alarm stage */
|
||||
@ -100,6 +106,23 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)
|
||||
return regmap_write(chip->map, chip->base + addr, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* qpnp_tm_decode_temp() - return temperature in mC corresponding to the
|
||||
* specified over-temperature stage
|
||||
* @chip: Pointer to the qpnp_tm chip
|
||||
* @stage: Over-temperature stage
|
||||
*
|
||||
* Return: temperature in mC
|
||||
*/
|
||||
static long qpnp_tm_decode_temp(struct qpnp_tm_chip *chip, unsigned int stage)
|
||||
{
|
||||
if (!chip->temp_map || chip->thresh >= THRESH_COUNT || stage == 0 ||
|
||||
stage > STAGE_COUNT)
|
||||
return 0;
|
||||
|
||||
return (*chip->temp_map)[chip->thresh][stage - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* qpnp_tm_get_temp_stage() - return over-temperature stage
|
||||
* @chip: Pointer to the qpnp_tm chip
|
||||
@ -149,14 +172,12 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
|
||||
|
||||
if (stage_new > stage_old) {
|
||||
/* increasing stage, use lower bound */
|
||||
chip->temp = (stage_new - 1) * TEMP_STAGE_STEP +
|
||||
chip->thresh * TEMP_THRESH_STEP +
|
||||
TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
|
||||
chip->temp = qpnp_tm_decode_temp(chip, stage_new)
|
||||
+ TEMP_STAGE_HYSTERESIS;
|
||||
} else if (stage_new < stage_old) {
|
||||
/* decreasing stage, use upper bound */
|
||||
chip->temp = stage_new * TEMP_STAGE_STEP +
|
||||
chip->thresh * TEMP_THRESH_STEP -
|
||||
TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
|
||||
chip->temp = qpnp_tm_decode_temp(chip, stage_new + 1)
|
||||
- TEMP_STAGE_HYSTERESIS;
|
||||
}
|
||||
|
||||
chip->stage = stage;
|
||||
@ -199,26 +220,28 @@ static int qpnp_tm_get_temp(void *data, int *temp)
|
||||
static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
|
||||
int temp)
|
||||
{
|
||||
u8 reg;
|
||||
long stage2_threshold_min = (*chip->temp_map)[THRESH_MIN][1];
|
||||
long stage2_threshold_max = (*chip->temp_map)[THRESH_MAX][1];
|
||||
bool disable_s2_shutdown = false;
|
||||
u8 reg;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&chip->lock));
|
||||
|
||||
/*
|
||||
* Default: S2 and S3 shutdown enabled, thresholds at
|
||||
* 105C/125C/145C, monitoring at 25Hz
|
||||
* lowest threshold set, monitoring at 25Hz
|
||||
*/
|
||||
reg = SHUTDOWN_CTRL1_RATE_25HZ;
|
||||
|
||||
if (temp == THERMAL_TEMP_INVALID ||
|
||||
temp < STAGE2_THRESHOLD_MIN) {
|
||||
temp < stage2_threshold_min) {
|
||||
chip->thresh = THRESH_MIN;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (temp <= STAGE2_THRESHOLD_MAX) {
|
||||
if (temp <= stage2_threshold_max) {
|
||||
chip->thresh = THRESH_MAX -
|
||||
((STAGE2_THRESHOLD_MAX - temp) /
|
||||
((stage2_threshold_max - temp) /
|
||||
TEMP_THRESH_STEP);
|
||||
disable_s2_shutdown = true;
|
||||
} else {
|
||||
@ -326,9 +349,7 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)
|
||||
? chip->stage : alarm_state_map[chip->stage];
|
||||
|
||||
if (stage)
|
||||
chip->temp = chip->thresh * TEMP_THRESH_STEP +
|
||||
(stage - 1) * TEMP_STAGE_STEP +
|
||||
TEMP_THRESH_MIN;
|
||||
chip->temp = qpnp_tm_decode_temp(chip, stage);
|
||||
|
||||
crit_temp = qpnp_tm_get_critical_trip_temp(chip);
|
||||
ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp);
|
||||
@ -350,7 +371,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct qpnp_tm_chip *chip;
|
||||
struct device_node *node;
|
||||
u8 type, subtype;
|
||||
u8 type, subtype, dig_major;
|
||||
u32 res;
|
||||
int ret, irq;
|
||||
|
||||
@ -400,6 +421,12 @@ static int qpnp_tm_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_DIG_MAJOR, &dig_major);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "could not read dig_major\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1
|
||||
&& subtype != QPNP_TM_SUBTYPE_GEN2)) {
|
||||
dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
|
||||
@ -408,6 +435,10 @@ static int qpnp_tm_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
chip->subtype = subtype;
|
||||
if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 1)
|
||||
chip->temp_map = &temp_map_gen2_v1;
|
||||
else
|
||||
chip->temp_map = &temp_map_gen1;
|
||||
|
||||
/*
|
||||
* Register the sensor before initializing the hardware to be able to
|
||||
|
@ -10,8 +10,6 @@
|
||||
#include <linux/thermal.h>
|
||||
#include "tsens.h"
|
||||
|
||||
#define CAL_MDEGC 30000
|
||||
|
||||
#define CONFIG_ADDR 0x3640
|
||||
#define CONFIG_ADDR_8660 0x3620
|
||||
/* CONFIG_ADDR bitmasks */
|
||||
@ -21,40 +19,38 @@
|
||||
#define CONFIG_SHIFT_8660 28
|
||||
#define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660)
|
||||
|
||||
#define STATUS_CNTL_ADDR_8064 0x3660
|
||||
#define CNTL_ADDR 0x3620
|
||||
/* CNTL_ADDR bitmasks */
|
||||
#define EN BIT(0)
|
||||
#define SW_RST BIT(1)
|
||||
#define SENSOR0_EN BIT(3)
|
||||
|
||||
#define MEASURE_PERIOD BIT(18)
|
||||
#define SLP_CLK_ENA BIT(26)
|
||||
#define SLP_CLK_ENA_8660 BIT(24)
|
||||
#define MEASURE_PERIOD 1
|
||||
#define SENSOR0_SHIFT 3
|
||||
|
||||
/* INT_STATUS_ADDR bitmasks */
|
||||
#define MIN_STATUS_MASK BIT(0)
|
||||
#define LOWER_STATUS_CLR BIT(1)
|
||||
#define UPPER_STATUS_CLR BIT(2)
|
||||
#define MAX_STATUS_MASK BIT(3)
|
||||
|
||||
#define THRESHOLD_ADDR 0x3624
|
||||
/* THRESHOLD_ADDR bitmasks */
|
||||
#define THRESHOLD_MAX_LIMIT_SHIFT 24
|
||||
#define THRESHOLD_MIN_LIMIT_SHIFT 16
|
||||
#define THRESHOLD_UPPER_LIMIT_SHIFT 8
|
||||
#define THRESHOLD_LOWER_LIMIT_SHIFT 0
|
||||
|
||||
/* Initial temperature threshold values */
|
||||
#define LOWER_LIMIT_TH 0x50
|
||||
#define UPPER_LIMIT_TH 0xdf
|
||||
#define MIN_LIMIT_TH 0x0
|
||||
#define MAX_LIMIT_TH 0xff
|
||||
|
||||
#define S0_STATUS_ADDR 0x3628
|
||||
#define INT_STATUS_ADDR 0x363c
|
||||
#define TRDY_MASK BIT(7)
|
||||
#define TIMEOUT_US 100
|
||||
|
||||
#define S0_STATUS_OFF 0x3628
|
||||
#define S1_STATUS_OFF 0x362c
|
||||
#define S2_STATUS_OFF 0x3630
|
||||
#define S3_STATUS_OFF 0x3634
|
||||
#define S4_STATUS_OFF 0x3638
|
||||
#define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */
|
||||
#define S6_STATUS_OFF 0x3668
|
||||
#define S7_STATUS_OFF 0x366c
|
||||
#define S8_STATUS_OFF 0x3670
|
||||
#define S9_STATUS_OFF 0x3674
|
||||
#define S10_STATUS_OFF 0x3678
|
||||
|
||||
/* Original slope - 350 to compensate mC to C inaccuracy */
|
||||
static u32 tsens_msm8960_slope[] = {
|
||||
826, 826, 804, 826,
|
||||
761, 782, 782, 849,
|
||||
782, 849, 782
|
||||
};
|
||||
|
||||
static int suspend_8960(struct tsens_priv *priv)
|
||||
{
|
||||
@ -115,17 +111,34 @@ static int resume_8960(struct tsens_priv *priv)
|
||||
static int enable_8960(struct tsens_priv *priv, int id)
|
||||
{
|
||||
int ret;
|
||||
u32 reg, mask;
|
||||
u32 reg, mask = BIT(id);
|
||||
|
||||
ret = regmap_read(priv->tm_map, CNTL_ADDR, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mask = BIT(id + SENSOR0_SHIFT);
|
||||
/* HARDWARE BUG:
|
||||
* On platforms with more than 6 sensors, all remaining sensors
|
||||
* must be enabled together, otherwise undefined results are expected.
|
||||
* (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver,
|
||||
* all the sensors are enabled in one step hence this bug is not
|
||||
* triggered.
|
||||
*/
|
||||
if (id > 5)
|
||||
mask = GENMASK(10, 6);
|
||||
|
||||
mask <<= SENSOR0_SHIFT;
|
||||
|
||||
/* Sensors already enabled. Skip. */
|
||||
if ((reg & mask) == mask)
|
||||
return 0;
|
||||
|
||||
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg |= MEASURE_PERIOD;
|
||||
|
||||
if (priv->num_sensors > 1)
|
||||
reg |= mask | SLP_CLK_ENA | EN;
|
||||
else
|
||||
@ -162,63 +175,11 @@ static void disable_8960(struct tsens_priv *priv)
|
||||
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||
}
|
||||
|
||||
static int init_8960(struct tsens_priv *priv)
|
||||
{
|
||||
int ret, i;
|
||||
u32 reg_cntl;
|
||||
|
||||
priv->tm_map = dev_get_regmap(priv->dev, NULL);
|
||||
if (!priv->tm_map)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* The status registers for each sensor are discontiguous
|
||||
* because some SoCs have 5 sensors while others have more
|
||||
* but the control registers stay in the same place, i.e
|
||||
* directly after the first 5 status registers.
|
||||
*/
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
if (i >= 5)
|
||||
priv->sensor[i].status = S0_STATUS_ADDR + 40;
|
||||
priv->sensor[i].status += i * 4;
|
||||
}
|
||||
|
||||
reg_cntl = SW_RST;
|
||||
ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->num_sensors > 1) {
|
||||
reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
|
||||
reg_cntl &= ~SW_RST;
|
||||
ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
|
||||
CONFIG_MASK, CONFIG);
|
||||
} else {
|
||||
reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
|
||||
reg_cntl &= ~CONFIG_MASK_8660;
|
||||
reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
|
||||
}
|
||||
|
||||
reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
|
||||
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg_cntl |= EN;
|
||||
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int calibrate_8960(struct tsens_priv *priv)
|
||||
{
|
||||
int i;
|
||||
char *data;
|
||||
|
||||
ssize_t num_read = priv->num_sensors;
|
||||
struct tsens_sensor *s = priv->sensor;
|
||||
u32 p1[11];
|
||||
|
||||
data = qfprom_read(priv->dev, "calib");
|
||||
if (IS_ERR(data))
|
||||
@ -226,60 +187,96 @@ static int calibrate_8960(struct tsens_priv *priv)
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
for (i = 0; i < num_read; i++, s++)
|
||||
s->offset = data[i];
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
p1[i] = data[i];
|
||||
priv->sensor[i].slope = tsens_msm8960_slope[i];
|
||||
}
|
||||
|
||||
compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Temperature on y axis and ADC-code on x-axis */
|
||||
static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
|
||||
{
|
||||
int slope, offset;
|
||||
static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
|
||||
/* ----- SROT ------ */
|
||||
/* No VERSION information */
|
||||
|
||||
slope = thermal_zone_get_slope(s->tzd);
|
||||
offset = CAL_MDEGC - slope * s->offset;
|
||||
/* CNTL */
|
||||
[TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0),
|
||||
[TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1),
|
||||
/* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
|
||||
[SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7),
|
||||
|
||||
return adc_code * slope + offset;
|
||||
}
|
||||
/* ----- TM ------ */
|
||||
/* INTERRUPT ENABLE */
|
||||
/* NO INTERRUPT ENABLE */
|
||||
|
||||
static int get_temp_8960(const struct tsens_sensor *s, int *temp)
|
||||
{
|
||||
int ret;
|
||||
u32 code, trdy;
|
||||
struct tsens_priv *priv = s->priv;
|
||||
unsigned long timeout;
|
||||
/* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
|
||||
[LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7),
|
||||
[UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15),
|
||||
/* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
|
||||
* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp
|
||||
* MIN_THRESH_0 -> CRIT_THRESH_1
|
||||
* MAX_THRESH_0 -> CRIT_THRESH_0
|
||||
*/
|
||||
[CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23),
|
||||
[CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31),
|
||||
|
||||
timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
|
||||
do {
|
||||
ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(trdy & TRDY_MASK))
|
||||
continue;
|
||||
ret = regmap_read(priv->tm_map, s->status, &code);
|
||||
if (ret)
|
||||
return ret;
|
||||
*temp = code_to_mdegC(code, s);
|
||||
return 0;
|
||||
} while (time_before(jiffies, timeout));
|
||||
/* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
|
||||
/* 1 == clear, 0 == normal operation */
|
||||
[LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9),
|
||||
[UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10),
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
/* NO CRITICAL INTERRUPT SUPPORT on 8960 */
|
||||
|
||||
/* Sn_STATUS */
|
||||
[LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7),
|
||||
[LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7),
|
||||
|
||||
/* No VALID field on 8960 */
|
||||
/* TSENS_INT_STATUS bits: 1 == threshold violated */
|
||||
[MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
|
||||
[LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
|
||||
[UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
|
||||
/* No CRITICAL field on 8960 */
|
||||
[MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
|
||||
|
||||
/* TRDY: 1=ready, 0=in progress */
|
||||
[TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
|
||||
};
|
||||
|
||||
static const struct tsens_ops ops_8960 = {
|
||||
.init = init_8960,
|
||||
.init = init_common,
|
||||
.calibrate = calibrate_8960,
|
||||
.get_temp = get_temp_8960,
|
||||
.get_temp = get_temp_common,
|
||||
.enable = enable_8960,
|
||||
.disable = disable_8960,
|
||||
.suspend = suspend_8960,
|
||||
.resume = resume_8960,
|
||||
};
|
||||
|
||||
static struct tsens_features tsens_8960_feat = {
|
||||
.ver_major = VER_0,
|
||||
.crit_int = 0,
|
||||
.adc = 1,
|
||||
.srot_split = 0,
|
||||
.max_sensors = 11,
|
||||
};
|
||||
|
||||
struct tsens_plat_data data_8960 = {
|
||||
.num_sensors = 11,
|
||||
.ops = &ops_8960,
|
||||
.feat = &tsens_8960_feat,
|
||||
.fields = tsens_8960_regfields,
|
||||
};
|
||||
|
@ -190,6 +190,39 @@
|
||||
|
||||
#define BIT_APPEND 0x3
|
||||
|
||||
/* eeprom layout data for mdm9607 */
|
||||
#define MDM9607_BASE0_MASK 0x000000ff
|
||||
#define MDM9607_BASE1_MASK 0x000ff000
|
||||
#define MDM9607_BASE0_SHIFT 0
|
||||
#define MDM9607_BASE1_SHIFT 12
|
||||
|
||||
#define MDM9607_S0_P1_MASK 0x00003f00
|
||||
#define MDM9607_S1_P1_MASK 0x03f00000
|
||||
#define MDM9607_S2_P1_MASK 0x0000003f
|
||||
#define MDM9607_S3_P1_MASK 0x0003f000
|
||||
#define MDM9607_S4_P1_MASK 0x0000003f
|
||||
|
||||
#define MDM9607_S0_P2_MASK 0x000fc000
|
||||
#define MDM9607_S1_P2_MASK 0xfc000000
|
||||
#define MDM9607_S2_P2_MASK 0x00000fc0
|
||||
#define MDM9607_S3_P2_MASK 0x00fc0000
|
||||
#define MDM9607_S4_P2_MASK 0x00000fc0
|
||||
|
||||
#define MDM9607_S0_P1_SHIFT 8
|
||||
#define MDM9607_S1_P1_SHIFT 20
|
||||
#define MDM9607_S2_P1_SHIFT 0
|
||||
#define MDM9607_S3_P1_SHIFT 12
|
||||
#define MDM9607_S4_P1_SHIFT 0
|
||||
|
||||
#define MDM9607_S0_P2_SHIFT 14
|
||||
#define MDM9607_S1_P2_SHIFT 26
|
||||
#define MDM9607_S2_P2_SHIFT 6
|
||||
#define MDM9607_S3_P2_SHIFT 18
|
||||
#define MDM9607_S4_P2_SHIFT 6
|
||||
|
||||
#define MDM9607_CAL_SEL_MASK 0x00700000
|
||||
#define MDM9607_CAL_SEL_SHIFT 20
|
||||
|
||||
static int calibrate_8916(struct tsens_priv *priv)
|
||||
{
|
||||
int base0 = 0, base1 = 0, i;
|
||||
@ -452,7 +485,56 @@ static int calibrate_8974(struct tsens_priv *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* v0.1: 8916, 8939, 8974 */
|
||||
static int calibrate_9607(struct tsens_priv *priv)
|
||||
{
|
||||
int base, i;
|
||||
u32 p1[5], p2[5];
|
||||
int mode = 0;
|
||||
u32 *qfprom_cdata;
|
||||
|
||||
qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
|
||||
if (IS_ERR(qfprom_cdata))
|
||||
return PTR_ERR(qfprom_cdata);
|
||||
|
||||
mode = (qfprom_cdata[2] & MDM9607_CAL_SEL_MASK) >> MDM9607_CAL_SEL_SHIFT;
|
||||
dev_dbg(priv->dev, "calibration mode is %d\n", mode);
|
||||
|
||||
switch (mode) {
|
||||
case TWO_PT_CALIB:
|
||||
base = (qfprom_cdata[2] & MDM9607_BASE1_MASK) >> MDM9607_BASE1_SHIFT;
|
||||
p2[0] = (qfprom_cdata[0] & MDM9607_S0_P2_MASK) >> MDM9607_S0_P2_SHIFT;
|
||||
p2[1] = (qfprom_cdata[0] & MDM9607_S1_P2_MASK) >> MDM9607_S1_P2_SHIFT;
|
||||
p2[2] = (qfprom_cdata[1] & MDM9607_S2_P2_MASK) >> MDM9607_S2_P2_SHIFT;
|
||||
p2[3] = (qfprom_cdata[1] & MDM9607_S3_P2_MASK) >> MDM9607_S3_P2_SHIFT;
|
||||
p2[4] = (qfprom_cdata[2] & MDM9607_S4_P2_MASK) >> MDM9607_S4_P2_SHIFT;
|
||||
for (i = 0; i < priv->num_sensors; i++)
|
||||
p2[i] = ((base + p2[i]) << 2);
|
||||
fallthrough;
|
||||
case ONE_PT_CALIB2:
|
||||
base = (qfprom_cdata[0] & MDM9607_BASE0_MASK);
|
||||
p1[0] = (qfprom_cdata[0] & MDM9607_S0_P1_MASK) >> MDM9607_S0_P1_SHIFT;
|
||||
p1[1] = (qfprom_cdata[0] & MDM9607_S1_P1_MASK) >> MDM9607_S1_P1_SHIFT;
|
||||
p1[2] = (qfprom_cdata[1] & MDM9607_S2_P1_MASK) >> MDM9607_S2_P1_SHIFT;
|
||||
p1[3] = (qfprom_cdata[1] & MDM9607_S3_P1_MASK) >> MDM9607_S3_P1_SHIFT;
|
||||
p1[4] = (qfprom_cdata[2] & MDM9607_S4_P1_MASK) >> MDM9607_S4_P1_SHIFT;
|
||||
for (i = 0; i < priv->num_sensors; i++)
|
||||
p1[i] = ((base + p1[i]) << 2);
|
||||
break;
|
||||
default:
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
p1[i] = 500;
|
||||
p2[i] = 780;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
compute_intercept_slope(priv, p1, p2, mode);
|
||||
kfree(qfprom_cdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* v0.1: 8916, 8939, 8974, 9607 */
|
||||
|
||||
static struct tsens_features tsens_v0_1_feat = {
|
||||
.ver_major = VER_0_1,
|
||||
@ -540,3 +622,17 @@ struct tsens_plat_data data_8974 = {
|
||||
.feat = &tsens_v0_1_feat,
|
||||
.fields = tsens_v0_1_regfields,
|
||||
};
|
||||
|
||||
static const struct tsens_ops ops_9607 = {
|
||||
.init = init_common,
|
||||
.calibrate = calibrate_9607,
|
||||
.get_temp = get_temp_common,
|
||||
};
|
||||
|
||||
struct tsens_plat_data data_9607 = {
|
||||
.num_sensors = 5,
|
||||
.ops = &ops_9607,
|
||||
.hw_ids = (unsigned int []){ 0, 1, 2, 3, 4 },
|
||||
.feat = &tsens_v0_1_feat,
|
||||
.fields = tsens_v0_1_regfields,
|
||||
};
|
||||
|
@ -380,11 +380,11 @@ static const struct tsens_ops ops_8976 = {
|
||||
.get_temp = get_temp_tsens_valid,
|
||||
};
|
||||
|
||||
/* Valid for both MSM8956 and MSM8976. Sensor ID 3 is unused. */
|
||||
/* Valid for both MSM8956 and MSM8976. */
|
||||
struct tsens_plat_data data_8976 = {
|
||||
.num_sensors = 11,
|
||||
.ops = &ops_8976,
|
||||
.hw_ids = (unsigned int[]){0, 1, 2, 4, 5, 6, 7, 8, 9, 10},
|
||||
.hw_ids = (unsigned int[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
.feat = &tsens_v1_feat,
|
||||
.fields = tsens_v1_regfields,
|
||||
};
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -85,6 +86,7 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
|
||||
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
|
||||
__func__, i, p1[i], p2[i]);
|
||||
|
||||
if (!priv->sensor[i].slope)
|
||||
priv->sensor[i].slope = SLOPE_DEFAULT;
|
||||
if (mode == TWO_PT_CALIB) {
|
||||
/*
|
||||
@ -515,6 +517,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
|
||||
dev_dbg(priv->dev, "[%u] %s: no violation: %d\n",
|
||||
hw_id, __func__, temp);
|
||||
}
|
||||
|
||||
if (tsens_version(priv) < VER_0_1) {
|
||||
/* Constraint: There is only 1 interrupt control register for all
|
||||
* 11 temperature sensor. So monitoring more than 1 sensor based
|
||||
* on interrupts will yield inconsistent result. To overcome this
|
||||
* issue we will monitor only sensor 0 which is the master sensor.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -530,6 +541,13 @@ static int tsens_set_trips(void *_sensor, int low, int high)
|
||||
int high_val, low_val, cl_high, cl_low;
|
||||
u32 hw_id = s->hw_id;
|
||||
|
||||
if (tsens_version(priv) < VER_0_1) {
|
||||
/* Pre v0.1 IP had a single register for each type of interrupt
|
||||
* and thresholds
|
||||
*/
|
||||
hw_id = 0;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
|
||||
hw_id, __func__, low, high);
|
||||
|
||||
@ -584,6 +602,8 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
|
||||
u32 valid;
|
||||
int ret;
|
||||
|
||||
/* VER_0 doesn't have VALID bit */
|
||||
if (tsens_version(priv) >= VER_0_1) {
|
||||
ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -597,6 +617,7 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Valid bit is set, OK to read the temperature */
|
||||
*temp = tsens_hw_to_mC(s, temp_idx);
|
||||
@ -608,7 +629,18 @@ int get_temp_common(const struct tsens_sensor *s, int *temp)
|
||||
{
|
||||
struct tsens_priv *priv = s->priv;
|
||||
int hw_id = s->hw_id;
|
||||
int last_temp = 0, ret;
|
||||
int last_temp = 0, ret, trdy;
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
|
||||
do {
|
||||
if (tsens_version(priv) == VER_0) {
|
||||
ret = regmap_field_read(priv->rf[TRDY], &trdy);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!trdy)
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
|
||||
if (ret)
|
||||
@ -617,6 +649,9 @@ int get_temp_common(const struct tsens_sensor *s, int *temp)
|
||||
*temp = code_to_degc(last_temp, s) * 1000;
|
||||
|
||||
return 0;
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
@ -738,6 +773,7 @@ int __init init_common(struct tsens_priv *priv)
|
||||
priv->tm_offset = 0x1000;
|
||||
}
|
||||
|
||||
if (tsens_version(priv) >= VER_0_1) {
|
||||
res = platform_get_resource(op, IORESOURCE_MEM, 0);
|
||||
tm_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(tm_base)) {
|
||||
@ -746,17 +782,33 @@ int __init init_common(struct tsens_priv *priv)
|
||||
}
|
||||
|
||||
priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
|
||||
if (IS_ERR(priv->tm_map)) {
|
||||
} else { /* VER_0 share the same gcc regs using a syscon */
|
||||
struct device *parent = priv->dev->parent;
|
||||
|
||||
if (parent)
|
||||
priv->tm_map = syscon_node_to_regmap(parent->of_node);
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(priv->tm_map)) {
|
||||
if (!priv->tm_map)
|
||||
ret = -ENODEV;
|
||||
else
|
||||
ret = PTR_ERR(priv->tm_map);
|
||||
goto err_put_device;
|
||||
}
|
||||
|
||||
/* VER_0 have only tm_map */
|
||||
if (!priv->srot_map)
|
||||
priv->srot_map = priv->tm_map;
|
||||
|
||||
if (tsens_version(priv) > VER_0_1) {
|
||||
for (i = VER_MAJOR; i <= VER_STEP; i++) {
|
||||
priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
|
||||
priv->fields[i]);
|
||||
if (IS_ERR(priv->rf[i]))
|
||||
return PTR_ERR(priv->rf[i]);
|
||||
if (IS_ERR(priv->rf[i])) {
|
||||
ret = PTR_ERR(priv->rf[i]);
|
||||
goto err_put_device;
|
||||
}
|
||||
}
|
||||
ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
|
||||
if (ret)
|
||||
@ -769,6 +821,10 @@ int __init init_common(struct tsens_priv *priv)
|
||||
ret = PTR_ERR(priv->rf[TSENS_EN]);
|
||||
goto err_put_device;
|
||||
}
|
||||
/* in VER_0 TSENS need to be explicitly enabled */
|
||||
if (tsens_version(priv) == VER_0)
|
||||
regmap_field_write(priv->rf[TSENS_EN], 1);
|
||||
|
||||
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
|
||||
if (ret)
|
||||
goto err_put_device;
|
||||
@ -791,6 +847,19 @@ int __init init_common(struct tsens_priv *priv)
|
||||
goto err_put_device;
|
||||
}
|
||||
|
||||
priv->rf[TSENS_SW_RST] =
|
||||
devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]);
|
||||
if (IS_ERR(priv->rf[TSENS_SW_RST])) {
|
||||
ret = PTR_ERR(priv->rf[TSENS_SW_RST]);
|
||||
goto err_put_device;
|
||||
}
|
||||
|
||||
priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]);
|
||||
if (IS_ERR(priv->rf[TRDY])) {
|
||||
ret = PTR_ERR(priv->rf[TRDY]);
|
||||
goto err_put_device;
|
||||
}
|
||||
|
||||
/* This loop might need changes if enum regfield_ids is reordered */
|
||||
for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) {
|
||||
for (i = 0; i < priv->feat->max_sensors; i++) {
|
||||
@ -806,7 +875,7 @@ int __init init_common(struct tsens_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->feat->crit_int) {
|
||||
if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) {
|
||||
/* Loop might need changes if enum regfield_ids is reordered */
|
||||
for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
|
||||
for (i = 0; i < priv->feat->max_sensors; i++) {
|
||||
@ -844,7 +913,11 @@ int __init init_common(struct tsens_priv *priv)
|
||||
}
|
||||
|
||||
spin_lock_init(&priv->ul_lock);
|
||||
|
||||
/* VER_0 interrupt doesn't need to be enabled */
|
||||
if (tsens_version(priv) >= VER_0_1)
|
||||
tsens_enable_irq(priv);
|
||||
|
||||
tsens_debug_init(op);
|
||||
|
||||
err_put_device:
|
||||
@ -895,6 +968,12 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
|
||||
|
||||
static const struct of_device_id tsens_table[] = {
|
||||
{
|
||||
.compatible = "qcom,ipq8064-tsens",
|
||||
.data = &data_8960,
|
||||
}, {
|
||||
.compatible = "qcom,mdm9607-tsens",
|
||||
.data = &data_9607,
|
||||
}, {
|
||||
.compatible = "qcom,msm8916-tsens",
|
||||
.data = &data_8916,
|
||||
}, {
|
||||
@ -943,10 +1022,19 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
|
||||
if (irq == -ENXIO)
|
||||
ret = 0;
|
||||
} else {
|
||||
/* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */
|
||||
if (tsens_version(priv) == VER_0)
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq,
|
||||
NULL, thread_fn,
|
||||
IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), priv);
|
||||
thread_fn, NULL,
|
||||
IRQF_TRIGGER_RISING,
|
||||
dev_name(&pdev->dev),
|
||||
priv);
|
||||
else
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
thread_fn, IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev),
|
||||
priv);
|
||||
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "%s: failed to get irq\n",
|
||||
__func__);
|
||||
@ -975,6 +1063,19 @@ static int tsens_register(struct tsens_priv *priv)
|
||||
priv->ops->enable(priv, i);
|
||||
}
|
||||
|
||||
/* VER_0 require to set MIN and MAX THRESH
|
||||
* These 2 regs are set using the:
|
||||
* - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C
|
||||
* - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C
|
||||
*/
|
||||
if (tsens_version(priv) < VER_0_1) {
|
||||
regmap_field_write(priv->rf[CRIT_THRESH_0],
|
||||
tsens_mC_to_hw(priv->sensor, 120000));
|
||||
|
||||
regmap_field_write(priv->rf[CRIT_THRESH_1],
|
||||
tsens_mC_to_hw(priv->sensor, 0));
|
||||
}
|
||||
|
||||
ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define CAL_DEGC_PT2 120
|
||||
#define SLOPE_FACTOR 1000
|
||||
#define SLOPE_DEFAULT 3200
|
||||
#define TIMEOUT_US 100
|
||||
#define THRESHOLD_MAX_ADC_CODE 0x3ff
|
||||
#define THRESHOLD_MIN_ADC_CODE 0x0
|
||||
|
||||
@ -25,7 +26,8 @@ struct tsens_priv;
|
||||
|
||||
/* IP version numbers in ascending order */
|
||||
enum tsens_ver {
|
||||
VER_0_1 = 0,
|
||||
VER_0 = 0,
|
||||
VER_0_1,
|
||||
VER_1_X,
|
||||
VER_2_X,
|
||||
};
|
||||
@ -585,7 +587,7 @@ int get_temp_common(const struct tsens_sensor *s, int *temp);
|
||||
extern struct tsens_plat_data data_8960;
|
||||
|
||||
/* TSENS v0.1 targets */
|
||||
extern struct tsens_plat_data data_8916, data_8939, data_8974;
|
||||
extern struct tsens_plat_data data_8916, data_8939, data_8974, data_9607;
|
||||
|
||||
/* TSENS v1 targets */
|
||||
extern struct tsens_plat_data data_tsens_v1, data_8976;
|
||||
|
@ -60,7 +60,7 @@
|
||||
#define MCELSIUS(temp) ((temp) * 1000)
|
||||
#define GEN3_FUSE_MASK 0xFFF
|
||||
|
||||
#define TSC_MAX_NUM 4
|
||||
#define TSC_MAX_NUM 5
|
||||
|
||||
/* default THCODE values if FUSEs are missing */
|
||||
static const int thcodes[TSC_MAX_NUM][3] = {
|
||||
@ -68,6 +68,7 @@ static const int thcodes[TSC_MAX_NUM][3] = {
|
||||
{ 3393, 2795, 2216 },
|
||||
{ 3389, 2805, 2237 },
|
||||
{ 3415, 2694, 2195 },
|
||||
{ 3356, 2724, 2244 },
|
||||
};
|
||||
|
||||
/* Structure for thermal temperature calculation */
|
||||
|
@ -300,7 +300,7 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev)
|
||||
* or 0x8xx, so they won't be away from the default value
|
||||
* for a lot.
|
||||
*
|
||||
* So here we do not return error if the calibartion data is
|
||||
* So here we do not return error if the calibration data is
|
||||
* not available, except the probe needs deferring.
|
||||
*/
|
||||
goto out;
|
||||
@ -418,7 +418,7 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev)
|
||||
}
|
||||
|
||||
/*
|
||||
* Without this undocummented value, the returned temperatures would
|
||||
* Without this undocumented value, the returned temperatures would
|
||||
* be higher than real ones by about 20C.
|
||||
*/
|
||||
#define SUN50I_H6_CTRL0_UNK 0x0000002f
|
||||
|
@ -2118,7 +2118,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
||||
struct tegra_soctherm *tegra;
|
||||
struct thermal_zone_device *z;
|
||||
struct tsensor_shared_calib shared_calib;
|
||||
struct resource *res;
|
||||
struct tegra_soctherm_soc *soc;
|
||||
unsigned int i;
|
||||
int err;
|
||||
@ -2140,26 +2139,20 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
||||
|
||||
tegra->soc = soc;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"soctherm-reg");
|
||||
tegra->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
tegra->regs = devm_platform_ioremap_resource_byname(pdev, "soctherm-reg");
|
||||
if (IS_ERR(tegra->regs)) {
|
||||
dev_err(&pdev->dev, "can't get soctherm registers");
|
||||
return PTR_ERR(tegra->regs);
|
||||
}
|
||||
|
||||
if (!tegra->soc->use_ccroc) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"car-reg");
|
||||
tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
tegra->clk_regs = devm_platform_ioremap_resource_byname(pdev, "car-reg");
|
||||
if (IS_ERR(tegra->clk_regs)) {
|
||||
dev_err(&pdev->dev, "can't get car clk registers");
|
||||
return PTR_ERR(tegra->clk_regs);
|
||||
}
|
||||
} else {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"ccroc-reg");
|
||||
tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
tegra->ccroc_regs = devm_platform_ioremap_resource_byname(pdev, "ccroc-reg");
|
||||
if (IS_ERR(tegra->ccroc_regs)) {
|
||||
dev_err(&pdev->dev, "can't get ccroc registers");
|
||||
return PTR_ERR(tegra->ccroc_regs);
|
||||
@ -2195,7 +2188,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* calculate tsensor calibaration data */
|
||||
/* calculate tsensor calibration data */
|
||||
for (i = 0; i < soc->num_tsensors; ++i) {
|
||||
err = tegra_calc_tsensor_calib(&soc->tsensors[i],
|
||||
&shared_calib,
|
||||
|
@ -561,24 +561,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_device_update);
|
||||
|
||||
/**
|
||||
* thermal_notify_framework - Sensor drivers use this API to notify framework
|
||||
* @tz: thermal zone device
|
||||
* @trip: indicates which trip point has been crossed
|
||||
*
|
||||
* This function handles the trip events from sensor drivers. It starts
|
||||
* throttling the cooling devices according to the policy configured.
|
||||
* For CRITICAL and HOT trip points, this notifies the respective drivers,
|
||||
* and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
|
||||
* The throttling policy is based on the configured platform data; if no
|
||||
* platform data is provided, this uses the step_wise throttling policy.
|
||||
*/
|
||||
void thermal_notify_framework(struct thermal_zone_device *tz, int trip)
|
||||
{
|
||||
handle_thermal_trip(tz, trip);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_notify_framework);
|
||||
|
||||
static void thermal_zone_device_check(struct work_struct *work)
|
||||
{
|
||||
struct thermal_zone_device *tz = container_of(work, struct
|
||||
@ -960,10 +942,7 @@ __thermal_cooling_device_register(struct device_node *np,
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct thermal_zone_device *pos = NULL;
|
||||
int result;
|
||||
|
||||
if (type && strlen(type) >= THERMAL_NAME_LENGTH)
|
||||
return ERR_PTR(-EINVAL);
|
||||
int ret;
|
||||
|
||||
if (!ops || !ops->get_max_state || !ops->get_cur_state ||
|
||||
!ops->set_cur_state)
|
||||
@ -973,14 +952,17 @@ __thermal_cooling_device_register(struct device_node *np,
|
||||
if (!cdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
|
||||
if (result < 0) {
|
||||
kfree(cdev);
|
||||
return ERR_PTR(result);
|
||||
ret = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto out_kfree_cdev;
|
||||
cdev->id = ret;
|
||||
|
||||
cdev->type = kstrdup(type ? type : "", GFP_KERNEL);
|
||||
if (!cdev->type) {
|
||||
ret = -ENOMEM;
|
||||
goto out_ida_remove;
|
||||
}
|
||||
|
||||
cdev->id = result;
|
||||
strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
|
||||
mutex_init(&cdev->lock);
|
||||
INIT_LIST_HEAD(&cdev->thermal_instances);
|
||||
cdev->np = np;
|
||||
@ -990,12 +972,9 @@ __thermal_cooling_device_register(struct device_node *np,
|
||||
cdev->devdata = devdata;
|
||||
thermal_cooling_device_setup_sysfs(cdev);
|
||||
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
|
||||
result = device_register(&cdev->device);
|
||||
if (result) {
|
||||
ida_simple_remove(&thermal_cdev_ida, cdev->id);
|
||||
put_device(&cdev->device);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
ret = device_register(&cdev->device);
|
||||
if (ret)
|
||||
goto out_kfree_type;
|
||||
|
||||
/* Add 'this' new cdev to the global cdev list */
|
||||
mutex_lock(&thermal_list_lock);
|
||||
@ -1013,6 +992,15 @@ __thermal_cooling_device_register(struct device_node *np,
|
||||
mutex_unlock(&thermal_list_lock);
|
||||
|
||||
return cdev;
|
||||
|
||||
out_kfree_type:
|
||||
kfree(cdev->type);
|
||||
put_device(&cdev->device);
|
||||
out_ida_remove:
|
||||
ida_simple_remove(&thermal_cdev_ida, cdev->id);
|
||||
out_kfree_cdev:
|
||||
kfree(cdev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1171,6 +1159,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
|
||||
ida_simple_remove(&thermal_cdev_ida, cdev->id);
|
||||
device_del(&cdev->device);
|
||||
thermal_cooling_device_destroy_sysfs(cdev);
|
||||
kfree(cdev->type);
|
||||
put_device(&cdev->device);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
|
||||
|
@ -66,6 +66,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
|
||||
}
|
||||
|
||||
void thermal_cdev_update(struct thermal_cooling_device *);
|
||||
void __thermal_cdev_update(struct thermal_cooling_device *cdev);
|
||||
|
||||
/**
|
||||
* struct thermal_trip - representation of a point in temperature domain
|
||||
|
@ -192,18 +192,11 @@ static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
|
||||
thermal_cooling_device_stats_update(cdev, target);
|
||||
}
|
||||
|
||||
void thermal_cdev_update(struct thermal_cooling_device *cdev)
|
||||
void __thermal_cdev_update(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
struct thermal_instance *instance;
|
||||
unsigned long target = 0;
|
||||
|
||||
mutex_lock(&cdev->lock);
|
||||
/* cooling device is updated*/
|
||||
if (cdev->updated) {
|
||||
mutex_unlock(&cdev->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure cdev enters the deepest cooling state */
|
||||
list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
|
||||
dev_dbg(&cdev->device, "zone%d->target=%lu\n",
|
||||
@ -216,11 +209,25 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
|
||||
|
||||
thermal_cdev_set_cur_state(cdev, target);
|
||||
|
||||
cdev->updated = true;
|
||||
mutex_unlock(&cdev->lock);
|
||||
trace_cdev_update(cdev, target);
|
||||
dev_dbg(&cdev->device, "set to state %lu\n", target);
|
||||
}
|
||||
|
||||
/**
|
||||
* thermal_cdev_update - update cooling device state if needed
|
||||
* @cdev: pointer to struct thermal_cooling_device
|
||||
*
|
||||
* Update the cooling device state if there is a need.
|
||||
*/
|
||||
void thermal_cdev_update(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
mutex_lock(&cdev->lock);
|
||||
if (!cdev->updated) {
|
||||
__thermal_cdev_update(cdev);
|
||||
cdev->updated = true;
|
||||
}
|
||||
mutex_unlock(&cdev->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_cdev_update);
|
||||
|
||||
/**
|
||||
|
@ -54,11 +54,8 @@ static int thermal_mmio_probe(struct platform_device *pdev)
|
||||
|
||||
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource);
|
||||
if (IS_ERR(sensor->mmio_base)) {
|
||||
dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n",
|
||||
PTR_ERR(sensor->mmio_base));
|
||||
if (IS_ERR(sensor->mmio_base))
|
||||
return PTR_ERR(sensor->mmio_base);
|
||||
}
|
||||
|
||||
sensor_init_func = device_get_match_data(&pdev->dev);
|
||||
if (sensor_init_func) {
|
||||
|
@ -704,14 +704,17 @@ static int thermal_of_populate_bind_params(struct device_node *np,
|
||||
|
||||
count = of_count_phandle_with_args(np, "cooling-device",
|
||||
"#cooling-cells");
|
||||
if (!count) {
|
||||
if (count <= 0) {
|
||||
pr_err("Add a cooling_device property with at least one device\n");
|
||||
ret = -ENOENT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
__tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL);
|
||||
if (!__tcbp)
|
||||
if (!__tcbp) {
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = of_parse_phandle_with_args(np, "cooling-device",
|
||||
|
@ -9,30 +9,29 @@
|
||||
* Eduardo Valentin <eduardo.valentin@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ti-bandgap.h"
|
||||
|
||||
@ -1143,14 +1142,10 @@ static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
|
||||
for (i = 0; i < bgp->conf->sensor_count; i++) {
|
||||
struct temp_sensor_registers *tsr;
|
||||
struct temp_sensor_regval *rval;
|
||||
u32 val = 0;
|
||||
|
||||
rval = &bgp->regval[i];
|
||||
tsr = bgp->conf->sensors[i].registers;
|
||||
|
||||
if (TI_BANDGAP_HAS(bgp, COUNTER))
|
||||
val = ti_bandgap_readl(bgp, tsr->bgap_counter);
|
||||
|
||||
if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
|
||||
ti_bandgap_writel(bgp, rval->tshut_threshold,
|
||||
tsr->tshut_threshold);
|
||||
|
@ -91,7 +91,7 @@ struct thermal_cooling_device_ops {
|
||||
|
||||
struct thermal_cooling_device {
|
||||
int id;
|
||||
char type[THERMAL_NAME_LENGTH];
|
||||
char *type;
|
||||
struct device device;
|
||||
struct device_node *np;
|
||||
void *devdata;
|
||||
@ -390,7 +390,6 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
|
||||
int thermal_zone_get_slope(struct thermal_zone_device *tz);
|
||||
int thermal_zone_get_offset(struct thermal_zone_device *tz);
|
||||
|
||||
void thermal_notify_framework(struct thermal_zone_device *, int);
|
||||
int thermal_zone_device_enable(struct thermal_zone_device *tz);
|
||||
int thermal_zone_device_disable(struct thermal_zone_device *tz);
|
||||
void thermal_zone_device_critical(struct thermal_zone_device *tz);
|
||||
@ -436,10 +435,6 @@ static inline int thermal_zone_get_offset(
|
||||
struct thermal_zone_device *tz)
|
||||
{ return -ENODEV; }
|
||||
|
||||
static inline void thermal_notify_framework(struct thermal_zone_device *tz,
|
||||
int trip)
|
||||
{ }
|
||||
|
||||
static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
|
||||
{ return -ENODEV; }
|
||||
|
||||
|
@ -60,7 +60,7 @@ enum thermal_genl_event {
|
||||
THERMAL_GENL_EVENT_UNSPEC,
|
||||
THERMAL_GENL_EVENT_TZ_CREATE, /* Thermal zone creation */
|
||||
THERMAL_GENL_EVENT_TZ_DELETE, /* Thermal zone deletion */
|
||||
THERMAL_GENL_EVENT_TZ_DISABLE, /* Thermal zone disabed */
|
||||
THERMAL_GENL_EVENT_TZ_DISABLE, /* Thermal zone disabled */
|
||||
THERMAL_GENL_EVENT_TZ_ENABLE, /* Thermal zone enabled */
|
||||
THERMAL_GENL_EVENT_TZ_TRIP_UP, /* Trip point crossed the way up */
|
||||
THERMAL_GENL_EVENT_TZ_TRIP_DOWN, /* Trip point crossed the way down */
|
||||
|
Loading…
x
Reference in New Issue
Block a user