linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] Add cold interrupt support to tsens driver
@ 2020-05-22 11:46 Manaf Meethalavalappu Pallikunhi
  2020-05-22 11:46 ` [PATCH v3 1/2] drivers: thermal: tsens: Add cold interrupt support Manaf Meethalavalappu Pallikunhi
  2020-05-22 11:46 ` [PATCH v3 2/2] dt-bindings: thermal: tsens: Add cold interrupt support in yaml Manaf Meethalavalappu Pallikunhi
  0 siblings, 2 replies; 5+ messages in thread
From: Manaf Meethalavalappu Pallikunhi @ 2020-05-22 11:46 UTC (permalink / raw)
  To: Amit Kucheria, Andy Gross, Bjorn Andersson, Zhang Rui,
	Daniel Lezcano, Rob Herring
  Cc: linux-pm, linux-arm-msm, devicetree, linux-kernel,
	Manaf Meethalavalappu Pallikunhi

The changes have dependency on merging tsens-common.c into tsens.c [1]
to merge first.

Dependencies:
[1] https://lkml.org/lkml/2020/4/29/1028

Changes in v3:
* Add cold interrupt support to tsens driver
* Update cold interrupt support in yaml

Manaf Meethalavalappu Pallikunhi (2):
  drivers: thermal: tsens: Add cold interrupt support
  dt-bindings: thermal: tsens: Add cold interrupt support in yaml

 .../bindings/thermal/qcom-tsens.yaml          |  42 +++++++
 drivers/thermal/qcom/tsens-v2.c               |   5 +
 drivers/thermal/qcom/tsens.c                  | 112 +++++++++++++++++-
 drivers/thermal/qcom/tsens.h                  |  11 ++
 4 files changed, 169 insertions(+), 1 deletion(-)

-- 
2.26.2

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

* [PATCH v3 1/2] drivers: thermal: tsens: Add cold interrupt support
  2020-05-22 11:46 [PATCH v3 0/2] Add cold interrupt support to tsens driver Manaf Meethalavalappu Pallikunhi
@ 2020-05-22 11:46 ` Manaf Meethalavalappu Pallikunhi
  2020-05-22 11:46 ` [PATCH v3 2/2] dt-bindings: thermal: tsens: Add cold interrupt support in yaml Manaf Meethalavalappu Pallikunhi
  1 sibling, 0 replies; 5+ messages in thread
From: Manaf Meethalavalappu Pallikunhi @ 2020-05-22 11:46 UTC (permalink / raw)
  To: Amit Kucheria, Andy Gross, Bjorn Andersson, Zhang Rui,
	Daniel Lezcano, Rob Herring
  Cc: linux-pm, linux-arm-msm, devicetree, linux-kernel,
	Manaf Meethalavalappu Pallikunhi

TSENS IP v2.6+ adds cold interrupt support. It triggers set
interrupt when aggregated minimum temperature of all TSENS falls
below cold preset threshold, 5 degree Celsius and triggers
reset interrupt when aggregated minimum temperature of all TSENS
crosses above reset threshold, 10 degree Celsius. These threshold
values could change in boot firmware code. Add support for this
interrupt in the driver.

It adds another virtual sensor to the of-thermal along with all
individual TSENS. This cold sensor only gives cold state value of
1 or 0 for successful temperature read. A state value of 1 indicates
minimum one TSENS is in cold temperature condition and state value
of 0 indicates all TSENS are out of cold temperature condition.

Signed-off-by: Manaf Meethalavalappu Pallikunhi <manafm@codeaurora.org>
---
 drivers/thermal/qcom/tsens-v2.c |   5 ++
 drivers/thermal/qcom/tsens.c    | 112 +++++++++++++++++++++++++++++++-
 drivers/thermal/qcom/tsens.h    |  11 ++++
 3 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
