linux-renesas-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] Add Thermal support for RZ/G2L
@ 2021-11-16 15:17 Biju Das
  2021-11-16 15:17 ` [PATCH 1/5] clk: renesas: r9a07g044: Add TSU clock and reset entries Biju Das
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Biju Das @ 2021-11-16 15:17 UTC (permalink / raw)
  To: Rob Herring, Philipp Zabel
  Cc: Biju Das, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, devicetree, Geert Uytterhoeven,
	Chris Paterson, Biju Das, Prabhakar Mahadev Lad,
	linux-renesas-soc

RZ/G2L SoC incorporates a thermal sensor unit (TSU) that measures
the temperature inside the LSI.
 
The thermal sensor in this unit measures temperatures in the range from
−40°C to 125°C with an accuracy of ±3°C. The TSU repeats measurement at
20-µs intervals, and automatically updates the results of measurement.

The TSU has no external pins as well as no interrupts.

This patch series aims to add TSU driver support for RZ/G2L SoC.

Biju Das (5):
  clk: renesas: r9a07g044: Add TSU clock and reset entries
  dt-bindings: thermal: Document Renesas RZ/G2L TSU
  thermal/drivers: Add TSU driver for RZ/G2L
  arm64: dts: renesas: r9a07g044: Add TSU node
  arm64: dts: renesas: r9a07g044: Create thermal zone to support IPA

 .../bindings/thermal/rzg2l-thermal.yaml       |  76 ++++++
 arch/arm64/boot/dts/renesas/r9a07g044.dtsi    |  42 +++
 drivers/clk/renesas/r9a07g044-cpg.c           |   3 +
 drivers/thermal/Kconfig                       |   9 +
 drivers/thermal/Makefile                      |   1 +
 drivers/thermal/rzg2l_thermal.c               | 239 ++++++++++++++++++
 6 files changed, 370 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/rzg2l-thermal.yaml
 create mode 100644 drivers/thermal/rzg2l_thermal.c

-- 
2.17.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/5] clk: renesas: r9a07g044: Add TSU clock and reset entries
  2021-11-16 15:17 [PATCH 0/5] Add Thermal support for RZ/G2L Biju Das
@ 2021-11-16 15:17 ` Biju Das
  2021-11-16 15:17 ` [PATCH 2/5] dt-bindings: thermal: Document Renesas RZ/G2L TSU Biju Das
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Biju Das @ 2021-11-16 15:17 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: Biju Das, Geert Uytterhoeven, linux-renesas-soc, linux-clk,
	Chris Paterson, Biju Das, Prabhakar Mahadev Lad

Add TSU clock and reset entries to CPG driver.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 drivers/clk/renesas/r9a07g044-cpg.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
index 02c4d0b9d7e5..5d8fcbc5752c 100644
--- a/drivers/clk/renesas/r9a07g044-cpg.c
+++ b/drivers/clk/renesas/r9a07g044-cpg.c
@@ -254,6 +254,8 @@ static struct rzg2l_mod_clk r9a07g044_mod_clks[] = {
 				0x5a8, 0),
 	DEF_MOD("adc_pclk",	R9A07G044_ADC_PCLK, R9A07G044_CLK_P0,
 				0x5a8, 1),
+	DEF_MOD("tsu_pclk",	R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU,
+				0x5ac, 0),
 };
 
 static struct rzg2l_reset r9a07g044_resets[] = {
@@ -299,6 +301,7 @@ static struct rzg2l_reset r9a07g044_resets[] = {
 	DEF_RST(R9A07G044_GPIO_SPARE_RESETN, 0x898, 2),
 	DEF_RST(R9A07G044_ADC_PRESETN, 0x8a8, 0),
 	DEF_RST(R9A07G044_ADC_ADRST_N, 0x8a8, 1),
+	DEF_RST(R9A07G044_TSU_PRESETN, 0x8ac, 0),
 };
 
 static const unsigned int r9a07g044_crit_mod_clks[] __initconst = {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/5] dt-bindings: thermal: Document Renesas RZ/G2L TSU
  2021-11-16 15:17 [PATCH 0/5] Add Thermal support for RZ/G2L Biju Das
  2021-11-16 15:17 ` [PATCH 1/5] clk: renesas: r9a07g044: Add TSU clock and reset entries Biju Das
@ 2021-11-16 15:17 ` Biju Das
  2021-11-16 15:17 ` [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L Biju Das
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Biju Das @ 2021-11-16 15:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: Biju Das, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, devicetree, Geert Uytterhoeven,
	Chris Paterson, Biju Das, Prabhakar Mahadev Lad,
	linux-renesas-soc

Document the Thermal Sensor Unit(TSU) in the RZ/G2L SoC.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 .../bindings/thermal/rzg2l-thermal.yaml       | 76 +++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/rzg2l-thermal.yaml

diff --git a/Documentation/devicetree/bindings/thermal/rzg2l-thermal.yaml b/Documentation/devicetree/bindings/thermal/rzg2l-thermal.yaml
new file mode 100644
index 000000000000..ccab9511a042
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/rzg2l-thermal.yaml
@@ -0,0 +1,76 @@
+# 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";
+                            };
+                    };
+            };
+    };
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
  2021-11-16 15:17 [PATCH 0/5] Add Thermal support for RZ/G2L Biju Das
  2021-11-16 15:17 ` [PATCH 1/5] clk: renesas: r9a07g044: Add TSU clock and reset entries Biju Das
  2021-11-16 15:17 ` [PATCH 2/5] dt-bindings: thermal: Document Renesas RZ/G2L TSU Biju Das
@ 2021-11-16 15:17 ` Biju Das
  2021-11-17  8:40   ` Niklas Söderlund
  2021-11-16 15:17 ` [PATCH 4/5] arm64: dts: renesas: r9a07g044: Add TSU node Biju Das
  2021-11-16 15:17 ` [PATCH 5/5] arm64: dts: renesas: r9a07g044: Create thermal zone to support IPA Biju Das
  4 siblings, 1 reply; 12+ messages in thread
