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