index b293ed32174b..1692e636d3bd 100644
--- a/drivers/thermal/qcom/tsens-v2.c
+++ b/drivers/thermal/qcom/tsens-v2.c
@@ -23,6 +23,7 @@
 #define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020
 #define TM_Sn_CRITICAL_THRESHOLD_OFF	0x0060
 #define TM_Sn_STATUS_OFF		0x00a0
+#define TM_COLD_INT_STATUS_OFF		0x00e0
 #define TM_TRDY_OFF			0x00e4
 #define TM_WDOG_LOG_OFF		0x013c
 
@@ -86,6 +87,9 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
 	REG_FIELD_FOR_EACH_SENSOR16(CRITICAL_STATUS, TM_Sn_STATUS_OFF, 19,  19),
 	REG_FIELD_FOR_EACH_SENSOR16(MAX_STATUS,      TM_Sn_STATUS_OFF, 20,  20),
 
+	/* COLD INTERRUPT STATUS */
+	[COLD_STATUS] = REG_FIELD(TM_COLD_INT_STATUS_OFF, 0, 0),
+
 	/* TRDY: 1=ready, 0=in progress */
 	[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
 };
@@ -93,6 +97,7 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_generic_v2 = {
 	.init		= init_common,
 	.get_temp	= get_temp_tsens_valid,
+	.get_cold_status  = get_cold_int_status,
 };
 
 struct tsens_plat_data data_tsens_v2 = {
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 8d3e94d2a9ed..ee93e9d07678 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -205,7 +205,8 @@ static void tsens_set_interrupt_v1(struct tsens_priv *priv, u32 hw_id,
 		index = LOW_INT_CLEAR_0 + hw_id;
 		break;
 	case CRITICAL:
-		/* No critical interrupts before v2 */
+	case COLD:
+		/* No critical and cold interrupts before v2 */
 		return;
 	}
 	regmap_field_write(priv->rf[index], enable ? 0 : 1);
@@ -236,6 +237,9 @@ static void tsens_set_interrupt_v2(struct tsens_priv *priv, u32 hw_id,
 		index_mask  = CRIT_INT_MASK_0 + hw_id;
 		index_clear = CRIT_INT_CLEAR_0 + hw_id;
 		break;
+	case COLD:
+		/* Nothing to handle for cold interrupt */
+		return;
 	}
 
 	if (enable) {
@@ -367,6 +371,35 @@ static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
 	return 0;
 }
 
+/**
+ * tsens_cold_irq_thread - Threaded interrupt handler for cold interrupt
+ * @irq: irq number
+ * @data: tsens controller private data
+ *
+ * Whenever interrupt triggers notify thermal framework using
+ * thermal_zone_device_update().
+ *
+ * Return: IRQ_HANDLED
+ */
+
+irqreturn_t tsens_cold_irq_thread(int irq, void *data)
+{
+	struct tsens_priv *priv = data;
+	struct tsens_sensor *s = priv->cold_sensor;
+	int cold_status, ret;
+
+	ret = regmap_field_read(priv->rf[COLD_STATUS], &cold_status);
+	if (ret)
+		return ret;
+
+	dev_dbg(priv->dev, "[%u] %s: cold interrupt is %s\n",
+		s->hw_id, __func__, cold_status ? "triggered" : "cleared");
+
+	thermal_zone_device_update(s->tzd, THERMAL_EVENT_UNSPECIFIED);
+
+	return IRQ_HANDLED;
+}
+
 /**
  * tsens_critical_irq_thread() - Threaded handler for critical interrupts
  * @irq: irq number
@@ -575,6 +608,20 @@ void tsens_disable_irq(struct tsens_priv *priv)
 	regmap_field_write(priv->rf[INT_EN], 0);
 }
 
+int get_cold_int_status(const struct tsens_sensor *s, bool *cold_status)
+{
+	struct tsens_priv *priv = s->priv;
+	int prev_cold = 0, ret;
+
+	ret = regmap_field_read(priv->rf[COLD_STATUS], &prev_cold);
+	if (ret)
+		return ret;
+
+	*cold_status = (bool)prev_cold;
+
+	return 0;
+}
+
 int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
 {
 	struct tsens_priv *priv = s->priv;
@@ -843,6 +890,19 @@ int __init init_common(struct tsens_priv *priv)
 		regmap_field_write(priv->rf[CC_MON_MASK], 1);
 	}
 
+	if (tsens_version(priv) > VER_1_X &&  ver_minor > 5) {
+		/* COLD interrupt is present only on v2.6+ */
+		priv->feat->cold_int = 1;
+		priv->rf[COLD_STATUS] = devm_regmap_field_alloc(
+						dev,
+						priv->tm_map,
+						priv->fields[COLD_STATUS]);
+		if (IS_ERR(priv->rf[COLD_STATUS])) {
+			ret = PTR_ERR(priv->rf[COLD_STATUS]);
+			goto err_put_device;
+		}
+	}
+
 	spin_lock_init(&priv->ul_lock);
 	tsens_enable_irq(priv);
 	tsens_debug_init(op);
