Skip to contentSkip to conversation

Add support for ipq8064 tsens

PATCH Superseded Ansuel Smith 2 participants 10 messages Jul 15, 2020 – Jul 16, 2020

Subsystems (6)

v3 of 15 Superseded Latest is v15 →

lore
Share & tools
lore
#0 lore raw

v3 cover Add support for ipq8064 tsens

Ipq8064 SoCs tsens driver is based on 8960 tsens driver. This patchset expand the 8960 unused driver with interrupt support and set_trip point. Ipq8064 needs to be registered as a gcc child as the tsens regs on this platform are shared with the controller.

v3:
* Change driver to register as child instead of use phandle v2:
* Fix dt-bindings problems

Ansuel Smith (7):
ipq806x: gcc: add support for child probe
drivers: thermal: tsens: try load regmap from parent for 8960
drivers: thermal: tsens: add ipq8064 support
dt-bindings: thermal: tsens: document ipq8064 bindings
drivers: thermal: tsens: add interrupt support for 9860 driver
drivers: thermal: tsens: add support for custom set_trip function
drivers: thermal: tsens: add set_trip support for 8960

 .../bindings/thermal/qcom-tsens.yaml          |  50 ++-
 drivers/clk/qcom/gcc-ipq806x.c                |   2 +-
 drivers/thermal/qcom/tsens-8960.c             | 286 +++++++++++++++++-
 drivers/thermal/qcom/tsens.c                  |   7 +
 drivers/thermal/qcom/tsens.h                  |   3 +
 5 files changed, 325 insertions(+), 23 deletions(-)
Signature · 1 line
2.27.0
#1 lore raw

PATCH v3 1/7 ipq806x: gcc: add support for child probe

Add support for child probing needed for tsens driver that share the seme regs of gcc for this platform.

---
 drivers/clk/qcom/gcc-ipq806x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/gcc-ipq806x.c +1 -1
index a8456e09c44d..d6b7adb4be38 100644
@@ -3089,7 +3089,7 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
 	regmap_write(regmap, 0x3cf8, 8);
 	regmap_write(regmap, 0x3d18, 8);
 
