Commit 34183ddd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'thermal-v5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux

Pull thermal updates from Daniel Lezcano:

 - Convert tsens configuration DT binding to yaml (Rajeshwari)

 - Add interrupt support on the rcar sensor (Niklas Söderlund)

 - Add a new Spreadtrum thermal driver (Baolin Wang)

 - Add thermal binding for the fsl scu board, a new API to retrieve the
   sensor id bound to the thermal zone and i.MX system controller sensor
   (Anson Huang))

 - Remove warning log when a deferred probe is requested on Exynos
   (Marek Szyprowski)

 - Add the thermal monitoring unit support for imx8mm with its DT
   bindings (Anson Huang)

 - Rephrase the Kconfig text for clarity (Linus Walleij)

 - Use the gpio descriptor for the ti-soc-thermal (Linus Walleij)

 - Align msg structure to 4 bytes for i.MX SC, fix the Kconfig
   dependency, add the __may_be unused annotation for PM functions and
   the COMPILE_TEST option for imx8mm (Anson Huang)

 - Fix a dependency on regmap in Kconfig for qoriq (Yuantian Tang)

 - Add DT binding and support for the rcar gen3 r8a77961 and improve the
   error path on the rcar init function (Niklas Söderlund)

 - Cleanup and improvements for the tsens Qcom sensor (Amit Kucheria)

 - Improve code by removing lock and caching values in the rcar thermal
   sensor (Niklas Söderlund)

 - Cleanup in the qoriq drivers and add a call to
   imx_thermal_unregister_legacy_cooling in the removal function (Anson
   Huang)

 - Remove redundant 'maxItems' in tsens and sprd DT bindings (Rob
   Herring)

 - Change the thermal DT bindings by making the cooling-maps optional
   (Yuantian Tang)

 - Add Tiger Lake support (Sumeet Pawnikar)

 - Use scnprintf() for avoiding potential buffer overflow (Takashi Iwai)

 - Make pkg_temp_lock a raw_spinlock_t(Clark Williams)

 - Fix incorrect data types by changing them to signed on i.MX SC (Anson
   Huang)

 - Replace zero-length array with flexible-array member (Gustavo A. R.
   Silva)

 - Add support for i.MX8MP in the driver and in the DT bindings (Anson
   Huang)

 - Fix return value of the cpufreq_set_cur_state() function (Willy
   Wolff)

 - Remove abusing and scary WARN_ON in the cpufreq cooling device
   (Daniel Lezcano)

 - Fix build warning of incorrect argument type reported by sparse on
   imx8mm (Anson Huang)

 - Fix stub for the devfreq cooling device (Martin Blumenstingl)

 - Fix cpu idle cooling documentation (Sergey Vidishev)

* tag 'thermal-v5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (52 commits)
  Documentation: cpu-idle-cooling: Fix diagram for 33% duty cycle
  thermal: devfreq_cooling: inline all stubs for CONFIG_DEVFREQ_THERMAL=n
  thermal: imx8mm: Fix build warning of incorrect argument type
  thermal/drivers/cpufreq_cooling: Remove abusing WARN_ON
  thermal/drivers/cpufreq_cooling: Fix return of cpufreq_set_cur_state
  thermal: imx8mm: Add i.MX8MP support
  dt-bindings: thermal: imx8mm-thermal: Add support for i.MX8MP
  thermal: qcom: tsens.h: Replace zero-length array with flexible-array member
  thermal: imx_sc_thermal: Fix incorrect data type
  thermal: int340x_thermal: Use scnprintf() for avoiding potential buffer overflow
  thermal: int340x: processor_thermal: Add Tiger Lake support
  thermal/x86_pkg_temp: Make pkg_temp_lock a raw_spinlock_t
  dt-bindings: thermal: make cooling-maps property optional
  dt-bindings: thermal: qcom-tsens: Remove redundant 'maxItems'
  dt-bindings: thermal: sprd: Remove redundant 'maxItems'
  thermal: imx: Calling imx_thermal_unregister_legacy_cooling() in .remove
  thermal: qoriq: Sort includes alphabetically
  thermal: qoriq: Use devm_add_action_or_reset() to handle all cleanups
  thermal: rcar_thermal: Remove lock in rcar_thermal_get_current_temp()
  thermal: rcar_thermal: Do not store ctemp in rcar_thermal_priv
  ...
