Commit fe2437cc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull thermal control updates from Rafael Wysocki:
 "These add a new driver for Renesas RZ/G2L TSU, update a few existing
  thermal control drivers and clean up the tmon utility.

  Specifics:

   - Add new TSU driver and DT bindings for the Renesas RZ/G2L platform
     (Biju Das).

   - Fix missing check when calling reset_control_deassert() in the
     rz2gl thermal driver (Biju Das).

   - In preparation for FORTIFY_SOURCE performing compile-time and
     run-time field bounds checking for memcpy(), avoid intentionally
     writing across neighboring fields in the int340x thermal control
     driver (Kees Cook).

   - Fix RFIM mailbox write commands handling in the int340x thermal
     control driver (Sumeet Pawnikar).

   - Fix PM issue occurring in the iMX thermal control driver during
     suspend/resume by implementing PM runtime support in it (Oleksij
     Rempel).

   - Add 'const' annotation to thermal_cooling_ops in the Intel
     powerclamp driver (Rikard Falkeborn).

   - Fix missing ADC bit set in the iMX8MP thermal driver to enable the
     sensor (Paul Gerber).

   - Drop unused local variable definition from tmon (ran jianping)"

* tag 'thermal-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  thermal/drivers/int340x: Fix RFIM mailbox write commands
  thermal/drivers/rz2gl: Add error check for reset_control_deassert()
  thermal/drivers/imx8mm: Enable ADC when enabling monitor
  thermal/drivers: Add TSU driver for RZ/G2L
  dt-bindings: thermal: Document Renesas RZ/G2L TSU
  thermal/drivers/intel_powerclamp: Constify static thermal_cooling_device_ops
  thermal/drivers/imx: Implement runtime PM support
  thermal: tools: tmon: remove unneeded local variable
  thermal: int340x: Use struct_group() for memcpy() region
parents b35b6d4d fff489ff
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/rzg2l-thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Renesas RZ/G2L Thermal Sensor Unit

description:
  On RZ/G2L SoCs, the thermal sensor unit (TSU) measures the
  temperature(Tj) inside the LSI.

maintainers:
  - Biju Das <biju.das.jz@bp.renesas.com>

properties:
  compatible:
    items:
      - enum:
          - renesas,r9a07g044-tsu # RZ/G2{L,LC}
      - const: renesas,rzg2l-tsu

  reg:
    maxItems: 1

  clocks:
    maxItems: 1

  power-domains:
    maxItems: 1

  resets:
    maxItems: 1

  "#thermal-sensor-cells":
    const: 1

required:
  - compatible
  - reg
  - clocks
  - power-domains
  - resets
  - "#thermal-sensor-cells"

additionalProperties: false

examples:
  - |
    #include <dt-bindings/clock/r9a07g044-cpg.h>

    tsu: thermal@10059400 {
            compatible = "renesas,r9a07g044-tsu",
                         "renesas,rzg2l-tsu";
            reg = <0x10059400 0x400>;
            clocks = <&cpg CPG_MOD R9A07G044_TSU_PCLK>;
            resets = <&cpg R9A07G044_TSU_PRESETN>;
            power-domains = <&cpg>;
            #thermal-sensor-cells = <1>;
    };

    thermal-zones {
            cpu-thermal {
                    polling-delay-passive = <250>;
                    polling-delay = <1000>;
                    thermal-sensors = <&tsu 0>;

                    trips {
                            sensor_crit: sensor-crit {
                                    temperature = <125000>;
                                    hysteresis = <1000>;
                                    type = "critical";
                            };
                    };
            };
    };
+9 −0
Original line number Diff line number Diff line
@@ -354,6 +354,15 @@ config RCAR_GEN3_THERMAL
	  Enable this to plug the R-Car Gen3 or RZ/G2 thermal sensor driver into
	  the Linux thermal framework.

config RZG2L_THERMAL
	tristate "Renesas RZ/G2L thermal driver"
	depends on ARCH_RENESAS || COMPILE_TEST
	depends on HAS_IOMEM
	depends on OF
	help
	  Enable this to plug the RZ/G2L thermal sensor driver into the Linux
	  thermal framework.

config KIRKWOOD_THERMAL
	tristate "Temperature sensor on Marvell Kirkwood SoCs"
	depends on MACH_KIRKWOOD || COMPILE_TEST