From: Biju Das @ 2021-11-16 15:17 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Biju Das, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Add Thermal Sensor Unit(TSU) driver for RZ/G2L SoC.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 drivers/thermal/Kconfig         |   9 ++
 drivers/thermal/Makefile        |   1 +
 drivers/thermal/rzg2l_thermal.c | 239 ++++++++++++++++++++++++++++++++
 3 files changed, 249 insertions(+)
 create mode 100644 drivers/thermal/rzg2l_thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index d7f44deab5b1..e37691e0bf20 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -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
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 82fc3e616e54..f0c36a1530d5 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -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
diff --git a/drivers/thermal/rzg2l_thermal.c b/drivers/thermal/rzg2l_thermal.c
new file mode 100644
index 000000000000..e551355cd4f6
--- /dev/null
+++ b/drivers/thermal/rzg2l_thermal.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G2L TSU Thermal Sensor Driver
+ *
+ * Copyright (C) 2021 Renesas Electronics Corporation
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/thermal.h>
+
+#include "thermal_hwmon.h"
+
+#define CTEMP_MASK	0xFFF
+
+/* default calibration values, if FUSE values are missing */
+#define SW_CALIB0_VAL	3148
+#define SW_CALIB1_VAL	503
+
+/* Register offsets */
+#define TSU_SM		0x00
+#define TSU_ST		0x04
+#define TSU_SAD		0x0C
+#define TSU_SS		0x10
+
+#define OTPTSUTRIM_REG(n)	(0x18 + ((n) * 0x4))
+
+/* Sensor Mode Register(TSU_SM) */
+#define TSU_SM_EN_TS		BIT(0)
+#define TSU_SM_ADC_EN_TS	BIT(1)
+#define TSU_SM_NORMAL_MODE	(TSU_SM_EN_TS | TSU_SM_ADC_EN_TS)
+
+/* TSU_ST bits */
+#define TSU_ST_START		BIT(0)
+
+#define TSU_SS_CONV_RUNNING	BIT(0)
+
+#define TS_CODE_AVE_SCALE(x)	((x) * 1000000)
+#define MCELSIUS(temp)		((temp) * 1000)
+#define TS_CODE_CAP_TIMES	8	/* Capture  times */
+#define RZG2L_THERMAL_GRAN	500	/* milli Celsius */
+
+#define RZG2L_TSU_SS_TIMEOUT_US	1000
+
+struct rzg2l_thermal_priv {
+	struct device *dev;
+	void __iomem *base;
+	struct thermal_zone_device *zone;
+	struct reset_control *rstc;
+	u32 calib0, calib1;
+};
+
+static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv *priv, u32 reg)
+{
+	return ioread32(priv->base + reg);
+}
+
+static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv *priv, u32 reg,
+				       u32 data)
+{
+	iowrite32(data, priv->base + reg);
+}
+
+static int rzg2l_thermal_round(int temp)
+{
+	int result, round_offs;
+
+	round_offs = temp >= 0 ? RZG2L_THERMAL_GRAN / 2 : -RZG2L_THERMAL_GRAN / 2;
+	result = (temp + round_offs) / RZG2L_THERMAL_GRAN;
+
+	return result * RZG2L_THERMAL_GRAN;
+}
+
+static int rzg2l_thermal_get_temp(void *devdata, int *temp)
+{
+	struct rzg2l_thermal_priv *priv = devdata;
+	u32 result, dsensor, ts_code_ave;
+	int val, i;
+
+	result = 0;
+	/*  Read the ADC value 8 times with an interval of 20 microsecs */
+	for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
+		result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK;
+		usleep_range(20, 30);
+	}
+
+	/* Calculate the average value */
+	ts_code_ave = result / TS_CODE_CAP_TIMES;
+
+	/* Curvature correction */
+	dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
+		(TS_CODE_AVE_SCALE(1) + (ts_code_ave * 13));
+
+	/* Temperature calculation */
+	val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
+		(priv->calib0 - priv->calib1))) - MCELSIUS(40);
+
+	/* Round value to device granularity setting */
+	*temp = rzg2l_thermal_round(val);
+
+	return 0;
+}
+
+static const struct thermal_zone_of_device_ops rzg2l_tz_of_ops = {
+	.get_temp = rzg2l_thermal_get_temp,
+};
+
+static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv)
+{
+	u32 reg_val;
+
+	rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
+	rzg2l_thermal_write(priv, TSU_ST, 0);
+
+	/* Before setting START bit, Wait for 60 µs */
+	usleep_range(60, 80);
+
+	reg_val = rzg2l_thermal_read(priv, TSU_ST);
+	reg_val |= TSU_ST_START;
+	rzg2l_thermal_write(priv, TSU_ST, reg_val);
+
+	return readl_poll_timeout(priv->base + TSU_SS, reg_val,
+				  reg_val == TSU_SS_CONV_RUNNING, 50,
+				  RZG2L_TSU_SS_TIMEOUT_US);
+}
+
+static int rzg2l_thermal_remove(struct platform_device *pdev)
+{
+	struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
+
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	reset_control_assert(priv->rstc);
+
+	return 0;
+}
+
+static void rzg2l_hwmon_action(void *data)
+{
+	struct thermal_zone_device *zone = data;
+
+	thermal_remove_hwmon_sysfs(zone);
+}
+
+static int rzg2l_thermal_probe(struct platform_device *pdev)
+{
+	struct thermal_zone_device *zone;
+	struct rzg2l_thermal_priv *priv;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->dev = dev;
+	priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+	if (IS_ERR(priv->rstc))
+		return dev_err_probe(dev, PTR_ERR(priv->rstc),
+				     "failed to get cpg reset");
+
+	reset_control_deassert(priv->rstc);
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	priv->calib0 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0));
+	if (!priv->calib0)
+		priv->calib0 = SW_CALIB0_VAL;
+
+	priv->calib1 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(1));
+	if (!priv->calib1)
+		priv->calib1 = SW_CALIB1_VAL;
+
+	platform_set_drvdata(pdev, priv);
+	ret = rzg2l_thermal_init(priv);
+	if (ret) {
+		dev_err(dev, "Failed to start TSU");
+		goto error_unregister;
+	}
+
+	zone = devm_thermal_zone_of_sensor_register(dev, 0, priv,
+						    &rzg2l_tz_of_ops);
+	if (IS_ERR(zone)) {
+		dev_err(dev, "Can't register thermal zone");
+		ret = PTR_ERR(zone);
+		goto error_unregister;
+	}
+
+	priv->zone = zone;
+	priv->zone->tzp->no_hwmon = false;
+	ret = thermal_add_hwmon_sysfs(priv->zone);
+	if (ret)
+		goto error_unregister;
+
+	ret = devm_add_action_or_reset(dev, rzg2l_hwmon_action, zone);
+	if (ret)
+		goto error_unregister;
+
+	dev_info(dev, "TSU probed with %s caliberation values",
+		 rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ?  "hw" : "sw");
+
+	return 0;
+
+error_unregister:
+	rzg2l_thermal_remove(pdev);
+
+	return ret;
+}
+
+static const struct of_device_id rzg2l_thermal_dt_ids[] = {
+	{ .compatible = "renesas,rzg2l-tsu", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzg2l_thermal_dt_ids);
+
+static struct platform_driver rzg2l_thermal_driver = {
+	.driver = {
+		.name = "rzg2l_thermal",
+		.of_match_table = rzg2l_thermal_dt_ids,
+	},
+	.probe = rzg2l_thermal_probe,
+	.remove = rzg2l_thermal_remove,
+};
+module_platform_driver(rzg2l_thermal_driver);
+
+MODULE_DESCRIPTION("Renesas RZ/G2L TSU Thermal Sensor Driver");
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/5] arm64: dts: renesas: r9a07g044: Add TSU node
  2021-11-16 15:17 [PATCH 0/5] Add Thermal support for RZ/G2L Biju Das
                   ` (2 preceding siblings ...)
  2021-11-16 15:17 ` [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L Biju Das
@ 2021-11-16 15:17 ` Biju Das
  2021-11-16 15:17 ` [PATCH 5/5] arm64: dts: renesas: r9a07g044: Create thermal zone to support IPA Biju Das
  4 siblings, 0 replies; 12+ messages in thread
From: Biju Das @ 2021-11-16 15:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: Biju Das, Geert Uytterhoeven, Magnus Damm, linux-renesas-soc,
	devicetree, Chris Paterson, Biju Das, Prabhakar Mahadev Lad

Add TSU node to RZ/G2L SoC DTSI.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 arch/arm64/boot/dts/renesas/r9a07g044.dtsi | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
index 15b3576df114..b2d593ba07ad 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
@@ -490,6 +490,16 @@
 			};
 		};
 
+		tsu: thermal@10059400 {
+			compatible = "renesas,r9a07g044-tsu",
+				     "renesas,rzg2l-tsu";
+			reg = <0 0x10059400 0 0x400>;
+			clocks = <&cpg CPG_MOD R9A07G044_TSU_PCLK>;
+			resets = <&cpg R9A07G044_TSU_PRESETN>;
+			power-domains = <&cpg>;
+			#thermal-sensor-cells = <1>;
+		};
+
 		sbc: spi@10060000 {
 			compatible = "renesas,r9a07g044-rpc-if",
 				     "renesas,rzg2l-rpc-if";
@@ -775,6 +785,22 @@
 		};
 	};
 
+	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";
+				};
+			};
+		};
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts-extended = <&gic GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/5] arm64: dts: renesas: r9a07g044: Create thermal zone to support IPA
  2021-11-16 15:17 [PATCH 0/5] Add Thermal support for RZ/G2L Biju Das
                   ` (3 preceding siblings ...)
  2021-11-16 15:17 ` [PATCH 4/5] arm64: dts: renesas: r9a07g044: Add TSU node Biju Das