-	return 0;
+	return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 }
 
 static struct platform_driver gcc_ipq806x_driver = {
Signature · 1 line
2.27.0
#2 lore raw

PATCH v3 2/7 drivers: thermal: tsens: try load regmap from parent for 8960

In reply to Ansuel Smith

Devices based on 8060 tsens driver (ipq8064) use the reg of the gcc driver. Try to load the regmap of the parent as they share the same regs.

---
 drivers/thermal/qcom/tsens-8960.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/thermal/qcom/tsens-8960.c +11 -1
index 2a28a5af209e..45788eb3c666 100644
@@ -7,6 +7,7 @@
 #include <linux/delay.h>
 #include <linux/bitops.h>
 #include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
 #include <linux/thermal.h>
 #include "tsens.h"
 
@@ -168,8 +169,17 @@ static int init_8960(struct tsens_priv *priv)
 	u32 reg_cntl;
 
 	priv->tm_map = dev_get_regmap(priv->dev, NULL);
-	if (!priv->tm_map)
+	if (!priv->tm_map) {
+		struct device *parent = priv->dev->parent;
+
+		if (parent)
+			priv->tm_map = syscon_node_to_regmap(parent->of_node);
+	}
+
+	if (!priv->tm_map || IS_ERR(priv->tm_map)) {
+		dev_err(priv->dev, "failed to get tsens regmap\n");
 		return -ENODEV;
+	}
 
 	/*
 	 * The status registers for each sensor are discontiguous
Signature · 1 line
2.27.0
#3 lore raw

PATCH v3 3/7 drivers: thermal: tsens: add ipq8064 support

In reply to Ansuel Smith

Ipq8064 SoCs based use the same 8960 driver.

---
 drivers/thermal/qcom/tsens.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/thermal/qcom/tsens.c +3 -0
index 39c4462e38f6..2985a064a0d1 100644
@@ -907,6 +907,9 @@ static const struct of_device_id tsens_table[] = {
 		.compatible = "qcom,msm8996-tsens",
 		.data = &data_8996,
 	}, {
+		.compatible = "qcom,ipq8064-tsens",
+		.data = &data_8060,
+	} {
 		.compatible = "qcom,tsens-v1",
 		.data = &data_tsens_v1,
 	}, {
Signature · 1 line
2.27.0
#4 lore raw

Re: [PATCH v3 3/7] drivers: thermal: tsens: add ipq8064 support

Thank you for the patch! Yet something to improve:

Hi Ansuel,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on clk/clk-next linus/master v5.8-rc5 next-20200715] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Ansuel-Smith/Add-support-for-ipq8064-tsens/20200716-064738
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: x86_64-allyesconfig (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project ed6b578040a85977026c93bf4188f996148f3218)

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate

All errors (new ones prefixed by >>):

drivers/thermal/qcom/tsens.c:385:13: warning: no previous prototype for function 'tsens_critical_irq_thread' [-Wmissing-prototypes] irqreturn_t tsens_critical_irq_thread(int irq, void *data)

               ^
   drivers/thermal/qcom/tsens.c:385:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   irqreturn_t tsens_critical_irq_thread(int irq, void *data)
   ^
   static 
   drivers/thermal/qcom/tsens.c:455:13: warning: no previous prototype for function 'tsens_irq_thread' [-Wmissing-prototypes]
   irqreturn_t tsens_irq_thread(int irq, void *data)
               ^
   drivers/thermal/qcom/tsens.c:455:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   irqreturn_t tsens_irq_thread(int irq, void *data)
   ^
   static 
   drivers/thermal/qcom/tsens.c:523:5: warning: no previous prototype for function 'tsens_set_trips' [-Wmissing-prototypes]
   int tsens_set_trips(void *_sensor, int low, int high)
       ^
   drivers/thermal/qcom/tsens.c:523:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tsens_set_trips(void *_sensor, int low, int high)
   ^
   static 
   drivers/thermal/qcom/tsens.c:560:5: warning: no previous prototype for function 'tsens_enable_irq' [-Wmissing-prototypes]
   int tsens_enable_irq(struct tsens_priv *priv)
       ^
   drivers/thermal/qcom/tsens.c:560:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tsens_enable_irq(struct tsens_priv *priv)
   ^
   static 
   drivers/thermal/qcom/tsens.c:573:6: warning: no previous prototype for function 'tsens_disable_irq' [-Wmissing-prototypes]
   void tsens_disable_irq(struct tsens_priv *priv)
        ^
   drivers/thermal/qcom/tsens.c:573:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   void tsens_disable_irq(struct tsens_priv *priv)
   ^
   static 
>> drivers/thermal/qcom/tsens.c:911:12: error: use of undeclared identifier 'data_8060'; did you mean 'data_8960'?
                   .data = &data_8060,
                            ^~~~~~~~~
                            data_8960
   drivers/thermal/qcom/tsens.h:585:31: note: 'data_8960' declared here
   extern struct tsens_plat_data data_8960;
                                 ^
>> drivers/thermal/qcom/tsens.c:912:4: error: expected '}'
           } {
             ^
   drivers/thermal/qcom/tsens.c:896:50: note: to match this '{'
   static const struct of_device_id tsens_table[] = {
                                                    ^

5 warnings and 2 errors generated.

vim +911 drivers/thermal/qcom/tsens.c

895
896 static const struct of_device_id tsens_table[] = {
897 {
898 .compatible = "qcom,msm8916-tsens",
899 .data = &data_8916,
900 }, {
901 .compatible = "qcom,msm8974-tsens",
902 .data = &data_8974,
903 }, {
904 .compatible = "qcom,msm8976-tsens",
905 .data = &data_8976,
906 }, {
907 .compatible = "qcom,msm8996-tsens",
908 .data = &data_8996,
909 }, {
910 .compatible = "qcom,ipq8064-tsens",

 > 911			.data = &data_8060,
 > 912		} {

913 .compatible = "qcom,tsens-v1",
914 .data = &data_tsens_v1,
915 }, {
916 .compatible = "qcom,tsens-v2",
917 .data = &data_tsens_v2,
918 },
919 {}
920 };
921 MODULE_DEVICE_TABLE(of, tsens_table);
922

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

#5 lore raw

PATCH v3 4/7 dt-bindings: thermal: tsens: document ipq8064 bindings

In reply to Ansuel Smith

Document the use of bindings used for ipq8064 SoCs tsens. ipq8064 use the same gcc regs and is set as a child of the qcom gcc.

---
 .../bindings/thermal/qcom-tsens.yaml          | 50 ++++++++++++++++---
 1 file changed, 43 insertions(+), 7 deletions(-)
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +43 -7
index d7be931b42d2..9d480e3943a2 100644
@@ -19,6 +19,11 @@ description: |
 properties:
   compatible:
     oneOf:
+      - description: msm9860 TSENS based
+        items:
+          - enum:
+            - qcom,ipq8064-tsens
+
       - description: v0.1 of TSENS
         items:
           - enum:
@@ -85,12 +90,18 @@ properties:
       Number of cells required to uniquely identify the thermal sensors. Since
       we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - "#thermal-sensor-cells"
+
 allOf:
   - if:
       properties:
         compatible:
           contains:
             enum:
+              - qcom,ipq8064-tsens
               - qcom,msm8916-tsens
               - qcom,msm8974-tsens
               - qcom,msm8976-tsens
@@ -111,17 +122,42 @@ allOf:
         interrupt-names:
           minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,tsens-v0_1
+              - qcom,tsens-v1
+              - qcom,tsens-v2
+
+    then:
+      required:
+        - reg
+        - interrupt-names
+        - "#qcom,sensors"
 
 additionalProperties: false
 
 examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    // Example msm9860 based SoC (ipq8064):
+    gcc: clock-controller {
+
+           /* ... */
+
+           tsens: thermal-sensor {
+                compatible = "qcom,ipq8064-tsens";
+
+                 nvmem-cells = <&tsens_calib>, <&tsens_calsel>;
+                 nvmem-cell-names = "calib", "calib_sel";
+                 interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+
+                 #thermal-sensor-cells = <1>;
+          };
+    };
+
   - |
     #include <dt-bindings/interrupt-controller/arm-gic.h>
     // Example 1 (legacy: for pre v1 IP):
