162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2020 NXP. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Anson Huang <Anson.Huang@nxp.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitfield.h> 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/nvmem-consumer.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/thermal.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "thermal_hwmon.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define TER 0x0 /* TMU enable */ 2262306a36Sopenharmony_ci#define TPS 0x4 2362306a36Sopenharmony_ci#define TRITSR 0x20 /* TMU immediate temp */ 2462306a36Sopenharmony_ci/* TMU calibration data registers */ 2562306a36Sopenharmony_ci#define TASR 0x28 2662306a36Sopenharmony_ci#define TASR_BUF_SLOPE_MASK GENMASK(19, 16) 2762306a36Sopenharmony_ci#define TASR_BUF_VREF_MASK GENMASK(4, 0) /* TMU_V1 */ 2862306a36Sopenharmony_ci#define TASR_BUF_VERF_SEL_MASK GENMASK(1, 0) /* TMU_V2 */ 2962306a36Sopenharmony_ci#define TCALIV(n) (0x30 + ((n) * 4)) 3062306a36Sopenharmony_ci#define TCALIV_EN BIT(31) 3162306a36Sopenharmony_ci#define TCALIV_HR_MASK GENMASK(23, 16) /* TMU_V1 */ 3262306a36Sopenharmony_ci#define TCALIV_RT_MASK GENMASK(7, 0) /* TMU_V1 */ 3362306a36Sopenharmony_ci#define TCALIV_SNSR105C_MASK GENMASK(27, 16) /* TMU_V2 */ 3462306a36Sopenharmony_ci#define TCALIV_SNSR25C_MASK GENMASK(11, 0) /* TMU_V2 */ 3562306a36Sopenharmony_ci#define TRIM 0x3c 3662306a36Sopenharmony_ci#define TRIM_BJT_CUR_MASK GENMASK(23, 20) 3762306a36Sopenharmony_ci#define TRIM_BGR_MASK GENMASK(31, 28) 3862306a36Sopenharmony_ci#define TRIM_VLSB_MASK GENMASK(15, 12) 3962306a36Sopenharmony_ci#define TRIM_EN_CH BIT(7) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define TER_ADC_PD BIT(30) 4262306a36Sopenharmony_ci#define TER_EN BIT(31) 4362306a36Sopenharmony_ci#define TRITSR_TEMP0_VAL_MASK GENMASK(7, 0) 4462306a36Sopenharmony_ci#define TRITSR_TEMP1_VAL_MASK GENMASK(23, 16) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define PROBE_SEL_ALL GENMASK(31, 30) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define probe_status_offset(x) (30 + x) 4962306a36Sopenharmony_ci#define SIGN_BIT BIT(7) 5062306a36Sopenharmony_ci#define TEMP_VAL_MASK GENMASK(6, 0) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* TMU OCOTP calibration data bitfields */ 5362306a36Sopenharmony_ci#define ANA0_EN BIT(25) 5462306a36Sopenharmony_ci#define ANA0_BUF_VREF_MASK GENMASK(24, 20) 5562306a36Sopenharmony_ci#define ANA0_BUF_SLOPE_MASK GENMASK(19, 16) 5662306a36Sopenharmony_ci#define ANA0_HR_MASK GENMASK(15, 8) 5762306a36Sopenharmony_ci#define ANA0_RT_MASK GENMASK(7, 0) 5862306a36Sopenharmony_ci#define TRIM2_VLSB_MASK GENMASK(23, 20) 5962306a36Sopenharmony_ci#define TRIM2_BGR_MASK GENMASK(19, 16) 6062306a36Sopenharmony_ci#define TRIM2_BJT_CUR_MASK GENMASK(15, 12) 6162306a36Sopenharmony_ci#define TRIM2_BUF_SLOP_SEL_MASK GENMASK(11, 8) 6262306a36Sopenharmony_ci#define TRIM2_BUF_VERF_SEL_MASK GENMASK(7, 6) 6362306a36Sopenharmony_ci#define TRIM3_TCA25_0_LSB_MASK GENMASK(31, 28) 6462306a36Sopenharmony_ci#define TRIM3_TCA40_0_MASK GENMASK(27, 16) 6562306a36Sopenharmony_ci#define TRIM4_TCA40_1_MASK GENMASK(31, 20) 6662306a36Sopenharmony_ci#define TRIM4_TCA105_0_MASK GENMASK(19, 8) 6762306a36Sopenharmony_ci#define TRIM4_TCA25_0_MSB_MASK GENMASK(7, 0) 6862306a36Sopenharmony_ci#define TRIM5_TCA105_1_MASK GENMASK(23, 12) 6962306a36Sopenharmony_ci#define TRIM5_TCA25_1_MASK GENMASK(11, 0) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define VER1_TEMP_LOW_LIMIT 10000 7262306a36Sopenharmony_ci#define VER2_TEMP_LOW_LIMIT -40000 7362306a36Sopenharmony_ci#define VER2_TEMP_HIGH_LIMIT 125000 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define TMU_VER1 0x1 7662306a36Sopenharmony_ci#define TMU_VER2 0x2 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct thermal_soc_data { 7962306a36Sopenharmony_ci u32 num_sensors; 8062306a36Sopenharmony_ci u32 version; 8162306a36Sopenharmony_ci int (*get_temp)(void *, int *); 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistruct tmu_sensor { 8562306a36Sopenharmony_ci struct imx8mm_tmu *priv; 8662306a36Sopenharmony_ci u32 hw_id; 8762306a36Sopenharmony_ci struct thermal_zone_device *tzd; 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistruct imx8mm_tmu { 9162306a36Sopenharmony_ci void __iomem *base; 9262306a36Sopenharmony_ci struct clk *clk; 9362306a36Sopenharmony_ci const struct thermal_soc_data *socdata; 9462306a36Sopenharmony_ci struct tmu_sensor sensors[]; 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int imx8mm_tmu_get_temp(void *data, int *temp) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct tmu_sensor *sensor = data; 10062306a36Sopenharmony_ci struct imx8mm_tmu *tmu = sensor->priv; 10162306a36Sopenharmony_ci u32 val; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* 10662306a36Sopenharmony_ci * Do not validate against the V bit (bit 31) due to errata 10762306a36Sopenharmony_ci * ERR051272: TMU: Bit 31 of registers TMU_TSCR/TMU_TRITSR/TMU_TRATSR invalid 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci *temp = val * 1000; 11162306a36Sopenharmony_ci if (*temp < VER1_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT) 11262306a36Sopenharmony_ci return -EAGAIN; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int imx8mp_tmu_get_temp(void *data, int *temp) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct tmu_sensor *sensor = data; 12062306a36Sopenharmony_ci struct imx8mm_tmu *tmu = sensor->priv; 12162306a36Sopenharmony_ci unsigned long val; 12262306a36Sopenharmony_ci bool ready; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci val = readl_relaxed(tmu->base + TRITSR); 12562306a36Sopenharmony_ci ready = test_bit(probe_status_offset(sensor->hw_id), &val); 12662306a36Sopenharmony_ci if (!ready) 12762306a36Sopenharmony_ci return -EAGAIN; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) : 13062306a36Sopenharmony_ci FIELD_GET(TRITSR_TEMP0_VAL_MASK, val); 13162306a36Sopenharmony_ci if (val & SIGN_BIT) /* negative */ 13262306a36Sopenharmony_ci val = (~(val & TEMP_VAL_MASK) + 1); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci *temp = val * 1000; 13562306a36Sopenharmony_ci if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT) 13662306a36Sopenharmony_ci return -EAGAIN; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int tmu_get_temp(struct thermal_zone_device *tz, int *temp) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct tmu_sensor *sensor = thermal_zone_device_priv(tz); 14462306a36Sopenharmony_ci struct imx8mm_tmu *tmu = sensor->priv; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return tmu->socdata->get_temp(sensor, temp); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic const struct thermal_zone_device_ops tmu_tz_ops = { 15062306a36Sopenharmony_ci .get_temp = tmu_get_temp, 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci u32 val; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci val = readl_relaxed(tmu->base + TER); 15862306a36Sopenharmony_ci val = enable ? (val | TER_EN) : (val & ~TER_EN); 15962306a36Sopenharmony_ci if (tmu->socdata->version == TMU_VER2) 16062306a36Sopenharmony_ci val = enable ? (val & ~TER_ADC_PD) : (val | TER_ADC_PD); 16162306a36Sopenharmony_ci writel_relaxed(val, tmu->base + TER); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci u32 val; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci val = readl_relaxed(tmu->base + TPS); 16962306a36Sopenharmony_ci val |= PROBE_SEL_ALL; 17062306a36Sopenharmony_ci writel_relaxed(val, tmu->base + TPS); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev, 17462306a36Sopenharmony_ci struct imx8mm_tmu *tmu) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct device *dev = &pdev->dev; 17762306a36Sopenharmony_ci u32 ana0; 17862306a36Sopenharmony_ci int ret; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0); 18162306a36Sopenharmony_ci if (ret) 18262306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Failed to read OCOTP nvmem cell\n"); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci writel(FIELD_PREP(TASR_BUF_VREF_MASK, 18562306a36Sopenharmony_ci FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) | 18662306a36Sopenharmony_ci FIELD_PREP(TASR_BUF_SLOPE_MASK, 18762306a36Sopenharmony_ci FIELD_GET(ANA0_BUF_SLOPE_MASK, ana0)), 18862306a36Sopenharmony_ci tmu->base + TASR); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci writel(FIELD_PREP(TCALIV_RT_MASK, FIELD_GET(ANA0_RT_MASK, ana0)) | 19162306a36Sopenharmony_ci FIELD_PREP(TCALIV_HR_MASK, FIELD_GET(ANA0_HR_MASK, ana0)) | 19262306a36Sopenharmony_ci ((ana0 & ANA0_EN) ? TCALIV_EN : 0), 19362306a36Sopenharmony_ci tmu->base + TCALIV(0)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int imx8mm_tmu_probe_set_calib_v2(struct platform_device *pdev, 19962306a36Sopenharmony_ci struct imx8mm_tmu *tmu) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 20262306a36Sopenharmony_ci struct nvmem_cell *cell; 20362306a36Sopenharmony_ci u32 trim[4] = { 0 }; 20462306a36Sopenharmony_ci size_t len; 20562306a36Sopenharmony_ci void *buf; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci cell = nvmem_cell_get(dev, "calib"); 20862306a36Sopenharmony_ci if (IS_ERR(cell)) 20962306a36Sopenharmony_ci return PTR_ERR(cell); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci buf = nvmem_cell_read(cell, &len); 21262306a36Sopenharmony_ci nvmem_cell_put(cell); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (IS_ERR(buf)) 21562306a36Sopenharmony_ci return PTR_ERR(buf); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci memcpy(trim, buf, min(len, sizeof(trim))); 21862306a36Sopenharmony_ci kfree(buf); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (len != 16) { 22162306a36Sopenharmony_ci dev_err(dev, 22262306a36Sopenharmony_ci "OCOTP nvmem cell length is %zu, must be 16.\n", len); 22362306a36Sopenharmony_ci return -EINVAL; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Blank sample hardware */ 22762306a36Sopenharmony_ci if (!trim[0] && !trim[1] && !trim[2] && !trim[3]) { 22862306a36Sopenharmony_ci /* Use a default 25C binary codes */ 22962306a36Sopenharmony_ci writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), 23062306a36Sopenharmony_ci tmu->base + TCALIV(0)); 23162306a36Sopenharmony_ci writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), 23262306a36Sopenharmony_ci tmu->base + TCALIV(1)); 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci writel(FIELD_PREP(TASR_BUF_VERF_SEL_MASK, 23762306a36Sopenharmony_ci FIELD_GET(TRIM2_BUF_VERF_SEL_MASK, trim[0])) | 23862306a36Sopenharmony_ci FIELD_PREP(TASR_BUF_SLOPE_MASK, 23962306a36Sopenharmony_ci FIELD_GET(TRIM2_BUF_SLOP_SEL_MASK, trim[0])), 24062306a36Sopenharmony_ci tmu->base + TASR); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci writel(FIELD_PREP(TRIM_BJT_CUR_MASK, 24362306a36Sopenharmony_ci FIELD_GET(TRIM2_BJT_CUR_MASK, trim[0])) | 24462306a36Sopenharmony_ci FIELD_PREP(TRIM_BGR_MASK, FIELD_GET(TRIM2_BGR_MASK, trim[0])) | 24562306a36Sopenharmony_ci FIELD_PREP(TRIM_VLSB_MASK, FIELD_GET(TRIM2_VLSB_MASK, trim[0])) | 24662306a36Sopenharmony_ci TRIM_EN_CH, 24762306a36Sopenharmony_ci tmu->base + TRIM); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 25062306a36Sopenharmony_ci FIELD_GET(TRIM3_TCA25_0_LSB_MASK, trim[1]) | 25162306a36Sopenharmony_ci (FIELD_GET(TRIM4_TCA25_0_MSB_MASK, trim[2]) << 4)) | 25262306a36Sopenharmony_ci FIELD_PREP(TCALIV_SNSR105C_MASK, 25362306a36Sopenharmony_ci FIELD_GET(TRIM4_TCA105_0_MASK, trim[2])), 25462306a36Sopenharmony_ci tmu->base + TCALIV(0)); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 25762306a36Sopenharmony_ci FIELD_GET(TRIM5_TCA25_1_MASK, trim[3])) | 25862306a36Sopenharmony_ci FIELD_PREP(TCALIV_SNSR105C_MASK, 25962306a36Sopenharmony_ci FIELD_GET(TRIM5_TCA105_1_MASK, trim[3])), 26062306a36Sopenharmony_ci tmu->base + TCALIV(1)); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 26362306a36Sopenharmony_ci FIELD_GET(TRIM3_TCA40_0_MASK, trim[1])) | 26462306a36Sopenharmony_ci FIELD_PREP(TCALIV_SNSR105C_MASK, 26562306a36Sopenharmony_ci FIELD_GET(TRIM4_TCA40_1_MASK, trim[2])), 26662306a36Sopenharmony_ci tmu->base + TCALIV(2)); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int imx8mm_tmu_probe_set_calib(struct platform_device *pdev, 27262306a36Sopenharmony_ci struct imx8mm_tmu *tmu) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * Lack of calibration data OCOTP reference is not considered 27862306a36Sopenharmony_ci * fatal to retain compatibility with old DTs. It is however 27962306a36Sopenharmony_ci * strongly recommended to update such old DTs to get correct 28062306a36Sopenharmony_ci * temperature compensation values for each SoC. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci if (!of_property_present(pdev->dev.of_node, "nvmem-cells")) { 28362306a36Sopenharmony_ci dev_warn(dev, 28462306a36Sopenharmony_ci "No OCOTP nvmem reference found, SoC-specific calibration not loaded. Please update your DT.\n"); 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (tmu->socdata->version == TMU_VER1) 28962306a36Sopenharmony_ci return imx8mm_tmu_probe_set_calib_v1(pdev, tmu); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return imx8mm_tmu_probe_set_calib_v2(pdev, tmu); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int imx8mm_tmu_probe(struct platform_device *pdev) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci const struct thermal_soc_data *data; 29762306a36Sopenharmony_ci struct imx8mm_tmu *tmu; 29862306a36Sopenharmony_ci int ret; 29962306a36Sopenharmony_ci int i; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci data = of_device_get_match_data(&pdev->dev); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors, 30462306a36Sopenharmony_ci data->num_sensors), GFP_KERNEL); 30562306a36Sopenharmony_ci if (!tmu) 30662306a36Sopenharmony_ci return -ENOMEM; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci tmu->socdata = data; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci tmu->base = devm_platform_ioremap_resource(pdev, 0); 31162306a36Sopenharmony_ci if (IS_ERR(tmu->base)) 31262306a36Sopenharmony_ci return PTR_ERR(tmu->base); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci tmu->clk = devm_clk_get(&pdev->dev, NULL); 31562306a36Sopenharmony_ci if (IS_ERR(tmu->clk)) 31662306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(tmu->clk), 31762306a36Sopenharmony_ci "failed to get tmu clock\n"); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ret = clk_prepare_enable(tmu->clk); 32062306a36Sopenharmony_ci if (ret) { 32162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to enable tmu clock: %d\n", ret); 32262306a36Sopenharmony_ci return ret; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* disable the monitor during initialization */ 32662306a36Sopenharmony_ci imx8mm_tmu_enable(tmu, false); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci for (i = 0; i < data->num_sensors; i++) { 32962306a36Sopenharmony_ci tmu->sensors[i].priv = tmu; 33062306a36Sopenharmony_ci tmu->sensors[i].tzd = 33162306a36Sopenharmony_ci devm_thermal_of_zone_register(&pdev->dev, i, 33262306a36Sopenharmony_ci &tmu->sensors[i], 33362306a36Sopenharmony_ci &tmu_tz_ops); 33462306a36Sopenharmony_ci if (IS_ERR(tmu->sensors[i].tzd)) { 33562306a36Sopenharmony_ci ret = PTR_ERR(tmu->sensors[i].tzd); 33662306a36Sopenharmony_ci dev_err(&pdev->dev, 33762306a36Sopenharmony_ci "failed to register thermal zone sensor[%d]: %d\n", 33862306a36Sopenharmony_ci i, ret); 33962306a36Sopenharmony_ci goto disable_clk; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci tmu->sensors[i].hw_id = i; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci devm_thermal_add_hwmon_sysfs(&pdev->dev, tmu->sensors[i].tzd); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci platform_set_drvdata(pdev, tmu); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ret = imx8mm_tmu_probe_set_calib(pdev, tmu); 34962306a36Sopenharmony_ci if (ret) 35062306a36Sopenharmony_ci goto disable_clk; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* enable all the probes for V2 TMU */ 35362306a36Sopenharmony_ci if (tmu->socdata->version == TMU_VER2) 35462306a36Sopenharmony_ci imx8mm_tmu_probe_sel_all(tmu); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* enable the monitor */ 35762306a36Sopenharmony_ci imx8mm_tmu_enable(tmu, true); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cidisable_clk: 36262306a36Sopenharmony_ci clk_disable_unprepare(tmu->clk); 36362306a36Sopenharmony_ci return ret; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int imx8mm_tmu_remove(struct platform_device *pdev) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct imx8mm_tmu *tmu = platform_get_drvdata(pdev); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* disable TMU */ 37162306a36Sopenharmony_ci imx8mm_tmu_enable(tmu, false); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci clk_disable_unprepare(tmu->clk); 37462306a36Sopenharmony_ci platform_set_drvdata(pdev, NULL); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic struct thermal_soc_data imx8mm_tmu_data = { 38062306a36Sopenharmony_ci .num_sensors = 1, 38162306a36Sopenharmony_ci .version = TMU_VER1, 38262306a36Sopenharmony_ci .get_temp = imx8mm_tmu_get_temp, 38362306a36Sopenharmony_ci}; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic struct thermal_soc_data imx8mp_tmu_data = { 38662306a36Sopenharmony_ci .num_sensors = 2, 38762306a36Sopenharmony_ci .version = TMU_VER2, 38862306a36Sopenharmony_ci .get_temp = imx8mp_tmu_get_temp, 38962306a36Sopenharmony_ci}; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic const struct of_device_id imx8mm_tmu_table[] = { 39262306a36Sopenharmony_ci { .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, }, 39362306a36Sopenharmony_ci { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, }, 39462306a36Sopenharmony_ci { }, 39562306a36Sopenharmony_ci}; 39662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx8mm_tmu_table); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic struct platform_driver imx8mm_tmu = { 39962306a36Sopenharmony_ci .driver = { 40062306a36Sopenharmony_ci .name = "i.mx8mm_thermal", 40162306a36Sopenharmony_ci .of_match_table = imx8mm_tmu_table, 40262306a36Sopenharmony_ci }, 40362306a36Sopenharmony_ci .probe = imx8mm_tmu_probe, 40462306a36Sopenharmony_ci .remove = imx8mm_tmu_remove, 40562306a36Sopenharmony_ci}; 40662306a36Sopenharmony_cimodule_platform_driver(imx8mm_tmu); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciMODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); 40962306a36Sopenharmony_ciMODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver"); 41062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 411