All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:27 ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki
  Cc: Markus Mayer, Broadcom Kernel List, Power Management List,
	Device Tree List, ARM Kernel List, Linux Kernel Mailing List

From: Markus Mayer <mmayer@broadcom.com>

This series adds the brcmstb AVS TMON driver.

The driver was originally written by Brian Norris.

Changes since v4:
- disable trip points properly when needed; there was code left-over
  from an older iteration of this driver that used long ints, which
  resulted in code that was incorrect now that we are using ints
- rebased on v4.14-rc1
- patches 3 & 4 (turning on CONFIG_BRCMSTB_THERMAL for arm/arm64) are no
  longer part of the series, because they were already picked up for 4.14

Changes since v3:
- Rebased on v4.13-rc3 to resolve conflicts in the MAINTAINERS file

Changes since v2:
- replaced calls to pr_debug() with calls to dev_dbg() [PATCH 2/4 only]
- all other patches are unchanged from v2

Changes since v1:
- Fixed wording in binding document
- Fixed lincensing to consistently mention GPL v2
- Use thermal_zone_get_slope() and thermal_zone_get_offset()
- Some minor clean-ups

Brian Norris (2):
  Documentation: devicetree: add binding for Broadcom STB AVS TMON
  thermal: add brcmstb AVS TMON driver

 .../devicetree/bindings/thermal/brcm,avs-tmon.txt  |  20 ++
 MAINTAINERS                                        |   8 +
 drivers/thermal/Kconfig                            |   2 +-
 drivers/thermal/broadcom/Kconfig                   |   7 +
 drivers/thermal/broadcom/Makefile                  |   1 +
 drivers/thermal/broadcom/brcmstb_thermal.c         | 387 +++++++++++++++++++++
 6 files changed, 424 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
 create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c

-- 
2.7.4

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

* [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:27 ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki
  Cc: Markus Mayer, Broadcom Kernel List, Power Management List,
	Device Tree List, ARM Kernel List, Linux Kernel Mailing List

From: Markus Mayer <mmayer-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

This series adds the brcmstb AVS TMON driver.

The driver was originally written by Brian Norris.

Changes since v4:
- disable trip points properly when needed; there was code left-over
  from an older iteration of this driver that used long ints, which
  resulted in code that was incorrect now that we are using ints
- rebased on v4.14-rc1
- patches 3 & 4 (turning on CONFIG_BRCMSTB_THERMAL for arm/arm64) are no
  longer part of the series, because they were already picked up for 4.14

Changes since v3:
- Rebased on v4.13-rc3 to resolve conflicts in the MAINTAINERS file

Changes since v2:
- replaced calls to pr_debug() with calls to dev_dbg() [PATCH 2/4 only]
- all other patches are unchanged from v2

Changes since v1:
- Fixed wording in binding document
- Fixed lincensing to consistently mention GPL v2
- Use thermal_zone_get_slope() and thermal_zone_get_offset()
- Some minor clean-ups

Brian Norris (2):
  Documentation: devicetree: add binding for Broadcom STB AVS TMON
  thermal: add brcmstb AVS TMON driver

 .../devicetree/bindings/thermal/brcm,avs-tmon.txt  |  20 ++
 MAINTAINERS                                        |   8 +
 drivers/thermal/Kconfig                            |   2 +-
 drivers/thermal/broadcom/Kconfig                   |   7 +
 drivers/thermal/broadcom/Makefile                  |   1 +
 drivers/thermal/broadcom/brcmstb_thermal.c         | 387 +++++++++++++++++++++
 6 files changed, 424 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
 create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c

-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:27 ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

From: Markus Mayer <mmayer@broadcom.com>

This series adds the brcmstb AVS TMON driver.

The driver was originally written by Brian Norris.

Changes since v4:
- disable trip points properly when needed; there was code left-over
  from an older iteration of this driver that used long ints, which
  resulted in code that was incorrect now that we are using ints
- rebased on v4.14-rc1
- patches 3 & 4 (turning on CONFIG_BRCMSTB_THERMAL for arm/arm64) are no
  longer part of the series, because they were already picked up for 4.14

Changes since v3:
- Rebased on v4.13-rc3 to resolve conflicts in the MAINTAINERS file

Changes since v2:
- replaced calls to pr_debug() with calls to dev_dbg() [PATCH 2/4 only]
- all other patches are unchanged from v2

Changes since v1:
- Fixed wording in binding document
- Fixed lincensing to consistently mention GPL v2
- Use thermal_zone_get_slope() and thermal_zone_get_offset()
- Some minor clean-ups

Brian Norris (2):
  Documentation: devicetree: add binding for Broadcom STB AVS TMON
  thermal: add brcmstb AVS TMON driver

 .../devicetree/bindings/thermal/brcm,avs-tmon.txt  |  20 ++
 MAINTAINERS                                        |   8 +
 drivers/thermal/Kconfig                            |   2 +-
 drivers/thermal/broadcom/Kconfig                   |   7 +
 drivers/thermal/broadcom/Makefile                  |   1 +
 drivers/thermal/broadcom/brcmstb_thermal.c         | 387 +++++++++++++++++++++
 6 files changed, 424 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
 create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c

-- 
2.7.4

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

* [PATCH v5 1/2] Documentation: devicetree: add binding for Broadcom STB AVS TMON
  2017-09-26 21:27 ` Markus Mayer
@ 2017-09-26 21:27   ` Markus Mayer
  -1 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki
  Cc: Broadcom Kernel List, Power Management List, Device Tree List,
	ARM Kernel List, Linux Kernel Mailing List, Markus Mayer

From: Brian Norris <computersforpeace@gmail.com>

Add binding for Broadcom STB thermal.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Markus Mayer <mmayer@broadcom.com>
---
 .../devicetree/bindings/thermal/brcm,avs-tmon.txt    | 20 ++++++++++++++++++++
 MAINTAINERS                                          |  8 ++++++++
 2 files changed, 28 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt

diff --git a/Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt b/Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
new file mode 100644
index 0000000..9d43553
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
@@ -0,0 +1,20 @@
+* Broadcom STB thermal management
+
+Thermal management core, provided by the AVS TMON hardware block.
+
+Required properties:
+- compatible: must be "brcm,avs-tmon" and/or "brcm,avs-tmon-bcm7445"
+- reg: address range for the AVS TMON registers
+- interrupts: temperature monitor interrupt, for high/low threshold triggers
+- interrupt-names: should be "tmon"
+- interrupt-parent: the parent interrupt controller
+
+Example:
+
+	thermal@f04d1500 {
+		compatible = "brcm,avs-tmon-bcm7445", "brcm,avs-tmon";
+		reg = <0xf04d1500 0x28>;
+		interrupts = <0x6>;
+		interrupt-names = "tmon";
+		interrupt-parent = <&avs_host_l2_intc>;
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index 2281af4..46c592b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2955,6 +2955,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
 F:	drivers/cpufreq/brcmstb*
 
+BROADCOM STB AVS TMON DRIVER
+M:	Markus Mayer <mmayer@broadcom.com>
+M:	bcm-kernel-feedback-list@broadcom.com
+L:	linux-pm@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
+F:	drivers/thermal/broadcom/brcmstb*
+
 BROADCOM STB NAND FLASH DRIVER
 M:	Brian Norris <computersforpeace@gmail.com>
 M:	Kamal Dasu <kdasu.kdev@gmail.com>
-- 
2.7.4

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

* [PATCH v5 1/2] Documentation: devicetree: add binding for Broadcom STB AVS TMON
@ 2017-09-26 21:27   ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

From: Brian Norris <computersforpeace@gmail.com>

Add binding for Broadcom STB thermal.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Markus Mayer <mmayer@broadcom.com>
---
 .../devicetree/bindings/thermal/brcm,avs-tmon.txt    | 20 ++++++++++++++++++++
 MAINTAINERS                                          |  8 ++++++++
 2 files changed, 28 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt

diff --git a/Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt b/Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
new file mode 100644
index 0000000..9d43553
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
@@ -0,0 +1,20 @@
+* Broadcom STB thermal management
+
+Thermal management core, provided by the AVS TMON hardware block.
+
+Required properties:
+- compatible: must be "brcm,avs-tmon" and/or "brcm,avs-tmon-bcm7445"
+- reg: address range for the AVS TMON registers
+- interrupts: temperature monitor interrupt, for high/low threshold triggers
+- interrupt-names: should be "tmon"
+- interrupt-parent: the parent interrupt controller
+
+Example:
+
+	thermal at f04d1500 {
+		compatible = "brcm,avs-tmon-bcm7445", "brcm,avs-tmon";
+		reg = <0xf04d1500 0x28>;
+		interrupts = <0x6>;
+		interrupt-names = "tmon";
+		interrupt-parent = <&avs_host_l2_intc>;
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index 2281af4..46c592b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2955,6 +2955,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
 F:	drivers/cpufreq/brcmstb*
 
+BROADCOM STB AVS TMON DRIVER
+M:	Markus Mayer <mmayer@broadcom.com>
+M:	bcm-kernel-feedback-list at broadcom.com
+L:	linux-pm at vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
+F:	drivers/thermal/broadcom/brcmstb*
+
 BROADCOM STB NAND FLASH DRIVER
 M:	Brian Norris <computersforpeace@gmail.com>
 M:	Kamal Dasu <kdasu.kdev@gmail.com>
-- 
2.7.4

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:27   ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki
  Cc: Broadcom Kernel List, Power Management List, Device Tree List,
	ARM Kernel List, Linux Kernel Mailing List, Markus Mayer

From: Brian Norris <computersforpeace@gmail.com>

The AVS TMON core provides temperature readings, a pair of configurable
high- and low-temperature threshold interrupts, and an emergency
over-temperature chip reset. The driver utilizes the first two to
provide temperature readings and high-temperature notifications to
applications. The over-temperature reset is not exposed to
applications; this reset threshold is critical to the system and should
be set with care within the bootloader.

Applications may choose to utilize the notification mechanism, the
temperature reading mechanism (e.g., through polling), or both.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Doug Berger <opendmb@gmail.com>
Signed-off-by: Markus Mayer <mmayer@broadcom.com>
---
 drivers/thermal/Kconfig                    |   2 +-
 drivers/thermal/broadcom/Kconfig           |   7 +
 drivers/thermal/broadcom/Makefile          |   1 +
 drivers/thermal/broadcom/brcmstb_thermal.c | 387 +++++++++++++++++++++++++++++
 4 files changed, 396 insertions(+), 1 deletion(-)
 create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 07002df..96774a7 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -408,7 +408,7 @@ config MTK_THERMAL
 	  controller present in Mediatek SoCs
 
 menu "Broadcom thermal drivers"
-depends on ARCH_BCM || COMPILE_TEST
+depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
 source "drivers/thermal/broadcom/Kconfig"
 endmenu
 
diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig
index 42c098e..c106a15 100644
--- a/drivers/thermal/broadcom/Kconfig
+++ b/drivers/thermal/broadcom/Kconfig
@@ -6,6 +6,13 @@ config BCM2835_THERMAL
 	help
 	  Support for thermal sensors on Broadcom bcm2835 SoCs.
 
+config BRCMSTB_THERMAL
+	tristate "Broadcom STB AVS TMON thermal driver"
+	depends on ARCH_BRCMSTB || COMPILE_TEST
+	help
+	  Enable this driver if you have a Broadcom STB SoC and would like
+	  thermal framework support.
+
 config BCM_NS_THERMAL
 	tristate "Northstar thermal driver"
 	depends on ARCH_BCM_IPROC || COMPILE_TEST
diff --git a/drivers/thermal/broadcom/Makefile b/drivers/thermal/broadcom/Makefile
index c6f62e4..fae10ec 100644
--- a/drivers/thermal/broadcom/Makefile
+++ b/drivers/thermal/broadcom/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_BCM2835_THERMAL)		+= bcm2835_thermal.o
+obj-$(CONFIG_BRCMSTB_THERMAL)		+= brcmstb_thermal.o
 obj-$(CONFIG_BCM_NS_THERMAL)		+= ns-thermal.o
diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c
new file mode 100644
index 0000000..1919f91
--- /dev/null
+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
@@ -0,0 +1,387 @@
+/*
+ * Broadcom STB AVS TMON thermal sensor driver
+ *
+ * Copyright (c) 2015-2017 Broadcom
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define DRV_NAME	"brcmstb_thermal"
+
+#define pr_fmt(fmt)	DRV_NAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/thermal.h>
+
+#define AVS_TMON_STATUS			0x00
+ #define AVS_TMON_STATUS_valid_msk	BIT(11)
+ #define AVS_TMON_STATUS_data_msk	GENMASK(10, 1)
+ #define AVS_TMON_STATUS_data_shift	1
+
+#define AVS_TMON_EN_OVERTEMP_RESET	0x04
+ #define AVS_TMON_EN_OVERTEMP_RESET_msk	BIT(0)
+
+#define AVS_TMON_RESET_THRESH		0x08
+ #define AVS_TMON_RESET_THRESH_msk	GENMASK(10, 1)
+ #define AVS_TMON_RESET_THRESH_shift	1
+
+#define AVS_TMON_INT_IDLE_TIME		0x10
+
+#define AVS_TMON_EN_TEMP_INT_SRCS	0x14
+ #define AVS_TMON_EN_TEMP_INT_SRCS_high	BIT(1)
+ #define AVS_TMON_EN_TEMP_INT_SRCS_low	BIT(0)
+
+#define AVS_TMON_INT_THRESH		0x18
+ #define AVS_TMON_INT_THRESH_high_msk	GENMASK(26, 17)
+ #define AVS_TMON_INT_THRESH_high_shift	17
+ #define AVS_TMON_INT_THRESH_low_msk	GENMASK(10, 1)
+ #define AVS_TMON_INT_THRESH_low_shift	1
+
+#define AVS_TMON_TEMP_INT_CODE		0x1c
+#define AVS_TMON_TP_TEST_ENABLE		0x20
+
+/* Default coefficients */
+#define AVS_TMON_TEMP_SLOPE		-487
+#define AVS_TMON_TEMP_OFFSET		410040
+
+/* HW related temperature constants */
+#define AVS_TMON_TEMP_MAX		0x3ff
+#define AVS_TMON_TEMP_MIN		-88161
+#define AVS_TMON_TEMP_MASK		AVS_TMON_TEMP_MAX
+
+enum avs_tmon_trip_type {
+	TMON_TRIP_TYPE_LOW = 0,
+	TMON_TRIP_TYPE_HIGH,
+	TMON_TRIP_TYPE_RESET,
+	TMON_TRIP_TYPE_MAX,
+};
+
+struct avs_tmon_trip {
+	/* HW bit to enable the trip */
+	u32 enable_offs;
+	u32 enable_mask;
+
+	/* HW field to read the trip temperature */
+	u32 reg_offs;
+	u32 reg_msk;
+	int reg_shift;
+};
+
+static struct avs_tmon_trip avs_tmon_trips[] = {
+	/* Trips when temperature is below threshold */
+	[TMON_TRIP_TYPE_LOW] = {
+		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
+		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_low,
+		.reg_offs	= AVS_TMON_INT_THRESH,
+		.reg_msk	= AVS_TMON_INT_THRESH_low_msk,
+		.reg_shift	= AVS_TMON_INT_THRESH_low_shift,
+	},
+	/* Trips when temperature is above threshold */
+	[TMON_TRIP_TYPE_HIGH] = {
+		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
+		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_high,
+		.reg_offs	= AVS_TMON_INT_THRESH,
+		.reg_msk	= AVS_TMON_INT_THRESH_high_msk,
+		.reg_shift	= AVS_TMON_INT_THRESH_high_shift,
+	},
+	/* Automatically resets chip when above threshold */
+	[TMON_TRIP_TYPE_RESET] = {
+		.enable_offs	= AVS_TMON_EN_OVERTEMP_RESET,
+		.enable_mask	= AVS_TMON_EN_OVERTEMP_RESET_msk,
+		.reg_offs	= AVS_TMON_RESET_THRESH,
+		.reg_msk	= AVS_TMON_RESET_THRESH_msk,
+		.reg_shift	= AVS_TMON_RESET_THRESH_shift,
+	},
+};
+
+struct brcmstb_thermal_priv {
+	void __iomem *tmon_base;
+	struct device *dev;
+	struct thermal_zone_device *thermal;
+};
+
+static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
+				int *offset)
+{
+	*slope = thermal_zone_get_slope(tz);
+	*offset = thermal_zone_get_offset(tz);
+}
+
+/* Convert a HW code to a temperature reading (millidegree celsius) */
+static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
+					u32 code)
+{
+	const int val = code & AVS_TMON_TEMP_MASK;
+	int slope, offset;
+
+	avs_tmon_get_coeffs(tz, &slope, &offset);
+
+	return slope * val + offset;
+}
+
+/*
+ * Convert a temperature value (millidegree celsius) to a HW code
+ *
+ * @temp: temperature to convert
+ * @low: if true, round toward the low side
+ */
+static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
+					int temp, bool low)
+{
+	int slope, offset;
+
+	if (temp < AVS_TMON_TEMP_MIN)
+		return AVS_TMON_TEMP_MAX; /* Maximum code value */
+
+	avs_tmon_get_coeffs(tz, &slope, &offset);
+
+	if (temp >= offset)
+		return 0;	/* Minimum code value */
+
+	if (low)
+		return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
+	else
+		return (u32)((offset - temp) / abs(slope));
+}
+
+static int brcmstb_get_temp(void *data, int *temp)
+{
+	struct brcmstb_thermal_priv *priv = data;
+	u32 val;
+	long t;
+
+	val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
+
+	if (!(val & AVS_TMON_STATUS_valid_msk)) {
+		dev_err(priv->dev, "reading not valid\n");
+		return -EIO;
+	}
+
+	val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
+
+	t = avs_tmon_code_to_temp(priv->thermal, val);
+	if (t < 0)
+		*temp = 0;
+	else
+		*temp = t;
+
+	return 0;
+}
+
+static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
+				 enum avs_tmon_trip_type type, int en)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
+
+	dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis", type);
+
+	if (en)
+		val |= trip->enable_mask;
+	else
+		val &= ~trip->enable_mask;
+
+	__raw_writel(val, priv->tmon_base + trip->enable_offs);
+}
+
+static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
+				  enum avs_tmon_trip_type type)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
+
+	val &= trip->reg_msk;
+	val >>= trip->reg_shift;
+
+	return avs_tmon_code_to_temp(priv->thermal, val);
+}
+
+static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
+				   enum avs_tmon_trip_type type,
+				   int temp)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val, orig;
+
+	dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
+
+	/* round toward low temp for the low interrupt */
+	val = avs_tmon_temp_to_code(priv->thermal, temp,
+				    type == TMON_TRIP_TYPE_LOW);
+
+	val <<= trip->reg_shift;
+	val &= trip->reg_msk;
+
+	orig = __raw_readl(priv->tmon_base + trip->reg_offs);
+	orig &= ~trip->reg_msk;
+	orig |= val;
+	__raw_writel(orig, priv->tmon_base + trip->reg_offs);
+}
+
+static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
+{
+	u32 val;
+
+	val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
+	return avs_tmon_code_to_temp(priv->thermal, val);
+}
+
+static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
+{
+	struct brcmstb_thermal_priv *priv = data;
+	int low, high, intr;
+
+	low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
+	high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
+	intr = avs_tmon_get_intr_temp(priv);
+
+	dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
+			low, intr, high);
+
+	/* Disable high-temp until next threshold shift */
+	if (intr >= high)
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
+	/* Disable low-temp until next threshold shift */
+	if (intr <= low)
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
+
+	/*
+	 * Notify using the interrupt temperature, in case the temperature
+	 * changes before it can next be read out
+	 */
+	thermal_zone_device_update(priv->thermal, intr);
+
+	return IRQ_HANDLED;
+}
+
+static int brcmstb_set_trips(void *data, int low, int high)
+{
+	struct brcmstb_thermal_priv *priv = data;
+
+	dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
+
+	/*
+	 * Disable low-temp if "low" is too small. As per thermal framework
+	 * API, we use -INT_MAX rather than INT_MIN.
+	 */
+	if (low <= -INT_MAX) {
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
+	} else {
+		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
+	}
+
+	/* Disable high-temp if "high" is too big. */
+	if (high == INT_MAX) {
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
+	} else {
+		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
+	}
+
+	return 0;
+}
+
+static struct thermal_zone_of_device_ops of_ops = {
+	.get_temp	= brcmstb_get_temp,
+	.set_trips	= brcmstb_set_trips,
+};
+
+static const struct of_device_id brcmstb_thermal_id_table[] = {
+	{ .compatible = "brcm,avs-tmon" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
+
+static int brcmstb_thermal_probe(struct platform_device *pdev)
+{
+	struct thermal_zone_device *thermal;
+	struct brcmstb_thermal_priv *priv;
+	struct resource *res;
+	int irq, ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->tmon_base))
+		return PTR_ERR(priv->tmon_base);
+
+	priv->dev = &pdev->dev;
+	platform_set_drvdata(pdev, priv);
+
+	thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
+	if (IS_ERR(thermal)) {
+		ret = PTR_ERR(thermal);
+		dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
+		return ret;
+	}
+
+	priv->thermal = thermal;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "could not get IRQ\n");
+		ret = irq;
+		goto err;
+	}
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					brcmstb_tmon_irq_thread, IRQF_ONESHOT,
+					DRV_NAME, priv);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
+		goto err;
+	}
+
+	dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
+
+	return 0;
+
+err:
+	thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
+	return ret;
+}
+
+static int brcmstb_thermal_exit(struct platform_device *pdev)
+{
+	struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
+	struct thermal_zone_device *thermal = priv->thermal;
+
+	if (thermal)
+		thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
+
+	return 0;
+}
+
+static struct platform_driver brcmstb_thermal_driver = {
+	.probe = brcmstb_thermal_probe,
+	.remove = brcmstb_thermal_exit,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = brcmstb_thermal_id_table,
+	},
+};
+module_platform_driver(brcmstb_thermal_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
-- 
2.7.4

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:27   ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki
  Cc: Broadcom Kernel List, Power Management List, Device Tree List,
	ARM Kernel List, Linux Kernel Mailing List, Markus Mayer

From: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

The AVS TMON core provides temperature readings, a pair of configurable
high- and low-temperature threshold interrupts, and an emergency
over-temperature chip reset. The driver utilizes the first two to
provide temperature readings and high-temperature notifications to
applications. The over-temperature reset is not exposed to
applications; this reset threshold is critical to the system and should
be set with care within the bootloader.

Applications may choose to utilize the notification mechanism, the
temperature reading mechanism (e.g., through polling), or both.

Signed-off-by: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Doug Berger <opendmb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Markus Mayer <mmayer-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/thermal/Kconfig                    |   2 +-
 drivers/thermal/broadcom/Kconfig           |   7 +
 drivers/thermal/broadcom/Makefile          |   1 +
 drivers/thermal/broadcom/brcmstb_thermal.c | 387 +++++++++++++++++++++++++++++
 4 files changed, 396 insertions(+), 1 deletion(-)
 create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 07002df..96774a7 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -408,7 +408,7 @@ config MTK_THERMAL
 	  controller present in Mediatek SoCs
 
 menu "Broadcom thermal drivers"
-depends on ARCH_BCM || COMPILE_TEST
+depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
 source "drivers/thermal/broadcom/Kconfig"
 endmenu
 
diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig
index 42c098e..c106a15 100644
--- a/drivers/thermal/broadcom/Kconfig
+++ b/drivers/thermal/broadcom/Kconfig
@@ -6,6 +6,13 @@ config BCM2835_THERMAL
 	help
 	  Support for thermal sensors on Broadcom bcm2835 SoCs.
 
+config BRCMSTB_THERMAL
+	tristate "Broadcom STB AVS TMON thermal driver"
+	depends on ARCH_BRCMSTB || COMPILE_TEST
+	help
+	  Enable this driver if you have a Broadcom STB SoC and would like
+	  thermal framework support.
+
 config BCM_NS_THERMAL
 	tristate "Northstar thermal driver"
 	depends on ARCH_BCM_IPROC || COMPILE_TEST
diff --git a/drivers/thermal/broadcom/Makefile b/drivers/thermal/broadcom/Makefile
index c6f62e4..fae10ec 100644
--- a/drivers/thermal/broadcom/Makefile
+++ b/drivers/thermal/broadcom/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_BCM2835_THERMAL)		+= bcm2835_thermal.o
+obj-$(CONFIG_BRCMSTB_THERMAL)		+= brcmstb_thermal.o
 obj-$(CONFIG_BCM_NS_THERMAL)		+= ns-thermal.o
diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c
new file mode 100644
index 0000000..1919f91
--- /dev/null
+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
@@ -0,0 +1,387 @@
+/*
+ * Broadcom STB AVS TMON thermal sensor driver
+ *
+ * Copyright (c) 2015-2017 Broadcom
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define DRV_NAME	"brcmstb_thermal"
+
+#define pr_fmt(fmt)	DRV_NAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/thermal.h>
+
+#define AVS_TMON_STATUS			0x00
+ #define AVS_TMON_STATUS_valid_msk	BIT(11)
+ #define AVS_TMON_STATUS_data_msk	GENMASK(10, 1)
+ #define AVS_TMON_STATUS_data_shift	1
+
+#define AVS_TMON_EN_OVERTEMP_RESET	0x04
+ #define AVS_TMON_EN_OVERTEMP_RESET_msk	BIT(0)
+
+#define AVS_TMON_RESET_THRESH		0x08
+ #define AVS_TMON_RESET_THRESH_msk	GENMASK(10, 1)
+ #define AVS_TMON_RESET_THRESH_shift	1
+
+#define AVS_TMON_INT_IDLE_TIME		0x10
+
+#define AVS_TMON_EN_TEMP_INT_SRCS	0x14
+ #define AVS_TMON_EN_TEMP_INT_SRCS_high	BIT(1)
+ #define AVS_TMON_EN_TEMP_INT_SRCS_low	BIT(0)
+
+#define AVS_TMON_INT_THRESH		0x18
+ #define AVS_TMON_INT_THRESH_high_msk	GENMASK(26, 17)
+ #define AVS_TMON_INT_THRESH_high_shift	17
+ #define AVS_TMON_INT_THRESH_low_msk	GENMASK(10, 1)
+ #define AVS_TMON_INT_THRESH_low_shift	1
+
+#define AVS_TMON_TEMP_INT_CODE		0x1c
+#define AVS_TMON_TP_TEST_ENABLE		0x20
+
+/* Default coefficients */
+#define AVS_TMON_TEMP_SLOPE		-487
+#define AVS_TMON_TEMP_OFFSET		410040
+
+/* HW related temperature constants */
+#define AVS_TMON_TEMP_MAX		0x3ff
+#define AVS_TMON_TEMP_MIN		-88161
+#define AVS_TMON_TEMP_MASK		AVS_TMON_TEMP_MAX
+
+enum avs_tmon_trip_type {
+	TMON_TRIP_TYPE_LOW = 0,
+	TMON_TRIP_TYPE_HIGH,
+	TMON_TRIP_TYPE_RESET,
+	TMON_TRIP_TYPE_MAX,
+};
+
+struct avs_tmon_trip {
+	/* HW bit to enable the trip */
+	u32 enable_offs;
+	u32 enable_mask;
+
+	/* HW field to read the trip temperature */
+	u32 reg_offs;
+	u32 reg_msk;
+	int reg_shift;
+};
+
+static struct avs_tmon_trip avs_tmon_trips[] = {
+	/* Trips when temperature is below threshold */
+	[TMON_TRIP_TYPE_LOW] = {
+		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
+		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_low,
+		.reg_offs	= AVS_TMON_INT_THRESH,
+		.reg_msk	= AVS_TMON_INT_THRESH_low_msk,
+		.reg_shift	= AVS_TMON_INT_THRESH_low_shift,
+	},
+	/* Trips when temperature is above threshold */
+	[TMON_TRIP_TYPE_HIGH] = {
+		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
+		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_high,
+		.reg_offs	= AVS_TMON_INT_THRESH,
+		.reg_msk	= AVS_TMON_INT_THRESH_high_msk,
+		.reg_shift	= AVS_TMON_INT_THRESH_high_shift,
+	},
+	/* Automatically resets chip when above threshold */
+	[TMON_TRIP_TYPE_RESET] = {
+		.enable_offs	= AVS_TMON_EN_OVERTEMP_RESET,
+		.enable_mask	= AVS_TMON_EN_OVERTEMP_RESET_msk,
+		.reg_offs	= AVS_TMON_RESET_THRESH,
+		.reg_msk	= AVS_TMON_RESET_THRESH_msk,
+		.reg_shift	= AVS_TMON_RESET_THRESH_shift,
+	},
+};
+
+struct brcmstb_thermal_priv {
+	void __iomem *tmon_base;
+	struct device *dev;
+	struct thermal_zone_device *thermal;
+};
+
+static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
+				int *offset)
+{
+	*slope = thermal_zone_get_slope(tz);
+	*offset = thermal_zone_get_offset(tz);
+}
+
+/* Convert a HW code to a temperature reading (millidegree celsius) */
+static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
+					u32 code)
+{
+	const int val = code & AVS_TMON_TEMP_MASK;
+	int slope, offset;
+
+	avs_tmon_get_coeffs(tz, &slope, &offset);
+
+	return slope * val + offset;
+}
+
+/*
+ * Convert a temperature value (millidegree celsius) to a HW code
+ *
+ * @temp: temperature to convert
+ * @low: if true, round toward the low side
+ */
+static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
+					int temp, bool low)
+{
+	int slope, offset;
+
+	if (temp < AVS_TMON_TEMP_MIN)
+		return AVS_TMON_TEMP_MAX; /* Maximum code value */
+
+	avs_tmon_get_coeffs(tz, &slope, &offset);
+
+	if (temp >= offset)
+		return 0;	/* Minimum code value */
+
+	if (low)
+		return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
+	else
+		return (u32)((offset - temp) / abs(slope));
+}
+
+static int brcmstb_get_temp(void *data, int *temp)
+{
+	struct brcmstb_thermal_priv *priv = data;
+	u32 val;
+	long t;
+
+	val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
+
+	if (!(val & AVS_TMON_STATUS_valid_msk)) {
+		dev_err(priv->dev, "reading not valid\n");
+		return -EIO;
+	}
+
+	val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
+
+	t = avs_tmon_code_to_temp(priv->thermal, val);
+	if (t < 0)
+		*temp = 0;
+	else
+		*temp = t;
+
+	return 0;
+}
+
+static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
+				 enum avs_tmon_trip_type type, int en)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
+
+	dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis", type);
+
+	if (en)
+		val |= trip->enable_mask;
+	else
+		val &= ~trip->enable_mask;
+
+	__raw_writel(val, priv->tmon_base + trip->enable_offs);
+}
+
+static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
+				  enum avs_tmon_trip_type type)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
+
+	val &= trip->reg_msk;
+	val >>= trip->reg_shift;
+
+	return avs_tmon_code_to_temp(priv->thermal, val);
+}
+
+static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
+				   enum avs_tmon_trip_type type,
+				   int temp)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val, orig;
+
+	dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
+
+	/* round toward low temp for the low interrupt */
+	val = avs_tmon_temp_to_code(priv->thermal, temp,
+				    type == TMON_TRIP_TYPE_LOW);
+
+	val <<= trip->reg_shift;
+	val &= trip->reg_msk;
+
+	orig = __raw_readl(priv->tmon_base + trip->reg_offs);
+	orig &= ~trip->reg_msk;
+	orig |= val;
+	__raw_writel(orig, priv->tmon_base + trip->reg_offs);
+}
+
+static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
+{
+	u32 val;
+
+	val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
+	return avs_tmon_code_to_temp(priv->thermal, val);
+}
+
+static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
+{
+	struct brcmstb_thermal_priv *priv = data;
+	int low, high, intr;
+
+	low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
+	high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
+	intr = avs_tmon_get_intr_temp(priv);
+
+	dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
+			low, intr, high);
+
+	/* Disable high-temp until next threshold shift */
+	if (intr >= high)
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
+	/* Disable low-temp until next threshold shift */
+	if (intr <= low)
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
+
+	/*
+	 * Notify using the interrupt temperature, in case the temperature
+	 * changes before it can next be read out
+	 */
+	thermal_zone_device_update(priv->thermal, intr);
+
+	return IRQ_HANDLED;
+}
+
+static int brcmstb_set_trips(void *data, int low, int high)
+{
+	struct brcmstb_thermal_priv *priv = data;
+
+	dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
+
+	/*
+	 * Disable low-temp if "low" is too small. As per thermal framework
+	 * API, we use -INT_MAX rather than INT_MIN.
+	 */
+	if (low <= -INT_MAX) {
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
+	} else {
+		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
+	}
+
+	/* Disable high-temp if "high" is too big. */
+	if (high == INT_MAX) {
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
+	} else {
+		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
+	}
+
+	return 0;
+}
+
+static struct thermal_zone_of_device_ops of_ops = {
+	.get_temp	= brcmstb_get_temp,
+	.set_trips	= brcmstb_set_trips,
+};
+
+static const struct of_device_id brcmstb_thermal_id_table[] = {
+	{ .compatible = "brcm,avs-tmon" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
+
+static int brcmstb_thermal_probe(struct platform_device *pdev)
+{
+	struct thermal_zone_device *thermal;
+	struct brcmstb_thermal_priv *priv;
+	struct resource *res;
+	int irq, ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->tmon_base))
+		return PTR_ERR(priv->tmon_base);
+
+	priv->dev = &pdev->dev;
+	platform_set_drvdata(pdev, priv);
+
+	thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
+	if (IS_ERR(thermal)) {
+		ret = PTR_ERR(thermal);
+		dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
+		return ret;
+	}
+
+	priv->thermal = thermal;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "could not get IRQ\n");
+		ret = irq;
+		goto err;
+	}
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					brcmstb_tmon_irq_thread, IRQF_ONESHOT,
+					DRV_NAME, priv);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
+		goto err;
+	}
+
+	dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
+
+	return 0;
+
+err:
+	thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
+	return ret;
+}
+
+static int brcmstb_thermal_exit(struct platform_device *pdev)
+{
+	struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
+	struct thermal_zone_device *thermal = priv->thermal;
+
+	if (thermal)
+		thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
+
+	return 0;
+}
+
+static struct platform_driver brcmstb_thermal_driver = {
+	.probe = brcmstb_thermal_probe,
+	.remove = brcmstb_thermal_exit,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = brcmstb_thermal_id_table,
+	},
+};
+module_platform_driver(brcmstb_thermal_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:27   ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

From: Brian Norris <computersforpeace@gmail.com>

The AVS TMON core provides temperature readings, a pair of configurable
high- and low-temperature threshold interrupts, and an emergency
over-temperature chip reset. The driver utilizes the first two to
provide temperature readings and high-temperature notifications to
applications. The over-temperature reset is not exposed to
applications; this reset threshold is critical to the system and should
be set with care within the bootloader.

Applications may choose to utilize the notification mechanism, the
temperature reading mechanism (e.g., through polling), or both.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Doug Berger <opendmb@gmail.com>
Signed-off-by: Markus Mayer <mmayer@broadcom.com>
---
 drivers/thermal/Kconfig                    |   2 +-
 drivers/thermal/broadcom/Kconfig           |   7 +
 drivers/thermal/broadcom/Makefile          |   1 +
 drivers/thermal/broadcom/brcmstb_thermal.c | 387 +++++++++++++++++++++++++++++
 4 files changed, 396 insertions(+), 1 deletion(-)
 create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 07002df..96774a7 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -408,7 +408,7 @@ config MTK_THERMAL
 	  controller present in Mediatek SoCs
 
 menu "Broadcom thermal drivers"
-depends on ARCH_BCM || COMPILE_TEST
+depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
 source "drivers/thermal/broadcom/Kconfig"
 endmenu
 
diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig
index 42c098e..c106a15 100644
--- a/drivers/thermal/broadcom/Kconfig
+++ b/drivers/thermal/broadcom/Kconfig
@@ -6,6 +6,13 @@ config BCM2835_THERMAL
 	help
 	  Support for thermal sensors on Broadcom bcm2835 SoCs.
 
+config BRCMSTB_THERMAL
+	tristate "Broadcom STB AVS TMON thermal driver"
+	depends on ARCH_BRCMSTB || COMPILE_TEST
+	help
+	  Enable this driver if you have a Broadcom STB SoC and would like
+	  thermal framework support.
+
 config BCM_NS_THERMAL
 	tristate "Northstar thermal driver"
 	depends on ARCH_BCM_IPROC || COMPILE_TEST
diff --git a/drivers/thermal/broadcom/Makefile b/drivers/thermal/broadcom/Makefile
index c6f62e4..fae10ec 100644
--- a/drivers/thermal/broadcom/Makefile
+++ b/drivers/thermal/broadcom/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_BCM2835_THERMAL)		+= bcm2835_thermal.o
+obj-$(CONFIG_BRCMSTB_THERMAL)		+= brcmstb_thermal.o
 obj-$(CONFIG_BCM_NS_THERMAL)		+= ns-thermal.o
diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c
new file mode 100644
index 0000000..1919f91
--- /dev/null
+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
@@ -0,0 +1,387 @@
+/*
+ * Broadcom STB AVS TMON thermal sensor driver
+ *
+ * Copyright (c) 2015-2017 Broadcom
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define DRV_NAME	"brcmstb_thermal"
+
+#define pr_fmt(fmt)	DRV_NAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/thermal.h>
+
+#define AVS_TMON_STATUS			0x00
+ #define AVS_TMON_STATUS_valid_msk	BIT(11)
+ #define AVS_TMON_STATUS_data_msk	GENMASK(10, 1)
+ #define AVS_TMON_STATUS_data_shift	1
+
+#define AVS_TMON_EN_OVERTEMP_RESET	0x04
+ #define AVS_TMON_EN_OVERTEMP_RESET_msk	BIT(0)
+
+#define AVS_TMON_RESET_THRESH		0x08
+ #define AVS_TMON_RESET_THRESH_msk	GENMASK(10, 1)
+ #define AVS_TMON_RESET_THRESH_shift	1
+
+#define AVS_TMON_INT_IDLE_TIME		0x10
+
+#define AVS_TMON_EN_TEMP_INT_SRCS	0x14
+ #define AVS_TMON_EN_TEMP_INT_SRCS_high	BIT(1)
+ #define AVS_TMON_EN_TEMP_INT_SRCS_low	BIT(0)
+
+#define AVS_TMON_INT_THRESH		0x18
+ #define AVS_TMON_INT_THRESH_high_msk	GENMASK(26, 17)
+ #define AVS_TMON_INT_THRESH_high_shift	17
+ #define AVS_TMON_INT_THRESH_low_msk	GENMASK(10, 1)
+ #define AVS_TMON_INT_THRESH_low_shift	1
+
+#define AVS_TMON_TEMP_INT_CODE		0x1c
+#define AVS_TMON_TP_TEST_ENABLE		0x20
+
+/* Default coefficients */
+#define AVS_TMON_TEMP_SLOPE		-487
+#define AVS_TMON_TEMP_OFFSET		410040
+
+/* HW related temperature constants */
+#define AVS_TMON_TEMP_MAX		0x3ff
+#define AVS_TMON_TEMP_MIN		-88161
+#define AVS_TMON_TEMP_MASK		AVS_TMON_TEMP_MAX
+
+enum avs_tmon_trip_type {
+	TMON_TRIP_TYPE_LOW = 0,
+	TMON_TRIP_TYPE_HIGH,
+	TMON_TRIP_TYPE_RESET,
+	TMON_TRIP_TYPE_MAX,
+};
+
+struct avs_tmon_trip {
+	/* HW bit to enable the trip */
+	u32 enable_offs;
+	u32 enable_mask;
+
+	/* HW field to read the trip temperature */
+	u32 reg_offs;
+	u32 reg_msk;
+	int reg_shift;
+};
+
+static struct avs_tmon_trip avs_tmon_trips[] = {
+	/* Trips when temperature is below threshold */
+	[TMON_TRIP_TYPE_LOW] = {
+		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
+		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_low,
+		.reg_offs	= AVS_TMON_INT_THRESH,
+		.reg_msk	= AVS_TMON_INT_THRESH_low_msk,
+		.reg_shift	= AVS_TMON_INT_THRESH_low_shift,
+	},
+	/* Trips when temperature is above threshold */
+	[TMON_TRIP_TYPE_HIGH] = {
+		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
+		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_high,
+		.reg_offs	= AVS_TMON_INT_THRESH,
+		.reg_msk	= AVS_TMON_INT_THRESH_high_msk,
+		.reg_shift	= AVS_TMON_INT_THRESH_high_shift,
+	},
+	/* Automatically resets chip when above threshold */
+	[TMON_TRIP_TYPE_RESET] = {
+		.enable_offs	= AVS_TMON_EN_OVERTEMP_RESET,
+		.enable_mask	= AVS_TMON_EN_OVERTEMP_RESET_msk,
+		.reg_offs	= AVS_TMON_RESET_THRESH,
+		.reg_msk	= AVS_TMON_RESET_THRESH_msk,
+		.reg_shift	= AVS_TMON_RESET_THRESH_shift,
+	},
+};
+
+struct brcmstb_thermal_priv {
+	void __iomem *tmon_base;
+	struct device *dev;
+	struct thermal_zone_device *thermal;
+};
+
+static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
+				int *offset)
+{
+	*slope = thermal_zone_get_slope(tz);
+	*offset = thermal_zone_get_offset(tz);
+}
+
+/* Convert a HW code to a temperature reading (millidegree celsius) */
+static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
+					u32 code)
+{
+	const int val = code & AVS_TMON_TEMP_MASK;
+	int slope, offset;
+
+	avs_tmon_get_coeffs(tz, &slope, &offset);
+
+	return slope * val + offset;
+}
+
+/*
+ * Convert a temperature value (millidegree celsius) to a HW code
+ *
+ * @temp: temperature to convert
+ * @low: if true, round toward the low side
+ */
+static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
+					int temp, bool low)
+{
+	int slope, offset;
+
+	if (temp < AVS_TMON_TEMP_MIN)
+		return AVS_TMON_TEMP_MAX; /* Maximum code value */
+
+	avs_tmon_get_coeffs(tz, &slope, &offset);
+
+	if (temp >= offset)
+		return 0;	/* Minimum code value */
+
+	if (low)
+		return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
+	else
+		return (u32)((offset - temp) / abs(slope));
+}
+
+static int brcmstb_get_temp(void *data, int *temp)
+{
+	struct brcmstb_thermal_priv *priv = data;
+	u32 val;
+	long t;
+
+	val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
+
+	if (!(val & AVS_TMON_STATUS_valid_msk)) {
+		dev_err(priv->dev, "reading not valid\n");
+		return -EIO;
+	}
+
+	val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
+
+	t = avs_tmon_code_to_temp(priv->thermal, val);
+	if (t < 0)
+		*temp = 0;
+	else
+		*temp = t;
+
+	return 0;
+}
+
+static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
+				 enum avs_tmon_trip_type type, int en)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
+
+	dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis", type);
+
+	if (en)
+		val |= trip->enable_mask;
+	else
+		val &= ~trip->enable_mask;
+
+	__raw_writel(val, priv->tmon_base + trip->enable_offs);
+}
+
+static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
+				  enum avs_tmon_trip_type type)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
+
+	val &= trip->reg_msk;
+	val >>= trip->reg_shift;
+
+	return avs_tmon_code_to_temp(priv->thermal, val);
+}
+
+static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
+				   enum avs_tmon_trip_type type,
+				   int temp)
+{
+	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
+	u32 val, orig;
+
+	dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
+
+	/* round toward low temp for the low interrupt */
+	val = avs_tmon_temp_to_code(priv->thermal, temp,
+				    type == TMON_TRIP_TYPE_LOW);
+
+	val <<= trip->reg_shift;
+	val &= trip->reg_msk;
+
+	orig = __raw_readl(priv->tmon_base + trip->reg_offs);
+	orig &= ~trip->reg_msk;
+	orig |= val;
+	__raw_writel(orig, priv->tmon_base + trip->reg_offs);
+}
+
+static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
+{
+	u32 val;
+
+	val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
+	return avs_tmon_code_to_temp(priv->thermal, val);
+}
+
+static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
+{
+	struct brcmstb_thermal_priv *priv = data;
+	int low, high, intr;
+
+	low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
+	high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
+	intr = avs_tmon_get_intr_temp(priv);
+
+	dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
+			low, intr, high);
+
+	/* Disable high-temp until next threshold shift */
+	if (intr >= high)
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
+	/* Disable low-temp until next threshold shift */
+	if (intr <= low)
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
+
+	/*
+	 * Notify using the interrupt temperature, in case the temperature
+	 * changes before it can next be read out
+	 */
+	thermal_zone_device_update(priv->thermal, intr);
+
+	return IRQ_HANDLED;
+}
+
+static int brcmstb_set_trips(void *data, int low, int high)
+{
+	struct brcmstb_thermal_priv *priv = data;
+
+	dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
+
+	/*
+	 * Disable low-temp if "low" is too small. As per thermal framework
+	 * API, we use -INT_MAX rather than INT_MIN.
+	 */
+	if (low <= -INT_MAX) {
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
+	} else {
+		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
+	}
+
+	/* Disable high-temp if "high" is too big. */
+	if (high == INT_MAX) {
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
+	} else {
+		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
+		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
+	}
+
+	return 0;
+}
+
+static struct thermal_zone_of_device_ops of_ops = {
+	.get_temp	= brcmstb_get_temp,
+	.set_trips	= brcmstb_set_trips,
+};
+
+static const struct of_device_id brcmstb_thermal_id_table[] = {
+	{ .compatible = "brcm,avs-tmon" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
+
+static int brcmstb_thermal_probe(struct platform_device *pdev)
+{
+	struct thermal_zone_device *thermal;
+	struct brcmstb_thermal_priv *priv;
+	struct resource *res;
+	int irq, ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->tmon_base))
+		return PTR_ERR(priv->tmon_base);
+
+	priv->dev = &pdev->dev;
+	platform_set_drvdata(pdev, priv);
+
+	thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
+	if (IS_ERR(thermal)) {
+		ret = PTR_ERR(thermal);
+		dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
+		return ret;
+	}
+
+	priv->thermal = thermal;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "could not get IRQ\n");
+		ret = irq;
+		goto err;
+	}
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					brcmstb_tmon_irq_thread, IRQF_ONESHOT,
+					DRV_NAME, priv);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
+		goto err;
+	}
+
+	dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
+
+	return 0;
+
+err:
+	thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
+	return ret;
+}
+
+static int brcmstb_thermal_exit(struct platform_device *pdev)
+{
+	struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
+	struct thermal_zone_device *thermal = priv->thermal;
+
+	if (thermal)
+		thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
+
+	return 0;
+}
+
+static struct platform_driver brcmstb_thermal_driver = {
+	.probe = brcmstb_thermal_probe,
+	.remove = brcmstb_thermal_exit,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = brcmstb_thermal_id_table,
+	},
+};
+module_platform_driver(brcmstb_thermal_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
-- 
2.7.4

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

* Re: [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
  2017-09-26 21:27   ` Markus Mayer
@ 2017-09-26 21:32     ` Scott Branden
  -1 siblings, 0 replies; 27+ messages in thread
From: Scott Branden @ 2017-09-26 21:32 UTC (permalink / raw)
  To: Markus Mayer, Zhang Rui, Eduardo Valentin, Rob Herring,
	Mark Rutland, Doug Berger, Brian Norris, Gregory Fong,
	Florian Fainelli, Rafał Miłecki
  Cc: Broadcom Kernel List, Power Management List, Device Tree List,
	ARM Kernel List, Linux Kernel Mailing List, Markus Mayer

Hi Markus,


On 17-09-26 02:27 PM, Markus Mayer wrote:
> From: Brian Norris <computersforpeace@gmail.com>
>
> The AVS TMON core provides temperature readings, a pair of configurable
> high- and low-temperature threshold interrupts, and an emergency
> over-temperature chip reset. The driver utilizes the first two to
> provide temperature readings and high-temperature notifications to
> applications. The over-temperature reset is not exposed to
> applications; this reset threshold is critical to the system and should
> be set with care within the bootloader.
>
> Applications may choose to utilize the notification mechanism, the
> temperature reading mechanism (e.g., through polling), or both.
>
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> Signed-off-by: Doug Berger <opendmb@gmail.com>
> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
> ---
>   drivers/thermal/Kconfig                    |   2 +-
>   drivers/thermal/broadcom/Kconfig           |   7 +
>   drivers/thermal/broadcom/Makefile          |   1 +
>   drivers/thermal/broadcom/brcmstb_thermal.c | 387 +++++++++++++++++++++++++++++
>   4 files changed, 396 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 07002df..96774a7 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -408,7 +408,7 @@ config MTK_THERMAL
>   	  controller present in Mediatek SoCs
>   
>   menu "Broadcom thermal drivers"
> -depends on ARCH_BCM || COMPILE_TEST
> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
No need for this additional depends.  ARCH_BCM is always defined before 
ARCH_BRCMSTB can be selected.
>   source "drivers/thermal/broadcom/Kconfig"
>   endmenu
>   
> diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig
> index 42c098e..c106a15 100644
> --- a/drivers/thermal/broadcom/Kconfig
> +++ b/drivers/thermal/broadcom/Kconfig
> @@ -6,6 +6,13 @@ config BCM2835_THERMAL
>   	help
>   	  Support for thermal sensors on Broadcom bcm2835 SoCs.
>   
> +config BRCMSTB_THERMAL
> +	tristate "Broadcom STB AVS TMON thermal driver"
> +	depends on ARCH_BRCMSTB || COMPILE_TEST
> +	help
> +	  Enable this driver if you have a Broadcom STB SoC and would like
> +	  thermal framework support.
> +
>   config BCM_NS_THERMAL
>   	tristate "Northstar thermal driver"
>   	depends on ARCH_BCM_IPROC || COMPILE_TEST
> diff --git a/drivers/thermal/broadcom/Makefile b/drivers/thermal/broadcom/Makefile
> index c6f62e4..fae10ec 100644
> --- a/drivers/thermal/broadcom/Makefile
> +++ b/drivers/thermal/broadcom/Makefile
> @@ -1,2 +1,3 @@
>   obj-$(CONFIG_BCM2835_THERMAL)		+= bcm2835_thermal.o
> +obj-$(CONFIG_BRCMSTB_THERMAL)		+= brcmstb_thermal.o
>   obj-$(CONFIG_BCM_NS_THERMAL)		+= ns-thermal.o
> diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c
> new file mode 100644
> index 0000000..1919f91
> --- /dev/null
> +++ b/drivers/thermal/broadcom/brcmstb_thermal.c
> @@ -0,0 +1,387 @@
> +/*
> + * Broadcom STB AVS TMON thermal sensor driver
> + *
> + * Copyright (c) 2015-2017 Broadcom
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#define DRV_NAME	"brcmstb_thermal"
> +
> +#define pr_fmt(fmt)	DRV_NAME ": " fmt
> +
> +#include <linux/bitops.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/irqreturn.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_device.h>
> +#include <linux/thermal.h>
> +
> +#define AVS_TMON_STATUS			0x00
> + #define AVS_TMON_STATUS_valid_msk	BIT(11)
> + #define AVS_TMON_STATUS_data_msk	GENMASK(10, 1)
> + #define AVS_TMON_STATUS_data_shift	1
> +
> +#define AVS_TMON_EN_OVERTEMP_RESET	0x04
> + #define AVS_TMON_EN_OVERTEMP_RESET_msk	BIT(0)
> +
> +#define AVS_TMON_RESET_THRESH		0x08
> + #define AVS_TMON_RESET_THRESH_msk	GENMASK(10, 1)
> + #define AVS_TMON_RESET_THRESH_shift	1
> +
> +#define AVS_TMON_INT_IDLE_TIME		0x10
> +
> +#define AVS_TMON_EN_TEMP_INT_SRCS	0x14
> + #define AVS_TMON_EN_TEMP_INT_SRCS_high	BIT(1)
> + #define AVS_TMON_EN_TEMP_INT_SRCS_low	BIT(0)
> +
> +#define AVS_TMON_INT_THRESH		0x18
> + #define AVS_TMON_INT_THRESH_high_msk	GENMASK(26, 17)
> + #define AVS_TMON_INT_THRESH_high_shift	17
> + #define AVS_TMON_INT_THRESH_low_msk	GENMASK(10, 1)
> + #define AVS_TMON_INT_THRESH_low_shift	1
> +
> +#define AVS_TMON_TEMP_INT_CODE		0x1c
> +#define AVS_TMON_TP_TEST_ENABLE		0x20
> +
> +/* Default coefficients */
> +#define AVS_TMON_TEMP_SLOPE		-487
> +#define AVS_TMON_TEMP_OFFSET		410040
> +
> +/* HW related temperature constants */
> +#define AVS_TMON_TEMP_MAX		0x3ff
> +#define AVS_TMON_TEMP_MIN		-88161
> +#define AVS_TMON_TEMP_MASK		AVS_TMON_TEMP_MAX
> +
> +enum avs_tmon_trip_type {
> +	TMON_TRIP_TYPE_LOW = 0,
> +	TMON_TRIP_TYPE_HIGH,
> +	TMON_TRIP_TYPE_RESET,
> +	TMON_TRIP_TYPE_MAX,
> +};
> +
> +struct avs_tmon_trip {
> +	/* HW bit to enable the trip */
> +	u32 enable_offs;
> +	u32 enable_mask;
> +
> +	/* HW field to read the trip temperature */
> +	u32 reg_offs;
> +	u32 reg_msk;
> +	int reg_shift;
> +};
> +
> +static struct avs_tmon_trip avs_tmon_trips[] = {
> +	/* Trips when temperature is below threshold */
> +	[TMON_TRIP_TYPE_LOW] = {
> +		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
> +		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_low,
> +		.reg_offs	= AVS_TMON_INT_THRESH,
> +		.reg_msk	= AVS_TMON_INT_THRESH_low_msk,
> +		.reg_shift	= AVS_TMON_INT_THRESH_low_shift,
> +	},
> +	/* Trips when temperature is above threshold */
> +	[TMON_TRIP_TYPE_HIGH] = {
> +		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
> +		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_high,
> +		.reg_offs	= AVS_TMON_INT_THRESH,
> +		.reg_msk	= AVS_TMON_INT_THRESH_high_msk,
> +		.reg_shift	= AVS_TMON_INT_THRESH_high_shift,
> +	},
> +	/* Automatically resets chip when above threshold */
> +	[TMON_TRIP_TYPE_RESET] = {
> +		.enable_offs	= AVS_TMON_EN_OVERTEMP_RESET,
> +		.enable_mask	= AVS_TMON_EN_OVERTEMP_RESET_msk,
> +		.reg_offs	= AVS_TMON_RESET_THRESH,
> +		.reg_msk	= AVS_TMON_RESET_THRESH_msk,
> +		.reg_shift	= AVS_TMON_RESET_THRESH_shift,
> +	},
> +};
> +
> +struct brcmstb_thermal_priv {
> +	void __iomem *tmon_base;
> +	struct device *dev;
> +	struct thermal_zone_device *thermal;
> +};
> +
> +static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
> +				int *offset)
> +{
> +	*slope = thermal_zone_get_slope(tz);
> +	*offset = thermal_zone_get_offset(tz);
> +}
> +
> +/* Convert a HW code to a temperature reading (millidegree celsius) */
> +static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
> +					u32 code)
> +{
> +	const int val = code & AVS_TMON_TEMP_MASK;
> +	int slope, offset;
> +
> +	avs_tmon_get_coeffs(tz, &slope, &offset);
> +
> +	return slope * val + offset;
> +}
> +
> +/*
> + * Convert a temperature value (millidegree celsius) to a HW code
> + *
> + * @temp: temperature to convert
> + * @low: if true, round toward the low side
> + */
> +static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
> +					int temp, bool low)
> +{
> +	int slope, offset;
> +
> +	if (temp < AVS_TMON_TEMP_MIN)
> +		return AVS_TMON_TEMP_MAX; /* Maximum code value */
> +
> +	avs_tmon_get_coeffs(tz, &slope, &offset);
> +
> +	if (temp >= offset)
> +		return 0;	/* Minimum code value */
> +
> +	if (low)
> +		return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
> +	else
> +		return (u32)((offset - temp) / abs(slope));
> +}
> +
> +static int brcmstb_get_temp(void *data, int *temp)
> +{
> +	struct brcmstb_thermal_priv *priv = data;
> +	u32 val;
> +	long t;
> +
> +	val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
> +
> +	if (!(val & AVS_TMON_STATUS_valid_msk)) {
> +		dev_err(priv->dev, "reading not valid\n");
> +		return -EIO;
> +	}
> +
> +	val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
> +
> +	t = avs_tmon_code_to_temp(priv->thermal, val);
> +	if (t < 0)
> +		*temp = 0;
> +	else
> +		*temp = t;
> +
> +	return 0;
> +}
> +
> +static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
> +				 enum avs_tmon_trip_type type, int en)
> +{
> +	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
> +	u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
> +
> +	dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis", type);
> +
> +	if (en)
> +		val |= trip->enable_mask;
> +	else
> +		val &= ~trip->enable_mask;
> +
> +	__raw_writel(val, priv->tmon_base + trip->enable_offs);
> +}
> +
> +static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
> +				  enum avs_tmon_trip_type type)
> +{
> +	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
> +	u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
> +
> +	val &= trip->reg_msk;
> +	val >>= trip->reg_shift;
> +
> +	return avs_tmon_code_to_temp(priv->thermal, val);
> +}
> +
> +static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
> +				   enum avs_tmon_trip_type type,
> +				   int temp)
> +{
> +	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
> +	u32 val, orig;
> +
> +	dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
> +
> +	/* round toward low temp for the low interrupt */
> +	val = avs_tmon_temp_to_code(priv->thermal, temp,
> +				    type == TMON_TRIP_TYPE_LOW);
> +
> +	val <<= trip->reg_shift;
> +	val &= trip->reg_msk;
> +
> +	orig = __raw_readl(priv->tmon_base + trip->reg_offs);
> +	orig &= ~trip->reg_msk;
> +	orig |= val;
> +	__raw_writel(orig, priv->tmon_base + trip->reg_offs);
> +}
> +
> +static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
> +{
> +	u32 val;
> +
> +	val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
> +	return avs_tmon_code_to_temp(priv->thermal, val);
> +}
> +
> +static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
> +{
> +	struct brcmstb_thermal_priv *priv = data;
> +	int low, high, intr;
> +
> +	low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
> +	high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
> +	intr = avs_tmon_get_intr_temp(priv);
> +
> +	dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
> +			low, intr, high);
> +
> +	/* Disable high-temp until next threshold shift */
> +	if (intr >= high)
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
> +	/* Disable low-temp until next threshold shift */
> +	if (intr <= low)
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
> +
> +	/*
> +	 * Notify using the interrupt temperature, in case the temperature
> +	 * changes before it can next be read out
> +	 */
> +	thermal_zone_device_update(priv->thermal, intr);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int brcmstb_set_trips(void *data, int low, int high)
> +{
> +	struct brcmstb_thermal_priv *priv = data;
> +
> +	dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
> +
> +	/*
> +	 * Disable low-temp if "low" is too small. As per thermal framework
> +	 * API, we use -INT_MAX rather than INT_MIN.
> +	 */
> +	if (low <= -INT_MAX) {
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
> +	} else {
> +		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
> +	}
> +
> +	/* Disable high-temp if "high" is too big. */
> +	if (high == INT_MAX) {
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
> +	} else {
> +		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct thermal_zone_of_device_ops of_ops = {
> +	.get_temp	= brcmstb_get_temp,
> +	.set_trips	= brcmstb_set_trips,
> +};
> +
> +static const struct of_device_id brcmstb_thermal_id_table[] = {
> +	{ .compatible = "brcm,avs-tmon" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
> +
> +static int brcmstb_thermal_probe(struct platform_device *pdev)
> +{
> +	struct thermal_zone_device *thermal;
> +	struct brcmstb_thermal_priv *priv;
> +	struct resource *res;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(priv->tmon_base))
> +		return PTR_ERR(priv->tmon_base);
> +
> +	priv->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, priv);
> +
> +	thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
> +	if (IS_ERR(thermal)) {
> +		ret = PTR_ERR(thermal);
> +		dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
> +		return ret;
> +	}
> +
> +	priv->thermal = thermal;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0) {
> +		dev_err(&pdev->dev, "could not get IRQ\n");
> +		ret = irq;
> +		goto err;
> +	}
> +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
> +					brcmstb_tmon_irq_thread, IRQF_ONESHOT,
> +					DRV_NAME, priv);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
> +		goto err;
> +	}
> +
> +	dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
> +
> +	return 0;
> +
> +err:
> +	thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
> +	return ret;
> +}
> +
> +static int brcmstb_thermal_exit(struct platform_device *pdev)
> +{
> +	struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
> +	struct thermal_zone_device *thermal = priv->thermal;
> +
> +	if (thermal)
> +		thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver brcmstb_thermal_driver = {
> +	.probe = brcmstb_thermal_probe,
> +	.remove = brcmstb_thermal_exit,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = brcmstb_thermal_id_table,
> +	},
> +};
> +module_platform_driver(brcmstb_thermal_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Brian Norris");
> +MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:32     ` Scott Branden
  0 siblings, 0 replies; 27+ messages in thread
From: Scott Branden @ 2017-09-26 21:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Markus,


On 17-09-26 02:27 PM, Markus Mayer wrote:
> From: Brian Norris <computersforpeace@gmail.com>
>
> The AVS TMON core provides temperature readings, a pair of configurable
> high- and low-temperature threshold interrupts, and an emergency
> over-temperature chip reset. The driver utilizes the first two to
> provide temperature readings and high-temperature notifications to
> applications. The over-temperature reset is not exposed to
> applications; this reset threshold is critical to the system and should
> be set with care within the bootloader.
>
> Applications may choose to utilize the notification mechanism, the
> temperature reading mechanism (e.g., through polling), or both.
>
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> Signed-off-by: Doug Berger <opendmb@gmail.com>
> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
> ---
>   drivers/thermal/Kconfig                    |   2 +-
>   drivers/thermal/broadcom/Kconfig           |   7 +
>   drivers/thermal/broadcom/Makefile          |   1 +
>   drivers/thermal/broadcom/brcmstb_thermal.c | 387 +++++++++++++++++++++++++++++
>   4 files changed, 396 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 07002df..96774a7 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -408,7 +408,7 @@ config MTK_THERMAL
>   	  controller present in Mediatek SoCs
>   
>   menu "Broadcom thermal drivers"
> -depends on ARCH_BCM || COMPILE_TEST
> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
No need for this additional depends.  ARCH_BCM is always defined before 
ARCH_BRCMSTB can be selected.
>   source "drivers/thermal/broadcom/Kconfig"
>   endmenu
>   
> diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig
> index 42c098e..c106a15 100644
> --- a/drivers/thermal/broadcom/Kconfig
> +++ b/drivers/thermal/broadcom/Kconfig
> @@ -6,6 +6,13 @@ config BCM2835_THERMAL
>   	help
>   	  Support for thermal sensors on Broadcom bcm2835 SoCs.
>   
> +config BRCMSTB_THERMAL
> +	tristate "Broadcom STB AVS TMON thermal driver"
> +	depends on ARCH_BRCMSTB || COMPILE_TEST
> +	help
> +	  Enable this driver if you have a Broadcom STB SoC and would like
> +	  thermal framework support.
> +
>   config BCM_NS_THERMAL
>   	tristate "Northstar thermal driver"
>   	depends on ARCH_BCM_IPROC || COMPILE_TEST
> diff --git a/drivers/thermal/broadcom/Makefile b/drivers/thermal/broadcom/Makefile
> index c6f62e4..fae10ec 100644
> --- a/drivers/thermal/broadcom/Makefile
> +++ b/drivers/thermal/broadcom/Makefile
> @@ -1,2 +1,3 @@
>   obj-$(CONFIG_BCM2835_THERMAL)		+= bcm2835_thermal.o
> +obj-$(CONFIG_BRCMSTB_THERMAL)		+= brcmstb_thermal.o
>   obj-$(CONFIG_BCM_NS_THERMAL)		+= ns-thermal.o
> diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c
> new file mode 100644
> index 0000000..1919f91
> --- /dev/null
> +++ b/drivers/thermal/broadcom/brcmstb_thermal.c
> @@ -0,0 +1,387 @@
> +/*
> + * Broadcom STB AVS TMON thermal sensor driver
> + *
> + * Copyright (c) 2015-2017 Broadcom
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#define DRV_NAME	"brcmstb_thermal"
> +
> +#define pr_fmt(fmt)	DRV_NAME ": " fmt
> +
> +#include <linux/bitops.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/irqreturn.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_device.h>
> +#include <linux/thermal.h>
> +
> +#define AVS_TMON_STATUS			0x00
> + #define AVS_TMON_STATUS_valid_msk	BIT(11)
> + #define AVS_TMON_STATUS_data_msk	GENMASK(10, 1)
> + #define AVS_TMON_STATUS_data_shift	1
> +
> +#define AVS_TMON_EN_OVERTEMP_RESET	0x04
> + #define AVS_TMON_EN_OVERTEMP_RESET_msk	BIT(0)
> +
> +#define AVS_TMON_RESET_THRESH		0x08
> + #define AVS_TMON_RESET_THRESH_msk	GENMASK(10, 1)
> + #define AVS_TMON_RESET_THRESH_shift	1
> +
> +#define AVS_TMON_INT_IDLE_TIME		0x10
> +
> +#define AVS_TMON_EN_TEMP_INT_SRCS	0x14
> + #define AVS_TMON_EN_TEMP_INT_SRCS_high	BIT(1)
> + #define AVS_TMON_EN_TEMP_INT_SRCS_low	BIT(0)
> +
> +#define AVS_TMON_INT_THRESH		0x18
> + #define AVS_TMON_INT_THRESH_high_msk	GENMASK(26, 17)
> + #define AVS_TMON_INT_THRESH_high_shift	17
> + #define AVS_TMON_INT_THRESH_low_msk	GENMASK(10, 1)
> + #define AVS_TMON_INT_THRESH_low_shift	1
> +
> +#define AVS_TMON_TEMP_INT_CODE		0x1c
> +#define AVS_TMON_TP_TEST_ENABLE		0x20
> +
> +/* Default coefficients */
> +#define AVS_TMON_TEMP_SLOPE		-487
> +#define AVS_TMON_TEMP_OFFSET		410040
> +
> +/* HW related temperature constants */
> +#define AVS_TMON_TEMP_MAX		0x3ff
> +#define AVS_TMON_TEMP_MIN		-88161
> +#define AVS_TMON_TEMP_MASK		AVS_TMON_TEMP_MAX
> +
> +enum avs_tmon_trip_type {
> +	TMON_TRIP_TYPE_LOW = 0,
> +	TMON_TRIP_TYPE_HIGH,
> +	TMON_TRIP_TYPE_RESET,
> +	TMON_TRIP_TYPE_MAX,
> +};
> +
> +struct avs_tmon_trip {
> +	/* HW bit to enable the trip */
> +	u32 enable_offs;
> +	u32 enable_mask;
> +
> +	/* HW field to read the trip temperature */
> +	u32 reg_offs;
> +	u32 reg_msk;
> +	int reg_shift;
> +};
> +
> +static struct avs_tmon_trip avs_tmon_trips[] = {
> +	/* Trips when temperature is below threshold */
> +	[TMON_TRIP_TYPE_LOW] = {
> +		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
> +		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_low,
> +		.reg_offs	= AVS_TMON_INT_THRESH,
> +		.reg_msk	= AVS_TMON_INT_THRESH_low_msk,
> +		.reg_shift	= AVS_TMON_INT_THRESH_low_shift,
> +	},
> +	/* Trips when temperature is above threshold */
> +	[TMON_TRIP_TYPE_HIGH] = {
> +		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
> +		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_high,
> +		.reg_offs	= AVS_TMON_INT_THRESH,
> +		.reg_msk	= AVS_TMON_INT_THRESH_high_msk,
> +		.reg_shift	= AVS_TMON_INT_THRESH_high_shift,
> +	},
> +	/* Automatically resets chip when above threshold */
> +	[TMON_TRIP_TYPE_RESET] = {
> +		.enable_offs	= AVS_TMON_EN_OVERTEMP_RESET,
> +		.enable_mask	= AVS_TMON_EN_OVERTEMP_RESET_msk,
> +		.reg_offs	= AVS_TMON_RESET_THRESH,
> +		.reg_msk	= AVS_TMON_RESET_THRESH_msk,
> +		.reg_shift	= AVS_TMON_RESET_THRESH_shift,
> +	},
> +};
> +
> +struct brcmstb_thermal_priv {
> +	void __iomem *tmon_base;
> +	struct device *dev;
> +	struct thermal_zone_device *thermal;
> +};
> +
> +static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
> +				int *offset)
> +{
> +	*slope = thermal_zone_get_slope(tz);
> +	*offset = thermal_zone_get_offset(tz);
> +}
> +
> +/* Convert a HW code to a temperature reading (millidegree celsius) */
> +static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
> +					u32 code)
> +{
> +	const int val = code & AVS_TMON_TEMP_MASK;
> +	int slope, offset;
> +
> +	avs_tmon_get_coeffs(tz, &slope, &offset);
> +
> +	return slope * val + offset;
> +}
> +
> +/*
> + * Convert a temperature value (millidegree celsius) to a HW code
> + *
> + * @temp: temperature to convert
> + * @low: if true, round toward the low side
> + */
> +static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
> +					int temp, bool low)
> +{
> +	int slope, offset;
> +
> +	if (temp < AVS_TMON_TEMP_MIN)
> +		return AVS_TMON_TEMP_MAX; /* Maximum code value */
> +
> +	avs_tmon_get_coeffs(tz, &slope, &offset);
> +
> +	if (temp >= offset)
> +		return 0;	/* Minimum code value */
> +
> +	if (low)
> +		return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
> +	else
> +		return (u32)((offset - temp) / abs(slope));
> +}
> +
> +static int brcmstb_get_temp(void *data, int *temp)
> +{
> +	struct brcmstb_thermal_priv *priv = data;
> +	u32 val;
> +	long t;
> +
> +	val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
> +
> +	if (!(val & AVS_TMON_STATUS_valid_msk)) {
> +		dev_err(priv->dev, "reading not valid\n");
> +		return -EIO;
> +	}
> +
> +	val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
> +
> +	t = avs_tmon_code_to_temp(priv->thermal, val);
> +	if (t < 0)
> +		*temp = 0;
> +	else
> +		*temp = t;
> +
> +	return 0;
> +}
> +
> +static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
> +				 enum avs_tmon_trip_type type, int en)
> +{
> +	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
> +	u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
> +
> +	dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis", type);
> +
> +	if (en)
> +		val |= trip->enable_mask;
> +	else
> +		val &= ~trip->enable_mask;
> +
> +	__raw_writel(val, priv->tmon_base + trip->enable_offs);
> +}
> +
> +static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
> +				  enum avs_tmon_trip_type type)
> +{
> +	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
> +	u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
> +
> +	val &= trip->reg_msk;
> +	val >>= trip->reg_shift;
> +
> +	return avs_tmon_code_to_temp(priv->thermal, val);
> +}
> +
> +static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
> +				   enum avs_tmon_trip_type type,
> +				   int temp)
> +{
> +	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
> +	u32 val, orig;
> +
> +	dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
> +
> +	/* round toward low temp for the low interrupt */
> +	val = avs_tmon_temp_to_code(priv->thermal, temp,
> +				    type == TMON_TRIP_TYPE_LOW);
> +
> +	val <<= trip->reg_shift;
> +	val &= trip->reg_msk;
> +
> +	orig = __raw_readl(priv->tmon_base + trip->reg_offs);
> +	orig &= ~trip->reg_msk;
> +	orig |= val;
> +	__raw_writel(orig, priv->tmon_base + trip->reg_offs);
> +}
> +
> +static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
> +{
> +	u32 val;
> +
> +	val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
> +	return avs_tmon_code_to_temp(priv->thermal, val);
> +}
> +
> +static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
> +{
> +	struct brcmstb_thermal_priv *priv = data;
> +	int low, high, intr;
> +
> +	low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
> +	high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
> +	intr = avs_tmon_get_intr_temp(priv);
> +
> +	dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
> +			low, intr, high);
> +
> +	/* Disable high-temp until next threshold shift */
> +	if (intr >= high)
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
> +	/* Disable low-temp until next threshold shift */
> +	if (intr <= low)
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
> +
> +	/*
> +	 * Notify using the interrupt temperature, in case the temperature
> +	 * changes before it can next be read out
> +	 */
> +	thermal_zone_device_update(priv->thermal, intr);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int brcmstb_set_trips(void *data, int low, int high)
> +{
> +	struct brcmstb_thermal_priv *priv = data;
> +
> +	dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
> +
> +	/*
> +	 * Disable low-temp if "low" is too small. As per thermal framework
> +	 * API, we use -INT_MAX rather than INT_MIN.
> +	 */
> +	if (low <= -INT_MAX) {
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
> +	} else {
> +		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
> +	}
> +
> +	/* Disable high-temp if "high" is too big. */
> +	if (high == INT_MAX) {
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
> +	} else {
> +		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
> +		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct thermal_zone_of_device_ops of_ops = {
> +	.get_temp	= brcmstb_get_temp,
> +	.set_trips	= brcmstb_set_trips,
> +};
> +
> +static const struct of_device_id brcmstb_thermal_id_table[] = {
> +	{ .compatible = "brcm,avs-tmon" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
> +
> +static int brcmstb_thermal_probe(struct platform_device *pdev)
> +{
> +	struct thermal_zone_device *thermal;
> +	struct brcmstb_thermal_priv *priv;
> +	struct resource *res;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(priv->tmon_base))
> +		return PTR_ERR(priv->tmon_base);
> +
> +	priv->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, priv);
> +
> +	thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
> +	if (IS_ERR(thermal)) {
> +		ret = PTR_ERR(thermal);
> +		dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
> +		return ret;
> +	}
> +
> +	priv->thermal = thermal;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0) {
> +		dev_err(&pdev->dev, "could not get IRQ\n");
> +		ret = irq;
> +		goto err;
> +	}
> +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
> +					brcmstb_tmon_irq_thread, IRQF_ONESHOT,
> +					DRV_NAME, priv);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
> +		goto err;
> +	}
> +
> +	dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
> +
> +	return 0;
> +
> +err:
> +	thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
> +	return ret;
> +}
> +
> +static int brcmstb_thermal_exit(struct platform_device *pdev)
> +{
> +	struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
> +	struct thermal_zone_device *thermal = priv->thermal;
> +
> +	if (thermal)
> +		thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver brcmstb_thermal_driver = {
> +	.probe = brcmstb_thermal_probe,
> +	.remove = brcmstb_thermal_exit,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = brcmstb_thermal_id_table,
> +	},
> +};
> +module_platform_driver(brcmstb_thermal_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Brian Norris");
> +MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");

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

* Re: [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
  2017-09-26 21:32     ` Scott Branden
@ 2017-09-26 21:38       ` Markus Mayer
  -1 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:38 UTC (permalink / raw)
  To: Scott Branden
  Cc: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki, Broadcom Kernel List,
	Power Management List, Device Tree List, ARM Kernel List,
	Linux Kernel Mailing List, Markus Mayer

On 26 September 2017 at 14:32, Scott Branden <scott.branden@broadcom.com> wrote:
> Hi Markus,
>
>
> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>
>> From: Brian Norris <computersforpeace@gmail.com>
>>
>> The AVS TMON core provides temperature readings, a pair of configurable
>> high- and low-temperature threshold interrupts, and an emergency
>> over-temperature chip reset. The driver utilizes the first two to
>> provide temperature readings and high-temperature notifications to
>> applications. The over-temperature reset is not exposed to
>> applications; this reset threshold is critical to the system and should
>> be set with care within the bootloader.
>>
>> Applications may choose to utilize the notification mechanism, the
>> temperature reading mechanism (e.g., through polling), or both.
>>
>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>> ---
>>   drivers/thermal/Kconfig                    |   2 +-
>>   drivers/thermal/broadcom/Kconfig           |   7 +
>>   drivers/thermal/broadcom/Makefile          |   1 +
>>   drivers/thermal/broadcom/brcmstb_thermal.c | 387
>> +++++++++++++++++++++++++++++
>>   4 files changed, 396 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index 07002df..96774a7 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>           controller present in Mediatek SoCs
>>     menu "Broadcom thermal drivers"
>> -depends on ARCH_BCM || COMPILE_TEST
>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>
> No need for this additional depends.  ARCH_BCM is always defined before
> ARCH_BRCMSTB can be selected.

ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
does. So, we do need both or the driver won't be built on ARM64.
(After internal discussions we went with that approach rather than
defining ARCH_BCM on ARM64.)

>>   source "drivers/thermal/broadcom/Kconfig"
>>   endmenu
>>   diff --git a/drivers/thermal/broadcom/Kconfig
>> b/drivers/thermal/broadcom/Kconfig
>> index 42c098e..c106a15 100644
>> --- a/drivers/thermal/broadcom/Kconfig
>> +++ b/drivers/thermal/broadcom/Kconfig
>> @@ -6,6 +6,13 @@ config BCM2835_THERMAL
>>         help
>>           Support for thermal sensors on Broadcom bcm2835 SoCs.
>>   +config BRCMSTB_THERMAL
>> +       tristate "Broadcom STB AVS TMON thermal driver"
>> +       depends on ARCH_BRCMSTB || COMPILE_TEST
>> +       help
>> +         Enable this driver if you have a Broadcom STB SoC and would like
>> +         thermal framework support.
>> +
>>   config BCM_NS_THERMAL
>>         tristate "Northstar thermal driver"
>>         depends on ARCH_BCM_IPROC || COMPILE_TEST
>> diff --git a/drivers/thermal/broadcom/Makefile
>> b/drivers/thermal/broadcom/Makefile
>> index c6f62e4..fae10ec 100644
>> --- a/drivers/thermal/broadcom/Makefile
>> +++ b/drivers/thermal/broadcom/Makefile
>> @@ -1,2 +1,3 @@
>>   obj-$(CONFIG_BCM2835_THERMAL)         += bcm2835_thermal.o
>> +obj-$(CONFIG_BRCMSTB_THERMAL)          += brcmstb_thermal.o
>>   obj-$(CONFIG_BCM_NS_THERMAL)          += ns-thermal.o
>> diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c
>> b/drivers/thermal/broadcom/brcmstb_thermal.c
>> new file mode 100644
>> index 0000000..1919f91
>> --- /dev/null
>> +++ b/drivers/thermal/broadcom/brcmstb_thermal.c
>> @@ -0,0 +1,387 @@
>>
>> +/*
>> + * Broadcom STB AVS TMON thermal sensor driver
>> + *
>> + * Copyright (c) 2015-2017 Broadcom
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#define DRV_NAME       "brcmstb_thermal"
>> +
>> +#define pr_fmt(fmt)    DRV_NAME ": " fmt
>> +
>> +#include <linux/bitops.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/of_device.h>
>> +#include <linux/thermal.h>
>> +
>> +#define AVS_TMON_STATUS                        0x00
>> + #define AVS_TMON_STATUS_valid_msk     BIT(11)
>> + #define AVS_TMON_STATUS_data_msk      GENMASK(10, 1)
>> + #define AVS_TMON_STATUS_data_shift    1
>> +
>> +#define AVS_TMON_EN_OVERTEMP_RESET     0x04
>> + #define AVS_TMON_EN_OVERTEMP_RESET_msk        BIT(0)
>> +
>> +#define AVS_TMON_RESET_THRESH          0x08
>> + #define AVS_TMON_RESET_THRESH_msk     GENMASK(10, 1)
>> + #define AVS_TMON_RESET_THRESH_shift   1
>> +
>> +#define AVS_TMON_INT_IDLE_TIME         0x10
>> +
>> +#define AVS_TMON_EN_TEMP_INT_SRCS      0x14
>> + #define AVS_TMON_EN_TEMP_INT_SRCS_high        BIT(1)
>> + #define AVS_TMON_EN_TEMP_INT_SRCS_low BIT(0)
>> +
>> +#define AVS_TMON_INT_THRESH            0x18
>> + #define AVS_TMON_INT_THRESH_high_msk  GENMASK(26, 17)
>> + #define AVS_TMON_INT_THRESH_high_shift        17
>> + #define AVS_TMON_INT_THRESH_low_msk   GENMASK(10, 1)
>> + #define AVS_TMON_INT_THRESH_low_shift 1
>> +
>> +#define AVS_TMON_TEMP_INT_CODE         0x1c
>> +#define AVS_TMON_TP_TEST_ENABLE                0x20
>> +
>> +/* Default coefficients */
>> +#define AVS_TMON_TEMP_SLOPE            -487
>> +#define AVS_TMON_TEMP_OFFSET           410040
>> +
>> +/* HW related temperature constants */
>> +#define AVS_TMON_TEMP_MAX              0x3ff
>> +#define AVS_TMON_TEMP_MIN              -88161
>> +#define AVS_TMON_TEMP_MASK             AVS_TMON_TEMP_MAX
>> +
>> +enum avs_tmon_trip_type {
>> +       TMON_TRIP_TYPE_LOW = 0,
>> +       TMON_TRIP_TYPE_HIGH,
>> +       TMON_TRIP_TYPE_RESET,
>> +       TMON_TRIP_TYPE_MAX,
>> +};
>> +
>> +struct avs_tmon_trip {
>> +       /* HW bit to enable the trip */
>> +       u32 enable_offs;
>> +       u32 enable_mask;
>> +
>> +       /* HW field to read the trip temperature */
>> +       u32 reg_offs;
>> +       u32 reg_msk;
>> +       int reg_shift;
>> +};
>> +
>> +static struct avs_tmon_trip avs_tmon_trips[] = {
>> +       /* Trips when temperature is below threshold */
>> +       [TMON_TRIP_TYPE_LOW] = {
>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_low,
>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>> +               .reg_msk        = AVS_TMON_INT_THRESH_low_msk,
>> +               .reg_shift      = AVS_TMON_INT_THRESH_low_shift,
>> +       },
>> +       /* Trips when temperature is above threshold */
>> +       [TMON_TRIP_TYPE_HIGH] = {
>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_high,
>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>> +               .reg_msk        = AVS_TMON_INT_THRESH_high_msk,
>> +               .reg_shift      = AVS_TMON_INT_THRESH_high_shift,
>> +       },
>> +       /* Automatically resets chip when above threshold */
>> +       [TMON_TRIP_TYPE_RESET] = {
>> +               .enable_offs    = AVS_TMON_EN_OVERTEMP_RESET,
>> +               .enable_mask    = AVS_TMON_EN_OVERTEMP_RESET_msk,
>> +               .reg_offs       = AVS_TMON_RESET_THRESH,
>> +               .reg_msk        = AVS_TMON_RESET_THRESH_msk,
>> +               .reg_shift      = AVS_TMON_RESET_THRESH_shift,
>> +       },
>> +};
>> +
>> +struct brcmstb_thermal_priv {
>> +       void __iomem *tmon_base;
>> +       struct device *dev;
>> +       struct thermal_zone_device *thermal;
>> +};
>> +
>> +static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int
>> *slope,
>> +                               int *offset)
>> +{
>> +       *slope = thermal_zone_get_slope(tz);
>> +       *offset = thermal_zone_get_offset(tz);
>> +}
>> +
>> +/* Convert a HW code to a temperature reading (millidegree celsius) */
>> +static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
>> +                                       u32 code)
>> +{
>> +       const int val = code & AVS_TMON_TEMP_MASK;
>> +       int slope, offset;
>> +
>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>> +
>> +       return slope * val + offset;
>> +}
>> +
>> +/*
>> + * Convert a temperature value (millidegree celsius) to a HW code
>> + *
>> + * @temp: temperature to convert
>> + * @low: if true, round toward the low side
>> + */
>> +static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
>> +                                       int temp, bool low)
>> +{
>> +       int slope, offset;
>> +
>> +       if (temp < AVS_TMON_TEMP_MIN)
>> +               return AVS_TMON_TEMP_MAX; /* Maximum code value */
>> +
>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>> +
>> +       if (temp >= offset)
>> +               return 0;       /* Minimum code value */
>> +
>> +       if (low)
>> +               return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
>> +       else
>> +               return (u32)((offset - temp) / abs(slope));
>> +}
>> +
>> +static int brcmstb_get_temp(void *data, int *temp)
>> +{
>> +       struct brcmstb_thermal_priv *priv = data;
>> +       u32 val;
>> +       long t;
>> +
>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
>> +
>> +       if (!(val & AVS_TMON_STATUS_valid_msk)) {
>> +               dev_err(priv->dev, "reading not valid\n");
>> +               return -EIO;
>> +       }
>> +
>> +       val = (val & AVS_TMON_STATUS_data_msk) >>
>> AVS_TMON_STATUS_data_shift;
>> +
>> +       t = avs_tmon_code_to_temp(priv->thermal, val);
>> +       if (t < 0)
>> +               *temp = 0;
>> +       else
>> +               *temp = t;
>> +
>> +       return 0;
>> +}
>> +
>> +static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
>> +                                enum avs_tmon_trip_type type, int en)
>> +{
>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>> +       u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
>> +
>> +       dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis",
>> type);
>> +
>> +       if (en)
>> +               val |= trip->enable_mask;
>> +       else
>> +               val &= ~trip->enable_mask;
>> +
>> +       __raw_writel(val, priv->tmon_base + trip->enable_offs);
>> +}
>> +
>> +static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
>> +                                 enum avs_tmon_trip_type type)
>> +{
>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>> +       u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
>> +
>> +       val &= trip->reg_msk;
>> +       val >>= trip->reg_shift;
>> +
>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>> +}
>> +
>> +static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
>> +                                  enum avs_tmon_trip_type type,
>> +                                  int temp)
>> +{
>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>> +       u32 val, orig;
>> +
>> +       dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
>> +
>> +       /* round toward low temp for the low interrupt */
>> +       val = avs_tmon_temp_to_code(priv->thermal, temp,
>> +                                   type == TMON_TRIP_TYPE_LOW);
>> +
>> +       val <<= trip->reg_shift;
>> +       val &= trip->reg_msk;
>> +
>> +       orig = __raw_readl(priv->tmon_base + trip->reg_offs);
>> +       orig &= ~trip->reg_msk;
>> +       orig |= val;
>> +       __raw_writel(orig, priv->tmon_base + trip->reg_offs);
>> +}
>> +
>> +static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
>> +{
>> +       u32 val;
>> +
>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>> +}
>> +
>> +static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
>> +{
>> +       struct brcmstb_thermal_priv *priv = data;
>> +       int low, high, intr;
>> +
>> +       low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
>> +       high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
>> +       intr = avs_tmon_get_intr_temp(priv);
>> +
>> +       dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
>> +                       low, intr, high);
>> +
>> +       /* Disable high-temp until next threshold shift */
>> +       if (intr >= high)
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>> +       /* Disable low-temp until next threshold shift */
>> +       if (intr <= low)
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>> +
>> +       /*
>> +        * Notify using the interrupt temperature, in case the temperature
>> +        * changes before it can next be read out
>> +        */
>> +       thermal_zone_device_update(priv->thermal, intr);
>> +
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static int brcmstb_set_trips(void *data, int low, int high)
>> +{
>> +       struct brcmstb_thermal_priv *priv = data;
>> +
>> +       dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
>> +
>> +       /*
>> +        * Disable low-temp if "low" is too small. As per thermal
>> framework
>> +        * API, we use -INT_MAX rather than INT_MIN.
>> +        */
>> +       if (low <= -INT_MAX) {
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>> +       } else {
>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
>> +       }
>> +
>> +       /* Disable high-temp if "high" is too big. */
>> +       if (high == INT_MAX) {
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>> +       } else {
>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static struct thermal_zone_of_device_ops of_ops = {
>> +       .get_temp       = brcmstb_get_temp,
>> +       .set_trips      = brcmstb_set_trips,
>> +};
>> +
>> +static const struct of_device_id brcmstb_thermal_id_table[] = {
>> +       { .compatible = "brcm,avs-tmon" },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
>> +
>> +static int brcmstb_thermal_probe(struct platform_device *pdev)
>> +{
>> +       struct thermal_zone_device *thermal;
>> +       struct brcmstb_thermal_priv *priv;
>> +       struct resource *res;
>> +       int irq, ret;
>> +
>> +       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>> +       if (!priv)
>> +               return -ENOMEM;
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
>> +       if (IS_ERR(priv->tmon_base))
>> +               return PTR_ERR(priv->tmon_base);
>> +
>> +       priv->dev = &pdev->dev;
>> +       platform_set_drvdata(pdev, priv);
>> +
>> +       thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
>> &of_ops);
>> +       if (IS_ERR(thermal)) {
>> +               ret = PTR_ERR(thermal);
>> +               dev_err(&pdev->dev, "could not register sensor: %d\n",
>> ret);
>> +               return ret;
>> +       }
>> +
>> +       priv->thermal = thermal;
>> +
>> +       irq = platform_get_irq(pdev, 0);
>> +       if (irq < 0) {
>> +               dev_err(&pdev->dev, "could not get IRQ\n");
>> +               ret = irq;
>> +               goto err;
>> +       }
>> +       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
>> +                                       brcmstb_tmon_irq_thread,
>> IRQF_ONESHOT,
>> +                                       DRV_NAME, priv);
>> +       if (ret < 0) {
>> +               dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
>> +               goto err;
>> +       }
>> +
>> +       dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
>> +
>> +       return 0;
>> +
>> +err:
>> +       thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
>> +       return ret;
>> +}
>> +
>> +static int brcmstb_thermal_exit(struct platform_device *pdev)
>> +{
>> +       struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
>> +       struct thermal_zone_device *thermal = priv->thermal;
>> +
>> +       if (thermal)
>> +               thermal_zone_of_sensor_unregister(&pdev->dev,
>> priv->thermal);
>> +
>> +       return 0;
>> +}
>> +
>> +static struct platform_driver brcmstb_thermal_driver = {
>> +       .probe = brcmstb_thermal_probe,
>> +       .remove = brcmstb_thermal_exit,
>> +       .driver = {
>> +               .name = DRV_NAME,
>> +               .of_match_table = brcmstb_thermal_id_table,
>> +       },
>> +};
>> +module_platform_driver(brcmstb_thermal_driver);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Brian Norris");
>> +MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
>
>

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 21:38       ` Markus Mayer
  0 siblings, 0 replies; 27+ messages in thread
From: Markus Mayer @ 2017-09-26 21:38 UTC (permalink / raw)
  To: linux-arm-kernel

On 26 September 2017 at 14:32, Scott Branden <scott.branden@broadcom.com> wrote:
> Hi Markus,
>
>
> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>
>> From: Brian Norris <computersforpeace@gmail.com>
>>
>> The AVS TMON core provides temperature readings, a pair of configurable
>> high- and low-temperature threshold interrupts, and an emergency
>> over-temperature chip reset. The driver utilizes the first two to
>> provide temperature readings and high-temperature notifications to
>> applications. The over-temperature reset is not exposed to
>> applications; this reset threshold is critical to the system and should
>> be set with care within the bootloader.
>>
>> Applications may choose to utilize the notification mechanism, the
>> temperature reading mechanism (e.g., through polling), or both.
>>
>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>> ---
>>   drivers/thermal/Kconfig                    |   2 +-
>>   drivers/thermal/broadcom/Kconfig           |   7 +
>>   drivers/thermal/broadcom/Makefile          |   1 +
>>   drivers/thermal/broadcom/brcmstb_thermal.c | 387
>> +++++++++++++++++++++++++++++
>>   4 files changed, 396 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index 07002df..96774a7 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>           controller present in Mediatek SoCs
>>     menu "Broadcom thermal drivers"
>> -depends on ARCH_BCM || COMPILE_TEST
>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>
> No need for this additional depends.  ARCH_BCM is always defined before
> ARCH_BRCMSTB can be selected.

ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
does. So, we do need both or the driver won't be built on ARM64.
(After internal discussions we went with that approach rather than
defining ARCH_BCM on ARM64.)

>>   source "drivers/thermal/broadcom/Kconfig"
>>   endmenu
>>   diff --git a/drivers/thermal/broadcom/Kconfig
>> b/drivers/thermal/broadcom/Kconfig
>> index 42c098e..c106a15 100644
>> --- a/drivers/thermal/broadcom/Kconfig
>> +++ b/drivers/thermal/broadcom/Kconfig
>> @@ -6,6 +6,13 @@ config BCM2835_THERMAL
>>         help
>>           Support for thermal sensors on Broadcom bcm2835 SoCs.
>>   +config BRCMSTB_THERMAL
>> +       tristate "Broadcom STB AVS TMON thermal driver"
>> +       depends on ARCH_BRCMSTB || COMPILE_TEST
>> +       help
>> +         Enable this driver if you have a Broadcom STB SoC and would like
>> +         thermal framework support.
>> +
>>   config BCM_NS_THERMAL
>>         tristate "Northstar thermal driver"
>>         depends on ARCH_BCM_IPROC || COMPILE_TEST
>> diff --git a/drivers/thermal/broadcom/Makefile
>> b/drivers/thermal/broadcom/Makefile
>> index c6f62e4..fae10ec 100644
>> --- a/drivers/thermal/broadcom/Makefile
>> +++ b/drivers/thermal/broadcom/Makefile
>> @@ -1,2 +1,3 @@
>>   obj-$(CONFIG_BCM2835_THERMAL)         += bcm2835_thermal.o
>> +obj-$(CONFIG_BRCMSTB_THERMAL)          += brcmstb_thermal.o
>>   obj-$(CONFIG_BCM_NS_THERMAL)          += ns-thermal.o
>> diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c
>> b/drivers/thermal/broadcom/brcmstb_thermal.c
>> new file mode 100644
>> index 0000000..1919f91
>> --- /dev/null
>> +++ b/drivers/thermal/broadcom/brcmstb_thermal.c
>> @@ -0,0 +1,387 @@
>>
>> +/*
>> + * Broadcom STB AVS TMON thermal sensor driver
>> + *
>> + * Copyright (c) 2015-2017 Broadcom
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#define DRV_NAME       "brcmstb_thermal"
>> +
>> +#define pr_fmt(fmt)    DRV_NAME ": " fmt
>> +
>> +#include <linux/bitops.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/of_device.h>
>> +#include <linux/thermal.h>
>> +
>> +#define AVS_TMON_STATUS                        0x00
>> + #define AVS_TMON_STATUS_valid_msk     BIT(11)
>> + #define AVS_TMON_STATUS_data_msk      GENMASK(10, 1)
>> + #define AVS_TMON_STATUS_data_shift    1
>> +
>> +#define AVS_TMON_EN_OVERTEMP_RESET     0x04
>> + #define AVS_TMON_EN_OVERTEMP_RESET_msk        BIT(0)
>> +
>> +#define AVS_TMON_RESET_THRESH          0x08
>> + #define AVS_TMON_RESET_THRESH_msk     GENMASK(10, 1)
>> + #define AVS_TMON_RESET_THRESH_shift   1
>> +
>> +#define AVS_TMON_INT_IDLE_TIME         0x10
>> +
>> +#define AVS_TMON_EN_TEMP_INT_SRCS      0x14
>> + #define AVS_TMON_EN_TEMP_INT_SRCS_high        BIT(1)
>> + #define AVS_TMON_EN_TEMP_INT_SRCS_low BIT(0)
>> +
>> +#define AVS_TMON_INT_THRESH            0x18
>> + #define AVS_TMON_INT_THRESH_high_msk  GENMASK(26, 17)
>> + #define AVS_TMON_INT_THRESH_high_shift        17
>> + #define AVS_TMON_INT_THRESH_low_msk   GENMASK(10, 1)
>> + #define AVS_TMON_INT_THRESH_low_shift 1
>> +
>> +#define AVS_TMON_TEMP_INT_CODE         0x1c
>> +#define AVS_TMON_TP_TEST_ENABLE                0x20
>> +
>> +/* Default coefficients */
>> +#define AVS_TMON_TEMP_SLOPE            -487
>> +#define AVS_TMON_TEMP_OFFSET           410040
>> +
>> +/* HW related temperature constants */
>> +#define AVS_TMON_TEMP_MAX              0x3ff
>> +#define AVS_TMON_TEMP_MIN              -88161
>> +#define AVS_TMON_TEMP_MASK             AVS_TMON_TEMP_MAX
>> +
>> +enum avs_tmon_trip_type {
>> +       TMON_TRIP_TYPE_LOW = 0,
>> +       TMON_TRIP_TYPE_HIGH,
>> +       TMON_TRIP_TYPE_RESET,
>> +       TMON_TRIP_TYPE_MAX,
>> +};
>> +
>> +struct avs_tmon_trip {
>> +       /* HW bit to enable the trip */
>> +       u32 enable_offs;
>> +       u32 enable_mask;
>> +
>> +       /* HW field to read the trip temperature */
>> +       u32 reg_offs;
>> +       u32 reg_msk;
>> +       int reg_shift;
>> +};
>> +
>> +static struct avs_tmon_trip avs_tmon_trips[] = {
>> +       /* Trips when temperature is below threshold */
>> +       [TMON_TRIP_TYPE_LOW] = {
>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_low,
>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>> +               .reg_msk        = AVS_TMON_INT_THRESH_low_msk,
>> +               .reg_shift      = AVS_TMON_INT_THRESH_low_shift,
>> +       },
>> +       /* Trips when temperature is above threshold */
>> +       [TMON_TRIP_TYPE_HIGH] = {
>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_high,
>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>> +               .reg_msk        = AVS_TMON_INT_THRESH_high_msk,
>> +               .reg_shift      = AVS_TMON_INT_THRESH_high_shift,
>> +       },
>> +       /* Automatically resets chip when above threshold */
>> +       [TMON_TRIP_TYPE_RESET] = {
>> +               .enable_offs    = AVS_TMON_EN_OVERTEMP_RESET,
>> +               .enable_mask    = AVS_TMON_EN_OVERTEMP_RESET_msk,
>> +               .reg_offs       = AVS_TMON_RESET_THRESH,
>> +               .reg_msk        = AVS_TMON_RESET_THRESH_msk,
>> +               .reg_shift      = AVS_TMON_RESET_THRESH_shift,
>> +       },
>> +};
>> +
>> +struct brcmstb_thermal_priv {
>> +       void __iomem *tmon_base;
>> +       struct device *dev;
>> +       struct thermal_zone_device *thermal;
>> +};
>> +
>> +static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int
>> *slope,
>> +                               int *offset)
>> +{
>> +       *slope = thermal_zone_get_slope(tz);
>> +       *offset = thermal_zone_get_offset(tz);
>> +}
>> +
>> +/* Convert a HW code to a temperature reading (millidegree celsius) */
>> +static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
>> +                                       u32 code)
>> +{
>> +       const int val = code & AVS_TMON_TEMP_MASK;
>> +       int slope, offset;
>> +
>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>> +
>> +       return slope * val + offset;
>> +}
>> +
>> +/*
>> + * Convert a temperature value (millidegree celsius) to a HW code
>> + *
>> + * @temp: temperature to convert
>> + * @low: if true, round toward the low side
>> + */
>> +static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
>> +                                       int temp, bool low)
>> +{
>> +       int slope, offset;
>> +
>> +       if (temp < AVS_TMON_TEMP_MIN)
>> +               return AVS_TMON_TEMP_MAX; /* Maximum code value */
>> +
>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>> +
>> +       if (temp >= offset)
>> +               return 0;       /* Minimum code value */
>> +
>> +       if (low)
>> +               return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
>> +       else
>> +               return (u32)((offset - temp) / abs(slope));
>> +}
>> +
>> +static int brcmstb_get_temp(void *data, int *temp)
>> +{
>> +       struct brcmstb_thermal_priv *priv = data;
>> +       u32 val;
>> +       long t;
>> +
>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
>> +
>> +       if (!(val & AVS_TMON_STATUS_valid_msk)) {
>> +               dev_err(priv->dev, "reading not valid\n");
>> +               return -EIO;
>> +       }
>> +
>> +       val = (val & AVS_TMON_STATUS_data_msk) >>
>> AVS_TMON_STATUS_data_shift;
>> +
>> +       t = avs_tmon_code_to_temp(priv->thermal, val);
>> +       if (t < 0)
>> +               *temp = 0;
>> +       else
>> +               *temp = t;
>> +
>> +       return 0;
>> +}
>> +
>> +static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
>> +                                enum avs_tmon_trip_type type, int en)
>> +{
>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>> +       u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
>> +
>> +       dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis",
>> type);
>> +
>> +       if (en)
>> +               val |= trip->enable_mask;
>> +       else
>> +               val &= ~trip->enable_mask;
>> +
>> +       __raw_writel(val, priv->tmon_base + trip->enable_offs);
>> +}
>> +
>> +static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
>> +                                 enum avs_tmon_trip_type type)
>> +{
>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>> +       u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
>> +
>> +       val &= trip->reg_msk;
>> +       val >>= trip->reg_shift;
>> +
>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>> +}
>> +
>> +static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
>> +                                  enum avs_tmon_trip_type type,
>> +                                  int temp)
>> +{
>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>> +       u32 val, orig;
>> +
>> +       dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
>> +
>> +       /* round toward low temp for the low interrupt */
>> +       val = avs_tmon_temp_to_code(priv->thermal, temp,
>> +                                   type == TMON_TRIP_TYPE_LOW);
>> +
>> +       val <<= trip->reg_shift;
>> +       val &= trip->reg_msk;
>> +
>> +       orig = __raw_readl(priv->tmon_base + trip->reg_offs);
>> +       orig &= ~trip->reg_msk;
>> +       orig |= val;
>> +       __raw_writel(orig, priv->tmon_base + trip->reg_offs);
>> +}
>> +
>> +static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
>> +{
>> +       u32 val;
>> +
>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>> +}
>> +
>> +static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
>> +{
>> +       struct brcmstb_thermal_priv *priv = data;
>> +       int low, high, intr;
>> +
>> +       low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
>> +       high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
>> +       intr = avs_tmon_get_intr_temp(priv);
>> +
>> +       dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
>> +                       low, intr, high);
>> +
>> +       /* Disable high-temp until next threshold shift */
>> +       if (intr >= high)
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>> +       /* Disable low-temp until next threshold shift */
>> +       if (intr <= low)
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>> +
>> +       /*
>> +        * Notify using the interrupt temperature, in case the temperature
>> +        * changes before it can next be read out
>> +        */
>> +       thermal_zone_device_update(priv->thermal, intr);
>> +
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static int brcmstb_set_trips(void *data, int low, int high)
>> +{
>> +       struct brcmstb_thermal_priv *priv = data;
>> +
>> +       dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
>> +
>> +       /*
>> +        * Disable low-temp if "low" is too small. As per thermal
>> framework
>> +        * API, we use -INT_MAX rather than INT_MIN.
>> +        */
>> +       if (low <= -INT_MAX) {
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>> +       } else {
>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
>> +       }
>> +
>> +       /* Disable high-temp if "high" is too big. */
>> +       if (high == INT_MAX) {
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>> +       } else {
>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static struct thermal_zone_of_device_ops of_ops = {
>> +       .get_temp       = brcmstb_get_temp,
>> +       .set_trips      = brcmstb_set_trips,
>> +};
>> +
>> +static const struct of_device_id brcmstb_thermal_id_table[] = {
>> +       { .compatible = "brcm,avs-tmon" },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
>> +
>> +static int brcmstb_thermal_probe(struct platform_device *pdev)
>> +{
>> +       struct thermal_zone_device *thermal;
>> +       struct brcmstb_thermal_priv *priv;
>> +       struct resource *res;
>> +       int irq, ret;
>> +
>> +       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>> +       if (!priv)
>> +               return -ENOMEM;
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
>> +       if (IS_ERR(priv->tmon_base))
>> +               return PTR_ERR(priv->tmon_base);
>> +
>> +       priv->dev = &pdev->dev;
>> +       platform_set_drvdata(pdev, priv);
>> +
>> +       thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
>> &of_ops);
>> +       if (IS_ERR(thermal)) {
>> +               ret = PTR_ERR(thermal);
>> +               dev_err(&pdev->dev, "could not register sensor: %d\n",
>> ret);
>> +               return ret;
>> +       }
>> +
>> +       priv->thermal = thermal;
>> +
>> +       irq = platform_get_irq(pdev, 0);
>> +       if (irq < 0) {
>> +               dev_err(&pdev->dev, "could not get IRQ\n");
>> +               ret = irq;
>> +               goto err;
>> +       }
>> +       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
>> +                                       brcmstb_tmon_irq_thread,
>> IRQF_ONESHOT,
>> +                                       DRV_NAME, priv);
>> +       if (ret < 0) {
>> +               dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
>> +               goto err;
>> +       }
>> +
>> +       dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
>> +
>> +       return 0;
>> +
>> +err:
>> +       thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
>> +       return ret;
>> +}
>> +
>> +static int brcmstb_thermal_exit(struct platform_device *pdev)
>> +{
>> +       struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
>> +       struct thermal_zone_device *thermal = priv->thermal;
>> +
>> +       if (thermal)
>> +               thermal_zone_of_sensor_unregister(&pdev->dev,
>> priv->thermal);
>> +
>> +       return 0;
>> +}
>> +
>> +static struct platform_driver brcmstb_thermal_driver = {
>> +       .probe = brcmstb_thermal_probe,
>> +       .remove = brcmstb_thermal_exit,
>> +       .driver = {
>> +               .name = DRV_NAME,
>> +               .of_match_table = brcmstb_thermal_id_table,
>> +       },
>> +};
>> +module_platform_driver(brcmstb_thermal_driver);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Brian Norris");
>> +MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
>
>

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

* Re: [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
  2017-09-26 21:38       ` Markus Mayer
@ 2017-09-26 22:08         ` Scott Branden
  -1 siblings, 0 replies; 27+ messages in thread
From: Scott Branden @ 2017-09-26 22:08 UTC (permalink / raw)
  To: Markus Mayer
  Cc: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki, Broadcom Kernel List,
	Power Management List, Device Tree List, ARM Kernel List,
	Linux Kernel Mailing List, Markus Mayer



On 17-09-26 02:38 PM, Markus Mayer wrote:
> On 26 September 2017 at 14:32, Scott Branden <scott.branden@broadcom.com> wrote:
>> Hi Markus,
>>
>>
>> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>> From: Brian Norris <computersforpeace@gmail.com>
>>>
>>> The AVS TMON core provides temperature readings, a pair of configurable
>>> high- and low-temperature threshold interrupts, and an emergency
>>> over-temperature chip reset. The driver utilizes the first two to
>>> provide temperature readings and high-temperature notifications to
>>> applications. The over-temperature reset is not exposed to
>>> applications; this reset threshold is critical to the system and should
>>> be set with care within the bootloader.
>>>
>>> Applications may choose to utilize the notification mechanism, the
>>> temperature reading mechanism (e.g., through polling), or both.
>>>
>>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>>> ---
>>>    drivers/thermal/Kconfig                    |   2 +-
>>>    drivers/thermal/broadcom/Kconfig           |   7 +
>>>    drivers/thermal/broadcom/Makefile          |   1 +
>>>    drivers/thermal/broadcom/brcmstb_thermal.c | 387
>>> +++++++++++++++++++++++++++++
>>>    4 files changed, 396 insertions(+), 1 deletion(-)
>>>    create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>>
>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>> index 07002df..96774a7 100644
>>> --- a/drivers/thermal/Kconfig
>>> +++ b/drivers/thermal/Kconfig
>>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>>            controller present in Mediatek SoCs
>>>      menu "Broadcom thermal drivers"
>>> -depends on ARCH_BCM || COMPILE_TEST
>>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>> No need for this additional depends.  ARCH_BCM is always defined before
>> ARCH_BRCMSTB can be selected.
> ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
> does. So, we do need both or the driver won't be built on ARM64.
> (After internal discussions we went with that approach rather than
> defining ARCH_BCM on ARM64.)
Got it.  Looking at our internal iproc tree I see we've done exactly the 
same with ARCH_BCM_IPROC needing to be added.  We haven't upstreamed
the thermal driver needing it yet.

Perhaps we should add ARCH_BCM to ARM64....

>
>>>    source "drivers/thermal/broadcom/Kconfig"
>>>    endmenu
>>>    diff --git a/drivers/thermal/broadcom/Kconfig
>>> b/drivers/thermal/broadcom/Kconfig
>>> index 42c098e..c106a15 100644
>>> --- a/drivers/thermal/broadcom/Kconfig
>>> +++ b/drivers/thermal/broadcom/Kconfig
>>> @@ -6,6 +6,13 @@ config BCM2835_THERMAL
>>>          help
>>>            Support for thermal sensors on Broadcom bcm2835 SoCs.
>>>    +config BRCMSTB_THERMAL
>>> +       tristate "Broadcom STB AVS TMON thermal driver"
>>> +       depends on ARCH_BRCMSTB || COMPILE_TEST
>>> +       help
>>> +         Enable this driver if you have a Broadcom STB SoC and would like
>>> +         thermal framework support.
>>> +
>>>    config BCM_NS_THERMAL
>>>          tristate "Northstar thermal driver"
>>>          depends on ARCH_BCM_IPROC || COMPILE_TEST
>>> diff --git a/drivers/thermal/broadcom/Makefile
>>> b/drivers/thermal/broadcom/Makefile
>>> index c6f62e4..fae10ec 100644
>>> --- a/drivers/thermal/broadcom/Makefile
>>> +++ b/drivers/thermal/broadcom/Makefile
>>> @@ -1,2 +1,3 @@
>>>    obj-$(CONFIG_BCM2835_THERMAL)         += bcm2835_thermal.o
>>> +obj-$(CONFIG_BRCMSTB_THERMAL)          += brcmstb_thermal.o
>>>    obj-$(CONFIG_BCM_NS_THERMAL)          += ns-thermal.o
>>> diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c
>>> b/drivers/thermal/broadcom/brcmstb_thermal.c
>>> new file mode 100644
>>> index 0000000..1919f91
>>> --- /dev/null
>>> +++ b/drivers/thermal/broadcom/brcmstb_thermal.c
>>> @@ -0,0 +1,387 @@
>>>
>>> +/*
>>> + * Broadcom STB AVS TMON thermal sensor driver
>>> + *
>>> + * Copyright (c) 2015-2017 Broadcom
>>> + *
>>> + * This software is licensed under the terms of the GNU General Public
>>> + * License version 2, as published by the Free Software Foundation, and
>>> + * may be copied, distributed, and modified under those terms.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + */
>>> +
>>> +#define DRV_NAME       "brcmstb_thermal"
>>> +
>>> +#define pr_fmt(fmt)    DRV_NAME ": " fmt
>>> +
>>> +#include <linux/bitops.h>
>>> +#include <linux/device.h>
>>> +#include <linux/err.h>
>>> +#include <linux/io.h>
>>> +#include <linux/irqreturn.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/thermal.h>
>>> +
>>> +#define AVS_TMON_STATUS                        0x00
>>> + #define AVS_TMON_STATUS_valid_msk     BIT(11)
>>> + #define AVS_TMON_STATUS_data_msk      GENMASK(10, 1)
>>> + #define AVS_TMON_STATUS_data_shift    1
>>> +
>>> +#define AVS_TMON_EN_OVERTEMP_RESET     0x04
>>> + #define AVS_TMON_EN_OVERTEMP_RESET_msk        BIT(0)
>>> +
>>> +#define AVS_TMON_RESET_THRESH          0x08
>>> + #define AVS_TMON_RESET_THRESH_msk     GENMASK(10, 1)
>>> + #define AVS_TMON_RESET_THRESH_shift   1
>>> +
>>> +#define AVS_TMON_INT_IDLE_TIME         0x10
>>> +
>>> +#define AVS_TMON_EN_TEMP_INT_SRCS      0x14
>>> + #define AVS_TMON_EN_TEMP_INT_SRCS_high        BIT(1)
>>> + #define AVS_TMON_EN_TEMP_INT_SRCS_low BIT(0)
>>> +
>>> +#define AVS_TMON_INT_THRESH            0x18
>>> + #define AVS_TMON_INT_THRESH_high_msk  GENMASK(26, 17)
>>> + #define AVS_TMON_INT_THRESH_high_shift        17
>>> + #define AVS_TMON_INT_THRESH_low_msk   GENMASK(10, 1)
>>> + #define AVS_TMON_INT_THRESH_low_shift 1
>>> +
>>> +#define AVS_TMON_TEMP_INT_CODE         0x1c
>>> +#define AVS_TMON_TP_TEST_ENABLE                0x20
>>> +
>>> +/* Default coefficients */
>>> +#define AVS_TMON_TEMP_SLOPE            -487
>>> +#define AVS_TMON_TEMP_OFFSET           410040
>>> +
>>> +/* HW related temperature constants */
>>> +#define AVS_TMON_TEMP_MAX              0x3ff
>>> +#define AVS_TMON_TEMP_MIN              -88161
>>> +#define AVS_TMON_TEMP_MASK             AVS_TMON_TEMP_MAX
>>> +
>>> +enum avs_tmon_trip_type {
>>> +       TMON_TRIP_TYPE_LOW = 0,
>>> +       TMON_TRIP_TYPE_HIGH,
>>> +       TMON_TRIP_TYPE_RESET,
>>> +       TMON_TRIP_TYPE_MAX,
>>> +};
>>> +
>>> +struct avs_tmon_trip {
>>> +       /* HW bit to enable the trip */
>>> +       u32 enable_offs;
>>> +       u32 enable_mask;
>>> +
>>> +       /* HW field to read the trip temperature */
>>> +       u32 reg_offs;
>>> +       u32 reg_msk;
>>> +       int reg_shift;
>>> +};
>>> +
>>> +static struct avs_tmon_trip avs_tmon_trips[] = {
>>> +       /* Trips when temperature is below threshold */
>>> +       [TMON_TRIP_TYPE_LOW] = {
>>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_low,
>>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>>> +               .reg_msk        = AVS_TMON_INT_THRESH_low_msk,
>>> +               .reg_shift      = AVS_TMON_INT_THRESH_low_shift,
>>> +       },
>>> +       /* Trips when temperature is above threshold */
>>> +       [TMON_TRIP_TYPE_HIGH] = {
>>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_high,
>>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>>> +               .reg_msk        = AVS_TMON_INT_THRESH_high_msk,
>>> +               .reg_shift      = AVS_TMON_INT_THRESH_high_shift,
>>> +       },
>>> +       /* Automatically resets chip when above threshold */
>>> +       [TMON_TRIP_TYPE_RESET] = {
>>> +               .enable_offs    = AVS_TMON_EN_OVERTEMP_RESET,
>>> +               .enable_mask    = AVS_TMON_EN_OVERTEMP_RESET_msk,
>>> +               .reg_offs       = AVS_TMON_RESET_THRESH,
>>> +               .reg_msk        = AVS_TMON_RESET_THRESH_msk,
>>> +               .reg_shift      = AVS_TMON_RESET_THRESH_shift,
>>> +       },
>>> +};
>>> +
>>> +struct brcmstb_thermal_priv {
>>> +       void __iomem *tmon_base;
>>> +       struct device *dev;
>>> +       struct thermal_zone_device *thermal;
>>> +};
>>> +
>>> +static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int
>>> *slope,
>>> +                               int *offset)
>>> +{
>>> +       *slope = thermal_zone_get_slope(tz);
>>> +       *offset = thermal_zone_get_offset(tz);
>>> +}
>>> +
>>> +/* Convert a HW code to a temperature reading (millidegree celsius) */
>>> +static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
>>> +                                       u32 code)
>>> +{
>>> +       const int val = code & AVS_TMON_TEMP_MASK;
>>> +       int slope, offset;
>>> +
>>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>>> +
>>> +       return slope * val + offset;
>>> +}
>>> +
>>> +/*
>>> + * Convert a temperature value (millidegree celsius) to a HW code
>>> + *
>>> + * @temp: temperature to convert
>>> + * @low: if true, round toward the low side
>>> + */
>>> +static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
>>> +                                       int temp, bool low)
>>> +{
>>> +       int slope, offset;
>>> +
>>> +       if (temp < AVS_TMON_TEMP_MIN)
>>> +               return AVS_TMON_TEMP_MAX; /* Maximum code value */
>>> +
>>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>>> +
>>> +       if (temp >= offset)
>>> +               return 0;       /* Minimum code value */
>>> +
>>> +       if (low)
>>> +               return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
>>> +       else
>>> +               return (u32)((offset - temp) / abs(slope));
>>> +}
>>> +
>>> +static int brcmstb_get_temp(void *data, int *temp)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = data;
>>> +       u32 val;
>>> +       long t;
>>> +
>>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
>>> +
>>> +       if (!(val & AVS_TMON_STATUS_valid_msk)) {
>>> +               dev_err(priv->dev, "reading not valid\n");
>>> +               return -EIO;
>>> +       }
>>> +
>>> +       val = (val & AVS_TMON_STATUS_data_msk) >>
>>> AVS_TMON_STATUS_data_shift;
>>> +
>>> +       t = avs_tmon_code_to_temp(priv->thermal, val);
>>> +       if (t < 0)
>>> +               *temp = 0;
>>> +       else
>>> +               *temp = t;
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
>>> +                                enum avs_tmon_trip_type type, int en)
>>> +{
>>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>>> +       u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
>>> +
>>> +       dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis",
>>> type);
>>> +
>>> +       if (en)
>>> +               val |= trip->enable_mask;
>>> +       else
>>> +               val &= ~trip->enable_mask;
>>> +
>>> +       __raw_writel(val, priv->tmon_base + trip->enable_offs);
>>> +}
>>> +
>>> +static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
>>> +                                 enum avs_tmon_trip_type type)
>>> +{
>>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>>> +       u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
>>> +
>>> +       val &= trip->reg_msk;
>>> +       val >>= trip->reg_shift;
>>> +
>>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>>> +}
>>> +
>>> +static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
>>> +                                  enum avs_tmon_trip_type type,
>>> +                                  int temp)
>>> +{
>>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>>> +       u32 val, orig;
>>> +
>>> +       dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
>>> +
>>> +       /* round toward low temp for the low interrupt */
>>> +       val = avs_tmon_temp_to_code(priv->thermal, temp,
>>> +                                   type == TMON_TRIP_TYPE_LOW);
>>> +
>>> +       val <<= trip->reg_shift;
>>> +       val &= trip->reg_msk;
>>> +
>>> +       orig = __raw_readl(priv->tmon_base + trip->reg_offs);
>>> +       orig &= ~trip->reg_msk;
>>> +       orig |= val;
>>> +       __raw_writel(orig, priv->tmon_base + trip->reg_offs);
>>> +}
>>> +
>>> +static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
>>> +{
>>> +       u32 val;
>>> +
>>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
>>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>>> +}
>>> +
>>> +static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = data;
>>> +       int low, high, intr;
>>> +
>>> +       low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
>>> +       high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
>>> +       intr = avs_tmon_get_intr_temp(priv);
>>> +
>>> +       dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
>>> +                       low, intr, high);
>>> +
>>> +       /* Disable high-temp until next threshold shift */
>>> +       if (intr >= high)
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>>> +       /* Disable low-temp until next threshold shift */
>>> +       if (intr <= low)
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>>> +
>>> +       /*
>>> +        * Notify using the interrupt temperature, in case the temperature
>>> +        * changes before it can next be read out
>>> +        */
>>> +       thermal_zone_device_update(priv->thermal, intr);
>>> +
>>> +       return IRQ_HANDLED;
>>> +}
>>> +
>>> +static int brcmstb_set_trips(void *data, int low, int high)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = data;
>>> +
>>> +       dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
>>> +
>>> +       /*
>>> +        * Disable low-temp if "low" is too small. As per thermal
>>> framework
>>> +        * API, we use -INT_MAX rather than INT_MIN.
>>> +        */
>>> +       if (low <= -INT_MAX) {
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>>> +       } else {
>>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
>>> +       }
>>> +
>>> +       /* Disable high-temp if "high" is too big. */
>>> +       if (high == INT_MAX) {
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>>> +       } else {
>>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static struct thermal_zone_of_device_ops of_ops = {
>>> +       .get_temp       = brcmstb_get_temp,
>>> +       .set_trips      = brcmstb_set_trips,
>>> +};
>>> +
>>> +static const struct of_device_id brcmstb_thermal_id_table[] = {
>>> +       { .compatible = "brcm,avs-tmon" },
>>> +       {},
>>> +};
>>> +MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
>>> +
>>> +static int brcmstb_thermal_probe(struct platform_device *pdev)
>>> +{
>>> +       struct thermal_zone_device *thermal;
>>> +       struct brcmstb_thermal_priv *priv;
>>> +       struct resource *res;
>>> +       int irq, ret;
>>> +
>>> +       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>>> +       if (!priv)
>>> +               return -ENOMEM;
>>> +
>>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +       priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
>>> +       if (IS_ERR(priv->tmon_base))
>>> +               return PTR_ERR(priv->tmon_base);
>>> +
>>> +       priv->dev = &pdev->dev;
>>> +       platform_set_drvdata(pdev, priv);
>>> +
>>> +       thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
>>> &of_ops);
>>> +       if (IS_ERR(thermal)) {
>>> +               ret = PTR_ERR(thermal);
>>> +               dev_err(&pdev->dev, "could not register sensor: %d\n",
>>> ret);
>>> +               return ret;
>>> +       }
>>> +
>>> +       priv->thermal = thermal;
>>> +
>>> +       irq = platform_get_irq(pdev, 0);
>>> +       if (irq < 0) {
>>> +               dev_err(&pdev->dev, "could not get IRQ\n");
>>> +               ret = irq;
>>> +               goto err;
>>> +       }
>>> +       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
>>> +                                       brcmstb_tmon_irq_thread,
>>> IRQF_ONESHOT,
>>> +                                       DRV_NAME, priv);
>>> +       if (ret < 0) {
>>> +               dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
>>> +               goto err;
>>> +       }
>>> +
>>> +       dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
>>> +
>>> +       return 0;
>>> +
>>> +err:
>>> +       thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
>>> +       return ret;
>>> +}
>>> +
>>> +static int brcmstb_thermal_exit(struct platform_device *pdev)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
>>> +       struct thermal_zone_device *thermal = priv->thermal;
>>> +
>>> +       if (thermal)
>>> +               thermal_zone_of_sensor_unregister(&pdev->dev,
>>> priv->thermal);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static struct platform_driver brcmstb_thermal_driver = {
>>> +       .probe = brcmstb_thermal_probe,
>>> +       .remove = brcmstb_thermal_exit,
>>> +       .driver = {
>>> +               .name = DRV_NAME,
>>> +               .of_match_table = brcmstb_thermal_id_table,
>>> +       },
>>> +};
>>> +module_platform_driver(brcmstb_thermal_driver);
>>> +
>>> +MODULE_LICENSE("GPL v2");
>>> +MODULE_AUTHOR("Brian Norris");
>>> +MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
>>

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 22:08         ` Scott Branden
  0 siblings, 0 replies; 27+ messages in thread
From: Scott Branden @ 2017-09-26 22:08 UTC (permalink / raw)
  To: linux-arm-kernel



On 17-09-26 02:38 PM, Markus Mayer wrote:
> On 26 September 2017 at 14:32, Scott Branden <scott.branden@broadcom.com> wrote:
>> Hi Markus,
>>
>>
>> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>> From: Brian Norris <computersforpeace@gmail.com>
>>>
>>> The AVS TMON core provides temperature readings, a pair of configurable
>>> high- and low-temperature threshold interrupts, and an emergency
>>> over-temperature chip reset. The driver utilizes the first two to
>>> provide temperature readings and high-temperature notifications to
>>> applications. The over-temperature reset is not exposed to
>>> applications; this reset threshold is critical to the system and should
>>> be set with care within the bootloader.
>>>
>>> Applications may choose to utilize the notification mechanism, the
>>> temperature reading mechanism (e.g., through polling), or both.
>>>
>>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>>> ---
>>>    drivers/thermal/Kconfig                    |   2 +-
>>>    drivers/thermal/broadcom/Kconfig           |   7 +
>>>    drivers/thermal/broadcom/Makefile          |   1 +
>>>    drivers/thermal/broadcom/brcmstb_thermal.c | 387
>>> +++++++++++++++++++++++++++++
>>>    4 files changed, 396 insertions(+), 1 deletion(-)
>>>    create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>>
>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>> index 07002df..96774a7 100644
>>> --- a/drivers/thermal/Kconfig
>>> +++ b/drivers/thermal/Kconfig
>>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>>            controller present in Mediatek SoCs
>>>      menu "Broadcom thermal drivers"
>>> -depends on ARCH_BCM || COMPILE_TEST
>>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>> No need for this additional depends.  ARCH_BCM is always defined before
>> ARCH_BRCMSTB can be selected.
> ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
> does. So, we do need both or the driver won't be built on ARM64.
> (After internal discussions we went with that approach rather than
> defining ARCH_BCM on ARM64.)
Got it.  Looking at our internal iproc tree I see we've done exactly the 
same with ARCH_BCM_IPROC needing to be added.  We haven't upstreamed
the thermal driver needing it yet.

Perhaps we should add ARCH_BCM to ARM64....

>
>>>    source "drivers/thermal/broadcom/Kconfig"
>>>    endmenu
>>>    diff --git a/drivers/thermal/broadcom/Kconfig
>>> b/drivers/thermal/broadcom/Kconfig
>>> index 42c098e..c106a15 100644
>>> --- a/drivers/thermal/broadcom/Kconfig
>>> +++ b/drivers/thermal/broadcom/Kconfig
>>> @@ -6,6 +6,13 @@ config BCM2835_THERMAL
>>>          help
>>>            Support for thermal sensors on Broadcom bcm2835 SoCs.
>>>    +config BRCMSTB_THERMAL
>>> +       tristate "Broadcom STB AVS TMON thermal driver"
>>> +       depends on ARCH_BRCMSTB || COMPILE_TEST
>>> +       help
>>> +         Enable this driver if you have a Broadcom STB SoC and would like
>>> +         thermal framework support.
>>> +
>>>    config BCM_NS_THERMAL
>>>          tristate "Northstar thermal driver"
>>>          depends on ARCH_BCM_IPROC || COMPILE_TEST
>>> diff --git a/drivers/thermal/broadcom/Makefile
>>> b/drivers/thermal/broadcom/Makefile
>>> index c6f62e4..fae10ec 100644
>>> --- a/drivers/thermal/broadcom/Makefile
>>> +++ b/drivers/thermal/broadcom/Makefile
>>> @@ -1,2 +1,3 @@
>>>    obj-$(CONFIG_BCM2835_THERMAL)         += bcm2835_thermal.o
>>> +obj-$(CONFIG_BRCMSTB_THERMAL)          += brcmstb_thermal.o
>>>    obj-$(CONFIG_BCM_NS_THERMAL)          += ns-thermal.o
>>> diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c
>>> b/drivers/thermal/broadcom/brcmstb_thermal.c
>>> new file mode 100644
>>> index 0000000..1919f91
>>> --- /dev/null
>>> +++ b/drivers/thermal/broadcom/brcmstb_thermal.c
>>> @@ -0,0 +1,387 @@
>>>
>>> +/*
>>> + * Broadcom STB AVS TMON thermal sensor driver
>>> + *
>>> + * Copyright (c) 2015-2017 Broadcom
>>> + *
>>> + * This software is licensed under the terms of the GNU General Public
>>> + * License version 2, as published by the Free Software Foundation, and
>>> + * may be copied, distributed, and modified under those terms.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + */
>>> +
>>> +#define DRV_NAME       "brcmstb_thermal"
>>> +
>>> +#define pr_fmt(fmt)    DRV_NAME ": " fmt
>>> +
>>> +#include <linux/bitops.h>
>>> +#include <linux/device.h>
>>> +#include <linux/err.h>
>>> +#include <linux/io.h>
>>> +#include <linux/irqreturn.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/thermal.h>
>>> +
>>> +#define AVS_TMON_STATUS                        0x00
>>> + #define AVS_TMON_STATUS_valid_msk     BIT(11)
>>> + #define AVS_TMON_STATUS_data_msk      GENMASK(10, 1)
>>> + #define AVS_TMON_STATUS_data_shift    1
>>> +
>>> +#define AVS_TMON_EN_OVERTEMP_RESET     0x04
>>> + #define AVS_TMON_EN_OVERTEMP_RESET_msk        BIT(0)
>>> +
>>> +#define AVS_TMON_RESET_THRESH          0x08
>>> + #define AVS_TMON_RESET_THRESH_msk     GENMASK(10, 1)
>>> + #define AVS_TMON_RESET_THRESH_shift   1
>>> +
>>> +#define AVS_TMON_INT_IDLE_TIME         0x10
>>> +
>>> +#define AVS_TMON_EN_TEMP_INT_SRCS      0x14
>>> + #define AVS_TMON_EN_TEMP_INT_SRCS_high        BIT(1)
>>> + #define AVS_TMON_EN_TEMP_INT_SRCS_low BIT(0)
>>> +
>>> +#define AVS_TMON_INT_THRESH            0x18
>>> + #define AVS_TMON_INT_THRESH_high_msk  GENMASK(26, 17)
>>> + #define AVS_TMON_INT_THRESH_high_shift        17
>>> + #define AVS_TMON_INT_THRESH_low_msk   GENMASK(10, 1)
>>> + #define AVS_TMON_INT_THRESH_low_shift 1
>>> +
>>> +#define AVS_TMON_TEMP_INT_CODE         0x1c
>>> +#define AVS_TMON_TP_TEST_ENABLE                0x20
>>> +
>>> +/* Default coefficients */
>>> +#define AVS_TMON_TEMP_SLOPE            -487
>>> +#define AVS_TMON_TEMP_OFFSET           410040
>>> +
>>> +/* HW related temperature constants */
>>> +#define AVS_TMON_TEMP_MAX              0x3ff
>>> +#define AVS_TMON_TEMP_MIN              -88161
>>> +#define AVS_TMON_TEMP_MASK             AVS_TMON_TEMP_MAX
>>> +
>>> +enum avs_tmon_trip_type {
>>> +       TMON_TRIP_TYPE_LOW = 0,
>>> +       TMON_TRIP_TYPE_HIGH,
>>> +       TMON_TRIP_TYPE_RESET,
>>> +       TMON_TRIP_TYPE_MAX,
>>> +};
>>> +
>>> +struct avs_tmon_trip {
>>> +       /* HW bit to enable the trip */
>>> +       u32 enable_offs;
>>> +       u32 enable_mask;
>>> +
>>> +       /* HW field to read the trip temperature */
>>> +       u32 reg_offs;
>>> +       u32 reg_msk;
>>> +       int reg_shift;
>>> +};
>>> +
>>> +static struct avs_tmon_trip avs_tmon_trips[] = {
>>> +       /* Trips when temperature is below threshold */
>>> +       [TMON_TRIP_TYPE_LOW] = {
>>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_low,
>>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>>> +               .reg_msk        = AVS_TMON_INT_THRESH_low_msk,
>>> +               .reg_shift      = AVS_TMON_INT_THRESH_low_shift,
>>> +       },
>>> +       /* Trips when temperature is above threshold */
>>> +       [TMON_TRIP_TYPE_HIGH] = {
>>> +               .enable_offs    = AVS_TMON_EN_TEMP_INT_SRCS,
>>> +               .enable_mask    = AVS_TMON_EN_TEMP_INT_SRCS_high,
>>> +               .reg_offs       = AVS_TMON_INT_THRESH,
>>> +               .reg_msk        = AVS_TMON_INT_THRESH_high_msk,
>>> +               .reg_shift      = AVS_TMON_INT_THRESH_high_shift,
>>> +       },
>>> +       /* Automatically resets chip when above threshold */
>>> +       [TMON_TRIP_TYPE_RESET] = {
>>> +               .enable_offs    = AVS_TMON_EN_OVERTEMP_RESET,
>>> +               .enable_mask    = AVS_TMON_EN_OVERTEMP_RESET_msk,
>>> +               .reg_offs       = AVS_TMON_RESET_THRESH,
>>> +               .reg_msk        = AVS_TMON_RESET_THRESH_msk,
>>> +               .reg_shift      = AVS_TMON_RESET_THRESH_shift,
>>> +       },
>>> +};
>>> +
>>> +struct brcmstb_thermal_priv {
>>> +       void __iomem *tmon_base;
>>> +       struct device *dev;
>>> +       struct thermal_zone_device *thermal;
>>> +};
>>> +
>>> +static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int
>>> *slope,
>>> +                               int *offset)
>>> +{
>>> +       *slope = thermal_zone_get_slope(tz);
>>> +       *offset = thermal_zone_get_offset(tz);
>>> +}
>>> +
>>> +/* Convert a HW code to a temperature reading (millidegree celsius) */
>>> +static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
>>> +                                       u32 code)
>>> +{
>>> +       const int val = code & AVS_TMON_TEMP_MASK;
>>> +       int slope, offset;
>>> +
>>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>>> +
>>> +       return slope * val + offset;
>>> +}
>>> +
>>> +/*
>>> + * Convert a temperature value (millidegree celsius) to a HW code
>>> + *
>>> + * @temp: temperature to convert
>>> + * @low: if true, round toward the low side
>>> + */
>>> +static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
>>> +                                       int temp, bool low)
>>> +{
>>> +       int slope, offset;
>>> +
>>> +       if (temp < AVS_TMON_TEMP_MIN)
>>> +               return AVS_TMON_TEMP_MAX; /* Maximum code value */
>>> +
>>> +       avs_tmon_get_coeffs(tz, &slope, &offset);
>>> +
>>> +       if (temp >= offset)
>>> +               return 0;       /* Minimum code value */
>>> +
>>> +       if (low)
>>> +               return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
>>> +       else
>>> +               return (u32)((offset - temp) / abs(slope));
>>> +}
>>> +
>>> +static int brcmstb_get_temp(void *data, int *temp)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = data;
>>> +       u32 val;
>>> +       long t;
>>> +
>>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
>>> +
>>> +       if (!(val & AVS_TMON_STATUS_valid_msk)) {
>>> +               dev_err(priv->dev, "reading not valid\n");
>>> +               return -EIO;
>>> +       }
>>> +
>>> +       val = (val & AVS_TMON_STATUS_data_msk) >>
>>> AVS_TMON_STATUS_data_shift;
>>> +
>>> +       t = avs_tmon_code_to_temp(priv->thermal, val);
>>> +       if (t < 0)
>>> +               *temp = 0;
>>> +       else
>>> +               *temp = t;
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
>>> +                                enum avs_tmon_trip_type type, int en)
>>> +{
>>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>>> +       u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
>>> +
>>> +       dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis",
>>> type);
>>> +
>>> +       if (en)
>>> +               val |= trip->enable_mask;
>>> +       else
>>> +               val &= ~trip->enable_mask;
>>> +
>>> +       __raw_writel(val, priv->tmon_base + trip->enable_offs);
>>> +}
>>> +
>>> +static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
>>> +                                 enum avs_tmon_trip_type type)
>>> +{
>>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>>> +       u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
>>> +
>>> +       val &= trip->reg_msk;
>>> +       val >>= trip->reg_shift;
>>> +
>>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>>> +}
>>> +
>>> +static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
>>> +                                  enum avs_tmon_trip_type type,
>>> +                                  int temp)
>>> +{
>>> +       struct avs_tmon_trip *trip = &avs_tmon_trips[type];
>>> +       u32 val, orig;
>>> +
>>> +       dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
>>> +
>>> +       /* round toward low temp for the low interrupt */
>>> +       val = avs_tmon_temp_to_code(priv->thermal, temp,
>>> +                                   type == TMON_TRIP_TYPE_LOW);
>>> +
>>> +       val <<= trip->reg_shift;
>>> +       val &= trip->reg_msk;
>>> +
>>> +       orig = __raw_readl(priv->tmon_base + trip->reg_offs);
>>> +       orig &= ~trip->reg_msk;
>>> +       orig |= val;
>>> +       __raw_writel(orig, priv->tmon_base + trip->reg_offs);
>>> +}
>>> +
>>> +static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
>>> +{
>>> +       u32 val;
>>> +
>>> +       val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
>>> +       return avs_tmon_code_to_temp(priv->thermal, val);
>>> +}
>>> +
>>> +static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = data;
>>> +       int low, high, intr;
>>> +
>>> +       low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
>>> +       high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
>>> +       intr = avs_tmon_get_intr_temp(priv);
>>> +
>>> +       dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
>>> +                       low, intr, high);
>>> +
>>> +       /* Disable high-temp until next threshold shift */
>>> +       if (intr >= high)
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>>> +       /* Disable low-temp until next threshold shift */
>>> +       if (intr <= low)
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>>> +
>>> +       /*
>>> +        * Notify using the interrupt temperature, in case the temperature
>>> +        * changes before it can next be read out
>>> +        */
>>> +       thermal_zone_device_update(priv->thermal, intr);
>>> +
>>> +       return IRQ_HANDLED;
>>> +}
>>> +
>>> +static int brcmstb_set_trips(void *data, int low, int high)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = data;
>>> +
>>> +       dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
>>> +
>>> +       /*
>>> +        * Disable low-temp if "low" is too small. As per thermal
>>> framework
>>> +        * API, we use -INT_MAX rather than INT_MIN.
>>> +        */
>>> +       if (low <= -INT_MAX) {
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
>>> +       } else {
>>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
>>> +       }
>>> +
>>> +       /* Disable high-temp if "high" is too big. */
>>> +       if (high == INT_MAX) {
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
>>> +       } else {
>>> +               avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
>>> +               avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static struct thermal_zone_of_device_ops of_ops = {
>>> +       .get_temp       = brcmstb_get_temp,
>>> +       .set_trips      = brcmstb_set_trips,
>>> +};
>>> +
>>> +static const struct of_device_id brcmstb_thermal_id_table[] = {
>>> +       { .compatible = "brcm,avs-tmon" },
>>> +       {},
>>> +};
>>> +MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
>>> +
>>> +static int brcmstb_thermal_probe(struct platform_device *pdev)
>>> +{
>>> +       struct thermal_zone_device *thermal;
>>> +       struct brcmstb_thermal_priv *priv;
>>> +       struct resource *res;
>>> +       int irq, ret;
>>> +
>>> +       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>>> +       if (!priv)
>>> +               return -ENOMEM;
>>> +
>>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +       priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
>>> +       if (IS_ERR(priv->tmon_base))
>>> +               return PTR_ERR(priv->tmon_base);
>>> +
>>> +       priv->dev = &pdev->dev;
>>> +       platform_set_drvdata(pdev, priv);
>>> +
>>> +       thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
>>> &of_ops);
>>> +       if (IS_ERR(thermal)) {
>>> +               ret = PTR_ERR(thermal);
>>> +               dev_err(&pdev->dev, "could not register sensor: %d\n",
>>> ret);
>>> +               return ret;
>>> +       }
>>> +
>>> +       priv->thermal = thermal;
>>> +
>>> +       irq = platform_get_irq(pdev, 0);
>>> +       if (irq < 0) {
>>> +               dev_err(&pdev->dev, "could not get IRQ\n");
>>> +               ret = irq;
>>> +               goto err;
>>> +       }
>>> +       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
>>> +                                       brcmstb_tmon_irq_thread,
>>> IRQF_ONESHOT,
>>> +                                       DRV_NAME, priv);
>>> +       if (ret < 0) {
>>> +               dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
>>> +               goto err;
>>> +       }
>>> +
>>> +       dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
>>> +
>>> +       return 0;
>>> +
>>> +err:
>>> +       thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
>>> +       return ret;
>>> +}
>>> +
>>> +static int brcmstb_thermal_exit(struct platform_device *pdev)
>>> +{
>>> +       struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
>>> +       struct thermal_zone_device *thermal = priv->thermal;
>>> +
>>> +       if (thermal)
>>> +               thermal_zone_of_sensor_unregister(&pdev->dev,
>>> priv->thermal);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static struct platform_driver brcmstb_thermal_driver = {
>>> +       .probe = brcmstb_thermal_probe,
>>> +       .remove = brcmstb_thermal_exit,
>>> +       .driver = {
>>> +               .name = DRV_NAME,
>>> +               .of_match_table = brcmstb_thermal_id_table,
>>> +       },
>>> +};
>>> +module_platform_driver(brcmstb_thermal_driver);
>>> +
>>> +MODULE_LICENSE("GPL v2");
>>> +MODULE_AUTHOR("Brian Norris");
>>> +MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
>>

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

* Re: [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 22:14           ` Florian Fainelli
  0 siblings, 0 replies; 27+ messages in thread
