1/* 2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 3 * 4 * Author: 5 * Mikko Perttunen <mperttunen@nvidia.com> 6 * 7 * This software is licensed under the terms of the GNU General Public 8 * License version 2, as published by the Free Software Foundation, and 9 * may be copied, distributed, and modified under those terms. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 */ 17 18#include <linux/bitops.h> 19#include <linux/clk.h> 20#include <linux/delay.h> 21#include <linux/err.h> 22#include <linux/interrupt.h> 23#include <linux/io.h> 24#include <linux/module.h> 25#include <linux/of.h> 26#include <linux/platform_device.h> 27#include <linux/reset.h> 28#include <linux/thermal.h> 29 30#include <soc/tegra/fuse.h> 31 32#define SENSOR_CONFIG0 0 33#define SENSOR_CONFIG0_STOP BIT(0) 34#define SENSOR_CONFIG0_TALL_SHIFT 8 35#define SENSOR_CONFIG0_TCALC_OVER BIT(4) 36#define SENSOR_CONFIG0_OVER BIT(3) 37#define SENSOR_CONFIG0_CPTR_OVER BIT(2) 38 39#define SENSOR_CONFIG1 4 40#define SENSOR_CONFIG1_TSAMPLE_SHIFT 0 41#define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15 42#define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24 43#define SENSOR_CONFIG1_TEMP_ENABLE BIT(31) 44 45#define SENSOR_CONFIG2 8 46#define SENSOR_CONFIG2_THERMA_SHIFT 16 47#define SENSOR_CONFIG2_THERMB_SHIFT 0 48 49#define SENSOR_PDIV 0x1c0 50#define SENSOR_PDIV_T124 0x8888 51#define SENSOR_HOTSPOT_OFF 0x1c4 52#define SENSOR_HOTSPOT_OFF_T124 0x00060600 53#define SENSOR_TEMP1 0x1c8 54#define SENSOR_TEMP2 0x1cc 55 56#define SENSOR_TEMP_MASK 0xffff 57#define READBACK_VALUE_MASK 0xff00 58#define READBACK_VALUE_SHIFT 8 59#define READBACK_ADD_HALF BIT(7) 60#define READBACK_NEGATE BIT(1) 61 62#define FUSE_TSENSOR8_CALIB 0x180 63#define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc 64 65#define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff 66#define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13) 67#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13 68 69#define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK 0x3ff 70#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK (0x7ff << 10) 71#define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT 10 72 73#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f 74#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21) 75#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21 76 77#define NOMINAL_CALIB_FT_T124 105 78#define NOMINAL_CALIB_CP_T124 25 79 80struct tegra_tsensor_configuration { 81 u32 tall, tsample, tiddq_en, ten_count, pdiv, tsample_ate, pdiv_ate; 82}; 83 84struct tegra_tsensor { 85 const struct tegra_tsensor_configuration *config; 86 u32 base, calib_fuse_offset; 87 /* Correction values used to modify values read from calibration fuses */ 88 s32 fuse_corr_alpha, fuse_corr_beta; 89}; 90 91struct tegra_thermctl_zone { 92 void __iomem *reg; 93 unsigned int shift; 94}; 95 96static const struct tegra_tsensor_configuration t124_tsensor_config = { 97 .tall = 16300, 98 .tsample = 120, 99 .tiddq_en = 1, 100 .ten_count = 1, 101 .pdiv = 8, 102 .tsample_ate = 480, 103 .pdiv_ate = 8 104}; 105 106static const struct tegra_tsensor t124_tsensors[] = { 107 { 108 .config = &t124_tsensor_config, 109 .base = 0xc0, 110 .calib_fuse_offset = 0x098, 111 .fuse_corr_alpha = 1135400, 112 .fuse_corr_beta = -6266900, 113 }, 114 { 115 .config = &t124_tsensor_config, 116 .base = 0xe0, 117 .calib_fuse_offset = 0x084, 118 .fuse_corr_alpha = 1122220, 119 .fuse_corr_beta = -5700700, 120 }, 121 { 122 .config = &t124_tsensor_config, 123 .base = 0x100, 124 .calib_fuse_offset = 0x088, 125 .fuse_corr_alpha = 1127000, 126 .fuse_corr_beta = -6768200, 127 }, 128 { 129 .config = &t124_tsensor_config, 130 .base = 0x120, 131 .calib_fuse_offset = 0x12c, 132 .fuse_corr_alpha = 1110900, 133 .fuse_corr_beta = -6232000, 134 }, 135 { 136 .config = &t124_tsensor_config, 137 .base = 0x140, 138 .calib_fuse_offset = 0x158, 139 .fuse_corr_alpha = 1122300, 140 .fuse_corr_beta = -5936400, 141 }, 142 { 143 .config = &t124_tsensor_config, 144 .base = 0x160, 145 .calib_fuse_offset = 0x15c, 146 .fuse_corr_alpha = 1145700, 147 .fuse_corr_beta = -7124600, 148 }, 149 { 150 .config = &t124_tsensor_config, 151 .base = 0x180, 152 .calib_fuse_offset = 0x154, 153 .fuse_corr_alpha = 1120100, 154 .fuse_corr_beta = -6000500, 155 }, 156 { 157 .config = &t124_tsensor_config, 158 .base = 0x1a0, 159 .calib_fuse_offset = 0x160, 160 .fuse_corr_alpha = 1106500, 161 .fuse_corr_beta = -6729300, 162 }, 163}; 164 165struct tegra_soctherm { 166 struct reset_control *reset; 167 struct clk *clock_tsensor; 168 struct clk *clock_soctherm; 169 void __iomem *regs; 170 171 struct thermal_zone_device *thermctl_tzs[4]; 172}; 173 174struct tsensor_shared_calibration { 175 u32 base_cp, base_ft; 176 u32 actual_temp_cp, actual_temp_ft; 177}; 178 179static int calculate_shared_calibration(struct tsensor_shared_calibration *r) 180{ 181 u32 val, shifted_cp, shifted_ft; 182 int err; 183 184 err = tegra_fuse_readl(FUSE_TSENSOR8_CALIB, &val); 185 if (err) 186 return err; 187 r->base_cp = val & FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK; 188 r->base_ft = (val & FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK) 189 >> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT; 190 val = ((val & FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK) 191 >> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT); 192 shifted_ft = sign_extend32(val, 4); 193 194 err = tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0, &val); 195 if (err) 196 return err; 197 shifted_cp = sign_extend32(val, 5); 198 199 r->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + shifted_cp; 200 r->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + shifted_ft; 201 202 return 0; 203} 204 205static s64 div64_s64_precise(s64 a, s64 b) 206{ 207 s64 r, al; 208 209 /* Scale up for increased precision division */ 210 al = a << 16; 211 212 r = div64_s64(al * 2 + 1, 2 * b); 213 return r >> 16; 214} 215 216static int 217calculate_tsensor_calibration(const struct tegra_tsensor *sensor, 218 const struct tsensor_shared_calibration *shared, 219 u32 *calib) 220{ 221 u32 val; 222 s32 actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp, 223 mult, div; 224 s16 therma, thermb; 225 s64 tmp; 226 int err; 227 228 err = tegra_fuse_readl(sensor->calib_fuse_offset, &val); 229 if (err) 230 return err; 231 232 actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12); 233 val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) 234 >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT; 235 actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12); 236 237 delta_sens = actual_tsensor_ft - actual_tsensor_cp; 238 delta_temp = shared->actual_temp_ft - shared->actual_temp_cp; 239 240 mult = sensor->config->pdiv * sensor->config->tsample_ate; 241 div = sensor->config->tsample * sensor->config->pdiv_ate; 242 243 therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult, 244 (s64) delta_sens * div); 245 246 tmp = (s64)actual_tsensor_ft * shared->actual_temp_cp - 247 (s64)actual_tsensor_cp * shared->actual_temp_ft; 248 thermb = div64_s64_precise(tmp, (s64)delta_sens); 249 250 therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha, 251 (s64)1000000LL); 252 thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha + 253 sensor->fuse_corr_beta, (s64)1000000LL); 254 255 *calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) | 256 ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT); 257 258 return 0; 259} 260 261static int enable_tsensor(struct tegra_soctherm *tegra, 262 const struct tegra_tsensor *sensor, 263 const struct tsensor_shared_calibration *shared) 264{ 265 void __iomem *base = tegra->regs + sensor->base; 266 unsigned int val; 267 u32 calib; 268 int err; 269 270 err = calculate_tsensor_calibration(sensor, shared, &calib); 271 if (err) 272 return err; 273 274 val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT; 275 writel(val, base + SENSOR_CONFIG0); 276 277 val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT; 278 val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT; 279 val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT; 280 val |= SENSOR_CONFIG1_TEMP_ENABLE; 281 writel(val, base + SENSOR_CONFIG1); 282 283 writel(calib, base + SENSOR_CONFIG2); 284 285 return 0; 286} 287 288/* 289 * Translate from soctherm readback format to millicelsius. 290 * The soctherm readback format in bits is as follows: 291 * TTTTTTTT H______N 292 * where T's contain the temperature in Celsius, 293 * H denotes an addition of 0.5 Celsius and N denotes negation 294 * of the final value. 295 */ 296static long translate_temp(u16 val) 297{ 298 long t; 299 300 t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000; 301 if (val & READBACK_ADD_HALF) 302 t += 500; 303 if (val & READBACK_NEGATE) 304 t *= -1; 305 306 return t; 307} 308 309static int tegra_thermctl_get_temp(void *data, long *out_temp) 310{ 311 struct tegra_thermctl_zone *zone = data; 312 u32 val; 313 314 val = (readl(zone->reg) >> zone->shift) & SENSOR_TEMP_MASK; 315 *out_temp = translate_temp(val); 316 317 return 0; 318} 319 320static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = { 321 .get_temp = tegra_thermctl_get_temp, 322}; 323 324static const struct of_device_id tegra_soctherm_of_match[] = { 325 { .compatible = "nvidia,tegra124-soctherm" }, 326 { }, 327}; 328MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match); 329 330struct thermctl_zone_desc { 331 unsigned int offset; 332 unsigned int shift; 333}; 334 335static const struct thermctl_zone_desc t124_thermctl_temp_zones[] = { 336 { SENSOR_TEMP1, 16 }, 337 { SENSOR_TEMP2, 16 }, 338 { SENSOR_TEMP1, 0 }, 339 { SENSOR_TEMP2, 0 } 340}; 341 342static int tegra_soctherm_probe(struct platform_device *pdev) 343{ 344 struct tegra_soctherm *tegra; 345 struct thermal_zone_device *tz; 346 struct tsensor_shared_calibration shared_calib; 347 struct resource *res; 348 unsigned int i; 349 int err; 350 351 const struct tegra_tsensor *tsensors = t124_tsensors; 352 353 tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); 354 if (!tegra) 355 return -ENOMEM; 356 357 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 358 tegra->regs = devm_ioremap_resource(&pdev->dev, res); 359 if (IS_ERR(tegra->regs)) 360 return PTR_ERR(tegra->regs); 361 362 tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); 363 if (IS_ERR(tegra->reset)) { 364 dev_err(&pdev->dev, "can't get soctherm reset\n"); 365 return PTR_ERR(tegra->reset); 366 } 367 368 tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor"); 369 if (IS_ERR(tegra->clock_tsensor)) { 370 dev_err(&pdev->dev, "can't get tsensor clock\n"); 371 return PTR_ERR(tegra->clock_tsensor); 372 } 373 374 tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm"); 375 if (IS_ERR(tegra->clock_soctherm)) { 376 dev_err(&pdev->dev, "can't get soctherm clock\n"); 377 return PTR_ERR(tegra->clock_soctherm); 378 } 379 380 reset_control_assert(tegra->reset); 381 382 err = clk_prepare_enable(tegra->clock_soctherm); 383 if (err) 384 return err; 385 386 err = clk_prepare_enable(tegra->clock_tsensor); 387 if (err) { 388 clk_disable_unprepare(tegra->clock_soctherm); 389 return err; 390 } 391 392 reset_control_deassert(tegra->reset); 393 394 /* Initialize raw sensors */ 395 396 err = calculate_shared_calibration(&shared_calib); 397 if (err) 398 goto disable_clocks; 399 400 for (i = 0; i < ARRAY_SIZE(t124_tsensors); ++i) { 401 err = enable_tsensor(tegra, tsensors + i, &shared_calib); 402 if (err) 403 goto disable_clocks; 404 } 405 406 writel(SENSOR_PDIV_T124, tegra->regs + SENSOR_PDIV); 407 writel(SENSOR_HOTSPOT_OFF_T124, tegra->regs + SENSOR_HOTSPOT_OFF); 408 409 /* Initialize thermctl sensors */ 410 411 for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) { 412 struct tegra_thermctl_zone *zone = 413 devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL); 414 if (!zone) { 415 err = -ENOMEM; 416 goto unregister_tzs; 417 } 418 419 zone->reg = tegra->regs + t124_thermctl_temp_zones[i].offset; 420 zone->shift = t124_thermctl_temp_zones[i].shift; 421 422 tz = thermal_zone_of_sensor_register(&pdev->dev, i, zone, 423 &tegra_of_thermal_ops); 424 if (IS_ERR(tz)) { 425 err = PTR_ERR(tz); 426 dev_err(&pdev->dev, "failed to register sensor: %d\n", 427 err); 428 goto unregister_tzs; 429 } 430 431 tegra->thermctl_tzs[i] = tz; 432 } 433 434 return 0; 435 436unregister_tzs: 437 while (i--) 438 thermal_zone_of_sensor_unregister(&pdev->dev, 439 tegra->thermctl_tzs[i]); 440 441disable_clocks: 442 clk_disable_unprepare(tegra->clock_tsensor); 443 clk_disable_unprepare(tegra->clock_soctherm); 444 445 return err; 446} 447 448static int tegra_soctherm_remove(struct platform_device *pdev) 449{ 450 struct tegra_soctherm *tegra = platform_get_drvdata(pdev); 451 unsigned int i; 452 453 for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) { 454 thermal_zone_of_sensor_unregister(&pdev->dev, 455 tegra->thermctl_tzs[i]); 456 } 457 458 clk_disable_unprepare(tegra->clock_tsensor); 459 clk_disable_unprepare(tegra->clock_soctherm); 460 461 return 0; 462} 463 464static struct platform_driver tegra_soctherm_driver = { 465 .probe = tegra_soctherm_probe, 466 .remove = tegra_soctherm_remove, 467 .driver = { 468 .name = "tegra-soctherm", 469 .of_match_table = tegra_soctherm_of_match, 470 }, 471}; 472module_platform_driver(tegra_soctherm_driver); 473 474MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); 475MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver"); 476MODULE_LICENSE("GPL v2"); 477