hisi_thermal.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*
  2. * Hisilicon thermal sensor driver
  3. *
  4. * Copyright (c) 2014-2015 Hisilicon Limited.
  5. * Copyright (c) 2014-2015 Linaro Limited.
  6. *
  7. * Xinwei Kong <kong.kongxinwei@hisilicon.com>
  8. * Leo Yan <leo.yan@linaro.org>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. *
  14. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  15. * kind, whether express or implied; without even the implied warranty
  16. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. */
  19. #include <linux/cpufreq.h>
  20. #include <linux/delay.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/module.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/io.h>
  25. #include "thermal_core.h"
  26. #define TEMP0_TH (0x4)
  27. #define TEMP0_RST_TH (0x8)
  28. #define TEMP0_CFG (0xC)
  29. #define TEMP0_EN (0x10)
  30. #define TEMP0_INT_EN (0x14)
  31. #define TEMP0_INT_CLR (0x18)
  32. #define TEMP0_RST_MSK (0x1C)
  33. #define TEMP0_VALUE (0x28)
  34. #define HISI_TEMP_BASE (-60000)
  35. #define HISI_TEMP_RESET (100000)
  36. #define HISI_TEMP_STEP (784)
  37. #define HISI_MAX_SENSORS 4
  38. struct hisi_thermal_sensor {
  39. struct hisi_thermal_data *thermal;
  40. struct thermal_zone_device *tzd;
  41. long sensor_temp;
  42. uint32_t id;
  43. uint32_t thres_temp;
  44. };
  45. struct hisi_thermal_data {
  46. struct mutex thermal_lock; /* protects register data */
  47. struct platform_device *pdev;
  48. struct clk *clk;
  49. struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];
  50. int irq, irq_bind_sensor;
  51. bool irq_enabled;
  52. void __iomem *regs;
  53. };
  54. /*
  55. * The temperature computation on the tsensor is as follow:
  56. * Unit: millidegree Celsius
  57. * Step: 255/200 (0.7843)
  58. * Temperature base: -60°C
  59. *
  60. * The register is programmed in temperature steps, every step is 784
  61. * millidegree and begins at -60 000 m°C
  62. *
  63. * The temperature from the steps:
  64. *
  65. * Temp = TempBase + (steps x 784)
  66. *
  67. * and the steps from the temperature:
  68. *
  69. * steps = (Temp - TempBase) / 784
  70. *
  71. */
  72. static inline int hisi_thermal_step_to_temp(int step)
  73. {
  74. return HISI_TEMP_BASE + (step * HISI_TEMP_STEP);
  75. }
  76. static inline long hisi_thermal_temp_to_step(long temp)
  77. {
  78. return (temp - HISI_TEMP_BASE) / HISI_TEMP_STEP;
  79. }
  80. static inline long hisi_thermal_round_temp(int temp)
  81. {
  82. return hisi_thermal_step_to_temp(
  83. hisi_thermal_temp_to_step(temp));
  84. }
  85. static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
  86. struct hisi_thermal_sensor *sensor)
  87. {
  88. long val;
  89. mutex_lock(&data->thermal_lock);
  90. /* disable interrupt */
  91. writel(0x0, data->regs + TEMP0_INT_EN);
  92. writel(0x1, data->regs + TEMP0_INT_CLR);
  93. /* disable module firstly */
  94. writel(0x0, data->regs + TEMP0_EN);
  95. /* select sensor id */
  96. writel((sensor->id << 12), data->regs + TEMP0_CFG);
  97. /* enable module */
  98. writel(0x1, data->regs + TEMP0_EN);
  99. usleep_range(3000, 5000);
  100. val = readl(data->regs + TEMP0_VALUE);
  101. val = hisi_thermal_step_to_temp(val);
  102. mutex_unlock(&data->thermal_lock);
  103. return val;
  104. }
  105. static void hisi_thermal_enable_bind_irq_sensor
  106. (struct hisi_thermal_data *data)
  107. {
  108. struct hisi_thermal_sensor *sensor;
  109. mutex_lock(&data->thermal_lock);
  110. sensor = &data->sensors[data->irq_bind_sensor];
  111. /* setting the hdak time */
  112. writel(0x0, data->regs + TEMP0_CFG);
  113. /* disable module firstly */
  114. writel(0x0, data->regs + TEMP0_RST_MSK);
  115. writel(0x0, data->regs + TEMP0_EN);
  116. /* select sensor id */
  117. writel((sensor->id << 12), data->regs + TEMP0_CFG);
  118. /* enable for interrupt */
  119. writel(hisi_thermal_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,
  120. data->regs + TEMP0_TH);
  121. writel(hisi_thermal_temp_to_step(HISI_TEMP_RESET),
  122. data->regs + TEMP0_RST_TH);
  123. /* enable module */
  124. writel(0x1, data->regs + TEMP0_RST_MSK);
  125. writel(0x1, data->regs + TEMP0_EN);
  126. writel(0x0, data->regs + TEMP0_INT_CLR);
  127. writel(0x1, data->regs + TEMP0_INT_EN);
  128. usleep_range(3000, 5000);
  129. mutex_unlock(&data->thermal_lock);
  130. }
  131. static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)
  132. {
  133. mutex_lock(&data->thermal_lock);
  134. /* disable sensor module */
  135. writel(0x0, data->regs + TEMP0_INT_EN);
  136. writel(0x0, data->regs + TEMP0_RST_MSK);
  137. writel(0x0, data->regs + TEMP0_EN);
  138. mutex_unlock(&data->thermal_lock);
  139. }
  140. static int hisi_thermal_get_temp(void *_sensor, int *temp)
  141. {
  142. struct hisi_thermal_sensor *sensor = _sensor;
  143. struct hisi_thermal_data *data = sensor->thermal;
  144. int sensor_id = -1, i;
  145. long max_temp = 0;
  146. *temp = hisi_thermal_get_sensor_temp(data, sensor);
  147. sensor->sensor_temp = *temp;
  148. for (i = 0; i < HISI_MAX_SENSORS; i++) {
  149. if (!data->sensors[i].tzd)
  150. continue;
  151. if (data->sensors[i].sensor_temp >= max_temp) {
  152. max_temp = data->sensors[i].sensor_temp;
  153. sensor_id = i;
  154. }
  155. }
  156. /* If no sensor has been enabled, then skip to enable irq */
  157. if (sensor_id == -1)
  158. return 0;
  159. mutex_lock(&data->thermal_lock);
  160. data->irq_bind_sensor = sensor_id;
  161. mutex_unlock(&data->thermal_lock);
  162. dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%d, thres=%d\n",
  163. sensor->id, data->irq_enabled, *temp, sensor->thres_temp);
  164. /*
  165. * Bind irq to sensor for two cases:
  166. * Reenable alarm IRQ if temperature below threshold;
  167. * if irq has been enabled, always set it;
  168. */
  169. if (data->irq_enabled) {
  170. hisi_thermal_enable_bind_irq_sensor(data);
  171. return 0;
  172. }
  173. if (max_temp < sensor->thres_temp) {
  174. data->irq_enabled = true;
  175. hisi_thermal_enable_bind_irq_sensor(data);
  176. enable_irq(data->irq);
  177. }
  178. return 0;
  179. }
  180. static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
  181. .get_temp = hisi_thermal_get_temp,
  182. };
  183. static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
  184. {
  185. struct hisi_thermal_data *data = dev;
  186. disable_irq_nosync(irq);
  187. data->irq_enabled = false;
  188. return IRQ_WAKE_THREAD;
  189. }
  190. static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
  191. {
  192. struct hisi_thermal_data *data = dev;
  193. struct hisi_thermal_sensor *sensor;
  194. int i;
  195. mutex_lock(&data->thermal_lock);
  196. sensor = &data->sensors[data->irq_bind_sensor];
  197. dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
  198. sensor->thres_temp);
  199. mutex_unlock(&data->thermal_lock);
  200. for (i = 0; i < HISI_MAX_SENSORS; i++) {
  201. if (!data->sensors[i].tzd)
  202. continue;
  203. thermal_zone_device_update(data->sensors[i].tzd,
  204. THERMAL_EVENT_UNSPECIFIED);
  205. }
  206. return IRQ_HANDLED;
  207. }
  208. static int hisi_thermal_register_sensor(struct platform_device *pdev,
  209. struct hisi_thermal_data *data,
  210. struct hisi_thermal_sensor *sensor,
  211. int index)
  212. {
  213. int ret, i;
  214. const struct thermal_trip *trip;
  215. sensor->id = index;
  216. sensor->thermal = data;
  217. sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
  218. sensor->id, sensor, &hisi_of_thermal_ops);
  219. if (IS_ERR(sensor->tzd)) {
  220. ret = PTR_ERR(sensor->tzd);
  221. sensor->tzd = NULL;
  222. dev_err(&pdev->dev, "failed to register sensor id %d: %d\n",
  223. sensor->id, ret);
  224. return ret;
  225. }
  226. trip = of_thermal_get_trip_points(sensor->tzd);
  227. for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
  228. if (trip[i].type == THERMAL_TRIP_PASSIVE) {
  229. sensor->thres_temp = hisi_thermal_round_temp(trip[i].temperature);
  230. break;
  231. }
  232. }
  233. return 0;
  234. }
  235. static const struct of_device_id of_hisi_thermal_match[] = {
  236. { .compatible = "hisilicon,tsensor" },
  237. { /* end */ }
  238. };
  239. MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
  240. static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
  241. bool on)
  242. {
  243. struct thermal_zone_device *tzd = sensor->tzd;
  244. tzd->ops->set_mode(tzd,
  245. on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
  246. }
  247. static int hisi_thermal_probe(struct platform_device *pdev)
  248. {
  249. struct hisi_thermal_data *data;
  250. struct resource *res;
  251. int i;
  252. int ret;
  253. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  254. if (!data)
  255. return -ENOMEM;
  256. mutex_init(&data->thermal_lock);
  257. data->pdev = pdev;
  258. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  259. data->regs = devm_ioremap_resource(&pdev->dev, res);
  260. if (IS_ERR(data->regs)) {
  261. dev_err(&pdev->dev, "failed to get io address\n");
  262. return PTR_ERR(data->regs);
  263. }
  264. data->irq = platform_get_irq(pdev, 0);
  265. if (data->irq < 0)
  266. return data->irq;
  267. platform_set_drvdata(pdev, data);
  268. data->clk = devm_clk_get(&pdev->dev, "thermal_clk");
  269. if (IS_ERR(data->clk)) {
  270. ret = PTR_ERR(data->clk);
  271. if (ret != -EPROBE_DEFER)
  272. dev_err(&pdev->dev,
  273. "failed to get thermal clk: %d\n", ret);
  274. return ret;
  275. }
  276. /* enable clock for thermal */
  277. ret = clk_prepare_enable(data->clk);
  278. if (ret) {
  279. dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
  280. return ret;
  281. }
  282. hisi_thermal_enable_bind_irq_sensor(data);
  283. data->irq_enabled = true;
  284. for (i = 0; i < HISI_MAX_SENSORS; ++i) {
  285. ret = hisi_thermal_register_sensor(pdev, data,
  286. &data->sensors[i], i);
  287. if (ret)
  288. dev_err(&pdev->dev,
  289. "failed to register thermal sensor: %d\n", ret);
  290. else
  291. hisi_thermal_toggle_sensor(&data->sensors[i], true);
  292. }
  293. ret = devm_request_threaded_irq(&pdev->dev, data->irq,
  294. hisi_thermal_alarm_irq,
  295. hisi_thermal_alarm_irq_thread,
  296. 0, "hisi_thermal", data);
  297. if (ret < 0) {
  298. dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
  299. return ret;
  300. }
  301. enable_irq(data->irq);
  302. return 0;
  303. }
  304. static int hisi_thermal_remove(struct platform_device *pdev)
  305. {
  306. struct hisi_thermal_data *data = platform_get_drvdata(pdev);
  307. int i;
  308. for (i = 0; i < HISI_MAX_SENSORS; i++) {
  309. struct hisi_thermal_sensor *sensor = &data->sensors[i];
  310. if (!sensor->tzd)
  311. continue;
  312. hisi_thermal_toggle_sensor(sensor, false);
  313. }
  314. hisi_thermal_disable_sensor(data);
  315. clk_disable_unprepare(data->clk);
  316. return 0;
  317. }
  318. #ifdef CONFIG_PM_SLEEP
  319. static int hisi_thermal_suspend(struct device *dev)
  320. {
  321. struct hisi_thermal_data *data = dev_get_drvdata(dev);
  322. hisi_thermal_disable_sensor(data);
  323. data->irq_enabled = false;
  324. clk_disable_unprepare(data->clk);
  325. return 0;
  326. }
  327. static int hisi_thermal_resume(struct device *dev)
  328. {
  329. struct hisi_thermal_data *data = dev_get_drvdata(dev);
  330. int ret;
  331. ret = clk_prepare_enable(data->clk);
  332. if (ret)
  333. return ret;
  334. data->irq_enabled = true;
  335. hisi_thermal_enable_bind_irq_sensor(data);
  336. return 0;
  337. }
  338. #endif
  339. static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
  340. hisi_thermal_suspend, hisi_thermal_resume);
  341. static struct platform_driver hisi_thermal_driver = {
  342. .driver = {
  343. .name = "hisi_thermal",
  344. .pm = &hisi_thermal_pm_ops,
  345. .of_match_table = of_hisi_thermal_match,
  346. },
  347. .probe = hisi_thermal_probe,
  348. .remove = hisi_thermal_remove,
  349. };
  350. module_platform_driver(hisi_thermal_driver);
  351. MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
  352. MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
  353. MODULE_DESCRIPTION("Hisilicon thermal driver");
  354. MODULE_LICENSE("GPL v2");