From: Florian Fainelli @ 2017-09-26 22:14 UTC (permalink / raw)
  To: Scott Branden, Markus Mayer
  Cc: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki, Broadcom Kernel List,
	Power Management List, Device Tree List, ARM Kernel List,
	Linux Kernel Mailing List, Markus Mayer

On 09/26/2017 03:08 PM, Scott Branden wrote:
> 
> 
> On 17-09-26 02:38 PM, Markus Mayer wrote:
>> On 26 September 2017 at 14:32, Scott Branden
>> <scott.branden@broadcom.com> wrote:
>>> Hi Markus,
>>>
>>>
>>> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>>> From: Brian Norris <computersforpeace@gmail.com>
>>>>
>>>> The AVS TMON core provides temperature readings, a pair of configurable
>>>> high- and low-temperature threshold interrupts, and an emergency
>>>> over-temperature chip reset. The driver utilizes the first two to
>>>> provide temperature readings and high-temperature notifications to
>>>> applications. The over-temperature reset is not exposed to
>>>> applications; this reset threshold is critical to the system and should
>>>> be set with care within the bootloader.
>>>>
>>>> Applications may choose to utilize the notification mechanism, the
>>>> temperature reading mechanism (e.g., through polling), or both.
>>>>
>>>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>>>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>>>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>>>> ---
>>>>    drivers/thermal/Kconfig                    |   2 +-
>>>>    drivers/thermal/broadcom/Kconfig           |   7 +
>>>>    drivers/thermal/broadcom/Makefile          |   1 +
>>>>    drivers/thermal/broadcom/brcmstb_thermal.c | 387
>>>> +++++++++++++++++++++++++++++
>>>>    4 files changed, 396 insertions(+), 1 deletion(-)
>>>>    create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index 07002df..96774a7 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>>>            controller present in Mediatek SoCs
>>>>      menu "Broadcom thermal drivers"
>>>> -depends on ARCH_BCM || COMPILE_TEST
>>>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>>> No need for this additional depends.  ARCH_BCM is always defined before
>>> ARCH_BRCMSTB can be selected.
>> ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
>> does. So, we do need both or the driver won't be built on ARM64.
>> (After internal discussions we went with that approach rather than
>> defining ARCH_BCM on ARM64.)
> Got it.  Looking at our internal iproc tree I see we've done exactly the
> same with ARCH_BCM_IPROC needing to be added.  We haven't upstreamed
> the thermal driver needing it yet.
> 
> Perhaps we should add ARCH_BCM to ARM64....