Signature · 1 line
2.27.0
#6 lore raw

PATCH v3 5/7 drivers: thermal: tsens: add interrupt support for 9860 driver

In reply to Ansuel Smith

Add interrupt support for 9860 tsens driver used to set thermal trip point for the system.

---
 drivers/thermal/qcom/tsens-8960.c | 196 +++++++++++++++++++++++++++---
 drivers/thermal/qcom/tsens.h      |   1 +
 2 files changed, 183 insertions(+), 14 deletions(-)
drivers/thermal/qcom/tsens-8960.c +182 -14
index 45788eb3c666..b302bfb924a6 100644
@@ -8,6 +8,7 @@
 #include <linux/bitops.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
+#include <linux/interrupt.h>
 #include <linux/thermal.h>
 #include "tsens.h"
 
@@ -27,7 +28,6 @@
 /* CNTL_ADDR bitmasks */
 #define EN			BIT(0)
 #define SW_RST			BIT(1)
-#define SENSOR0_EN		BIT(3)
 #define SLP_CLK_ENA		BIT(26)
 #define SLP_CLK_ENA_8660	BIT(24)
 #define MEASURE_PERIOD		1
@@ -41,14 +41,26 @@
 
 #define THRESHOLD_ADDR		0x3624
 /* THRESHOLD_ADDR bitmasks */
+#define THRESHOLD_MAX_CODE		0x20000
+#define THRESHOLD_MIN_CODE		0
 #define THRESHOLD_MAX_LIMIT_SHIFT	24
 #define THRESHOLD_MIN_LIMIT_SHIFT	16
 #define THRESHOLD_UPPER_LIMIT_SHIFT	8
 #define THRESHOLD_LOWER_LIMIT_SHIFT	0
+#define THRESHOLD_MAX_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
+						THRESHOLD_MAX_LIMIT_SHIFT)
+#define THRESHOLD_MIN_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
+						THRESHOLD_MIN_LIMIT_SHIFT)
+#define THRESHOLD_UPPER_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
+						THRESHOLD_UPPER_LIMIT_SHIFT)
+#define THRESHOLD_LOWER_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
+						THRESHOLD_LOWER_LIMIT_SHIFT)
 
 /* Initial temperature threshold values */
-#define LOWER_LIMIT_TH		0x50
-#define UPPER_LIMIT_TH		0xdf
+#define LOWER_LIMIT_TH_8960	0x50
+#define UPPER_LIMIT_TH_8960	0xdf
+#define LOWER_LIMIT_TH_8064	0x9d /* 95C */
+#define UPPER_LIMIT_TH_8064	0xa6 /* 105C */
 #define MIN_LIMIT_TH		0x0
 #define MAX_LIMIT_TH		0xff
 
@@ -57,6 +69,169 @@
 #define TRDY_MASK		BIT(7)
 #define TIMEOUT_US		100
 
