tegra_soctherm.c 12 KB

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