@ 2021-11-16 15:17 ` Biju Das
  4 siblings, 0 replies; 12+ messages in thread
From: Biju Das @ 2021-11-16 15:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: Biju Das, Geert Uytterhoeven, Magnus Damm, linux-renesas-soc,
	devicetree, Chris Paterson, Biju Das, Prabhakar Mahadev Lad

Setup a thermal zone driven by SoC temperature sensor.
Create passive trip points and bind them to CPUFreq cooling
device that supports power extension.

Based on the work done by Dien Pham <dien.pham.ry@renesas.com>
and others for r8a77990 SoC.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
This patch depend upon [1]
[1] https://patchwork.kernel.org/project/linux-renesas-soc/list/?series=579123
---
 arch/arm64/boot/dts/renesas/r9a07g044.dtsi | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
index b2d593ba07ad..d78fb375a622 100644
--- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi
@@ -87,6 +87,7 @@
 			compatible = "arm,cortex-a55";
 			reg = <0>;
 			device_type = "cpu";
+			#cooling-cells = <2>;
 			next-level-cache = <&L3_CA55>;
 			enable-method = "psci";
 			clocks = <&cpg CPG_CORE R9A07G044_CLK_I>;
@@ -790,6 +791,15 @@
 			polling-delay-passive = <250>;
 			polling-delay = <1000>;
 			thermal-sensors = <&tsu 0>;
+			sustainable-power = <717>;
+
+			cooling-maps {
+				map0 {
+					trip = <&target>;
+					cooling-device = <&cpu0 0 2>;
+					contribution = <1024>;
+				};
+			};
 
 			trips {
 				sensor_crit: sensor-crit {
@@ -797,6 +807,12 @@
 					hysteresis = <1000>;
 					type = "critical";
 				};
+
+				target: trip-point {
+					temperature = <100000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
 			};
 		};
 	};
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
  2021-11-16 15:17 ` [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L Biju Das
@ 2021-11-17  8:40   ` Niklas Söderlund
  2021-11-17  8:55     ` Biju Das
  2021-11-20 17:21     ` Biju Das
  0 siblings, 2 replies; 12+ messages in thread
From: Niklas Söderlund @ 2021-11-17  8:40 UTC (permalink / raw)
  To: Biju Das
  Cc: Philipp Zabel, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

HI Biju,

Thanks for your work.

On 2021-11-16 15:17:48 +0000, Biju Das wrote:
> Add Thermal Sensor Unit(TSU) driver for RZ/G2L SoC.
> 
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
>  drivers/thermal/Kconfig         |   9 ++
>  drivers/thermal/Makefile        |   1 +
>  drivers/thermal/rzg2l_thermal.c | 239 ++++++++++++++++++++++++++++++++
>  3 files changed, 249 insertions(+)
>  create mode 100644 drivers/thermal/rzg2l_thermal.c
> 
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index d7f44deab5b1..e37691e0bf20 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -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
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 82fc3e616e54..f0c36a1530d5 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -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
> diff --git a/drivers/thermal/rzg2l_thermal.c b/drivers/thermal/rzg2l_thermal.c
> new file mode 100644
> index 000000000000..e551355cd4f6
> --- /dev/null
> +++ b/drivers/thermal/rzg2l_thermal.c
> @@ -0,0 +1,239 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Renesas RZ/G2L TSU Thermal Sensor Driver
> + *
> + * Copyright (C) 2021 Renesas Electronics Corporation
> + */
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/reset.h>
> +#include <linux/thermal.h>
> +
> +#include "thermal_hwmon.h"
> +
> +#define CTEMP_MASK	0xFFF
> +
> +/* default calibration values, if FUSE values are missing */
> +#define SW_CALIB0_VAL	3148
> +#define SW_CALIB1_VAL	503
> +
> +/* Register offsets */
> +#define TSU_SM		0x00
> +#define TSU_ST		0x04
> +#define TSU_SAD		0x0C
> +#define TSU_SS		0x10
> +
> +#define OTPTSUTRIM_REG(n)	(0x18 + ((n) * 0x4))
> +
> +/* Sensor Mode Register(TSU_SM) */
> +#define TSU_SM_EN_TS		BIT(0)
> +#define TSU_SM_ADC_EN_TS	BIT(1)
> +#define TSU_SM_NORMAL_MODE	(TSU_SM_EN_TS | TSU_SM_ADC_EN_TS)
> +
> +/* TSU_ST bits */
> +#define TSU_ST_START		BIT(0)
> +
> +#define TSU_SS_CONV_RUNNING	BIT(0)
> +
> +#define TS_CODE_AVE_SCALE(x)	((x) * 1000000)
> +#define MCELSIUS(temp)		((temp) * 1000)
> +#define TS_CODE_CAP_TIMES	8	/* Capture  times */
> +#define RZG2L_THERMAL_GRAN	500	/* milli Celsius */
> +
> +#define RZG2L_TSU_SS_TIMEOUT_US	1000
> +
> +struct rzg2l_thermal_priv {
> +	struct device *dev;
> +	void __iomem *base;
> +	struct thermal_zone_device *zone;
> +	struct reset_control *rstc;
> +	u32 calib0, calib1;
> +};
> +
> +static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv *priv, u32 reg)
> +{
> +	return ioread32(priv->base + reg);
> +}
> +
> +static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv *priv, u32 reg,
> +				       u32 data)
> +{
> +	iowrite32(data, priv->base + reg);
> +}
> +
> +static int rzg2l_thermal_round(int temp)
> +{
> +	int result, round_offs;
> +
> +	round_offs = temp >= 0 ? RZG2L_THERMAL_GRAN / 2 : -RZG2L_THERMAL_GRAN / 2;
> +	result = (temp + round_offs) / RZG2L_THERMAL_GRAN;
> +
> +	return result * RZG2L_THERMAL_GRAN;
> +}
> +
> +static int rzg2l_thermal_get_temp(void *devdata, int *temp)
> +{
> +	struct rzg2l_thermal_priv *priv = devdata;
> +	u32 result, dsensor, ts_code_ave;
> +	int val, i;
> +
> +	result = 0;
> +	/*  Read the ADC value 8 times with an interval of 20 microsecs */
> +	for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
> +		result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK;
> +		usleep_range(20, 30);
> +	}
> +
> +	/* Calculate the average value */
> +	ts_code_ave = result / TS_CODE_CAP_TIMES;
> +
> +	/* Curvature correction */
> +	dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
> +		(TS_CODE_AVE_SCALE(1) + (ts_code_ave * 13));
> +
> +	/* Temperature calculation */
> +	val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
> +		(priv->calib0 - priv->calib1))) - MCELSIUS(40);
> +
> +	/* Round value to device granularity setting */
> +	*temp = rzg2l_thermal_round(val);
> +
> +	return 0;
> +}
> +
> +static const struct thermal_zone_of_device_ops rzg2l_tz_of_ops = {
> +	.get_temp = rzg2l_thermal_get_temp,
> +};
> +
> +static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv)
> +{
> +	u32 reg_val;
> +
> +	rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
> +	rzg2l_thermal_write(priv, TSU_ST, 0);
> +
> +	/* Before setting START bit, Wait for 60 µs */
> +	usleep_range(60, 80);
> +
> +	reg_val = rzg2l_thermal_read(priv, TSU_ST);
> +	reg_val |= TSU_ST_START;
> +	rzg2l_thermal_write(priv, TSU_ST, reg_val);
> +
> +	return readl_poll_timeout(priv->base + TSU_SS, reg_val,
> +				  reg_val == TSU_SS_CONV_RUNNING, 50,
> +				  RZG2L_TSU_SS_TIMEOUT_US);
> +}
> +
> +static int rzg2l_thermal_remove(struct platform_device *pdev)
> +{
> +	struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
> +
> +	pm_runtime_put(&pdev->dev);
> +	pm_runtime_disable(&pdev->dev);
> +	reset_control_assert(priv->rstc);
> +
> +	return 0;
> +}
> +
> +static void rzg2l_hwmon_action(void *data)
> +{
> +	struct thermal_zone_device *zone = data;
> +
> +	thermal_remove_hwmon_sysfs(zone);
> +}
> +
> +static int rzg2l_thermal_probe(struct platform_device *pdev)
> +{
> +	struct thermal_zone_device *zone;
> +	struct rzg2l_thermal_priv *priv;
> +	struct device *dev = &pdev->dev;
> +	int ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	priv->dev = dev;
> +	priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> +	if (IS_ERR(priv->rstc))
> +		return dev_err_probe(dev, PTR_ERR(priv->rstc),
> +				     "failed to get cpg reset");
> +
> +	reset_control_deassert(priv->rstc);
> +
> +	pm_runtime_enable(dev);
> +	pm_runtime_get_sync(dev);
> +
> +	priv->calib0 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0));
> +	if (!priv->calib0)
> +		priv->calib0 = SW_CALIB0_VAL;
> +
> +	priv->calib1 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(1));
> +	if (!priv->calib1)
> +		priv->calib1 = SW_CALIB1_VAL;
> +
> +	platform_set_drvdata(pdev, priv);
> +	ret = rzg2l_thermal_init(priv);
> +	if (ret) {
> +		dev_err(dev, "Failed to start TSU");
> +		goto error_unregister;
> +	}
> +
> +	zone = devm_thermal_zone_of_sensor_register(dev, 0, priv,
> +						    &rzg2l_tz_of_ops);
> +	if (IS_ERR(zone)) {
> +		dev_err(dev, "Can't register thermal zone");
> +		ret = PTR_ERR(zone);
> +		goto error_unregister;
> +	}
> +
> +	priv->zone = zone;
> +	priv->zone->tzp->no_hwmon = false;
> +	ret = thermal_add_hwmon_sysfs(priv->zone);
> +	if (ret)
> +		goto error_unregister;
> +
> +	ret = devm_add_action_or_reset(dev, rzg2l_hwmon_action, zone);
> +	if (ret)
> +		goto error_unregister;

This driver only uses one zone would it be worth considering calling 
thermal_remove_hwmon_sysfs() directly from rzg2l_thermal_remove()?  
Compare then Renesas Gen2 and Gen3 drivers. Where Gen3 uses devres to 
make it easier to deal with more then one zone wile Gen2 calls it 
directly from its remove function.

> +
> +	dev_info(dev, "TSU probed with %s caliberation values",
> +		 rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ?  "hw" : "sw");
> +
> +	return 0;
> +
> +error_unregister:
> +	rzg2l_thermal_remove(pdev);
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id rzg2l_thermal_dt_ids[] = {
> +	{ .compatible = "renesas,rzg2l-tsu", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, rzg2l_thermal_dt_ids);
> +
> +static struct platform_driver rzg2l_thermal_driver = {
> +	.driver = {
> +		.name = "rzg2l_thermal",
> +		.of_match_table = rzg2l_thermal_dt_ids,
> +	},
> +	.probe = rzg2l_thermal_probe,
> +	.remove = rzg2l_thermal_remove,
> +};
> +module_platform_driver(rzg2l_thermal_driver);
> +
> +MODULE_DESCRIPTION("Renesas RZ/G2L TSU Thermal Sensor Driver");
> +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.17.1
> 

-- 
Kind Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
  2021-11-17  8:40   ` Niklas Söderlund
@ 2021-11-17  8:55     ` Biju Das
  2021-11-17 14:12       ` Niklas Söderlund
  2021-11-20 17:21     ` Biju Das
  1 sibling, 1 reply; 12+ messages in thread
From: Biju Das @ 2021-11-17  8:55 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Philipp Zabel, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Hi Niklas,

Thanks for the feedback.

> Subject: Re: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
> 
> HI Biju,
> 
> Thanks for your work.
> 
> On 2021-11-16 15:17:48 +0000, Biju Das wrote:
> > Add Thermal Sensor Unit(TSU) driver for RZ/G2L SoC.
> >
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > ---
> >  drivers/thermal/Kconfig         |   9 ++
> >  drivers/thermal/Makefile        |   1 +
> >  drivers/thermal/rzg2l_thermal.c | 239
> > ++++++++++++++++++++++++++++++++
> >  3 files changed, 249 insertions(+)
> >  create mode 100644 drivers/thermal/rzg2l_thermal.c
> >
> > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index
> > d7f44deab5b1..e37691e0bf20 100644
> > --- a/drivers/thermal/Kconfig
> > +++ b/drivers/thermal/Kconfig
> > @@ -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 diff --git
> > a/drivers/thermal/Makefile b/drivers/thermal/Makefile index
> > 82fc3e616e54..f0c36a1530d5 100644
> > --- a/drivers/thermal/Makefile
> > +++ b/drivers/thermal/Makefile
> > @@ -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
> > diff --git a/drivers/thermal/rzg2l_thermal.c
> > b/drivers/thermal/rzg2l_thermal.c new file mode 100644 index
> > 000000000000..e551355cd4f6
> > --- /dev/null
> > +++ b/drivers/thermal/rzg2l_thermal.c
> > @@ -0,0 +1,239 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Renesas RZ/G2L TSU Thermal Sensor Driver
> > + *
> > + * Copyright (C) 2021 Renesas Electronics Corporation  */ #include
> > +<linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include
> > +<linux/iopoll.h> #include <linux/module.h> #include
> > +<linux/of_device.h> #include <linux/platform_device.h> #include
> > +<linux/pm_runtime.h> #include <linux/reset.h> #include
> > +<linux/thermal.h>
> > +
> > +#include "thermal_hwmon.h"
> > +
> > +#define CTEMP_MASK	0xFFF
> > +
> > +/* default calibration values, if FUSE values are missing */
> > +#define SW_CALIB0_VAL	3148
> > +#define SW_CALIB1_VAL	503
> > +
> > +/* Register offsets */
> > +#define TSU_SM		0x00
> > +#define TSU_ST		0x04
> > +#define TSU_SAD		0x0C
> > +#define TSU_SS		0x10
> > +
> > +#define OTPTSUTRIM_REG(n)	(0x18 + ((n) * 0x4))
> > +
> > +/* Sensor Mode Register(TSU_SM) */
> > +#define TSU_SM_EN_TS		BIT(0)
> > +#define TSU_SM_ADC_EN_TS	BIT(1)
> > +#define TSU_SM_NORMAL_MODE	(TSU_SM_EN_TS | TSU_SM_ADC_EN_TS)
> > +
> > +/* TSU_ST bits */
> > +#define TSU_ST_START		BIT(0)
> > +
> > +#define TSU_SS_CONV_RUNNING	BIT(0)
> > +
> > +#define TS_CODE_AVE_SCALE(x)	((x) * 1000000)
> > +#define MCELSIUS(temp)		((temp) * 1000)
> > +#define TS_CODE_CAP_TIMES	8	/* Capture  times */
> > +#define RZG2L_THERMAL_GRAN	500	/* milli Celsius */
> > +
> > +#define RZG2L_TSU_SS_TIMEOUT_US	1000
> > +
> > +struct rzg2l_thermal_priv {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +	struct thermal_zone_device *zone;
> > +	struct reset_control *rstc;
> > +	u32 calib0, calib1;
> > +};
> > +
> > +static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv *priv,
> > +u32 reg) {
> > +	return ioread32(priv->base + reg);
> > +}
> > +
> > +static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv *priv,
> u32 reg,
> > +				       u32 data)
> > +{
> > +	iowrite32(data, priv->base + reg);
> > +}
> > +
> > +static int rzg2l_thermal_round(int temp) {
> > +	int result, round_offs;
> > +
> > +	round_offs = temp >= 0 ? RZG2L_THERMAL_GRAN / 2 : -
> RZG2L_THERMAL_GRAN / 2;
> > +	result = (temp + round_offs) / RZG2L_THERMAL_GRAN;
> > +
> > +	return result * RZG2L_THERMAL_GRAN;
> > +}
> > +
> > +static int rzg2l_thermal_get_temp(void *devdata, int *temp) {
> > +	struct rzg2l_thermal_priv *priv = devdata;
> > +	u32 result, dsensor, ts_code_ave;
> > +	int val, i;
> > +
> > +	result = 0;
> > +	/*  Read the ADC value 8 times with an interval of 20 microsecs */
> > +	for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
> > +		result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK;
> > +		usleep_range(20, 30);
> > +	}
> > +
> > +	/* Calculate the average value */
> > +	ts_code_ave = result / TS_CODE_CAP_TIMES;
> > +
> > +	/* Curvature correction */
> > +	dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
> > +		(TS_CODE_AVE_SCALE(1) + (ts_code_ave * 13));
> > +
> > +	/* Temperature calculation */
> > +	val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
> > +		(priv->calib0 - priv->calib1))) - MCELSIUS(40);
> > +
> > +	/* Round value to device granularity setting */
> > +	*temp = rzg2l_thermal_round(val);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct thermal_zone_of_device_ops rzg2l_tz_of_ops = {
> > +	.get_temp = rzg2l_thermal_get_temp,
> > +};
> > +
> > +static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv) {
> > +	u32 reg_val;
> > +
> > +	rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
> > +	rzg2l_thermal_write(priv, TSU_ST, 0);
> > +
> > +	/* Before setting START bit, Wait for 60 µs */
> > +	usleep_range(60, 80);
> > +
> > +	reg_val = rzg2l_thermal_read(priv, TSU_ST);
> > +	reg_val |= TSU_ST_START;
> > +	rzg2l_thermal_write(priv, TSU_ST, reg_val);
> > +
> > +	return readl_poll_timeout(priv->base + TSU_SS, reg_val,
> > +				  reg_val == TSU_SS_CONV_RUNNING, 50,
> > +				  RZG2L_TSU_SS_TIMEOUT_US);
> > +}
> > +
> > +static int rzg2l_thermal_remove(struct platform_device *pdev) {
> > +	struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
> > +
> > +	pm_runtime_put(&pdev->dev);
> > +	pm_runtime_disable(&pdev->dev);
> > +	reset_control_assert(priv->rstc);
> > +
> > +	return 0;
> > +}
> > +
> > +static void rzg2l_hwmon_action(void *data) {
> > +	struct thermal_zone_device *zone = data;
> > +
> > +	thermal_remove_hwmon_sysfs(zone);
> > +}
> > +
> > +static int rzg2l_thermal_probe(struct platform_device *pdev) {
> > +	struct thermal_zone_device *zone;
> > +	struct rzg2l_thermal_priv *priv;
> > +	struct device *dev = &pdev->dev;
> > +	int ret;
> > +
> > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->base = devm_platform_ioremap_resource(pdev, 0);
> > +	if (IS_ERR(priv->base))
> > +		return PTR_ERR(priv->base);
> > +
> > +	priv->dev = dev;
> > +	priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> > +	if (IS_ERR(priv->rstc))
> > +		return dev_err_probe(dev, PTR_ERR(priv->rstc),
> > +				     "failed to get cpg reset");
> > +
> > +	reset_control_deassert(priv->rstc);
> > +
> > +	pm_runtime_enable(dev);
> > +	pm_runtime_get_sync(dev);
> > +
> > +	priv->calib0 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0));
> > +	if (!priv->calib0)
> > +		priv->calib0 = SW_CALIB0_VAL;
> > +
> > +	priv->calib1 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(1));
> > +	if (!priv->calib1)
> > +		priv->calib1 = SW_CALIB1_VAL;
> > +
> > +	platform_set_drvdata(pdev, priv);
> > +	ret = rzg2l_thermal_init(priv);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to start TSU");
> > +		goto error_unregister;
> > +	}
> > +
> > +	zone = devm_thermal_zone_of_sensor_register(dev, 0, priv,
> > +						    &rzg2l_tz_of_ops);
> > +	if (IS_ERR(zone)) {
> > +		dev_err(dev, "Can't register thermal zone");
> > +		ret = PTR_ERR(zone);
> > +		goto error_unregister;
> > +	}
> > +
> > +	priv->zone = zone;
> > +	priv->zone->tzp->no_hwmon = false;
> > +	ret = thermal_add_hwmon_sysfs(priv->zone);
> > +	if (ret)
> > +		goto error_unregister;
> > +
> > +	ret = devm_add_action_or_reset(dev, rzg2l_hwmon_action, zone);
> > +	if (ret)
> > +		goto error_unregister;
> 
> This driver only uses one zone would it be worth considering calling
> thermal_remove_hwmon_sysfs() directly from rzg2l_thermal_remove()?
> Compare then Renesas Gen2 and Gen3 drivers. Where Gen3 uses devres to make
> it easier to deal with more then one zone wile Gen2 calls it directly from
> its remove function.

OK, will use Gen2 style as it has 1 sensor on the next version.

Another separate question, I have in my mind is how do we test trip points
for negative temperature? 
This TSU doesn't have any interrupts and
we need to use polling, The range is -40 to 125 degrees.
If it goes below -40, I guess we need to shutdown the system.
On device tree we normally specify only positive temperature.
How do we handle this?

Regards,
Biju



> 
> > +
> > +	dev_info(dev, "TSU probed with %s caliberation values",
> > +		 rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ?  "hw" : "sw");
> > +
> > +	return 0;
> > +
> > +error_unregister:
> > +	rzg2l_thermal_remove(pdev);
> > +
> > +	return ret;
> > +}
> > +
> > +static const struct of_device_id rzg2l_thermal_dt_ids[] = {
> > +	{ .compatible = "renesas,rzg2l-tsu", },
> > +	{ /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, rzg2l_thermal_dt_ids);
> > +
> > +static struct platform_driver rzg2l_thermal_driver = {
> > +	.driver = {
> > +		.name = "rzg2l_thermal",
> > +		.of_match_table = rzg2l_thermal_dt_ids,
> > +	},
> > +	.probe = rzg2l_thermal_probe,
> > +	.remove = rzg2l_thermal_remove,
> > +};
> > +module_platform_driver(rzg2l_thermal_driver);
> > +
> > +MODULE_DESCRIPTION("Renesas RZ/G2L TSU Thermal Sensor Driver");
> > +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
> > +MODULE_LICENSE("GPL v2");
> > --
> > 2.17.1
> >
> 
> --
> Kind Regards,
> Niklas Söderlund

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
  2021-11-17  8:55     ` Biju Das
@ 2021-11-17 14:12       ` Niklas Söderlund
  2021-11-17 14:27         ` Biju Das
  0 siblings, 1 reply; 12+ messages in thread
From: Niklas Söderlund @ 2021-11-17 14:12 UTC (permalink / raw)
  To: Biju Das
  Cc: Philipp Zabel, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Hi Biju,

On 2021-11-17 08:55:15 +0000, Biju Das wrote:
> Another separate question, I have in my mind is how do we test trip 
> points
> for negative temperature? 

I think this is two different questions.

> This TSU doesn't have any interrupts and
> we need to use polling, The range is -40 to 125 degrees.

For tripping a trip-point polling or interrupt works. The only 
difference is in the worst case polling will detect that i past the 
trop-point <pollig-delay> later. For testing triggering of trippoints 
(high or low) I don't think we need to care about this.

To actually test it we have two options.

1. Put the SoC in a good freezer and, alternately open an office branch 
   in the arctics :-)