+#define TSENS_EN		BIT(0)
+#define TSENS_SW_RST		BIT(1)
+#define TSENS_ADC_CLK_SEL	BIT(2)
+#define SENSOR0_EN		BIT(3)
+#define SENSOR1_EN		BIT(4)
+#define SENSOR2_EN		BIT(5)
+#define SENSOR3_EN		BIT(6)
+#define SENSOR4_EN		BIT(7)
+#define SENSORS_EN		(SENSOR0_EN | SENSOR1_EN | \
+				SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
+#define TSENS_8064_SENSOR5_EN				BIT(8)
+#define TSENS_8064_SENSOR6_EN				BIT(9)
+#define TSENS_8064_SENSOR7_EN				BIT(10)
+#define TSENS_8064_SENSOR8_EN				BIT(11)
+#define TSENS_8064_SENSOR9_EN				BIT(12)
+#define TSENS_8064_SENSOR10_EN				BIT(13)
+#define TSENS_8064_SENSORS_EN				(SENSORS_EN | \
+						TSENS_8064_SENSOR5_EN | \
+						TSENS_8064_SENSOR6_EN | \
+						TSENS_8064_SENSOR7_EN | \
+						TSENS_8064_SENSOR8_EN | \
+						TSENS_8064_SENSOR9_EN | \
+						TSENS_8064_SENSOR10_EN)
+
+u32 tsens_8960_slope[] = {
+			1176, 1176, 1154, 1176,
+			1111, 1132, 1132, 1199,
+			1132, 1199, 1132
+			};
+
+/* Temperature on y axis and ADC-code on x-axis */
+static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
+{
+	int slope, offset;
+
+	slope = thermal_zone_get_slope(s->tzd);
+	offset = CAL_MDEGC - slope * s->offset;
+
+	return adc_code * slope + offset;
+}
+
+static void notify_uspace_tsens_fn(struct work_struct *work)
+{
+	struct tsens_sensor *s = container_of(work, struct tsens_sensor,
+								notify_work);
+
+	sysfs_notify(&s->tzd->device.kobj, NULL, "type");
+}
+
+static void tsens_scheduler_fn(struct work_struct *work)
+{
+	struct tsens_priv *priv =
+		container_of(work, struct tsens_priv, tsens_work);
+	unsigned int threshold, threshold_low, code, reg, sensor, mask;
+	bool upper_th_x, lower_th_x;
+	int ret;
+
+	ret = regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064, &reg);
+	if (ret)
+		return;
+	reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR;
+	ret = regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064, reg);
+	if (ret)
+		return;
+
+	mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);
+	ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, &threshold);
+	if (ret)
+		return;
+	threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK) >>
+			THRESHOLD_LOWER_LIMIT_SHIFT;
+	threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK) >>
+		    THRESHOLD_UPPER_LIMIT_SHIFT;
+
+	ret = regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064, &reg);
+	if (ret)
+		return;
+
+	ret = regmap_read(priv->tm_map, CNTL_ADDR, &sensor);
+	if (ret)
+		return;
+	sensor &= (uint32_t)TSENS_8064_SENSORS_EN;
+	sensor >>= SENSOR0_SHIFT;
+
+	/* Constraint: There is only 1 interrupt control register for all
+	 * 11 temperature sensor. So monitoring more than 1 sensor based
+	 * on interrupts will yield inconsistent result. To overcome this
+	 * issue we will monitor only sensor 0 which is the master sensor.
+	 */
+
+	/* Skip if the sensor is disabled */
+	if (sensor & 1) {
+		ret = regmap_read(priv->tm_map, priv->sensor[0].status, &code);
+		if (ret)
+			return;
+		upper_th_x = code >= threshold;
+		lower_th_x = code <= threshold_low;
+		if (upper_th_x)
+			mask |= UPPER_STATUS_CLR;
+		if (lower_th_x)
+			mask |= LOWER_STATUS_CLR;
+		if (upper_th_x || lower_th_x) {
+			/* Notify user space */
+			schedule_work(&priv->sensor[0].notify_work);
+			pr_debug("Trigger (%d degrees) for sensor %d\n",
+				 code_to_mdegC(code, &priv->sensor[0]), 0);
+		}
+	}
+	regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064, reg & mask);
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+	struct tsens_priv *priv = data;
+
+	schedule_work(&priv->tsens_work);
+	return IRQ_HANDLED;
+}
+
+static void hw_init(struct tsens_priv *priv)
+{
+	int ret;
+	unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
+	unsigned int reg_status_cntl = 0;
+
+	regmap_read(priv->tm_map, CNTL_ADDR, &reg_cntl);
+	regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl | TSENS_SW_RST);
+
+	reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18) |
+		    (((1 << priv->num_sensors) - 1) << SENSOR0_SHIFT);
+	regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
+	regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064, &reg_status_cntl);
+	reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR |
+			   MIN_STATUS_MASK | MAX_STATUS_MASK;
+	regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064, reg_status_cntl);
+	reg_cntl |= TSENS_EN;
+	regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
+
+	regmap_read(priv->tm_map, CONFIG_ADDR, &reg_cfg);
+	if (priv->num_sensors > 1)
+		reg_cfg = (reg_cfg & ~CONFIG_MASK) | CONFIG;
+	else
+		reg_cfg = (reg_cfg & ~CONFIG_MASK) |
+			  (CONFIG << CONFIG_SHIFT_8660);
+	regmap_write(priv->tm_map, CONFIG_ADDR, reg_cfg);
+
+	reg_thr |= (LOWER_LIMIT_TH_8064 << THRESHOLD_LOWER_LIMIT_SHIFT) |
+		   (UPPER_LIMIT_TH_8064 << THRESHOLD_UPPER_LIMIT_SHIFT) |
+		   (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT) |
+		   (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT);
+
+	regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_thr);
+
+	ret = devm_request_irq(priv->dev, priv->tsens_irq, tsens_isr,
+			       IRQF_TRIGGER_RISING, "tsens_interrupt", priv);
+	if (ret < 0) {
+		dev_err(priv->dev, "request_irq FAIL: %d", ret);
+		return;
+	}
+
+	INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
+}
+
 static int suspend_8960(struct tsens_priv *priv)
 {
 	int ret;
@@ -191,6 +366,8 @@ static int init_8960(struct tsens_priv *priv)
 		if (i >= 5)
 			priv->sensor[i].status = S0_STATUS_ADDR + 40;
 		priv->sensor[i].status += i * 4;
+		priv->sensor[i].slope = tsens_8960_slope[i];
+		INIT_WORK(&priv->sensor[i].notify_work, notify_uspace_tsens_fn);
 	}
 
 	reg_cntl = SW_RST;