If it is just added to satisfy dependencies, I don't see much value in
doing that. It does make sense in the ARM v7 multiplatform context, but
outside of that, not so sur.
-- 
Florian

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

* Re: [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 22:14           ` Florian Fainelli
  0 siblings, 0 replies; 27+ messages in thread
From: Florian Fainelli @ 2017-09-26 22:14 UTC (permalink / raw)
  To: Scott Branden, Markus Mayer
  Cc: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Florian Fainelli,
	Rafał Miłecki, Broadcom Kernel List,
	Power Management List, Device Tree List, ARM Kernel List,
	Linux Kernel Mailing List, Markus Mayer

On 09/26/2017 03:08 PM, Scott Branden wrote:
> 
> 
> On 17-09-26 02:38 PM, Markus Mayer wrote:
>> On 26 September 2017 at 14:32, Scott Branden
>> <scott.branden-dY08KVG/lbpWk0Htik3J/w@public.gmane.org> wrote:
>>> Hi Markus,
>>>
>>>
>>> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>>> From: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>>>>
>>>> The AVS TMON core provides temperature readings, a pair of configurable
>>>> high- and low-temperature threshold interrupts, and an emergency
>>>> over-temperature chip reset. The driver utilizes the first two to
>>>> provide temperature readings and high-temperature notifications to
>>>> applications. The over-temperature reset is not exposed to
>>>> applications; this reset threshold is critical to the system and should
>>>> be set with care within the bootloader.
>>>>
>>>> Applications may choose to utilize the notification mechanism, the
>>>> temperature reading mechanism (e.g., through polling), or both.
>>>>
>>>> Signed-off-by: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>>>> Signed-off-by: Doug Berger <opendmb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>>>> Signed-off-by: Markus Mayer <mmayer-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
>>>> ---
>>>>    drivers/thermal/Kconfig                    |   2 +-
>>>>    drivers/thermal/broadcom/Kconfig           |   7 +
>>>>    drivers/thermal/broadcom/Makefile          |   1 +
>>>>    drivers/thermal/broadcom/brcmstb_thermal.c | 387
>>>> +++++++++++++++++++++++++++++
>>>>    4 files changed, 396 insertions(+), 1 deletion(-)
>>>>    create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index 07002df..96774a7 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>>>            controller present in Mediatek SoCs
>>>>      menu "Broadcom thermal drivers"
>>>> -depends on ARCH_BCM || COMPILE_TEST
>>>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>>> No need for this additional depends.  ARCH_BCM is always defined before
>>> ARCH_BRCMSTB can be selected.
>> ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
>> does. So, we do need both or the driver won't be built on ARM64.
>> (After internal discussions we went with that approach rather than
>> defining ARCH_BCM on ARM64.)
> Got it.  Looking at our internal iproc tree I see we've done exactly the
> same with ARCH_BCM_IPROC needing to be added.  We haven't upstreamed
> the thermal driver needing it yet.
> 
> Perhaps we should add ARCH_BCM to ARM64....

If it is just added to satisfy dependencies, I don't see much value in
doing that. It does make sense in the ARM v7 multiplatform context, but
outside of that, not so sur.
-- 
Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 22:14           ` Florian Fainelli
  0 siblings, 0 replies; 27+ messages in thread
From: Florian Fainelli @ 2017-09-26 22:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/26/2017 03:08 PM, Scott Branden wrote:
> 
> 
> On 17-09-26 02:38 PM, Markus Mayer wrote:
>> On 26 September 2017 at 14:32, Scott Branden
>> <scott.branden@broadcom.com> wrote:
>>> Hi Markus,
>>>
>>>
>>> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>>> From: Brian Norris <computersforpeace@gmail.com>
>>>>
>>>> The AVS TMON core provides temperature readings, a pair of configurable
>>>> high- and low-temperature threshold interrupts, and an emergency
>>>> over-temperature chip reset. The driver utilizes the first two to
>>>> provide temperature readings and high-temperature notifications to
>>>> applications. The over-temperature reset is not exposed to
>>>> applications; this reset threshold is critical to the system and should
>>>> be set with care within the bootloader.
>>>>
>>>> Applications may choose to utilize the notification mechanism, the
>>>> temperature reading mechanism (e.g., through polling), or both.
>>>>
>>>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>>>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>>>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>>>> ---
>>>>    drivers/thermal/Kconfig                    |   2 +-
>>>>    drivers/thermal/broadcom/Kconfig           |   7 +
>>>>    drivers/thermal/broadcom/Makefile          |   1 +
>>>>    drivers/thermal/broadcom/brcmstb_thermal.c | 387
>>>> +++++++++++++++++++++++++++++
>>>>    4 files changed, 396 insertions(+), 1 deletion(-)
>>>>    create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>>>
>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>> index 07002df..96774a7 100644
>>>> --- a/drivers/thermal/Kconfig
>>>> +++ b/drivers/thermal/Kconfig
>>>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>>>            controller present in Mediatek SoCs
>>>>      menu "Broadcom thermal drivers"
>>>> -depends on ARCH_BCM || COMPILE_TEST
>>>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>>> No need for this additional depends.  ARCH_BCM is always defined before
>>> ARCH_BRCMSTB can be selected.
>> ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
>> does. So, we do need both or the driver won't be built on ARM64.
>> (After internal discussions we went with that approach rather than
>> defining ARCH_BCM on ARM64.)
> Got it.  Looking at our internal iproc tree I see we've done exactly the
> same with ARCH_BCM_IPROC needing to be added.  We haven't upstreamed
> the thermal driver needing it yet.
> 
> Perhaps we should add ARCH_BCM to ARM64....

If it is just added to satisfy dependencies, I don't see much value in
doing that. It does make sense in the ARM v7 multiplatform context, but
outside of that, not so sur.
-- 
Florian

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

* Re: [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
  2017-09-26 22:14           ` Florian Fainelli
@ 2017-09-26 22:17             ` Scott Branden
  -1 siblings, 0 replies; 27+ messages in thread
From: Scott Branden @ 2017-09-26 22:17 UTC (permalink / raw)
  To: Florian Fainelli, Markus Mayer
  Cc: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
	Doug Berger, Brian Norris, Gregory Fong, Rafał Miłecki,
	Broadcom Kernel List, Power Management List, Device Tree List,
	ARM Kernel List, Linux Kernel Mailing List, Markus Mayer



On 17-09-26 03:14 PM, Florian Fainelli wrote:
> On 09/26/2017 03:08 PM, Scott Branden wrote:
>>
>> On 17-09-26 02:38 PM, Markus Mayer wrote:
>>> On 26 September 2017 at 14:32, Scott Branden
>>> <scott.branden@broadcom.com> wrote:
>>>> Hi Markus,
>>>>
>>>>
>>>> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>>>> From: Brian Norris <computersforpeace@gmail.com>
>>>>>
>>>>> The AVS TMON core provides temperature readings, a pair of configurable
>>>>> high- and low-temperature threshold interrupts, and an emergency
>>>>> over-temperature chip reset. The driver utilizes the first two to
>>>>> provide temperature readings and high-temperature notifications to
>>>>> applications. The over-temperature reset is not exposed to
>>>>> applications; this reset threshold is critical to the system and should
>>>>> be set with care within the bootloader.
>>>>>
>>>>> Applications may choose to utilize the notification mechanism, the
>>>>> temperature reading mechanism (e.g., through polling), or both.
>>>>>
>>>>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>>>>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>>>>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>>>>> ---
>>>>>     drivers/thermal/Kconfig                    |   2 +-
>>>>>     drivers/thermal/broadcom/Kconfig           |   7 +
>>>>>     drivers/thermal/broadcom/Makefile          |   1 +
>>>>>     drivers/thermal/broadcom/brcmstb_thermal.c | 387
>>>>> +++++++++++++++++++++++++++++
>>>>>     4 files changed, 396 insertions(+), 1 deletion(-)
>>>>>     create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>>>>
>>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>>> index 07002df..96774a7 100644
>>>>> --- a/drivers/thermal/Kconfig
>>>>> +++ b/drivers/thermal/Kconfig
>>>>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>>>>             controller present in Mediatek SoCs
>>>>>       menu "Broadcom thermal drivers"
>>>>> -depends on ARCH_BCM || COMPILE_TEST
>>>>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>>>> No need for this additional depends.  ARCH_BCM is always defined before
>>>> ARCH_BRCMSTB can be selected.
>>> ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
>>> does. So, we do need both or the driver won't be built on ARM64.
>>> (After internal discussions we went with that approach rather than
>>> defining ARCH_BCM on ARM64.)
>> Got it.  Looking at our internal iproc tree I see we've done exactly the
>> same with ARCH_BCM_IPROC needing to be added.  We haven't upstreamed
>> the thermal driver needing it yet.
>>
>> Perhaps we should add ARCH_BCM to ARM64....
> If it is just added to satisfy dependencies, I don't see much value in
> doing that. It does make sense in the ARM v7 multiplatform context, but
> outside of that, not so sur.
OK - we'll just continue to add ARCH_BCM_IPROC || ARCH_BRCMSTB 
everywhere as needed.

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

* [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver
@ 2017-09-26 22:17             ` Scott Branden
  0 siblings, 0 replies; 27+ messages in thread
From: Scott Branden @ 2017-09-26 22:17 UTC (permalink / raw)
  To: linux-arm-kernel



On 17-09-26 03:14 PM, Florian Fainelli wrote:
> On 09/26/2017 03:08 PM, Scott Branden wrote:
>>
>> On 17-09-26 02:38 PM, Markus Mayer wrote:
>>> On 26 September 2017 at 14:32, Scott Branden
>>> <scott.branden@broadcom.com> wrote:
>>>> Hi Markus,
>>>>
>>>>
>>>> On 17-09-26 02:27 PM, Markus Mayer wrote:
>>>>> From: Brian Norris <computersforpeace@gmail.com>
>>>>>
>>>>> The AVS TMON core provides temperature readings, a pair of configurable
>>>>> high- and low-temperature threshold interrupts, and an emergency
>>>>> over-temperature chip reset. The driver utilizes the first two to
>>>>> provide temperature readings and high-temperature notifications to
>>>>> applications. The over-temperature reset is not exposed to
>>>>> applications; this reset threshold is critical to the system and should
>>>>> be set with care within the bootloader.
>>>>>
>>>>> Applications may choose to utilize the notification mechanism, the
>>>>> temperature reading mechanism (e.g., through polling), or both.
>>>>>
>>>>> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
>>>>> Signed-off-by: Doug Berger <opendmb@gmail.com>
>>>>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>>>>> ---
>>>>>     drivers/thermal/Kconfig                    |   2 +-
>>>>>     drivers/thermal/broadcom/Kconfig           |   7 +
>>>>>     drivers/thermal/broadcom/Makefile          |   1 +
>>>>>     drivers/thermal/broadcom/brcmstb_thermal.c | 387
>>>>> +++++++++++++++++++++++++++++
>>>>>     4 files changed, 396 insertions(+), 1 deletion(-)
>>>>>     create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
>>>>>
>>>>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>>>>> index 07002df..96774a7 100644
>>>>> --- a/drivers/thermal/Kconfig
>>>>> +++ b/drivers/thermal/Kconfig
>>>>> @@ -408,7 +408,7 @@ config MTK_THERMAL
>>>>>             controller present in Mediatek SoCs
>>>>>       menu "Broadcom thermal drivers"
>>>>> -depends on ARCH_BCM || COMPILE_TEST
>>>>> +depends on ARCH_BCM || ARCH_BRCMSTB || COMPILE_TEST
>>>> No need for this additional depends.  ARCH_BCM is always defined before
>>>> ARCH_BRCMSTB can be selected.
>>> ARCH_BCM does not exist in arch/arm64/configs/defconfig. ARCH_BRCMSTB
>>> does. So, we do need both or the driver won't be built on ARM64.
>>> (After internal discussions we went with that approach rather than
>>> defining ARCH_BCM on ARM64.)
>> Got it.  Looking at our internal iproc tree I see we've done exactly the
>> same with ARCH_BCM_IPROC needing to be added.  We haven't upstreamed
>> the thermal driver needing it yet.
>>
>> Perhaps we should add ARCH_BCM to ARM64....
> If it is just added to satisfy dependencies, I don't see much value in
> doing that. It does make sense in the ARM v7 multiplatform context, but
> outside of that, not so sur.
OK - we'll just continue to add ARCH_BCM_IPROC || ARCH_BRCMSTB 
everywhere as needed.

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

* Re: [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-10-26 16:55   ` Florian Fainelli
  0 siblings, 0 replies; 27+ messages in thread
From: Florian Fainelli @ 2017-10-26 16:55 UTC (permalink / raw)
  To: Markus Mayer, Zhang Rui, Eduardo Valentin, Rob Herring,
	Mark Rutland, Doug Berger, Brian Norris, Gregory Fong,
	Florian Fainelli, Rafał Miłecki
  Cc: Markus Mayer, Broadcom Kernel List, Power Management List,
	Device Tree List, ARM Kernel List, Linux Kernel Mailing List

On 09/26/2017 02:27 PM, Markus Mayer wrote:
> From: Markus Mayer <mmayer@broadcom.com>
> 
> This series adds the brcmstb AVS TMON driver.
> 
> The driver was originally written by Brian Norris.

Rui, Eduardo, what's going on here? Can either one of you merge this
driver or are we going to miss another merge window?



> 
> Changes since v4:
> - disable trip points properly when needed; there was code left-over
>   from an older iteration of this driver that used long ints, which
>   resulted in code that was incorrect now that we are using ints
> - rebased on v4.14-rc1
> - patches 3 & 4 (turning on CONFIG_BRCMSTB_THERMAL for arm/arm64) are no
>   longer part of the series, because they were already picked up for 4.14
> 
> Changes since v3:
> - Rebased on v4.13-rc3 to resolve conflicts in the MAINTAINERS file
> 
> Changes since v2:
> - replaced calls to pr_debug() with calls to dev_dbg() [PATCH 2/4 only]
> - all other patches are unchanged from v2
> 
> Changes since v1:
> - Fixed wording in binding document
> - Fixed lincensing to consistently mention GPL v2
> - Use thermal_zone_get_slope() and thermal_zone_get_offset()
> - Some minor clean-ups
> 
> Brian Norris (2):
>   Documentation: devicetree: add binding for Broadcom STB AVS TMON
>   thermal: add brcmstb AVS TMON driver
> 
>  .../devicetree/bindings/thermal/brcm,avs-tmon.txt  |  20 ++
>  MAINTAINERS                                        |   8 +
>  drivers/thermal/Kconfig                            |   2 +-
>  drivers/thermal/broadcom/Kconfig                   |   7 +
>  drivers/thermal/broadcom/Makefile                  |   1 +
>  drivers/thermal/broadcom/brcmstb_thermal.c         | 387 +++++++++++++++++++++
>  6 files changed, 424 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
>  create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
> 


-- 
Florian

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

* Re: [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-10-26 16:55   ` Florian Fainelli
  0 siblings, 0 replies; 27+ messages in thread
From: Florian Fainelli @ 2017-10-26 16:55 UTC (permalink / raw)
  To: Markus Mayer, Zhang Rui, Eduardo Valentin, Rob Herring,
	Mark Rutland, Doug Berger, Brian Norris, Gregory Fong,
	Florian Fainelli, Rafał Miłecki
  Cc: Markus Mayer, Broadcom Kernel List, Power Management List,
	Device Tree List, ARM Kernel List, Linux Kernel Mailing List

On 09/26/2017 02:27 PM, Markus Mayer wrote:
> From: Markus Mayer <mmayer-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> 
> This series adds the brcmstb AVS TMON driver.
> 
> The driver was originally written by Brian Norris.

Rui, Eduardo, what's going on here? Can either one of you merge this
driver or are we going to miss another merge window?



> 
> Changes since v4:
> - disable trip points properly when needed; there was code left-over
>   from an older iteration of this driver that used long ints, which
>   resulted in code that was incorrect now that we are using ints
> - rebased on v4.14-rc1
> - patches 3 & 4 (turning on CONFIG_BRCMSTB_THERMAL for arm/arm64) are no
>   longer part of the series, because they were already picked up for 4.14
> 
> Changes since v3:
> - Rebased on v4.13-rc3 to resolve conflicts in the MAINTAINERS file
> 
> Changes since v2:
> - replaced calls to pr_debug() with calls to dev_dbg() [PATCH 2/4 only]
> - all other patches are unchanged from v2
> 
> Changes since v1:
> - Fixed wording in binding document
> - Fixed lincensing to consistently mention GPL v2
> - Use thermal_zone_get_slope() and thermal_zone_get_offset()
> - Some minor clean-ups
> 
> Brian Norris (2):
>   Documentation: devicetree: add binding for Broadcom STB AVS TMON
>   thermal: add brcmstb AVS TMON driver
> 
>  .../devicetree/bindings/thermal/brcm,avs-tmon.txt  |  20 ++
>  MAINTAINERS                                        |   8 +
>  drivers/thermal/Kconfig                            |   2 +-
>  drivers/thermal/broadcom/Kconfig                   |   7 +
>  drivers/thermal/broadcom/Makefile                  |   1 +
>  drivers/thermal/broadcom/brcmstb_thermal.c         | 387 +++++++++++++++++++++
>  6 files changed, 424 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
>  create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
> 


-- 
Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-10-26 16:55   ` Florian Fainelli
  0 siblings, 0 replies; 27+ messages in thread
From: Florian Fainelli @ 2017-10-26 16:55 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/26/2017 02:27 PM, Markus Mayer wrote:
> From: Markus Mayer <mmayer@broadcom.com>
> 
> This series adds the brcmstb AVS TMON driver.
> 
> The driver was originally written by Brian Norris.

Rui, Eduardo, what's going on here? Can either one of you merge this
driver or are we going to miss another merge window?



> 
> Changes since v4:
> - disable trip points properly when needed; there was code left-over
>   from an older iteration of this driver that used long ints, which
>   resulted in code that was incorrect now that we are using ints
> - rebased on v4.14-rc1
> - patches 3 & 4 (turning on CONFIG_BRCMSTB_THERMAL for arm/arm64) are no
>   longer part of the series, because they were already picked up for 4.14
> 
> Changes since v3:
> - Rebased on v4.13-rc3 to resolve conflicts in the MAINTAINERS file
> 
> Changes since v2:
> - replaced calls to pr_debug() with calls to dev_dbg() [PATCH 2/4 only]
> - all other patches are unchanged from v2
> 
> Changes since v1:
> - Fixed wording in binding document
> - Fixed lincensing to consistently mention GPL v2
> - Use thermal_zone_get_slope() and thermal_zone_get_offset()
> - Some minor clean-ups
> 
> Brian Norris (2):
>   Documentation: devicetree: add binding for Broadcom STB AVS TMON
>   thermal: add brcmstb AVS TMON driver
> 
>  .../devicetree/bindings/thermal/brcm,avs-tmon.txt  |  20 ++
>  MAINTAINERS                                        |   8 +
>  drivers/thermal/Kconfig                            |   2 +-
>  drivers/thermal/broadcom/Kconfig                   |   7 +
>  drivers/thermal/broadcom/Makefile                  |   1 +
>  drivers/thermal/broadcom/brcmstb_thermal.c         | 387 +++++++++++++++++++++
>  6 files changed, 424 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
>  create mode 100644 drivers/thermal/broadcom/brcmstb_thermal.c
> 


-- 
Florian

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

* Re: [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
  2017-10-26 16:55   ` Florian Fainelli
@ 2017-10-26 18:24     ` Eduardo Valentin
  -1 siblings, 0 replies; 27+ messages in thread
From: Eduardo Valentin @ 2017-10-26 18:24 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Markus Mayer, Zhang Rui, Rob Herring, Mark Rutland, Doug Berger,
	Brian Norris, Gregory Fong, Rafał Miłecki,
	Markus Mayer, Broadcom Kernel List, Power Management List,
	Device Tree List, ARM Kernel List, Linux Kernel Mailing List

On Thu, Oct 26, 2017 at 09:55:50AM -0700, Florian Fainelli wrote:
> On 09/26/2017 02:27 PM, Markus Mayer wrote:
> > From: Markus Mayer <mmayer@broadcom.com>
> > 
> > This series adds the brcmstb AVS TMON driver.
> > 
> > The driver was originally written by Brian Norris.
> 
> Rui, Eduardo, what's going on here? Can either one of you merge this
> driver or are we going to miss another merge window?

I am taking a look. Thanks for the reminder.

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

* [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-10-26 18:24     ` Eduardo Valentin
  0 siblings, 0 replies; 27+ messages in thread
From: Eduardo Valentin @ 2017-10-26 18:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Oct 26, 2017 at 09:55:50AM -0700, Florian Fainelli wrote:
> On 09/26/2017 02:27 PM, Markus Mayer wrote:
> > From: Markus Mayer <mmayer@broadcom.com>
> > 
> > This series adds the brcmstb AVS TMON driver.
> > 
> > The driver was originally written by Brian Norris.
> 
> Rui, Eduardo, what's going on here? Can either one of you merge this
> driver or are we going to miss another merge window?

I am taking a look. Thanks for the reminder.

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

* Re: [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-10-26 18:39       ` Eduardo Valentin
  0 siblings, 0 replies; 27+ messages in thread
From: Eduardo Valentin @ 2017-10-26 18:39 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Markus Mayer, Zhang Rui, Rob Herring, Mark Rutland, Doug Berger,
	Brian Norris, Gregory Fong, Rafał Miłecki,
	Markus Mayer, Broadcom Kernel List, Power Management List,
	Device Tree List, ARM Kernel List, Linux Kernel Mailing List

On Thu, Oct 26, 2017 at 11:24:33AM -0700, Eduardo Valentin wrote:
> On Thu, Oct 26, 2017 at 09:55:50AM -0700, Florian Fainelli wrote:
> > On 09/26/2017 02:27 PM, Markus Mayer wrote:
> > > From: Markus Mayer <mmayer@broadcom.com>
> > > 
> > > This series adds the brcmstb AVS TMON driver.
> > > 
> > > The driver was originally written by Brian Norris.
> > 
> > Rui, Eduardo, what's going on here? Can either one of you merge this
> > driver or are we going to miss another merge window?
> 
> I am taking a look. Thanks for the reminder.
> 

I had no issues with these patches. Queued both in my -linus branch.
Apologizes for letting this to fall into the cracks.

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

* Re: [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-10-26 18:39       ` Eduardo Valentin
  0 siblings, 0 replies; 27+ messages in thread
From: Eduardo Valentin @ 2017-10-26 18:39 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Markus Mayer, Zhang Rui, Rob Herring, Mark Rutland, Doug Berger,
	Brian Norris, Gregory Fong, Rafał Miłecki,
	Markus Mayer, Broadcom Kernel List, Power Management List,
	Device Tree List, ARM Kernel List, Linux Kernel Mailing List

On Thu, Oct 26, 2017 at 11:24:33AM -0700, Eduardo Valentin wrote:
> On Thu, Oct 26, 2017 at 09:55:50AM -0700, Florian Fainelli wrote:
> > On 09/26/2017 02:27 PM, Markus Mayer wrote:
> > > From: Markus Mayer <mmayer-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> > > 
> > > This series adds the brcmstb AVS TMON driver.
> > > 
> > > The driver was originally written by Brian Norris.
> > 
> > Rui, Eduardo, what's going on here? Can either one of you merge this
> > driver or are we going to miss another merge window?
> 
> I am taking a look. Thanks for the reminder.
> 

I had no issues with these patches. Queued both in my -linus branch.
Apologizes for letting this to fall into the cracks.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver
@ 2017-10-26 18:39       ` Eduardo Valentin
  0 siblings, 0 replies; 27+ messages in thread
From: Eduardo Valentin @ 2017-10-26 18:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Oct 26, 2017 at 11:24:33AM -0700, Eduardo Valentin wrote:
> On Thu, Oct 26, 2017 at 09:55:50AM -0700, Florian Fainelli wrote:
> > On 09/26/2017 02:27 PM, Markus Mayer wrote:
> > > From: Markus Mayer <mmayer@broadcom.com>
> > > 
> > > This series adds the brcmstb AVS TMON driver.
> > > 
> > > The driver was originally written by Brian Norris.
> > 
> > Rui, Eduardo, what's going on here? Can either one of you merge this
> > driver or are we going to miss another merge window?
> 
> I am taking a look. Thanks for the reminder.
> 

I had no issues with these patches. Queued both in my -linus branch.
Apologizes for letting this to fall into the cracks.

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

end of thread, other threads:[~2017-10-26 18:39 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-26 21:27 [PATCH v5 0/2] thermal: add brcmstb AVS TMON driver Markus Mayer
2017-09-26 21:27 ` Markus Mayer
2017-09-26 21:27 ` Markus Mayer
2017-09-26 21:27 ` [PATCH v5 1/2] Documentation: devicetree: add binding for Broadcom STB AVS TMON Markus Mayer
2017-09-26 21:27   ` Markus Mayer
2017-09-26 21:27 ` [PATCH v5 2/2] thermal: add brcmstb AVS TMON driver Markus Mayer
2017-09-26 21:27   ` Markus Mayer
2017-09-26 21:27   ` Markus Mayer
2017-09-26 21:32   ` Scott Branden
2017-09-26 21:32     ` Scott Branden
2017-09-26 21:38     ` Markus Mayer
2017-09-26 21:38       ` Markus Mayer
2017-09-26 22:08       ` Scott Branden
2017-09-26 22:08         ` Scott Branden
2017-09-26 22:14         ` Florian Fainelli
2017-09-26 22:14           ` Florian Fainelli
2017-09-26 22:14           ` Florian Fainelli
2017-09-26 22:17           ` Scott Branden
2017-09-26 22:17             ` Scott Branden
2017-10-26 16:55 ` [PATCH v5 0/2] " Florian Fainelli
2017-10-26 16:55   ` Florian Fainelli
2017-10-26 16:55   ` Florian Fainelli
2017-10-26 18:24   ` Eduardo Valentin
2017-10-26 18:24     ` Eduardo Valentin
2017-10-26 18:39     ` Eduardo Valentin
2017-10-26 18:39       ` Eduardo Valentin
2017-10-26 18:39       ` Eduardo Valentin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.