hisi_thermal.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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 * 1000 + (step * 200000 / 255));
  61. }
  62. static inline long _temp_to_step(long temp)
  63. {
  64. return ((temp - HISI_TEMP_BASE * 1000) * 255) / 200000;
  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, int *temp)
  121. {
  122. struct hisi_thermal_sensor *sensor = _sensor;
  123. struct hisi_thermal_data *data = sensor->thermal;
  124. int sensor_id = -1, 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].tzd)
  130. continue;
  131. if (data->sensors[i].sensor_temp >= max_temp) {
  132. max_temp = data->sensors[i].sensor_temp;
  133. sensor_id = i;
  134. }
  135. }
  136. /* If no sensor has been enabled, then skip to enable irq */
  137. if (sensor_id == -1)
  138. return 0;
  139. mutex_lock(&data->thermal_lock);
  140. data->irq_bind_sensor = sensor_id;
  141. mutex_unlock(&data->thermal_lock);
  142. dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%d, thres=%d\n",
  143. sensor->id, data->irq_enabled, *temp, sensor->thres_temp);
  144. /*
  145. * Bind irq to sensor for two cases:
  146. * Reenable alarm IRQ if temperature below threshold;
  147. * if irq has been enabled, always set it;
  148. */
  149. if (data->irq_enabled) {
  150. hisi_thermal_enable_bind_irq_sensor(data);
  151. return 0;
  152. }
  153. if (max_temp < sensor->thres_temp) {
  154. data->irq_enabled = true;
  155. hisi_thermal_enable_bind_irq_sensor(data);
  156. enable_irq(data->irq);
  157. }
  158. return 0;
  159. }
  160. static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
  161. .get_temp = hisi_thermal_get_temp,
  162. };
  163. static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
  164. {
  165. struct hisi_thermal_data *data = dev;
  166. disable_irq_nosync(irq);
  167. data->irq_enabled = false;
  168. return IRQ_WAKE_THREAD;
  169. }
  170. static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
  171. {
  172. struct hisi_thermal_data *data = dev;
  173. struct hisi_thermal_sensor *sensor;
  174. int i;
  175. mutex_lock(&data->thermal_lock);
  176. sensor = &data->sensors[data->irq_bind_sensor];
  177. dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
  178. sensor->thres_temp / 1000);
  179. mutex_unlock(&data->thermal_lock);
  180. for (i = 0; i < HISI_MAX_SENSORS; i++) {
  181. if (!data->sensors[i].tzd)
  182. continue;
  183. thermal_zone_device_update(data->sensors[i].tzd,
  184. THERMAL_EVENT_UNSPECIFIED);
  185. }
  186. return IRQ_HANDLED;
  187. }
  188. static int hisi_thermal_register_sensor(struct platform_device *pdev,
  189. struct hisi_thermal_data *data,
  190. struct hisi_thermal_sensor *sensor,
  191. int index)
  192. {
  193. int ret, i;
  194. const struct thermal_trip *trip;
  195. sensor->id = index;
  196. sensor->thermal = data;
  197. sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
  198. sensor->id, sensor, &hisi_of_thermal_ops);
  199. if (IS_ERR(sensor->tzd)) {
  200. ret = PTR_ERR(sensor->tzd);
  201. sensor->tzd = NULL;
  202. dev_err(&pdev->dev, "failed to register sensor id %d: %d\n",
  203. sensor->id, ret);
  204. return ret;
  205. }
  206. trip = of_thermal_get_trip_points(sensor->tzd);
  207. for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
  208. if (trip[i].type == THERMAL_TRIP_PASSIVE) {
  209. sensor->thres_temp = trip[i].temperature;
  210. break;
  211. }
  212. }
  213. return 0;
  214. }
  215. static const struct of_device_id of_hisi_thermal_match[] = {
  216. { .compatible = "hisilicon,tsensor" },
  217. { /* end */ }
  218. };
  219. MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
  220. static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
  221. bool on)
  222. {
  223. struct thermal_zone_device *tzd = sensor->tzd;
  224. tzd->ops->set_mode(tzd,
  225. on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
  226. }
  227. static int hisi_thermal_probe(struct platform_device *pdev)
  228. {
  229. struct hisi_thermal_data *data;
  230. struct resource *res;
  231. int i;
  232. int ret;
  233. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  234. if (!data)
  235. return -ENOMEM;
  236. mutex_init(&data->thermal_lock);
  237. data->pdev = pdev;
  238. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  239. data->regs = devm_ioremap_resource(&pdev->dev, res);
  240. if (IS_ERR(data->regs)) {
  241. dev_err(&pdev->dev, "failed to get io address\n");
  242. return PTR_ERR(data->regs);
  243. }
  244. data->irq = platform_get_irq(pdev, 0);
  245. if (data->irq < 0)
  246. return data->irq;
  247. ret = devm_request_threaded_irq(&pdev->dev, data->irq,
  248. hisi_thermal_alarm_irq,
  249. hisi_thermal_alarm_irq_thread,
  250. 0, "hisi_thermal", data);
  251. if (ret < 0) {
  252. dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
  253. return ret;
  254. }
  255. platform_set_drvdata(pdev, data);
  256. data->clk = devm_clk_get(&pdev->dev, "thermal_clk");
  257. if (IS_ERR(data->clk)) {
  258. ret = PTR_ERR(data->clk);
  259. if (ret != -EPROBE_DEFER)
  260. dev_err(&pdev->dev,
  261. "failed to get thermal clk: %d\n", ret);
  262. return ret;
  263. }
  264. /* enable clock for thermal */
  265. ret = clk_prepare_enable(data->clk);
  266. if (ret) {
  267. dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
  268. return ret;
  269. }
  270. hisi_thermal_enable_bind_irq_sensor(data);
  271. irq_get_irqchip_state(data->irq, IRQCHIP_STATE_MASKED,
  272. &data->irq_enabled);
  273. for (i = 0; i < HISI_MAX_SENSORS; ++i) {
  274. ret = hisi_thermal_register_sensor(pdev, data,
  275. &data->sensors[i], i);
  276. if (ret)
  277. dev_err(&pdev->dev,
  278. "failed to register thermal sensor: %d\n", ret);
  279. else
  280. hisi_thermal_toggle_sensor(&data->sensors[i], true);
  281. }
  282. return 0;
  283. }
  284. static int hisi_thermal_remove(struct platform_device *pdev)
  285. {
  286. struct hisi_thermal_data *data = platform_get_drvdata(pdev);
  287. int i;
  288. for (i = 0; i < HISI_MAX_SENSORS; i++) {
  289. struct hisi_thermal_sensor *sensor = &data->sensors[i];
  290. if (!sensor->tzd)
  291. continue;
  292. hisi_thermal_toggle_sensor(sensor, false);
  293. }
  294. hisi_thermal_disable_sensor(data);
  295. clk_disable_unprepare(data->clk);
  296. return 0;
  297. }
  298. #ifdef CONFIG_PM_SLEEP
  299. static int hisi_thermal_suspend(struct device *dev)
  300. {
  301. struct hisi_thermal_data *data = dev_get_drvdata(dev);
  302. hisi_thermal_disable_sensor(data);
  303. data->irq_enabled = false;
  304. clk_disable_unprepare(data->clk);
  305. return 0;
  306. }
  307. static int hisi_thermal_resume(struct device *dev)
  308. {
  309. struct hisi_thermal_data *data = dev_get_drvdata(dev);
  310. clk_prepare_enable(data->clk);
  311. data->irq_enabled = true;
  312. hisi_thermal_enable_bind_irq_sensor(data);
  313. return 0;
  314. }
  315. #endif
  316. static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
  317. hisi_thermal_suspend, hisi_thermal_resume);
  318. static struct platform_driver hisi_thermal_driver = {
  319. .driver = {
  320. .name = "hisi_thermal",
  321. .pm = &hisi_thermal_pm_ops,
  322. .of_match_table = of_hisi_thermal_match,
  323. },
  324. .probe = hisi_thermal_probe,
  325. .remove = hisi_thermal_remove,
  326. };
  327. module_platform_driver(hisi_thermal_driver);
  328. MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
  329. MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
  330. MODULE_DESCRIPTION("Hisilicon thermal driver");
  331. MODULE_LICENSE("GPL v2");