@@ -241,18 +418,9 @@ static int calibrate_8960(struct tsens_priv *priv)
 
 	kfree(data);
 
-	return 0;
-}
-
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-	int slope, offset;
+	hw_init(priv);
 
-	slope = thermal_zone_get_slope(s->tzd);
-	offset = CAL_MDEGC - slope * s->offset;
-
-	return adc_code * slope + offset;
+	return 0;
 }
 
 static int get_temp_8960(const struct tsens_sensor *s, int *temp)
drivers/thermal/qcom/tsens.h +1 -0
index 59d01162c66a..2f145001e4d5 100644
@@ -48,6 +48,7 @@ enum tsens_irq_type {
 struct tsens_sensor {
 	struct tsens_priv		*priv;
 	struct thermal_zone_device	*tzd;
+	struct work_struct		notify_work;
 	int				offset;
 	unsigned int			hw_id;
 	int				slope;
Signature · 1 line
2.27.0
#7 lore raw

Re: [PATCH v3 5/7] drivers: thermal: tsens: add interrupt support for 9860 driver

Thank you for the patch! Perhaps something to improve:

Hi Ansuel,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on clk/clk-next linus/master v5.8-rc5 next-20200715] [cannot apply to thermal/next]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Ansuel-Smith/Add-support-for-ipq8064-tsens/20200716-064738
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: riscv-allyesconfig (attached as .config)
compiler: riscv64-linux-gcc (GCC) 9.3.0

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=riscv

If you fix the issue, kindly add following tag as appropriate

All warnings (new ones prefixed by >>):

In file included from include/linux/dev_printk.h:14,

                    from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from drivers/thermal/qcom/tsens-8960.c:6:
   drivers/thermal/qcom/tsens-8960.c: In function 'tsens_scheduler_fn':
   drivers/thermal/qcom/tsens-8960.c:124:41: error: 'struct tsens_priv' has no member named 'tsens_work'; did you mean 'sensor'?
     124 |   container_of(work, struct tsens_priv, tsens_work);
         |                                         ^~~~~~~~~~
   include/linux/compiler.h:372:9: note: in definition of macro '__compiletime_assert'
     372 |   if (!(condition))     \
         |         ^~~~~~~~~
   include/linux/compiler.h:392:2: note: in expansion of macro '_compiletime_assert'
     392 |  _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
         |  ^~~~~~~~~~~~~~~~~~~
   include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert'
      39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
         |                                     ^~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:1003:2: note: in expansion of macro 'BUILD_BUG_ON_MSG'
    1003 |  BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \
         |  ^~~~~~~~~~~~~~~~
   include/linux/kernel.h:1003:20: note: in expansion of macro '__same_type'
    1003 |  BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \
         |                    ^~~~~~~~~~~
   drivers/thermal/qcom/tsens-8960.c:124:3: note: in expansion of macro 'container_of'
     124 |   container_of(work, struct tsens_priv, tsens_work);
         |   ^~~~~~~~~~~~
   In file included from <command-line>:
   drivers/thermal/qcom/tsens-8960.c:124:41: error: 'struct tsens_priv' has no member named 'tsens_work'; did you mean 'sensor'?
     124 |   container_of(work, struct tsens_priv, tsens_work);
         |                                         ^~~~~~~~~~
   include/linux/compiler_types.h:133:57: note: in definition of macro '__compiler_offsetof'
     133 | #define __compiler_offsetof(a, b) __builtin_offsetof(a, b)
         |                                                         ^
   include/linux/kernel.h:1006:21: note: in expansion of macro 'offsetof'
    1006 |  ((type *)(__mptr - offsetof(type, member))); })
         |                     ^~~~~~~~
   drivers/thermal/qcom/tsens-8960.c:124:3: note: in expansion of macro 'container_of'
     124 |   container_of(work, struct tsens_priv, tsens_work);
         |   ^~~~~~~~~~~~
>> drivers/thermal/qcom/tsens-8960.c:137:9: warning: conversion from 'long unsigned int' to 'unsigned int' changes value from '18446744073709551609' to '4294967289' [-Woverflow]
     137 |  mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);
         |         ^
   drivers/thermal/qcom/tsens-8960.c: In function 'tsens_isr':
   drivers/thermal/qcom/tsens-8960.c:187:23: error: 'struct tsens_priv' has no member named 'tsens_work'; did you mean 'sensor'?
     187 |  schedule_work(&priv->tsens_work);
         |                       ^~~~~~~~~~
         |                       sensor
   drivers/thermal/qcom/tsens-8960.c: In function 'hw_init':
   drivers/thermal/qcom/tsens-8960.c:225:40: error: 'struct tsens_priv' has no member named 'tsens_irq'
     225 |  ret = devm_request_irq(priv->dev, priv->tsens_irq, tsens_isr,
         |                                        ^~
   In file included from include/linux/rhashtable-types.h:15,
                    from include/linux/ipc.h:7,
                    from include/uapi/linux/sem.h:5,
                    from include/linux/sem.h:5,
                    from include/linux/sched.h:15,
                    from include/linux/ratelimit.h:6,
                    from include/linux/dev_printk.h:16,
                    from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from drivers/thermal/qcom/tsens-8960.c:6:
   drivers/thermal/qcom/tsens-8960.c:232:19: error: 'struct tsens_priv' has no member named 'tsens_work'; did you mean 'sensor'?
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |                   ^~~~~~~~~~
   include/linux/workqueue.h:242:16: note: in definition of macro '__INIT_WORK'
     242 |   __init_work((_work), _onstack);    \
         |                ^~~~~
   drivers/thermal/qcom/tsens-8960.c:232:2: note: in expansion of macro 'INIT_WORK'
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |  ^~~~~~~~~
   drivers/thermal/qcom/tsens-8960.c:232:19: error: 'struct tsens_priv' has no member named 'tsens_work'; did you mean 'sensor'?
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |                   ^~~~~~~~~~
   include/linux/workqueue.h:243:4: note: in definition of macro '__INIT_WORK'
     243 |   (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
         |    ^~~~~
   drivers/thermal/qcom/tsens-8960.c:232:2: note: in expansion of macro 'INIT_WORK'
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |  ^~~~~~~~~
   drivers/thermal/qcom/tsens-8960.c:232:19: error: 'struct tsens_priv' has no member named 'tsens_work'; did you mean 'sensor'?
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |                   ^~~~~~~~~~
   include/linux/workqueue.h:244:20: note: in definition of macro '__INIT_WORK'
     244 |   INIT_LIST_HEAD(&(_work)->entry);   \
         |                    ^~~~~
   drivers/thermal/qcom/tsens-8960.c:232:2: note: in expansion of macro 'INIT_WORK'
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |  ^~~~~~~~~
   drivers/thermal/qcom/tsens-8960.c:232:19: error: 'struct tsens_priv' has no member named 'tsens_work'; did you mean 'sensor'?
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |                   ^~~~~~~~~~
   include/linux/workqueue.h:245:4: note: in definition of macro '__INIT_WORK'
     245 |   (_work)->func = (_func);    \
         |    ^~~~~
   drivers/thermal/qcom/tsens-8960.c:232:2: note: in expansion of macro 'INIT_WORK'
     232 |  INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
         |  ^~~~~~~~~
   In file included from include/linux/bits.h:23,
                    from include/linux/bitops.h:5,
                    from include/linux/kernel.h:12,
                    from include/asm-generic/bug.h:19,
                    from arch/riscv/include/asm/bug.h:83,
                    from include/linux/bug.h:5,
                    from arch/riscv/include/asm/current.h:13,
                    from include/linux/sched.h:12,
                    from include/linux/ratelimit.h:6,
                    from include/linux/dev_printk.h:16,
                    from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from drivers/thermal/qcom/tsens-8960.c:6:
   drivers/thermal/qcom/tsens-8960.c: In function 'disable_8960':
   include/linux/bits.h:26:28: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
      26 |   __builtin_constant_p((l) > (h)), (l) > (h), 0)))
         |                            ^
   include/linux/build_bug.h:16:62: note: in definition of macro 'BUILD_BUG_ON_ZERO'
      16 | #define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))
         |                                                              ^
   include/linux/bits.h:39:3: note: in expansion of macro 'GENMASK_INPUT_CHECK'
      39 |  (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l))
         |   ^~~~~~~~~~~~~~~~~~~
   drivers/thermal/qcom/tsens-8960.c:323:9: note: in expansion of macro 'GENMASK'
     323 |  mask = GENMASK(priv->num_sensors - 1, 0);
         |         ^~~~~~~
   include/linux/bits.h:26:40: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
      26 |   __builtin_constant_p((l) > (h)), (l) > (h), 0)))
         |                                        ^
   include/linux/build_bug.h:16:62: note: in definition of macro 'BUILD_BUG_ON_ZERO'
      16 | #define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))
         |                                                              ^
   include/linux/bits.h:39:3: note: in expansion of macro 'GENMASK_INPUT_CHECK'
      39 |  (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l))
         |   ^~~~~~~~~~~~~~~~~~~
   drivers/thermal/qcom/tsens-8960.c:323:9: note: in expansion of macro 'GENMASK'
     323 |  mask = GENMASK(priv->num_sensors - 1, 0);
         |         ^~~~~~~
   drivers/thermal/qcom/tsens-8960.c: In function 'init_8960':
   include/linux/bits.h:26:28: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
      26 |   __builtin_constant_p((l) > (h)), (l) > (h), 0)))
         |                            ^