parents 8645f09b 11700fcb
......@@ -166,6 +166,17 @@ Required properties:
followed by "fsl,imx-sc-key";
- linux,keycodes: See Documentation/devicetree/bindings/input/input.yaml
Thermal bindings based on SCU Message Protocol
------------------------------------------------------------
Required properties:
- compatible: Should be :
"fsl,imx8qxp-sc-thermal"
followed by "fsl,imx-sc-thermal";
- #thermal-sensor-cells: See Documentation/devicetree/bindings/thermal/thermal.txt
for a description.
Example (imx8qxp):
-------------
aliases {
......@@ -238,6 +249,11 @@ firmware {
compatible = "fsl,imx8qxp-sc-wdt", "fsl,imx-sc-wdt";
timeout-sec = <60>;
};
tsens: thermal-sensor {
compatible = "fsl,imx8qxp-sc-thermal", "fsl,imx-sc-thermal";
#thermal-sensor-cells = <1>;
};
};
};
......
* Thermal Monitoring Unit (TMU) on Freescale i.MX8MM SoC
Required properties:
- compatible : Must be "fsl,imx8mm-tmu" or "fsl,imx8mp-tmu".
- reg : Address range of TMU registers.
- clocks : TMU's clock source.
- #thermal-sensor-cells : Should be 0 or 1. See ./thermal.txt for a description.
Example:
tmu: tmu@30260000 {
compatible = "fsl,imx8mm-tmu";
reg = <0x30260000 0x10000>;
clocks = <&clk IMX8MM_CLK_TMU_ROOT>;
#thermal-sensor-cells = <0>;
};
......@@ -38,11 +38,11 @@ properties:
- enum:
- qcom,msm8996-tsens
- qcom,msm8998-tsens
- qcom,sc7180-tsens
- qcom,sdm845-tsens
- const: qcom,tsens-v2
reg:
maxItems: 2
items:
- description: TM registers
- description: SROT registers
......
......@@ -11,6 +11,7 @@ Required properties:
- "renesas,r8a774b1-thermal" (RZ/G2N)
- "renesas,r8a7795-thermal" (R-Car H3)
- "renesas,r8a7796-thermal" (R-Car M3-W)
- "renesas,r8a77961-thermal" (R-Car M3-W+)
- "renesas,r8a77965-thermal" (R-Car M3-N)
- "renesas,r8a77980-thermal" (R-Car V3H)
- reg : Address ranges of the thermal registers. Each sensor
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/sprd-thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Spreadtrum thermal sensor controller bindings
maintainers:
- Orson Zhai <orsonzhai@gmail.com>
- Baolin Wang <baolin.wang7@gmail.com>
- Chunyan Zhang <zhang.lyra@gmail.com>
properties:
compatible:
const: sprd,ums512-thermal
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: enable
nvmem-cells:
maxItems: 2
description:
Reference to nvmem nodes for the calibration data.
nvmem-cell-names:
items:
- const: thm_sign_cal
- const: thm_ratio_cal
"#thermal-sensor-cells":
const: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^([a-z]*-)?sensor(-section)?@[0-9]+$":
type: object
description:
Represent one thermal sensor.
properties:
reg:
description: Specify the sensor id.
maxItems: 1
nvmem-cells:
maxItems: 1
description:
Reference to an nvmem node for the calibration data.
nvmem-cell-names:
const: sen_delta_cal
required:
- reg
- nvmem-cells
- nvmem-cell-names
required:
- compatible
- reg
- clocks
- clock-names
- nvmem-cells
- nvmem-cell-names
- "#thermal-sensor-cells"
- "#address-cells"
- "#size-cells"
examples:
- |
ap_thm0: thermal@32200000 {
compatible = "sprd,ums512-thermal";
reg = <0 0x32200000 0 0x10000>;
clock-names = "enable";
clocks = <&aonapb_gate 32>;
#thermal-sensor-cells = <1>;
nvmem-cells = <&thm0_sign>, <&thm0_ratio>;
nvmem-cell-names = "thm_sign_cal", "thm_ratio_cal";
#address-cells = <1>;
#size-cells = <0>;
prometheus-sensor@0 {
reg = <0>;
nvmem-cells = <&thm0_sen0>;
nvmem-cell-names = "sen_delta_cal";
};
ank-sensor@1 {
reg = <1>;
nvmem-cells = <&thm0_sen1>;
nvmem-cell-names = "sen_delta_cal";
};
};
...
......@@ -142,11 +142,11 @@ Required properties:
- trips: A sub-node which is a container of only trip point nodes
Type: sub-node required to describe the thermal zone.
Optional property:
- cooling-maps: A sub-node which is a container of only cooling device
Type: sub-node map nodes, used to describe the relation between trips
and cooling devices.
Optional property:
- coefficients: An array of integers (one signed cell) containing
Type: array coefficients to compose a linear relation between
Elem size: one cell the sensors listed in the thermal-sensors property.
......
......@@ -105,8 +105,8 @@ and this variation will modulate the cooling effect.
idle <-------------->
running
<----------------------------->
duty cycle 33%
<--------------------->
duty cycle 33%
^
......
# SPDX-License-Identifier: GPL-2.0-only
#
# Generic thermal sysfs drivers configuration
# Generic thermal drivers configuration
#
menuconfig THERMAL
bool "Generic Thermal sysfs driver"
bool "Thermal drivers"
help
Generic Thermal Sysfs driver offers a generic mechanism for
Thermal drivers offer a generic mechanism for
thermal management. Usually it's made up of one or more thermal
zone and cooling device.
zones and cooling devices.
Each thermal zone contains its own temperature, trip points,
cooling devices.
All platforms with ACPI thermal support can use this driver.
and cooling devices.
All platforms with ACPI or Open Firmware thermal support can use
this driver.
If you want this support, you should say Y here.
if THERMAL
......@@ -251,6 +252,27 @@ config IMX_THERMAL
cpufreq is used as the cooling device to throttle CPUs when the
passive trip is crossed.
config IMX_SC_THERMAL
tristate "Temperature sensor driver for NXP i.MX SoCs with System Controller"
depends on IMX_SCU
depends on OF
help
Support for Temperature Monitor (TEMPMON) found on NXP i.MX SoCs with
system controller inside, Linux kernel has to communicate with system
controller via MU (message unit) IPC to get temperature from thermal
sensor. It supports one critical trip point and one
passive trip point for each thermal sensor.
config IMX8MM_THERMAL
tristate "Temperature sensor driver for Freescale i.MX8MM SoC"
depends on ARCH_MXC || COMPILE_TEST
depends on OF
help
Support for Thermal Monitoring Unit (TMU) found on Freescale i.MX8MM SoC.
It supports one critical trip point and one passive trip point. The
cpufreq is used as the cooling device to throttle CPUs when the passive
trip is crossed.
config MAX77620_THERMAL
tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
depends on MFD_MAX77620
......@@ -265,6 +287,7 @@ config QORIQ_THERMAL
tristate "QorIQ Thermal Monitoring Unit"
depends on THERMAL_OF
depends on HAS_IOMEM
select REGMAP_MMIO
help
Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms.
It supports one critical trip point and one passive trip point. The
......@@ -460,4 +483,11 @@ config UNIPHIER_THERMAL
Enable this to plug in UniPhier on-chip PVT thermal driver into the
thermal framework. The driver supports CPU thermal zone temperature
reporting and a couple of trip points.
config SPRD_THERMAL
tristate "Temperature sensor on Spreadtrum SoCs"
depends on ARCH_SPRD || COMPILE_TEST
help
Support for the Spreadtrum thermal sensor driver in the Linux thermal
framework.
endif
......@@ -43,6 +43,8 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
obj-$(CONFIG_IMX_SC_THERMAL) += imx_sc_thermal.o
obj-$(CONFIG_IMX8MM_THERMAL) += imx8mm_thermal.o
obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o
......@@ -57,3 +59,4 @@ obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o
obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
......@@ -273,7 +273,7 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
/* Request state should be less than max_level */
if (WARN_ON(state > cpufreq_cdev->max_level))
if (state > cpufreq_cdev->max_level)
return -EINVAL;
num_cpus = cpumask_weight(cpufreq_cdev->policy->cpus);
......@@ -437,7 +437,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
int ret;
/* Request state should be less than max_level */
if (WARN_ON(state > cpufreq_cdev->max_level))
if (state > cpufreq_cdev->max_level)
return -EINVAL;
/* Check if the old cooling action is same as new cooling action */
......@@ -456,6 +456,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
capacity = frequency * max_capacity;
capacity /= cpufreq_cdev->policy->cpuinfo.max_freq;
arch_set_thermal_pressure(cpus, max_capacity - capacity);
ret = 0;
}
return ret;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2020 NXP.
*
* Author: Anson Huang <Anson.Huang@nxp.com>
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include "thermal_core.h"
#define TER 0x0 /* TMU enable */
#define TPS 0x4
#define TRITSR 0x20 /* TMU immediate temp */
#define TER_EN BIT(31)
#define TRITSR_TEMP0_VAL_MASK 0xff
#define TRITSR_TEMP1_VAL_MASK 0xff0000
#define PROBE_SEL_ALL GENMASK(31, 30)
#define probe_status_offset(x) (30 + x)
#define SIGN_BIT BIT(7)
#define TEMP_VAL_MASK GENMASK(6, 0)
#define VER1_TEMP_LOW_LIMIT 10000
#define VER2_TEMP_LOW_LIMIT -40000
#define VER2_TEMP_HIGH_LIMIT 125000
#define TMU_VER1 0x1
#define TMU_VER2 0x2
struct thermal_soc_data {
u32 num_sensors;
u32 version;
int (*get_temp)(void *, int *);
};
struct tmu_sensor {
struct imx8mm_tmu *priv;
u32 hw_id;
struct thermal_zone_device *tzd;
};
struct imx8mm_tmu {
void __iomem *base;
struct clk *clk;
const struct thermal_soc_data *socdata;
struct tmu_sensor sensors[0];
};
static int imx8mm_tmu_get_temp(void *data, int *temp)
{
struct tmu_sensor *sensor = data;
struct imx8mm_tmu *tmu = sensor->priv;
u32 val;
val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK;
*temp = val * 1000;
if (*temp < VER1_TEMP_LOW_LIMIT)
return -EAGAIN;
return 0;
}
static int imx8mp_tmu_get_temp(void *data, int *temp)
{
struct tmu_sensor *sensor = data;
struct imx8mm_tmu *tmu = sensor->priv;
unsigned long val;
bool ready;
val = readl_relaxed(tmu->base + TRITSR);
ready = test_bit(probe_status_offset(sensor->hw_id), &val);
if (!ready)
return -EAGAIN;
val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) :
FIELD_GET(TRITSR_TEMP0_VAL_MASK, val);
if (val & SIGN_BIT) /* negative */
val = (~(val & TEMP_VAL_MASK) + 1);
*temp = val * 1000;
if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)
return -EAGAIN;
return 0;
}
static int tmu_get_temp(void *data, int *temp)
{
struct tmu_sensor *sensor = data;
struct imx8mm_tmu *tmu = sensor->priv;
return tmu->socdata->get_temp(data, temp);
}
static struct thermal_zone_of_device_ops tmu_tz_ops = {
.get_temp = tmu_get_temp,
};
static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)
{
u32 val;
val = readl_relaxed(tmu->base + TER);
val = enable ? (val | TER_EN) : (val & ~TER_EN);
writel_relaxed(val, tmu->base + TER);
}
static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)
{
u32 val;
val = readl_relaxed(tmu->base + TPS);
val |= PROBE_SEL_ALL;
writel_relaxed(val, tmu->base + TPS);
}
static int imx8mm_tmu_probe(struct platform_device *pdev)
{
const struct thermal_soc_data *data;
struct imx8mm_tmu *tmu;
int ret;
int i;
data = of_device_get_match_data(&pdev->dev);
tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,
data->num_sensors), GFP_KERNEL);
if (!tmu)
return -ENOMEM;
tmu->socdata = data;
tmu->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tmu->base))
return PTR_ERR(tmu->base);
tmu->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tmu->clk)) {
ret = PTR_ERR(tmu->clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"failed to get tmu clock: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(tmu->clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable tmu clock: %d\n", ret);
return ret;
}
/* disable the monitor during initialization */
imx8mm_tmu_enable(tmu, false);
for (i = 0; i < data->num_sensors; i++) {
tmu->sensors[i].priv = tmu;
tmu->sensors[i].tzd =
devm_thermal_zone_of_sensor_register(&pdev->dev, i,
&tmu->sensors[i],
&tmu_tz_ops);
if (IS_ERR(tmu->sensors[i].tzd)) {
dev_err(&pdev->dev,
"failed to register thermal zone sensor[%d]: %d\n",
i, ret);
return PTR_ERR(tmu->sensors[i].tzd);
}
tmu->sensors[i].hw_id = i;
}
platform_set_drvdata(pdev, tmu);
/* enable all the probes for V2 TMU */
if (tmu->socdata->version == TMU_VER2)
imx8mm_tmu_probe_sel_all(tmu);
/* enable the monitor */
imx8mm_tmu_enable(tmu, true);
return 0;
}
static int imx8mm_tmu_remove(struct platform_device *pdev)
{
struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
/* disable TMU */
imx8mm_tmu_enable(tmu, false);
clk_disable_unprepare(tmu->clk);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct thermal_soc_data imx8mm_tmu_data = {
.num_sensors = 1,
.version = TMU_VER1,
.get_temp = imx8mm_tmu_get_temp,
};
static struct thermal_soc_data imx8mp_tmu_data = {
.num_sensors = 2,
.version = TMU_VER2,
.get_temp = imx8mp_tmu_get_temp,
};
static const struct of_device_id imx8mm_tmu_table[] = {
{ .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },
{ .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
{ },
};
static struct platform_driver imx8mm_tmu = {
.driver = {
.name = "i.mx8mm_thermal",
.of_match_table = imx8mm_tmu_table,
},
.probe = imx8mm_tmu_probe,
.remove = imx8mm_tmu_remove,
};
module_platform_driver(imx8mm_tmu);
MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
MODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018-2020 NXP.
*/
#include <linux/err.h>
#include <linux/firmware/imx/sci.h>
#include <linux/firmware/imx/types.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/thermal.h>
#include "thermal_core.h"
#define IMX_SC_MISC_FUNC_GET_TEMP 13
static struct imx_sc_ipc *thermal_ipc_handle;
struct imx_sc_sensor {
struct thermal_zone_device *tzd;
u32 resource_id;
};
struct req_get_temp {
u16 resource_id;
u8 type;
} __packed __aligned(4);
struct resp_get_temp {
s16 celsius;
s8 tenths;
} __packed __aligned(4);
struct imx_sc_msg_misc_get_temp {
struct imx_sc_rpc_msg hdr;
union {
struct req_get_temp req;
struct resp_get_temp resp;
} data;
} __packed __aligned(4);
static int imx_sc_thermal_get_temp(void *data, int *temp)
{
struct imx_sc_msg_misc_get_temp msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
struct imx_sc_sensor *sensor = data;
int ret;
msg.data.req.resource_id = sensor->resource_id;
msg.data.req.type = IMX_SC_C_TEMP;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_MISC;
hdr->func = IMX_SC_MISC_FUNC_GET_TEMP;
hdr->size = 2;
ret = imx_scu_call_rpc(thermal_ipc_handle, &msg, true);
if (ret) {
dev_err(&sensor->tzd->device, "read temp sensor %d failed, ret %d\n",
sensor->resource_id, ret);
return ret;
}
*temp = msg.data.resp.celsius * 1000 + msg.data.resp.tenths * 100;
return 0;
}
static const struct thermal_zone_of_device_ops imx_sc_thermal_ops = {
.get_temp = imx_sc_thermal_get_temp,
};
static int imx_sc_thermal_probe(struct platform_device *pdev)
{
struct device_node *np, *child, *sensor_np;
struct imx_sc_sensor *sensor;
int ret;
ret = imx_scu_get_handle(&thermal_ipc_handle);
if (ret)
return ret;
np = of_find_node_by_name(NULL, "thermal-zones");
if (!np)
return -ENODEV;
sensor_np = of_node_get(pdev->dev.of_node);
for_each_available_child_of_node(np, child) {
sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor) {
of_node_put(sensor_np);
return -ENOMEM;
}
ret = thermal_zone_of_get_sensor_id(child,
sensor_np,
&sensor->resource_id);
if (ret < 0) {
dev_err(&pdev->dev,
"failed to get valid sensor resource id: %d\n",
ret);
break;
}
sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
sensor->resource_id,
sensor,
&imx_sc_thermal_ops);
if (IS_ERR(sensor->tzd)) {
dev_err(&pdev->dev, "failed to register thermal zone\n");
ret = PTR_ERR(sensor->tzd);
break;
}
}
of_node_put(sensor_np);
return ret;
}
static int imx_sc_thermal_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id imx_sc_thermal_table[] = {
{ .compatible = "fsl,imx-sc-thermal", },
{}
};
MODULE_DEVICE_TABLE(of, imx_sc_thermal_table);
static struct platform_driver imx_sc_thermal_driver = {
.probe = imx_sc_thermal_probe,
.remove = imx_sc_thermal_remove,
.driver = {
.name = "imx-sc-thermal",
.of_match_table = imx_sc_thermal_table,
},
};
module_platform_driver(imx_sc_thermal_driver);
MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
MODULE_DESCRIPTION("Thermal driver for NXP i.MX SoCs with system controller");
MODULE_LICENSE("GPL v2");
......@@ -3,24 +3,17 @@
// Copyright 2013 Freescale Semiconductor, Inc.
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/cpu_cooling.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/thermal.h>
#include <linux/types.h>
#include <linux/nvmem-consumer.h>
#define REG_SET 0x4
......@@ -872,14 +865,12 @@ static int imx_thermal_remove(struct platform_device *pdev)
clk_disable_unprepare(data->thermal_clk);
thermal_zone_device_unregister(data->tz);
cpufreq_cooling_unregister(data->cdev);
cpufreq_cpu_put(data->policy);
imx_thermal_unregister_legacy_cooling(data);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int imx_thermal_suspend(struct device *dev)
static int __maybe_unused imx_thermal_suspend(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
struct regmap *map = data->tempmon;
......@@ -900,7 +891,7 @@ static int imx_thermal_suspend(struct device *dev)
return 0;
}
static int imx_thermal_resume(struct device *dev)
static int __maybe_unused imx_thermal_resume(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
struct regmap *map = data->tempmon;
......@@ -918,7 +909,6 @@ static int imx_thermal_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
imx_thermal_suspend, imx_thermal_resume);
......
......@@ -65,7 +65,7 @@ static ssize_t available_uuids_show(struct device *dev,
for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) {
if (priv->uuid_bitmap & (1 << i))
if (PAGE_SIZE - length > 0)
length += snprintf(&buf[length],
length += scnprintf(&buf[length],
PAGE_SIZE - length,
"%s\n",
int3400_thermal_uuids[i]);
......
......@@ -45,6 +45,9 @@
/* JasperLake thermal reporting device */
#define PCI_DEVICE_ID_PROC_JSL_THERMAL 0x4503
/* TigerLake thermal reporting device */
#define PCI_DEVICE_ID_PROC_TGL_THERMAL 0x9A03
#define DRV_NAME "proc_thermal"
struct power_config {
......@@ -728,6 +731,8 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_ICL_THERMAL),
.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_JSL_THERMAL)},
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_TGL_THERMAL),
.driver_data = (kernel_ulong_t)&rapl_mmio_hsw, },
{ 0, },
};
......
......@@ -448,6 +448,50 @@ thermal_zone_of_add_sensor(struct device_node *zone,
return tzd;
}
/**
* thermal_zone_of_get_sensor_id - get sensor ID from a DT thermal zone
* @tz_np: a valid thermal zone device node.
* @sensor_np: a sensor node of a valid sensor device.
* @id: the sensor ID returned if success.
*
* This function will get sensor ID from a given thermal zone node and
* the sensor node must match the temperature provider @sensor_np.
*
* Return: 0 on success, proper error code otherwise.
*/
int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
struct device_node *sensor_np,
u32 *id)
{
struct of_phandle_args sensor_specs;
int ret;
ret = of_parse_phandle_with_args(tz_np,
"thermal-sensors",
"#thermal-sensor-cells",
0,
&sensor_specs);
if (ret)
return ret;
if (sensor_specs.np != sensor_np) {
of_node_put(sensor_specs.np);
return -ENODEV;
}
if (sensor_specs.args_count > 1)
pr_warn("%pOFn: too many cells in sensor specifier %d\n",
sensor_specs.np, sensor_specs.args_count);
*id = sensor_specs.args_count ? sensor_specs.args[0] : 0;
of_node_put(sensor_specs.np);
return 0;
}
EXPORT_SYMBOL_GPL(thermal_zone_of_get_sensor_id);
/**
* thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
* @dev: a valid struct device pointer of a sensor device. Must contain
......@@ -499,36 +543,22 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
sensor_np = of_node_get(dev->of_node);
for_each_available_child_of_node(np, child) {
struct of_phandle_args sensor_specs;
int ret, id;
/* For now, thermal framework supports only 1 sensor per zone */
ret = of_parse_phandle_with_args(child, "thermal-sensors",
"#thermal-sensor-cells",
0, &sensor_specs);
ret = thermal_zone_of_get_sensor_id(child, sensor_np, &id);
if (ret)
continue;
if (sensor_specs.args_count >= 1) {
id = sensor_specs.args[0];
WARN(sensor_specs.args_count > 1,
"%pOFn: too many cells in sensor specifier %d\n",
sensor_specs.np, sensor_specs.args_count);
} else {
id = 0;
}
if (sensor_specs.np == sensor_np && id == sensor_id) {
if (id == sensor_id) {
tzd = thermal_zone_of_add_sensor(child, sensor_np,
data, ops);
if (!IS_ERR(tzd))
tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
of_node_put(sensor_specs.np);
of_node_put(child);
goto exit;
}
of_node_put(sensor_specs.np);
}
exit:
of_node_put(sensor_np);
......
......@@ -245,7 +245,7 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
return adc_code * slope + offset;
}
static int get_temp_8960(struct tsens_sensor *s, int *temp)
static int get_temp_8960(const struct tsens_sensor *s, int *temp)
{
int ret;
u32 code, trdy;
......@@ -279,7 +279,7 @@ static const struct tsens_ops ops_8960 = {
.resume = resume_8960,
};
const struct tsens_plat_data data_8960 = {
struct tsens_plat_data data_8960 = {
.num_sensors = 11,
.ops = &ops_8960,
};
This diff is collapsed.
......@@ -327,7 +327,7 @@ static int calibrate_8974(struct tsens_priv *priv)
/* v0.1: 8916, 8974 */
static const struct tsens_features tsens_v0_1_feat = {
static struct tsens_features tsens_v0_1_feat = {
.ver_major = VER_0_1,
.crit_int = 0,
.adc = 1,
......@@ -377,7 +377,7 @@ static const struct tsens_ops ops_8916 = {
.get_temp = get_temp_common,
};
const struct tsens_plat_data data_8916 = {
struct tsens_plat_data data_8916 = {
.num_sensors = 5,
.ops = &ops_8916,
.hw_ids = (unsigned int []){0, 1, 2, 4, 5 },
......@@ -392,7 +392,7 @@ static const struct tsens_ops ops_8974 = {
.get_temp = get_temp_common,
};
const struct tsens_plat_data data_8974 = {
struct tsens_plat_data data_8974 = {
.num_sensors = 11,
.ops = &ops_8974,
.feat = &tsens_v0_1_feat,
......
......@@ -299,7 +299,7 @@ static int calibrate_8976(struct tsens_priv *priv)
/* v1.x: msm8956,8976,qcs404,405 */
static const struct tsens_features tsens_v1_feat = {
static struct tsens_features tsens_v1_feat = {
.ver_major = VER_1_X,
.crit_int = 0,
.adc = 1,
......@@ -368,7 +368,7 @@ static const struct tsens_ops ops_generic_v1 = {
.get_temp = get_temp_tsens_valid,
};
const struct tsens_plat_data data_tsens_v1 = {
struct tsens_plat_data data_tsens_v1 = {
.ops = &ops_generic_v1,
.feat = &tsens_v1_feat,
.fields = tsens_v1_regfields,
......@@ -381,7 +381,7 @@ static const struct tsens_ops ops_8976 = {
};
/* Valid for both MSM8956 and MSM8976. Sensor ID 3 is unused. */
const struct tsens_plat_data data_8976 = {
struct tsens_plat_data data_8976 = {
.num_sensors = 11,
.ops = &ops_8976,
.hw_ids = (unsigned int[]){0, 1, 2, 4, 5, 6, 7, 8, 9, 10},
......
......@@ -24,10 +24,11 @@
#define TM_Sn_CRITICAL_THRESHOLD_OFF 0x0060
#define TM_Sn_STATUS_OFF 0x00a0
#define TM_TRDY_OFF 0x00e4
#define TM_WDOG_LOG_OFF 0x013c
/* v2.x: 8996, 8998, sdm845 */
static const struct tsens_features tsens_v2_feat = {
static struct tsens_features tsens_v2_feat = {
.ver_major = VER_2_X,
.crit_int = 1,
.adc = 0,
......@@ -51,8 +52,9 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
[INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 2),
/* TEMPERATURE THRESHOLDS */
REG_FIELD_FOR_EACH_SENSOR16(LOW_THRESH, TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 0, 11),
REG_FIELD_FOR_EACH_SENSOR16(UP_THRESH, TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 12, 23),
REG_FIELD_FOR_EACH_SENSOR16(LOW_THRESH, TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 0, 11),
REG_FIELD_FOR_EACH_SENSOR16(UP_THRESH, TM_Sn_UPPER_LOWER_THRESHOLD_OFF, 12, 23),
REG_FIELD_FOR_EACH_SENSOR16(CRIT_THRESH, TM_Sn_CRITICAL_THRESHOLD_OFF, 0, 11),
/* INTERRUPTS [CLEAR/STATUS/MASK] */
REG_FIELD_SPLIT_BITS_0_15(LOW_INT_STATUS, TM_UPPER_LOWER_INT_STATUS_OFF),
......@@ -61,6 +63,18 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
REG_FIELD_SPLIT_BITS_16_31(UP_INT_STATUS, TM_UPPER_LOWER_INT_STATUS_OFF),
REG_FIELD_SPLIT_BITS_16_31(UP_INT_CLEAR, TM_UPPER_LOWER_INT_CLEAR_OFF),
REG_FIELD_SPLIT_BITS_16_31(UP_INT_MASK, TM_UPPER_LOWER_INT_MASK_OFF),
REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_STATUS, TM_CRITICAL_INT_STATUS_OFF),
REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_CLEAR, TM_CRITICAL_INT_CLEAR_OFF),
REG_FIELD_SPLIT_BITS_0_15(CRIT_INT_MASK, TM_CRITICAL_INT_MASK_OFF),
/* WATCHDOG on v2.3 or later */
[WDOG_BARK_STATUS] = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 31, 31),
[WDOG_BARK_CLEAR] = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF, 31, 31),
[WDOG_BARK_MASK] = REG_FIELD(TM_CRITICAL_INT_MASK_OFF, 31, 31),
[CC_MON_STATUS] = REG_FIELD(TM_CRITICAL_INT_STATUS_OFF, 30, 30),
[CC_MON_CLEAR] = REG_FIELD(TM_CRITICAL_INT_CLEAR_OFF, 30, 30),
[CC_MON_MASK] = REG_FIELD(TM_CRITICAL_INT_MASK_OFF, 30, 30),
[WDOG_BARK_COUNT] = REG_FIELD(TM_WDOG_LOG_OFF, 0, 7),
/* Sn_STATUS */
REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 11),
......@@ -81,14 +95,14 @@ static const struct tsens_ops ops_generic_v2 = {
.get_temp = get_temp_tsens_valid,
};
const struct tsens_plat_data data_tsens_v2 = {
struct tsens_plat_data data_tsens_v2 = {
.ops = &ops_generic_v2,
.feat = &tsens_v2_feat,
.fields = tsens_v2_regfields,
};
/* Kept around for backward compatibility with old msm8996.dtsi */
const struct tsens_plat_data data_8996 = {
struct tsens_plat_data data_8996 = {
.num_sensors = 13,
.ops = &ops_generic_v2,
.feat = &tsens_v2_feat,
......
......@@ -85,11 +85,42 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = {
.set_trips = tsens_set_trips,
};
static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
irq_handler_t thread_fn)
{
struct platform_device *pdev;
int ret, irq;
pdev = of_find_device_by_node(priv->dev->of_node);
if (!pdev)
return -ENODEV;
irq = platform_get_irq_byname(pdev, irqname);
if (irq < 0) {
ret = irq;
/* For old DTs with no IRQ defined */
if (irq == -ENXIO)
ret = 0;
} else {
ret = devm_request_threaded_irq(&pdev->dev, irq,
NULL, thread_fn,
IRQF_ONESHOT,
dev_name(&pdev->dev), priv);
if (ret)
dev_err(&pdev->dev, "%s: failed to get irq\n",
__func__);
else
enable_irq_wake(irq);
}
put_device(&pdev->dev);
return ret;
}
static int tsens_register(struct tsens_priv *priv)
{
int i, ret, irq;
int i, ret;
struct thermal_zone_device *tzd;
struct platform_device *pdev;
for (i = 0; i < priv->num_sensors; i++) {
priv->sensor[i].priv = priv;
......@@ -103,32 +134,14 @@ static int tsens_register(struct tsens_priv *priv)
priv->ops->enable(priv, i);
}
pdev = of_find_device_by_node(priv->dev->of_node);
if (!pdev)
return -ENODEV;
irq = platform_get_irq_byname(pdev, "uplow");
if (irq < 0) {
ret = irq;
/* For old DTs with no IRQ defined */
if (irq == -ENXIO)
ret = 0;
goto err_put_device;
}
ret = devm_request_threaded_irq(&pdev->dev, irq,
NULL, tsens_irq_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
dev_name(&pdev->dev), priv);
if (ret) {
dev_err(&pdev->dev, "%s: failed to get irq\n", __func__);
goto err_put_device;
}
ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
if (ret < 0)
return ret;
enable_irq_wake(irq);
if (priv->feat->crit_int)
ret = tsens_register_irq(priv, "critical",
tsens_critical_irq_thread);
err_put_device:
put_device(&pdev->dev);
return ret;
}
......
......@@ -23,6 +23,7 @@
struct tsens_priv;
/* IP version numbers in ascending order */
enum tsens_ver {
VER_0_1 = 0,
VER_1_X,
......@@ -32,6 +33,7 @@ enum tsens_ver {
enum tsens_irq_type {
LOWER,
UPPER,
CRITICAL,
};
/**
......@@ -67,7 +69,7 @@ struct tsens_ops {
/* mandatory callbacks */
int (*init)(struct tsens_priv *priv);
int (*calibrate)(struct tsens_priv *priv);
int (*get_temp)(struct tsens_sensor *s, int *temp);
int (*get_temp)(const struct tsens_sensor *s, int *temp);
/* optional callbacks */
int (*enable)(struct tsens_priv *priv, int i);
void (*disable)(struct tsens_priv *priv);
......@@ -374,6 +376,82 @@ enum regfield_ids {
CRITICAL_STATUS_13,
CRITICAL_STATUS_14,
CRITICAL_STATUS_15,
CRIT_INT_STATUS_0, /* CRITICAL interrupt status */
CRIT_INT_STATUS_1,
CRIT_INT_STATUS_2,
CRIT_INT_STATUS_3,
CRIT_INT_STATUS_4,
CRIT_INT_STATUS_5,
CRIT_INT_STATUS_6,
CRIT_INT_STATUS_7,
CRIT_INT_STATUS_8,
CRIT_INT_STATUS_9,
CRIT_INT_STATUS_10,
CRIT_INT_STATUS_11,
CRIT_INT_STATUS_12,
CRIT_INT_STATUS_13,
CRIT_INT_STATUS_14,
CRIT_INT_STATUS_15,
CRIT_INT_CLEAR_0, /* CRITICAL interrupt clear */
CRIT_INT_CLEAR_1,
CRIT_INT_CLEAR_2,
CRIT_INT_CLEAR_3,
CRIT_INT_CLEAR_4,
CRIT_INT_CLEAR_5,
CRIT_INT_CLEAR_6,
CRIT_INT_CLEAR_7,
CRIT_INT_CLEAR_8,
CRIT_INT_CLEAR_9,
CRIT_INT_CLEAR_10,
CRIT_INT_CLEAR_11,
CRIT_INT_CLEAR_12,
CRIT_INT_CLEAR_13,
CRIT_INT_CLEAR_14,
CRIT_INT_CLEAR_15,
CRIT_INT_MASK_0, /* CRITICAL interrupt mask */
CRIT_INT_MASK_1,
CRIT_INT_MASK_2,
CRIT_INT_MASK_3,
CRIT_INT_MASK_4,
CRIT_INT_MASK_5,
CRIT_INT_MASK_6,
CRIT_INT_MASK_7,
CRIT_INT_MASK_8,
CRIT_INT_MASK_9,
CRIT_INT_MASK_10,
CRIT_INT_MASK_11,
CRIT_INT_MASK_12,
CRIT_INT_MASK_13,
CRIT_INT_MASK_14,
CRIT_INT_MASK_15,
CRIT_THRESH_0, /* CRITICAL threshold values */
CRIT_THRESH_1,
CRIT_THRESH_2,
CRIT_THRESH_3,
CRIT_THRESH_4,
CRIT_THRESH_5,
CRIT_THRESH_6,
CRIT_THRESH_7,
CRIT_THRESH_8,
CRIT_THRESH_9,
CRIT_THRESH_10,
CRIT_THRESH_11,
CRIT_THRESH_12,
CRIT_THRESH_13,
CRIT_THRESH_14,
CRIT_THRESH_15,
/* WATCHDOG */
WDOG_BARK_STATUS,
WDOG_BARK_CLEAR,
WDOG_BARK_MASK,
WDOG_BARK_COUNT,
/* CYCLE COMPLETION MONITOR */
CC_MON_STATUS,
CC_MON_CLEAR,
CC_MON_MASK,
MIN_STATUS_0, /* MIN threshold violated */
MIN_STATUS_1,
MIN_STATUS_2,
......@@ -418,6 +496,7 @@ enum regfield_ids {
* @adc: do the sensors only output adc code (instead of temperature)?
* @srot_split: does the IP neatly splits the register space into SROT and TM,
* with SROT only being available to secure boot firmware?
* @has_watchdog: does this IP support watchdog functionality?
* @max_sensors: maximum sensors supported by this version of the IP
*/
struct tsens_features {
......@@ -425,6 +504,7 @@ struct tsens_features {
unsigned int crit_int:1;
unsigned int adc:1;
unsigned int srot_split:1;
unsigned int has_watchdog:1;
unsigned int max_sensors;
};
......@@ -440,12 +520,14 @@ struct tsens_plat_data {
const u32 num_sensors;
const struct tsens_ops *ops;
unsigned int *hw_ids;
const struct tsens_features *feat;
struct tsens_features *feat;
const struct reg_field *fields;
};
/**
* struct tsens_context - Registers to be saved/restored across a context loss
* @threshold: Threshold register value
* @control: Control register value
*/
struct tsens_context {
int threshold;
......@@ -460,6 +542,8 @@ struct tsens_context {
* @srot_map: pointer to SROT register address space
* @tm_offset: deal with old device trees that don't address TM and SROT
* address space separately
* @ul_lock: lock while processing upper/lower threshold interrupts
* @crit_lock: lock while processing critical threshold interrupts
* @rf: array of regmap_fields used to store value of the field
* @ctx: registers to be saved and restored during suspend/resume
* @feat: features of the IP
......@@ -481,36 +565,37 @@ struct tsens_priv {
struct regmap_field *rf[MAX_REGFIELDS];
struct tsens_context ctx;
const struct tsens_features *feat;
struct tsens_features *feat;
const struct reg_field *fields;
const struct tsens_ops *ops;
struct dentry *debug_root;
struct dentry *debug;
struct tsens_sensor sensor[0];
struct tsens_sensor sensor[];
};
char *qfprom_read(struct device *dev, const char *cname);
void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode);
int init_common(struct tsens_priv *priv);
int get_temp_tsens_valid(struct tsens_sensor *s, int *temp);
int get_temp_common(struct tsens_sensor *s, int *temp);
int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp);
int get_temp_common(const struct tsens_sensor *s, int *temp);
int tsens_enable_irq(struct tsens_priv *priv);
void tsens_disable_irq(struct tsens_priv *priv);
int tsens_set_trips(void *_sensor, int low, int high);
irqreturn_t tsens_irq_thread(int irq, void *data);
irqreturn_t tsens_critical_irq_thread(int irq, void *data);
/* TSENS target */
extern const struct tsens_plat_data data_8960;
extern struct tsens_plat_data data_8960;
/* TSENS v0.1 targets */
extern const struct tsens_plat_data data_8916, data_8974;
extern struct tsens_plat_data data_8916, data_8974;
/* TSENS v1 targets */
extern const struct tsens_plat_data data_tsens_v1, data_8976;
extern struct tsens_plat_data data_tsens_v1, data_8976;
/* TSENS v2 targets */
extern const struct tsens_plat_data data_8996, data_tsens_v2;
extern struct tsens_plat_data data_8996, data_tsens_v2;
#endif /* __QCOM_TSENS_H__ */
......@@ -3,12 +3,11 @@
// Copyright 2016 Freescale Semiconductor, Inc.
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/thermal.h>
......@@ -228,6 +227,14 @@ static const struct regmap_access_table qoriq_rd_table = {
.n_yes_ranges = ARRAY_SIZE(qoriq_yes_ranges),
};
static void qoriq_tmu_action(void *p)
{
struct qoriq_tmu_data *data = p;
regmap_write(data->regmap, REGS_TMR, TMR_DISABLE);
clk_disable_unprepare(data->clk);
}
static int qoriq_tmu_probe(struct platform_device *pdev)
{
int ret;
......@@ -278,6 +285,10 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
return ret;
}
ret = devm_add_action_or_reset(dev, qoriq_tmu_action, data);
if (ret)
return ret;
/* version register offset at: 0xbf8 on both v1 and v2 */
ret = regmap_read(data->regmap, REGS_IPBRR(0), &ver);
if (ret) {
......@@ -290,34 +301,16 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
ret = qoriq_tmu_calibration(dev, data); /* TMU calibration */
if (ret < 0)
goto err;
return ret;
ret = qoriq_tmu_register_tmu_zone(dev, data);
if (ret < 0) {
dev_err(dev, "Failed to register sensors\n");
ret = -ENODEV;
goto err;
return ret;
}
platform_set_drvdata(pdev, data);
return 0;
err:
clk_disable_unprepare(data->clk);
return ret;
}
static int qoriq_tmu_remove(struct platform_device *pdev)
{
struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
/* Disable monitoring */
regmap_write(data->regmap, REGS_TMR, TMR_DISABLE);
clk_disable_unprepare(data->clk);
return 0;
}
......@@ -365,7 +358,6 @@ static struct platform_driver qoriq_tmu = {
.of_match_table = qoriq_tmu_match,
},
.probe = qoriq_tmu_probe,
.remove = qoriq_tmu_remove,
};
module_platform_driver(qoriq_tmu);
......
......@@ -81,8 +81,6 @@ struct rcar_gen3_thermal_tsc {
void __iomem *base;
struct thermal_zone_device *zone;
struct equation_coefs coef;
int low;
int high;
int tj_t;
int id; /* thermal channel id */
};
......@@ -204,12 +202,14 @@ static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
return INT_FIXPT(val);
}
static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
static int rcar_gen3_thermal_update_range(struct rcar_gen3_thermal_tsc *tsc)
{
struct rcar_gen3_thermal_tsc *tsc = devdata;
int temperature, low, high;
rcar_gen3_thermal_get_temp(tsc, &temperature);
low = clamp_val(low, -40000, 120000);
high = clamp_val(high, -40000, 120000);
low = temperature - MCELSIUS(1);
high = temperature + MCELSIUS(1);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
......@@ -217,15 +217,11 @@ static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
tsc->low = low;
tsc->high = high;
return 0;
}
static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
.get_temp = rcar_gen3_thermal_get_temp,
.set_trips = rcar_gen3_thermal_set_trips,
};
static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on)
......@@ -246,9 +242,11 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
for (i = 0; i < priv->num_tscs; i++) {
status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
if (status)
if (status) {
rcar_gen3_thermal_update_range(priv->tscs[i]);
thermal_zone_device_update(priv->tscs[i]->zone,
THERMAL_EVENT_UNSPECIFIED);
}
}
return IRQ_HANDLED;
......@@ -324,6 +322,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
.compatible = "renesas,r8a7796-thermal",
.data = &rcar_gen3_ths_tj_1_m3_w,
},
{
.compatible = "renesas,r8a77961-thermal",
.data = &rcar_gen3_ths_tj_1_m3_w,
},
{
.compatible = "renesas,r8a77965-thermal",
.data = &rcar_gen3_ths_tj_1,
......@@ -446,14 +448,15 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
goto error_unregister;
ret = devm_add_action_or_reset(dev, rcar_gen3_hwmon_action, zone);
if (ret) {
if (ret)
goto error_unregister;
}
ret = of_thermal_get_ntrips(tsc->zone);
if (ret < 0)
goto error_unregister;
rcar_gen3_thermal_update_range(tsc);
dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
}
......@@ -492,7 +495,7 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
priv->thermal_init(tsc);
rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high);
rcar_gen3_thermal_update_range(tsc);
}
rcar_thermal_irq_set(priv, true);
......
......@@ -95,7 +95,6 @@ struct rcar_thermal_priv {
struct mutex lock;
struct list_head list;
int id;
u32 ctemp;
};
#define rcar_thermal_for_each_priv(pos, common) \
......@@ -201,7 +200,6 @@ static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
struct device *dev = rcar_priv_to_dev(priv);
int i;
u32 ctemp, old, new;
int ret = -EINVAL;
mutex_lock(&priv->lock);
......@@ -247,37 +245,29 @@ static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
((ctemp - 1) << 0)));
}
dev_dbg(dev, "thermal%d %d -> %d\n", priv->id, priv->ctemp, ctemp);
priv->ctemp = ctemp;
ret = 0;
err_out_unlock:
mutex_unlock(&priv->lock);
return ret;
return ctemp ? ctemp : -EINVAL;
}
static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
int *temp)
{
int tmp;
int ret;
ret = rcar_thermal_update_temp(priv);
if (ret < 0)
return ret;
int ctemp;
mutex_lock(&priv->lock);
if (priv->chip->ctemp_bands == 1)
tmp = MCELSIUS((priv->ctemp * 5) - 65);
else if (priv->ctemp < 24)
tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10);
else
tmp = MCELSIUS((priv->ctemp * 5) - 60);
mutex_unlock(&priv->lock);
ctemp = rcar_thermal_update_temp(priv);
if (ctemp < 0)
return ctemp;
/* Guaranteed operating range is -45C to 125C. */
*temp = tmp;
if (priv->chip->ctemp_bands == 1)
*temp = MCELSIUS((ctemp * 5) - 65);
else if (ctemp < 24)
*temp = MCELSIUS(((ctemp * 55) - 720) / 10);
else
*temp = MCELSIUS((ctemp * 5) - 60);
return 0;
}
......@@ -387,28 +377,17 @@ static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
static void rcar_thermal_work(struct work_struct *work)
{
struct rcar_thermal_priv *priv;
int cctemp, nctemp;
int ret;
priv = container_of(work, struct rcar_thermal_priv, work.work);
ret = rcar_thermal_get_current_temp(priv, &cctemp);
if (ret < 0)
return;
ret = rcar_thermal_update_temp(priv);
if (ret < 0)
return;
rcar_thermal_irq_enable(priv);
ret = rcar_thermal_get_current_temp(priv, &nctemp);
if (ret < 0)
return;
if (nctemp != cctemp)
thermal_zone_device_update(priv->zone,
THERMAL_EVENT_UNSPECIFIED);
thermal_zone_device_update(priv->zone, THERMAL_EVENT_UNSPECIFIED);
}
static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
......@@ -521,8 +500,10 @@ static int rcar_thermal_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM,
mres++);
common->base = devm_ioremap_resource(dev, res);
if (IS_ERR(common->base))
return PTR_ERR(common->base);
if (IS_ERR(common->base)) {
ret = PTR_ERR(common->base);
goto error_unregister;
}
idle = 0; /* polling delay is not needed */
}
......
......@@ -1094,7 +1094,9 @@ static int exynos_tmu_probe(struct platform_device *pdev)
&exynos_sensor_ops);
if (IS_ERR(data->tzd)) {
ret = PTR_ERR(data->tzd);
dev_err(&pdev->dev, "Failed to register sensor: %d\n", ret);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to register sensor: %d\n",
ret);
goto err_sclk;
}
......
This diff is collapsed.
......@@ -478,7 +478,8 @@ static int stm_thermal_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume);
static SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops,
stm_thermal_suspend, stm_thermal_resume);
static const struct thermal_zone_of_device_ops stm_tz_ops = {
.get_temp = stm_thermal_get_temp,
......
......@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/types.h>
......@@ -24,7 +24,6 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include "ti-bandgap.h"
......@@ -743,27 +742,13 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
static int ti_bandgap_tshut_init(struct ti_bandgap *bgp,
struct platform_device *pdev)
{
int gpio_nr = bgp->tshut_gpio;
int status;
/* Request for gpio_86 line */
status = gpio_request(gpio_nr, "tshut");
if (status < 0) {
dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86);
return status;
}
status = gpio_direction_input(gpio_nr);
if (status) {
dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr);
return status;
}
status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler,
status = request_irq(gpiod_to_irq(bgp->tshut_gpiod),
ti_bandgap_tshut_irq_handler,
IRQF_TRIGGER_RISING, "tshut", NULL);
if (status) {
gpio_free(gpio_nr);
if (status)
dev_err(bgp->dev, "request irq failed for TSHUT");
}
return 0;
}
......@@ -860,11 +845,10 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
} while (res);
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
bgp->tshut_gpio = of_get_gpio(node, 0);
if (!gpio_is_valid(bgp->tshut_gpio)) {
dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
bgp->tshut_gpio);
return ERR_PTR(-EINVAL);
bgp->tshut_gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
if (IS_ERR(bgp->tshut_gpiod)) {
dev_err(&pdev->dev, "invalid gpio for tshut\n");
return ERR_CAST(bgp->tshut_gpiod);
}
}
......@@ -1046,10 +1030,8 @@ int ti_bandgap_probe(struct platform_device *pdev)
put_fclock:
clk_put(bgp->fclock);
free_irqs:
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
gpio_free(bgp->tshut_gpio);
}
if (TI_BANDGAP_HAS(bgp, TSHUT))
free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
return ret;
}
......@@ -1079,10 +1061,8 @@ int ti_bandgap_remove(struct platform_device *pdev)
if (TI_BANDGAP_HAS(bgp, TALERT))
free_irq(bgp->irq, bgp);
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
gpio_free(bgp->tshut_gpio);
}
if (TI_BANDGAP_HAS(bgp, TSHUT))
free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
return 0;
}
......
......@@ -13,6 +13,8 @@
#include <linux/types.h>
#include <linux/err.h>
struct gpio_desc;
/**
* DOC: bandgap driver data structure
* ==================================
......@@ -199,7 +201,7 @@ struct ti_bandgap {
struct clk *div_clk;
spinlock_t lock; /* shields this struct */
int irq;
int tshut_gpio;
struct gpio_desc *tshut_gpiod;
u32 clk_rate;
};
......
......@@ -75,7 +75,7 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *dfc);
#else /* !CONFIG_DEVFREQ_THERMAL */
struct thermal_cooling_device *
static inline struct thermal_cooling_device *
of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
struct devfreq_cooling_power *dfc_power)
{
......
......@@ -364,6 +364,9 @@ struct thermal_trip {
/* Function declarations */
#ifdef CONFIG_THERMAL_OF
int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
struct device_node *sensor_np,
u32 *id);
struct thermal_zone_device *
thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
const struct thermal_zone_of_device_ops *ops);
......@@ -375,6 +378,13 @@ struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
void devm_thermal_zone_of_sensor_unregister(struct device *dev,
struct thermal_zone_device *tz);
#else
static inline int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
struct device_node *sensor_np,
u32 *id)
{
return -ENOENT;
}
static inline struct thermal_zone_device *
thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
const struct thermal_zone_of_device_ops *ops)
......
......@@ -46,7 +46,7 @@ static void start_daemon_mode(void);
pthread_t event_tid;
pthread_mutex_t input_lock;
void usage()
void usage(void)
{
printf("Usage: tmon [OPTION...]\n");
printf(" -c, --control cooling device in control\n");
......@@ -62,7 +62,7 @@ void usage()
exit(0);
}
void version()
void version(void)
{
printf("TMON version %s\n", VERSION);
exit(EXIT_SUCCESS);
......@@ -70,7 +70,6 @@ void version()
static void tmon_cleanup(void)
{
syslog(LOG_INFO, "TMON exit cleanup\n");
fflush(stdout);
refresh();
......@@ -96,7 +95,6 @@ static void tmon_cleanup(void)
exit(1);
}
static void tmon_sig_handler(int sig)
{
syslog(LOG_INFO, "TMON caught signal %d\n", sig);
......@@ -120,7 +118,6 @@ static void tmon_sig_handler(int sig)
tmon_exit = true;
}
static void start_syslog(void)
{
if (debug_on)
......@@ -167,7 +164,6 @@ static void prepare_logging(void)
return;
}
fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n");
for (i = 0; i < ptdata.nr_tz_sensor; i++) {
char binding_str[33]; /* size of long + 1 */
......@@ -175,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 & (1 << j)) ?
'1' : '0';
fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n",
......@@ -187,7 +183,6 @@ static void prepare_logging(void)
trip_type_name[ptdata.tzi[i].tp[j].type],
ptdata.tzi[i].tp[j].temp);
}
}
for (i = 0; i < ptdata.nr_cooling_dev; i++)
......@@ -219,7 +214,6 @@ static struct option opts[] = {
{ 0, 0, NULL, 0 }
};
int main(int argc, char **argv)
{
int err = 0;
......@@ -283,7 +277,7 @@ int main(int argc, char **argv)
if (signal(SIGINT, tmon_sig_handler) == SIG_ERR)
syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
if (signal(SIGTERM, tmon_sig_handler) == SIG_ERR)
syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
syslog(LOG_DEBUG, "Cannot handle SIGTERM\n");
if (probe_thermal_sysfs()) {
pthread_mutex_destroy(&input_lock);
......@@ -328,8 +322,7 @@ int main(int argc, char **argv)
show_cooling_device();
}
time_elapsed += ticktime;
controller_handler(trec[0].temp[target_tz_index] / 1000,
&yk);
controller_handler(trec[0].temp[target_tz_index] / 1000, &yk);
trec[0].pid_out_pct = yk;
if (!dialogue_on)
show_control_w();
......@@ -340,14 +333,15 @@ int main(int argc, char **argv)
return 0;
}
static void start_daemon_mode()
static void start_daemon_mode(void)
{
daemon_mode = 1;
/* fork */
pid_t sid, pid = fork();
if (pid < 0) {
if (pid < 0)
exit(EXIT_FAILURE);
} else if (pid > 0)
else if (pid > 0)
/* kill parent */
exit(EXIT_SUCCESS);
......@@ -366,11 +360,9 @@ static void start_daemon_mode()
if ((chdir("/")) < 0)
exit(EXIT_FAILURE);
sleep(10);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment