Thermal control updates for 5.16-rc1
- Constify a variable in thermal MMIO driver (Rikard Falkeborn). - Add the current temperature in the netlink message when crossing a trip point in order to prevent useless back and forth reading from userspace (Daniel Lezcano). - Add support for the 'HC' variant on PM8998 PMIC in order to support VADC channels on recent QCom boards (Bjorn Andersson). - Add support for calibration values from hardware when they are fused (Niklas Söderlund). - Fix NULL pointer dereference in the thermal_release callback when an error occurs in the thermal_zone_device_register() (Yuanzheng Song). - Fix use-after-free in __thermal_cooling_device_register() in the error path (Ziyang Xuan). - Fix compilation of the LMh driver when CONFIG_QCOM_SCM is not set (Jackie Liu). - Add timeout when reading a register that can block forever in certain circumstances in the tsens driver (Ansuel Smith). - Add DT binding for the reset lines and use them in the rockchip sensor driver (Johan Jonker). - Add new uniphier NX1 SoC temperature sensor (Kunihiko Hayashi). - Save and restore the TCC value in the int340x driver (Antoine Tenart). - Deprecate the writability of the cooling device state sysfs file and the user space governor (Daniel Lezcano). - Delete bogus length check in int340x (Dan Carpenter). - Use bitmap_zalloc/bitmap_free when applicable in intel_powerclamp (Christophe JAILLET). - Move thermal ABI documentation to Documentation/ABI (Mauro Carvalho Chehab). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmGBkrwSHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRxAXcQAJQC2NOxDrN+QxDiWUW67xUpxg9rcWxg pXHq5I9jutk0FqFD0Jky+Qz8ptLOVeColgwaW0GBUWVVWsrsd+Vh091jyN0dfTLz Rw6bqsr+N7M5U10uTBOnz7CyIZCLAFpwRbi9/NfzhV2MqwlCMnh+b/GLZzqHoHoh 2O9rs3SMdYdWatkRuWA5T1EA9+rIKOR1BV+WMQBaF7lUIcL2xcrFUl1lNG2v4GHz pjVHoSyexvZyRxqWXH+jq5yl3EEhs4PuTnprQMO2Y+ly0NbKXKE2izihLuGTCRUE f5ToXxJRGwl6eQYXIG/IyN01tIXCNQ5e4q4wTN0CLtLOtHkypA7fwJzOJMTZANmv PRhx4IPHy1jax7qAoMEUdtDQTVpf9i1oKrk66Ei+FQX7E5R3HeTuLxScq7W9yDu7 B7jMnqXLFbUcxrAdKA5R9vKc03/QjsOxZHElK41bAdxR6/KqqAtl5fVOhpp5+LtB HfFU6NDk/R/6BouhcfV98/ndbICKUQZiifEWz2QToVD5uf07vNp9ZXKz3NIRdgXR n/0LsoLAodrllVG/hWy1vLAZYbNuGwOZsnSyh+zAprsKhWzNMAeWfizJzXzl9fjZ +PfyMITcd/Mne7jhzz8AXx+eZBy7SltZxDI46c5/y6AEqhgm3micpaKIXs8jhl8/ Xn9o4RCDN0sf =UBs9 -----END PGP SIGNATURE----- Merge tag 'thermal-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull thermal control updates from Rafael Wysocki: "These extend the thermal trip point crossing notifications sent via netlink to contain the temperature causing the trip point to be crossed, deprecate the user space thermal governor, add new DT bindings to drivers, move ABI documentation to Documentation/ABI, fix assorted issues and clean up code. Specifics: - Constify a variable in thermal MMIO driver (Rikard Falkeborn). - Add the current temperature in the netlink message when crossing a trip point in order to prevent useless back and forth reading from userspace (Daniel Lezcano). - Add support for the 'HC' variant on PM8998 PMIC in order to support VADC channels on recent QCom boards (Bjorn Andersson). - Add support for calibration values from hardware when they are fused (Niklas Söderlund). - Fix NULL pointer dereference in the thermal_release callback when an error occurs in the thermal_zone_device_register() (Yuanzheng Song). - Fix use-after-free in __thermal_cooling_device_register() in the error path (Ziyang Xuan). - Fix compilation of the LMh driver when CONFIG_QCOM_SCM is not set (Jackie Liu). - Add timeout when reading a register that can block forever in certain circumstances in the tsens driver (Ansuel Smith). - Add DT binding for the reset lines and use them in the rockchip sensor driver (Johan Jonker). - Add new uniphier NX1 SoC temperature sensor (Kunihiko Hayashi). - Save and restore the TCC value in the int340x driver (Antoine Tenart). - Deprecate the writability of the cooling device state sysfs file and the user space governor (Daniel Lezcano). - Delete bogus length check in int340x (Dan Carpenter). - Use bitmap_zalloc/bitmap_free when applicable in intel_powerclamp (Christophe JAILLET). - Move thermal ABI documentation to Documentation/ABI (Mauro Carvalho Chehab)" * tag 'thermal-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (21 commits) thermal/core: Deprecate changing cooling device state from userspace thermal/core: Make the userspace governor deprecated thermal/drivers/int340x: Improve the tcc offset saving for suspend/resume thermal/drivers/uniphier: Add compatible string for NX1 SoC dt-bindings: thermal: uniphier: Add binding for NX1 SoC thermal/drivers/rockchip_thermal: Allow more resets for tsadc node dt-bindings: thermal: remove redundant comments from rockchip-thermal.yaml dt-bindings: thermal: allow more resets for tsadc node in rockchip-thermal.yaml thermal/drivers/tsens: Add timeout to get_temp_tsens_valid thermal/drivers/qcom/lmh: make QCOM_LMH depends on QCOM_SCM thermal/core: fix a UAF bug in __thermal_cooling_device_register() thermal/core: Fix null pointer dereference in thermal_release() thermal: rcar_gen3_thermal: Read calibration from hardware thermal: rcar_gen3_thermal: Store thcode and ptat in priv data thermal/drivers/qcom/spmi-adc-tm5: Add support for HC variant dt-bindings: thermal: qcom: add HC variant of adc-thermal monitor bindings thermal: Move ABI documentation to Documentation/ABI thermal/drivers/netlink: Add the temperature when crossing a trip point thermal/drivers/thermal_mmio: Constify static struct thermal_mmio_ops thermal: int340x: delete bogus length check ...
This commit is contained in:
Коммит
f73cd9c951
|
@ -0,0 +1,259 @@
|
|||
What: /sys/class/thermal/thermal_zoneX/type
|
||||
Description:
|
||||
Strings which represent the thermal zone type.
|
||||
This is given by thermal zone driver as part of registration.
|
||||
E.g: "acpitz" indicates it's an ACPI thermal device.
|
||||
In order to keep it consistent with hwmon sys attribute; this
|
||||
shouldbe a short, lowercase string, not containing spaces nor
|
||||
dashes.
|
||||
|
||||
RO, Required
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/temp
|
||||
Description:
|
||||
Current temperature as reported by thermal zone (sensor).
|
||||
|
||||
Unit: millidegree Celsius
|
||||
|
||||
RO, Required
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/mode
|
||||
Description:
|
||||
One of the predefined values in [enabled, disabled].
|
||||
This file gives information about the algorithm that is
|
||||
currently managing the thermal zone. It can be either default
|
||||
kernel based algorithm or user space application.
|
||||
|
||||
enabled
|
||||
enable Kernel Thermal management.
|
||||
disabled
|
||||
Preventing kernel thermal zone driver actions upon
|
||||
trip points so that user application can take full
|
||||
charge of the thermal management.
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/policy
|
||||
Description:
|
||||
One of the various thermal governors used for a particular zone.
|
||||
|
||||
RW, Required
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/available_policies
|
||||
Description:
|
||||
Available thermal governors which can be used for a
|
||||
particular zone.
|
||||
|
||||
RO, Required
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/trip_point_Y_temp
|
||||
Description:
|
||||
The temperature above which trip point will be fired.
|
||||
|
||||
Unit: millidegree Celsius
|
||||
|
||||
RO, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/trip_point_Y_type
|
||||
Description:
|
||||
Strings which indicate the type of the trip point.
|
||||
|
||||
E.g. it can be one of critical, hot, passive, `active[0-*]`
|
||||
for ACPI thermal zone.
|
||||
|
||||
RO, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/trip_point_Y_hyst
|
||||
Description:
|
||||
The hysteresis value for a trip point, represented as an
|
||||
integer.
|
||||
|
||||
Unit: Celsius
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/cdevY
|
||||
Description:
|
||||
Sysfs link to the thermal cooling device node where the sys I/F
|
||||
for cooling device throttling control represents.
|
||||
|
||||
RO, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/cdevY_trip_point
|
||||
Description:
|
||||
The trip point in this thermal zone which `cdev[0-*]` is
|
||||
associated with; -1 means the cooling device is not
|
||||
associated with any trip point.
|
||||
|
||||
RO, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/cdevY_weight
|
||||
Description:
|
||||
The influence of `cdev[0-*]` in this thermal zone. This value
|
||||
is relative to the rest of cooling devices in the thermal
|
||||
zone. For example, if a cooling device has a weight double
|
||||
than that of other, it's twice as effective in cooling the
|
||||
thermal zone.
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/emul_temp
|
||||
Description:
|
||||
Interface to set the emulated temperature method in thermal zone
|
||||
(sensor). After setting this temperature, the thermal zone may
|
||||
pass this temperature to platform emulation function if
|
||||
registered or cache it locally. This is useful in debugging
|
||||
different temperature threshold and its associated cooling
|
||||
action. This is write only node and writing 0 on this node
|
||||
should disable emulation.
|
||||
|
||||
Unit: millidegree Celsius
|
||||
|
||||
WO, Optional
|
||||
|
||||
WARNING:
|
||||
Be careful while enabling this option on production systems,
|
||||
because userland can easily disable the thermal policy by simply
|
||||
flooding this sysfs node with low temperature values.
|
||||
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/k_d
|
||||
Description:
|
||||
The derivative term of the power allocator governor's PID
|
||||
controller. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/k_i
|
||||
Description:
|
||||
The integral term of the power allocator governor's PID
|
||||
controller. This term allows the PID controller to compensate
|
||||
for long term drift. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/k_po
|
||||
Description:
|
||||
The proportional term of the power allocator governor's PID
|
||||
controller during temperature overshoot. Temperature overshoot
|
||||
is when the current temperature is above the "desired
|
||||
temperature" trip point. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/k_pu
|
||||
Description:
|
||||
The proportional term of the power allocator governor's PID
|
||||
controller during temperature undershoot. Temperature undershoot
|
||||
is when the current temperature is below the "desired
|
||||
temperature" trip point. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/integral_cutoff
|
||||
Description:
|
||||
Temperature offset from the desired temperature trip point
|
||||
above which the integral term of the power allocator
|
||||
governor's PID controller starts accumulating errors. For
|
||||
example, if integral_cutoff is 0, then the integral term only
|
||||
accumulates error when temperature is above the desired
|
||||
temperature trip point. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
Unit: millidegree Celsius
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/slope
|
||||
Description:
|
||||
The slope constant used in a linear extrapolation model
|
||||
to determine a hotspot temperature based off the sensor's
|
||||
raw readings. It is up to the device driver to determine
|
||||
the usage of these values.
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/offset
|
||||
Description:
|
||||
The offset constant used in a linear extrapolation model
|
||||
to determine a hotspot temperature based off the sensor's
|
||||
raw readings. It is up to the device driver to determine
|
||||
the usage of these values.
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/thermal_zoneX/sustainable_power
|
||||
Description:
|
||||
An estimate of the sustained power that can be dissipated by
|
||||
the thermal zone. Used by the power allocator governor. For
|
||||
more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
Unit: milliwatts
|
||||
|
||||
RW, Optional
|
||||
|
||||
What: /sys/class/thermal/cooling_deviceX/type
|
||||
Description:
|
||||
String which represents the type of device, e.g:
|
||||
|
||||
- for generic ACPI: should be "Fan", "Processor" or "LCD"
|
||||
- for memory controller device on intel_menlow platform:
|
||||
should be "Memory controller".
|
||||
|
||||
RO, Required
|
||||
|
||||
What: /sys/class/thermal/cooling_deviceX/max_state
|
||||
Description:
|
||||
The maximum permissible cooling state of this cooling device.
|
||||
|
||||
RO, Required
|
||||
|
||||
What: /sys/class/thermal/cooling_deviceX/cur_state
|
||||
Description:
|
||||
The current cooling state of this cooling device.
|
||||
The value can any integer numbers between 0 and max_state:
|
||||
|
||||
- cur_state == 0 means no cooling
|
||||
- cur_state == max_state means the maximum cooling.
|
||||
|
||||
RW, Required
|
||||
|
||||
What: /sys/class/thermal/cooling_deviceX/stats/reset
|
||||
Description:
|
||||
Writing any value resets the cooling device's statistics.
|
||||
|
||||
WO, Required
|
||||
|
||||
What: /sys/class/thermal/cooling_deviceX/stats/time_in_state_ms:
|
||||
Description:
|
||||
The amount of time spent by the cooling device in various
|
||||
cooling states. The output will have "<state> <time>" pair
|
||||
in each line, which will mean this cooling device spent <time>
|
||||
msec of time at <state>.
|
||||
|
||||
Output will have one line for each of the supported states.
|
||||
|
||||
RO, Required
|
||||
|
||||
What: /sys/class/thermal/cooling_deviceX/stats/total_trans
|
||||
Description:
|
||||
A single positive value showing the total number of times
|
||||
the state of a cooling device is changed.
|
||||
|
||||
RO, Required
|
||||
|
||||
What: /sys/class/thermal/cooling_deviceX/stats/trans_table
|
||||
Description:
|
||||
This gives fine grained information about all the cooling state
|
||||
transitions. The cat output here is a two dimensional matrix,
|
||||
where an entry <i,j> (row i, column j) represents the number
|
||||
of transitions from State_i to State_j. If the transition
|
||||
table is bigger than PAGE_SIZE, reading this will return
|
||||
an -EFBIG error.
|
||||
|
||||
RO, Required
|
|
@ -0,0 +1,149 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/qcom-spmi-adc-tm-hc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm's SPMI PMIC ADC HC Thermal Monitoring
|
||||
maintainers:
|
||||
- Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,spmi-adc-tm-hc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
description:
|
||||
Number of cells required to uniquely identify the thermal sensors. Since
|
||||
we have multiple sensors this is set to 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
qcom,avg-samples:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Number of samples to be used for measurement.
|
||||
enum:
|
||||
- 1
|
||||
- 2
|
||||
- 4
|
||||
- 8
|
||||
- 16
|
||||
default: 1
|
||||
|
||||
qcom,decimation:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: This parameter is used to decrease ADC sampling rate.
|
||||
Quicker measurements can be made by reducing decimation ratio.
|
||||
enum:
|
||||
- 256
|
||||
- 512
|
||||
- 1024
|
||||
default: 1024
|
||||
|
||||
patternProperties:
|
||||
"^([-a-z0-9]*)@[0-7]$":
|
||||
type: object
|
||||
description:
|
||||
Represent one thermal sensor.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: Specify the sensor channel. There are 8 channels in PMIC5's ADC TM
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
|
||||
io-channels:
|
||||
description:
|
||||
From common IIO binding. Used to pipe PMIC ADC channel to thermal monitor
|
||||
|
||||
qcom,ratiometric:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Channel calibration type.
|
||||
If this property is specified VADC will use the VDD reference
|
||||
(1.875V) and GND for channel calibration. If property is not found,
|
||||
channel will be calibrated with 0V and 1.25V reference channels,
|
||||
also known as absolute calibration.
|
||||
|
||||
qcom,hw-settle-time-us:
|
||||
description: Time between AMUX getting configured and the ADC starting conversion.
|
||||
enum: [0, 100, 200, 300, 400, 500, 600, 700, 1000, 2000, 4000, 6000, 8000, 10000]
|
||||
|
||||
qcom,pre-scaling:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: Used for scaling the channel input signal before the
|
||||
signal is fed to VADC. The configuration for this node is to know the
|
||||
pre-determined ratio and use it for post scaling. It is a pair of
|
||||
integers, denoting the numerator and denominator of the fraction by
|
||||
which input signal is multiplied. For example, <1 3> indicates the
|
||||
signal is scaled down to 1/3 of its value before ADC measurement. If
|
||||
property is not found default value depending on chip will be used.
|
||||
items:
|
||||
- const: 1
|
||||
- enum: [ 1, 3, 4, 6, 20, 8, 10 ]
|
||||
|
||||
required:
|
||||
- reg
|
||||
- io-channels
|
||||
|
||||
additionalProperties:
|
||||
false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/iio/qcom,spmi-vadc.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spmi_bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pm8998_adc: adc@3100 {
|
||||
reg = <0x3100>;
|
||||
compatible = "qcom,spmi-adc-rev2";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#io-channel-cells = <1>;
|
||||
|
||||
/* Other propreties are omitted */
|
||||
adc-chan@4c {
|
||||
reg = <ADC5_XO_THERM_100K_PU>;
|
||||
};
|
||||
};
|
||||
|
||||
pm8998_adc_tm: adc-tm@3400 {
|
||||
compatible = "qcom,spmi-adc-tm-hc";
|
||||
reg = <0x3400>;
|
||||
interrupts = <0x2 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
thermistor@1 {
|
||||
reg = <1>;
|
||||
io-channels = <&pm8998_adc ADC5_XO_THERM_100K_PU>;
|
||||
qcom,ratiometric;
|
||||
qcom,hw-settle-time-us = <200>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -12,14 +12,14 @@ maintainers:
|
|||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,px30-tsadc # PX30 SoCs
|
||||
- rockchip,rv1108-tsadc # RV1108 SoCs
|
||||
- rockchip,rk3228-tsadc # RK3228 SoCs
|
||||
- rockchip,rk3288-tsadc # RK3288 SoCs
|
||||
- rockchip,rk3328-tsadc # RK3328 SoCs
|
||||
- rockchip,rk3368-tsadc # RK3368 SoCs
|
||||
- rockchip,rk3399-tsadc # RK3399 SoCs
|
||||
- rockchip,rk3568-tsadc # RK3568 SoCs
|
||||
- rockchip,px30-tsadc
|
||||
- rockchip,rk3228-tsadc
|
||||
- rockchip,rk3288-tsadc
|
||||
- rockchip,rk3328-tsadc
|
||||
- rockchip,rk3368-tsadc
|
||||
- rockchip,rk3399-tsadc
|
||||
- rockchip,rk3568-tsadc
|
||||
- rockchip,rv1108-tsadc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -37,11 +37,15 @@ properties:
|
|||
- const: apb_pclk
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
reset-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: tsadc-apb
|
||||
- const: tsadc
|
||||
- const: tsadc-phy
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
@ -71,7 +75,6 @@ required:
|
|||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
|
|
@ -20,6 +20,7 @@ properties:
|
|||
- socionext,uniphier-pxs2-thermal
|
||||
- socionext,uniphier-ld20-thermal
|
||||
- socionext,uniphier-pxs3-thermal
|
||||
- socionext,uniphier-nx1-thermal
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
|
|
@ -428,6 +428,9 @@ of thermal zone device. E.g. the generic thermal driver registers one hwmon
|
|||
class device and build the associated hwmon sysfs I/F for all the registered
|
||||
ACPI thermal zones.
|
||||
|
||||
Please read Documentation/ABI/testing/sysfs-class-thermal for thermal
|
||||
zone and cooling device attribute details.
|
||||
|
||||
::
|
||||
|
||||
/sys/class/hwmon/hwmon[0-*]:
|
||||
|
@ -437,228 +440,6 @@ ACPI thermal zones.
|
|||
|
||||
Please read Documentation/hwmon/sysfs-interface.rst for additional information.
|
||||
|
||||
Thermal zone attributes
|
||||
-----------------------
|
||||
|
||||
type
|
||||
Strings which represent the thermal zone type.
|
||||
This is given by thermal zone driver as part of registration.
|
||||
E.g: "acpitz" indicates it's an ACPI thermal device.
|
||||
In order to keep it consistent with hwmon sys attribute; this should
|
||||
be a short, lowercase string, not containing spaces nor dashes.
|
||||
RO, Required
|
||||
|
||||
temp
|
||||
Current temperature as reported by thermal zone (sensor).
|
||||
Unit: millidegree Celsius
|
||||
RO, Required
|
||||
|
||||
mode
|
||||
One of the predefined values in [enabled, disabled].
|
||||
This file gives information about the algorithm that is currently
|
||||
managing the thermal zone. It can be either default kernel based
|
||||
algorithm or user space application.
|
||||
|
||||
enabled
|
||||
enable Kernel Thermal management.
|
||||
disabled
|
||||
Preventing kernel thermal zone driver actions upon
|
||||
trip points so that user application can take full
|
||||
charge of the thermal management.
|
||||
|
||||
RW, Optional
|
||||
|
||||
policy
|
||||
One of the various thermal governors used for a particular zone.
|
||||
|
||||
RW, Required
|
||||
|
||||
available_policies
|
||||
Available thermal governors which can be used for a particular zone.
|
||||
|
||||
RO, Required
|
||||
|
||||
`trip_point_[0-*]_temp`
|
||||
The temperature above which trip point will be fired.
|
||||
|
||||
Unit: millidegree Celsius
|
||||
|
||||
RO, Optional
|
||||
|
||||
`trip_point_[0-*]_type`
|
||||
Strings which indicate the type of the trip point.
|
||||
|
||||
E.g. it can be one of critical, hot, passive, `active[0-*]` for ACPI
|
||||
thermal zone.
|
||||
|
||||
RO, Optional
|
||||
|
||||
`trip_point_[0-*]_hyst`
|
||||
The hysteresis value for a trip point, represented as an integer
|
||||
Unit: Celsius
|
||||
RW, Optional
|
||||
|
||||
`cdev[0-*]`
|
||||
Sysfs link to the thermal cooling device node where the sys I/F
|
||||
for cooling device throttling control represents.
|
||||
|
||||
RO, Optional
|
||||
|
||||
`cdev[0-*]_trip_point`
|
||||
The trip point in this thermal zone which `cdev[0-*]` is associated
|
||||
with; -1 means the cooling device is not associated with any trip
|
||||
point.
|
||||
|
||||
RO, Optional
|
||||
|
||||
`cdev[0-*]_weight`
|
||||
The influence of `cdev[0-*]` in this thermal zone. This value
|
||||
is relative to the rest of cooling devices in the thermal
|
||||
zone. For example, if a cooling device has a weight double
|
||||
than that of other, it's twice as effective in cooling the
|
||||
thermal zone.
|
||||
|
||||
RW, Optional
|
||||
|
||||
emul_temp
|
||||
Interface to set the emulated temperature method in thermal zone
|
||||
(sensor). After setting this temperature, the thermal zone may pass
|
||||
this temperature to platform emulation function if registered or
|
||||
cache it locally. This is useful in debugging different temperature
|
||||
threshold and its associated cooling action. This is write only node
|
||||
and writing 0 on this node should disable emulation.
|
||||
Unit: millidegree Celsius
|
||||
|
||||
WO, Optional
|
||||
|
||||
WARNING:
|
||||
Be careful while enabling this option on production systems,
|
||||
because userland can easily disable the thermal policy by simply
|
||||
flooding this sysfs node with low temperature values.
|
||||
|
||||
sustainable_power
|
||||
An estimate of the sustained power that can be dissipated by
|
||||
the thermal zone. Used by the power allocator governor. For
|
||||
more information see Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
Unit: milliwatts
|
||||
|
||||
RW, Optional
|
||||
|
||||
k_po
|
||||
The proportional term of the power allocator governor's PID
|
||||
controller during temperature overshoot. Temperature overshoot
|
||||
is when the current temperature is above the "desired
|
||||
temperature" trip point. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
k_pu
|
||||
The proportional term of the power allocator governor's PID
|
||||
controller during temperature undershoot. Temperature undershoot
|
||||
is when the current temperature is below the "desired
|
||||
temperature" trip point. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
k_i
|
||||
The integral term of the power allocator governor's PID
|
||||
controller. This term allows the PID controller to compensate
|
||||
for long term drift. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
k_d
|
||||
The derivative term of the power allocator governor's PID
|
||||
controller. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
RW, Optional
|
||||
|
||||
integral_cutoff
|
||||
Temperature offset from the desired temperature trip point
|
||||
above which the integral term of the power allocator
|
||||
governor's PID controller starts accumulating errors. For
|
||||
example, if integral_cutoff is 0, then the integral term only
|
||||
accumulates error when temperature is above the desired
|
||||
temperature trip point. For more information see
|
||||
Documentation/driver-api/thermal/power_allocator.rst
|
||||
|
||||
Unit: millidegree Celsius
|
||||
|
||||
RW, Optional
|
||||
|
||||
slope
|
||||
The slope constant used in a linear extrapolation model
|
||||
to determine a hotspot temperature based off the sensor's
|
||||
raw readings. It is up to the device driver to determine
|
||||
the usage of these values.
|
||||
|
||||
RW, Optional
|
||||
|
||||
offset
|
||||
The offset constant used in a linear extrapolation model
|
||||
to determine a hotspot temperature based off the sensor's
|
||||
raw readings. It is up to the device driver to determine
|
||||
the usage of these values.
|
||||
|
||||
RW, Optional
|
||||
|
||||
Cooling device attributes
|
||||
-------------------------
|
||||
|
||||
type
|
||||
String which represents the type of device, e.g:
|
||||
|
||||
- for generic ACPI: should be "Fan", "Processor" or "LCD"
|
||||
- for memory controller device on intel_menlow platform:
|
||||
should be "Memory controller".
|
||||
|
||||
RO, Required
|
||||
|
||||
max_state
|
||||
The maximum permissible cooling state of this cooling device.
|
||||
|
||||
RO, Required
|
||||
|
||||
cur_state
|
||||
The current cooling state of this cooling device.
|
||||
The value can any integer numbers between 0 and max_state:
|
||||
|
||||
- cur_state == 0 means no cooling
|
||||
- cur_state == max_state means the maximum cooling.
|
||||
|
||||
RW, Required
|
||||
|
||||
stats/reset
|
||||
Writing any value resets the cooling device's statistics.
|
||||
WO, Required
|
||||
|
||||
stats/time_in_state_ms:
|
||||
The amount of time spent by the cooling device in various cooling
|
||||
states. The output will have "<state> <time>" pair in each line, which
|
||||
will mean this cooling device spent <time> msec of time at <state>.
|
||||
Output will have one line for each of the supported states.
|
||||
RO, Required
|
||||
|
||||
|
||||
stats/total_trans:
|
||||
A single positive value showing the total number of times the state of a
|
||||
cooling device is changed.
|
||||
|
||||
RO, Required
|
||||
|
||||
stats/trans_table:
|
||||
This gives fine grained information about all the cooling state
|
||||
transitions. The cat output here is a two dimensional matrix, where an
|
||||
entry <i,j> (row i, column j) represents the number of transitions from
|
||||
State_i to State_j. If the transition table is bigger than PAGE_SIZE,
|
||||
reading this will return an -EFBIG error.
|
||||
RO, Required
|
||||
|
||||
3. A simple implementation
|
||||
==========================
|
||||
|
||||
|
|
|
@ -18649,7 +18649,9 @@ L: linux-pm@vger.kernel.org
|
|||
S: Supported
|
||||
Q: https://patchwork.kernel.org/project/linux-pm/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git thermal
|
||||
F: Documentation/ABI/testing/sysfs-class-thermal
|
||||
F: Documentation/devicetree/bindings/thermal/
|
||||
F: Documentation/driver-api/thermal/
|
||||
F: drivers/thermal/
|
||||
F: include/linux/cpu_cooling.h
|
||||
F: include/linux/thermal.h
|
||||
|
|
|
@ -15,6 +15,14 @@
|
|||
|
||||
#include "thermal_core.h"
|
||||
|
||||
static int user_space_bind(struct thermal_zone_device *tz)
|
||||
{
|
||||
pr_warn("Userspace governor deprecated: use thermal netlink " \
|
||||
"notification instead\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* notify_user_space - Notifies user space about thermal events
|
||||
* @tz: thermal_zone_device
|
||||
|
@ -43,5 +51,6 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
|
|||
static struct thermal_governor thermal_gov_user_space = {
|
||||
.name = "user_space",
|
||||
.throttle = notify_user_space,
|
||||
.bind_to_tz = user_space_bind,
|
||||
};
|
||||
THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space);
|
||||
|
|
|
@ -129,11 +129,10 @@ static ssize_t available_uuids_show(struct device *dev,
|
|||
|
||||
for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) {
|
||||
if (priv->uuid_bitmap & (1 << i))
|
||||
if (PAGE_SIZE - length > 0)
|
||||
length += scnprintf(&buf[length],
|
||||
PAGE_SIZE - length,
|
||||
"%s\n",
|
||||
int3400_thermal_uuids[i]);
|
||||
length += scnprintf(&buf[length],
|
||||
PAGE_SIZE - length,
|
||||
"%s\n",
|
||||
int3400_thermal_uuids[i]);
|
||||
}
|
||||
|
||||
return length;
|
||||
|
|
|
@ -44,15 +44,21 @@ static int int3401_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int int3401_thermal_suspend(struct device *dev)
|
||||
{
|
||||
return proc_thermal_suspend(dev);
|
||||
}
|
||||
static int int3401_thermal_resume(struct device *dev)
|
||||
{
|
||||
return proc_thermal_resume(dev);
|
||||
}
|
||||
#else
|
||||
#define int3401_thermal_suspend NULL
|
||||
#define int3401_thermal_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, NULL, int3401_thermal_resume);
|
||||
static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, int3401_thermal_suspend,
|
||||
int3401_thermal_resume);
|
||||
|
||||
static struct platform_driver int3401_driver = {
|
||||
.probe = int3401_add,
|
||||
|
|
|
@ -68,8 +68,7 @@ static const struct attribute_group power_limit_attribute_group = {
|
|||
.name = "power_limits"
|
||||
};
|
||||
|
||||
static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static int tcc_get_offset(void)
|
||||
{
|
||||
u64 val;
|
||||
int err;
|
||||
|
@ -78,8 +77,20 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
val = (val >> 24) & 0x3f;
|
||||
return sprintf(buf, "%d\n", (int)val);
|
||||
return (val >> 24) & 0x3f;
|
||||
}
|
||||
|
||||
static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int tcc;
|
||||
|
||||
tcc = tcc_get_offset();
|
||||
if (tcc < 0)
|
||||
return tcc;
|
||||
|
||||
return sprintf(buf, "%d\n", tcc);
|
||||
}
|
||||
|
||||
static int tcc_offset_update(unsigned int tcc)
|
||||
|
@ -107,8 +118,6 @@ static int tcc_offset_update(unsigned int tcc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tcc_offset_save = -1;
|
||||
|
||||
static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
|
@ -131,8 +140,6 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
tcc_offset_save = tcc;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -345,6 +352,18 @@ void proc_thermal_remove(struct proc_thermal_device *proc_priv)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_remove);
|
||||
|
||||
static int tcc_offset_save = -1;
|
||||
|
||||
int proc_thermal_suspend(struct device *dev)
|
||||
{
|
||||
tcc_offset_save = tcc_get_offset();
|
||||
if (tcc_offset_save < 0)
|
||||
dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_suspend);
|
||||
|
||||
int proc_thermal_resume(struct device *dev)
|
||||
{
|
||||
struct proc_thermal_device *proc_dev;
|
||||
|
@ -352,6 +371,7 @@ int proc_thermal_resume(struct device *dev)
|
|||
proc_dev = dev_get_drvdata(dev);
|
||||
proc_thermal_read_ppcc(proc_dev);
|
||||
|
||||
/* Do not update if saving failed */
|
||||
if (tcc_offset_save >= 0)
|
||||
tcc_offset_update(tcc_offset_save);
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ void proc_thermal_mbox_remove(struct pci_dev *pdev);
|
|||
int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp);
|
||||
int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
|
||||
void proc_thermal_remove(struct proc_thermal_device *proc_priv);
|
||||
int proc_thermal_suspend(struct device *dev);
|
||||
int proc_thermal_resume(struct device *dev);
|
||||
int proc_thermal_mmio_add(struct pci_dev *pdev,
|
||||
struct proc_thermal_device *proc_priv,
|
||||
|
|
|
@ -314,6 +314,20 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int proc_thermal_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct proc_thermal_pci *pci_info;
|
||||
|
||||
proc_priv = pci_get_drvdata(pdev);
|
||||
pci_info = proc_priv->priv_data;
|
||||
|
||||
if (!pci_info->no_legacy)
|
||||
return proc_thermal_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int proc_thermal_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
@ -335,10 +349,12 @@ static int proc_thermal_pci_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
#else
|
||||
#define proc_thermal_pci_suspend NULL
|
||||
#define proc_thermal_pci_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
|
||||
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
|
||||
proc_thermal_pci_resume);
|
||||
|
||||
static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
|
||||
|
|
|
@ -107,15 +107,21 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int proc_thermal_pci_suspend(struct device *dev)
|
||||
{
|
||||
return proc_thermal_suspend(dev);
|
||||
}
|
||||
static int proc_thermal_pci_resume(struct device *dev)
|
||||
{
|
||||
return proc_thermal_resume(dev);
|
||||
}
|
||||
#else
|
||||
#define proc_thermal_pci_suspend NULL
|
||||
#define proc_thermal_pci_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
|
||||
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
|
||||
proc_thermal_pci_resume);
|
||||
|
||||
static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
|
||||
|
|
|
@ -705,10 +705,8 @@ static enum cpuhp_state hp_state;
|
|||
static int __init powerclamp_init(void)
|
||||
{
|
||||
int retval;
|
||||
int bitmap_size;
|
||||
|
||||
bitmap_size = BITS_TO_LONGS(num_possible_cpus()) * sizeof(long);
|
||||
cpu_clamping_mask = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
cpu_clamping_mask = bitmap_zalloc(num_possible_cpus(), GFP_KERNEL);
|
||||
if (!cpu_clamping_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -753,7 +751,7 @@ exit_free_thread:
|
|||
exit_unregister:
|
||||
cpuhp_remove_state_nocalls(hp_state);
|
||||
exit_free:
|
||||
kfree(cpu_clamping_mask);
|
||||
bitmap_free(cpu_clamping_mask);
|
||||
return retval;
|
||||
}
|
||||
module_init(powerclamp_init);
|
||||
|
@ -764,7 +762,7 @@ static void __exit powerclamp_exit(void)
|
|||
cpuhp_remove_state_nocalls(hp_state);
|
||||
free_percpu(worker_data);
|
||||
thermal_cooling_device_unregister(cooling_dev);
|
||||
kfree(cpu_clamping_mask);
|
||||
bitmap_free(cpu_clamping_mask);
|
||||
|
||||
cancel_delayed_work_sync(&poll_pkg_cstate_work);
|
||||
debugfs_remove_recursive(debug_dir);
|
||||
|
|
|
@ -34,7 +34,7 @@ config QCOM_SPMI_TEMP_ALARM
|
|||
|
||||
config QCOM_LMH
|
||||
tristate "Qualcomm Limits Management Hardware"
|
||||
depends on ARCH_QCOM
|
||||
depends on ARCH_QCOM && QCOM_SCM
|
||||
help
|
||||
This enables initialization of Qualcomm limits management
|
||||
hardware(LMh). LMh allows for hardware-enforced mitigation for cpus based on
|
||||
|
|
|
@ -82,6 +82,7 @@ struct adc_tm5_data {
|
|||
const u32 full_scale_code_volt;
|
||||
unsigned int *decimation;
|
||||
unsigned int *hw_settle;
|
||||
bool is_hc;
|
||||
};
|
||||
|
||||
enum adc_tm5_cal_method {
|
||||
|
@ -146,6 +147,14 @@ static const struct adc_tm5_data adc_tm5_data_pmic = {
|
|||
64000, 128000 },
|
||||
};
|
||||
|
||||
static const struct adc_tm5_data adc_tm_hc_data_pmic = {
|
||||
.full_scale_code_volt = 0x70e4,
|
||||
.decimation = (unsigned int []) { 256, 512, 1024 },
|
||||
.hw_settle = (unsigned int []) { 0, 100, 200, 300, 400, 500, 600, 700,
|
||||
1000, 2000, 4000, 6000, 8000, 10000 },
|
||||
.is_hc = true,
|
||||
};
|
||||
|
||||
static int adc_tm5_read(struct adc_tm5_chip *adc_tm, u16 offset, u8 *data, int len)
|
||||
{
|
||||
return regmap_bulk_read(adc_tm->regmap, adc_tm->base + offset, data, len);
|
||||
|
@ -375,6 +384,29 @@ static int adc_tm5_register_tzd(struct adc_tm5_chip *adc_tm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adc_tm_hc_init(struct adc_tm5_chip *chip)
|
||||
{
|
||||
unsigned int i;
|
||||
u8 buf[2];
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < chip->nchannels; i++) {
|
||||
if (chip->channels[i].channel >= ADC_TM5_NUM_CHANNELS) {
|
||||
dev_err(chip->dev, "Invalid channel %d\n", chip->channels[i].channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
buf[0] = chip->decimation;
|
||||
buf[1] = chip->avg_samples | ADC_TM5_FAST_AVG_EN;
|
||||
|
||||
ret = adc_tm5_write(chip, ADC_TM5_ADC_DIG_PARAM, buf, sizeof(buf));
|
||||
if (ret)
|
||||
dev_err(chip->dev, "block write failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc_tm5_init(struct adc_tm5_chip *chip)
|
||||
{
|
||||
u8 buf[4], channels_available;
|
||||
|
@ -591,7 +623,10 @@ static int adc_tm5_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = adc_tm5_init(adc_tm);
|
||||
if (adc_tm->data->is_hc)
|
||||
ret = adc_tm_hc_init(adc_tm);
|
||||
else
|
||||
ret = adc_tm5_init(adc_tm);
|
||||
if (ret) {
|
||||
dev_err(dev, "adc-tm init failed\n");
|
||||
return ret;
|
||||
|
@ -612,6 +647,10 @@ static const struct of_device_id adc_tm5_match_table[] = {
|
|||
.compatible = "qcom,spmi-adc-tm5",
|
||||
.data = &adc_tm5_data_pmic,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,spmi-adc-tm-hc",
|
||||
.data = &adc_tm_hc_data_pmic,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc_tm5_match_table);
|
||||
|
|
|
@ -603,22 +603,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
|
|||
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;
|
||||
while (!valid) {
|
||||
/* Valid bit is 0 for 6 AHB clock cycles.
|
||||
* At 19.2MHz, 1 AHB clock is ~60ns.
|
||||
* We should enter this loop very, very rarely.
|
||||
*/
|
||||
ndelay(400);
|
||||
ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (tsens_version(priv) == VER_0)
|
||||
goto get_temp;
|
||||
|
||||
/* Valid bit is 0 for 6 AHB clock cycles.
|
||||
* At 19.2MHz, 1 AHB clock is ~60ns.
|
||||
* We should enter this loop very, very rarely.
|
||||
* Wait 1 us since it's the min of poll_timeout macro.
|
||||
* Old value was 400 ns.
|
||||
*/
|
||||
ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid,
|
||||
valid, 1, 20 * USEC_PER_MSEC);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
get_temp:
|
||||
/* Valid bit is set, OK to read the temperature */
|
||||
*temp = tsens_hw_to_mC(s, temp_idx);
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
#define REG_GEN3_THCODE1 0x50
|
||||
#define REG_GEN3_THCODE2 0x54
|
||||
#define REG_GEN3_THCODE3 0x58
|
||||
#define REG_GEN3_PTAT1 0x5c
|
||||
#define REG_GEN3_PTAT2 0x60
|
||||
#define REG_GEN3_PTAT3 0x64
|
||||
#define REG_GEN3_THSCP 0x68
|
||||
|
||||
/* IRQ{STR,MSK,EN} bits */
|
||||
#define IRQ_TEMP1 BIT(0)
|
||||
|
@ -55,6 +59,9 @@
|
|||
#define THCTR_PONM BIT(6)
|
||||
#define THCTR_THSST BIT(0)
|
||||
|
||||
/* THSCP bits */
|
||||
#define THSCP_COR_PARA_VLD (BIT(15) | BIT(14))
|
||||
|
||||
#define CTEMP_MASK 0xFFF
|
||||
|
||||
#define MCELSIUS(temp) ((temp) * 1000)
|
||||
|
@ -62,15 +69,6 @@
|
|||
|
||||
#define TSC_MAX_NUM 5
|
||||
|
||||
/* default THCODE values if FUSEs are missing */
|
||||
static const int thcodes[TSC_MAX_NUM][3] = {
|
||||
{ 3397, 2800, 2221 },
|
||||
{ 3393, 2795, 2216 },
|
||||
{ 3389, 2805, 2237 },
|
||||
{ 3415, 2694, 2195 },
|
||||
{ 3356, 2724, 2244 },
|
||||
};
|
||||
|
||||
/* Structure for thermal temperature calculation */
|
||||
struct equation_coefs {
|
||||
int a1;
|
||||
|
@ -84,13 +82,14 @@ struct rcar_gen3_thermal_tsc {
|
|||
struct thermal_zone_device *zone;
|
||||
struct equation_coefs coef;
|
||||
int tj_t;
|
||||
unsigned int id; /* thermal channel id */
|
||||
int thcode[3];
|
||||
};
|
||||
|
||||
struct rcar_gen3_thermal_priv {
|
||||
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
|
||||
unsigned int num_tscs;
|
||||
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
|
||||
int ptat[3];
|
||||
};
|
||||
|
||||
static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
|
||||
|
@ -133,8 +132,8 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
|
|||
/* no idea where these constants come from */
|
||||
#define TJ_3 -41
|
||||
|
||||
static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
|
||||
int *ptat, const int *thcode,
|
||||
static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_priv *priv,
|
||||
struct rcar_gen3_thermal_tsc *tsc,
|
||||
int ths_tj_1)
|
||||
{
|
||||
/* TODO: Find documentation and document constant calculation formula */
|
||||
|
@ -143,16 +142,16 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
|
|||
* 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((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3))
|
||||
/ (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3);
|
||||
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(thcode[1] - thcode[2]),
|
||||
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(thcode[2]) - tsc->coef.a1 * TJ_3;
|
||||
tsc->coef.b1 = FIXPT_INT(tsc->thcode[2]) - tsc->coef.a1 * TJ_3;
|
||||
|
||||
tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
|
||||
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(thcode[0]) - tsc->coef.a2 * ths_tj_1;
|
||||
tsc->coef.b2 = FIXPT_INT(tsc->thcode[0]) - tsc->coef.a2 * ths_tj_1;
|
||||
}
|
||||
|
||||
static int rcar_gen3_thermal_round(int temp)
|
||||
|
@ -174,7 +173,7 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
|
|||
/* Read register and convert to mili Celsius */
|
||||
reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
|
||||
|
||||
if (reg <= thcodes[tsc->id][1])
|
||||
if (reg <= tsc->thcode[1])
|
||||
val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1,
|
||||
tsc->coef.a1);
|
||||
else
|
||||
|
@ -253,6 +252,64 @@ static const struct soc_device_attribute r8a7795es1[] = {
|
|||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static bool rcar_gen3_thermal_read_fuses(struct rcar_gen3_thermal_priv *priv)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 thscp;
|
||||
|
||||
/* If fuses are not set, fallback to pseudo values. */
|
||||
thscp = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_THSCP);
|
||||
if ((thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) {
|
||||
/* Default THCODE values in case FUSEs are not set. */
|
||||
static const int thcodes[TSC_MAX_NUM][3] = {
|
||||
{ 3397, 2800, 2221 },
|
||||
{ 3393, 2795, 2216 },
|
||||
{ 3389, 2805, 2237 },
|
||||
{ 3415, 2694, 2195 },
|
||||
{ 3356, 2724, 2244 },
|
||||
};
|
||||
|
||||
priv->ptat[0] = 2631;
|
||||
priv->ptat[1] = 1509;
|
||||
priv->ptat[2] = 435;
|
||||
|
||||
for (i = 0; i < priv->num_tscs; i++) {
|
||||
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
|
||||
|
||||
tsc->thcode[0] = thcodes[i][0];
|
||||
tsc->thcode[1] = thcodes[i][1];
|
||||
tsc->thcode[2] = thcodes[i][2];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the pseudo calibration points with fused values.
|
||||
* PTAT is shared between all TSCs but only fused for the first
|
||||
* TSC while THCODEs are fused for each TSC.
|
||||
*/
|
||||
priv->ptat[0] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT1) &
|
||||
GEN3_FUSE_MASK;
|
||||
priv->ptat[1] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT2) &
|
||||
GEN3_FUSE_MASK;
|
||||
priv->ptat[2] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT3) &
|
||||
GEN3_FUSE_MASK;
|
||||
|
||||
for (i = 0; i < priv->num_tscs; i++) {
|
||||
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
|
||||
|
||||
tsc->thcode[0] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE1) &
|
||||
GEN3_FUSE_MASK;
|
||||
tsc->thcode[1] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE2) &
|
||||
GEN3_FUSE_MASK;
|
||||
tsc->thcode[2] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE3) &
|
||||
GEN3_FUSE_MASK;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)
|
||||
{
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR);
|
||||
|
@ -401,10 +458,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* default values if FUSEs are missing */
|
||||
/* TODO: Read values from hardware on supported platforms */
|
||||
int ptat[3] = { 2631, 1509, 435 };
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
@ -439,9 +492,17 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
ret = PTR_ERR(tsc->base);
|
||||
goto error_unregister;
|
||||
}
|
||||
tsc->id = i;
|
||||
|
||||
priv->tscs[i] = tsc;
|
||||
}
|
||||
|
||||
priv->num_tscs = i;
|
||||
|
||||
if (!rcar_gen3_thermal_read_fuses(priv))
|
||||
dev_info(dev, "No calibration values fused, fallback to driver values\n");
|
||||
|
||||
for (i = 0; i < priv->num_tscs; i++) {
|
||||
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
|
||||
|
||||
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
|
||||
&rcar_gen3_tz_of_ops);
|
||||
|
@ -453,7 +514,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
tsc->zone = zone;
|
||||
|
||||
priv->thermal_init(tsc);
|
||||
rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
|
||||
rcar_gen3_thermal_calc_coefs(priv, tsc, *ths_tj_1);
|
||||
|
||||
tsc->zone->tzp->no_hwmon = false;
|
||||
ret = thermal_add_hwmon_sysfs(tsc->zone);
|
||||
|
@ -471,8 +532,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
dev_info(dev, "TSC%u: Loaded %d trip points\n", i, ret);
|
||||
}
|
||||
|
||||
priv->num_tscs = i;
|
||||
|
||||
if (!priv->num_tscs) {
|
||||
ret = -ENODEV;
|
||||
goto error_unregister;
|
||||
|
|
|
@ -1383,7 +1383,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(thermal->regs))
|
||||
return PTR_ERR(thermal->regs);
|
||||
|
||||
thermal->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb");
|
||||
thermal->reset = devm_reset_control_array_get(&pdev->dev, false, false);
|
||||
if (IS_ERR(thermal->reset)) {
|
||||
error = PTR_ERR(thermal->reset);
|
||||
dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error);
|
||||
|
|
|
@ -375,10 +375,12 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
|
|||
if (tz->last_temperature != THERMAL_TEMP_INVALID) {
|
||||
if (tz->last_temperature < trip_temp &&
|
||||
tz->temperature >= trip_temp)
|
||||
thermal_notify_tz_trip_up(tz->id, trip);
|
||||
thermal_notify_tz_trip_up(tz->id, trip,
|
||||
tz->temperature);
|
||||
if (tz->last_temperature >= trip_temp &&
|
||||
tz->temperature < (trip_temp - hyst))
|
||||
thermal_notify_tz_trip_down(tz->id, trip);
|
||||
thermal_notify_tz_trip_down(tz->id, trip,
|
||||
tz->temperature);
|
||||
}
|
||||
|
||||
if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
|
||||
|
@ -887,7 +889,7 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct thermal_zone_device *pos = NULL;
|
||||
int ret;
|
||||
int id, ret;
|
||||
|
||||
if (!ops || !ops->get_max_state || !ops->get_cur_state ||
|
||||
!ops->set_cur_state)
|
||||
|
@ -901,6 +903,11 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
if (ret < 0)
|
||||
goto out_kfree_cdev;
|
||||
cdev->id = ret;
|
||||
id = ret;
|
||||
|
||||
ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
|
||||
if (ret)
|
||||
goto out_ida_remove;
|
||||
|
||||
cdev->type = kstrdup(type ? type : "", GFP_KERNEL);
|
||||
if (!cdev->type) {
|
||||
|
@ -916,7 +923,6 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
cdev->device.class = &thermal_class;
|
||||
cdev->devdata = devdata;
|
||||
thermal_cooling_device_setup_sysfs(cdev);
|
||||
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
|
||||
ret = device_register(&cdev->device);
|
||||
if (ret)
|
||||
goto out_kfree_type;
|
||||
|
@ -941,8 +947,9 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
out_kfree_type:
|
||||
kfree(cdev->type);
|
||||
put_device(&cdev->device);
|
||||
cdev = NULL;
|
||||
out_ida_remove:
|
||||
ida_simple_remove(&thermal_cdev_ida, cdev->id);
|
||||
ida_simple_remove(&thermal_cdev_ida, id);
|
||||
out_kfree_cdev:
|
||||
kfree(cdev);
|
||||
return ERR_PTR(ret);
|
||||
|
@ -1227,6 +1234,10 @@ thermal_zone_device_register(const char *type, int trips, int mask,
|
|||
tz->id = id;
|
||||
strlcpy(tz->type, type, sizeof(tz->type));
|
||||
|
||||
result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);
|
||||
if (result)
|
||||
goto remove_id;
|
||||
|
||||
if (!ops->critical)
|
||||
ops->critical = thermal_zone_device_critical;
|
||||
|
||||
|
@ -1248,7 +1259,6 @@ thermal_zone_device_register(const char *type, int trips, int mask,
|
|||
/* A new thermal zone needs to be updated anyway. */
|
||||
atomic_set(&tz->need_update, 1);
|
||||
|
||||
dev_set_name(&tz->device, "thermal_zone%d", tz->id);
|
||||
result = device_register(&tz->device);
|
||||
if (result)
|
||||
goto release_device;
|
||||
|
|
|
@ -34,7 +34,7 @@ static int thermal_mmio_get_temperature(void *private, int *temp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_of_device_ops thermal_mmio_ops = {
|
||||
static const struct thermal_zone_of_device_ops thermal_mmio_ops = {
|
||||
.get_temp = thermal_mmio_get_temperature,
|
||||
};
|
||||
|
||||
|
|
|
@ -121,7 +121,8 @@ static int thermal_genl_event_tz(struct param *p)
|
|||
static int thermal_genl_event_tz_trip_up(struct param *p)
|
||||
{
|
||||
if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
|
||||
nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
|
||||
nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
|
||||
nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
|
@ -285,16 +286,16 @@ int thermal_notify_tz_disable(int tz_id)
|
|||
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
|
||||
}
|
||||
|
||||
int thermal_notify_tz_trip_down(int tz_id, int trip_id)
|
||||
int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp)
|
||||
{
|
||||
struct param p = { .tz_id = tz_id, .trip_id = trip_id };
|
||||
struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
|
||||
|
||||
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
|
||||
}
|
||||
|
||||
int thermal_notify_tz_trip_up(int tz_id, int trip_id)
|
||||
int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp)
|
||||
{
|
||||
struct param p = { .tz_id = tz_id, .trip_id = trip_id };
|
||||
struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
|
||||
|
||||
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ int thermal_notify_tz_create(int tz_id, const char *name);
|
|||
int thermal_notify_tz_delete(int tz_id);
|
||||
int thermal_notify_tz_enable(int tz_id);
|
||||
int thermal_notify_tz_disable(int tz_id);
|
||||
int thermal_notify_tz_trip_down(int tz_id, int id);
|
||||
int thermal_notify_tz_trip_up(int tz_id, int id);
|
||||
int thermal_notify_tz_trip_down(int tz_id, int id, int temp);
|
||||
int thermal_notify_tz_trip_up(int tz_id, int id, int temp);
|
||||
int thermal_notify_tz_trip_delete(int tz_id, int id);
|
||||
int thermal_notify_tz_trip_add(int tz_id, int id, int type,
|
||||
int temp, int hyst);
|
||||
|
@ -49,12 +49,12 @@ static inline int thermal_notify_tz_disable(int tz_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_notify_tz_trip_down(int tz_id, int id)
|
||||
static inline int thermal_notify_tz_trip_down(int tz_id, int id, int temp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_notify_tz_trip_up(int tz_id, int id)
|
||||
static inline int thermal_notify_tz_trip_up(int tz_id, int id, int temp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -610,6 +610,9 @@ cur_state_store(struct device *dev, struct device_attribute *attr,
|
|||
unsigned long state;
|
||||
int result;
|
||||
|
||||
dev_warn_once(&cdev->device,
|
||||
"Setting cooling device state is deprecated\n");
|
||||
|
||||
if (sscanf(buf, "%ld\n", &state) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -358,6 +358,10 @@ static const struct of_device_id uniphier_tm_dt_ids[] = {
|
|||
.compatible = "socionext,uniphier-pxs3-thermal",
|
||||
.data = &uniphier_ld20_tm_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-thermal",
|
||||
.data = &uniphier_ld20_tm_data,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids);
|
||||
|
|
Загрузка…
Ссылка в новой задаче