include/linux/build_bug.h:16:62: note: in definition of macro 'BUILD_BUG_ON_ZERO'

vim +137 drivers/thermal/qcom/tsens-8960.c

120
121 static void tsens_scheduler_fn(struct work_struct *work)
122 {
123 struct tsens_priv *priv =

 > 124			container_of(work, struct tsens_priv, tsens_work);
   125		unsigned int threshold, threshold_low, code, reg, sensor, mask;
   126		bool upper_th_x, lower_th_x;
   127		int ret;
   128	
   129		ret = regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064, &reg);
   130		if (ret)
   131			return;
   132		reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR;
   133		ret = regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064, reg);
   134		if (ret)
   135			return;
   136	
 > 137		mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);

138 ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, &threshold);
139 if (ret)
140 return;
141 threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK) >>
142 THRESHOLD_LOWER_LIMIT_SHIFT;
143 threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK) >>
144 THRESHOLD_UPPER_LIMIT_SHIFT;
145
146 ret = regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064, &reg);
147 if (ret)
148 return;
149
150 ret = regmap_read(priv->tm_map, CNTL_ADDR, &sensor);
151 if (ret)
152 return;
153 sensor &= (uint32_t)TSENS_8064_SENSORS_EN;
154 sensor >>= SENSOR0_SHIFT;
155
156 /* Constraint: There is only 1 interrupt control register for all
157 * 11 temperature sensor. So monitoring more than 1 sensor based
158 * on interrupts will yield inconsistent result. To overcome this
159 * issue we will monitor only sensor 0 which is the master sensor.
160 */
161
162 /* Skip if the sensor is disabled */
163 if (sensor & 1) {
164 ret = regmap_read(priv->tm_map, priv->sensor[0].status, &code);
165 if (ret)
166 return;
167 upper_th_x = code >= threshold;
168 lower_th_x = code <= threshold_low;
169 if (upper_th_x)
170 mask |= UPPER_STATUS_CLR;
171 if (lower_th_x)
172 mask |= LOWER_STATUS_CLR;
173 if (upper_th_x || lower_th_x) {
174 /* Notify user space */
175 schedule_work(&priv->sensor[0].notify_work);
176 pr_debug("Trigger (%d degrees) for sensor %d\n",
177 code_to_mdegC(code, &priv->sensor[0]), 0);
178 }
179 }
180 regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064, reg & mask);
181 }
182

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

#8 lore raw

PATCH v3 6/7 drivers: thermal: tsens: add support for custom set_trip function

In reply to Ansuel Smith

8960 tsens driver have a custom implementation to set set_trip function. Permit the generic driver to use the custom function if provided.

---
 drivers/thermal/qcom/tsens.c | 4 ++++
 drivers/thermal/qcom/tsens.h | 2 ++
 2 files changed, 6 insertions(+)
drivers/thermal/qcom/tsens.c +4 -0
index 2985a064a0d1..2b55b34d66fb 100644
@@ -530,6 +530,10 @@ static int tsens_set_trips(void *_sensor, int low, int high)
 	int high_val, low_val, cl_high, cl_low;
 	u32 hw_id = s->hw_id;
 
+	// Use the driver set_trips if present
+	if (priv->ops->set_trip_temp)
+		return priv->ops->set_trip_temp(_sensor, low, high);
+
 	dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
 		hw_id, __func__, low, high);
 
