exynos4_tmu.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /*
  2. * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit)
  3. *
  4. * Copyright (C) 2011 Samsung Electronics
  5. * Donggeun Kim <dg77.kim@samsung.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. */
  22. #include <linux/module.h>
  23. #include <linux/err.h>
  24. #include <linux/kernel.h>
  25. #include <linux/slab.h>
  26. #include <linux/platform_device.h>
  27. #include <linux/interrupt.h>
  28. #include <linux/clk.h>
  29. #include <linux/workqueue.h>
  30. #include <linux/sysfs.h>
  31. #include <linux/kobject.h>
  32. #include <linux/io.h>
  33. #include <linux/mutex.h>
  34. #include <linux/hwmon.h>
  35. #include <linux/hwmon-sysfs.h>
  36. #include <linux/platform_data/exynos4_tmu.h>
  37. #define EXYNOS4_TMU_REG_TRIMINFO 0x0
  38. #define EXYNOS4_TMU_REG_CONTROL 0x20
  39. #define EXYNOS4_TMU_REG_STATUS 0x28
  40. #define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40
  41. #define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44
  42. #define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50
  43. #define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54
  44. #define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58
  45. #define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C
  46. #define EXYNOS4_TMU_REG_PAST_TEMP0 0x60
  47. #define EXYNOS4_TMU_REG_PAST_TEMP1 0x64
  48. #define EXYNOS4_TMU_REG_PAST_TEMP2 0x68
  49. #define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C
  50. #define EXYNOS4_TMU_REG_INTEN 0x70
  51. #define EXYNOS4_TMU_REG_INTSTAT 0x74
  52. #define EXYNOS4_TMU_REG_INTCLEAR 0x78
  53. #define EXYNOS4_TMU_GAIN_SHIFT 8
  54. #define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24
  55. #define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff
  56. #define EXYNOS4_TMU_CORE_ON 3
  57. #define EXYNOS4_TMU_CORE_OFF 2
  58. #define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50
  59. #define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1
  60. #define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10
  61. #define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100
  62. #define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000
  63. #define EXYNOS4_TMU_INTCLEAR_VAL 0x1111
  64. struct exynos4_tmu_data {
  65. struct exynos4_tmu_platform_data *pdata;
  66. struct device *hwmon_dev;
  67. struct resource *mem;
  68. void __iomem *base;
  69. int irq;
  70. struct work_struct irq_work;
  71. struct mutex lock;
  72. struct clk *clk;
  73. u8 temp_error1, temp_error2;
  74. };
  75. /*
  76. * TMU treats temperature as a mapped temperature code.
  77. * The temperature is converted differently depending on the calibration type.
  78. */
  79. static int temp_to_code(struct exynos4_tmu_data *data, u8 temp)
  80. {
  81. struct exynos4_tmu_platform_data *pdata = data->pdata;
  82. int temp_code;
  83. /* temp should range between 25 and 125 */
  84. if (temp < 25 || temp > 125) {
  85. temp_code = -EINVAL;
  86. goto out;
  87. }
  88. switch (pdata->cal_type) {
  89. case TYPE_TWO_POINT_TRIMMING:
  90. temp_code = (temp - 25) *
  91. (data->temp_error2 - data->temp_error1) /
  92. (85 - 25) + data->temp_error1;
  93. break;
  94. case TYPE_ONE_POINT_TRIMMING:
  95. temp_code = temp + data->temp_error1 - 25;
  96. break;
  97. default:
  98. temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
  99. break;
  100. }
  101. out:
  102. return temp_code;
  103. }
  104. /*
  105. * Calculate a temperature value from a temperature code.
  106. * The unit of the temperature is degree Celsius.
  107. */
  108. static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code)
  109. {
  110. struct exynos4_tmu_platform_data *pdata = data->pdata;
  111. int temp;
  112. /* temp_code should range between 75 and 175 */
  113. if (temp_code < 75 || temp_code > 175) {
  114. temp = -ENODATA;
  115. goto out;
  116. }
  117. switch (pdata->cal_type) {
  118. case TYPE_TWO_POINT_TRIMMING:
  119. temp = (temp_code - data->temp_error1) * (85 - 25) /
  120. (data->temp_error2 - data->temp_error1) + 25;
  121. break;
  122. case TYPE_ONE_POINT_TRIMMING:
  123. temp = temp_code - data->temp_error1 + 25;
  124. break;
  125. default:
  126. temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET;
  127. break;
  128. }
  129. out:
  130. return temp;
  131. }
  132. static int exynos4_tmu_initialize(struct platform_device *pdev)
  133. {
  134. struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
  135. struct exynos4_tmu_platform_data *pdata = data->pdata;
  136. unsigned int status, trim_info;
  137. int ret = 0, threshold_code;
  138. mutex_lock(&data->lock);
  139. clk_enable(data->clk);
  140. status = readb(data->base + EXYNOS4_TMU_REG_STATUS);
  141. if (!status) {
  142. ret = -EBUSY;
  143. goto out;
  144. }
  145. /* Save trimming info in order to perform calibration */
  146. trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO);
  147. data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK;
  148. data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK);
  149. /* Write temperature code for threshold */
  150. threshold_code = temp_to_code(data, pdata->threshold);
  151. if (threshold_code < 0) {
  152. ret = threshold_code;
  153. goto out;
  154. }
  155. writeb(threshold_code,
  156. data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP);
  157. writeb(pdata->trigger_levels[0],
  158. data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0);
  159. writeb(pdata->trigger_levels[1],
  160. data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1);
  161. writeb(pdata->trigger_levels[2],
  162. data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2);
  163. writeb(pdata->trigger_levels[3],
  164. data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3);
  165. writel(EXYNOS4_TMU_INTCLEAR_VAL,
  166. data->base + EXYNOS4_TMU_REG_INTCLEAR);
  167. out:
  168. clk_disable(data->clk);
  169. mutex_unlock(&data->lock);
  170. return ret;
  171. }
  172. static void exynos4_tmu_control(struct platform_device *pdev, bool on)
  173. {
  174. struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
  175. struct exynos4_tmu_platform_data *pdata = data->pdata;
  176. unsigned int con, interrupt_en;
  177. mutex_lock(&data->lock);
  178. clk_enable(data->clk);
  179. con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT |
  180. pdata->gain << EXYNOS4_TMU_GAIN_SHIFT;
  181. if (on) {
  182. con |= EXYNOS4_TMU_CORE_ON;
  183. interrupt_en = pdata->trigger_level3_en << 12 |
  184. pdata->trigger_level2_en << 8 |
  185. pdata->trigger_level1_en << 4 |
  186. pdata->trigger_level0_en;
  187. } else {
  188. con |= EXYNOS4_TMU_CORE_OFF;
  189. interrupt_en = 0; /* Disable all interrupts */
  190. }
  191. writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN);
  192. writel(con, data->base + EXYNOS4_TMU_REG_CONTROL);
  193. clk_disable(data->clk);
  194. mutex_unlock(&data->lock);
  195. }
  196. static int exynos4_tmu_read(struct exynos4_tmu_data *data)
  197. {
  198. u8 temp_code;
  199. int temp;
  200. mutex_lock(&data->lock);
  201. clk_enable(data->clk);
  202. temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP);
  203. temp = code_to_temp(data, temp_code);
  204. clk_disable(data->clk);
  205. mutex_unlock(&data->lock);
  206. return temp;
  207. }
  208. static void exynos4_tmu_work(struct work_struct *work)
  209. {
  210. struct exynos4_tmu_data *data = container_of(work,
  211. struct exynos4_tmu_data, irq_work);
  212. mutex_lock(&data->lock);
  213. clk_enable(data->clk);
  214. writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR);
  215. kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE);
  216. enable_irq(data->irq);
  217. clk_disable(data->clk);
  218. mutex_unlock(&data->lock);
  219. }
  220. static irqreturn_t exynos4_tmu_irq(int irq, void *id)
  221. {
  222. struct exynos4_tmu_data *data = id;
  223. disable_irq_nosync(irq);
  224. schedule_work(&data->irq_work);
  225. return IRQ_HANDLED;
  226. }
  227. static ssize_t exynos4_tmu_show_name(struct device *dev,
  228. struct device_attribute *attr, char *buf)
  229. {
  230. return sprintf(buf, "exynos4-tmu\n");
  231. }
  232. static ssize_t exynos4_tmu_show_temp(struct device *dev,
  233. struct device_attribute *attr, char *buf)
  234. {
  235. struct exynos4_tmu_data *data = dev_get_drvdata(dev);
  236. int ret;
  237. ret = exynos4_tmu_read(data);
  238. if (ret < 0)
  239. return ret;
  240. /* convert from degree Celsius to millidegree Celsius */
  241. return sprintf(buf, "%d\n", ret * 1000);
  242. }
  243. static ssize_t exynos4_tmu_show_alarm(struct device *dev,
  244. struct device_attribute *devattr, char *buf)
  245. {
  246. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  247. struct exynos4_tmu_data *data = dev_get_drvdata(dev);
  248. struct exynos4_tmu_platform_data *pdata = data->pdata;
  249. int temp;
  250. unsigned int trigger_level;
  251. temp = exynos4_tmu_read(data);
  252. if (temp < 0)
  253. return temp;
  254. trigger_level = pdata->threshold + pdata->trigger_levels[attr->index];
  255. return sprintf(buf, "%d\n", !!(temp > trigger_level));
  256. }
  257. static ssize_t exynos4_tmu_show_level(struct device *dev,
  258. struct device_attribute *devattr, char *buf)
  259. {
  260. struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
  261. struct exynos4_tmu_data *data = dev_get_drvdata(dev);
  262. struct exynos4_tmu_platform_data *pdata = data->pdata;
  263. unsigned int temp = pdata->threshold +
  264. pdata->trigger_levels[attr->index];
  265. return sprintf(buf, "%u\n", temp * 1000);
  266. }
  267. static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL);
  268. static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0);
  269. static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
  270. exynos4_tmu_show_alarm, NULL, 1);
  271. static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
  272. exynos4_tmu_show_alarm, NULL, 2);
  273. static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
  274. exynos4_tmu_show_alarm, NULL, 3);
  275. static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1);
  276. static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2);
  277. static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO,
  278. exynos4_tmu_show_level, NULL, 3);
  279. static struct attribute *exynos4_tmu_attributes[] = {
  280. &dev_attr_name.attr,
  281. &sensor_dev_attr_temp1_input.dev_attr.attr,
  282. &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
  283. &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
  284. &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
  285. &sensor_dev_attr_temp1_max.dev_attr.attr,
  286. &sensor_dev_attr_temp1_crit.dev_attr.attr,
  287. &sensor_dev_attr_temp1_emergency.dev_attr.attr,
  288. NULL,
  289. };
  290. static const struct attribute_group exynos4_tmu_attr_group = {
  291. .attrs = exynos4_tmu_attributes,
  292. };
  293. static int __devinit exynos4_tmu_probe(struct platform_device *pdev)
  294. {
  295. struct exynos4_tmu_data *data;
  296. struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data;
  297. int ret;
  298. if (!pdata) {
  299. dev_err(&pdev->dev, "No platform init data supplied.\n");
  300. return -ENODEV;
  301. }
  302. data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL);
  303. if (!data) {
  304. dev_err(&pdev->dev, "Failed to allocate driver structure\n");
  305. return -ENOMEM;
  306. }
  307. data->irq = platform_get_irq(pdev, 0);
  308. if (data->irq < 0) {
  309. ret = data->irq;
  310. dev_err(&pdev->dev, "Failed to get platform irq\n");
  311. goto err_free;
  312. }
  313. INIT_WORK(&data->irq_work, exynos4_tmu_work);
  314. data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  315. if (!data->mem) {
  316. ret = -ENOENT;
  317. dev_err(&pdev->dev, "Failed to get platform resource\n");
  318. goto err_free;
  319. }
  320. data->mem = request_mem_region(data->mem->start,
  321. resource_size(data->mem), pdev->name);
  322. if (!data->mem) {
  323. ret = -ENODEV;
  324. dev_err(&pdev->dev, "Failed to request memory region\n");
  325. goto err_free;
  326. }
  327. data->base = ioremap(data->mem->start, resource_size(data->mem));
  328. if (!data->base) {
  329. ret = -ENODEV;
  330. dev_err(&pdev->dev, "Failed to ioremap memory\n");
  331. goto err_mem_region;
  332. }
  333. ret = request_irq(data->irq, exynos4_tmu_irq,
  334. IRQF_TRIGGER_RISING,
  335. "exynos4-tmu", data);
  336. if (ret) {
  337. dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
  338. goto err_io_remap;
  339. }
  340. data->clk = clk_get(NULL, "tmu_apbif");
  341. if (IS_ERR(data->clk)) {
  342. ret = PTR_ERR(data->clk);
  343. dev_err(&pdev->dev, "Failed to get clock\n");
  344. goto err_irq;
  345. }
  346. data->pdata = pdata;
  347. platform_set_drvdata(pdev, data);
  348. mutex_init(&data->lock);
  349. ret = exynos4_tmu_initialize(pdev);
  350. if (ret) {
  351. dev_err(&pdev->dev, "Failed to initialize TMU\n");
  352. goto err_clk;
  353. }
  354. ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
  355. if (ret) {
  356. dev_err(&pdev->dev, "Failed to create sysfs group\n");
  357. goto err_clk;
  358. }
  359. data->hwmon_dev = hwmon_device_register(&pdev->dev);
  360. if (IS_ERR(data->hwmon_dev)) {
  361. ret = PTR_ERR(data->hwmon_dev);
  362. dev_err(&pdev->dev, "Failed to register hwmon device\n");
  363. goto err_create_group;
  364. }
  365. exynos4_tmu_control(pdev, true);
  366. return 0;
  367. err_create_group:
  368. sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
  369. err_clk:
  370. platform_set_drvdata(pdev, NULL);
  371. clk_put(data->clk);
  372. err_irq:
  373. free_irq(data->irq, data);
  374. err_io_remap:
  375. iounmap(data->base);
  376. err_mem_region:
  377. release_mem_region(data->mem->start, resource_size(data->mem));
  378. err_free:
  379. kfree(data);
  380. return ret;
  381. }
  382. static int __devexit exynos4_tmu_remove(struct platform_device *pdev)
  383. {
  384. struct exynos4_tmu_data *data = platform_get_drvdata(pdev);
  385. exynos4_tmu_control(pdev, false);
  386. hwmon_device_unregister(data->hwmon_dev);
  387. sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group);
  388. clk_put(data->clk);
  389. free_irq(data->irq, data);
  390. iounmap(data->base);
  391. release_mem_region(data->mem->start, resource_size(data->mem));
  392. platform_set_drvdata(pdev, NULL);
  393. kfree(data);
  394. return 0;
  395. }
  396. #ifdef CONFIG_PM
  397. static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state)
  398. {
  399. exynos4_tmu_control(pdev, false);
  400. return 0;
  401. }
  402. static int exynos4_tmu_resume(struct platform_device *pdev)
  403. {
  404. exynos4_tmu_initialize(pdev);
  405. exynos4_tmu_control(pdev, true);
  406. return 0;
  407. }
  408. #else
  409. #define exynos4_tmu_suspend NULL
  410. #define exynos4_tmu_resume NULL
  411. #endif
  412. static struct platform_driver exynos4_tmu_driver = {
  413. .driver = {
  414. .name = "exynos4-tmu",
  415. .owner = THIS_MODULE,
  416. },
  417. .probe = exynos4_tmu_probe,
  418. .remove = __devexit_p(exynos4_tmu_remove),
  419. .suspend = exynos4_tmu_suspend,
  420. .resume = exynos4_tmu_resume,
  421. };
  422. module_platform_driver(exynos4_tmu_driver);
  423. MODULE_DESCRIPTION("EXYNOS4 TMU Driver");
  424. MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
  425. MODULE_LICENSE("GPL");
  426. MODULE_ALIAS("platform:exynos4-tmu");