@@ -852,6 +912,30 @@ int __init init_common(struct tsens_priv *priv)
 	return ret;
 }
 
+/**
+ * tsens_get_cold_status - It gets cold temperature status of TSENS
+ * @data: tsens cold sensor private data
+ * @cold_status: pointer to store last cold interrupt status
+ *
+ * It gives cold state value of 0 or 1 on success. A state
+ * value of 1 indicates minimum one TSENS is in cold temperature
+ * condition and a state value of 0 indicates all TSENS are out of
+ * cold temperature condition.
+ *
+ * Return: 0 on success, a negative errno will be returned in
+ * error cases.
+ */
+static int tsens_get_cold_status(void *data, int *cold_status)
+{
+	struct tsens_sensor *s = data;
+	struct tsens_priv *priv = s->priv;
+
+	if (priv->ops->get_cold_status)
+		return priv->ops->get_cold_status(s, (bool *)cold_status);
+
+	return -ENOTSUPP;
+}
+
 static int tsens_get_temp(void *data, int *temp)
 {
 	struct tsens_sensor *s = data;
@@ -923,6 +1007,10 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = {
 	.set_trips = tsens_set_trips,
 };
 
+static const struct thermal_zone_of_device_ops tsens_cold_of_ops = {
+	.get_temp = tsens_get_cold_status,
+};
+
 static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
 			      irq_handler_t thread_fn)
 {
@@ -980,6 +1068,28 @@ static int tsens_register(struct tsens_priv *priv)
 		ret = tsens_register_irq(priv, "critical",
 					 tsens_critical_irq_thread);
 
+	if (priv->feat->cold_int) {
+		priv->cold_sensor = devm_kzalloc(priv->dev,
+					sizeof(struct tsens_sensor),
+					GFP_KERNEL);
+		if (!priv->cold_sensor)
+			return -ENOMEM;
+
+		priv->cold_sensor->hw_id = COLD_SENSOR_HW_ID;
+		priv->cold_sensor->priv = priv;
+		tzd = devm_thermal_zone_of_sensor_register(priv->dev,
+					priv->cold_sensor->hw_id,
+					priv->cold_sensor,
+					&tsens_cold_of_ops);
+		if (IS_ERR(tzd)) {
+			ret = 0;
+			return ret;
+		}
+
+		priv->cold_sensor->tzd = tzd;
+		ret = tsens_register_irq(priv, "cold", tsens_cold_irq_thread);
+	}
+
 	return ret;
 }
 
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 59d01162c66a..be532fabef30 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -15,6 +15,7 @@
 #define SLOPE_DEFAULT		3200
 #define THRESHOLD_MAX_ADC_CODE	0x3ff
 #define THRESHOLD_MIN_ADC_CODE	0x0
+#define COLD_SENSOR_HW_ID	128
 
 #include <linux/interrupt.h>
 #include <linux/thermal.h>