2. Use the thermal emulation framework.

    echo $temprature_in_mcelcius > /sys/class/thermal/$zone/emul_temp

  If the temperature set using this is above/below a trippoint the 
  associated action will happen. A good demo of this is to try on Gen3 
  where you can observe the cooling device state changes as the 
  different trip points are triggerd in:

      /sys/class/thermal/$cool/cur_state

  And of course if you set a temperature that trips the critical point 
  the system will shutdown.

> If it goes below -40, I guess we need to shutdown the system.
> On device tree we normally specify only positive temperature.
> How do we handle this?

I have not tested it but would it not be as simple as adding a second 
critical trippoint at -40 ?

-- 
Kind Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
  2021-11-17 14:12       ` Niklas Söderlund
@ 2021-11-17 14:27         ` Biju Das
  0 siblings, 0 replies; 12+ messages in thread
From: Biju Das @ 2021-11-17 14:27 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Philipp Zabel, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Hi Niklas,

> Subject: Re: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
> 
> Hi Biju,
> 
> On 2021-11-17 08:55:15 +0000, Biju Das wrote:
> > Another separate question, I have in my mind is how do we test trip
> > points for negative temperature?
> 
> I think this is two different questions.
> 
> > This TSU doesn't have any interrupts and we need to use polling, The
> > range is -40 to 125 degrees.
> 
> For tripping a trip-point polling or interrupt works. The only difference
> is in the worst case polling will detect that i past the trop-point
> <pollig-delay> later. For testing triggering of trippoints (high or low) I
> don't think we need to care about this.
> 
> To actually test it we have two options.
> 
> 1. Put the SoC in a good freezer and, alternately open an office branch
>    in the arctics :-)
> 
> 2. Use the thermal emulation framework.
> 
>     echo $temprature_in_mcelcius > /sys/class/thermal/$zone/emul_temp
> 
>   If the temperature set using this is above/below a trippoint the
>   associated action will happen. A good demo of this is to try on Gen3
>   where you can observe the cooling device state changes as the
>   different trip points are triggerd in:
> 
>       /sys/class/thermal/$cool/cur_state
> 
>   And of course if you set a temperature that trips the critical point
>   the system will shutdown.