drivers/thermal/qcom/tsens.h +2 -0
index 2f145001e4d5..c27fae39d542 100644
@@ -65,6 +65,7 @@ struct tsens_sensor {
  * @suspend: Function to suspend the tsens device
  * @resume: Function to resume the tsens device
  * @get_trend: Function to get the thermal/temp trend
+ * @set_trip_temp: Function to get trip temp
  */
 struct tsens_ops {
 	/* mandatory callbacks */
@@ -77,6 +78,7 @@ struct tsens_ops {
 	int (*suspend)(struct tsens_priv *priv);
 	int (*resume)(struct tsens_priv *priv);
 	int (*get_trend)(struct tsens_sensor *s, enum thermal_trend *trend);
+	int (*set_trip_temp)(void *data, int trip, int temp);
 };
 
 #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
Signature · 1 line
2.27.0
#9 lore raw

PATCH v3 7/7 drivers: thermal: tsens: add set_trip support for 8960

In reply to Ansuel Smith

Add custom set_trip function for 8960 needed to set trip point to the tsens driver for 8960 driver.

---
 drivers/thermal/qcom/tsens-8960.c | 78 +++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
drivers/thermal/qcom/tsens-8960.c +78 -0
index b302bfb924a6..f6ed2450a7ba 100644
@@ -93,6 +93,15 @@
 						TSENS_8064_SENSOR9_EN | \
 						TSENS_8064_SENSOR10_EN)
 
+/* Trips: from very hot to very cold */
+enum tsens_trip_type {
+	TSENS_TRIP_STAGE3 = 0,
+	TSENS_TRIP_STAGE2,
+	TSENS_TRIP_STAGE1,
+	TSENS_TRIP_STAGE0,
+	TSENS_TRIP_NUM,
+};
+
 u32 tsens_8960_slope[] = {
 			1176, 1176, 1154, 1176,
 			1111, 1132, 1132, 1199,
@@ -110,6 +119,16 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
 	return adc_code * slope + offset;
 }
 
+static int mdegC_to_code(int degC, const struct tsens_sensor *s)
+{
+	int slope, offset;
+
+	slope = thermal_zone_get_slope(s->tzd);
+	offset = CAL_MDEGC - slope * s->offset;
+
+	return degC / slope - offset;
+}
+
 static void notify_uspace_tsens_fn(struct work_struct *work)
 {
 	struct tsens_sensor *s = container_of(work, struct tsens_sensor,
@@ -447,6 +466,64 @@ static int get_temp_8960(const struct tsens_sensor *s, int *temp)
 	return -ETIMEDOUT;
 }
 
+static int set_trip_temp_ipq8064(void *data, int trip, int temp)
+{
+	unsigned int reg_th, reg_cntl;
+	int ret, code, code_chk, hi_code, lo_code;
+	const struct tsens_sensor *s = data;
+	struct tsens_priv *priv = s->priv;
+
+	code = mdegC_to_code(temp, s);
+	code_chk = code;
+
+	if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE)
+		return -EINVAL;
+
+	ret = regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064, &reg_cntl);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, &reg_th);
+	if (ret)
+		return ret;
+
+	hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK)
+			>> THRESHOLD_UPPER_LIMIT_SHIFT;
+	lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK)
+			>> THRESHOLD_LOWER_LIMIT_SHIFT;
+
+	switch (trip) {
+	case TSENS_TRIP_STAGE3:
+		code <<= THRESHOLD_MAX_LIMIT_SHIFT;
+		reg_th &= ~THRESHOLD_MAX_LIMIT_MASK;
+		break;
+	case TSENS_TRIP_STAGE2:
+		if (code_chk <= lo_code)
+			return -EINVAL;
+		code <<= THRESHOLD_UPPER_LIMIT_SHIFT;
+		reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK;
+		break;
+	case TSENS_TRIP_STAGE1:
+		if (code_chk >= hi_code)
+			return -EINVAL;
+		code <<= THRESHOLD_LOWER_LIMIT_SHIFT;
+		reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK;
+		break;
+	case TSENS_TRIP_STAGE0:
+		code <<= THRESHOLD_MIN_LIMIT_SHIFT;
+		reg_th &= ~THRESHOLD_MIN_LIMIT_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_th | code);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static const struct tsens_ops ops_8960 = {
 	.init		= init_8960,
 	.calibrate	= calibrate_8960,
@@ -455,6 +532,7 @@ static const struct tsens_ops ops_8960 = {
 	.disable	= disable_8960,
 	.suspend	= suspend_8960,
 	.resume		= resume_8960,
+	.set_trip_temp	= set_trip_temp_ipq8064,
 };
 
 struct tsens_plat_data data_8960 = {
Signature · 1 line
2.27.0