+1 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ obj-$(CONFIG_SUN8I_THERMAL) += sun8i_thermal.o
obj-$(CONFIG_ROCKCHIP_THERMAL)	+= rockchip_thermal.o
obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
obj-$(CONFIG_RCAR_GEN3_THERMAL)	+= rcar_gen3_thermal.o
obj-$(CONFIG_RZG2L_THERMAL)	+= rzg2l_thermal.o
obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
obj-y				+= samsung/
obj-$(CONFIG_DOVE_THERMAL)  	+= dove_thermal.o
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#define TPS			0x4
#define TRITSR			0x20	/* TMU immediate temp */

#define TER_ADC_PD		BIT(30)
#define TER_EN			BIT(31)
#define TRITSR_TEMP0_VAL_MASK	0xff
#define TRITSR_TEMP1_VAL_MASK	0xff0000
@@ -113,6 +114,8 @@ static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)

	val = readl_relaxed(tmu->base + TER);
	val = enable ? (val | TER_EN) : (val & ~TER_EN);
	if (tmu->socdata->version == TMU_VER2)
		val = enable ? (val & ~TER_ADC_PD) : (val | TER_ADC_PD);
	writel_relaxed(val, tmu->base + TER);
}

+91 −54
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/thermal.h>
#include <linux/nvmem-consumer.h>
#include <linux/pm_runtime.h>

#define REG_SET		0x4
#define REG_CLR		0x8
@@ -194,6 +195,7 @@ static struct thermal_soc_data thermal_imx7d_data = {
};

struct imx_thermal_data {
	struct device *dev;
	struct cpufreq_policy *policy;
	struct thermal_zone_device *tz;
	struct thermal_cooling_device *cdev;
@@ -252,44 +254,15 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
	const struct thermal_soc_data *soc_data = data->socdata;
	struct regmap *map = data->tempmon;
	unsigned int n_meas;
	bool wait, run_measurement;
	u32 val;
	int ret;

	run_measurement = !data->irq_enabled;
	if (!run_measurement) {
		/* Check if a measurement is currently in progress */
		regmap_read(map, soc_data->temp_data, &val);
		wait = !(val & soc_data->temp_valid_mask);
	} else {
		/*
		 * Every time we measure the temperature, we will power on the
		 * temperature sensor, enable measurements, take a reading,
		 * disable measurements, power off the temperature sensor.
		 */
		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
			    soc_data->power_down_mask);
		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
			    soc_data->measure_temp_mask);

		wait = true;
	}

	/*
	 * According to the temp sensor designers, it may require up to ~17us
	 * to complete a measurement.
	 */
	if (wait)
		usleep_range(20, 50);
	ret = pm_runtime_resume_and_get(data->dev);
	if (ret < 0)
		return ret;

	regmap_read(map, soc_data->temp_data, &val);

	if (run_measurement) {
		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
			     soc_data->measure_temp_mask);
		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
			     soc_data->power_down_mask);
	}

	if ((val & soc_data->temp_valid_mask) == 0) {
		dev_dbg(&tz->device, "temp measurement never finished\n");
		return -EAGAIN;
@@ -328,6 +301,8 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
		enable_irq(data->irq);
	}

	pm_runtime_put(data->dev);

	return 0;
}

@@ -335,24 +310,16 @@ static int imx_change_mode(struct thermal_zone_device *tz,
			   enum thermal_device_mode mode)
{
	struct imx_thermal_data *data = tz->devdata;
	struct regmap *map = data->tempmon;
	const struct thermal_soc_data *soc_data = data->socdata;

	if (mode == THERMAL_DEVICE_ENABLED) {
		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
			     soc_data->power_down_mask);
		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
			     soc_data->measure_temp_mask);
		pm_runtime_get(data->dev);

		if (!data->irq_enabled) {
			data->irq_enabled = true;
			enable_irq(data->irq);
		}
	} else {
		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
			     soc_data->measure_temp_mask);
		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
			     soc_data->power_down_mask);
		pm_runtime_put(data->dev);

		if (data->irq_enabled) {
			disable_irq(data->irq);
@@ -393,6 +360,11 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
			     int temp)
{
	struct imx_thermal_data *data = tz->devdata;
	int ret;

	ret = pm_runtime_resume_and_get(data->dev);
	if (ret < 0)
		return ret;

	/* do not allow changing critical threshold */
	if (trip == IMX_TRIP_CRITICAL)
@@ -406,6 +378,8 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,

	imx_set_alarm_temp(data, temp);

	pm_runtime_put(data->dev);

	return 0;
}