This I have tested with thermal IPA (writable_trips and thermal statistics) and
I can see the cooling state transitions around trip temperature.

> 
> > If it goes below -40, I guess we need to shutdown the system.
> > On device tree we normally specify only positive temperature.
> > How do we handle this?
> 
> I have not tested it but would it not be as simple as adding a second
> critical trippoint at -40 ?

OK. This can happen only from a cold start(where the temp is below -40).
So at this point, I am not sure whether we should not rely on TSU values
as the value from TSU may not linear or it is beyond SoC characteristics
And so we should do a shutdown.

Regards,
Biju

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
  2021-11-17  8:40   ` Niklas Söderlund
  2021-11-17  8:55     ` Biju Das
@ 2021-11-20 17:21     ` Biju Das
  2021-11-20 19:39       ` Biju Das
  1 sibling, 1 reply; 12+ messages in thread
From: Biju Das @ 2021-11-20 17:21 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Philipp Zabel, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc

Hi Niklas,

> -----Original Message-----
> From: Niklas Söderlund <niklas.soderlund@ragnatech.se>
> Sent: 17 November 2021 08:41
> To: Biju Das <biju.das.jz@bp.renesas.com>
> Cc: Philipp Zabel <p.zabel@pengutronix.de>; Rafael J. Wysocki
> <rafael@kernel.org>; Daniel Lezcano <daniel.lezcano@linaro.org>; Amit
> Kucheria <amitk@kernel.org>; Zhang Rui <rui.zhang@intel.com>; linux-
> pm@vger.kernel.org; Geert Uytterhoeven <geert+renesas@glider.be>; Chris
> Paterson <Chris.Paterson2@renesas.com>; Biju Das
> <biju.das@bp.renesas.com>; Prabhakar Mahadev Lad <prabhakar.mahadev-
> lad.rj@bp.renesas.com>; linux-renesas-soc@vger.kernel.org
> Subject: Re: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
> 
> HI Biju,
> 
> Thanks for your work.
> 
> On 2021-11-16 15:17:48 +0000, Biju Das wrote:
> > Add Thermal Sensor Unit(TSU) driver for RZ/G2L SoC.
> >
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > ---
> >  drivers/thermal/Kconfig         |   9 ++
> >  drivers/thermal/Makefile        |   1 +
> >  drivers/thermal/rzg2l_thermal.c | 239
> > ++++++++++++++++++++++++++++++++
> >  3 files changed, 249 insertions(+)
> >  create mode 100644 drivers/thermal/rzg2l_thermal.c
> >
> > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index
> > d7f44deab5b1..e37691e0bf20 100644
> > --- a/drivers/thermal/Kconfig
> > +++ b/drivers/thermal/Kconfig
> > @@ -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 diff --git
> > a/drivers/thermal/Makefile b/drivers/thermal/Makefile index
> > 82fc3e616e54..f0c36a1530d5 100644
> > --- a/drivers/thermal/Makefile
> > +++ b/drivers/thermal/Makefile
> > @@ -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
> > diff --git a/drivers/thermal/rzg2l_thermal.c
> > b/drivers/thermal/rzg2l_thermal.c new file mode 100644 index
> > 000000000000..e551355cd4f6
> > --- /dev/null
> > +++ b/drivers/thermal/rzg2l_thermal.c
> > @@ -0,0 +1,239 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Renesas RZ/G2L TSU Thermal Sensor Driver
> > + *
> > + * Copyright (C) 2021 Renesas Electronics Corporation  */ #include
> > +<linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include
> > +<linux/iopoll.h> #include <linux/module.h> #include
> > +<linux/of_device.h> #include <linux/platform_device.h> #include
> > +<linux/pm_runtime.h> #include <linux/reset.h> #include
> > +<linux/thermal.h>
> > +
> > +#include "thermal_hwmon.h"
> > +
> > +#define CTEMP_MASK	0xFFF
> > +
> > +/* default calibration values, if FUSE values are missing */
> > +#define SW_CALIB0_VAL	3148
> > +#define SW_CALIB1_VAL	503
> > +
> > +/* Register offsets */
> > +#define TSU_SM		0x00
> > +#define TSU_ST		0x04
> > +#define TSU_SAD		0x0C
> > +#define TSU_SS		0x10
> > +
> > +#define OTPTSUTRIM_REG(n)	(0x18 + ((n) * 0x4))
> > +
> > +/* Sensor Mode Register(TSU_SM) */
> > +#define TSU_SM_EN_TS		BIT(0)
> > +#define TSU_SM_ADC_EN_TS	BIT(1)
> > +#define TSU_SM_NORMAL_MODE	(TSU_SM_EN_TS | TSU_SM_ADC_EN_TS)
> > +
> > +/* TSU_ST bits */
> > +#define TSU_ST_START		BIT(0)
> > +
> > +#define TSU_SS_CONV_RUNNING	BIT(0)
> > +
> > +#define TS_CODE_AVE_SCALE(x)	((x) * 1000000)
> > +#define MCELSIUS(temp)		((temp) * 1000)
> > +#define TS_CODE_CAP_TIMES	8	/* Capture  times */
> > +#define RZG2L_THERMAL_GRAN	500	/* milli Celsius */
> > +
> > +#define RZG2L_TSU_SS_TIMEOUT_US	1000
> > +
> > +struct rzg2l_thermal_priv {
> > +	struct device *dev;
> > +	void __iomem *base;
> > +	struct thermal_zone_device *zone;
> > +	struct reset_control *rstc;
> > +	u32 calib0, calib1;
> > +};
> > +
> > +static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv *priv,
> > +u32 reg) {
> > +	return ioread32(priv->base + reg);
> > +}
> > +
> > +static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv *priv,
> u32 reg,
> > +				       u32 data)
> > +{
> > +	iowrite32(data, priv->base + reg);
> > +}
> > +
> > +static int rzg2l_thermal_round(int temp) {
> > +	int result, round_offs;
> > +
> > +	round_offs = temp >= 0 ? RZG2L_THERMAL_GRAN / 2 : -
> RZG2L_THERMAL_GRAN / 2;
> > +	result = (temp + round_offs) / RZG2L_THERMAL_GRAN;
> > +
> > +	return result * RZG2L_THERMAL_GRAN;
> > +}
> > +
> > +static int rzg2l_thermal_get_temp(void *devdata, int *temp) {
> > +	struct rzg2l_thermal_priv *priv = devdata;
> > +	u32 result, dsensor, ts_code_ave;
> > +	int val, i;
> > +
> > +	result = 0;
> > +	/*  Read the ADC value 8 times with an interval of 20 microsecs */
> > +	for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
> > +		result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK;
> > +		usleep_range(20, 30);
> > +	}
> > +
> > +	/* Calculate the average value */
> > +	ts_code_ave = result / TS_CODE_CAP_TIMES;
> > +
> > +	/* Curvature correction */
> > +	dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
> > +		(TS_CODE_AVE_SCALE(1) + (ts_code_ave * 13));
> > +
> > +	/* Temperature calculation */
> > +	val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
> > +		(priv->calib0 - priv->calib1))) - MCELSIUS(40);
> > +
> > +	/* Round value to device granularity setting */
> > +	*temp = rzg2l_thermal_round(val);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct thermal_zone_of_device_ops rzg2l_tz_of_ops = {
> > +	.get_temp = rzg2l_thermal_get_temp,
> > +};
> > +
> > +static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv) {
> > +	u32 reg_val;
> > +
> > +	rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
> > +	rzg2l_thermal_write(priv, TSU_ST, 0);
> > +
> > +	/* Before setting START bit, Wait for 60 µs */
> > +	usleep_range(60, 80);
> > +
> > +	reg_val = rzg2l_thermal_read(priv, TSU_ST);
> > +	reg_val |= TSU_ST_START;
> > +	rzg2l_thermal_write(priv, TSU_ST, reg_val);
> > +
> > +	return readl_poll_timeout(priv->base + TSU_SS, reg_val,
> > +				  reg_val == TSU_SS_CONV_RUNNING, 50,
> > +				  RZG2L_TSU_SS_TIMEOUT_US);
> > +}
> > +
> > +static int rzg2l_thermal_remove(struct platform_device *pdev) {
> > +	struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
> > +
> > +	pm_runtime_put(&pdev->dev);
> > +	pm_runtime_disable(&pdev->dev);
> > +	reset_control_assert(priv->rstc);
> > +
> > +	return 0;
> > +}
> > +
> > +static void rzg2l_hwmon_action(void *data) {
> > +	struct thermal_zone_device *zone = data;
> > +
> > +	thermal_remove_hwmon_sysfs(zone);
> > +}
> > +
> > +static int rzg2l_thermal_probe(struct platform_device *pdev) {
> > +	struct thermal_zone_device *zone;
> > +	struct rzg2l_thermal_priv *priv;
> > +	struct device *dev = &pdev->dev;
> > +	int ret;
> > +
> > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->base = devm_platform_ioremap_resource(pdev, 0);
> > +	if (IS_ERR(priv->base))
> > +		return PTR_ERR(priv->base);
> > +
> > +	priv->dev = dev;
> > +	priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> > +	if (IS_ERR(priv->rstc))
> > +		return dev_err_probe(dev, PTR_ERR(priv->rstc),
> > +				     "failed to get cpg reset");
> > +
> > +	reset_control_deassert(priv->rstc);
> > +
> > +	pm_runtime_enable(dev);
> > +	pm_runtime_get_sync(dev);
> > +
> > +	priv->calib0 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0));
> > +	if (!priv->calib0)
> > +		priv->calib0 = SW_CALIB0_VAL;
> > +
> > +	priv->calib1 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(1));
> > +	if (!priv->calib1)
> > +		priv->calib1 = SW_CALIB1_VAL;
> > +
> > +	platform_set_drvdata(pdev, priv);
> > +	ret = rzg2l_thermal_init(priv);
> > +	if (ret) {
> > +		dev_err(dev, "Failed to start TSU");
> > +		goto error_unregister;
> > +	}
> > +
> > +	zone = devm_thermal_zone_of_sensor_register(dev, 0, priv,
> > +						    &rzg2l_tz_of_ops);
> > +	if (IS_ERR(zone)) {
> > +		dev_err(dev, "Can't register thermal zone");
> > +		ret = PTR_ERR(zone);
> > +		goto error_unregister;
> > +	}
> > +
> > +	priv->zone = zone;
> > +	priv->zone->tzp->no_hwmon = false;
> > +	ret = thermal_add_hwmon_sysfs(priv->zone);
> > +	if (ret)
> > +		goto error_unregister;
> > +
> > +	ret = devm_add_action_or_reset(dev, rzg2l_hwmon_action, zone);
> > +	if (ret)
> > +		goto error_unregister;
> 

