hisi_thermal.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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 (-60)
  35. #define HISI_TEMP_RESET (100000)
  36. #define HISI_MAX_SENSORS 4
  37. struct hisi_thermal_sensor {
  38. struct hisi_thermal_data *thermal;
  39. struct thermal_zone_device *tzd;
  40. long sensor_temp;
  41. uint32_t id;
  42. uint32_t thres_temp;
  43. };
  44. struct hisi_thermal_data {
  45. struct mutex thermal_lock; /* protects register data */
  46. struct platform_device *pdev;
  47. struct clk *clk;
  48. struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];
  49. int irq, irq_bind_sensor;
  50. bool irq_enabled;
  51. void __iomem *regs;
  52. };
  53. /* in millicelsius */
  54. static inline int _step_to_temp(int step)
  55. {
  56. /*
  57. * Every step equals (1 * 200) / 255 celsius, and finally
  58. * need convert to millicelsius.
  59. */
  60. return (HISI_TEMP_BASE + (step * 200 / 255)) * 1000;
  61. }
  62. static inline long _temp_to_step(long temp)
  63. {
  64. return ((temp / 1000 - HISI_TEMP_BASE) * 255 / 200);
  65. }
  66. static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
  67. struct hisi_thermal_sensor *sensor)
  68. {
  69. long val;
  70. mutex_lock(&data->thermal_lock);
  71. /* disable interrupt */
  72. writel(0x0, data->regs + TEMP0_INT_EN);
  73. writel(0x1, data->regs + TEMP0_INT_CLR);
  74. /* disable module firstly */
  75. writel(0x0, data->regs + TEMP0_EN);
  76. /* select sensor id */
  77. writel((sensor->id << 12), data->regs + TEMP0_CFG);
  78. /* enable module */
  79. writel(0x1, data->regs + TEMP0_EN);
  80. usleep_range(3000, 5000);
  81. val = readl(data->regs + TEMP0_VALUE);
  82. val = _step_to_temp(val);
  83. mutex_unlock(&data->thermal_lock);
  84. return val;
  85. }
  86. static void hisi_thermal_enable_bind_irq_sensor
  87. (struct hisi_thermal_data *data)
  88. {
  89. struct hisi_thermal_sensor *sensor;
  90. mutex_lock(&data->thermal_lock);
  91. sensor = &data->sensors[data->irq_bind_sensor];
  92. /* setting the hdak time */
  93. writel(0x0, data->regs + TEMP0_CFG);
  94. /* disable module firstly */
  95. writel(0x0, data->regs + TEMP0_RST_MSK);
  96. writel(0x0, data->regs + TEMP0_EN);
  97. /* select sensor id */
  98. writel((sensor->id << 12), data->regs + TEMP0_CFG);
  99. /* enable for interrupt */
  100. writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,
  101. data->regs + TEMP0_TH);
  102. writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH);
  103. /* enable module */
  104. writel(0x1, data->regs + TEMP0_RST_MSK);
  105. writel(0x1, data->regs + TEMP0_EN);
  106. writel(0x0, data->regs + TEMP0_INT_CLR);
  107. writel(0x1, data->regs + TEMP0_INT_EN);
  108. usleep_range(3000, 5000);
  109. mutex_unlock(&data->thermal_lock);
  110. }
  111. static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)
  112. {
  113. mutex_lock(&data->thermal_lock);
  114. /* disable sensor module */
  115. writel(0x0, data->regs + TEMP0_INT_EN);
  116. writel(0x0, data->regs + TEMP0_RST_MSK);
  117. writel(0x0, data->regs + TEMP0_EN);
  118. mutex_unlock(&data->thermal_lock);
  119. }
  120. static int hisi_thermal_get_temp(void *_sensor, long *temp)
  121. {
  122. struct hisi_thermal_sensor *sensor = _sensor;
  123. struct hisi_thermal_data *data = sensor->thermal;
  124. int sensor_id = 0, i;
  125. long max_temp = 0;
  126. *temp = hisi_thermal_get_sensor_temp(data, sensor);
  127. sensor->sensor_temp = *temp;
  128. for (i = 0; i < HISI_MAX_SENSORS; i++) {
  129. if (data->sensors[i].sensor_temp >= max_temp) {
  130. max_temp = data->sensors[i].sensor_temp;
  131. sensor_id = i;
  132. }
  133. }
  134. mutex_lock(&data->thermal_lock);
  135. data->irq_bind_sensor = sensor_id;
  136. mutex_unlock(&data->thermal_lock);
  137. dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%ld, thres=%d\n",
  138. sensor->id, data->irq_enabled, *temp, sensor->thres_temp);
  139. /*
  140. * Bind irq to sensor for two cases:
  141. * Reenable alarm IRQ if temperature below threshold;
  142. * if irq has been enabled, always set it;
  143. */
  144. if (data->irq_enabled) {
  145. hisi_thermal_enable_bind_irq_sensor(data);
  146. return 0;
  147. }
  148. if (max_temp < sensor->thres_temp) {
  149. data->irq_enabled = true;
  150. hisi_thermal_enable_bind_irq_sensor(data);
  151. enable_irq(data->irq);
  152. }
  153. return 0;
  154. }
  155. static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
  156. .get_temp = hisi_thermal_get_temp,
  157. };
  158. static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
  159. {
  160. struct hisi_thermal_data *data = dev;
  161. disable_irq_nosync(irq);
  162. data->irq_enabled = false;
  163. return IRQ_WAKE_THREAD;
  164. }
  165. static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
  166. {
  167. struct hisi_thermal_data *data = dev;
  168. struct hisi_thermal_sensor *sensor;
  169. int i;
  170. mutex_lock(&data->thermal_lock);
  171. sensor = &data->sensors[data->irq_bind_sensor];
  172. dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
  173. sensor->thres_temp / 1000);
  174. mutex_unlock(&data->thermal_lock);
  175. for (i = 0; i < HISI_MAX_SENSORS; i++)
  176. thermal_zone_device_update(data->sensors[i].tzd);
  177. return IRQ_HANDLED;
  178. }
  179. static int hisi_thermal_register_sensor(struct platform_device *pdev,
  180. struct hisi_thermal_data *data,
  181. struct hisi_thermal_sensor *sensor,
  182. int index)
  183. {
  184. int ret, i;
  185. const struct thermal_trip *trip;
  186. sensor->id = index;
  187. sensor->thermal = data;
  188. sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, sensor->id,
  189. sensor, &hisi_of_thermal_ops);
  190. if (IS_ERR(sensor->tzd)) {
  191. ret = PTR_ERR(sensor->tzd);
  192. dev_err(&pdev->dev, "failed to register sensor id %d: %d\n",
  193. sensor->id, ret);
  194. return ret;
  195. }
  196. trip = of_thermal_get_trip_points(sensor->tzd);
  197. for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
  198. if (trip[i].type == THERMAL_TRIP_PASSIVE) {
  199. sensor->thres_temp = trip[i].temperature;
  200. break;
  201. }
  202. }
  203. return 0;
  204. }
  205. static const struct of_device_id of_hisi_thermal_match[] = {
  206. { .compatible = "hisilicon,tsensor" },
  207. { /* end */ }
  208. };
  209. MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
  210. static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
  211. bool on)
  212. {
  213. struct thermal_zone_device *tzd = sensor->tzd;
  214. tzd->ops->set_mode(tzd,
  215. on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
  216. }
  217. static int hisi_thermal_probe(struct platform_device *pdev)
  218. {
  219. struct hisi_thermal_data *data;
  220. struct resource *res;
  221. int i;
  222. int ret;
  223. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  224. if (!data)
  225. return -ENOMEM;
  226. mutex_init(&data->thermal_lock);
  227. data->pdev = pdev;
  228. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  229. data->regs = devm_ioremap_resource(&pdev->dev, res);
  230. if (IS_ERR(data->regs)) {
  231. dev_err(&pdev->dev, "failed to get io address\n");
  232. return PTR_ERR(data->regs);
  233. }
  234. data->irq = platform_get_irq(pdev, 0);
  235. if (data->irq < 0)
  236. return data->irq;
  237. ret = devm_request_threaded_irq(&pdev->dev, data->irq,
  238. hisi_thermal_alarm_irq,
  239. hisi_thermal_alarm_irq_thread,
  240. 0, "hisi_thermal", data);
  241. if (ret < 0) {
  242. dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
  243. return ret;
  244. }
  245. platform_set_drvdata(pdev, data);
  246. data->clk = devm_clk_get(&pdev->dev, "thermal_clk");
  247. if (IS_ERR(data->clk)) {
  248. ret = PTR_ERR(data->clk);
  249. if (ret != -EPROBE_DEFER)
  250. dev_err(&pdev->dev,
  251. "failed to get thermal clk: %d\n", ret);
  252. return ret;
  253. }
  254. /* enable clock for thermal */
  255. ret = clk_prepare_enable(data->clk);
  256. if (ret) {
  257. dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
  258. return ret;
  259. }
  260. for (i = 0; i < HISI_MAX_SENSORS; ++i) {
  261. ret = hisi_thermal_register_sensor(pdev, data,
  262. &data->sensors[i], i);
  263. if (ret) {
  264. dev_err(&pdev->dev,
  265. "failed to register thermal sensor: %d\n", ret);
  266. goto err_get_sensor_data;
  267. }
  268. }
  269. hisi_thermal_enable_bind_irq_sensor(data);
  270. data->irq_enabled = true;
  271. for (i = 0; i < HISI_MAX_SENSORS; i++)
  272. hisi_thermal_toggle_sensor(&data->sensors[i], true);
  273. return 0;
  274. err_get_sensor_data:
  275. clk_disable_unprepare(data->clk);
  276. return ret;
  277. }
  278. static int hisi_thermal_remove(struct platform_device *pdev)
  279. {
  280. struct hisi_thermal_data *data = platform_get_drvdata(pdev);
  281. int i;
  282. for (i = 0; i < HISI_MAX_SENSORS; i++) {
  283. struct hisi_thermal_sensor *sensor = &data->sensors[i];
  284. hisi_thermal_toggle_sensor(sensor, false);
  285. thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd);
  286. }
  287. hisi_thermal_disable_sensor(data);
  288. clk_disable_unprepare(data->clk);
  289. return 0;
  290. }
  291. #ifdef CONFIG_PM_SLEEP
  292. static int hisi_thermal_suspend(struct device *dev)
  293. {
  294. struct hisi_thermal_data *data = dev_get_drvdata(dev);
  295. hisi_thermal_disable_sensor(data);
  296. data->irq_enabled = false;
  297. clk_disable_unprepare(data->clk);
  298. return 0;
  299. }
  300. static int hisi_thermal_resume(struct device *dev)
  301. {
  302. struct hisi_thermal_data *data = dev_get_drvdata(dev);
  303. clk_prepare_enable(data->clk);
  304. data->irq_enabled = true;
  305. hisi_thermal_enable_bind_irq_sensor(data);
  306. return 0;
  307. }
  308. #endif
  309. static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
  310. hisi_thermal_suspend, hisi_thermal_resume);
  311. static struct platform_driver hisi_thermal_driver = {
  312. .driver = {
  313. .name = "hisi_thermal",
  314. .owner = THIS_MODULE,
  315. .pm = &hisi_thermal_pm_ops,
  316. .of_match_table = of_hisi_thermal_match,
  317. },
  318. .probe = hisi_thermal_probe,
  319. .remove = hisi_thermal_remove,
  320. };
  321. module_platform_driver(hisi_thermal_driver);
  322. MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
  323. MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
  324. MODULE_DESCRIPTION("Hisilicon thermal driver");
  325. MODULE_LICENSE("GPL v2");