mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
- Add the QCom Nord temperature sensor DT bindings (Deepti Jaggi)
- Use devm_add_action_or_reset() for clock disable on the NVidia soctherm and switch to devm cooling device registration version (Daniel Lezcano) - Replace the devm version implementation by the helper doing the same thing (Daniel Lezcano) - Add the Amlogic T7 thermal sensor along with thermal calibration data read from SMC calls (Ronald Claveau) - Fix typo in comment, "uppper" with "upper" in the TSens QCom driver (Jinseok Kim) - Add the QCom Shikra temperature sensor DT bindings (Gaurav Kohli) - Add the QCom Hawi temperature sensor DT bindings (Dipa Ramesh Mantre) - Fix atomic temperature read in the QCom tsens to comply with hardware documentation (Priyansh Jain) - Fix trailing whitespace and repeated word in the OF code. Do not split quoted string across lines in the iMX7 driver (Mayur Kumar) - Add SpacemiT K1 thermal sensor support (Shuwei Wu) - Add the i.MX93 temperature sensor support and filter out the invalid temperature (Jacky Bai) - Enable by default the TMU (Thermal Monitoring Unit) on Exynos platform (Krzysztof Kozlowski) - Split the core code and the OF which are interleaved. Add the cooling device per index registration in order to support dedicated cooling devices controller (Daniel Lezcano) - Add DT binding to specify an index in the cooling device map (Gaurav Kohli) - Rework interrupt initialization in the Tsens driver and add the optional wakeup source (Priyansh Jain) -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAmoli08ACgkQqDIjiipP 6E/8Ngf+ORzClFRspHOgXlA+lx2AAdtqNXWgxp7a7ZKfzgcNhavYrftdTfR61t3f XnZj7xxNzM/v4Qh0JdveIbHVUx8jzO+YEI9UVTaxc63Nf7DpPdQFlNdQSVkpW4LH g69a3MZpTDs5Ko9eSeNOoJKe2WH55dVbtvubT34y8vgT85oaQK+HprE2/wvkwttj uEWreOOL+NO/fOOOnONUB+6qCVJ2j7p0+Pmwvdfux/yhmZZGMfTiIWtt0aGfFILN L/k4D1xAiYhpGPtz5On5uc3BTFm9JHmLrtcxyoY6yAUBf+9ggZkSNT9/63tJ7c+X gH2yjL+eFex+i9UzCzulZ5wWO3cE0g== =7OnQ -----END PGP SIGNATURE----- Merge tag 'thermal-v7.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux Pull thermal driver updates for 7.2 from Daniel Lezcano: - Add the QCom Nord temperature sensor DT bindings (Deepti Jaggi) - Use devm_add_action_or_reset() for clock disable on the NVidia soctherm and switch to devm cooling device registration version (Daniel Lezcano) - Replace the devm version implementation by the helper doing the same thing (Daniel Lezcano) - Add the Amlogic T7 thermal sensor along with thermal calibration data read from SMC calls (Ronald Claveau) - Fix typo in comment, "uppper" with "upper" in the TSens QCom driver (Jinseok Kim) - Add the QCom Shikra temperature sensor DT bindings (Gaurav Kohli) - Add the QCom Hawi temperature sensor DT bindings (Dipa Ramesh Mantre) - Fix atomic temperature read in the QCom tsens to comply with hardware documentation (Priyansh Jain) - Fix trailing whitespace and repeated word in the OF code. Do not split quoted string across lines in the iMX7 driver (Mayur Kumar) - Add SpacemiT K1 thermal sensor support (Shuwei Wu) - Add the i.MX93 temperature sensor support and filter out the invalid temperature (Jacky Bai) - Enable by default the TMU (Thermal Monitoring Unit) on Exynos platform (Krzysztof Kozlowski) - Split the core code and the OF which are interleaved. Add the cooling device per index registration in order to support dedicated cooling devices controller (Daniel Lezcano) - Add DT binding to specify an index in the cooling device map (Gaurav Kohli) - Rework interrupt initialization in the Tsens driver and add the optional wakeup source (Priyansh Jain)" * tag 'thermal-v7.2-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (34 commits) thermal/drivers/qcom/tsens: Disable wakeup interrupt setup on automotive targets thermal/drivers/qcom/tsens: Switch wake IRQ handling to PM callbacks thermal/core: Fix missing stub for devm_thermal_cooling_device_register dt-bindings: thermal: cooling-devices: Update support for 3 cells cooling device thermal/of: Support cooling device ID in cooling-spec thermal/of: Pass cdev_id and introduce devm registration helper thermal/of: Add cooling device ID support thermal/of: Rename the devm_thermal_of_cooling_device_register() function thermal/core: Make cooling device OF node conditional on CONFIG_THERMAL_OF thermal/of: Move cooling device OF helpers out of thermal core hwmon: Use non-OF thermal cooling device registration API thermal/core: Add devm_thermal_cooling_device_register() thermal/core: Introduce non-OF thermal_cooling_device_register() thermal/drivers/samsung: Enable TMU by default thermal/driver/qoriq: Workaround unexpected temperature readings from tmu thermal/drivers/qoriq: Add i.MX93 tmu support dt-bindings: thermal: qoriq: Add compatible string for imx93 thermal/drivers/spacemit/k1: Add thermal sensor support dt-bindings: thermal: Add SpacemiT K1 thermal sensor thermal/drivers/imx: Do not split quoted string across lines ...
This commit is contained in:
commit
bdbca04e7e
|
|
@ -63,7 +63,8 @@ properties:
|
|||
description: The PWM that is used to control the fan.
|
||||
maxItems: 1
|
||||
|
||||
"#cooling-cells": true
|
||||
"#cooling-cells":
|
||||
const: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ properties:
|
|||
- amlogic,g12a-cpu-thermal
|
||||
- amlogic,g12a-ddr-thermal
|
||||
- const: amlogic,g12a-thermal
|
||||
- const: amlogic,a1-cpu-thermal
|
||||
- enum:
|
||||
- amlogic,a1-cpu-thermal
|
||||
- amlogic,t7-thermal
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
@ -42,12 +44,34 @@ properties:
|
|||
'#thermal-sensor-cells':
|
||||
const: 0
|
||||
|
||||
amlogic,secure-monitor:
|
||||
description: phandle to the secure monitor
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
- description: phandle to the secure monitor
|
||||
- description: sensor index to get specific calibration data
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- amlogic,ao-secure
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- amlogic,a1-cpu-thermal
|
||||
- amlogic,g12a-thermal
|
||||
then:
|
||||
required:
|
||||
- amlogic,ao-secure
|
||||
else:
|
||||
required:
|
||||
- amlogic,secure-monitor
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
@ -62,4 +86,13 @@ examples:
|
|||
#thermal-sensor-cells = <0>;
|
||||
amlogic,ao-secure = <&sec_AO>;
|
||||
};
|
||||
- |
|
||||
temperature-sensor@20000 {
|
||||
compatible = "amlogic,t7-thermal";
|
||||
reg = <0x0 0x20000 0x0 0x50>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clkc_periphs CLKID_TS>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
amlogic,secure-monitor = <&sm 1>;
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -56,8 +56,10 @@ properties:
|
|||
- enum:
|
||||
- qcom,eliza-tsens
|
||||
- qcom,glymur-tsens
|
||||
- qcom,hawi-tsens
|
||||
- qcom,kaanapali-tsens
|
||||
- qcom,milos-tsens
|
||||
- qcom,nord-tsens
|
||||
- qcom,msm8953-tsens
|
||||
- qcom,msm8996-tsens
|
||||
- qcom,msm8998-tsens
|
||||
|
|
@ -74,6 +76,7 @@ properties:
|
|||
- qcom,sdm630-tsens
|
||||
- qcom,sdm670-tsens
|
||||
- qcom,sdm845-tsens
|
||||
- qcom,shikra-tsens
|
||||
- qcom,sm6115-tsens
|
||||
- qcom,sm6350-tsens
|
||||
- qcom,sm6375-tsens
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ properties:
|
|||
enum:
|
||||
- fsl,qoriq-tmu
|
||||
- fsl,imx8mq-tmu
|
||||
- fsl,imx93-tmu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/thermal/spacemit,k1-tsensor.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SpacemiT K1 Thermal Sensor
|
||||
|
||||
description:
|
||||
The SpacemiT K1 Thermal Sensor monitors the temperature of the SoC
|
||||
using multiple internal sensors (e.g., soc, package, gpu, clusters).
|
||||
|
||||
maintainers:
|
||||
- Shuwei Wu <shuwei.wu@mailbox.org>
|
||||
|
||||
$ref: thermal-sensor.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: spacemit,k1-tsensor
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Core clock for thermal sensor
|
||||
- description: Bus clock for thermal sensor
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: bus
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: Reset for the thermal sensor
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
description:
|
||||
The first cell indicates the sensor ID.
|
||||
0 = soc
|
||||
1 = package
|
||||
2 = gpu
|
||||
3 = cluster0
|
||||
4 = cluster1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- "#thermal-sensor-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/spacemit,k1-syscon.h>
|
||||
|
||||
thermal@d4018000 {
|
||||
compatible = "spacemit,k1-tsensor";
|
||||
reg = <0xd4018000 0x100>;
|
||||
clocks = <&syscon_apbc CLK_TSEN>,
|
||||
<&syscon_apbc CLK_TSEN_BUS>;
|
||||
clock-names = "core", "bus";
|
||||
interrupts = <61>;
|
||||
resets = <&syscon_apbc RESET_TSEN>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
|
@ -44,10 +44,14 @@ select: true
|
|||
properties:
|
||||
"#cooling-cells":
|
||||
description:
|
||||
Must be 2, in order to specify minimum and maximum cooling state used in
|
||||
Must be 2 or 3. If 2, specifies minimum and maximum cooling state used in
|
||||
the cooling-maps reference. The first cell is the minimum cooling state
|
||||
and the second cell is the maximum cooling state requested.
|
||||
const: 2
|
||||
If 3, the first cell specifies the thermal mitigation device specifier
|
||||
index for devices that support multiple thermal mitigation mechanisms.
|
||||
The two other cells are respectively the minimum cooling state and the
|
||||
maximum cooling state.
|
||||
enum: [2, 3]
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
|
|
|
|||
|
|
@ -211,7 +211,8 @@ patternProperties:
|
|||
device. Using the THERMAL_NO_LIMIT (-1UL) constant in the
|
||||
cooling-device phandle limit specifier lets the framework
|
||||
use the minimum and maximum cooling state for that cooling
|
||||
device automatically.
|
||||
device automatically. If three arguments are specified,
|
||||
the first argument is the cooling device specifier.
|
||||
|
||||
contribution:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
|
|
|||
|
|
@ -41,12 +41,13 @@ static const struct meson_sm_chip gxbb_chip = {
|
|||
.cmd_shmem_in_base = 0x82000020,
|
||||
.cmd_shmem_out_base = 0x82000021,
|
||||
.cmd = {
|
||||
CMD(SM_EFUSE_READ, 0x82000030),
|
||||
CMD(SM_EFUSE_WRITE, 0x82000031),
|
||||
CMD(SM_EFUSE_READ, 0x82000030),
|
||||
CMD(SM_EFUSE_WRITE, 0x82000031),
|
||||
CMD(SM_EFUSE_USER_MAX, 0x82000033),
|
||||
CMD(SM_GET_CHIP_ID, 0x82000044),
|
||||
CMD(SM_A1_PWRC_SET, 0x82000093),
|
||||
CMD(SM_A1_PWRC_GET, 0x82000095),
|
||||
CMD(SM_GET_CHIP_ID, 0x82000044),
|
||||
CMD(SM_THERMAL_CALIB_READ, 0x82000047),
|
||||
CMD(SM_A1_PWRC_SET, 0x82000093),
|
||||
CMD(SM_A1_PWRC_GET, 0x82000095),
|
||||
{ /* sentinel */ },
|
||||
},
|
||||
};
|
||||
|
|
@ -245,6 +246,23 @@ struct meson_sm_firmware *meson_sm_get(struct device_node *sm_node)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(meson_sm_get);
|
||||
|
||||
/**
|
||||
* meson_sm_get_thermal_calib - Read thermal sensor calibration data.
|
||||
* @fw: Pointer to secure-monitor firmware.
|
||||
* @trim_info: Pointer to store the returned calibration data.
|
||||
* @tsensor_id: Sensor index to identify which sensor's calibration data
|
||||
* to retrieve
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int meson_sm_get_thermal_calib(struct meson_sm_firmware *fw, u32 *trim_info,
|
||||
u32 tsensor_id)
|
||||
{
|
||||
return meson_sm_call(fw, SM_THERMAL_CALIB_READ, trim_info, tsensor_id,
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_sm_get_thermal_calib);
|
||||
|
||||
#define SM_CHIP_ID_LENGTH 119
|
||||
#define SM_CHIP_ID_OFFSET 4
|
||||
#define SM_CHIP_ID_SIZE 12
|
||||
|
|
|
|||
|
|
@ -1791,8 +1791,9 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
|
|||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL)) {
|
||||
gpu->cooling = thermal_of_cooling_device_register(dev->of_node,
|
||||
(char *)dev_name(dev), gpu, &cooling_ops);
|
||||
gpu->cooling = thermal_of_cooling_device_register(dev->of_node, 0,
|
||||
dev_name(dev),
|
||||
gpu, &cooling_ops);
|
||||
if (IS_ERR(gpu->cooling))
|
||||
return PTR_ERR(gpu->cooling);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ static int amc6821_probe(struct i2c_client *client)
|
|||
"Failed to initialize hwmon\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_THERMAL) && fan_np && data->fan_cooling_levels)
|
||||
return PTR_ERR_OR_ZERO(devm_thermal_of_cooling_device_register(dev,
|
||||
return PTR_ERR_OR_ZERO(devm_thermal_of_child_cooling_device_register(dev,
|
||||
fan_np, client->name, data, &amc6821_cooling_ops));
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -841,8 +841,9 @@ static int aspeed_create_pwm_cooling(struct device *dev,
|
|||
}
|
||||
snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port);
|
||||
|
||||
cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
|
||||
cdev->name, cdev, &aspeed_pwm_cool_ops);
|
||||
cdev->tcdev = devm_thermal_of_child_cooling_device_register(dev, child,
|
||||
cdev->name, cdev,
|
||||
&aspeed_pwm_cool_ops);
|
||||
if (IS_ERR(cdev->tcdev))
|
||||
return PTR_ERR(cdev->tcdev);
|
||||
|
||||
|
|
|
|||
|
|
@ -532,8 +532,8 @@ static void cros_ec_hwmon_register_fan_cooling_devices(struct device *dev,
|
|||
|
||||
cpriv->hwmon_priv = priv;
|
||||
cpriv->index = i;
|
||||
cdev = devm_thermal_of_cooling_device_register(dev, NULL, type, cpriv,
|
||||
&cros_ec_thermal_cooling_ops);
|
||||
cdev = devm_thermal_cooling_device_register(dev, type, cpriv,
|
||||
&cros_ec_thermal_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
dev_warn(dev, "failed to register fan %zu as a cooling device: %pe\n", i,
|
||||
cdev);
|
||||
|
|
|
|||
|
|
@ -1161,8 +1161,8 @@ static int dell_smm_init_cdev(struct device *dev, u8 fan_num)
|
|||
if (cdata) {
|
||||
cdata->fan_num = fan_num;
|
||||
cdata->data = data;
|
||||
cdev = devm_thermal_of_cooling_device_register(dev, NULL, name, cdata,
|
||||
&dell_smm_cooling_ops);
|
||||
cdev = devm_thermal_cooling_device_register(dev, name, cdata,
|
||||
&dell_smm_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
devm_kfree(dev, cdata);
|
||||
ret = PTR_ERR(cdev);
|
||||
|
|
|
|||
|
|
@ -309,9 +309,9 @@ static int emc2305_set_single_tz(struct device *dev, struct device_node *fan_nod
|
|||
pwm = data->pwm_min[cdev_idx];
|
||||
|
||||
data->cdev_data[cdev_idx].cdev =
|
||||
devm_thermal_of_cooling_device_register(dev, fan_node,
|
||||
emc2305_fan_name[idx], data,
|
||||
&emc2305_cooling_ops);
|
||||
devm_thermal_of_child_cooling_device_register(dev, fan_node,
|
||||
emc2305_fan_name[idx], data,
|
||||
&emc2305_cooling_ops);
|
||||
|
||||
if (IS_ERR(data->cdev_data[cdev_idx].cdev)) {
|
||||
dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]);
|
||||
|
|
|
|||
|
|
@ -592,8 +592,10 @@ static int gpio_fan_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* Optional cooling device register for Device tree platforms */
|
||||
fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
|
||||
"gpio-fan", fan_data, &gpio_fan_cool_ops);
|
||||
fan_data->cdev = devm_thermal_of_child_cooling_device_register(dev, np,
|
||||
"gpio-fan",
|
||||
fan_data,
|
||||
&gpio_fan_cool_ops);
|
||||
|
||||
dev_info(dev, "GPIO fan initialized\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -794,9 +794,9 @@ static int max6650_probe(struct i2c_client *client)
|
|||
return err;
|
||||
|
||||
if (IS_ENABLED(CONFIG_THERMAL)) {
|
||||
cooling_dev = devm_thermal_of_cooling_device_register(dev,
|
||||
dev->of_node, client->name,
|
||||
data, &max6650_cooling_ops);
|
||||
cooling_dev = devm_thermal_of_child_cooling_device_register(dev, dev->of_node,
|
||||
client->name, data,
|
||||
&max6650_cooling_ops);
|
||||
if (IS_ERR(cooling_dev)) {
|
||||
dev_warn(dev, "thermal cooling device register failed: %ld\n",
|
||||
PTR_ERR(cooling_dev));
|
||||
|
|
|
|||
|
|
@ -583,8 +583,8 @@ static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan)
|
|||
pwm->fan = fan;
|
||||
/* Set minimal PWM speed. */
|
||||
pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY);
|
||||
pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i],
|
||||
pwm, &mlxreg_fan_cooling_ops);
|
||||
pwm->cdev = devm_thermal_cooling_device_register(dev, mlxreg_fan_name[i],
|
||||
pwm, &mlxreg_fan_cooling_ops);
|
||||
if (IS_ERR(pwm->cdev)) {
|
||||
dev_err(dev, "Failed to register cooling device\n");
|
||||
return PTR_ERR(pwm->cdev);
|
||||
|
|
|
|||
|
|
@ -857,8 +857,10 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
|
|||
snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
|
||||
pwm_port);
|
||||
|
||||
cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
|
||||
cdev->name, cdev, &npcm7xx_pwm_cool_ops);
|
||||
cdev->tcdev = devm_thermal_of_child_cooling_device_register(dev, child,
|
||||
cdev->name,
|
||||
cdev,
|
||||
&npcm7xx_pwm_cool_ops);
|
||||
if (IS_ERR(cdev->tcdev))
|
||||
return PTR_ERR(cdev->tcdev);
|
||||
|
||||
|
|
|
|||
|
|
@ -685,8 +685,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
|
|||
|
||||
ctx->pwm_fan_state = ctx->pwm_fan_max_state;
|
||||
if (IS_ENABLED(CONFIG_THERMAL)) {
|
||||
cdev = devm_thermal_of_cooling_device_register(dev,
|
||||
dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops);
|
||||
cdev = devm_thermal_of_child_cooling_device_register(dev, dev->of_node,
|
||||
"pwm-fan", ctx,
|
||||
&pwm_fan_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
dev_err(dev,
|
||||
|
|
|
|||
|
|
@ -337,9 +337,9 @@ static int qnap_mcu_hwmon_probe(struct platform_device *pdev)
|
|||
* levels and only succeed with either no or correct cooling levels.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_THERMAL) && hwm->fan_cooling_levels) {
|
||||
cdev = devm_thermal_of_cooling_device_register(dev,
|
||||
to_of_node(hwm->fan_node), "qnap-mcu-hwmon",
|
||||
hwm, &qnap_mcu_hwmon_cooling_ops);
|
||||
cdev = devm_thermal_of_child_cooling_device_register(dev, to_of_node(hwm->fan_node),
|
||||
"qnap-mcu-hwmon", hwm,
|
||||
&qnap_mcu_hwmon_cooling_ops);
|
||||
if (IS_ERR(cdev))
|
||||
return dev_err_probe(dev, PTR_ERR(cdev),
|
||||
"Failed to register qnap-mcu-hwmon as cooling device\n");
|
||||
|
|
|
|||
|
|
@ -541,8 +541,9 @@ static int tc654_probe(struct i2c_client *client)
|
|||
if (IS_ENABLED(CONFIG_THERMAL)) {
|
||||
struct thermal_cooling_device *cdev;
|
||||
|
||||
cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, client->name,
|
||||
hwmon_dev, &tc654_fan_cool_ops);
|
||||
cdev = devm_thermal_of_child_cooling_device_register(dev, dev->of_node,
|
||||
client->name, hwmon_dev,
|
||||
&tc654_fan_cool_ops);
|
||||
return PTR_ERR_OR_ZERO(cdev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1966,8 +1966,8 @@ static int tegra210_emc_probe(struct platform_device *pdev)
|
|||
|
||||
tegra210_emc_debugfs_init(emc);
|
||||
|
||||
cd = devm_thermal_of_cooling_device_register(emc->dev, np, "emc", emc,
|
||||
&tegra210_emc_cd_ops);
|
||||
cd = devm_thermal_of_child_cooling_device_register(emc->dev, np, "emc", emc,
|
||||
&tegra210_emc_cd_ops);
|
||||
if (IS_ERR(cd)) {
|
||||
err = PTR_ERR(cd);
|
||||
dev_err(emc->dev, "failed to register cooling device: %d\n",
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ static int qmp_cooling_device_add(struct qmp *qmp,
|
|||
qmp_cdev->qmp = qmp;
|
||||
qmp_cdev->state = !qmp_cdev_max_state;
|
||||
qmp_cdev->name = cdev_name;
|
||||
qmp_cdev->cdev = devm_thermal_of_cooling_device_register
|
||||
qmp_cdev->cdev = devm_thermal_of_child_cooling_device_register
|
||||
(qmp->dev, node,
|
||||
cdev_name,
|
||||
qmp_cdev, &qmp_cooling_device_ops);
|
||||
|
|
|
|||
|
|
@ -436,6 +436,7 @@ config AMLOGIC_THERMAL
|
|||
tristate "Amlogic Thermal Support"
|
||||
default ARCH_MESON
|
||||
depends on OF && ARCH_MESON
|
||||
depends on MESON_SM
|
||||
help
|
||||
If you say yes here you get support for Amlogic Thermal
|
||||
for G12 SoC Family.
|
||||
|
|
@ -472,6 +473,8 @@ endmenu
|
|||
|
||||
source "drivers/thermal/renesas/Kconfig"
|
||||
|
||||
source "drivers/thermal/spacemit/Kconfig"
|
||||
|
||||
source "drivers/thermal/tegra/Kconfig"
|
||||
|
||||
config GENERIC_ADC_THERMAL
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ obj-y += mediatek/
|
|||
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
|
||||
obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
|
||||
obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
|
||||
obj-y += spacemit/
|
||||
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
|
||||
obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o
|
||||
obj-$(CONFIG_LOONGSON2_THERMAL) += loongson2_thermal.o
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/firmware/meson/meson_sm.h>
|
||||
|
||||
#include "thermal_hwmon.h"
|
||||
|
||||
|
|
@ -84,12 +85,14 @@ struct amlogic_thermal_soc_calib_data {
|
|||
* @u_efuse_off: register offset to read fused calibration value
|
||||
* @calibration_parameters: calibration parameters structure pointer
|
||||
* @regmap_config: regmap config for the device
|
||||
* @use_sm: read data from secure monitor instead of efuse
|
||||
* This structure is required for configuration of amlogic thermal driver.
|
||||
*/
|
||||
struct amlogic_thermal_data {
|
||||
int u_efuse_off;
|
||||
const struct amlogic_thermal_soc_calib_data *calibration_parameters;
|
||||
const struct regmap_config *regmap_config;
|
||||
bool use_sm;
|
||||
};
|
||||
|
||||
struct amlogic_thermal {
|
||||
|
|
@ -100,6 +103,8 @@ struct amlogic_thermal {
|
|||
struct clk *clk;
|
||||
struct thermal_zone_device *tzd;
|
||||
u32 trim_info;
|
||||
struct meson_sm_firmware *sm_fw;
|
||||
u32 tsensor_id;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -133,26 +138,6 @@ static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata,
|
|||
return temp;
|
||||
}
|
||||
|
||||
static int amlogic_thermal_initialize(struct amlogic_thermal *pdata)
|
||||
{
|
||||
int ret = 0;
|
||||
int ver;
|
||||
|
||||
regmap_read(pdata->sec_ao_map, pdata->data->u_efuse_off,
|
||||
&pdata->trim_info);
|
||||
|
||||
ver = TSENSOR_TRIM_VERSION(pdata->trim_info);
|
||||
|
||||
if ((ver & TSENSOR_TRIM_CALIB_VALID_MASK) == 0) {
|
||||
ret = -EINVAL;
|
||||
dev_err(&pdata->pdev->dev,
|
||||
"tsensor thermal calibration not supported: 0x%x!\n",
|
||||
ver);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amlogic_thermal_enable(struct amlogic_thermal *data)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -190,6 +175,67 @@ static int amlogic_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amlogic_thermal_probe_sm(struct platform_device *pdev,
|
||||
struct amlogic_thermal *pdata)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct of_phandle_args ph_args;
|
||||
int ret;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"amlogic,secure-monitor",
|
||||
1, 0, &ph_args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!ph_args.np) {
|
||||
dev_err(dev, "Failed to parse secure monitor phandle\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata->sm_fw = meson_sm_get(ph_args.np);
|
||||
of_node_put(ph_args.np);
|
||||
if (!pdata->sm_fw) {
|
||||
dev_err(dev, "Failed to get secure monitor firmware\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
pdata->tsensor_id = ph_args.args[0];
|
||||
|
||||
return meson_sm_get_thermal_calib(pdata->sm_fw,
|
||||
&pdata->trim_info,
|
||||
pdata->tsensor_id);
|
||||
}
|
||||
|
||||
static int amlogic_thermal_probe_syscon(struct platform_device *pdev,
|
||||
struct amlogic_thermal *pdata)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int ver;
|
||||
|
||||
pdata->sec_ao_map =
|
||||
syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"amlogic,ao-secure");
|
||||
if (IS_ERR(pdata->sec_ao_map)) {
|
||||
dev_err(dev, "syscon regmap lookup failed.\n");
|
||||
return PTR_ERR(pdata->sec_ao_map);
|
||||
}
|
||||
|
||||
regmap_read(pdata->sec_ao_map, pdata->data->u_efuse_off,
|
||||
&pdata->trim_info);
|
||||
|
||||
ver = TSENSOR_TRIM_VERSION(pdata->trim_info);
|
||||
|
||||
if ((ver & TSENSOR_TRIM_CALIB_VALID_MASK) == 0) {
|
||||
dev_err(&pdata->pdev->dev,
|
||||
"tsensor thermal calibration not supported: 0x%x!\n",
|
||||
ver);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops amlogic_thermal_ops = {
|
||||
.get_temp = amlogic_thermal_get_temp,
|
||||
};
|
||||
|
|
@ -226,6 +272,12 @@ static const struct amlogic_thermal_data amlogic_thermal_a1_cpu_param = {
|
|||
.regmap_config = &amlogic_thermal_regmap_config_g12a,
|
||||
};
|
||||
|
||||
static const struct amlogic_thermal_data amlogic_thermal_t7_param = {
|
||||
.use_sm = true,
|
||||
.calibration_parameters = &amlogic_thermal_g12a,
|
||||
.regmap_config = &amlogic_thermal_regmap_config_g12a,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_amlogic_thermal_match[] = {
|
||||
{
|
||||
.compatible = "amlogic,g12a-ddr-thermal",
|
||||
|
|
@ -239,6 +291,10 @@ static const struct of_device_id of_amlogic_thermal_match[] = {
|
|||
.compatible = "amlogic,a1-cpu-thermal",
|
||||
.data = &amlogic_thermal_a1_cpu_param,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,t7-thermal",
|
||||
.data = &amlogic_thermal_t7_param,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_amlogic_thermal_match);
|
||||
|
|
@ -271,12 +327,12 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(pdata->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(pdata->clk), "failed to get clock\n");
|
||||
|
||||
pdata->sec_ao_map = syscon_regmap_lookup_by_phandle
|
||||
(pdev->dev.of_node, "amlogic,ao-secure");
|
||||
if (IS_ERR(pdata->sec_ao_map)) {
|
||||
dev_err(dev, "syscon regmap lookup failed.\n");
|
||||
return PTR_ERR(pdata->sec_ao_map);
|
||||
}
|
||||
if (pdata->data->use_sm)
|
||||
ret = amlogic_thermal_probe_sm(pdev, pdata);
|
||||
else
|
||||
ret = amlogic_thermal_probe_syscon(pdev, pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pdata->tzd = devm_thermal_of_zone_register(&pdev->dev,
|
||||
0,
|
||||
|
|
@ -290,10 +346,6 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
|
|||
|
||||
devm_thermal_add_hwmon_sysfs(&pdev->dev, pdata->tzd);
|
||||
|
||||
ret = amlogic_thermal_initialize(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = amlogic_thermal_enable(pdata);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -592,7 +592,7 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||
if (!name)
|
||||
goto remove_qos_req;
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, name, cpufreq_cdev,
|
||||
cdev = thermal_of_cooling_device_register(np, 0, name, cpufreq_cdev,
|
||||
cooling_ops);
|
||||
kfree(name);
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ static int __cpuidle_cooling_register(struct device_node *np,
|
|||
goto out_unregister;
|
||||
}
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, name, idle_cdev,
|
||||
cdev = thermal_of_cooling_device_register(np, 0, name, idle_cdev,
|
||||
&cpuidle_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
|
|||
if (!name)
|
||||
goto remove_qos_req;
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, name, dfc, ops);
|
||||
cdev = thermal_of_cooling_device_register(np, 0, name, dfc, ops);
|
||||
kfree(name);
|
||||
|
||||
if (IS_ERR(cdev)) {
|
||||
|
|
|
|||
|
|
@ -693,8 +693,8 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
|||
goto clk_disable;
|
||||
}
|
||||
|
||||
dev_info(dev, "%s CPU temperature grade - max:%dC"
|
||||
" critical:%dC passive:%dC\n", data->temp_grade,
|
||||
dev_info(dev, "%s CPU temperature grade - max:%dC critical:%dC passive:%dC\n",
|
||||
data->temp_grade,
|
||||
data->temp_max / 1000, trips[IMX_TRIP_CRITICAL].temperature / 1000,
|
||||
trips[IMX_TRIP_PASSIVE].temperature / 1000);
|
||||
|
||||
|
|
|
|||
|
|
@ -90,9 +90,10 @@ static int khadas_mcu_fan_probe(struct platform_device *pdev)
|
|||
ctx->mcu = mcu;
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
cdev = devm_thermal_of_cooling_device_register(dev->parent,
|
||||
dev->parent->of_node, "khadas-mcu-fan", ctx,
|
||||
&khadas_mcu_fan_cooling_ops);
|
||||
cdev = devm_thermal_of_child_cooling_device_register(dev->parent,
|
||||
dev->parent->of_node,
|
||||
"khadas-mcu-fan", ctx,
|
||||
&khadas_mcu_fan_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
dev_err(dev, "Failed to register khadas-mcu-fan as cooling device: %d\n",
|
||||
|
|
|
|||
|
|
@ -263,7 +263,6 @@ static int __init init_tsens_v2_no_rpm(struct tsens_priv *priv)
|
|||
static const struct tsens_ops ops_generic_v2 = {
|
||||
.init = init_common,
|
||||
.get_temp = get_temp_tsens_valid,
|
||||
.resume = tsens_resume_common,
|
||||
};
|
||||
|
||||
struct tsens_plat_data data_tsens_v2 = {
|
||||
|
|
@ -307,3 +306,11 @@ struct tsens_plat_data data_8996 = {
|
|||
.feat = &tsens_v2_feat,
|
||||
.fields = tsens_v2_regfields,
|
||||
};
|
||||
|
||||
/* Do not enable wakeup capable interrupts for automotive platforms */
|
||||
struct tsens_plat_data data_automotive_v2 = {
|
||||
.ops = &ops_generic_v2,
|
||||
.feat = &tsens_v2_feat,
|
||||
.fields = tsens_v2_regfields,
|
||||
.no_irq_wake = true,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
* @up_viol: upper threshold violated
|
||||
* @up_thresh: upper threshold temperature value
|
||||
* @up_irq_mask: mask register for upper threshold irqs
|
||||
* @up_irq_clear: clear register for uppper threshold irqs
|
||||
* @up_irq_clear: clear register for upper threshold irqs
|
||||
* @low_viol: lower threshold violated
|
||||
* @low_thresh: lower threshold temperature value
|
||||
* @low_irq_mask: mask register for lower threshold irqs
|
||||
|
|
@ -316,9 +316,66 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
|
|||
}
|
||||
|
||||
/**
|
||||
* tsens_hw_to_mC - Return sign-extended temperature in mCelsius.
|
||||
* tsens_read_temp - Retrieve temperature readings from the hardware.
|
||||
* @s: Pointer to sensor struct
|
||||
* @field: Index into regmap_field array pointing to temperature data
|
||||
* @temp: temperature in deciCelsius to be read from hardware
|
||||
*
|
||||
* This function handles temperature returned in ADC code or deciCelsius
|
||||
* depending on IP version.
|
||||
*
|
||||
* Return: 0 on success, a negative errno will be returned in error cases
|
||||
*/
|
||||
static int tsens_read_temp(const struct tsens_sensor *s, int field, int *temp)
|
||||
{
|
||||
struct tsens_priv *priv = s->priv;
|
||||
int temp_val[MAX_READ_RETRY] = {0};
|
||||
u32 status;
|
||||
int ret;
|
||||
u32 last_temp_mask = GENMASK(priv->fields[LAST_TEMP_0].msb,
|
||||
priv->fields[LAST_TEMP_0].lsb);
|
||||
u32 valid_bit = priv->rf[VALID_0] ? BIT(priv->fields[VALID_0].lsb) : 0;
|
||||
|
||||
for (int i = 0; i < MAX_READ_RETRY; i++) {
|
||||
ret = regmap_read(priv->tm_map, priv->fields[field].reg, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* VER_0 doesn't have a VALID bit */
|
||||
if (!valid_bit) {
|
||||
*temp = status & last_temp_mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
temp_val[i] = status & last_temp_mask;
|
||||
|
||||
if (status & valid_bit) {
|
||||
*temp = temp_val[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* As per the HW guidelines, if none of the attempts observe a
|
||||
* valid sample, a stable fallback value must be returned. If the
|
||||
* first and second samples match, the second value is returned;
|
||||
* otherwise, if the second and third samples match, the third
|
||||
* value is returned.
|
||||
*/
|
||||
if (temp_val[0] == temp_val[1])
|
||||
*temp = temp_val[1];
|
||||
else if (temp_val[1] == temp_val[2])
|
||||
*temp = temp_val[2];
|
||||
else
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tsens_hw_to_mC - Return sign-extended temperature in mCelsius.
|
||||
* @s: Pointer to sensor struct
|
||||
* @temp: temperature in milliCelsius to be read from hardware
|
||||
*
|
||||
* This function handles temperature returned in ADC code or deciCelsius
|
||||
* depending on IP version.
|
||||
|
|
@ -326,20 +383,14 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
|
|||
* Return: Temperature in milliCelsius on success, a negative errno will
|
||||
* be returned in error cases
|
||||
*/
|
||||
static int tsens_hw_to_mC(const struct tsens_sensor *s, int field)
|
||||
static int tsens_hw_to_mC(const struct tsens_sensor *s, int temp)
|
||||
{
|
||||
struct tsens_priv *priv = s->priv;
|
||||
u32 resolution;
|
||||
u32 temp = 0;
|
||||
int ret;
|
||||
|
||||
resolution = priv->fields[LAST_TEMP_0].msb -
|
||||
priv->fields[LAST_TEMP_0].lsb;
|
||||
|
||||
ret = regmap_field_read(priv->rf[field], &temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Convert temperature from ADC code to milliCelsius */
|
||||
if (priv->feat->adc)
|
||||
return code_to_degc(temp, s) * 1000;
|
||||
|
|
@ -514,8 +565,10 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
|
|||
&d->crit_irq_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
d->crit_thresh = tsens_hw_to_mC(s, CRIT_THRESH_0 + hw_id);
|
||||
ret = regmap_field_read(priv->rf[CRIT_THRESH_0 + hw_id], &d->crit_thresh);
|
||||
if (ret)
|
||||
return ret;
|
||||
d->crit_thresh = tsens_hw_to_mC(s, d->crit_thresh);
|
||||
} else {
|
||||
/* No mask register on older TSENS */
|
||||
d->up_irq_mask = 0;
|
||||
|
|
@ -525,8 +578,16 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
|
|||
d->crit_thresh = 0;
|
||||
}
|
||||
|
||||
d->up_thresh = tsens_hw_to_mC(s, UP_THRESH_0 + hw_id);
|
||||
d->low_thresh = tsens_hw_to_mC(s, LOW_THRESH_0 + hw_id);
|
||||
ret = regmap_field_read(priv->rf[UP_THRESH_0 + hw_id], &d->up_thresh);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
d->up_thresh = tsens_hw_to_mC(s, d->up_thresh);
|
||||
ret = regmap_field_read(priv->rf[LOW_THRESH_0 + hw_id], &d->low_thresh);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
d->low_thresh = tsens_hw_to_mC(s, d->low_thresh);
|
||||
|
||||
dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u|%u) | clr(%u|%u|%u) | mask(%u|%u|%u)\n",
|
||||
hw_id, __func__,
|
||||
|
|
@ -750,33 +811,15 @@ static void tsens_disable_irq(struct tsens_priv *priv)
|
|||
|
||||
int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
|
||||
{
|
||||
struct tsens_priv *priv = s->priv;
|
||||
int hw_id = s->hw_id;
|
||||
u32 temp_idx = LAST_TEMP_0 + hw_id;
|
||||
u32 valid_idx = VALID_0 + hw_id;
|
||||
u32 valid;
|
||||
int ret;
|
||||
|
||||
/* VER_0 doesn't have VALID bit */
|
||||
if (tsens_version(priv) == VER_0)
|
||||
goto get_temp;
|
||||
ret = tsens_read_temp(s, temp_idx, temp);
|
||||
if (!ret)
|
||||
*temp = tsens_hw_to_mC(s, *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);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_temp_common(const struct tsens_sensor *s, int *temp)
|
||||
|
|
@ -1086,22 +1129,30 @@ static int tsens_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
|
||||
static int __maybe_unused tsens_suspend(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tsens_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (priv->ops && priv->ops->suspend)
|
||||
return priv->ops->suspend(priv);
|
||||
if (priv->ops && priv->ops->suspend) {
|
||||
ret = priv->ops->suspend(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tsens_suspend_common(priv);
|
||||
}
|
||||
|
||||
static int __maybe_unused tsens_resume(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tsens_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (priv->ops && priv->ops->resume)
|
||||
return priv->ops->resume(priv);
|
||||
if (priv->ops && priv->ops->resume) {
|
||||
ret = priv->ops->resume(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tsens_resume_common(priv);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
|
||||
|
|
@ -1161,6 +1212,12 @@ static const struct of_device_id tsens_table[] = {
|
|||
}, {
|
||||
.compatible = "qcom,tsens-v2",
|
||||
.data = &data_tsens_v2,
|
||||
}, {
|
||||
.compatible = "qcom,sa8775p-tsens",
|
||||
.data = &data_automotive_v2,
|
||||
}, {
|
||||
.compatible = "qcom,sa8255p-tsens",
|
||||
.data = &data_automotive_v2,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
|
@ -1172,7 +1229,7 @@ static const struct thermal_zone_device_ops tsens_of_ops = {
|
|||
};
|
||||
|
||||
static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
|
||||
irq_handler_t thread_fn)
|
||||
irq_handler_t thread_fn, int *irq_num)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int ret, irq;
|
||||
|
|
@ -1205,7 +1262,7 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
|
|||
dev_err(&pdev->dev, "%s: failed to get irq\n",
|
||||
__func__);
|
||||
else
|
||||
enable_irq_wake(irq);
|
||||
*irq_num = irq;
|
||||
}
|
||||
|
||||
put_device(&pdev->dev);
|
||||
|
|
@ -1232,11 +1289,38 @@ static int tsens_reinit(struct tsens_priv *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int tsens_suspend_common(struct tsens_priv *priv)
|
||||
{
|
||||
if (!device_may_wakeup(priv->dev))
|
||||
return 0;
|
||||
|
||||
if (priv->feat->combo_int)
|
||||
enable_irq_wake(priv->combined_irq);
|
||||
else {
|
||||
enable_irq_wake(priv->uplow_irq);
|
||||
if (priv->feat->crit_int)
|
||||
enable_irq_wake(priv->crit_irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsens_resume_common(struct tsens_priv *priv)
|
||||
{
|
||||
if (pm_suspend_target_state == PM_SUSPEND_MEM)
|
||||
tsens_reinit(priv);
|
||||
|
||||
if (!device_may_wakeup(priv->dev))
|
||||
return 0;
|
||||
|
||||
if (priv->feat->combo_int)
|
||||
disable_irq_wake(priv->combined_irq);
|
||||
else {
|
||||
disable_irq_wake(priv->uplow_irq);
|
||||
if (priv->feat->crit_int)
|
||||
disable_irq_wake(priv->crit_irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1276,15 +1360,18 @@ static int tsens_register(struct tsens_priv *priv)
|
|||
|
||||
if (priv->feat->combo_int) {
|
||||
ret = tsens_register_irq(priv, "combined",
|
||||
tsens_combined_irq_thread);
|
||||
tsens_combined_irq_thread, &priv->combined_irq);
|
||||
} else {
|
||||
ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
|
||||
ret = tsens_register_irq(priv, "uplow", tsens_irq_thread,
|
||||
&priv->uplow_irq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (priv->feat->crit_int)
|
||||
if (priv->feat->crit_int) {
|
||||
ret = tsens_register_irq(priv, "critical",
|
||||
tsens_critical_irq_thread);
|
||||
tsens_critical_irq_thread,
|
||||
&priv->crit_irq);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -1343,6 +1430,8 @@ static int tsens_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
device_init_wakeup(dev, !data->no_irq_wake);
|
||||
|
||||
if (!priv->ops || !priv->ops->init || !priv->ops->get_temp)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#define THRESHOLD_MIN_ADC_CODE 0x0
|
||||
|
||||
#define MAX_SENSORS 16
|
||||
#define MAX_READ_RETRY 3
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/thermal.h>
|
||||
|
|
@ -531,6 +532,7 @@ struct tsens_features {
|
|||
* @hw_ids: Subset of sensors ids supported by platform, if not the first n
|
||||
* @feat: features of the IP
|
||||
* @fields: bitfield locations
|
||||
* @no_irq_wake: if set, TSENS interrupts will not be configured as wakeup sources
|
||||
*/
|
||||
struct tsens_plat_data {
|
||||
const u32 num_sensors;
|
||||
|
|
@ -538,6 +540,7 @@ struct tsens_plat_data {
|
|||
unsigned int *hw_ids;
|
||||
struct tsens_features *feat;
|
||||
const struct reg_field *fields;
|
||||
bool no_irq_wake;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -567,6 +570,9 @@ struct tsens_context {
|
|||
* @ops: pointer to list of callbacks supported by this device
|
||||
* @debug_root: pointer to debugfs dentry for all tsens
|
||||
* @debug: pointer to debugfs dentry for tsens controller
|
||||
* @uplow_irq: IRQ number for uplow (upper/lower) threshold interrupts
|
||||
* @crit_irq: IRQ number for critical threshold interrupts
|
||||
* @combined_irq: IRQ number for combined threshold interrupts
|
||||
* @sensor: list of sensors attached to this device
|
||||
*/
|
||||
struct tsens_priv {
|
||||
|
|
@ -588,6 +594,10 @@ struct tsens_priv {
|
|||
struct dentry *debug_root;
|
||||
struct dentry *debug;
|
||||
|
||||
int uplow_irq;
|
||||
int crit_irq;
|
||||
int combined_irq;
|
||||
|
||||
struct tsens_sensor sensor[] __counted_by(num_sensors);
|
||||
};
|
||||
|
||||
|
|
@ -639,8 +649,17 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp);
|
|||
int get_temp_common(const struct tsens_sensor *s, int *temp);
|
||||
#ifdef CONFIG_SUSPEND
|
||||
int tsens_resume_common(struct tsens_priv *priv);
|
||||
int tsens_suspend_common(struct tsens_priv *priv);
|
||||
#else
|
||||
#define tsens_resume_common NULL
|
||||
static inline int tsens_resume_common(struct tsens_priv *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tsens_suspend_common(struct tsens_priv *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TSENS target */
|
||||
|
|
@ -659,4 +678,7 @@ extern const struct tsens_plat_data data_ipq5018;
|
|||
extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
|
||||
extern const struct tsens_plat_data data_ipq5332, data_ipq5424;
|
||||
|
||||
/* TSENS automotive targets */
|
||||
extern struct tsens_plat_data data_automotive_v2;
|
||||
|
||||
#endif /* __QCOM_TSENS_H__ */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright 2016 Freescale Semiconductor, Inc.
|
||||
// Copyright 2025 NXP
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
|
@ -24,10 +26,14 @@
|
|||
#define TMTMIR_DEFAULT 0x0000000f
|
||||
#define TIER_DISABLE 0x0
|
||||
#define TEUMR0_V2 0x51009c00
|
||||
#define TEUMR0_V21 0x55000c00
|
||||
#define TMSARA_V2 0xe
|
||||
#define TMU_VER1 0x1
|
||||
#define TMU_VER2 0x2
|
||||
|
||||
/* errata ID info define */
|
||||
#define TMU_ERR052243 BIT(0)
|
||||
|
||||
#define REGS_TMR 0x000 /* Mode Register */
|
||||
#define TMR_DISABLE 0x0
|
||||
#define TMR_ME 0x80000000
|
||||
|
|
@ -43,6 +49,15 @@
|
|||
#define REGS_TIER 0x020 /* Interrupt Enable Register */
|
||||
#define TIER_DISABLE 0x0
|
||||
|
||||
#define REGS_TIDR 0x24
|
||||
#define TEMP_RATE_IRQ_MASK GENMASK(25, 24)
|
||||
#define TMRTRCTR 0x70
|
||||
#define TMRTRCTR_EN BIT(31)
|
||||
#define TMRTRCTR_TEMP_MASK GENMASK(7, 0)
|
||||
#define TMFTRCTR 0x74
|
||||
#define TMFTRCTR_EN BIT(31)
|
||||
#define TMFTRCTR_TEMP_MASK GENMASK(7, 0)
|
||||
#define TEMP_RATE_THR_LVL 0x7
|
||||
|
||||
#define REGS_TTCFGR 0x080 /* Temperature Configuration Register */
|
||||
#define REGS_TSCFGR 0x084 /* Sensor Configuration Register */
|
||||
|
|
@ -73,14 +88,26 @@ struct qoriq_sensor {
|
|||
int id;
|
||||
};
|
||||
|
||||
struct tmu_drvdata {
|
||||
u32 teumr0;
|
||||
u32 tmu_errata;
|
||||
};
|
||||
|
||||
struct qoriq_tmu_data {
|
||||
int ver;
|
||||
u32 ttrcr[NUM_TTRCR_MAX];
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
struct qoriq_sensor sensor[SITES_MAX];
|
||||
const struct tmu_drvdata *drvdata;
|
||||
};
|
||||
|
||||
static inline bool qoriq_tmu_has_errata(const struct tmu_drvdata *drvdata,
|
||||
u32 flag)
|
||||
{
|
||||
return drvdata->tmu_errata & flag;
|
||||
}
|
||||
|
||||
static struct qoriq_tmu_data *qoriq_sensor_to_data(struct qoriq_sensor *s)
|
||||
{
|
||||
return container_of(s, struct qoriq_tmu_data, sensor[s->id]);
|
||||
|
|
@ -90,7 +117,7 @@ static int tmu_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
{
|
||||
struct qoriq_sensor *qsensor = thermal_zone_device_priv(tz);
|
||||
struct qoriq_tmu_data *qdata = qoriq_sensor_to_data(qsensor);
|
||||
u32 val;
|
||||
u32 val, tidr;
|
||||
/*
|
||||
* REGS_TRITSR(id) has the following layout:
|
||||
*
|
||||
|
|
@ -123,6 +150,15 @@ static int tmu_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
10 * USEC_PER_MSEC))
|
||||
return -ENODATA;
|
||||
|
||||
/*ERR052243: If a raising or falling edge happens, try later */
|
||||
if (qoriq_tmu_has_errata(qdata->drvdata, TMU_ERR052243)) {
|
||||
regmap_read(qdata->regmap, REGS_TIDR, &tidr);
|
||||
if (tidr & TEMP_RATE_IRQ_MASK) {
|
||||
regmap_write(qdata->regmap, REGS_TIDR, TEMP_RATE_IRQ_MASK);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (qdata->ver == TMU_VER1) {
|
||||
*temp = (val & GENMASK(7, 0)) * MILLIDEGREE_PER_DEGREE;
|
||||
} else {
|
||||
|
|
@ -234,9 +270,18 @@ static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
|
|||
regmap_write(data->regmap, REGS_TMTMIR, TMTMIR_DEFAULT);
|
||||
} else {
|
||||
regmap_write(data->regmap, REGS_V2_TMTMIR, TMTMIR_DEFAULT);
|
||||
regmap_write(data->regmap, REGS_V2_TEUMR(0), TEUMR0_V2);
|
||||
regmap_write(data->regmap, REGS_V2_TEUMR(0),
|
||||
data->drvdata->teumr0);
|
||||
}
|
||||
|
||||
/* ERR052243: Set the raising & falling edge monitor */
|
||||
if (qoriq_tmu_has_errata(data->drvdata, TMU_ERR052243)) {
|
||||
regmap_write(data->regmap, TMRTRCTR, TMRTRCTR_EN |
|
||||
FIELD_PREP(TMRTRCTR_TEMP_MASK, TEMP_RATE_THR_LVL));
|
||||
regmap_write(data->regmap, TMFTRCTR, TMFTRCTR_EN |
|
||||
FIELD_PREP(TMFTRCTR_TEMP_MASK, TEMP_RATE_THR_LVL));
|
||||
|
||||
}
|
||||
/* Disable monitoring */
|
||||
regmap_write(data->regmap, REGS_TMR, TMR_DISABLE);
|
||||
}
|
||||
|
|
@ -319,6 +364,10 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
|
|||
|
||||
data->ver = (ver >> 8) & 0xff;
|
||||
|
||||
data->drvdata = of_device_get_match_data(&pdev->dev);
|
||||
if (!data->drvdata)
|
||||
return dev_err_probe(dev, -EINVAL, "Failed to get match data\n");
|
||||
|
||||
qoriq_tmu_init_device(data); /* TMU initialization */
|
||||
|
||||
ret = qoriq_tmu_calibration(dev, data); /* TMU calibration */
|
||||
|
|
@ -376,9 +425,23 @@ static int qoriq_tmu_resume(struct device *dev)
|
|||
static DEFINE_SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
|
||||
qoriq_tmu_suspend, qoriq_tmu_resume);
|
||||
|
||||
static const struct tmu_drvdata qoriq_tmu_data = {
|
||||
.teumr0 = TEUMR0_V2,
|
||||
};
|
||||
|
||||
static const struct tmu_drvdata imx8mq_tmu_data = {
|
||||
.teumr0 = TEUMR0_V2,
|
||||
};
|
||||
|
||||
static const struct tmu_drvdata imx93_data = {
|
||||
.teumr0 = TEUMR0_V21,
|
||||
.tmu_errata = TMU_ERR052243,
|
||||
};
|
||||
|
||||
static const struct of_device_id qoriq_tmu_match[] = {
|
||||
{ .compatible = "fsl,qoriq-tmu", },
|
||||
{ .compatible = "fsl,imx8mq-tmu", },
|
||||
{ .compatible = "fsl,qoriq-tmu", .data = &qoriq_tmu_data },
|
||||
{ .compatible = "fsl,imx8mq-tmu", .data = &imx8mq_tmu_data },
|
||||
{ .compatible = "fsl,imx93-tmu", .data = &imx93_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ config EXYNOS_THERMAL
|
|||
tristate "Exynos thermal management unit driver"
|
||||
depends on THERMAL_OF
|
||||
depends on HAS_IOMEM
|
||||
default ARCH_EXYNOS
|
||||
help
|
||||
If you say yes here you get support for the TMU (Thermal Management
|
||||
Unit) driver for Samsung Exynos series of SoCs. This driver initialises
|
||||
|
|
|
|||
19
drivers/thermal/spacemit/Kconfig
Normal file
19
drivers/thermal/spacemit/Kconfig
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menu "SpacemiT thermal drivers"
|
||||
depends on ARCH_SPACEMIT || COMPILE_TEST
|
||||
|
||||
config SPACEMIT_K1_TSENSOR
|
||||
tristate "SpacemiT K1 thermal sensor driver"
|
||||
depends on THERMAL_OF
|
||||
help
|
||||
This driver provides support for the thermal sensor
|
||||
integrated in the SpacemiT K1 SoC.
|
||||
|
||||
The thermal sensor monitors temperatures for five thermal zones:
|
||||
soc, package, gpu, cluster0, and cluster1. It supports reporting
|
||||
temperature values and handling high/low threshold interrupts.
|
||||
|
||||
Say Y here if you want to enable thermal monitoring on SpacemiT K1.
|
||||
If compiled as a module, it will be called k1_tsensor.
|
||||
|
||||
endmenu
|
||||
3
drivers/thermal/spacemit/Makefile
Normal file
3
drivers/thermal/spacemit/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-$(CONFIG_SPACEMIT_K1_TSENSOR) += k1_tsensor.o
|
||||
280
drivers/thermal/spacemit/k1_tsensor.c
Normal file
280
drivers/thermal/spacemit/k1_tsensor.c
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Thermal sensor driver for SpacemiT K1 SoC
|
||||
*
|
||||
* Copyright (C) 2026 Shuwei Wu <shuwei.wu@mailbox.org>
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "../thermal_hwmon.h"
|
||||
|
||||
#define K1_TSENSOR_PCTRL_REG 0x00
|
||||
#define K1_TSENSOR_PCTRL_ENABLE BIT(0)
|
||||
#define K1_TSENSOR_PCTRL_TEMP_MODE BIT(3)
|
||||
#define K1_TSENSOR_PCTRL_RAW_SEL BIT(7)
|
||||
|
||||
#define K1_TSENSOR_PCTRL_CTUNE GENMASK(11, 8)
|
||||
#define K1_TSENSOR_PCTRL_SW_CTRL GENMASK(21, 18)
|
||||
#define K1_TSENSOR_PCTRL_HW_AUTO_MODE BIT(23)
|
||||
|
||||
#define K1_TSENSOR_EN_REG 0x08
|
||||
#define K1_TSENSOR_EN_ALL GENMASK(MAX_SENSOR_NUMBER - 1, 0)
|
||||
|
||||
#define K1_TSENSOR_TIME_REG 0x0C
|
||||
#define K1_TSENSOR_TIME_WAIT_REF_CNT GENMASK(3, 0)
|
||||
#define K1_TSENSOR_TIME_ADC_CNT_RST GENMASK(7, 4)
|
||||
#define K1_TSENSOR_TIME_FILTER_PERIOD GENMASK(21, 20)
|
||||
#define K1_TSENSOR_TIME_MASK GENMASK(23, 0)
|
||||
|
||||
#define K1_TSENSOR_INT_CLR_REG 0x10
|
||||
#define K1_TSENSOR_INT_EN_REG 0x14
|
||||
#define K1_TSENSOR_INT_STA_REG 0x18
|
||||
|
||||
#define K1_TSENSOR_INT_EN_MASK BIT(0)
|
||||
#define K1_TSENSOR_INT_MASK(x) (GENMASK(2, 1) << ((x) * 2))
|
||||
|
||||
#define K1_TSENSOR_DATA_BASE_REG 0x20
|
||||
#define K1_TSENSOR_DATA_REG(x) (K1_TSENSOR_DATA_BASE_REG + ((x) / 2) * 4)
|
||||
#define K1_TSENSOR_DATA_LOW_MASK GENMASK(15, 0)
|
||||
#define K1_TSENSOR_DATA_HIGH_MASK GENMASK(31, 16)
|
||||
|
||||
#define K1_TSENSOR_THRSH_BASE_REG 0x40
|
||||
#define K1_TSENSOR_THRSH_REG(x) (K1_TSENSOR_THRSH_BASE_REG + ((x) * 4))
|
||||
#define K1_TSENSOR_THRSH_LOW_MASK GENMASK(15, 0)
|
||||
#define K1_TSENSOR_THRSH_HIGH_MASK GENMASK(31, 16)
|
||||
|
||||
#define MAX_SENSOR_NUMBER 5
|
||||
|
||||
/* Hardware offset value required for temperature calculation */
|
||||
#define TEMPERATURE_OFFSET 278
|
||||
|
||||
struct k1_tsensor_channel {
|
||||
struct k1_tsensor *ts;
|
||||
struct thermal_zone_device *tzd;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct k1_tsensor {
|
||||
void __iomem *base;
|
||||
struct k1_tsensor_channel ch[MAX_SENSOR_NUMBER];
|
||||
};
|
||||
|
||||
static void k1_tsensor_init(struct k1_tsensor *ts)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Disable all the interrupts */
|
||||
writel(0xffffffff, ts->base + K1_TSENSOR_INT_EN_REG);
|
||||
|
||||
/* Configure ADC sampling time and filter period */
|
||||
val = readl(ts->base + K1_TSENSOR_TIME_REG);
|
||||
val &= ~K1_TSENSOR_TIME_MASK;
|
||||
val |= K1_TSENSOR_TIME_FILTER_PERIOD |
|
||||
K1_TSENSOR_TIME_ADC_CNT_RST |
|
||||
K1_TSENSOR_TIME_WAIT_REF_CNT;
|
||||
writel(val, ts->base + K1_TSENSOR_TIME_REG);
|
||||
|
||||
/*
|
||||
* Enable all sensors' auto mode, enable dither control,
|
||||
* consecutive mode, and power up sensor.
|
||||
*/
|
||||
val = readl(ts->base + K1_TSENSOR_PCTRL_REG);
|
||||
val &= ~K1_TSENSOR_PCTRL_SW_CTRL;
|
||||
val &= ~K1_TSENSOR_PCTRL_CTUNE;
|
||||
val |= K1_TSENSOR_PCTRL_RAW_SEL |
|
||||
K1_TSENSOR_PCTRL_TEMP_MODE |
|
||||
K1_TSENSOR_PCTRL_HW_AUTO_MODE |
|
||||
K1_TSENSOR_PCTRL_ENABLE;
|
||||
writel(val, ts->base + K1_TSENSOR_PCTRL_REG);
|
||||
|
||||
/* Enable each sensor */
|
||||
val = readl(ts->base + K1_TSENSOR_EN_REG);
|
||||
val |= K1_TSENSOR_EN_ALL;
|
||||
writel(val, ts->base + K1_TSENSOR_EN_REG);
|
||||
}
|
||||
|
||||
static void k1_tsensor_enable_irq(struct k1_tsensor_channel *ch)
|
||||
{
|
||||
struct k1_tsensor *ts = ch->ts;
|
||||
u32 val;
|
||||
|
||||
val = readl(ts->base + K1_TSENSOR_INT_CLR_REG);
|
||||
val |= K1_TSENSOR_INT_MASK(ch->id);
|
||||
writel(val, ts->base + K1_TSENSOR_INT_CLR_REG);
|
||||
|
||||
val = readl(ts->base + K1_TSENSOR_INT_EN_REG);
|
||||
val &= ~K1_TSENSOR_INT_MASK(ch->id);
|
||||
writel(val, ts->base + K1_TSENSOR_INT_EN_REG);
|
||||
|
||||
/* Enable thermal interrupt */
|
||||
val = readl(ts->base + K1_TSENSOR_INT_EN_REG);
|
||||
val |= K1_TSENSOR_INT_EN_MASK;
|
||||
writel(val, ts->base + K1_TSENSOR_INT_EN_REG);
|
||||
}
|
||||
|
||||
/*
|
||||
* The conversion formula used is:
|
||||
* T(m°C) = (((raw_value & mask) >> shift) - TEMPERATURE_OFFSET) * 1000
|
||||
*/
|
||||
static int k1_tsensor_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct k1_tsensor_channel *ch = thermal_zone_device_priv(tz);
|
||||
struct k1_tsensor *ts = ch->ts;
|
||||
u32 val;
|
||||
|
||||
val = readl(ts->base + K1_TSENSOR_DATA_REG(ch->id));
|
||||
if (ch->id % 2)
|
||||
*temp = FIELD_GET(K1_TSENSOR_DATA_HIGH_MASK, val);
|
||||
else
|
||||
*temp = FIELD_GET(K1_TSENSOR_DATA_LOW_MASK, val);
|
||||
|
||||
*temp -= TEMPERATURE_OFFSET;
|
||||
*temp *= 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each sensor, the hardware threshold register is 32 bits:
|
||||
* - Lower 16 bits [15:0] configure the low threshold temperature.
|
||||
* - Upper 16 bits [31:16] configure the high threshold temperature.
|
||||
*/
|
||||
static int k1_tsensor_set_trips(struct thermal_zone_device *tz, int low, int high)
|
||||
{
|
||||
struct k1_tsensor_channel *ch = thermal_zone_device_priv(tz);
|
||||
struct k1_tsensor *ts = ch->ts;
|
||||
u32 val;
|
||||
|
||||
if (low >= high)
|
||||
return -EINVAL;
|
||||
|
||||
low = clamp_val(low / 1000 + TEMPERATURE_OFFSET, TEMPERATURE_OFFSET,
|
||||
FIELD_MAX(K1_TSENSOR_THRSH_LOW_MASK));
|
||||
high = clamp_val(high / 1000 + TEMPERATURE_OFFSET, TEMPERATURE_OFFSET,
|
||||
FIELD_MAX(K1_TSENSOR_THRSH_HIGH_MASK));
|
||||
|
||||
val = readl(ts->base + K1_TSENSOR_THRSH_REG(ch->id));
|
||||
|
||||
val &= ~(K1_TSENSOR_THRSH_LOW_MASK | K1_TSENSOR_THRSH_HIGH_MASK);
|
||||
val |= FIELD_PREP(K1_TSENSOR_THRSH_LOW_MASK, low);
|
||||
val |= FIELD_PREP(K1_TSENSOR_THRSH_HIGH_MASK, high);
|
||||
|
||||
writel(val, ts->base + K1_TSENSOR_THRSH_REG(ch->id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops k1_tsensor_ops = {
|
||||
.get_temp = k1_tsensor_get_temp,
|
||||
.set_trips = k1_tsensor_set_trips,
|
||||
};
|
||||
|
||||
static irqreturn_t k1_tsensor_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct k1_tsensor *ts = (struct k1_tsensor *)data;
|
||||
int mask, status, i;
|
||||
|
||||
status = readl(ts->base + K1_TSENSOR_INT_STA_REG);
|
||||
|
||||
for (i = 0; i < MAX_SENSOR_NUMBER; i++) {
|
||||
if (status & K1_TSENSOR_INT_MASK(i)) {
|
||||
mask = readl(ts->base + K1_TSENSOR_INT_CLR_REG);
|
||||
mask |= K1_TSENSOR_INT_MASK(i);
|
||||
writel(mask, ts->base + K1_TSENSOR_INT_CLR_REG);
|
||||
thermal_zone_device_update(ts->ch[i].tzd, THERMAL_EVENT_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int k1_tsensor_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct k1_tsensor *ts;
|
||||
struct reset_control *reset;
|
||||
struct clk *clk;
|
||||
int i, irq, ret;
|
||||
|
||||
ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
|
||||
if (!ts)
|
||||
return -ENOMEM;
|
||||
|
||||
ts->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ts->base))
|
||||
return dev_err_probe(dev, PTR_ERR(ts->base), "Failed to get reg\n");
|
||||
|
||||
reset = devm_reset_control_get_exclusive_deasserted(dev, NULL);
|
||||
if (IS_ERR(reset))
|
||||
return dev_err_probe(dev, PTR_ERR(reset), "Failed to get/deassert reset control\n");
|
||||
|
||||
clk = devm_clk_get_enabled(dev, "core");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "Failed to get core clock\n");
|
||||
|
||||
clk = devm_clk_get_enabled(dev, "bus");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "Failed to get bus clock\n");
|
||||
|
||||
k1_tsensor_init(ts);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
k1_tsensor_irq_thread,
|
||||
IRQF_ONESHOT, "k1_tsensor", ts);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < MAX_SENSOR_NUMBER; ++i) {
|
||||
ts->ch[i].id = i;
|
||||
ts->ch[i].ts = ts;
|
||||
ts->ch[i].tzd = devm_thermal_of_zone_register(dev, i, ts->ch + i, &k1_tsensor_ops);
|
||||
if (IS_ERR(ts->ch[i].tzd))
|
||||
return PTR_ERR(ts->ch[i].tzd);
|
||||
|
||||
/* Attach sysfs hwmon attributes for userspace monitoring */
|
||||
ret = devm_thermal_add_hwmon_sysfs(dev, ts->ch[i].tzd);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to add hwmon sysfs attributes\n");
|
||||
|
||||
k1_tsensor_enable_irq(ts->ch + i);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id k1_tsensor_dt_ids[] = {
|
||||
{ .compatible = "spacemit,k1-tsensor" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, k1_tsensor_dt_ids);
|
||||
|
||||
static struct platform_driver k1_tsensor_driver = {
|
||||
.driver = {
|
||||
.name = "k1_tsensor",
|
||||
.of_match_table = k1_tsensor_dt_ids,
|
||||
},
|
||||
.probe = k1_tsensor_probe,
|
||||
};
|
||||
module_platform_driver(k1_tsensor_driver);
|
||||
|
||||
MODULE_DESCRIPTION("SpacemiT K1 Thermal Sensor Driver");
|
||||
MODULE_AUTHOR("Shuwei Wu <shuwei.wu@mailbox.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -1499,6 +1499,13 @@ static int soctherm_clk_enable(struct platform_device *pdev, bool enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void soctherm_clk_disable(void *data)
|
||||
{
|
||||
struct platform_device *pdev = data;
|
||||
|
||||
soctherm_clk_enable(pdev, false);
|
||||
}
|
||||
|
||||
static int throt_get_cdev_max_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *max_state)
|
||||
{
|
||||
|
|
@ -1700,9 +1707,9 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
|
|||
stc->init = true;
|
||||
} else {
|
||||
|
||||
tcd = thermal_of_cooling_device_register(np_stcc,
|
||||
(char *)name, ts,
|
||||
&throt_cooling_ops);
|
||||
tcd = devm_thermal_of_child_cooling_device_register(dev, np_stcc,
|
||||
(char *)name, ts,
|
||||
&throt_cooling_ops);
|
||||
if (IS_ERR_OR_NULL(tcd)) {
|
||||
dev_err(dev,
|
||||
"throttle-cfg: %s: failed to register cooling device\n",
|
||||
|
|
@ -2175,6 +2182,10 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_add_action_or_reset(&pdev->dev, soctherm_clk_disable, pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
soctherm_thermtrips_parse(pdev);
|
||||
|
||||
soctherm_init_hw_throt_cdev(pdev);
|
||||
|
|
@ -2184,10 +2195,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
|||
for (i = 0; i < soc->num_ttgs; ++i) {
|
||||
struct tegra_thermctl_zone *zone =
|
||||
devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
|
||||
if (!zone) {
|
||||
err = -ENOMEM;
|
||||
goto disable_clocks;
|
||||
}
|
||||
if (!zone)
|
||||
return -ENOMEM;
|
||||
|
||||
zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset;
|
||||
zone->dev = &pdev->dev;
|
||||
|
|
@ -2201,7 +2210,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
|||
err = PTR_ERR(z);
|
||||
dev_err(&pdev->dev, "failed to register sensor: %d\n",
|
||||
err);
|
||||
goto disable_clocks;
|
||||
return err;
|
||||
}
|
||||
|
||||
zone->tz = z;
|
||||
|
|
@ -2210,7 +2219,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
|||
/* Configure hw trip points */
|
||||
err = tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z);
|
||||
if (err)
|
||||
goto disable_clocks;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = soctherm_interrupts_init(pdev, tegra);
|
||||
|
|
@ -2218,11 +2227,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
|
|||
soctherm_debug_init(pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clocks:
|
||||
soctherm_clk_enable(pdev, false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tegra_soctherm_remove(struct platform_device *pdev)
|
||||
|
|
@ -2230,8 +2234,6 @@ static void tegra_soctherm_remove(struct platform_device *pdev)
|
|||
struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
|
||||
|
||||
debugfs_remove_recursive(tegra->debugfs_dir);
|
||||
|
||||
soctherm_clk_enable(pdev, false);
|
||||
}
|
||||
|
||||
static int __maybe_unused soctherm_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -963,7 +963,7 @@ static void thermal_cdev_release(struct device *dev)
|
|||
kfree(cdev);
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device *
|
||||
struct thermal_cooling_device *
|
||||
thermal_cooling_device_alloc(const char *type, const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
|
|
@ -1002,7 +1002,7 @@ thermal_cooling_device_alloc(const char *type, const struct thermal_cooling_devi
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata)
|
||||
int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata)
|
||||
{
|
||||
unsigned long current_state;
|
||||
int ret;
|
||||
|
|
@ -1058,48 +1058,11 @@ static int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* __thermal_cooling_device_register() - register a new thermal cooling device
|
||||
* @np: a pointer to a device tree node.
|
||||
* @type: the thermal cooling device type.
|
||||
* @devdata: device private data.
|
||||
* @ops: standard thermal cooling devices callbacks.
|
||||
*
|
||||
* 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.
|
||||
* It also gives the opportunity to link the cooling device to a device tree
|
||||
* node, so that it can be bound to a thermal zone created out of device tree.
|
||||
*
|
||||
* Return: a pointer to the created struct thermal_cooling_device or an
|
||||
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
|
||||
*/
|
||||
static struct thermal_cooling_device *
|
||||
__thermal_cooling_device_register(struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
int ret;
|
||||
|
||||
cdev = thermal_cooling_device_alloc(type, ops);
|
||||
if (IS_ERR(cdev))
|
||||
return cdev;
|
||||
|
||||
cdev->np = np;
|
||||
|
||||
ret = thermal_cooling_device_add(cdev, devdata);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return cdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* thermal_cooling_device_register() - register a new thermal cooling device
|
||||
* @type: the thermal cooling device type.
|
||||
* @devdata: device private data.
|
||||
* @ops: standard thermal cooling devices callbacks.
|
||||
* @ops: standard thermal cooling devices callbacks.
|
||||
*
|
||||
* 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
|
||||
|
|
@ -1112,82 +1075,62 @@ struct thermal_cooling_device *
|
|||
thermal_cooling_device_register(const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return __thermal_cooling_device_register(NULL, type, devdata, ops);
|
||||
struct thermal_cooling_device *cdev;
|
||||
int ret;
|
||||
|
||||
cdev = thermal_cooling_device_alloc(type, ops);
|
||||
if (IS_ERR(cdev))
|
||||
return cdev;
|
||||
|
||||
ret = thermal_cooling_device_add(cdev, devdata);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return cdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
|
||||
|
||||
/**
|
||||
* thermal_of_cooling_device_register() - register an OF thermal cooling device
|
||||
* @np: a pointer to a device tree node.
|
||||
* @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 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.
|
||||
*
|
||||
* Return: a pointer to the created struct thermal_cooling_device or an
|
||||
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
thermal_of_cooling_device_register(struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
static void thermal_cooling_device_release(void *data)
|
||||
{
|
||||
return __thermal_cooling_device_register(np, type, devdata, ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
|
||||
struct thermal_cooling_device *cdev = data;
|
||||
|
||||
static void thermal_cooling_device_release(struct device *dev, void *res)
|
||||
{
|
||||
thermal_cooling_device_unregister(
|
||||
*(struct thermal_cooling_device **)res);
|
||||
thermal_cooling_device_unregister(cdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_thermal_of_cooling_device_register() - register an OF thermal cooling
|
||||
* device
|
||||
* devm_thermal_cooling_device_register() - register a thermal cooling device
|
||||
*
|
||||
* @dev: a valid struct device pointer of a sensor device.
|
||||
* @np: a pointer to a device tree node.
|
||||
* @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 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.
|
||||
* This function will register a cooling device. 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.
|
||||
*
|
||||
* Return: a pointer to the created struct thermal_cooling_device or an
|
||||
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
devm_thermal_cooling_device_register(struct device *dev, const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
struct thermal_cooling_device **ptr, *tcd;
|
||||
struct thermal_cooling_device *cdev;
|
||||
int ret;
|
||||
|
||||
ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
cdev = thermal_cooling_device_register(type, devdata, ops);
|
||||
if (IS_ERR(cdev))
|
||||
return cdev;
|
||||
|
||||
tcd = __thermal_cooling_device_register(np, type, devdata, ops);
|
||||
if (IS_ERR(tcd)) {
|
||||
devres_free(ptr);
|
||||
return tcd;
|
||||
}
|
||||
ret = devm_add_action_or_reset(dev, thermal_cooling_device_release, cdev);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
*ptr = tcd;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return tcd;
|
||||
return cdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
|
||||
EXPORT_SYMBOL_GPL(devm_thermal_cooling_device_register);
|
||||
|
||||
static bool thermal_cooling_device_present(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -267,6 +267,11 @@ void thermal_zone_device_critical_shutdown(struct thermal_zone_device *tz);
|
|||
void thermal_governor_update_tz(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event reason);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
thermal_cooling_device_alloc(const char *type, const struct thermal_cooling_device_ops *ops);
|
||||
|
||||
int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata);
|
||||
|
||||
/* Helpers */
|
||||
#define for_each_trip_desc(__tz, __td) \
|
||||
for (__td = __tz->trips; __td - __tz->trips < __tz->num_trips; __td++)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *n
|
|||
int ret, count;
|
||||
|
||||
*ntrips = 0;
|
||||
|
||||
|
||||
struct device_node *trips __free(device_node) = of_get_child_by_name(np, "trips");
|
||||
if (!trips)
|
||||
return NULL;
|
||||
|
|
@ -259,16 +259,34 @@ static bool thermal_of_get_cooling_spec(struct device_node *map_np, int index,
|
|||
|
||||
of_node_put(cooling_spec.np);
|
||||
|
||||
if (cooling_spec.args_count < 2) {
|
||||
pr_err("wrong reference to cooling device, missing limits\n");
|
||||
/*
|
||||
* There are two formats:
|
||||
* - Legacy format : <&cdev lower upper>
|
||||
* - New format : <&cdev cdev_id lower upper>
|
||||
*
|
||||
* With the new format, along with the device node pointer,
|
||||
* the cdev_id must match with the cooling device cdev_id in
|
||||
* order to bind
|
||||
*/
|
||||
if (cooling_spec.args_count < 2 || cooling_spec.args_count > 3) {
|
||||
pr_err("Invalid number of cooling device parameters\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cooling_spec.np != cdev->np)
|
||||
return false;
|
||||
|
||||
c->lower = cooling_spec.args[0];
|
||||
c->upper = cooling_spec.args[1];
|
||||
if (cooling_spec.args_count == 3 &&
|
||||
cooling_spec.args[0] != cdev->cdev_id)
|
||||
return false;
|
||||
|
||||
if (cooling_spec.args_count != 3) {
|
||||
c->lower = cooling_spec.args[0];
|
||||
c->upper = cooling_spec.args[1];
|
||||
} else {
|
||||
c->lower = cooling_spec.args[1];
|
||||
c->upper = cooling_spec.args[2];
|
||||
}
|
||||
c->weight = weight;
|
||||
|
||||
return true;
|
||||
|
|
@ -494,7 +512,7 @@ EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register);
|
|||
/**
|
||||
* devm_thermal_of_zone_unregister - Resource managed version of
|
||||
* thermal_of_zone_unregister().
|
||||
* @dev: Device for which which resource was allocated.
|
||||
* @dev: Device for which resource was allocated.
|
||||
* @tz: a pointer to struct thermal_zone where the sensor is registered.
|
||||
*
|
||||
* This function removes the sensor callbacks and private data from the
|
||||
|
|
@ -510,3 +528,125 @@ void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_dev
|
|||
devm_thermal_of_zone_match, tz));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
|
||||
|
||||
/**
|
||||
* thermal_of_cooling_device_register() - register an OF thermal cooling device
|
||||
* @np: a pointer to a device tree node.
|
||||
* @cdev_id: a cooling device id in the cooling controller
|
||||
* @type: the thermal cooling device type.
|
||||
* @devdata: device private data.
|
||||
* @ops: standard thermal cooling devices callbacks.
|
||||
*
|
||||
* 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.
|
||||
* It also gives the opportunity to link the cooling device to a device tree
|
||||
* node, so that it can be bound to a thermal zone created out of device tree.
|
||||
*
|
||||
* Return: a pointer to the created struct thermal_cooling_device or an
|
||||
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
thermal_of_cooling_device_register(struct device_node *np, u32 cdev_id,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
int ret;
|
||||
|
||||
cdev = thermal_cooling_device_alloc(type, ops);
|
||||
if (IS_ERR(cdev))
|
||||
return cdev;
|
||||
|
||||
cdev->np = np;
|
||||
cdev->cdev_id = cdev_id;
|
||||
|
||||
ret = thermal_cooling_device_add(cdev, devdata);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return cdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
|
||||
|
||||
static void thermal_of_cooling_device_release(void *data)
|
||||
{
|
||||
struct thermal_cooling_device *cdev = data;
|
||||
|
||||
thermal_cooling_device_unregister(cdev);
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device *
|
||||
__devm_thermal_of_cooling_device_register(struct device *dev, struct device_node *np,
|
||||
u32 cdev_id, const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
int ret;
|
||||
|
||||
cdev = thermal_of_cooling_device_register(np, cdev_id, type, devdata, ops);
|
||||
if (IS_ERR(cdev))
|
||||
return cdev;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, thermal_of_cooling_device_release, cdev);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return cdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_thermal_of_cooling_device_register() - register an OF thermal cooling device
|
||||
* @dev: a valid struct device pointer of a sensor device.
|
||||
* @cdev_id: 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 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.
|
||||
*
|
||||
* Return: a pointer to the created struct thermal_cooling_device or an
|
||||
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev, u32 cdev_id,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return __devm_thermal_of_cooling_device_register(dev, dev->of_node, cdev_id,
|
||||
type, devdata, ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
|
||||
|
||||
/**
|
||||
* devm_thermal_of_child_cooling_device_register() - register an OF thermal cooling
|
||||
* device
|
||||
* @dev: a valid struct device pointer of a sensor device.
|
||||
* @np: a pointer to a device tree node.
|
||||
* @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 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.
|
||||
*
|
||||
* This function should be used when a cooling controller has child
|
||||
* nodes which are referenced in the thermal zone cooling map.
|
||||
*
|
||||
* Return: a pointer to the created struct thermal_cooling_device or an
|
||||
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_child_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return __devm_thermal_of_cooling_device_register(dev, np, 0, type, devdata, ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_thermal_of_child_cooling_device_register);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ enum {
|
|||
SM_EFUSE_WRITE,
|
||||
SM_EFUSE_USER_MAX,
|
||||
SM_GET_CHIP_ID,
|
||||
SM_THERMAL_CALIB_READ,
|
||||
SM_A1_PWRC_SET,
|
||||
SM_A1_PWRC_GET,
|
||||
};
|
||||
|
|
@ -27,5 +28,7 @@ int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
|
|||
unsigned int bsize, unsigned int cmd_index, u32 arg0,
|
||||
u32 arg1, u32 arg2, u32 arg3, u32 arg4);
|
||||
struct meson_sm_firmware *meson_sm_get(struct device_node *firmware_node);
|
||||
int meson_sm_get_thermal_calib(struct meson_sm_firmware *fw, u32 *trim_info,
|
||||
u32 tsensor_id);
|
||||
|
||||
#endif /* _MESON_SM_FW_H_ */
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ struct thermal_cooling_device {
|
|||
const char *type;
|
||||
unsigned long max_state;
|
||||
struct device device;
|
||||
struct device_node *np;
|
||||
void *devdata;
|
||||
void *stats;
|
||||
const struct thermal_cooling_device_ops *ops;
|
||||
|
|
@ -133,6 +132,10 @@ struct thermal_cooling_device {
|
|||
struct mutex lock; /* protect thermal_instances list */
|
||||
struct list_head thermal_instances;
|
||||
struct list_head node;
|
||||
#ifdef CONFIG_THERMAL_OF
|
||||
struct device_node *np;
|
||||
u32 cdev_id;
|
||||
#endif
|
||||
#ifdef CONFIG_THERMAL_DEBUGFS
|
||||
struct thermal_debugfs *debugfs;
|
||||
#endif
|
||||
|
|
@ -198,6 +201,21 @@ struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, in
|
|||
|
||||
void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
thermal_of_cooling_device_register(struct device_node *np, u32 cdev_id,
|
||||
const char *type, void *data,
|
||||
const struct thermal_cooling_device_ops *ops);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev, u32 cdev_id,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_child_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops);
|
||||
#else
|
||||
|
||||
static inline
|
||||
|
|
@ -211,6 +229,31 @@ static inline void devm_thermal_of_zone_unregister(struct device *dev,
|
|||
struct thermal_zone_device *tz)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
thermal_of_cooling_device_register(struct device_node *np, u32 cdev_id,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev, u32 cdev_id,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
devm_thermal_of_child_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
int for_each_thermal_trip(struct thermal_zone_device *tz,
|
||||
|
|
@ -252,14 +295,11 @@ void thermal_zone_device_update(struct thermal_zone_device *,
|
|||
|
||||
struct thermal_cooling_device *thermal_cooling_device_register(const char *,
|
||||
void *, const struct thermal_cooling_device_ops *);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
thermal_of_cooling_device_register(struct device_node *np, const char *, void *,
|
||||
const struct thermal_cooling_device_ops *);
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops);
|
||||
devm_thermal_cooling_device_register(struct device *dev, const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops);
|
||||
|
||||
void thermal_cooling_device_update(struct thermal_cooling_device *);
|
||||
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
|
||||
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
|
||||
|
|
@ -304,19 +344,12 @@ static inline struct thermal_cooling_device *
|
|||
thermal_cooling_device_register(const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{ return ERR_PTR(-ENODEV); }
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
thermal_of_cooling_device_register(struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
devm_thermal_cooling_device_register(struct device *dev, const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{ return ERR_PTR(-ENODEV); }
|
||||
static inline struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void thermal_cooling_device_unregister(
|
||||
struct thermal_cooling_device *cdev)
|
||||
{ }
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user