409 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2020 NXP.4 *5 * Author: Anson Huang <Anson.Huang@nxp.com>6 */7 8#include <linux/bitfield.h>9#include <linux/clk.h>10#include <linux/err.h>11#include <linux/io.h>12#include <linux/module.h>13#include <linux/nvmem-consumer.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/slab.h>17#include <linux/thermal.h>18 19#include "thermal_hwmon.h"20 21#define TER 0x0 /* TMU enable */22#define TPS 0x423#define TRITSR 0x20 /* TMU immediate temp */24/* TMU calibration data registers */25#define TASR 0x2826#define TASR_BUF_SLOPE_MASK GENMASK(19, 16)27#define TASR_BUF_VREF_MASK GENMASK(4, 0) /* TMU_V1 */28#define TASR_BUF_VERF_SEL_MASK GENMASK(1, 0) /* TMU_V2 */29#define TCALIV(n) (0x30 + ((n) * 4))30#define TCALIV_EN BIT(31)31#define TCALIV_HR_MASK GENMASK(23, 16) /* TMU_V1 */32#define TCALIV_RT_MASK GENMASK(7, 0) /* TMU_V1 */33#define TCALIV_SNSR105C_MASK GENMASK(27, 16) /* TMU_V2 */34#define TCALIV_SNSR25C_MASK GENMASK(11, 0) /* TMU_V2 */35#define TRIM 0x3c36#define TRIM_BJT_CUR_MASK GENMASK(23, 20)37#define TRIM_BGR_MASK GENMASK(31, 28)38#define TRIM_VLSB_MASK GENMASK(15, 12)39#define TRIM_EN_CH BIT(7)40 41#define TER_ADC_PD BIT(30)42#define TER_EN BIT(31)43#define TRITSR_TEMP0_VAL_MASK GENMASK(7, 0)44#define TRITSR_TEMP1_VAL_MASK GENMASK(23, 16)45 46#define PROBE_SEL_ALL GENMASK(31, 30)47 48#define probe_status_offset(x) (30 + x)49#define SIGN_BIT BIT(7)50#define TEMP_VAL_MASK GENMASK(6, 0)51 52/* TMU OCOTP calibration data bitfields */53#define ANA0_EN BIT(25)54#define ANA0_BUF_VREF_MASK GENMASK(24, 20)55#define ANA0_BUF_SLOPE_MASK GENMASK(19, 16)56#define ANA0_HR_MASK GENMASK(15, 8)57#define ANA0_RT_MASK GENMASK(7, 0)58#define TRIM2_VLSB_MASK GENMASK(23, 20)59#define TRIM2_BGR_MASK GENMASK(19, 16)60#define TRIM2_BJT_CUR_MASK GENMASK(15, 12)61#define TRIM2_BUF_SLOP_SEL_MASK GENMASK(11, 8)62#define TRIM2_BUF_VERF_SEL_MASK GENMASK(7, 6)63#define TRIM3_TCA25_0_LSB_MASK GENMASK(31, 28)64#define TRIM3_TCA40_0_MASK GENMASK(27, 16)65#define TRIM4_TCA40_1_MASK GENMASK(31, 20)66#define TRIM4_TCA105_0_MASK GENMASK(19, 8)67#define TRIM4_TCA25_0_MSB_MASK GENMASK(7, 0)68#define TRIM5_TCA105_1_MASK GENMASK(23, 12)69#define TRIM5_TCA25_1_MASK GENMASK(11, 0)70 71#define VER1_TEMP_LOW_LIMIT 1000072#define VER2_TEMP_LOW_LIMIT -4000073#define VER2_TEMP_HIGH_LIMIT 12500074 75#define TMU_VER1 0x176#define TMU_VER2 0x277 78struct thermal_soc_data {79 u32 num_sensors;80 u32 version;81 int (*get_temp)(void *data, int *temp);82};83 84struct tmu_sensor {85 struct imx8mm_tmu *priv;86 u32 hw_id;87 struct thermal_zone_device *tzd;88};89 90struct imx8mm_tmu {91 void __iomem *base;92 struct clk *clk;93 const struct thermal_soc_data *socdata;94 struct tmu_sensor sensors[];95};96 97static int imx8mm_tmu_get_temp(void *data, int *temp)98{99 struct tmu_sensor *sensor = data;100 struct imx8mm_tmu *tmu = sensor->priv;101 u32 val;102 103 val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK;104 105 /*106 * Do not validate against the V bit (bit 31) due to errata107 * ERR051272: TMU: Bit 31 of registers TMU_TSCR/TMU_TRITSR/TMU_TRATSR invalid108 */109 110 *temp = val * 1000;111 if (*temp < VER1_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)112 return -EAGAIN;113 114 return 0;115}116 117static int imx8mp_tmu_get_temp(void *data, int *temp)118{119 struct tmu_sensor *sensor = data;120 struct imx8mm_tmu *tmu = sensor->priv;121 unsigned long val;122 bool ready;123 124 val = readl_relaxed(tmu->base + TRITSR);125 ready = test_bit(probe_status_offset(sensor->hw_id), &val);126 if (!ready)127 return -EAGAIN;128 129 val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) :130 FIELD_GET(TRITSR_TEMP0_VAL_MASK, val);131 if (val & SIGN_BIT) /* negative */132 val = (~(val & TEMP_VAL_MASK) + 1);133 134 *temp = val * 1000;135 if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)136 return -EAGAIN;137 138 return 0;139}140 141static int tmu_get_temp(struct thermal_zone_device *tz, int *temp)142{143 struct tmu_sensor *sensor = thermal_zone_device_priv(tz);144 struct imx8mm_tmu *tmu = sensor->priv;145 146 return tmu->socdata->get_temp(sensor, temp);147}148 149static const struct thermal_zone_device_ops tmu_tz_ops = {150 .get_temp = tmu_get_temp,151};152 153static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)154{155 u32 val;156 157 val = readl_relaxed(tmu->base + TER);158 val = enable ? (val | TER_EN) : (val & ~TER_EN);159 if (tmu->socdata->version == TMU_VER2)160 val = enable ? (val & ~TER_ADC_PD) : (val | TER_ADC_PD);161 writel_relaxed(val, tmu->base + TER);162}163 164static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)165{166 u32 val;167 168 val = readl_relaxed(tmu->base + TPS);169 val |= PROBE_SEL_ALL;170 writel_relaxed(val, tmu->base + TPS);171}172 173static int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev,174 struct imx8mm_tmu *tmu)175{176 struct device *dev = &pdev->dev;177 u32 ana0;178 int ret;179 180 ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0);181 if (ret)182 return dev_err_probe(dev, ret, "Failed to read OCOTP nvmem cell\n");183 184 writel(FIELD_PREP(TASR_BUF_VREF_MASK,185 FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) |186 FIELD_PREP(TASR_BUF_SLOPE_MASK,187 FIELD_GET(ANA0_BUF_SLOPE_MASK, ana0)),188 tmu->base + TASR);189 190 writel(FIELD_PREP(TCALIV_RT_MASK, FIELD_GET(ANA0_RT_MASK, ana0)) |191 FIELD_PREP(TCALIV_HR_MASK, FIELD_GET(ANA0_HR_MASK, ana0)) |192 ((ana0 & ANA0_EN) ? TCALIV_EN : 0),193 tmu->base + TCALIV(0));194 195 return 0;196}197 198static int imx8mm_tmu_probe_set_calib_v2(struct platform_device *pdev,199 struct imx8mm_tmu *tmu)200{201 struct device *dev = &pdev->dev;202 struct nvmem_cell *cell;203 u32 trim[4] = { 0 };204 size_t len;205 void *buf;206 207 cell = nvmem_cell_get(dev, "calib");208 if (IS_ERR(cell))209 return PTR_ERR(cell);210 211 buf = nvmem_cell_read(cell, &len);212 nvmem_cell_put(cell);213 214 if (IS_ERR(buf))215 return PTR_ERR(buf);216 217 memcpy(trim, buf, min(len, sizeof(trim)));218 kfree(buf);219 220 if (len != 16) {221 dev_err(dev,222 "OCOTP nvmem cell length is %zu, must be 16.\n", len);223 return -EINVAL;224 }225 226 /* Blank sample hardware */227 if (!trim[0] && !trim[1] && !trim[2] && !trim[3]) {228 /* Use a default 25C binary codes */229 writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c),230 tmu->base + TCALIV(0));231 writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c),232 tmu->base + TCALIV(1));233 return 0;234 }235 236 writel(FIELD_PREP(TASR_BUF_VERF_SEL_MASK,237 FIELD_GET(TRIM2_BUF_VERF_SEL_MASK, trim[0])) |238 FIELD_PREP(TASR_BUF_SLOPE_MASK,239 FIELD_GET(TRIM2_BUF_SLOP_SEL_MASK, trim[0])),240 tmu->base + TASR);241 242 writel(FIELD_PREP(TRIM_BJT_CUR_MASK,243 FIELD_GET(TRIM2_BJT_CUR_MASK, trim[0])) |244 FIELD_PREP(TRIM_BGR_MASK, FIELD_GET(TRIM2_BGR_MASK, trim[0])) |245 FIELD_PREP(TRIM_VLSB_MASK, FIELD_GET(TRIM2_VLSB_MASK, trim[0])) |246 TRIM_EN_CH,247 tmu->base + TRIM);248 249 writel(FIELD_PREP(TCALIV_SNSR25C_MASK,250 FIELD_GET(TRIM3_TCA25_0_LSB_MASK, trim[1]) |251 (FIELD_GET(TRIM4_TCA25_0_MSB_MASK, trim[2]) << 4)) |252 FIELD_PREP(TCALIV_SNSR105C_MASK,253 FIELD_GET(TRIM4_TCA105_0_MASK, trim[2])),254 tmu->base + TCALIV(0));255 256 writel(FIELD_PREP(TCALIV_SNSR25C_MASK,257 FIELD_GET(TRIM5_TCA25_1_MASK, trim[3])) |258 FIELD_PREP(TCALIV_SNSR105C_MASK,259 FIELD_GET(TRIM5_TCA105_1_MASK, trim[3])),260 tmu->base + TCALIV(1));261 262 writel(FIELD_PREP(TCALIV_SNSR25C_MASK,263 FIELD_GET(TRIM3_TCA40_0_MASK, trim[1])) |264 FIELD_PREP(TCALIV_SNSR105C_MASK,265 FIELD_GET(TRIM4_TCA40_1_MASK, trim[2])),266 tmu->base + TCALIV(2));267 268 return 0;269}270 271static int imx8mm_tmu_probe_set_calib(struct platform_device *pdev,272 struct imx8mm_tmu *tmu)273{274 struct device *dev = &pdev->dev;275 276 /*277 * Lack of calibration data OCOTP reference is not considered278 * fatal to retain compatibility with old DTs. It is however279 * strongly recommended to update such old DTs to get correct280 * temperature compensation values for each SoC.281 */282 if (!of_property_present(pdev->dev.of_node, "nvmem-cells")) {283 dev_warn(dev,284 "No OCOTP nvmem reference found, SoC-specific calibration not loaded. Please update your DT.\n");285 return 0;286 }287 288 if (tmu->socdata->version == TMU_VER1)289 return imx8mm_tmu_probe_set_calib_v1(pdev, tmu);290 291 return imx8mm_tmu_probe_set_calib_v2(pdev, tmu);292}293 294static int imx8mm_tmu_probe(struct platform_device *pdev)295{296 const struct thermal_soc_data *data;297 struct imx8mm_tmu *tmu;298 int ret;299 int i;300 301 data = of_device_get_match_data(&pdev->dev);302 303 tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,304 data->num_sensors), GFP_KERNEL);305 if (!tmu)306 return -ENOMEM;307 308 tmu->socdata = data;309 310 tmu->base = devm_platform_ioremap_resource(pdev, 0);311 if (IS_ERR(tmu->base))312 return PTR_ERR(tmu->base);313 314 tmu->clk = devm_clk_get(&pdev->dev, NULL);315 if (IS_ERR(tmu->clk))316 return dev_err_probe(&pdev->dev, PTR_ERR(tmu->clk),317 "failed to get tmu clock\n");318 319 ret = clk_prepare_enable(tmu->clk);320 if (ret) {321 dev_err(&pdev->dev, "failed to enable tmu clock: %d\n", ret);322 return ret;323 }324 325 /* disable the monitor during initialization */326 imx8mm_tmu_enable(tmu, false);327 328 for (i = 0; i < data->num_sensors; i++) {329 tmu->sensors[i].priv = tmu;330 tmu->sensors[i].tzd =331 devm_thermal_of_zone_register(&pdev->dev, i,332 &tmu->sensors[i],333 &tmu_tz_ops);334 if (IS_ERR(tmu->sensors[i].tzd)) {335 ret = PTR_ERR(tmu->sensors[i].tzd);336 dev_err(&pdev->dev,337 "failed to register thermal zone sensor[%d]: %d\n",338 i, ret);339 goto disable_clk;340 }341 tmu->sensors[i].hw_id = i;342 343 devm_thermal_add_hwmon_sysfs(&pdev->dev, tmu->sensors[i].tzd);344 }345 346 platform_set_drvdata(pdev, tmu);347 348 ret = imx8mm_tmu_probe_set_calib(pdev, tmu);349 if (ret)350 goto disable_clk;351 352 /* enable all the probes for V2 TMU */353 if (tmu->socdata->version == TMU_VER2)354 imx8mm_tmu_probe_sel_all(tmu);355 356 /* enable the monitor */357 imx8mm_tmu_enable(tmu, true);358 359 return 0;360 361disable_clk:362 clk_disable_unprepare(tmu->clk);363 return ret;364}365 366static void imx8mm_tmu_remove(struct platform_device *pdev)367{368 struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);369 370 /* disable TMU */371 imx8mm_tmu_enable(tmu, false);372 373 clk_disable_unprepare(tmu->clk);374 platform_set_drvdata(pdev, NULL);375}376 377static struct thermal_soc_data imx8mm_tmu_data = {378 .num_sensors = 1,379 .version = TMU_VER1,380 .get_temp = imx8mm_tmu_get_temp,381};382 383static struct thermal_soc_data imx8mp_tmu_data = {384 .num_sensors = 2,385 .version = TMU_VER2,386 .get_temp = imx8mp_tmu_get_temp,387};388 389static const struct of_device_id imx8mm_tmu_table[] = {390 { .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },391 { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },392 { },393};394MODULE_DEVICE_TABLE(of, imx8mm_tmu_table);395 396static struct platform_driver imx8mm_tmu = {397 .driver = {398 .name = "i.mx8mm_thermal",399 .of_match_table = imx8mm_tmu_table,400 },401 .probe = imx8mm_tmu_probe,402 .remove_new = imx8mm_tmu_remove,403};404module_platform_driver(imx8mm_tmu);405 406MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");407MODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver");408MODULE_LICENSE("GPL v2");409