@@ -681,6 +655,8 @@ static int imx_thermal_probe(struct platform_device *pdev)
	if (!data)
		return -ENOMEM;

	data->dev = &pdev->dev;

	map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
	if (IS_ERR(map)) {
		ret = PTR_ERR(map);
@@ -800,6 +776,16 @@ static int imx_thermal_probe(struct platform_device *pdev)
		     data->socdata->power_down_mask);
	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
		     data->socdata->measure_temp_mask);
	/* After power up, we need a delay before first access can be done. */
	usleep_range(20, 50);

	/* the core was configured and enabled just before */
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(data->dev);

	ret = pm_runtime_resume_and_get(data->dev);
	if (ret < 0)
		goto disable_runtime_pm;

	data->irq_enabled = true;
	ret = thermal_zone_device_enable(data->tz);
@@ -814,10 +800,15 @@ static int imx_thermal_probe(struct platform_device *pdev)
		goto thermal_zone_unregister;
	}

	pm_runtime_put(data->dev);

	return 0;

thermal_zone_unregister:
	thermal_zone_device_unregister(data->tz);
disable_runtime_pm:
	pm_runtime_put_noidle(data->dev);
	pm_runtime_disable(data->dev);
clk_disable:
	clk_disable_unprepare(data->thermal_clk);
legacy_cleanup:
@@ -829,13 +820,9 @@ static int imx_thermal_probe(struct platform_device *pdev)
static int imx_thermal_remove(struct platform_device *pdev)
{
	struct imx_thermal_data *data = platform_get_drvdata(pdev);
	struct regmap *map = data->tempmon;

	/* Disable measurements */
	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
		     data->socdata->power_down_mask);
	if (!IS_ERR(data->thermal_clk))
		clk_disable_unprepare(data->thermal_clk);
	pm_runtime_put_noidle(data->dev);
	pm_runtime_disable(data->dev);

	thermal_zone_device_unregister(data->tz);
	imx_thermal_unregister_legacy_cooling(data);
@@ -858,29 +845,79 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
	ret = thermal_zone_device_disable(data->tz);
	if (ret)
		return ret;

	return pm_runtime_force_suspend(data->dev);
}

static int __maybe_unused imx_thermal_resume(struct device *dev)
{
	struct imx_thermal_data *data = dev_get_drvdata(dev);
	int ret;

	ret = pm_runtime_force_resume(data->dev);
	if (ret)
		return ret;
	/* Enabled thermal sensor after resume */
	return thermal_zone_device_enable(data->tz);
}

static int __maybe_unused imx_thermal_runtime_suspend(struct device *dev)
{
	struct imx_thermal_data *data = dev_get_drvdata(dev);
	const struct thermal_soc_data *socdata = data->socdata;
	struct regmap *map = data->tempmon;
	int ret;

	ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR,
			   socdata->measure_temp_mask);
	if (ret)
		return ret;

	ret = regmap_write(map, socdata->sensor_ctrl + REG_SET,
			   socdata->power_down_mask);
	if (ret)
		return ret;

	clk_disable_unprepare(data->thermal_clk);

	return 0;
}

static int __maybe_unused imx_thermal_resume(struct device *dev)
static int __maybe_unused imx_thermal_runtime_resume(struct device *dev)
{
	struct imx_thermal_data *data = dev_get_drvdata(dev);
	const struct thermal_soc_data *socdata = data->socdata;
	struct regmap *map = data->tempmon;
	int ret;

	ret = clk_prepare_enable(data->thermal_clk);
	if (ret)
		return ret;
	/* Enabled thermal sensor after resume */
	ret = thermal_zone_device_enable(data->tz);

	ret = regmap_write(map, socdata->sensor_ctrl + REG_CLR,
			   socdata->power_down_mask);
	if (ret)
		return ret;

	ret = regmap_write(map, socdata->sensor_ctrl + REG_SET,
			   socdata->measure_temp_mask);
	if (ret)
		return ret;

	/*
	 * According to the temp sensor designers, it may require up to ~17us
	 * to complete a measurement.
	 */
	usleep_range(20, 50);

	return 0;
}

static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
			 imx_thermal_suspend, imx_thermal_resume);
static const struct dev_pm_ops imx_thermal_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(imx_thermal_suspend, imx_thermal_resume)
	SET_RUNTIME_PM_OPS(imx_thermal_runtime_suspend,
			   imx_thermal_runtime_resume, NULL)
};

static struct platform_driver imx_thermal = {
	.driver = {
Loading