mirror of
https://github.com/torvalds/linux.git
synced 2026-10-23 15:32:04 +02:00
Merge branch 'thermal-drivers'
Merge updates of assorted thermal control drivers for 7.4: - Add the Exynos ACPM thermal driver for Google GS101, along with DT bindings and a MAINTAINERS entry (Tudor Ambarus) - Add Renesas RZ/G3L thermal sensor support and DT bindings, and move default calibration values to per-SoC match data (Biju Das) - Add Qualcomm MSM8952 TSENS support and the corresponding DT binding compatible (Muzaffer Kadir) - Document the Qualcomm PMAU0102 Master BandGap temperature monitor compatible in the DT bindings (Dhruvin Rajpura) - Extend the QCom TSENS v2 trip temperature limits to the hardware range of -204°C to +204°C to prevent interrupt storms when operating beyond the previous software limits (Priyansh Jain) - Fix temperature threshold map indexing in the QCom SPMI temperature alarm driver to prevent out-of-bounds reads (Georgi Djakov) - Describe the additional bus clock required by the Amlogic T7 thermal sensor and switch the driver to the clk_bulk API to manage multiple clocks (Ronald Claveau) - Request the Airoha EN7581 IRQ after thermal zone registration to prevent the interrupt handler from accessing an unregistered or already freed thermal zone (Vitaliy Sochnev) - Fix the Airoha AN7583 ADC mux field mapping, serialize access to the shared ADC, and verify mux selection to avoid invalid temperature readings and spurious critical shutdowns (Vitaliy Sochnev) - Register separate thermal zones for the AN7583 bandgap, GbE and CPU sensors, and update the DT bindings to use one thermal sensor cell to select the sensor (Vitaliy Sochnev) - Fix signed integer overflow in the Renesas RZ/G3E temperature-to-code conversion, preserve compare interrupt state across runtime PM, and prevent overlapping temperature conversions (Ovidiu Panait) - Remove redundant trip window validation and runtime PM pm_runtime_mark_last_busy() calls from the Renesas RZ/G3E driver (Ovidiu Panait) - Propagate reset assertion failures from Renesas RZ/G3E suspend and attempt to restore power if the sensor was active (Pengpeng Hou) - Stop the TI bandgap alert IRQ before removing sensor interfaces and cancel pending alert work to prevent use-after-free on driver removal (Weigang He) - Validate Spreadtrum sensor IDs read from the device tree before using them for register offsets and array indexing (Weigang He) - Convert the TI OMAP bandgap DT bindings to schema and document the DRA752 compatible and thermal sensor cells (Bhargav Joshi) - Use DT property helpers matching the signed temperature and unsigned hysteresis types defined by the thermal zone bindings (Rob Herring) - Reuse common error handling code in the power allocator governor bind callback (Markus Elfring) - Constify the thermal zone device operations in the i.MX9 driver (Christophe JAILLET) - Fix kernel-doc parameter names and firmware node references in the cooling device registration helpers (Aryan Sinha) - Correct the documented return value of ti_bandgap_get_sensor_data() to describe validation errors and potentially NULL stored data (Karl Mehltretter) - Ensure NUL-termination when copying the cooling device command-line argument in tmon and fix the associated string truncation warning (Florian Fainelli) - Fix undefined behavior caused by a signed shift in the tmon thermal zone binding display (Liu Jing) - Fix wording in tmon comments (Hemanth Selam) - Simplify cpufreq_set_cur_state() in the cpufreq_cooling thermal control driver (Thorsten Blum) * thermal-drivers: (36 commits) thermal/drivers/rzg3e: Propagate reset assertion failure from suspend thermal: ti-soc-thermal: Fix the return value in ti_bandgap_get_sensor_data() kernel-doc thermal/fw: Fix kernel-doc parameter names thermal/qcom/tsens: Add support for MSM8952 tsens dt-bindings: thermal: tsens: Add MSM8952 thermal/drivers/amlogic: Switch to clk_bulk API to support multiple clocks dt-bindings: thermal: amlogic: describe bus clock for t7-thermal tools/thermal/tmon: Fix string truncation warning in optarg copy thermal/drivers/airoha: Register a thermal zone per AN7583 sensor dt-bindings: arm: airoha: Use one thermal sensor cell for AN7583 thermal/drivers/airoha: Serialise access to the shared ADC thermal/drivers/airoha: Fix AN7583 ADC mux field mapping thermal/drivers/sprd: validate the sensor id from the device tree thermal/drivers/ti-soc-thermal: Cancel pending alert work on remove thermal/drivers/qcom-spmi-temp-alarm: Fix temp_map indexing thermal: gov_power_allocator: Use common error handling code in power_allocator_bind() tools/thermal/tmon: Fix signed shift UB in binding display MAINTAINERS: Add entry for Samsung Exynos ACPM thermal driver thermal/drivers/samsung: Add Exynos ACPM TMU driver GS101 dt-bindings: thermal: Add Google GS101 TMU ...
This commit is contained in:
commit
503bb6e70b
|
|
@ -26,7 +26,8 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
'#thermal-sensor-cells':
|
||||
const: 0
|
||||
description: Sensor index, 0 bandgap, 1 GbE, 2 CPU.
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
|
|||
|
|
@ -32,7 +32,15 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
items:
|
||||
- description: Bus clock, gates register access to the sensor.
|
||||
- description: Functional clock of the temperature sensor, shared between sensors.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: core
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
|
@ -72,6 +80,22 @@ allOf:
|
|||
else:
|
||||
required:
|
||||
- amlogic,secure-monitor
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: amlogic,t7-thermal
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
required:
|
||||
- clock-names
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
@ -94,7 +118,8 @@ examples:
|
|||
compatible = "amlogic,t7-thermal";
|
||||
reg = <0x20000 0x50>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clkc_periphs CLKID_TS>;
|
||||
clocks = <&clkc_periphs CLKID_SYS_TS_A73>, <&clkc_periphs CLKID_TS>;
|
||||
clock-names = "bus", "core";
|
||||
#thermal-sensor-cells = <0>;
|
||||
amlogic,secure-monitor = <&sm 1>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/google,gs101-tmu-top.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung Exynos ACPM Thermal Management Unit (TMU)
|
||||
|
||||
maintainers:
|
||||
- Tudor Ambarus <tudor.ambarus@linaro.org>
|
||||
|
||||
description:
|
||||
The Samsung Exynos ACPM TMU is a thermal sensor block found on Exynos
|
||||
based platforms (such as Google GS101 and Exynos850). It supports
|
||||
both direct register-level access and firmware-mediated management
|
||||
via the ACPM (Alive Clock and Power Manager) firmware.
|
||||
|
||||
On these platforms, the hardware is managed in a hybrid fashion. The
|
||||
Application Processor (AP) maintains direct memory-mapped access
|
||||
exclusively to the interrupt pending registers to identify thermal
|
||||
events. All other functional aspects - including sensor
|
||||
initialization, threshold configuration, and temperature acquisition
|
||||
- are handled by the ACPM firmware. The AP coordinates these
|
||||
operations through the ACPM IPC protocol.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: google,gs101-tmu-top
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: APB peripheral clock (PCLK) for TMU register access.
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
||||
samsung,acpm-ipc:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the ACPM IPC node.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
- "#thermal-sensor-cells"
|
||||
- samsung,acpm-ipc
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/google,gs101.h>
|
||||
|
||||
thermal-sensor@100a0000 {
|
||||
compatible = "google,gs101-tmu-top";
|
||||
reg = <0x100a0000 0x800>;
|
||||
clocks = <&cmu_misc CLK_GOUT_MISC_TMU_TOP_PCLK>;
|
||||
interrupts = <GIC_SPI 769 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
samsung,acpm-ipc = <&acpm_ipc>;
|
||||
};
|
||||
|
|
@ -21,7 +21,12 @@ description:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,pm8775-mbg-tm
|
||||
oneOf:
|
||||
- const: qcom,pm8775-mbg-tm
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,pmau0102-mbg-tm
|
||||
- const: qcom,pm8775-mbg-tm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ properties:
|
|||
items:
|
||||
- enum:
|
||||
- qcom,msm8937-tsens
|
||||
- qcom,msm8952-tsens
|
||||
- qcom,msm8956-tsens
|
||||
- qcom,msm8976-tsens
|
||||
- qcom,qcs404-tsens
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ $ref: thermal-sensor.yaml#
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: renesas,r9a08g045-tsu
|
||||
enum:
|
||||
- renesas,r9a08g045-tsu
|
||||
- renesas,r9a08g046-tsu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
177
Documentation/devicetree/bindings/thermal/ti,omap-bandgap.yaml
Normal file
177
Documentation/devicetree/bindings/thermal/ti,omap-bandgap.yaml
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/ti,omap-bandgap.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments OMAP SCM bandgap
|
||||
|
||||
maintainers:
|
||||
- Eduardo Valentin <edubezval@gmail.com>
|
||||
|
||||
description:
|
||||
In the System Control Module, OMAP supplies a voltage reference and a
|
||||
temperature sensor feature that are gathered in the band gap voltage and
|
||||
temperature sensor (VBGAPTS) module. The band gap provides current and
|
||||
voltage reference for its internal circuits and other analog IP blocks. The
|
||||
analog-to-digital converter (ADC) produces an output value that is
|
||||
proportional to the silicon temperature.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,omap34xx-bandgap
|
||||
- ti,omap36xx-bandgap
|
||||
- ti,omap4430-bandgap
|
||||
- ti,omap4460-bandgap
|
||||
- ti,omap4470-bandgap
|
||||
- ti,omap5430-bandgap
|
||||
- ti,dra752-bandgap
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
used to inform which GPIO line the tshut signal is routed to. The
|
||||
informed GPIO will be treated as an IRQ;
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
enum: [0, 1]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- $ref: thermal-sensor.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- ti,omap34xx-bandgap
|
||||
- ti,omap36xx-bandgap
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
|
||||
interrupts: false
|
||||
|
||||
gpios: false
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 0
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,omap4430-bandgap
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
interrupts: false
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- gpios
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- ti,omap4460-bandgap
|
||||
- ti,omap4470-bandgap
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- interrupts
|
||||
- gpios
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,omap5430-bandgap
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
|
||||
gpios: false
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- interrupts
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,dra752-bandgap
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
|
||||
gpios: false
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bandgap@48002524 {
|
||||
compatible = "ti,omap34xx-bandgap";
|
||||
reg = <0x48002524 0x4>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
bandgap@4a0021e0 {
|
||||
compatible = "ti,dra752-bandgap";
|
||||
reg = <0x4a0021e0 0xc>, <0x4a00232c 0xc>,
|
||||
<0x4a002380 0x2c>, <0x4a0023c0 0x3c>,
|
||||
<0x4a002564 0x8>, <0x4a002574 0x50>;
|
||||
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>; /* talert */
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
* Texas Instrument OMAP SCM bandgap bindings
|
||||
|
||||
In the System Control Module, OMAP supplies a voltage reference
|
||||
and a temperature sensor feature that are gathered in the band
|
||||
gap voltage and temperature sensor (VBGAPTS) module. The band
|
||||
gap provides current and voltage reference for its internal
|
||||
circuits and other analog IP blocks. The analog-to-digital
|
||||
converter (ADC) produces an output value that is proportional
|
||||
to the silicon temperature.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be:
|
||||
- "ti,omap34xx-bandgap" : for OMAP34xx bandgap
|
||||
- "ti,omap36xx-bandgap" : for OMAP36xx bandgap
|
||||
- "ti,omap4430-bandgap" : for OMAP4430 bandgap
|
||||
- "ti,omap4460-bandgap" : for OMAP4460 bandgap
|
||||
- "ti,omap4470-bandgap" : for OMAP4470 bandgap
|
||||
- "ti,omap5430-bandgap" : for OMAP5430 bandgap
|
||||
- interrupts : this entry should indicate which interrupt line
|
||||
the talert signal is routed to;
|
||||
Specific:
|
||||
- gpios : this entry should be used to inform which GPIO
|
||||
line the tshut signal is routed to. The informed GPIO will
|
||||
be treated as an IRQ;
|
||||
- regs : this entry must also be specified and it is specific
|
||||
to each bandgap version, because the mapping may change from
|
||||
soc to soc, apart of depending on available features.
|
||||
|
||||
Example:
|
||||
OMAP34xx:
|
||||
bandgap {
|
||||
reg = <0x48002524 0x4>;
|
||||
compatible = "ti,omap34xx-bandgap";
|
||||
};
|
||||
|
||||
OMAP36xx:
|
||||
bandgap {
|
||||
reg = <0x48002524 0x4>;
|
||||
compatible = "ti,omap36xx-bandgap";
|
||||
};
|
||||
|
||||
OMAP4430:
|
||||
bandgap {
|
||||
reg = <0x4a002260 0x4 0x4a00232C 0x4>;
|
||||
compatible = "ti,omap4430-bandgap";
|
||||
};
|
||||
|
||||
OMAP4460:
|
||||
bandgap {
|
||||
reg = <0x4a002260 0x4
|
||||
0x4a00232C 0x4
|
||||
0x4a002378 0x18>;
|
||||
compatible = "ti,omap4460-bandgap";
|
||||
interrupts = <0 126 4>; /* talert */
|
||||
gpios = <&gpio3 22 0>; /* tshut */
|
||||
};
|
||||
|
||||
OMAP4470:
|
||||
bandgap {
|
||||
reg = <0x4a002260 0x4
|
||||
0x4a00232C 0x4
|
||||
0x4a002378 0x18>;
|
||||
compatible = "ti,omap4470-bandgap";
|
||||
interrupts = <0 126 4>; /* talert */
|
||||
gpios = <&gpio3 22 0>; /* tshut */
|
||||
};
|
||||
|
||||
OMAP5430:
|
||||
bandgap {
|
||||
reg = <0x4a0021e0 0xc
|
||||
0x4a00232c 0xc
|
||||
0x4a002380 0x2c
|
||||
0x4a0023C0 0x3c>;
|
||||
compatible = "ti,omap5430-bandgap";
|
||||
interrupts = <0 126 4>; /* talert */
|
||||
};
|
||||
|
||||
DRA752:
|
||||
bandgap {
|
||||
reg = <0x4a0021e0 0xc
|
||||
0x4a00232c 0xc
|
||||
0x4a002380 0x2c
|
||||
0x4a0023C0 0x3c
|
||||
0x4a002564 0x8
|
||||
0x4a002574 0x50>;
|
||||
compatible = "ti,dra752-bandgap";
|
||||
interrupts = <0 126 4>; /* talert */
|
||||
};
|
||||
|
|
@ -24294,6 +24294,14 @@ F: drivers/clk/samsung/clk-acpm.c
|
|||
F: drivers/firmware/samsung/exynos-acpm*
|
||||
F: include/linux/firmware/samsung/exynos-acpm-protocol.h
|
||||
|
||||
SAMSUNG EXYNOS ACPM THERMAL DRIVER
|
||||
M: Tudor Ambarus <tudor.ambarus@linaro.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
L: linux-samsung-soc@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/thermal/google,gs101-tmu-top.yaml
|
||||
F: drivers/thermal/samsung/acpm-tmu.c
|
||||
|
||||
SAMSUNG EXYNOS MAILBOX DRIVER
|
||||
M: Tudor Ambarus <tudor.ambarus@linaro.org>
|
||||
L: linux-samsung-soc@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -18,10 +19,10 @@
|
|||
#define EN7581_DOUT_TADC 0x2f8
|
||||
#define EN7581_DOUT_TADC_MASK GENMASK(15, 0)
|
||||
|
||||
#define AN7583_MUX_SENSOR 0x2a0
|
||||
#define AN7583_MUX_TADC 0x2a0
|
||||
#define AN7583_LOAD_ADJ GENMASK(3, 2)
|
||||
#define AN7583_MUX_TADC 0x2e4
|
||||
#define AN7583_MUX_TADC_MASK GENMASK(3, 1)
|
||||
#define AN7583_MUX_SENSOR 0x2e4
|
||||
#define AN7583_MUX_SENSOR_MASK GENMASK(3, 1)
|
||||
#define AN7583_DOUT_TADC 0x2f0
|
||||
|
||||
/* PTP_THERMAL regs */
|
||||
|
|
@ -191,6 +192,7 @@
|
|||
#define AN7583_NUM_SENSOR 3
|
||||
|
||||
#define AIROHA_THERMAL_NO_MUX_SENSOR -1
|
||||
#define AIROHA_THERMAL_MUX_TRIES 3
|
||||
|
||||
/* Convert temp to raw value as read from ADC ((((temp / 100) - init) * slope) / 1000) + offset */
|
||||
#define TEMP_TO_RAW(priv, temp) ((((((temp) / 100) - (priv)->init_temp) * \
|
||||
|
|
@ -243,6 +245,11 @@ enum airoha_thermal_chip_scu_field {
|
|||
AIROHA_THERMAL_FIELD_MAX,
|
||||
};
|
||||
|
||||
struct airoha_thermal_zone {
|
||||
struct airoha_thermal_priv *priv;
|
||||
int sensor;
|
||||
};
|
||||
|
||||
struct airoha_thermal_priv {
|
||||
struct regmap *map;
|
||||
struct regmap *chip_scu;
|
||||
|
|
@ -250,7 +257,8 @@ struct airoha_thermal_priv {
|
|||
struct resource scu_adc_res;
|
||||
|
||||
u32 pllrg_protect;
|
||||
int current_adc;
|
||||
/* Serialises mux selection and ADC sampling */
|
||||
struct mutex lock;
|
||||
|
||||
struct thermal_zone_device *tz;
|
||||
int init_temp;
|
||||
|
|
@ -260,6 +268,9 @@ struct airoha_thermal_priv {
|
|||
|
||||
struct airoha_thermal_soc_data {
|
||||
u32 pllrg_protect;
|
||||
/* Sensor mux value per zone, NULL without a sensor mux */
|
||||
const int *sensors;
|
||||
int num_sensors;
|
||||
|
||||
const struct thermal_zone_device_ops *thdev_ops;
|
||||
int (*probe)(struct platform_device *pdev,
|
||||
|
|
@ -294,9 +305,26 @@ static int airoha_get_thermal_ADC(struct airoha_thermal_priv *priv)
|
|||
return val;
|
||||
}
|
||||
|
||||
static bool airoha_thermal_mux_holds(struct airoha_thermal_priv *priv,
|
||||
int tdac_idx, int sensor_idx)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (regmap_field_read(priv->chip_scu_fields[AIROHA_THERMAL_MUX_TADC], &val) ||
|
||||
val != tdac_idx)
|
||||
return false;
|
||||
|
||||
if (sensor_idx == AIROHA_THERMAL_NO_MUX_SENSOR)
|
||||
return true;
|
||||
|
||||
return !regmap_field_read(priv->chip_scu_fields[AIROHA_THERMAL_MUX_SENSOR], &val) &&
|
||||
val == sensor_idx;
|
||||
}
|
||||
|
||||
static void airoha_set_thermal_mux(struct airoha_thermal_priv *priv,
|
||||
int tdac_idx, int sensor_idx)
|
||||
{
|
||||
int tries = AIROHA_THERMAL_MUX_TRIES;
|
||||
u32 pllrg;
|
||||
|
||||
/* Save PLLRG current value */
|
||||
|
|
@ -307,19 +335,17 @@ static void airoha_set_thermal_mux(struct airoha_thermal_priv *priv,
|
|||
priv->pllrg_protect);
|
||||
|
||||
/*
|
||||
* Configure Thermal Sensor mux to sensor_idx.
|
||||
* Configure Thermal Sensor mux to sensor_idx and Thermal ADC mux to
|
||||
* tdac_idx. Writes can be dropped silently, so read them back.
|
||||
* (if not supported, sensor_idx is AIROHA_THERMAL_NO_MUX_SENSOR)
|
||||
*/
|
||||
if (sensor_idx != AIROHA_THERMAL_NO_MUX_SENSOR)
|
||||
regmap_field_write(priv->chip_scu_fields[AIROHA_THERMAL_MUX_SENSOR],
|
||||
sensor_idx);
|
||||
|
||||
/* Configure Thermal ADC mux to tdac_idx */
|
||||
if (priv->current_adc != tdac_idx) {
|
||||
do {
|
||||
if (sensor_idx != AIROHA_THERMAL_NO_MUX_SENSOR)
|
||||
regmap_field_write(priv->chip_scu_fields[AIROHA_THERMAL_MUX_SENSOR],
|
||||
sensor_idx);
|
||||
regmap_field_write(priv->chip_scu_fields[AIROHA_THERMAL_MUX_TADC],
|
||||
tdac_idx);
|
||||
priv->current_adc = tdac_idx;
|
||||
}
|
||||
} while (!airoha_thermal_mux_holds(priv, tdac_idx, sensor_idx) && --tries);
|
||||
|
||||
/* Restore PLLRG value on exit */
|
||||
regmap_write(priv->chip_scu, EN7581_PLLRG_PROTECT, pllrg);
|
||||
|
|
@ -330,7 +356,8 @@ static void airoha_set_thermal_mux(struct airoha_thermal_priv *priv,
|
|||
|
||||
static int en7581_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
|
||||
struct airoha_thermal_zone *zone = thermal_zone_device_priv(tz);
|
||||
struct airoha_thermal_priv *priv = zone->priv;
|
||||
int min_value, max_value, avg_value, value;
|
||||
int i;
|
||||
|
||||
|
|
@ -356,7 +383,8 @@ static int en7581_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
static int en7581_thermal_set_trips(struct thermal_zone_device *tz, int low,
|
||||
int high)
|
||||
{
|
||||
struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
|
||||
struct airoha_thermal_zone *zone = thermal_zone_device_priv(tz);
|
||||
struct airoha_thermal_priv *priv = zone->priv;
|
||||
bool enable_monitor = false;
|
||||
|
||||
if (high != INT_MAX) {
|
||||
|
|
@ -528,7 +556,7 @@ static int en7581_thermal_probe(struct platform_device *pdev,
|
|||
struct device_node *chip_scu_np;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *base;
|
||||
int i, irq, ret;
|
||||
int i;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
|
|
@ -567,6 +595,18 @@ static int en7581_thermal_probe(struct platform_device *pdev,
|
|||
of_address_to_resource(chip_scu_np, 0, &priv->scu_adc_res);
|
||||
of_node_put(chip_scu_np);
|
||||
|
||||
en7581_thermal_setup_monitor(priv);
|
||||
en7581_thermal_setup_adc_val(dev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en7581_thermal_post_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct airoha_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||
int irq, ret;
|
||||
|
||||
/* After zone registration: the handler uses priv->tz */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
|
@ -577,16 +617,6 @@ static int en7581_thermal_probe(struct platform_device *pdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
en7581_thermal_setup_monitor(priv);
|
||||
en7581_thermal_setup_adc_val(dev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en7581_thermal_post_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct airoha_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
/* Enable LOW and HIGH interrupt (if supported) */
|
||||
regmap_write(priv->map, EN7581_TEMPMONINT,
|
||||
EN7581_HOFSINTEN0 | EN7581_LOFSINTEN0);
|
||||
|
|
@ -594,28 +624,56 @@ static int en7581_thermal_post_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int an7583_thermal_read_diode(struct airoha_thermal_priv *priv,
|
||||
int diode, int sensor_idx, int *val)
|
||||
{
|
||||
airoha_set_thermal_mux(priv, diode, sensor_idx);
|
||||
*val = airoha_get_thermal_ADC(priv);
|
||||
|
||||
return airoha_thermal_mux_holds(priv, diode, sensor_idx) ? 0 : -EAGAIN;
|
||||
}
|
||||
|
||||
static int an7583_thermal_read_diodes(struct airoha_thermal_priv *priv,
|
||||
int sensor_idx, int *zero, int *d0,
|
||||
int *d1)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = an7583_thermal_read_diode(priv, AN7583_ZERO_TADC, sensor_idx, zero);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = an7583_thermal_read_diode(priv, AN7583_D0_TADC, sensor_idx, d0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return an7583_thermal_read_diode(priv, AN7583_D1_TADC, sensor_idx, d1);
|
||||
}
|
||||
|
||||
static int an7583_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
|
||||
int sensor_idx;
|
||||
struct airoha_thermal_zone *zone = thermal_zone_device_priv(tz);
|
||||
struct airoha_thermal_priv *priv = zone->priv;
|
||||
int sensor_idx = zone->sensor;
|
||||
int delta_diode, delta_gain;
|
||||
int coeff, slope, offset;
|
||||
int tries = AIROHA_THERMAL_MUX_TRIES;
|
||||
int ret;
|
||||
|
||||
int diode_zero, diode_d0, diode_d1;
|
||||
|
||||
/* Always read sensor AN7583_BGP_TEMP_SENSOR */
|
||||
sensor_idx = AN7583_BGP_TEMP_SENSOR;
|
||||
|
||||
coeff = an7583_thermal_coeff[sensor_idx];
|
||||
slope = an7583_thermal_slope[sensor_idx];
|
||||
offset = an7583_thermal_offset[sensor_idx];
|
||||
|
||||
airoha_set_thermal_mux(priv, AN7583_ZERO_TADC, sensor_idx);
|
||||
diode_zero = airoha_get_thermal_ADC(priv);
|
||||
airoha_set_thermal_mux(priv, AN7583_D0_TADC, sensor_idx);
|
||||
diode_d0 = airoha_get_thermal_ADC(priv);
|
||||
airoha_set_thermal_mux(priv, AN7583_D1_TADC, sensor_idx);
|
||||
diode_d1 = airoha_get_thermal_ADC(priv);
|
||||
mutex_lock(&priv->lock);
|
||||
do {
|
||||
ret = an7583_thermal_read_diodes(priv, sensor_idx, &diode_zero,
|
||||
&diode_d0, &diode_d1);
|
||||
} while (ret == -EAGAIN && --tries);
|
||||
mutex_unlock(&priv->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
delta_diode = diode_d1 - diode_d0;
|
||||
delta_gain = (delta_diode * coeff) / 100 + (diode_zero - diode_d1);
|
||||
|
|
@ -634,8 +692,8 @@ static const struct thermal_zone_device_ops an7583_tz_ops = {
|
|||
|
||||
static const struct reg_field an7583_chip_scu_fields[AIROHA_THERMAL_FIELD_MAX] = {
|
||||
[AIROHA_THERMAL_DOUT_TADC] = REG_FIELD(AN7583_DOUT_TADC, 0, 31),
|
||||
[AIROHA_THERMAL_MUX_TADC] = REG_FIELD(AN7583_MUX_TADC, 1, 3),
|
||||
[AIROHA_THERMAL_MUX_SENSOR] = REG_FIELD(AN7583_MUX_SENSOR, 2, 3),
|
||||
[AIROHA_THERMAL_MUX_TADC] = REG_FIELD(AN7583_MUX_TADC, 2, 3),
|
||||
[AIROHA_THERMAL_MUX_SENSOR] = REG_FIELD(AN7583_MUX_SENSOR, 1, 3),
|
||||
};
|
||||
|
||||
static int an7583_thermal_probe(struct platform_device *pdev,
|
||||
|
|
@ -667,7 +725,7 @@ static int airoha_thermal_probe(struct platform_device *pdev)
|
|||
const struct airoha_thermal_soc_data *soc_data;
|
||||
struct airoha_thermal_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
soc_data = device_get_match_data(dev);
|
||||
|
||||
|
|
@ -676,7 +734,10 @@ static int airoha_thermal_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
priv->pllrg_protect = soc_data->pllrg_protect;
|
||||
priv->current_adc = -1;
|
||||
|
||||
ret = devm_mutex_init(dev, &priv->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!soc_data->probe)
|
||||
return -EINVAL;
|
||||
|
|
@ -686,11 +747,31 @@ static int airoha_thermal_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
/* register of thermal sensor and get info from DT */
|
||||
priv->tz = devm_thermal_of_zone_register(dev, 0, priv,
|
||||
soc_data->thdev_ops);
|
||||
if (IS_ERR(priv->tz)) {
|
||||
dev_err(dev, "register thermal zone sensor failed\n");
|
||||
return PTR_ERR(priv->tz);
|
||||
for (i = 0; i < soc_data->num_sensors; i++) {
|
||||
struct airoha_thermal_zone *zone;
|
||||
struct thermal_zone_device *tz;
|
||||
|
||||
zone = devm_kzalloc(dev, sizeof(*zone), GFP_KERNEL);
|
||||
if (!zone)
|
||||
return -ENOMEM;
|
||||
|
||||
zone->priv = priv;
|
||||
zone->sensor = soc_data->sensors ? soc_data->sensors[i] :
|
||||
AIROHA_THERMAL_NO_MUX_SENSOR;
|
||||
|
||||
tz = devm_thermal_of_zone_register(dev, i, zone,
|
||||
soc_data->thdev_ops);
|
||||
if (IS_ERR(tz)) {
|
||||
/* A DT may describe fewer zones than sensors */
|
||||
if (i && PTR_ERR(tz) == -ENODEV)
|
||||
continue;
|
||||
|
||||
dev_err(dev, "register thermal zone %d failed\n", i);
|
||||
return PTR_ERR(tz);
|
||||
}
|
||||
|
||||
if (!i)
|
||||
priv->tz = tz;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
|
@ -698,7 +779,15 @@ static int airoha_thermal_probe(struct platform_device *pdev)
|
|||
return soc_data->post_probe ? soc_data->post_probe(pdev) : 0;
|
||||
}
|
||||
|
||||
/* The bandgap sensor stays zone 0 */
|
||||
static const int an7583_zone_sensors[AN7583_NUM_SENSOR] = {
|
||||
AN7583_BGP_TEMP_SENSOR,
|
||||
AN7583_GBE_TEMP_SENSOR,
|
||||
AN7583_CPU_TEMP_SENSOR,
|
||||
};
|
||||
|
||||
static const struct airoha_thermal_soc_data en7581_data = {
|
||||
.num_sensors = 1,
|
||||
.pllrg_protect = EN7581_SCU_THERMAL_PROTECT_KEY,
|
||||
.thdev_ops = &en7581_thdev_ops,
|
||||
.probe = &en7581_thermal_probe,
|
||||
|
|
@ -706,6 +795,8 @@ static const struct airoha_thermal_soc_data en7581_data = {
|
|||
};
|
||||
|
||||
static const struct airoha_thermal_soc_data an7583_data = {
|
||||
.sensors = an7583_zone_sensors,
|
||||
.num_sensors = AN7583_NUM_SENSOR,
|
||||
.pllrg_protect = AN7583_SCU_THERMAL_PROTECT_KEY,
|
||||
.thdev_ops = &an7583_tz_ops,
|
||||
.probe = &an7583_thermal_probe,
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ struct amlogic_thermal {
|
|||
const struct amlogic_thermal_data *data;
|
||||
struct regmap *regmap;
|
||||
struct regmap *sec_ao_map;
|
||||
struct clk *clk;
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
struct thermal_zone_device *tzd;
|
||||
u32 trim_info;
|
||||
struct meson_sm_firmware *sm_fw;
|
||||
|
|
@ -142,7 +143,7 @@ static int amlogic_thermal_enable(struct amlogic_thermal *data)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
ret = clk_bulk_prepare_enable(data->num_clks, data->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -156,7 +157,7 @@ static void amlogic_thermal_disable(struct amlogic_thermal *data)
|
|||
{
|
||||
regmap_update_bits(data->regmap, TSENSOR_CFG_REG1,
|
||||
TSENSOR_CFG_REG1_ENABLE, 0);
|
||||
clk_disable_unprepare(data->clk);
|
||||
clk_bulk_disable_unprepare(data->num_clks, data->clks);
|
||||
}
|
||||
|
||||
static int amlogic_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
|
|
@ -323,9 +324,10 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(pdata->regmap))
|
||||
return PTR_ERR(pdata->regmap);
|
||||
|
||||
pdata->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(pdata->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(pdata->clk), "failed to get clock\n");
|
||||
ret = devm_clk_bulk_get_all(dev, &pdata->clks);
|
||||
if (ret <= 0)
|
||||
return dev_err_probe(dev, ret ?: -ENOENT, "failed to get clocks\n");
|
||||
pdata->num_clks = ret;
|
||||
|
||||
if (pdata->data->use_sm)
|
||||
ret = amlogic_thermal_probe_sm(pdev, pdata);
|
||||
|
|
|
|||
|
|
@ -488,12 +488,12 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
|
|||
frequency = get_state_freq(cpufreq_cdev, state);
|
||||
|
||||
ret = freq_qos_update_request(&cpufreq_cdev->qos_req, frequency);
|
||||
if (ret >= 0) {
|
||||
cpufreq_cdev->cpufreq_state = state;
|
||||
ret = 0;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
cpufreq_cdev->cpufreq_state = state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -712,22 +712,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
|
|||
ret = check_power_actors(tz, params);
|
||||
if (ret < 0) {
|
||||
dev_warn(&tz->device, "power_allocator: binding failed\n");
|
||||
kfree(params);
|
||||
return ret;
|
||||
goto free_params;
|
||||
}
|
||||
|
||||
ret = allocate_actors_buffer(params, ret);
|
||||
if (ret) {
|
||||
dev_warn(&tz->device, "power_allocator: allocation failed\n");
|
||||
kfree(params);
|
||||
return ret;
|
||||
goto free_params;
|
||||
}
|
||||
|
||||
if (!tz->tzp) {
|
||||
tz->tzp = kzalloc_obj(*tz->tzp);
|
||||
if (!tz->tzp) {
|
||||
ret = -ENOMEM;
|
||||
goto free_params;
|
||||
goto free_power;
|
||||
}
|
||||
|
||||
params->allocated_tzp = true;
|
||||
|
|
@ -751,8 +749,9 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
|
|||
|
||||
return 0;
|
||||
|
||||
free_params:
|
||||
free_power:
|
||||
kfree(params->power);
|
||||
free_params:
|
||||
kfree(params);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ static int imx91_tmu_change_mode(struct thermal_zone_device *tz, enum thermal_de
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops tmu_tz_ops = {
|
||||
static const struct thermal_zone_device_ops tmu_tz_ops = {
|
||||
.get_temp = imx91_tmu_get_temp,
|
||||
.change_mode = imx91_tmu_change_mode,
|
||||
.set_trips = imx91_tmu_set_trips,
|
||||
|
|
|
|||
|
|
@ -345,8 +345,8 @@ static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
|
|||
}
|
||||
|
||||
skip:
|
||||
memcpy(chip->temp_thresh_map, chip->data->temp_map[threshold],
|
||||
sizeof(chip->temp_thresh_map));
|
||||
memcpy(chip->temp_thresh_map, (*chip->data->temp_map)[threshold],
|
||||
sizeof(chip->temp_thresh_map));
|
||||
reg |= threshold;
|
||||
if (disable_stage2_shutdown && !chip->require_stage2_shutdown)
|
||||
reg |= SHUTDOWN_CTRL1_OVERRIDE_STAGE2;
|
||||
|
|
@ -535,8 +535,8 @@ static int qpnp_tm_sync_thresholds(struct qpnp_tm_chip *chip)
|
|||
return ret;
|
||||
|
||||
threshold = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
|
||||
memcpy(chip->temp_thresh_map, chip->data->temp_map[threshold],
|
||||
sizeof(chip->temp_thresh_map));
|
||||
memcpy(chip->temp_thresh_map, (*chip->data->temp_map)[threshold],
|
||||
sizeof(chip->temp_thresh_map));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,34 @@ static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = {
|
|||
[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
|
||||
};
|
||||
|
||||
static int __init init_8952(struct tsens_priv *priv)
|
||||
{
|
||||
priv->sensor[0].p1_calib_offset = 2;
|
||||
priv->sensor[0].p2_calib_offset = -1;
|
||||
priv->sensor[1].p1_calib_offset = -4;
|
||||
priv->sensor[1].p2_calib_offset = -4;
|
||||
priv->sensor[2].p1_calib_offset = 4;
|
||||
priv->sensor[2].p2_calib_offset = 5;
|
||||
priv->sensor[3].p1_calib_offset = 1;
|
||||
priv->sensor[3].p2_calib_offset = 1;
|
||||
priv->sensor[4].p1_calib_offset = 2;
|
||||
priv->sensor[4].p2_calib_offset = 3;
|
||||
priv->sensor[5].p1_calib_offset = -1;
|
||||
priv->sensor[5].p2_calib_offset = -1;
|
||||
priv->sensor[6].p1_calib_offset = 0;
|
||||
priv->sensor[6].p2_calib_offset = -1;
|
||||
priv->sensor[7].p1_calib_offset = 3;
|
||||
priv->sensor[7].p2_calib_offset = 4;
|
||||
priv->sensor[8].p1_calib_offset = 2;
|
||||
priv->sensor[8].p2_calib_offset = 4;
|
||||
priv->sensor[9].p1_calib_offset = 0;
|
||||
priv->sensor[9].p2_calib_offset = 0;
|
||||
priv->sensor[10].p1_calib_offset = -3;
|
||||
priv->sensor[10].p2_calib_offset = -2;
|
||||
|
||||
return init_common(priv);
|
||||
}
|
||||
|
||||
static int __init init_8956(struct tsens_priv *priv) {
|
||||
priv->sensor[0].slope = 3313;
|
||||
priv->sensor[1].slope = 3275;
|
||||
|
|
@ -223,6 +251,19 @@ struct tsens_plat_data data_8937 = {
|
|||
.fields = tsens_v1_regfields,
|
||||
};
|
||||
|
||||
static const struct tsens_ops ops_8952 = {
|
||||
.init = init_8952,
|
||||
.calibrate = tsens_calibrate_common,
|
||||
.get_temp = get_temp_tsens_valid,
|
||||
};
|
||||
|
||||
struct tsens_plat_data data_8952 = {
|
||||
.num_sensors = 11,
|
||||
.ops = &ops_8952,
|
||||
.feat = &tsens_v1_feat,
|
||||
.fields = tsens_v1_regfields,
|
||||
};
|
||||
|
||||
static const struct tsens_ops ops_8956 = {
|
||||
.init = init_8956,
|
||||
.calibrate = tsens_calibrate_common,
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ static struct tsens_features tsens_v2_feat = {
|
|||
.adc = 0,
|
||||
.srot_split = 1,
|
||||
.max_sensors = 16,
|
||||
.trip_min_temp = -40000,
|
||||
.trip_max_temp = 120000,
|
||||
.trip_min_temp = -204000,
|
||||
.trip_max_temp = 204000,
|
||||
};
|
||||
|
||||
static struct tsens_features ipq8074_feat = {
|
||||
|
|
|
|||
|
|
@ -1191,6 +1191,9 @@ static const struct of_device_id tsens_table[] = {
|
|||
}, {
|
||||
.compatible = "qcom,msm8939-tsens",
|
||||
.data = &data_8939,
|
||||
}, {
|
||||
.compatible = "qcom,msm8952-tsens",
|
||||
.data = &data_8952,
|
||||
}, {
|
||||
.compatible = "qcom,msm8956-tsens",
|
||||
.data = &data_8956,
|
||||
|
|
|
|||
|
|
@ -669,7 +669,7 @@ extern struct tsens_plat_data data_8960;
|
|||
extern struct tsens_plat_data data_8226, data_8909, data_8916, data_8939, data_8974, data_9607;
|
||||
|
||||
/* TSENS v1 targets */
|
||||
extern struct tsens_plat_data data_tsens_v1, data_8937, data_8976, data_8956;
|
||||
extern struct tsens_plat_data data_tsens_v1, data_8937, data_8952, data_8976, data_8956;
|
||||
|
||||
/* TSENS v1 with no RPM targets */
|
||||
extern const struct tsens_plat_data data_ipq5018;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ struct rzg3e_thermal_info {
|
|||
* @info: chip type specific information
|
||||
* @trmval0: calibration value 0 (b)
|
||||
* @trmval1: calibration value 1 (c)
|
||||
* @sier: cached interrupt enable register
|
||||
* @lock: protects hardware access during conversions
|
||||
*/
|
||||
struct rzg3e_thermal_priv {
|
||||
|
|
@ -103,6 +104,7 @@ struct rzg3e_thermal_priv {
|
|||
const struct rzg3e_thermal_info *info;
|
||||
u16 trmval0;
|
||||
u16 trmval1;
|
||||
u32 sier;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
|
|
@ -148,12 +150,16 @@ static int rzg3e_thermal_power_on(struct rzg3e_thermal_priv *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Restore interrupt enable state */
|
||||
writel(priv->sier, priv->base + TSU_SIER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzg3e_thermal_power_off(struct rzg3e_thermal_priv *priv)
|
||||
{
|
||||
/* Disable all interrupts */
|
||||
/* Save and disable all interrupts */
|
||||
priv->sier = readl(priv->base + TSU_SIER);
|
||||
writel(0, priv->base + TSU_SIER);
|
||||
|
||||
/* Clear pending interrupts */
|
||||
|
|
@ -194,7 +200,12 @@ static u16 rzg3e_thermal_temp_to_code(struct rzg3e_thermal_priv *priv, int temp_
|
|||
s64 numerator, denominator;
|
||||
s64 code;
|
||||
|
||||
numerator = (temp_mc - info->temp_d_mc) * (priv->trmval1 - priv->trmval0);
|
||||
/*
|
||||
* Perform the arithmetic in 64 bits so that it cannot overflow for
|
||||
* -INT_MAX/INT_MAX values passed from the thermal core or when
|
||||
* userspace writes arbitrary trip point temperatures.
|
||||
*/
|
||||
numerator = ((s64)temp_mc - info->temp_d_mc) * (priv->trmval1 - priv->trmval0);
|
||||
denominator = info->temp_e_mc - info->temp_d_mc;
|
||||
|
||||
code = div64_s64(numerator, denominator) + priv->trmval0;
|
||||
|
|
@ -214,6 +225,16 @@ static int rzg3e_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
|
||||
guard(mutex)(&priv->lock);
|
||||
|
||||
/* Make sure a previous conversion is not in progress */
|
||||
ret = readl_poll_timeout(priv->base + TSU_SSR, status,
|
||||
!(status & TSU_SSR_CONV),
|
||||
TSU_POLL_DELAY_US,
|
||||
USEC_PER_MSEC);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Timeout waiting for conversion\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Clear any previous conversion status */
|
||||
writel(TSU_SICR_ADCLR, priv->base + TSU_SICR);
|
||||
|
||||
|
|
@ -241,7 +262,6 @@ static int rzg3e_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
*temp, *temp / 1000, abs(*temp) % 1000, code);
|
||||
|
||||
out:
|
||||
pm_runtime_mark_last_busy(priv->dev);
|
||||
pm_runtime_put_autosuspend(priv->dev);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -254,10 +274,6 @@ static int rzg3e_thermal_set_trips(struct thermal_zone_device *tz,
|
|||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* Hardware requires low < high */
|
||||
if (low >= high)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -293,11 +309,9 @@ static int rzg3e_thermal_set_trips(struct thermal_zone_device *tz,
|
|||
/* Enable comparison with "out of range" mode (CMPCOND=0) */
|
||||
writel(TSU_CMSR_CMPEN, priv->base + TSU_CMSR);
|
||||
|
||||
/* Unmask compare IRQ and start a conversion to evaluate window */
|
||||
/* Unmask compare IRQ */
|
||||
writel(TSU_SIER_CMPIE, priv->base + TSU_SIER);
|
||||
writel(TSU_STRGR_ADST, priv->base + TSU_STRGR);
|
||||
|
||||
pm_runtime_mark_last_busy(priv->dev);
|
||||
pm_runtime_put_autosuspend(priv->dev);
|
||||
|
||||
return 0;
|
||||
|
|
@ -469,7 +483,6 @@ static int rzg3e_thermal_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
dev_warn(dev, "Failed to add hwmon sysfs attributes\n");
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
dev_info(dev, "RZ/G3E thermal sensor registered\n");
|
||||
|
|
@ -499,15 +512,19 @@ static int rzg3e_thermal_runtime_resume(struct device *dev)
|
|||
static int rzg3e_thermal_suspend(struct device *dev)
|
||||
{
|
||||
struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev);
|
||||
bool active = pm_runtime_active(dev);
|
||||
int ret;
|
||||
|
||||
/* If device is active, power it off */
|
||||
if (pm_runtime_active(dev))
|
||||
if (active)
|
||||
rzg3e_thermal_power_off(priv);
|
||||
|
||||
/* Assert reset to ensure clean state after resume */
|
||||
reset_control_assert(priv->rstc);
|
||||
ret = reset_control_assert(priv->rstc);
|
||||
if (ret && active)
|
||||
rzg3e_thermal_power_on(priv);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rzg3e_thermal_resume(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/units.h>
|
||||
|
|
@ -27,10 +28,6 @@
|
|||
|
||||
#define TSU_READ_STEPS 8
|
||||
|
||||
/* Default calibration values, if FUSE values are missing. */
|
||||
#define SW_CALIB0_VAL 1297
|
||||
#define SW_CALIB1_VAL 751
|
||||
|
||||
#define MCELSIUS(temp) ((temp) * MILLIDEGREE_PER_DEGREE)
|
||||
|
||||
/**
|
||||
|
|
@ -55,6 +52,16 @@ struct rzg3s_thermal_priv {
|
|||
u16 calib1;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rzg3s_thermal_info - RZ/G3S thermal information
|
||||
* @calib0: calibration value if FUSE value is missing
|
||||
* @calib1: calibration value if FUSE value is missing
|
||||
*/
|
||||
struct rzg3s_thermal_info {
|
||||
u16 calib0;
|
||||
u16 calib1;
|
||||
};
|
||||
|
||||
static int rzg3s_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct rzg3s_thermal_priv *priv = thermal_zone_device_priv(tz);
|
||||
|
|
@ -149,7 +156,8 @@ static const struct thermal_zone_device_ops rzg3s_tz_of_ops = {
|
|||
.change_mode = rzg3s_thermal_change_mode,
|
||||
};
|
||||
|
||||
static int rzg3s_thermal_read_calib(struct rzg3s_thermal_priv *priv)
|
||||
static int rzg3s_thermal_read_calib(struct rzg3s_thermal_priv *priv,
|
||||
const struct rzg3s_thermal_info *info)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
u32 val;
|
||||
|
|
@ -163,13 +171,13 @@ static int rzg3s_thermal_read_calib(struct rzg3s_thermal_priv *priv)
|
|||
if (val & OTPTSUTRIM_EN_MASK)
|
||||
priv->calib0 = FIELD_GET(OTPTSUTRIM_MASK, val);
|
||||
else
|
||||
priv->calib0 = SW_CALIB0_VAL;
|
||||
priv->calib0 = info->calib0;
|
||||
|
||||
val = readl(priv->base + OTPTSUTRIM_REG(1));
|
||||
if (val & OTPTSUTRIM_EN_MASK)
|
||||
priv->calib1 = FIELD_GET(OTPTSUTRIM_MASK, val);
|
||||
else
|
||||
priv->calib1 = SW_CALIB1_VAL;
|
||||
priv->calib1 = info->calib1;
|
||||
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
|
|
@ -178,6 +186,7 @@ static int rzg3s_thermal_read_calib(struct rzg3s_thermal_priv *priv)
|
|||
|
||||
static int rzg3s_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct rzg3s_thermal_info *info = device_get_match_data(&pdev->dev);
|
||||
struct rzg3s_thermal_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
|
@ -208,7 +217,7 @@ static int rzg3s_thermal_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable runtime PM!\n");
|
||||
|
||||
ret = rzg3s_thermal_read_calib(priv);
|
||||
ret = rzg3s_thermal_read_calib(priv, info);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to read calibration data!\n");
|
||||
|
||||
|
|
@ -251,8 +260,19 @@ static const struct dev_pm_ops rzg3s_thermal_pm_ops = {
|
|||
SYSTEM_SLEEP_PM_OPS(rzg3s_thermal_suspend, rzg3s_thermal_resume)
|
||||
};
|
||||
|
||||
static const struct rzg3s_thermal_info rzg3s_info = {
|
||||
.calib0 = 1297,
|
||||
.calib1 = 751,
|
||||
};
|
||||
|
||||
static const struct rzg3s_thermal_info rzg3l_info = {
|
||||
.calib0 = 1322,
|
||||
.calib1 = 772,
|
||||
};
|
||||
|
||||
static const struct of_device_id rzg3s_thermal_dt_ids[] = {
|
||||
{ .compatible = "renesas,r9a08g045-tsu" },
|
||||
{ .compatible = "renesas,r9a08g045-tsu", .data = &rzg3s_info },
|
||||
{ .compatible = "renesas,r9a08g046-tsu", .data = &rzg3l_info },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rzg3s_thermal_dt_ids);
|
||||
|
|
|
|||
|
|
@ -10,3 +10,22 @@ config EXYNOS_THERMAL
|
|||
the TMU, reports temperature and handles cooling action if defined.
|
||||
This driver uses the Exynos core thermal APIs and TMU configuration
|
||||
data from the supported SoCs.
|
||||
|
||||
config EXYNOS_ACPM_THERMAL
|
||||
tristate "Exynos ACPM thermal management unit driver"
|
||||
depends on THERMAL_OF
|
||||
depends on HAS_IOMEM
|
||||
depends on EXYNOS_ACPM_PROTOCOL
|
||||
default ARCH_EXYNOS
|
||||
help
|
||||
Support for the Thermal Management Unit (TMU) on Samsung Exynos SoCs
|
||||
utilizing the ACPM IPC protocol, such as the Google GS101.
|
||||
|
||||
The TMU on these platforms is managed through a hybrid architecture.
|
||||
This driver handles direct register access for thermal interrupt status
|
||||
monitoring and communicates with the Alive Clock and Power Manager
|
||||
(ACPM) firmware via the ACPM IPC protocol for functional sensor control
|
||||
and configuration.
|
||||
|
||||
Select this if you want to monitor device temperature and enable
|
||||
thermal mitigation on Samsung Exynos ACPM based devices.
|
||||
|
|
|
|||
|
|
@ -4,3 +4,5 @@
|
|||
#
|
||||
obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
|
||||
exynos_thermal-y := exynos_tmu.o
|
||||
obj-$(CONFIG_EXYNOS_ACPM_THERMAL) += exynos_acpm_thermal.o
|
||||
exynos_acpm_thermal-y := acpm-tmu.o
|
||||
|
|
|
|||
651
drivers/thermal/samsung/acpm-tmu.c
Normal file
651
drivers/thermal/samsung/acpm-tmu.c
Normal file
|
|
@ -0,0 +1,651 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2019 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2025 Google LLC.
|
||||
* Copyright 2026 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "../thermal_hwmon.h"
|
||||
|
||||
#define EXYNOS_TMU_SENSOR(i) BIT(i)
|
||||
#define EXYNOS_TMU_SENSORS_MAX_COUNT 16
|
||||
|
||||
#define GS101_CPUCL2_SENSOR_MASK (EXYNOS_TMU_SENSOR(0) | \
|
||||
EXYNOS_TMU_SENSOR(6) | \
|
||||
EXYNOS_TMU_SENSOR(7) | \
|
||||
EXYNOS_TMU_SENSOR(8) | \
|
||||
EXYNOS_TMU_SENSOR(9))
|
||||
#define GS101_CPUCL1_SENSOR_MASK (EXYNOS_TMU_SENSOR(4) | \
|
||||
EXYNOS_TMU_SENSOR(5))
|
||||
#define GS101_CPUCL0_SENSOR_MASK (EXYNOS_TMU_SENSOR(1) | \
|
||||
EXYNOS_TMU_SENSOR(2))
|
||||
|
||||
#define GS101_REG_INTPEND(i) ((i) * 0x50 + 0xf8)
|
||||
|
||||
enum {
|
||||
P0_INTPEND,
|
||||
P1_INTPEND,
|
||||
P2_INTPEND,
|
||||
P3_INTPEND,
|
||||
P4_INTPEND,
|
||||
P5_INTPEND,
|
||||
P6_INTPEND,
|
||||
P7_INTPEND,
|
||||
P8_INTPEND,
|
||||
P9_INTPEND,
|
||||
P10_INTPEND,
|
||||
P11_INTPEND,
|
||||
P12_INTPEND,
|
||||
P13_INTPEND,
|
||||
P14_INTPEND,
|
||||
P15_INTPEND,
|
||||
REG_INTPEND_COUNT,
|
||||
};
|
||||
|
||||
struct acpm_tmu_sensor_group {
|
||||
u16 mask;
|
||||
u8 id;
|
||||
};
|
||||
|
||||
struct acpm_tmu_sensor {
|
||||
const struct acpm_tmu_sensor_group *group;
|
||||
struct thermal_zone_device *tzd;
|
||||
struct acpm_tmu_priv *priv;
|
||||
struct mutex lock; /* protects sensor state */
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct acpm_tmu_priv {
|
||||
struct regmap_field *regmap_fields[REG_INTPEND_COUNT];
|
||||
struct acpm_handle *handle;
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
unsigned int mbox_chan_id;
|
||||
unsigned int num_sensors;
|
||||
int irq;
|
||||
struct acpm_tmu_sensor sensors[] __counted_by(num_sensors);
|
||||
};
|
||||
|
||||
struct acpm_tmu_driver_data {
|
||||
const struct reg_field *reg_fields;
|
||||
const struct acpm_tmu_sensor_group *sensor_groups;
|
||||
unsigned int num_sensor_groups;
|
||||
unsigned int mbox_chan_id;
|
||||
};
|
||||
|
||||
#define ACPM_TMU_SENSOR_GROUP(_mask, _id) \
|
||||
{ \
|
||||
.mask = _mask, \
|
||||
.id = _id, \
|
||||
}
|
||||
|
||||
static const struct acpm_tmu_sensor_group gs101_sensor_groups[] = {
|
||||
ACPM_TMU_SENSOR_GROUP(GS101_CPUCL2_SENSOR_MASK, 0),
|
||||
ACPM_TMU_SENSOR_GROUP(GS101_CPUCL1_SENSOR_MASK, 1),
|
||||
ACPM_TMU_SENSOR_GROUP(GS101_CPUCL0_SENSOR_MASK, 2),
|
||||
};
|
||||
|
||||
static const struct reg_field gs101_reg_fields[REG_INTPEND_COUNT] = {
|
||||
[P0_INTPEND] = REG_FIELD(GS101_REG_INTPEND(0), 0, 31),
|
||||
[P1_INTPEND] = REG_FIELD(GS101_REG_INTPEND(1), 0, 31),
|
||||
[P2_INTPEND] = REG_FIELD(GS101_REG_INTPEND(2), 0, 31),
|
||||
[P3_INTPEND] = REG_FIELD(GS101_REG_INTPEND(3), 0, 31),
|
||||
[P4_INTPEND] = REG_FIELD(GS101_REG_INTPEND(4), 0, 31),
|
||||
[P5_INTPEND] = REG_FIELD(GS101_REG_INTPEND(5), 0, 31),
|
||||
[P6_INTPEND] = REG_FIELD(GS101_REG_INTPEND(6), 0, 31),
|
||||
[P7_INTPEND] = REG_FIELD(GS101_REG_INTPEND(7), 0, 31),
|
||||
[P8_INTPEND] = REG_FIELD(GS101_REG_INTPEND(8), 0, 31),
|
||||
[P9_INTPEND] = REG_FIELD(GS101_REG_INTPEND(9), 0, 31),
|
||||
[P10_INTPEND] = REG_FIELD(GS101_REG_INTPEND(10), 0, 31),
|
||||
[P11_INTPEND] = REG_FIELD(GS101_REG_INTPEND(11), 0, 31),
|
||||
[P12_INTPEND] = REG_FIELD(GS101_REG_INTPEND(12), 0, 31),
|
||||
[P13_INTPEND] = REG_FIELD(GS101_REG_INTPEND(13), 0, 31),
|
||||
[P14_INTPEND] = REG_FIELD(GS101_REG_INTPEND(14), 0, 31),
|
||||
[P15_INTPEND] = REG_FIELD(GS101_REG_INTPEND(15), 0, 31),
|
||||
};
|
||||
|
||||
static const struct regmap_config gs101_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.use_relaxed_mmio = true,
|
||||
.max_register = GS101_REG_INTPEND(15),
|
||||
};
|
||||
|
||||
static const struct acpm_tmu_driver_data acpm_tmu_gs101 = {
|
||||
.reg_fields = gs101_reg_fields,
|
||||
.sensor_groups = gs101_sensor_groups,
|
||||
.num_sensor_groups = ARRAY_SIZE(gs101_sensor_groups),
|
||||
.mbox_chan_id = 9,
|
||||
};
|
||||
|
||||
static int acpm_tmu_op_tz_control(struct acpm_tmu_sensor *sensor, bool on)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = sensor->priv;
|
||||
struct acpm_handle *handle = priv->handle;
|
||||
const struct acpm_tmu_ops *ops = &handle->ops->tmu;
|
||||
int ret;
|
||||
|
||||
ret = ops->tz_control(handle, priv->mbox_chan_id, sensor->group->id,
|
||||
on);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sensor->enabled = on;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpm_tmu_control_rollback(struct acpm_tmu_priv *priv, int start_idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = start_idx; i >= 0; i--) {
|
||||
struct acpm_tmu_sensor *sensor = &priv->sensors[i];
|
||||
int ret;
|
||||
|
||||
if (!sensor->tzd)
|
||||
continue;
|
||||
|
||||
mutex_lock(&sensor->lock);
|
||||
ret = acpm_tmu_op_tz_control(sensor, false);
|
||||
mutex_unlock(&sensor->lock);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "Rollback: Failed to disable sensor %d: %d\n",
|
||||
i, ret);
|
||||
}
|
||||
}
|
||||
|
||||
static int acpm_tmu_control(struct acpm_tmu_priv *priv, bool on, bool rollback)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
int i, ret, err = 0;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
struct acpm_tmu_sensor *sensor = &priv->sensors[i];
|
||||
|
||||
/* Skip sensors that weren't found in DT */
|
||||
if (!sensor->tzd)
|
||||
continue;
|
||||
|
||||
mutex_lock(&sensor->lock);
|
||||
ret = acpm_tmu_op_tz_control(sensor, on);
|
||||
mutex_unlock(&sensor->lock);
|
||||
if (ret) {
|
||||
if (!err)
|
||||
err = ret;
|
||||
|
||||
/* On enable, stop on first error if rollback is requested */
|
||||
if (on && rollback) {
|
||||
acpm_tmu_control_rollback(priv, i - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct acpm_tmu_sensor *sensor = thermal_zone_device_priv(tz);
|
||||
struct acpm_tmu_priv *priv = sensor->priv;
|
||||
struct acpm_handle *handle = priv->handle;
|
||||
const struct acpm_tmu_ops *ops = &handle->ops->tmu;
|
||||
struct device *dev = priv->dev;
|
||||
int acpm_temp = 0, ret;
|
||||
|
||||
/*
|
||||
* Fast path: check locklessly if the sensor is enabled to avoid
|
||||
* expensive runtime PM operations when it is disabled. Any race with
|
||||
* concurrent disabling is caught by the second check under the lock
|
||||
* after PM resume.
|
||||
*/
|
||||
if (!sensor->enabled)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
scoped_guard(mutex, &sensor->lock) {
|
||||
if (!sensor->enabled) {
|
||||
ret = -EAGAIN;
|
||||
} else {
|
||||
ret = ops->read_temp(handle, priv->mbox_chan_id,
|
||||
sensor->group->id, &acpm_temp);
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*temp = acpm_temp * MILLIDEGREE_PER_DEGREE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpm_tmu_update_thresholds(struct acpm_tmu_sensor *sensor,
|
||||
u8 thresholds[2], u8 inten)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = sensor->priv;
|
||||
struct acpm_handle *handle = priv->handle;
|
||||
const struct acpm_tmu_ops *ops = &handle->ops->tmu;
|
||||
unsigned int mbox_chan_id = priv->mbox_chan_id;
|
||||
u8 acpm_sensor_id = sensor->group->id;
|
||||
bool was_enabled;
|
||||
int ret, restore_ret;
|
||||
|
||||
guard(mutex)(&sensor->lock);
|
||||
|
||||
was_enabled = sensor->enabled;
|
||||
|
||||
if (was_enabled) {
|
||||
ret = acpm_tmu_op_tz_control(sensor, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ops->set_threshold(handle, mbox_chan_id, acpm_sensor_id,
|
||||
thresholds, 2);
|
||||
if (!ret) {
|
||||
ret = ops->set_interrupt_enable(handle, mbox_chan_id,
|
||||
acpm_sensor_id, inten);
|
||||
}
|
||||
|
||||
if (was_enabled) {
|
||||
restore_ret = acpm_tmu_op_tz_control(sensor, true);
|
||||
if (restore_ret)
|
||||
dev_err(priv->dev, "Failed to restore sensor state: %d\n",
|
||||
restore_ret);
|
||||
if (!ret)
|
||||
ret = restore_ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpm_tmu_set_trips(struct thermal_zone_device *tz, int low, int high)
|
||||
{
|
||||
struct acpm_tmu_sensor *sensor = thermal_zone_device_priv(tz);
|
||||
struct acpm_tmu_priv *priv = sensor->priv;
|
||||
struct device *dev = priv->dev;
|
||||
u8 thresholds[2] = {};
|
||||
u8 inten = 0;
|
||||
int ret;
|
||||
|
||||
/* If a valid lower bound exists, set the threshold and enable its interrupt */
|
||||
if (low > -INT_MAX) {
|
||||
thresholds[0] = clamp_val(low / MILLIDEGREE_PER_DEGREE, 0, 255);
|
||||
inten |= BIT(0);
|
||||
}
|
||||
|
||||
/* If a valid upper bound exists, set the threshold and enable its interrupt */
|
||||
if (high < INT_MAX) {
|
||||
thresholds[1] = clamp_val(high / MILLIDEGREE_PER_DEGREE, 0, 255);
|
||||
inten |= BIT(1);
|
||||
}
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = acpm_tmu_update_thresholds(sensor, thresholds, inten);
|
||||
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops acpm_tmu_sensor_ops = {
|
||||
.get_temp = acpm_tmu_get_temp,
|
||||
.set_trips = acpm_tmu_set_trips,
|
||||
};
|
||||
|
||||
static int acpm_tmu_has_pending_irq(struct acpm_tmu_sensor *sensor,
|
||||
bool *pending_irq)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = sensor->priv;
|
||||
unsigned long mask = sensor->group->mask;
|
||||
int i, ret;
|
||||
u32 val;
|
||||
|
||||
guard(mutex)(&sensor->lock);
|
||||
|
||||
for_each_set_bit(i, &mask, EXYNOS_TMU_SENSORS_MAX_COUNT) {
|
||||
ret = regmap_field_read(priv->regmap_fields[i], &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val) {
|
||||
*pending_irq = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t acpm_tmu_thread_fn(int irq, void *id)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = id;
|
||||
struct acpm_handle *handle = priv->handle;
|
||||
const struct acpm_tmu_ops *ops = &handle->ops->tmu;
|
||||
struct device *dev = priv->dev;
|
||||
bool handled = false;
|
||||
int i, ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to resume: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
struct acpm_tmu_sensor *sensor = &priv->sensors[i];
|
||||
bool pending_irq = false;
|
||||
|
||||
if (!sensor->tzd)
|
||||
continue;
|
||||
|
||||
ret = acpm_tmu_has_pending_irq(sensor, &pending_irq);
|
||||
if (ret || !pending_irq)
|
||||
continue;
|
||||
|
||||
handled = true;
|
||||
|
||||
scoped_guard(mutex, &sensor->lock) {
|
||||
ret = ops->clear_tz_irq(handle, priv->mbox_chan_id,
|
||||
sensor->group->id);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "Sensor %d: failed to clear IRQ (%d)\n",
|
||||
i, ret);
|
||||
}
|
||||
|
||||
thermal_zone_device_update(sensor->tzd,
|
||||
THERMAL_EVENT_UNSPECIFIED);
|
||||
}
|
||||
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static const struct of_device_id acpm_tmu_match[] = {
|
||||
{ .compatible = "google,gs101-tmu-top" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, acpm_tmu_match);
|
||||
|
||||
static int acpm_tmu_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct acpm_tmu_driver_data *data = &acpm_tmu_gs101;
|
||||
struct acpm_handle *acpm_handle;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct acpm_tmu_priv *priv;
|
||||
struct regmap *regmap;
|
||||
void __iomem *base;
|
||||
int i, ret;
|
||||
|
||||
acpm_handle = devm_acpm_get_by_phandle(dev);
|
||||
if (IS_ERR(acpm_handle))
|
||||
return dev_err_probe(dev, PTR_ERR(acpm_handle),
|
||||
"Failed to get ACPM handle\n");
|
||||
|
||||
priv = devm_kzalloc(dev,
|
||||
struct_size(priv, sensors, data->num_sensor_groups),
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->handle = acpm_handle;
|
||||
priv->mbox_chan_id = data->mbox_chan_id;
|
||||
priv->num_sensors = data->num_sensor_groups;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return dev_err_probe(dev, PTR_ERR(base), "Failed to ioremap resource\n");
|
||||
|
||||
regmap = devm_regmap_init_mmio(dev, base, &gs101_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
|
||||
|
||||
ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->regmap_fields,
|
||||
data->reg_fields, REG_INTPEND_COUNT);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Unable to map syscon registers\n");
|
||||
|
||||
priv->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->clk),
|
||||
"Failed to get the clock\n");
|
||||
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (priv->irq < 0)
|
||||
return dev_err_probe(dev, priv->irq, "Failed to get irq\n");
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, 100);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to resume device\n");
|
||||
|
||||
ret = acpm_handle->ops->tmu.init(acpm_handle, priv->mbox_chan_id);
|
||||
if (ret) {
|
||||
ret = dev_err_probe(dev, ret, "Failed to init TMU\n");
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
struct acpm_tmu_sensor *sensor = &priv->sensors[i];
|
||||
|
||||
mutex_init(&sensor->lock);
|
||||
sensor->group = &data->sensor_groups[i];
|
||||
sensor->priv = priv;
|
||||
|
||||
sensor->tzd = devm_thermal_of_zone_register(dev, i, sensor,
|
||||
&acpm_tmu_sensor_ops);
|
||||
if (IS_ERR(sensor->tzd)) {
|
||||
ret = PTR_ERR(sensor->tzd);
|
||||
if (ret == -ENODEV) {
|
||||
sensor->tzd = NULL;
|
||||
dev_dbg(dev, "Sensor %d not used in DT, skipping\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = dev_err_probe(dev, ret, "Failed to register sensor %d\n", i);
|
||||
goto err_rollback;
|
||||
}
|
||||
|
||||
mutex_lock(&sensor->lock);
|
||||
ret = acpm_tmu_op_tz_control(sensor, true);
|
||||
mutex_unlock(&sensor->lock);
|
||||
if (ret) {
|
||||
ret = dev_err_probe(dev, ret, "Failed to enable sensor %d\n", i);
|
||||
goto err_rollback;
|
||||
}
|
||||
|
||||
thermal_zone_device_update(sensor->tzd,
|
||||
THERMAL_EVENT_UNSPECIFIED);
|
||||
|
||||
ret = devm_thermal_add_hwmon_sysfs(dev, sensor->tzd);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to add hwmon sysfs!\n");
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, priv->irq, NULL,
|
||||
acpm_tmu_thread_fn, IRQF_ONESHOT,
|
||||
dev_name(dev), priv);
|
||||
if (ret) {
|
||||
ret = dev_err_probe(dev, ret, "Failed to request irq\n");
|
||||
goto err_rollback;
|
||||
}
|
||||
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_rollback:
|
||||
acpm_tmu_control_rollback(priv, i - 1);
|
||||
err_pm_put:
|
||||
pm_runtime_dont_use_autosuspend(dev);
|
||||
pm_runtime_put_sync(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acpm_tmu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
/* Stop IRQ first to prevent race with thread_fn */
|
||||
disable_irq(priv->irq);
|
||||
|
||||
/*
|
||||
* Disable autosuspend to force the subsequent pm_runtime_put_sync()
|
||||
* inside acpm_tmu_control() to synchronously suspend the device
|
||||
* immediately, preventing clock leaks when the driver is removed.
|
||||
*/
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
acpm_tmu_control(priv, false, false);
|
||||
}
|
||||
|
||||
static int acpm_tmu_suspend(struct device *dev)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
|
||||
struct acpm_handle *handle = priv->handle;
|
||||
const struct acpm_tmu_ops *ops = &handle->ops->tmu;
|
||||
int ret, restore_ret;
|
||||
|
||||
ret = acpm_tmu_control(priv, false, false);
|
||||
if (ret)
|
||||
goto err_restore_sensors;
|
||||
|
||||
/* APB clock not required for this specific msg */
|
||||
ret = ops->suspend(handle, priv->mbox_chan_id);
|
||||
if (ret)
|
||||
goto err_restore_sensors;
|
||||
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
if (ret)
|
||||
goto err_resume_acpm;
|
||||
|
||||
return 0;
|
||||
|
||||
err_resume_acpm:
|
||||
restore_ret = ops->resume(handle, priv->mbox_chan_id);
|
||||
if (restore_ret)
|
||||
dev_err(dev, "Failed to resume ACPM after force suspend failure: %d\n",
|
||||
restore_ret);
|
||||
|
||||
err_restore_sensors:
|
||||
restore_ret = acpm_tmu_control(priv, true, false);
|
||||
if (restore_ret)
|
||||
dev_err(dev, "Failed to re-enable TMU after suspend failure: %d\n",
|
||||
restore_ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpm_tmu_resume(struct device *dev)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
|
||||
struct acpm_handle *handle = priv->handle;
|
||||
const struct acpm_tmu_ops *ops = &handle->ops->tmu;
|
||||
int ret, restore_ret;
|
||||
|
||||
/* APB clock not required for this specific msg */
|
||||
ret = ops->resume(handle, priv->mbox_chan_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
goto err_suspend_acpm;
|
||||
|
||||
ret = acpm_tmu_control(priv, true, true);
|
||||
if (ret)
|
||||
goto err_suspend_pm;
|
||||
|
||||
return 0;
|
||||
|
||||
err_suspend_pm:
|
||||
restore_ret = pm_runtime_force_suspend(dev);
|
||||
if (restore_ret)
|
||||
dev_err(dev, "Failed to force suspend during resume rollback: %d\n",
|
||||
restore_ret);
|
||||
err_suspend_acpm:
|
||||
restore_ret = ops->suspend(handle, priv->mbox_chan_id);
|
||||
if (restore_ret)
|
||||
dev_err(dev, "Failed to suspend ACPM during resume rollback: %d\n",
|
||||
restore_ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpm_tmu_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpm_tmu_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct acpm_tmu_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return clk_prepare_enable(priv->clk);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops acpm_tmu_pm_ops = {
|
||||
SYSTEM_SLEEP_PM_OPS(acpm_tmu_suspend, acpm_tmu_resume)
|
||||
RUNTIME_PM_OPS(acpm_tmu_runtime_suspend, acpm_tmu_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver acpm_tmu_driver = {
|
||||
.driver = {
|
||||
.name = "gs-tmu",
|
||||
.pm = pm_ptr(&acpm_tmu_pm_ops),
|
||||
.of_match_table = acpm_tmu_match,
|
||||
},
|
||||
.probe = acpm_tmu_probe,
|
||||
.remove = acpm_tmu_remove,
|
||||
};
|
||||
module_platform_driver(acpm_tmu_driver);
|
||||
|
||||
MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@linaro.org>");
|
||||
MODULE_DESCRIPTION("Samsung Exynos ACPM TMU Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -396,6 +396,12 @@ static int sprd_thm_probe(struct platform_device *pdev)
|
|||
goto of_put;
|
||||
}
|
||||
|
||||
if (sen->id < 0 || sen->id >= SPRD_THM_MAX_SENSOR) {
|
||||
dev_err(&pdev->dev, "invalid sensor id %d\n", sen->id);
|
||||
ret = -EINVAL;
|
||||
goto of_put;
|
||||
}
|
||||
|
||||
ret = sprd_thm_sensor_calibration(sen_child, thm, sen);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "efuse cal analysis failed");
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@
|
|||
|
||||
/**
|
||||
* thermal_fwnode_cooling_device_register() - register an thermal cooling device
|
||||
* @np: a pointer to a device tree node.
|
||||
* @of_index: a cooling device index in the cooling controller
|
||||
* @fwnode: a pointer to a firmware node.
|
||||
* @fwn_index: a cooling device index in the cooling controller
|
||||
* @type: the thermal cooling device type.
|
||||
* @devdata: device private data.
|
||||
* @ops: standard thermal cooling devices callbacks.
|
||||
*
|
||||
* This function will register a cooling device with device tree node reference.
|
||||
* This function will register a cooling device with a firmware node reference.
|
||||
* This interface function adds a new thermal cooling device (fan/processor/...)
|
||||
* to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
|
||||
* to all the thermal zone devices registered at the same time.
|
||||
|
|
@ -71,7 +71,7 @@ __devm_thermal_fwnode_cooling_device_register(struct device *dev, struct fwnode_
|
|||
/**
|
||||
* devm_thermal_fwnode_cooling_device_register() - register a thermal cooling device
|
||||
* @dev: a valid struct device pointer of a sensor device.
|
||||
* @fw_index: a cooling device index in the cooling controller
|
||||
* @fwn_index: a cooling device index in the cooling controller
|
||||
* @type: the thermal cooling device type.
|
||||
* @devdata: device private data.
|
||||
* @ops: standard thermal cooling devices callbacks.
|
||||
|
|
|
|||
|
|
@ -576,7 +576,8 @@ int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data)
|
|||
* @bgp: pointer to bandgap instance
|
||||
* @id: sensor id
|
||||
*
|
||||
* Return: data stored by set function with sensor id on success or NULL
|
||||
* Return: the stored sensor data, which may be %NULL, or an ERR_PTR()
|
||||
* if @bgp or @id is invalid.
|
||||
*/
|
||||
void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id)
|
||||
{
|
||||
|
|
@ -1077,6 +1078,10 @@ void ti_bandgap_remove(struct platform_device *pdev)
|
|||
if (!soc_device_match(soc_no_cpu_notifier))
|
||||
cpu_pm_unregister_notifier(&bgp->nb);
|
||||
|
||||
/* Stop the alerts first: they queue work on the sensors' data */
|
||||
if (TI_BANDGAP_HAS(bgp, TALERT))
|
||||
free_irq(bgp->irq, bgp);
|
||||
|
||||
/* Remove sensor interfaces */
|
||||
for (i = 0; i < bgp->conf->sensor_count; i++) {
|
||||
if (bgp->conf->sensors[i].unregister_cooling)
|
||||
|
|
@ -1093,9 +1098,6 @@ void ti_bandgap_remove(struct platform_device *pdev)
|
|||
clk_put(bgp->fclock);
|
||||
clk_put(bgp->div_clk);
|
||||
|
||||
if (TI_BANDGAP_HAS(bgp, TALERT))
|
||||
free_irq(bgp->irq, bgp);
|
||||
|
||||
if (TI_BANDGAP_HAS(bgp, TSHUT))
|
||||
free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,6 +195,10 @@ int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
|
|||
|
||||
data = ti_bandgap_get_sensor_data(bgp, id);
|
||||
|
||||
/* Work queued by the talert IRQ must not outlive the data */
|
||||
if (!IS_ERR_OR_NULL(data))
|
||||
cancel_work_sync(&data->thermal_wq);
|
||||
|
||||
if (!IS_ERR_OR_NULL(data) && data->ti_thermal) {
|
||||
if (data->our_zone)
|
||||
thermal_zone_device_unregister(data->ti_thermal);
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ static int find_tzone_cdev(struct dirent *nl, char *tz_name,
|
|||
cdev_name, cdev_name_linked, cdev_id);
|
||||
tzi->cdev_binding |= (1 << cdev_id);
|
||||
|
||||
/* find the trip point in which the cdev is binded to
|
||||
/* find the trip point in which the cdev is bound to
|
||||
* in this tzone
|
||||
*/
|
||||
snprintf(cdev_trip_name, sizeof(cdev_trip_name) - 1,
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ static void prepare_logging(void)
|
|||
|
||||
memset(binding_str, 0, sizeof(binding_str));
|
||||
for (j = 0; j < 32; j++)
|
||||
binding_str[j] = (ptdata.tzi[i].cdev_binding & (1 << j)) ?
|
||||
binding_str[j] = (ptdata.tzi[i].cdev_binding & (1U << j)) ?
|
||||
'1' : '0';
|
||||
|
||||
fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n",
|
||||
|
|
@ -230,7 +230,7 @@ int main(int argc, char **argv)
|
|||
switch (c) {
|
||||
case 'c':
|
||||
no_control = 0;
|
||||
strncpy(ctrl_cdev, optarg, CDEV_NAME_SIZE);
|
||||
snprintf(ctrl_cdev, sizeof(ctrl_cdev), "%s", optarg);
|
||||
break;
|
||||
case 'd':
|
||||
start_daemon_mode();
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ struct tz_info {
|
|||
char type[256]; /* e.g. acpitz */
|
||||
int instance;
|
||||
int passive; /* active zone has passive node to force passive mode */
|
||||
int nr_cdev; /* number of cooling device binded */
|
||||
int nr_cdev; /* number of cooling devices bound */
|
||||
int nr_trip_pts;
|
||||
struct trip_point tp[MAX_NR_TRIP];
|
||||
unsigned long cdev_binding; /* bitmap for attached cdevs */
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ void show_cooling_device(void)
|
|||
unsigned long trip_binding =
|
||||
ptdata.tzi[i].trip_binding[cdev_inst];
|
||||
int k = 0; /* per zone trip point id that
|
||||
* binded to this cdev, one to
|
||||
* is bound to this cdev, one to
|
||||
* many possible based on the
|
||||
* binding bitmask.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user