162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Broadcom STB AVS TMON thermal sensor driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015-2017 Broadcom
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define DRV_NAME	"brcmstb_thermal"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define pr_fmt(fmt)	DRV_NAME ": " fmt
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/bitops.h>
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/err.h>
1562306a36Sopenharmony_ci#include <linux/io.h>
1662306a36Sopenharmony_ci#include <linux/irqreturn.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/of.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/thermal.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define AVS_TMON_STATUS			0x00
2562306a36Sopenharmony_ci #define AVS_TMON_STATUS_valid_msk	BIT(11)
2662306a36Sopenharmony_ci #define AVS_TMON_STATUS_data_msk	GENMASK(10, 1)
2762306a36Sopenharmony_ci #define AVS_TMON_STATUS_data_shift	1
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define AVS_TMON_EN_OVERTEMP_RESET	0x04
3062306a36Sopenharmony_ci #define AVS_TMON_EN_OVERTEMP_RESET_msk	BIT(0)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define AVS_TMON_RESET_THRESH		0x08
3362306a36Sopenharmony_ci #define AVS_TMON_RESET_THRESH_msk	GENMASK(10, 1)
3462306a36Sopenharmony_ci #define AVS_TMON_RESET_THRESH_shift	1
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define AVS_TMON_INT_IDLE_TIME		0x10
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define AVS_TMON_EN_TEMP_INT_SRCS	0x14
3962306a36Sopenharmony_ci #define AVS_TMON_EN_TEMP_INT_SRCS_high	BIT(1)
4062306a36Sopenharmony_ci #define AVS_TMON_EN_TEMP_INT_SRCS_low	BIT(0)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define AVS_TMON_INT_THRESH		0x18
4362306a36Sopenharmony_ci #define AVS_TMON_INT_THRESH_high_msk	GENMASK(26, 17)
4462306a36Sopenharmony_ci #define AVS_TMON_INT_THRESH_high_shift	17
4562306a36Sopenharmony_ci #define AVS_TMON_INT_THRESH_low_msk	GENMASK(10, 1)
4662306a36Sopenharmony_ci #define AVS_TMON_INT_THRESH_low_shift	1
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define AVS_TMON_TEMP_INT_CODE		0x1c
4962306a36Sopenharmony_ci#define AVS_TMON_TP_TEST_ENABLE		0x20
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Default coefficients */
5262306a36Sopenharmony_ci#define AVS_TMON_TEMP_SLOPE		487
5362306a36Sopenharmony_ci#define AVS_TMON_TEMP_OFFSET		410040
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* HW related temperature constants */
5662306a36Sopenharmony_ci#define AVS_TMON_TEMP_MAX		0x3ff
5762306a36Sopenharmony_ci#define AVS_TMON_TEMP_MIN		-88161
5862306a36Sopenharmony_ci#define AVS_TMON_TEMP_MASK		AVS_TMON_TEMP_MAX
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cienum avs_tmon_trip_type {
6162306a36Sopenharmony_ci	TMON_TRIP_TYPE_LOW = 0,
6262306a36Sopenharmony_ci	TMON_TRIP_TYPE_HIGH,
6362306a36Sopenharmony_ci	TMON_TRIP_TYPE_RESET,
6462306a36Sopenharmony_ci	TMON_TRIP_TYPE_MAX,
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct avs_tmon_trip {
6862306a36Sopenharmony_ci	/* HW bit to enable the trip */
6962306a36Sopenharmony_ci	u32 enable_offs;
7062306a36Sopenharmony_ci	u32 enable_mask;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* HW field to read the trip temperature */
7362306a36Sopenharmony_ci	u32 reg_offs;
7462306a36Sopenharmony_ci	u32 reg_msk;
7562306a36Sopenharmony_ci	int reg_shift;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic struct avs_tmon_trip avs_tmon_trips[] = {
7962306a36Sopenharmony_ci	/* Trips when temperature is below threshold */
8062306a36Sopenharmony_ci	[TMON_TRIP_TYPE_LOW] = {
8162306a36Sopenharmony_ci		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
8262306a36Sopenharmony_ci		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_low,
8362306a36Sopenharmony_ci		.reg_offs	= AVS_TMON_INT_THRESH,
8462306a36Sopenharmony_ci		.reg_msk	= AVS_TMON_INT_THRESH_low_msk,
8562306a36Sopenharmony_ci		.reg_shift	= AVS_TMON_INT_THRESH_low_shift,
8662306a36Sopenharmony_ci	},
8762306a36Sopenharmony_ci	/* Trips when temperature is above threshold */
8862306a36Sopenharmony_ci	[TMON_TRIP_TYPE_HIGH] = {
8962306a36Sopenharmony_ci		.enable_offs	= AVS_TMON_EN_TEMP_INT_SRCS,
9062306a36Sopenharmony_ci		.enable_mask	= AVS_TMON_EN_TEMP_INT_SRCS_high,
9162306a36Sopenharmony_ci		.reg_offs	= AVS_TMON_INT_THRESH,
9262306a36Sopenharmony_ci		.reg_msk	= AVS_TMON_INT_THRESH_high_msk,
9362306a36Sopenharmony_ci		.reg_shift	= AVS_TMON_INT_THRESH_high_shift,
9462306a36Sopenharmony_ci	},
9562306a36Sopenharmony_ci	/* Automatically resets chip when above threshold */
9662306a36Sopenharmony_ci	[TMON_TRIP_TYPE_RESET] = {
9762306a36Sopenharmony_ci		.enable_offs	= AVS_TMON_EN_OVERTEMP_RESET,
9862306a36Sopenharmony_ci		.enable_mask	= AVS_TMON_EN_OVERTEMP_RESET_msk,
9962306a36Sopenharmony_ci		.reg_offs	= AVS_TMON_RESET_THRESH,
10062306a36Sopenharmony_ci		.reg_msk	= AVS_TMON_RESET_THRESH_msk,
10162306a36Sopenharmony_ci		.reg_shift	= AVS_TMON_RESET_THRESH_shift,
10262306a36Sopenharmony_ci	},
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistruct brcmstb_thermal_params {
10662306a36Sopenharmony_ci	unsigned int offset;
10762306a36Sopenharmony_ci	unsigned int mult;
10862306a36Sopenharmony_ci	const struct thermal_zone_device_ops *of_ops;
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct brcmstb_thermal_priv {
11262306a36Sopenharmony_ci	void __iomem *tmon_base;
11362306a36Sopenharmony_ci	struct device *dev;
11462306a36Sopenharmony_ci	struct thermal_zone_device *thermal;
11562306a36Sopenharmony_ci	/* Process specific thermal parameters used for calculations */
11662306a36Sopenharmony_ci	const struct brcmstb_thermal_params *temp_params;
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/* Convert a HW code to a temperature reading (millidegree celsius) */
12062306a36Sopenharmony_cistatic inline int avs_tmon_code_to_temp(struct brcmstb_thermal_priv *priv,
12162306a36Sopenharmony_ci					u32 code)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	int offset = priv->temp_params->offset;
12462306a36Sopenharmony_ci	int mult = priv->temp_params->mult;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return (offset - (int)((code & AVS_TMON_TEMP_MASK) * mult));
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/*
13062306a36Sopenharmony_ci * Convert a temperature value (millidegree celsius) to a HW code
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci * @temp: temperature to convert
13362306a36Sopenharmony_ci * @low: if true, round toward the low side
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_cistatic inline u32 avs_tmon_temp_to_code(struct brcmstb_thermal_priv *priv,
13662306a36Sopenharmony_ci					int temp, bool low)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	int offset = priv->temp_params->offset;
13962306a36Sopenharmony_ci	int mult = priv->temp_params->mult;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (temp < AVS_TMON_TEMP_MIN)
14262306a36Sopenharmony_ci		return AVS_TMON_TEMP_MAX;	/* Maximum code value */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (temp >= offset)
14562306a36Sopenharmony_ci		return 0;	/* Minimum code value */
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (low)
14862306a36Sopenharmony_ci		return (u32)(DIV_ROUND_UP(offset - temp, mult));
14962306a36Sopenharmony_ci	else
15062306a36Sopenharmony_ci		return (u32)((offset - temp) / mult);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic int brcmstb_get_temp(struct thermal_zone_device *tz, int *temp)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct brcmstb_thermal_priv *priv = thermal_zone_device_priv(tz);
15662306a36Sopenharmony_ci	u32 val;
15762306a36Sopenharmony_ci	long t;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (!(val & AVS_TMON_STATUS_valid_msk))
16262306a36Sopenharmony_ci		return -EIO;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	t = avs_tmon_code_to_temp(priv, val);
16762306a36Sopenharmony_ci	if (t < 0)
16862306a36Sopenharmony_ci		*temp = 0;
16962306a36Sopenharmony_ci	else
17062306a36Sopenharmony_ci		*temp = t;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return 0;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
17662306a36Sopenharmony_ci				 enum avs_tmon_trip_type type, int en)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
17962306a36Sopenharmony_ci	u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis", type);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (en)
18462306a36Sopenharmony_ci		val |= trip->enable_mask;
18562306a36Sopenharmony_ci	else
18662306a36Sopenharmony_ci		val &= ~trip->enable_mask;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	__raw_writel(val, priv->tmon_base + trip->enable_offs);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
19262306a36Sopenharmony_ci				  enum avs_tmon_trip_type type)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
19562306a36Sopenharmony_ci	u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	val &= trip->reg_msk;
19862306a36Sopenharmony_ci	val >>= trip->reg_shift;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return avs_tmon_code_to_temp(priv, val);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
20462306a36Sopenharmony_ci				   enum avs_tmon_trip_type type,
20562306a36Sopenharmony_ci				   int temp)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct avs_tmon_trip *trip = &avs_tmon_trips[type];
20862306a36Sopenharmony_ci	u32 val, orig;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* round toward low temp for the low interrupt */
21362306a36Sopenharmony_ci	val = avs_tmon_temp_to_code(priv, temp,
21462306a36Sopenharmony_ci				    type == TMON_TRIP_TYPE_LOW);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	val <<= trip->reg_shift;
21762306a36Sopenharmony_ci	val &= trip->reg_msk;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	orig = __raw_readl(priv->tmon_base + trip->reg_offs);
22062306a36Sopenharmony_ci	orig &= ~trip->reg_msk;
22162306a36Sopenharmony_ci	orig |= val;
22262306a36Sopenharmony_ci	__raw_writel(orig, priv->tmon_base + trip->reg_offs);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	u32 val;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
23062306a36Sopenharmony_ci	return avs_tmon_code_to_temp(priv, val);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct brcmstb_thermal_priv *priv = data;
23662306a36Sopenharmony_ci	int low, high, intr;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
23962306a36Sopenharmony_ci	high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
24062306a36Sopenharmony_ci	intr = avs_tmon_get_intr_temp(priv);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
24362306a36Sopenharmony_ci			low, intr, high);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* Disable high-temp until next threshold shift */
24662306a36Sopenharmony_ci	if (intr >= high)
24762306a36Sopenharmony_ci		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
24862306a36Sopenharmony_ci	/* Disable low-temp until next threshold shift */
24962306a36Sopenharmony_ci	if (intr <= low)
25062306a36Sopenharmony_ci		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/*
25362306a36Sopenharmony_ci	 * Notify using the interrupt temperature, in case the temperature
25462306a36Sopenharmony_ci	 * changes before it can next be read out
25562306a36Sopenharmony_ci	 */
25662306a36Sopenharmony_ci	thermal_zone_device_update(priv->thermal, intr);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return IRQ_HANDLED;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int brcmstb_set_trips(struct thermal_zone_device *tz, int low, int high)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct brcmstb_thermal_priv *priv = thermal_zone_device_priv(tz);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/*
26862306a36Sopenharmony_ci	 * Disable low-temp if "low" is too small. As per thermal framework
26962306a36Sopenharmony_ci	 * API, we use -INT_MAX rather than INT_MIN.
27062306a36Sopenharmony_ci	 */
27162306a36Sopenharmony_ci	if (low <= -INT_MAX) {
27262306a36Sopenharmony_ci		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
27362306a36Sopenharmony_ci	} else {
27462306a36Sopenharmony_ci		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
27562306a36Sopenharmony_ci		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* Disable high-temp if "high" is too big. */
27962306a36Sopenharmony_ci	if (high == INT_MAX) {
28062306a36Sopenharmony_ci		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
28162306a36Sopenharmony_ci	} else {
28262306a36Sopenharmony_ci		avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
28362306a36Sopenharmony_ci		avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return 0;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic const struct thermal_zone_device_ops brcmstb_16nm_of_ops = {
29062306a36Sopenharmony_ci	.get_temp	= brcmstb_get_temp,
29162306a36Sopenharmony_ci};
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic const struct brcmstb_thermal_params brcmstb_16nm_params = {
29462306a36Sopenharmony_ci	.offset	= 457829,
29562306a36Sopenharmony_ci	.mult	= 557,
29662306a36Sopenharmony_ci	.of_ops	= &brcmstb_16nm_of_ops,
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic const struct thermal_zone_device_ops brcmstb_28nm_of_ops = {
30062306a36Sopenharmony_ci	.get_temp	= brcmstb_get_temp,
30162306a36Sopenharmony_ci	.set_trips	= brcmstb_set_trips,
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic const struct brcmstb_thermal_params brcmstb_28nm_params = {
30562306a36Sopenharmony_ci	.offset	= 410040,
30662306a36Sopenharmony_ci	.mult	= 487,
30762306a36Sopenharmony_ci	.of_ops	= &brcmstb_28nm_of_ops,
30862306a36Sopenharmony_ci};
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic const struct of_device_id brcmstb_thermal_id_table[] = {
31162306a36Sopenharmony_ci	{ .compatible = "brcm,avs-tmon-bcm7216", .data = &brcmstb_16nm_params },
31262306a36Sopenharmony_ci	{ .compatible = "brcm,avs-tmon", .data = &brcmstb_28nm_params },
31362306a36Sopenharmony_ci	{},
31462306a36Sopenharmony_ci};
31562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int brcmstb_thermal_probe(struct platform_device *pdev)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	const struct thermal_zone_device_ops *of_ops;
32062306a36Sopenharmony_ci	struct thermal_zone_device *thermal;
32162306a36Sopenharmony_ci	struct brcmstb_thermal_priv *priv;
32262306a36Sopenharmony_ci	int irq, ret;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
32562306a36Sopenharmony_ci	if (!priv)
32662306a36Sopenharmony_ci		return -ENOMEM;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	priv->temp_params = of_device_get_match_data(&pdev->dev);
32962306a36Sopenharmony_ci	if (!priv->temp_params)
33062306a36Sopenharmony_ci		return -EINVAL;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	priv->tmon_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
33362306a36Sopenharmony_ci	if (IS_ERR(priv->tmon_base))
33462306a36Sopenharmony_ci		return PTR_ERR(priv->tmon_base);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	priv->dev = &pdev->dev;
33762306a36Sopenharmony_ci	of_ops = priv->temp_params->of_ops;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	thermal = devm_thermal_of_zone_register(&pdev->dev, 0, priv,
34062306a36Sopenharmony_ci						of_ops);
34162306a36Sopenharmony_ci	if (IS_ERR(thermal)) {
34262306a36Sopenharmony_ci		ret = PTR_ERR(thermal);
34362306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
34462306a36Sopenharmony_ci		return ret;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	priv->thermal = thermal;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	irq = platform_get_irq_optional(pdev, 0);
35062306a36Sopenharmony_ci	if (irq >= 0) {
35162306a36Sopenharmony_ci		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
35262306a36Sopenharmony_ci						brcmstb_tmon_irq_thread,
35362306a36Sopenharmony_ci						IRQF_ONESHOT,
35462306a36Sopenharmony_ci						DRV_NAME, priv);
35562306a36Sopenharmony_ci		if (ret < 0) {
35662306a36Sopenharmony_ci			dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
35762306a36Sopenharmony_ci			return ret;
35862306a36Sopenharmony_ci		}
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return 0;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic struct platform_driver brcmstb_thermal_driver = {
36762306a36Sopenharmony_ci	.probe = brcmstb_thermal_probe,
36862306a36Sopenharmony_ci	.driver = {
36962306a36Sopenharmony_ci		.name = DRV_NAME,
37062306a36Sopenharmony_ci		.of_match_table = brcmstb_thermal_id_table,
37162306a36Sopenharmony_ci	},
37262306a36Sopenharmony_ci};
37362306a36Sopenharmony_cimodule_platform_driver(brcmstb_thermal_driver);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
37662306a36Sopenharmony_ciMODULE_AUTHOR("Brian Norris");
37762306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
378