imx_thermal.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. * Copyright 2013 Freescale Semiconductor, Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. */
  9. #include <linux/cpu_cooling.h>
  10. #include <linux/cpufreq.h>
  11. #include <linux/delay.h>
  12. #include <linux/device.h>
  13. #include <linux/init.h>
  14. #include <linux/io.h>
  15. #include <linux/kernel.h>
  16. #include <linux/mfd/syscon.h>
  17. #include <linux/module.h>
  18. #include <linux/of.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/regmap.h>
  21. #include <linux/slab.h>
  22. #include <linux/thermal.h>
  23. #include <linux/types.h>
  24. #define REG_SET 0x4
  25. #define REG_CLR 0x8
  26. #define REG_TOG 0xc
  27. #define MISC0 0x0150
  28. #define MISC0_REFTOP_SELBIASOFF (1 << 3)
  29. #define TEMPSENSE0 0x0180
  30. #define TEMPSENSE0_TEMP_CNT_SHIFT 8
  31. #define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
  32. #define TEMPSENSE0_FINISHED (1 << 2)
  33. #define TEMPSENSE0_MEASURE_TEMP (1 << 1)
  34. #define TEMPSENSE0_POWER_DOWN (1 << 0)
  35. #define TEMPSENSE1 0x0190
  36. #define TEMPSENSE1_MEASURE_FREQ 0xffff
  37. #define OCOTP_ANA1 0x04e0
  38. /* The driver supports 1 passive trip point and 1 critical trip point */
  39. enum imx_thermal_trip {
  40. IMX_TRIP_PASSIVE,
  41. IMX_TRIP_CRITICAL,
  42. IMX_TRIP_NUM,
  43. };
  44. /*
  45. * It defines the temperature in millicelsius for passive trip point
  46. * that will trigger cooling action when crossed.
  47. */
  48. #define IMX_TEMP_PASSIVE 85000
  49. #define IMX_POLLING_DELAY 2000 /* millisecond */
  50. #define IMX_PASSIVE_DELAY 1000
  51. struct imx_thermal_data {
  52. struct thermal_zone_device *tz;
  53. struct thermal_cooling_device *cdev;
  54. enum thermal_device_mode mode;
  55. struct regmap *tempmon;
  56. int c1, c2; /* See formula in imx_get_sensor_data() */
  57. unsigned long temp_passive;
  58. unsigned long temp_critical;
  59. };
  60. static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
  61. {
  62. struct imx_thermal_data *data = tz->devdata;
  63. struct regmap *map = data->tempmon;
  64. static unsigned long last_temp;
  65. unsigned int n_meas;
  66. u32 val;
  67. /*
  68. * Every time we measure the temperature, we will power on the
  69. * temperature sensor, enable measurements, take a reading,
  70. * disable measurements, power off the temperature sensor.
  71. */
  72. regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
  73. regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
  74. /*
  75. * According to the temp sensor designers, it may require up to ~17us
  76. * to complete a measurement.
  77. */
  78. usleep_range(20, 50);
  79. regmap_read(map, TEMPSENSE0, &val);
  80. regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
  81. regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
  82. if ((val & TEMPSENSE0_FINISHED) == 0) {
  83. dev_dbg(&tz->device, "temp measurement never finished\n");
  84. return -EAGAIN;
  85. }
  86. n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
  87. /* See imx_get_sensor_data() for formula derivation */
  88. *temp = data->c2 + data->c1 * n_meas;
  89. if (*temp != last_temp) {
  90. dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
  91. last_temp = *temp;
  92. }
  93. return 0;
  94. }
  95. static int imx_get_mode(struct thermal_zone_device *tz,
  96. enum thermal_device_mode *mode)
  97. {
  98. struct imx_thermal_data *data = tz->devdata;
  99. *mode = data->mode;
  100. return 0;
  101. }
  102. static int imx_set_mode(struct thermal_zone_device *tz,
  103. enum thermal_device_mode mode)
  104. {
  105. struct imx_thermal_data *data = tz->devdata;
  106. if (mode == THERMAL_DEVICE_ENABLED) {
  107. tz->polling_delay = IMX_POLLING_DELAY;
  108. tz->passive_delay = IMX_PASSIVE_DELAY;
  109. } else {
  110. tz->polling_delay = 0;
  111. tz->passive_delay = 0;
  112. }
  113. data->mode = mode;
  114. thermal_zone_device_update(tz);
  115. return 0;
  116. }
  117. static int imx_get_trip_type(struct thermal_zone_device *tz, int trip,
  118. enum thermal_trip_type *type)
  119. {
  120. *type = (trip == IMX_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
  121. THERMAL_TRIP_CRITICAL;
  122. return 0;
  123. }
  124. static int imx_get_crit_temp(struct thermal_zone_device *tz,
  125. unsigned long *temp)
  126. {
  127. struct imx_thermal_data *data = tz->devdata;
  128. *temp = data->temp_critical;
  129. return 0;
  130. }
  131. static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
  132. unsigned long *temp)
  133. {
  134. struct imx_thermal_data *data = tz->devdata;
  135. *temp = (trip == IMX_TRIP_PASSIVE) ? data->temp_passive :
  136. data->temp_critical;
  137. return 0;
  138. }
  139. static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
  140. unsigned long temp)
  141. {
  142. struct imx_thermal_data *data = tz->devdata;
  143. if (trip == IMX_TRIP_CRITICAL)
  144. return -EPERM;
  145. if (temp > IMX_TEMP_PASSIVE)
  146. return -EINVAL;
  147. data->temp_passive = temp;
  148. return 0;
  149. }
  150. static int imx_bind(struct thermal_zone_device *tz,
  151. struct thermal_cooling_device *cdev)
  152. {
  153. int ret;
  154. ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,
  155. THERMAL_NO_LIMIT,
  156. THERMAL_NO_LIMIT);
  157. if (ret) {
  158. dev_err(&tz->device,
  159. "binding zone %s with cdev %s failed:%d\n",
  160. tz->type, cdev->type, ret);
  161. return ret;
  162. }
  163. return 0;
  164. }
  165. static int imx_unbind(struct thermal_zone_device *tz,
  166. struct thermal_cooling_device *cdev)
  167. {
  168. int ret;
  169. ret = thermal_zone_unbind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev);
  170. if (ret) {
  171. dev_err(&tz->device,
  172. "unbinding zone %s with cdev %s failed:%d\n",
  173. tz->type, cdev->type, ret);
  174. return ret;
  175. }
  176. return 0;
  177. }
  178. static const struct thermal_zone_device_ops imx_tz_ops = {
  179. .bind = imx_bind,
  180. .unbind = imx_unbind,
  181. .get_temp = imx_get_temp,
  182. .get_mode = imx_get_mode,
  183. .set_mode = imx_set_mode,
  184. .get_trip_type = imx_get_trip_type,
  185. .get_trip_temp = imx_get_trip_temp,
  186. .get_crit_temp = imx_get_crit_temp,
  187. .set_trip_temp = imx_set_trip_temp,
  188. };
  189. static int imx_get_sensor_data(struct platform_device *pdev)
  190. {
  191. struct imx_thermal_data *data = platform_get_drvdata(pdev);
  192. struct regmap *map;
  193. int t1, t2, n1, n2;
  194. int ret;
  195. u32 val;
  196. map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
  197. "fsl,tempmon-data");
  198. if (IS_ERR(map)) {
  199. ret = PTR_ERR(map);
  200. dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
  201. return ret;
  202. }
  203. ret = regmap_read(map, OCOTP_ANA1, &val);
  204. if (ret) {
  205. dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
  206. return ret;
  207. }
  208. if (val == 0 || val == ~0) {
  209. dev_err(&pdev->dev, "invalid sensor calibration data\n");
  210. return -EINVAL;
  211. }
  212. /*
  213. * Sensor data layout:
  214. * [31:20] - sensor value @ 25C
  215. * [19:8] - sensor value of hot
  216. * [7:0] - hot temperature value
  217. */
  218. n1 = val >> 20;
  219. n2 = (val & 0xfff00) >> 8;
  220. t2 = val & 0xff;
  221. t1 = 25; /* t1 always 25C */
  222. /*
  223. * Derived from linear interpolation,
  224. * Tmeas = T2 + (Nmeas - N2) * (T1 - T2) / (N1 - N2)
  225. * We want to reduce this down to the minimum computation necessary
  226. * for each temperature read. Also, we want Tmeas in millicelsius
  227. * and we don't want to lose precision from integer division. So...
  228. * milli_Tmeas = 1000 * T2 + 1000 * (Nmeas - N2) * (T1 - T2) / (N1 - N2)
  229. * Let constant c1 = 1000 * (T1 - T2) / (N1 - N2)
  230. * milli_Tmeas = (1000 * T2) + c1 * (Nmeas - N2)
  231. * milli_Tmeas = (1000 * T2) + (c1 * Nmeas) - (c1 * N2)
  232. * Let constant c2 = (1000 * T2) - (c1 * N2)
  233. * milli_Tmeas = c2 + (c1 * Nmeas)
  234. */
  235. data->c1 = 1000 * (t1 - t2) / (n1 - n2);
  236. data->c2 = 1000 * t2 - data->c1 * n2;
  237. /*
  238. * Set the default passive cooling trip point to 20 °C below the
  239. * maximum die temperature. Can be changed from userspace.
  240. */
  241. data->temp_passive = 1000 * (t2 - 20);
  242. /*
  243. * The maximum die temperature is t2, let's give 5 °C cushion
  244. * for noise and possible temperature rise between measurements.
  245. */
  246. data->temp_critical = 1000 * (t2 - 5);
  247. return 0;
  248. }
  249. static int imx_thermal_probe(struct platform_device *pdev)
  250. {
  251. struct imx_thermal_data *data;
  252. struct cpumask clip_cpus;
  253. struct regmap *map;
  254. int ret;
  255. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  256. if (!data)
  257. return -ENOMEM;
  258. map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
  259. if (IS_ERR(map)) {
  260. ret = PTR_ERR(map);
  261. dev_err(&pdev->dev, "failed to get tempmon regmap: %d\n", ret);
  262. return ret;
  263. }
  264. data->tempmon = map;
  265. platform_set_drvdata(pdev, data);
  266. ret = imx_get_sensor_data(pdev);
  267. if (ret) {
  268. dev_err(&pdev->dev, "failed to get sensor data\n");
  269. return ret;
  270. }
  271. /* Make sure sensor is in known good state for measurements */
  272. regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
  273. regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
  274. regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
  275. regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
  276. regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
  277. cpumask_set_cpu(0, &clip_cpus);
  278. data->cdev = cpufreq_cooling_register(&clip_cpus);
  279. if (IS_ERR(data->cdev)) {
  280. ret = PTR_ERR(data->cdev);
  281. dev_err(&pdev->dev,
  282. "failed to register cpufreq cooling device: %d\n", ret);
  283. return ret;
  284. }
  285. data->tz = thermal_zone_device_register("imx_thermal_zone",
  286. IMX_TRIP_NUM,
  287. BIT(IMX_TRIP_PASSIVE), data,
  288. &imx_tz_ops, NULL,
  289. IMX_PASSIVE_DELAY,
  290. IMX_POLLING_DELAY);
  291. if (IS_ERR(data->tz)) {
  292. ret = PTR_ERR(data->tz);
  293. dev_err(&pdev->dev,
  294. "failed to register thermal zone device %d\n", ret);
  295. cpufreq_cooling_unregister(data->cdev);
  296. return ret;
  297. }
  298. data->mode = THERMAL_DEVICE_ENABLED;
  299. return 0;
  300. }
  301. static int imx_thermal_remove(struct platform_device *pdev)
  302. {
  303. struct imx_thermal_data *data = platform_get_drvdata(pdev);
  304. thermal_zone_device_unregister(data->tz);
  305. cpufreq_cooling_unregister(data->cdev);
  306. return 0;
  307. }
  308. #ifdef CONFIG_PM_SLEEP
  309. static int imx_thermal_suspend(struct device *dev)
  310. {
  311. struct imx_thermal_data *data = dev_get_drvdata(dev);
  312. struct regmap *map = data->tempmon;
  313. u32 val;
  314. regmap_read(map, TEMPSENSE0, &val);
  315. if ((val & TEMPSENSE0_POWER_DOWN) == 0) {
  316. /*
  317. * If a measurement is taking place, wait for a long enough
  318. * time for it to finish, and then check again. If it still
  319. * does not finish, something must go wrong.
  320. */
  321. udelay(50);
  322. regmap_read(map, TEMPSENSE0, &val);
  323. if ((val & TEMPSENSE0_POWER_DOWN) == 0)
  324. return -ETIMEDOUT;
  325. }
  326. return 0;
  327. }
  328. static int imx_thermal_resume(struct device *dev)
  329. {
  330. /* Nothing to do for now */
  331. return 0;
  332. }
  333. #endif
  334. static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
  335. imx_thermal_suspend, imx_thermal_resume);
  336. static const struct of_device_id of_imx_thermal_match[] = {
  337. { .compatible = "fsl,imx6q-tempmon", },
  338. { /* end */ }
  339. };
  340. static struct platform_driver imx_thermal = {
  341. .driver = {
  342. .name = "imx_thermal",
  343. .owner = THIS_MODULE,
  344. .pm = &imx_thermal_pm_ops,
  345. .of_match_table = of_imx_thermal_match,
  346. },
  347. .probe = imx_thermal_probe,
  348. .remove = imx_thermal_remove,
  349. };
  350. module_platform_driver(imx_thermal);
  351. MODULE_AUTHOR("Freescale Semiconductor, Inc.");
  352. MODULE_DESCRIPTION("Thermal driver for Freescale i.MX SoCs");
  353. MODULE_LICENSE("GPL v2");
  354. MODULE_ALIAS("platform:imx-thermal");