@@ -34,6 +35,7 @@ enum tsens_irq_type {
 	LOWER,
 	UPPER,
 	CRITICAL,
+	COLD,
 };
 
 /**
@@ -64,6 +66,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
+ * @get_cold_status: Function to get the cold interrupt status
  */
 struct tsens_ops {
 	/* mandatory callbacks */
@@ -76,6 +79,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 (*get_cold_status)(const struct tsens_sensor *s, bool *cold_status);
 };
 
 #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
@@ -485,6 +489,8 @@ enum regfield_ids {
 	MAX_STATUS_14,
 	MAX_STATUS_15,
 
+	COLD_STATUS,		/* COLD interrupt status */
+
 	/* Keep last */
 	MAX_REGFIELDS
 };
@@ -497,6 +503,7 @@ enum regfield_ids {
  * @srot_split: does the IP neatly splits the register space into SROT and TM,
  *              with SROT only being available to secure boot firmware?
  * @has_watchdog: does this IP support watchdog functionality?
+ * @cold_int: does this IP support COLD interrupt ?
  * @max_sensors: maximum sensors supported by this version of the IP
  */
 struct tsens_features {
@@ -505,6 +512,7 @@ struct tsens_features {
 	unsigned int adc:1;
 	unsigned int srot_split:1;
 	unsigned int has_watchdog:1;
+	unsigned int cold_int:1;
 	unsigned int max_sensors;
 };
 
@@ -551,6 +559,7 @@ struct tsens_context {
  * @ops: pointer to list of callbacks supported by this device
  * @debug_root: pointer to debugfs dentry for all tsens
  * @debug: pointer to debugfs dentry for tsens controller
+ * @cold_sensor: pointer to cold sensor attached to this device
  * @sensor: list of sensors attached to this device
  */
 struct tsens_priv {
@@ -571,6 +580,7 @@ struct tsens_priv {
 
 	struct dentry			*debug_root;
 	struct dentry			*debug;
+	struct tsens_sensor		*cold_sensor;
 
 	struct tsens_sensor		sensor[];
 };
@@ -580,6 +590,7 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mo
 int init_common(struct tsens_priv *priv);
 int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp);
 int get_temp_common(const struct tsens_sensor *s, int *temp);
+int get_cold_int_status(const struct tsens_sensor *s, bool *cold_status);
 
 /* TSENS target */
 extern struct tsens_plat_data data_8960;
-- 
2.26.2

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

* [PATCH v3 2/2] dt-bindings: thermal: tsens: Add cold interrupt support in yaml
  2020-05-22 11:46 [PATCH v3 0/2] Add cold interrupt support to tsens driver Manaf Meethalavalappu Pallikunhi
  2020-05-22 11:46 ` [PATCH v3 1/2] drivers: thermal: tsens: Add cold interrupt support Manaf Meethalavalappu Pallikunhi
@ 2020-05-22 11:46 ` Manaf Meethalavalappu Pallikunhi
  2020-05-28 23:32   ` Rob Herring
  1 sibling, 1 reply; 5+ messages in thread
From: Manaf Meethalavalappu Pallikunhi @ 2020-05-22 11:46 UTC (permalink / raw)
  To: Amit Kucheria, Andy Gross, Bjorn Andersson, Zhang Rui,
	Daniel Lezcano, Rob Herring
  Cc: linux-pm, linux-arm-msm, devicetree, linux-kernel,
	Manaf Meethalavalappu Pallikunhi

Add cold interrupt support for tsens in yaml.

Signed-off-by: Manaf Meethalavalappu Pallikunhi <manafm@codeaurora.org>
---
 .../bindings/thermal/qcom-tsens.yaml          | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index 2ddd39d96766..3592322fe172 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -52,12 +52,14 @@ properties:
     items:
       - description: Combined interrupt if upper or lower threshold crossed
       - description: Interrupt if critical threshold crossed
+      - description: Interrupt if cold threshold is crossed
 
   interrupt-names:
     minItems: 1
     items:
       - const: uplow
       - const: critical
+      - const: cold
 
   nvmem-cells:
     minItems: 1
@@ -109,8 +111,10 @@ allOf:
       properties:
         interrupts:
           minItems: 2
+          maxItems: 3
         interrupt-names:
           minItems: 2
+          maxItems: 3
 
 required:
   - compatible
@@ -174,4 +178,42 @@ examples:
            #qcom,sensors = <13>;
            #thermal-sensor-cells = <1>;
     };
+
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    // Example 4 (for any platform containing v2.6+ of the TSENS IP)
+    //           (with thermal-zone):
+    tsens4: thermal-sensor@c265000 {
+           compatible = "qcom,sc7180-tsens", "qcom,tsens-v2";
+           reg = <0xc265000 0x1ff>,
+                 <0xc223000 0x1ff>;
+
+           interrupts = <GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>,
+                        <GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>,
+                        <GIC_SPI 501 IRQ_TYPE_EDGE_RISING>;
+           interrupt-names = "uplow", "critical", "cold";
+
+           #qcom,sensors = <15>;
+           #thermal-sensor-cells = <1>;
+    };
+
+    thermal-zones {
+            cold_thermal: cold-thermal {
+                    polling-delay-passive = <0>;
+                    polling-delay = <0>;
+
+                    thermal-sensors = <&tsens4 128>;
+
+                    trips {
+                            cold-trip {
+                                    temperature = <1>;
+                                    hysteresis = <1>;
+                                    type = "passive";
+                            };
+                    };
+
+                    cooling-maps {
+                    };
+            };
+    };
 ...
-- 
2.26.2

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

* Re: [PATCH v3 2/2] dt-bindings: thermal: tsens: Add cold interrupt support in yaml
  2020-05-22 11:46 ` [PATCH v3 2/2] dt-bindings: thermal: tsens: Add cold interrupt support in yaml Manaf Meethalavalappu Pallikunhi
@ 2020-05-28 23:32   ` Rob Herring
  0 siblings, 0 replies; 5+ messages in thread
From: Rob Herring @ 2020-05-28 23:32 UTC (permalink / raw)
  To: Manaf Meethalavalappu Pallikunhi
  Cc: Rob Herring, devicetree, Amit Kucheria, linux-kernel, Zhang Rui,
	linux-arm-msm, Andy Gross, Bjorn Andersson, Daniel Lezcano,
	linux-pm

On Fri, 22 May 2020 17:16:26 +0530, Manaf Meethalavalappu Pallikunhi wrote:
> Add cold interrupt support for tsens in yaml.
> 
> Signed-off-by: Manaf Meethalavalappu Pallikunhi <manafm@codeaurora.org>
> ---
>  .../bindings/thermal/qcom-tsens.yaml          | 42 +++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

* [PATCH v3 1/2] drivers: thermal: tsens: Add cold interrupt support
  2020-05-22 11:44 [PATCH v3 0/2] Add cold interrupt support to tsens driver Manaf Meethalavalappu Pallikunhi
@ 2020-05-22 11:44 ` Manaf Meethalavalappu Pallikunhi
  0 siblings, 0 replies; 5+ messages in thread
From: Manaf Meethalavalappu Pallikunhi @ 2020-05-22 11:44 UTC (permalink / raw)
  To: Amit Kucheria, Andy Gross, Bjorn Andersson, Zhang Rui,
	Daniel Lezcano, Rob Herring
  Cc: linux-pm, linux-arm-msm, devicetree, linux-kernel,
	Manaf Meethalavalappu Pallikunhi

TSENS IP v2.6+ adds cold interrupt support. It triggers set
interrupt when aggregated minimum temperature of all TSENS falls
below cold preset threshold, 5 degree Celsius and triggers
reset interrupt when aggregated minimum temperature of all TSENS
crosses above reset threshold, 10 degree Celsius. These threshold
values could change in boot firmware code. Add support for this
interrupt in the driver.

It adds another virtual sensor to the of-thermal along with all
individual TSENS. This cold sensor only gives cold state value of
1 or 0 for successful temperature read. A state value of 1 indicates
minimum one TSENS is in cold temperature condition and state value
of 0 indicates all TSENS are out of cold temperature condition.

Signed-off-by: Manaf Meethalavalappu Pallikunhi <manafm@codeaurora.org>
---
 drivers/thermal/qcom/tsens-v2.c |   5 ++
 drivers/thermal/qcom/tsens.c    | 112 +++++++++++++++++++++++++++++++-
 drivers/thermal/qcom/tsens.h    |  11 ++++
 3 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
index b293ed32174b..1692e636d3bd 100644
--- a/drivers/thermal/qcom/tsens-v2.c
+++ b/drivers/thermal/qcom/tsens-v2.c
@@ -23,6 +23,7 @@
 #define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020
 #define TM_Sn_CRITICAL_THRESHOLD_OFF	0x0060
 #define TM_Sn_STATUS_OFF		0x00a0
+#define TM_COLD_INT_STATUS_OFF		0x00e0
 #define TM_TRDY_OFF			0x00e4
 #define TM_WDOG_LOG_OFF		0x013c
 
@@ -86,6 +87,9 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
 	REG_FIELD_FOR_EACH_SENSOR16(CRITICAL_STATUS, TM_Sn_STATUS_OFF, 19,  19),
 	REG_FIELD_FOR_EACH_SENSOR16(MAX_STATUS,      TM_Sn_STATUS_OFF, 20,  20),
 
+	/* COLD INTERRUPT STATUS */
+	[COLD_STATUS] = REG_FIELD(TM_COLD_INT_STATUS_OFF, 0, 0),
+
 	/* TRDY: 1=ready, 0=in progress */
 	[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
 };
@@ -93,6 +97,7 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_generic_v2 = {
 	.init		= init_common,
 	.get_temp	= get_temp_tsens_valid,
+	.get_cold_status  = get_cold_int_status,
 };
 
 struct tsens_plat_data data_tsens_v2 = {
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 8d3e94d2a9ed..ee93e9d07678 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -205,7 +205,8 @@ static void tsens_set_interrupt_v1(struct tsens_priv *priv, u32 hw_id,
 		index = LOW_INT_CLEAR_0 + hw_id;
 		break;
 	case CRITICAL:
-		/* No critical interrupts before v2 */
+	case COLD:
+		/* No critical and cold interrupts before v2 */
 		return;
 	}
 	regmap_field_write(priv->rf[index], enable ? 0 : 1);
@@ -236,6 +237,9 @@ static void tsens_set_interrupt_v2(struct tsens_priv *priv, u32 hw_id,
 		index_mask  = CRIT_INT_MASK_0 + hw_id;
 		index_clear = CRIT_INT_CLEAR_0 + hw_id;
 		break;
+	case COLD:
+		/* Nothing to handle for cold interrupt */
+		return;
 	}
 
 	if (enable) {
@@ -367,6 +371,35 @@ static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
 	return 0;
 }
 
+/**
+ * tsens_cold_irq_thread - Threaded interrupt handler for cold interrupt
+ * @irq: irq number
+ * @data: tsens controller private data
+ *
+ * Whenever interrupt triggers notify thermal framework using
+ * thermal_zone_device_update().
+ *
+ * Return: IRQ_HANDLED
+ */
+
+irqreturn_t tsens_cold_irq_thread(int irq, void *data)
+{
+	struct tsens_priv *priv = data;
+	struct tsens_sensor *s = priv->cold_sensor;
+	int cold_status, ret;
+
+	ret = regmap_field_read(priv->rf[COLD_STATUS], &cold_status);
+	if (ret)
+		return ret;
+
+	dev_dbg(priv->dev, "[%u] %s: cold interrupt is %s\n",
+		s->hw_id, __func__, cold_status ? "triggered" : "cleared");
+
+	thermal_zone_device_update(s->tzd, THERMAL_EVENT_UNSPECIFIED);
+
+	return IRQ_HANDLED;
+}
+
 /**
  * tsens_critical_irq_thread() - Threaded handler for critical interrupts
  * @irq: irq number
@@ -575,6 +608,20 @@ void tsens_disable_irq(struct tsens_priv *priv)
 	regmap_field_write(priv->rf[INT_EN], 0);
 }
 
+int get_cold_int_status(const struct tsens_sensor *s, bool *cold_status)
+{
+	struct tsens_priv *priv = s->priv;
+	int prev_cold = 0, ret;
+
+	ret = regmap_field_read(priv->rf[COLD_STATUS], &prev_cold);
+	if (ret)
+		return ret;
+
+	*cold_status = (bool)prev_cold;
+
+	return 0;
+}
+
 int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
 {
 	struct tsens_priv *priv = s->priv;
@@ -843,6 +890,19 @@ int __init init_common(struct tsens_priv *priv)
 		regmap_field_write(priv->rf[CC_MON_MASK], 1);
 	}
 
+	if (tsens_version(priv) > VER_1_X &&  ver_minor > 5) {
+		/* COLD interrupt is present only on v2.6+ */
+		priv->feat->cold_int = 1;
+		priv->rf[COLD_STATUS] = devm_regmap_field_alloc(
+						dev,
+						priv->tm_map,
+						priv->fields[COLD_STATUS]);
+		if (IS_ERR(priv->rf[COLD_STATUS])) {
+			ret = PTR_ERR(priv->rf[COLD_STATUS]);
+			goto err_put_device;
+		}
+	}
+
 	spin_lock_init(&priv->ul_lock);
 	tsens_enable_irq(priv);
 	tsens_debug_init(op);
@@ -852,6 +912,30 @@ int __init init_common(struct tsens_priv *priv)
 	return ret;
 }
 
+/**
+ * tsens_get_cold_status - It gets cold temperature status of TSENS
+ * @data: tsens cold sensor private data
+ * @cold_status: pointer to store last cold interrupt status
+ *
+ * It gives cold state value of 0 or 1 on success. A state
+ * value of 1 indicates minimum one TSENS is in cold temperature
+ * condition and a state value of 0 indicates all TSENS are out of
+ * cold temperature condition.
+ *
+ * Return: 0 on success, a negative errno will be returned in
+ * error cases.
+ */
+static int tsens_get_cold_status(void *data, int *cold_status)
+{
+	struct tsens_sensor *s = data;
+	struct tsens_priv *priv = s->priv;
+
+	if (priv->ops->get_cold_status)
+		return priv->ops->get_cold_status(s, (bool *)cold_status);
+
+	return -ENOTSUPP;
+}
+
 static int tsens_get_temp(void *data, int *temp)
 {
 	struct tsens_sensor *s = data;
@@ -923,6 +1007,10 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = {
 	.set_trips = tsens_set_trips,
 };
 
+static const struct thermal_zone_of_device_ops tsens_cold_of_ops = {
+	.get_temp = tsens_get_cold_status,
+};
+
 static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
 			      irq_handler_t thread_fn)
 {
@@ -980,6 +1068,28 @@ static int tsens_register(struct tsens_priv *priv)
 		ret = tsens_register_irq(priv, "critical",
 					 tsens_critical_irq_thread);
 
+	if (priv->feat->cold_int) {
+		priv->cold_sensor = devm_kzalloc(priv->dev,
+					sizeof(struct tsens_sensor),
+					GFP_KERNEL);
+		if (!priv->cold_sensor)
+			return -ENOMEM;
+
+		priv->cold_sensor->hw_id = COLD_SENSOR_HW_ID;
+		priv->cold_sensor->priv = priv;
+		tzd = devm_thermal_zone_of_sensor_register(priv->dev,
+					priv->cold_sensor->hw_id,
+					priv->cold_sensor,
+					&tsens_cold_of_ops);
+		if (IS_ERR(tzd)) {
+			ret = 0;
+			return ret;
+		}
+
+		priv->cold_sensor->tzd = tzd;
+		ret = tsens_register_irq(priv, "cold", tsens_cold_irq_thread);
+	}
+
 	return ret;
 }
 
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 59d01162c66a..be532fabef30 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -15,6 +15,7 @@
 #define SLOPE_DEFAULT		3200
 #define THRESHOLD_MAX_ADC_CODE	0x3ff
 #define THRESHOLD_MIN_ADC_CODE	0x0
+#define COLD_SENSOR_HW_ID	128
 
 #include <linux/interrupt.h>
 #include <linux/thermal.h>
@@ -34,6 +35,7 @@ enum tsens_irq_type {
 	LOWER,
 	UPPER,
 	CRITICAL,
+	COLD,
 };
 
 /**
@@ -64,6 +66,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
+ * @get_cold_status: Function to get the cold interrupt status
  */
 struct tsens_ops {
 	/* mandatory callbacks */
@@ -76,6 +79,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 (*get_cold_status)(const struct tsens_sensor *s, bool *cold_status);
 };
 
 #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
@@ -485,6 +489,8 @@ enum regfield_ids {
 	MAX_STATUS_14,
 	MAX_STATUS_15,
 
+	COLD_STATUS,		/* COLD interrupt status */
+
 	/* Keep last */
 	MAX_REGFIELDS
 };
@@ -497,6 +503,7 @@ enum regfield_ids {
  * @srot_split: does the IP neatly splits the register space into SROT and TM,
  *              with SROT only being available to secure boot firmware?
  * @has_watchdog: does this IP support watchdog functionality?
+ * @cold_int: does this IP support COLD interrupt ?
  * @max_sensors: maximum sensors supported by this version of the IP
  */
 struct tsens_features {
@@ -505,6 +512,7 @@ struct tsens_features {
 	unsigned int adc:1;
 	unsigned int srot_split:1;
 	unsigned int has_watchdog:1;
+	unsigned int cold_int:1;
 	unsigned int max_sensors;
 };
 
@@ -551,6 +559,7 @@ struct tsens_context {
  * @ops: pointer to list of callbacks supported by this device
  * @debug_root: pointer to debugfs dentry for all tsens
  * @debug: pointer to debugfs dentry for tsens controller
+ * @cold_sensor: pointer to cold sensor attached to this device
  * @sensor: list of sensors attached to this device
  */
 struct tsens_priv {
@@ -571,6 +580,7 @@ struct tsens_priv {
 
 	struct dentry			*debug_root;
 	struct dentry			*debug;
+	struct tsens_sensor		*cold_sensor;
 
 	struct tsens_sensor		sensor[];
 };
@@ -580,6 +590,7 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mo
 int init_common(struct tsens_priv *priv);
 int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp);
 int get_temp_common(const struct tsens_sensor *s, int *temp);
+int get_cold_int_status(const struct tsens_sensor *s, bool *cold_status);
 
 /* TSENS target */
 extern struct tsens_plat_data data_8960;
-- 
2.26.2

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

end of thread, other threads:[~2020-05-28 23:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-22 11:46 [PATCH v3 0/2] Add cold interrupt support to tsens driver Manaf Meethalavalappu Pallikunhi
2020-05-22 11:46 ` [PATCH v3 1/2] drivers: thermal: tsens: Add cold interrupt support Manaf Meethalavalappu Pallikunhi
2020-05-22 11:46 ` [PATCH v3 2/2] dt-bindings: thermal: tsens: Add cold interrupt support in yaml Manaf Meethalavalappu Pallikunhi
2020-05-28 23:32   ` Rob Herring
  -- strict thread matches above, loose matches on Subject: below --
2020-05-22 11:44 [PATCH v3 0/2] Add cold interrupt support to tsens driver Manaf Meethalavalappu Pallikunhi
2020-05-22 11:44 ` [PATCH v3 1/2] drivers: thermal: tsens: Add cold interrupt support Manaf Meethalavalappu Pallikunhi

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).