> This driver only uses one zone would it be worth considering calling
> thermal_remove_hwmon_sysfs() directly from rzg2l_thermal_remove()?

In fact this is correct.

> Compare then Renesas Gen2 and Gen3 drivers. Where Gen3 uses devres to make
> it easier to deal with more then one zone wile Gen2 calls it directly from
> its remove function.

If you see rcar-thermal.c there are unregister path (goto error_unregister)
Where we call thermal_remove_hwmon_sysfs without adding hwmon_sys

See [1]
[1] https://elixir.bootlin.com/linux/latest/source/drivers/thermal/rcar_thermal.c#L561

For any error upto L561, any unregister blindly calls thermal_remove_hwmon_sysfs,
Which is wrong.

Looks like we need a fix on Gen2 drivers.

Please let me know, if I am missing anything here.

Regards,
biju

> 
> > +
> > +	dev_info(dev, "TSU probed with %s caliberation values",
> > +		 rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ?  "hw" : "sw");
> > +
> > +	return 0;
> > +
> > +error_unregister:
> > +	rzg2l_thermal_remove(pdev);
> > +
> > +	return ret;
> > +}
> > +
> > +static const struct of_device_id rzg2l_thermal_dt_ids[] = {
> > +	{ .compatible = "renesas,rzg2l-tsu", },
> > +	{ /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, rzg2l_thermal_dt_ids);
> > +
> > +static struct platform_driver rzg2l_thermal_driver = {
> > +	.driver = {
> > +		.name = "rzg2l_thermal",
> > +		.of_match_table = rzg2l_thermal_dt_ids,
> > +	},
> > +	.probe = rzg2l_thermal_probe,
> > +	.remove = rzg2l_thermal_remove,
> > +};
> > +module_platform_driver(rzg2l_thermal_driver);
> > +
> > +MODULE_DESCRIPTION("Renesas RZ/G2L TSU Thermal Sensor Driver");
> > +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
> > +MODULE_LICENSE("GPL v2");
> > --
> > 2.17.1
> >
> 
> --
> Kind Regards,
> Niklas Söderlund

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
  2021-11-20 17:21     ` Biju Das
@ 2021-11-20 19:39       ` Biju Das
  0 siblings, 0 replies; 12+ messages in thread
From: Biju Das @ 2021-11-20 19:39 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Philipp Zabel, Rafael J. Wysocki, Daniel Lezcano, Amit Kucheria,
	Zhang Rui, linux-pm, Geert Uytterhoeven, Chris Paterson,
	Biju Das, Prabhakar Mahadev Lad, linux-renesas-soc



> -----Original Message-----
> From: Biju Das
> Sent: 20 November 2021 17:21
> To: 'Niklas Söderlund' <niklas.soderlund@ragnatech.se>
> Cc: Philipp Zabel <p.zabel@pengutronix.de>; Rafael J. Wysocki
> <rafael@kernel.org>; Daniel Lezcano <daniel.lezcano@linaro.org>; Amit
> Kucheria <amitk@kernel.org>; Zhang Rui <rui.zhang@intel.com>; linux-
> pm@vger.kernel.org; Geert Uytterhoeven <geert+renesas@glider.be>; Chris
> Paterson <Chris.Paterson2@renesas.com>; Biju Das
> <biju.das@bp.renesas.com>; Prabhakar Mahadev Lad <prabhakar.mahadev-
> lad.rj@bp.renesas.com>; linux-renesas-soc@vger.kernel.org
> Subject: RE: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
> 
> Hi Niklas,
> 
> > -----Original Message-----
> > From: Niklas Söderlund <niklas.soderlund@ragnatech.se>
> > Sent: 17 November 2021 08:41
> > To: Biju Das <biju.das.jz@bp.renesas.com>
> > Cc: Philipp Zabel <p.zabel@pengutronix.de>; Rafael J. Wysocki
> > <rafael@kernel.org>; Daniel Lezcano <daniel.lezcano@linaro.org>; Amit
> > Kucheria <amitk@kernel.org>; Zhang Rui <rui.zhang@intel.com>; linux-
> > pm@vger.kernel.org; Geert Uytterhoeven <geert+renesas@glider.be>;
> > Chris Paterson <Chris.Paterson2@renesas.com>; Biju Das
> > <biju.das@bp.renesas.com>; Prabhakar Mahadev Lad <prabhakar.mahadev-
> > lad.rj@bp.renesas.com>; linux-renesas-soc@vger.kernel.org
> > Subject: Re: [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L
> >
> > HI Biju,
> >
> > Thanks for your work.
> >
> > On 2021-11-16 15:17:48 +0000, Biju Das wrote:
> > > Add Thermal Sensor Unit(TSU) driver for RZ/G2L SoC.
> > >
> > > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > > Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > > ---
> > >  drivers/thermal/Kconfig         |   9 ++
> > >  drivers/thermal/Makefile        |   1 +
> > >  drivers/thermal/rzg2l_thermal.c | 239
> > > ++++++++++++++++++++++++++++++++
> > >  3 files changed, 249 insertions(+)
> > >  create mode 100644 drivers/thermal/rzg2l_thermal.c
> > >
> > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index
> > > d7f44deab5b1..e37691e0bf20 100644
> > > --- a/drivers/thermal/Kconfig
> > > +++ b/drivers/thermal/Kconfig
> > > @@ -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 diff --git
> > > a/drivers/thermal/Makefile b/drivers/thermal/Makefile index
> > > 82fc3e616e54..f0c36a1530d5 100644
> > > --- a/drivers/thermal/Makefile
> > > +++ b/drivers/thermal/Makefile
> > > @@ -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
> > > diff --git a/drivers/thermal/rzg2l_thermal.c
> > > b/drivers/thermal/rzg2l_thermal.c new file mode 100644 index
> > > 000000000000..e551355cd4f6
> > > --- /dev/null
> > > +++ b/drivers/thermal/rzg2l_thermal.c
> > > @@ -0,0 +1,239 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * Renesas RZ/G2L TSU Thermal Sensor Driver
> > > + *
> > > + * Copyright (C) 2021 Renesas Electronics Corporation  */ #include
> > > +<linux/delay.h> #include <linux/err.h> #include <linux/io.h>
> > > +#include <linux/iopoll.h> #include <linux/module.h> #include
> > > +<linux/of_device.h> #include <linux/platform_device.h> #include
> > > +<linux/pm_runtime.h> #include <linux/reset.h> #include
> > > +<linux/thermal.h>
> > > +
> > > +#include "thermal_hwmon.h"
> > > +
> > > +#define CTEMP_MASK	0xFFF
> > > +
> > > +/* default calibration values, if FUSE values are missing */
> > > +#define SW_CALIB0_VAL	3148
> > > +#define SW_CALIB1_VAL	503
> > > +
> > > +/* Register offsets */
> > > +#define TSU_SM		0x00
> > > +#define TSU_ST		0x04
> > > +#define TSU_SAD		0x0C
> > > +#define TSU_SS		0x10
> > > +
> > > +#define OTPTSUTRIM_REG(n)	(0x18 + ((n) * 0x4))
> > > +
> > > +/* Sensor Mode Register(TSU_SM) */
> > > +#define TSU_SM_EN_TS		BIT(0)
> > > +#define TSU_SM_ADC_EN_TS	BIT(1)
> > > +#define TSU_SM_NORMAL_MODE	(TSU_SM_EN_TS | TSU_SM_ADC_EN_TS)
> > > +
> > > +/* TSU_ST bits */
> > > +#define TSU_ST_START		BIT(0)
> > > +
> > > +#define TSU_SS_CONV_RUNNING	BIT(0)
> > > +
> > > +#define TS_CODE_AVE_SCALE(x)	((x) * 1000000)
> > > +#define MCELSIUS(temp)		((temp) * 1000)
> > > +#define TS_CODE_CAP_TIMES	8	/* Capture  times */
> > > +#define RZG2L_THERMAL_GRAN	500	/* milli Celsius */
> > > +
> > > +#define RZG2L_TSU_SS_TIMEOUT_US	1000
> > > +
> > > +struct rzg2l_thermal_priv {
> > > +	struct device *dev;
> > > +	void __iomem *base;
> > > +	struct thermal_zone_device *zone;
> > > +	struct reset_control *rstc;
> > > +	u32 calib0, calib1;
> > > +};
> > > +
> > > +static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv
> > > +*priv,
> > > +u32 reg) {
> > > +	return ioread32(priv->base + reg); }
> > > +
> > > +static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv
> > > +*priv,
> > u32 reg,
> > > +				       u32 data)
> > > +{
> > > +	iowrite32(data, priv->base + reg); }
> > > +
> > > +static int rzg2l_thermal_round(int temp) {
> > > +	int result, round_offs;
> > > +
> > > +	round_offs = temp >= 0 ? RZG2L_THERMAL_GRAN / 2 : -
> > RZG2L_THERMAL_GRAN / 2;
> > > +	result = (temp + round_offs) / RZG2L_THERMAL_GRAN;
> > > +
> > > +	return result * RZG2L_THERMAL_GRAN; }
> > > +
> > > +static int rzg2l_thermal_get_temp(void *devdata, int *temp) {
> > > +	struct rzg2l_thermal_priv *priv = devdata;
> > > +	u32 result, dsensor, ts_code_ave;
> > > +	int val, i;
> > > +
> > > +	result = 0;
> > > +	/*  Read the ADC value 8 times with an interval of 20 microsecs */
> > > +	for (i = 0; i < TS_CODE_CAP_TIMES ; i++) {
> > > +		result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK;
> > > +		usleep_range(20, 30);
> > > +	}
> > > +
> > > +	/* Calculate the average value */
> > > +	ts_code_ave = result / TS_CODE_CAP_TIMES;
> > > +
> > > +	/* Curvature correction */
> > > +	dsensor = TS_CODE_AVE_SCALE(ts_code_ave) /
> > > +		(TS_CODE_AVE_SCALE(1) + (ts_code_ave * 13));
> > > +
> > > +	/* Temperature calculation */
> > > +	val = ((dsensor - priv->calib1) * (MCELSIUS(165) /
> > > +		(priv->calib0 - priv->calib1))) - MCELSIUS(40);
> > > +
> > > +	/* Round value to device granularity setting */
> > > +	*temp = rzg2l_thermal_round(val);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct thermal_zone_of_device_ops rzg2l_tz_of_ops = {
> > > +	.get_temp = rzg2l_thermal_get_temp, };
> > > +
> > > +static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv) {
> > > +	u32 reg_val;
> > > +
> > > +	rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE);
> > > +	rzg2l_thermal_write(priv, TSU_ST, 0);
> > > +
> > > +	/* Before setting START bit, Wait for 60 µs */
> > > +	usleep_range(60, 80);
> > > +
> > > +	reg_val = rzg2l_thermal_read(priv, TSU_ST);
> > > +	reg_val |= TSU_ST_START;
> > > +	rzg2l_thermal_write(priv, TSU_ST, reg_val);
> > > +
> > > +	return readl_poll_timeout(priv->base + TSU_SS, reg_val,
> > > +				  reg_val == TSU_SS_CONV_RUNNING, 50,
> > > +				  RZG2L_TSU_SS_TIMEOUT_US);
> > > +}
> > > +
> > > +static int rzg2l_thermal_remove(struct platform_device *pdev) {
> > > +	struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
> > > +
> > > +	pm_runtime_put(&pdev->dev);
> > > +	pm_runtime_disable(&pdev->dev);
> > > +	reset_control_assert(priv->rstc);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void rzg2l_hwmon_action(void *data) {
> > > +	struct thermal_zone_device *zone = data;
> > > +
> > > +	thermal_remove_hwmon_sysfs(zone);
> > > +}
> > > +
> > > +static int rzg2l_thermal_probe(struct platform_device *pdev) {
> > > +	struct thermal_zone_device *zone;
> > > +	struct rzg2l_thermal_priv *priv;
> > > +	struct device *dev = &pdev->dev;
> > > +	int ret;
> > > +
> > > +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > +	if (!priv)
> > > +		return -ENOMEM;
> > > +
> > > +	priv->base = devm_platform_ioremap_resource(pdev, 0);
> > > +	if (IS_ERR(priv->base))
> > > +		return PTR_ERR(priv->base);
> > > +
> > > +	priv->dev = dev;
> > > +	priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> > > +	if (IS_ERR(priv->rstc))
> > > +		return dev_err_probe(dev, PTR_ERR(priv->rstc),
> > > +				     "failed to get cpg reset");
> > > +
> > > +	reset_control_deassert(priv->rstc);
> > > +
> > > +	pm_runtime_enable(dev);
> > > +	pm_runtime_get_sync(dev);
> > > +
> > > +	priv->calib0 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0));
> > > +	if (!priv->calib0)
> > > +		priv->calib0 = SW_CALIB0_VAL;
> > > +
> > > +	priv->calib1 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(1));
> > > +	if (!priv->calib1)
> > > +		priv->calib1 = SW_CALIB1_VAL;
> > > +
> > > +	platform_set_drvdata(pdev, priv);
> > > +	ret = rzg2l_thermal_init(priv);
> > > +	if (ret) {
> > > +		dev_err(dev, "Failed to start TSU");
> > > +		goto error_unregister;
> > > +	}
> > > +
> > > +	zone = devm_thermal_zone_of_sensor_register(dev, 0, priv,
> > > +						    &rzg2l_tz_of_ops);
> > > +	if (IS_ERR(zone)) {
> > > +		dev_err(dev, "Can't register thermal zone");
> > > +		ret = PTR_ERR(zone);
> > > +		goto error_unregister;
> > > +	}
> > > +
> > > +	priv->zone = zone;
> > > +	priv->zone->tzp->no_hwmon = false;
> > > +	ret = thermal_add_hwmon_sysfs(priv->zone);
> > > +	if (ret)
> > > +		goto error_unregister;
> > > +
> > > +	ret = devm_add_action_or_reset(dev, rzg2l_hwmon_action, zone);
> > > +	if (ret)
> > > +		goto error_unregister;
> >
> 
> > This driver only uses one zone would it be worth considering calling
> > thermal_remove_hwmon_sysfs() directly from rzg2l_thermal_remove()?
> 
> In fact this is correct.
> 
> > Compare then Renesas Gen2 and Gen3 drivers. Where Gen3 uses devres to
> > make it easier to deal with more then one zone wile Gen2 calls it
> > directly from its remove function.
> 
> If you see rcar-thermal.c there are unregister path (goto
> error_unregister) Where we call thermal_remove_hwmon_sysfs without adding
> hwmon_sys
> 
> See [1]
> [1]
> https://elixir.bootlin.com/linux/latest/source/drivers/thermal/rcar_therma
> l.c#L561
> 
> For any error upto L561, any unregister blindly calls
> thermal_remove_hwmon_sysfs, Which is wrong.

