|
10 | 10 | #include <linux/err.h>
|
11 | 11 | #include <linux/io.h>
|
12 | 12 | #include <linux/module.h>
|
| 13 | +#include <linux/nvmem-consumer.h> |
13 | 14 | #include <linux/of.h>
|
14 | 15 | #include <linux/of_device.h>
|
15 | 16 | #include <linux/platform_device.h>
|
| 17 | +#include <linux/slab.h> |
16 | 18 | #include <linux/thermal.h>
|
17 | 19 |
|
18 | 20 | #include "thermal_core.h"
|
19 | 21 |
|
20 | 22 | #define TER 0x0 /* TMU enable */
|
21 | 23 | #define TPS 0x4
|
22 | 24 | #define TRITSR 0x20 /* TMU immediate temp */
|
| 25 | +/* TMU calibration data registers */ |
| 26 | +#define TASR 0x28 |
| 27 | +#define TASR_BUF_SLOPE_MASK GENMASK(19, 16) |
| 28 | +#define TASR_BUF_VREF_MASK GENMASK(4, 0) /* TMU_V1 */ |
| 29 | +#define TASR_BUF_VERF_SEL_MASK GENMASK(1, 0) /* TMU_V2 */ |
| 30 | +#define TCALIV(n) (0x30 + ((n) * 4)) |
| 31 | +#define TCALIV_EN BIT(31) |
| 32 | +#define TCALIV_HR_MASK GENMASK(23, 16) /* TMU_V1 */ |
| 33 | +#define TCALIV_RT_MASK GENMASK(7, 0) /* TMU_V1 */ |
| 34 | +#define TCALIV_SNSR105C_MASK GENMASK(27, 16) /* TMU_V2 */ |
| 35 | +#define TCALIV_SNSR25C_MASK GENMASK(11, 0) /* TMU_V2 */ |
| 36 | +#define TRIM 0x3c |
| 37 | +#define TRIM_BJT_CUR_MASK GENMASK(23, 20) |
| 38 | +#define TRIM_BGR_MASK GENMASK(31, 28) |
| 39 | +#define TRIM_VLSB_MASK GENMASK(15, 12) |
| 40 | +#define TRIM_EN_CH BIT(7) |
23 | 41 |
|
24 | 42 | #define TER_ADC_PD BIT(30)
|
25 | 43 | #define TER_EN BIT(31)
|
|
32 | 50 | #define SIGN_BIT BIT(7)
|
33 | 51 | #define TEMP_VAL_MASK GENMASK(6, 0)
|
34 | 52 |
|
| 53 | +/* TMU OCOTP calibration data bitfields */ |
| 54 | +#define ANA0_EN BIT(25) |
| 55 | +#define ANA0_BUF_VREF_MASK GENMASK(24, 20) |
| 56 | +#define ANA0_BUF_SLOPE_MASK GENMASK(19, 16) |
| 57 | +#define ANA0_HR_MASK GENMASK(15, 8) |
| 58 | +#define ANA0_RT_MASK GENMASK(7, 0) |
| 59 | +#define TRIM2_VLSB_MASK GENMASK(23, 20) |
| 60 | +#define TRIM2_BGR_MASK GENMASK(19, 16) |
| 61 | +#define TRIM2_BJT_CUR_MASK GENMASK(15, 12) |
| 62 | +#define TRIM2_BUF_SLOP_SEL_MASK GENMASK(11, 8) |
| 63 | +#define TRIM2_BUF_VERF_SEL_MASK GENMASK(7, 6) |
| 64 | +#define TRIM3_TCA25_0_LSB_MASK GENMASK(31, 28) |
| 65 | +#define TRIM3_TCA40_0_MASK GENMASK(27, 16) |
| 66 | +#define TRIM4_TCA40_1_MASK GENMASK(31, 20) |
| 67 | +#define TRIM4_TCA105_0_MASK GENMASK(19, 8) |
| 68 | +#define TRIM4_TCA25_0_MSB_MASK GENMASK(7, 0) |
| 69 | +#define TRIM5_TCA105_1_MASK GENMASK(23, 12) |
| 70 | +#define TRIM5_TCA25_1_MASK GENMASK(11, 0) |
| 71 | + |
35 | 72 | #define VER1_TEMP_LOW_LIMIT 10000
|
36 | 73 | #define VER2_TEMP_LOW_LIMIT -40000
|
37 | 74 | #define VER2_TEMP_HIGH_LIMIT 125000
|
@@ -134,6 +171,129 @@ static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)
|
134 | 171 | writel_relaxed(val, tmu->base + TPS);
|
135 | 172 | }
|
136 | 173 |
|
| 174 | +static int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev, |
| 175 | + struct imx8mm_tmu *tmu) |
| 176 | +{ |
| 177 | + struct device *dev = &pdev->dev; |
| 178 | + u32 ana0; |
| 179 | + int ret; |
| 180 | + |
| 181 | + ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0); |
| 182 | + if (ret) { |
| 183 | + dev_warn(dev, "Failed to read OCOTP nvmem cell (%d).\n", ret); |
| 184 | + return ret; |
| 185 | + } |
| 186 | + |
| 187 | + writel(FIELD_PREP(TASR_BUF_VREF_MASK, |
| 188 | + FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) | |
| 189 | + FIELD_PREP(TASR_BUF_SLOPE_MASK, |
| 190 | + FIELD_GET(ANA0_BUF_SLOPE_MASK, ana0)), |
| 191 | + tmu->base + TASR); |
| 192 | + |
| 193 | + writel(FIELD_PREP(TCALIV_RT_MASK, FIELD_GET(ANA0_RT_MASK, ana0)) | |
| 194 | + FIELD_PREP(TCALIV_HR_MASK, FIELD_GET(ANA0_HR_MASK, ana0)) | |
| 195 | + ((ana0 & ANA0_EN) ? TCALIV_EN : 0), |
| 196 | + tmu->base + TCALIV(0)); |
| 197 | + |
| 198 | + return 0; |
| 199 | +} |
| 200 | + |
| 201 | +static int imx8mm_tmu_probe_set_calib_v2(struct platform_device *pdev, |
| 202 | + struct imx8mm_tmu *tmu) |
| 203 | +{ |
| 204 | + struct device *dev = &pdev->dev; |
| 205 | + struct nvmem_cell *cell; |
| 206 | + u32 trim[4] = { 0 }; |
| 207 | + size_t len; |
| 208 | + void *buf; |
| 209 | + |
| 210 | + cell = nvmem_cell_get(dev, "calib"); |
| 211 | + if (IS_ERR(cell)) |
| 212 | + return PTR_ERR(cell); |
| 213 | + |
| 214 | + buf = nvmem_cell_read(cell, &len); |
| 215 | + nvmem_cell_put(cell); |
| 216 | + |
| 217 | + if (IS_ERR(buf)) |
| 218 | + return PTR_ERR(buf); |
| 219 | + |
| 220 | + memcpy(trim, buf, min(len, sizeof(trim))); |
| 221 | + kfree(buf); |
| 222 | + |
| 223 | + if (len != 16) { |
| 224 | + dev_err(dev, |
| 225 | + "OCOTP nvmem cell length is %zu, must be 16.\n", len); |
| 226 | + return -EINVAL; |
| 227 | + } |
| 228 | + |
| 229 | + /* Blank sample hardware */ |
| 230 | + if (!trim[0] && !trim[1] && !trim[2] && !trim[3]) { |
| 231 | + /* Use a default 25C binary codes */ |
| 232 | + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), |
| 233 | + tmu->base + TCALIV(0)); |
| 234 | + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c), |
| 235 | + tmu->base + TCALIV(1)); |
| 236 | + return 0; |
| 237 | + } |
| 238 | + |
| 239 | + writel(FIELD_PREP(TASR_BUF_VERF_SEL_MASK, |
| 240 | + FIELD_GET(TRIM2_BUF_VERF_SEL_MASK, trim[0])) | |
| 241 | + FIELD_PREP(TASR_BUF_SLOPE_MASK, |
| 242 | + FIELD_GET(TRIM2_BUF_SLOP_SEL_MASK, trim[0])), |
| 243 | + tmu->base + TASR); |
| 244 | + |
| 245 | + writel(FIELD_PREP(TRIM_BJT_CUR_MASK, |
| 246 | + FIELD_GET(TRIM2_BJT_CUR_MASK, trim[0])) | |
| 247 | + FIELD_PREP(TRIM_BGR_MASK, FIELD_GET(TRIM2_BGR_MASK, trim[0])) | |
| 248 | + FIELD_PREP(TRIM_VLSB_MASK, FIELD_GET(TRIM2_VLSB_MASK, trim[0])) | |
| 249 | + TRIM_EN_CH, |
| 250 | + tmu->base + TRIM); |
| 251 | + |
| 252 | + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, |
| 253 | + FIELD_GET(TRIM3_TCA25_0_LSB_MASK, trim[1]) | |
| 254 | + (FIELD_GET(TRIM4_TCA25_0_MSB_MASK, trim[2]) << 4)) | |
| 255 | + FIELD_PREP(TCALIV_SNSR105C_MASK, |
| 256 | + FIELD_GET(TRIM4_TCA105_0_MASK, trim[2])), |
| 257 | + tmu->base + TCALIV(0)); |
| 258 | + |
| 259 | + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, |
| 260 | + FIELD_GET(TRIM5_TCA25_1_MASK, trim[3])) | |
| 261 | + FIELD_PREP(TCALIV_SNSR105C_MASK, |
| 262 | + FIELD_GET(TRIM5_TCA105_1_MASK, trim[3])), |
| 263 | + tmu->base + TCALIV(1)); |
| 264 | + |
| 265 | + writel(FIELD_PREP(TCALIV_SNSR25C_MASK, |
| 266 | + FIELD_GET(TRIM3_TCA40_0_MASK, trim[1])) | |
| 267 | + FIELD_PREP(TCALIV_SNSR105C_MASK, |
| 268 | + FIELD_GET(TRIM4_TCA40_1_MASK, trim[2])), |
| 269 | + tmu->base + TCALIV(2)); |
| 270 | + |
| 271 | + return 0; |
| 272 | +} |
| 273 | + |
| 274 | +static int imx8mm_tmu_probe_set_calib(struct platform_device *pdev, |
| 275 | + struct imx8mm_tmu *tmu) |
| 276 | +{ |
| 277 | + struct device *dev = &pdev->dev; |
| 278 | + |
| 279 | + /* |
| 280 | + * Lack of calibration data OCOTP reference is not considered |
| 281 | + * fatal to retain compatibility with old DTs. It is however |
| 282 | + * strongly recommended to update such old DTs to get correct |
| 283 | + * temperature compensation values for each SoC. |
| 284 | + */ |
| 285 | + if (!of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) { |
| 286 | + dev_warn(dev, |
| 287 | + "No OCOTP nvmem reference found, SoC-specific calibration not loaded. Please update your DT.\n"); |
| 288 | + return 0; |
| 289 | + } |
| 290 | + |
| 291 | + if (tmu->socdata->version == TMU_VER1) |
| 292 | + return imx8mm_tmu_probe_set_calib_v1(pdev, tmu); |
| 293 | + |
| 294 | + return imx8mm_tmu_probe_set_calib_v2(pdev, tmu); |
| 295 | +} |
| 296 | + |
137 | 297 | static int imx8mm_tmu_probe(struct platform_device *pdev)
|
138 | 298 | {
|
139 | 299 | const struct thermal_soc_data *data;
|
@@ -186,6 +346,10 @@ static int imx8mm_tmu_probe(struct platform_device *pdev)
|
186 | 346 |
|
187 | 347 | platform_set_drvdata(pdev, tmu);
|
188 | 348 |
|
| 349 | + ret = imx8mm_tmu_probe_set_calib(pdev, tmu); |
| 350 | + if (ret) |
| 351 | + goto disable_clk; |
| 352 | + |
189 | 353 | /* enable all the probes for V2 TMU */
|
190 | 354 | if (tmu->socdata->version == TMU_VER2)
|
191 | 355 | imx8mm_tmu_probe_sel_all(tmu);
|
|
0 commit comments