Oops, I am wrong, remove function is taking care.
Sorry for the noise.

Regards,
Biju

> 
> >
> > > +
> > > +	dev_info(dev, "TSU probed with %s caliberation values",
> > > +		 rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ?  "hw" : "sw");
> > > +
> > > +	return 0;
> > > +
> > > +error_unregister:
> > > +	rzg2l_thermal_remove(pdev);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static const struct of_device_id rzg2l_thermal_dt_ids[] = {
> > > +	{ .compatible = "renesas,rzg2l-tsu", },
> > > +	{ /* sentinel */ }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, rzg2l_thermal_dt_ids);
> > > +
> > > +static struct platform_driver rzg2l_thermal_driver = {
> > > +	.driver = {
> > > +		.name = "rzg2l_thermal",
> > > +		.of_match_table = rzg2l_thermal_dt_ids,
> > > +	},
> > > +	.probe = rzg2l_thermal_probe,
> > > +	.remove = rzg2l_thermal_remove,
> > > +};
> > > +module_platform_driver(rzg2l_thermal_driver);
> > > +
> > > +MODULE_DESCRIPTION("Renesas RZ/G2L TSU Thermal Sensor Driver");
> > > +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
> > > +MODULE_LICENSE("GPL v2");
> > > --
> > > 2.17.1
> > >
> >
> > --
> > Kind Regards,
> > Niklas Söderlund

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-11-20 19:39 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-16 15:17 [PATCH 0/5] Add Thermal support for RZ/G2L Biju Das
2021-11-16 15:17 ` [PATCH 1/5] clk: renesas: r9a07g044: Add TSU clock and reset entries Biju Das
2021-11-16 15:17 ` [PATCH 2/5] dt-bindings: thermal: Document Renesas RZ/G2L TSU Biju Das
2021-11-16 15:17 ` [PATCH 3/5] thermal/drivers: Add TSU driver for RZ/G2L Biju Das
2021-11-17  8:40   ` Niklas Söderlund
2021-11-17  8:55     ` Biju Das
2021-11-17 14:12       ` Niklas Söderlund
2021-11-17 14:27         ` Biju Das
2021-11-20 17:21     ` Biju Das
2021-11-20 19:39       ` Biju Das
2021-11-16 15:17 ` [PATCH 4/5] arm64: dts: renesas: r9a07g044: Add TSU node Biju Das
2021-11-16 15:17 ` [PATCH 5/5] arm64: dts: renesas: r9a07g044: Create thermal zone to support IPA Biju Das

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).