rcar_gen3_thermal.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*
  2. * R-Car Gen3 THS thermal sensor driver
  3. * Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
  4. *
  5. * Copyright (C) 2016 Renesas Electronics Corporation.
  6. * Copyright (C) 2016 Sang Engineering
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; version 2 of the License.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. */
  18. #include <linux/delay.h>
  19. #include <linux/err.h>
  20. #include <linux/interrupt.h>
  21. #include <linux/io.h>
  22. #include <linux/module.h>
  23. #include <linux/of_device.h>
  24. #include <linux/platform_device.h>
  25. #include <linux/pm_runtime.h>
  26. #include <linux/spinlock.h>
  27. #include <linux/thermal.h>
  28. #include "thermal_core.h"
  29. /* Register offsets */
  30. #define REG_GEN3_IRQSTR 0x04
  31. #define REG_GEN3_IRQMSK 0x08
  32. #define REG_GEN3_IRQCTL 0x0C
  33. #define REG_GEN3_IRQEN 0x10
  34. #define REG_GEN3_IRQTEMP1 0x14
  35. #define REG_GEN3_IRQTEMP2 0x18
  36. #define REG_GEN3_IRQTEMP3 0x1C
  37. #define REG_GEN3_CTSR 0x20
  38. #define REG_GEN3_THCTR 0x20
  39. #define REG_GEN3_TEMP 0x28
  40. #define REG_GEN3_THCODE1 0x50
  41. #define REG_GEN3_THCODE2 0x54
  42. #define REG_GEN3_THCODE3 0x58
  43. /* IRQ{STR,MSK,EN} bits */
  44. #define IRQ_TEMP1 BIT(0)
  45. #define IRQ_TEMP2 BIT(1)
  46. #define IRQ_TEMP3 BIT(2)
  47. #define IRQ_TEMPD1 BIT(3)
  48. #define IRQ_TEMPD2 BIT(4)
  49. #define IRQ_TEMPD3 BIT(5)
  50. /* CTSR bits */
  51. #define CTSR_PONM BIT(8)
  52. #define CTSR_AOUT BIT(7)
  53. #define CTSR_THBGR BIT(5)
  54. #define CTSR_VMEN BIT(4)
  55. #define CTSR_VMST BIT(1)
  56. #define CTSR_THSST BIT(0)
  57. /* THCTR bits */
  58. #define THCTR_PONM BIT(6)
  59. #define THCTR_THSST BIT(0)
  60. #define CTEMP_MASK 0xFFF
  61. #define MCELSIUS(temp) ((temp) * 1000)
  62. #define GEN3_FUSE_MASK 0xFFF
  63. #define TSC_MAX_NUM 3
  64. /* Structure for thermal temperature calculation */
  65. struct equation_coefs {
  66. int a1;
  67. int b1;
  68. int a2;
  69. int b2;
  70. };
  71. struct rcar_gen3_thermal_tsc {
  72. void __iomem *base;
  73. struct thermal_zone_device *zone;
  74. struct equation_coefs coef;
  75. int low;
  76. int high;
  77. };
  78. struct rcar_gen3_thermal_priv {
  79. struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
  80. unsigned int num_tscs;
  81. spinlock_t lock; /* Protect interrupts on and off */
  82. const struct rcar_gen3_thermal_data *data;
  83. };
  84. struct rcar_gen3_thermal_data {
  85. void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
  86. };
  87. static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
  88. u32 reg)
  89. {
  90. return ioread32(tsc->base + reg);
  91. }
  92. static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
  93. u32 reg, u32 data)
  94. {
  95. iowrite32(data, tsc->base + reg);
  96. }
  97. /*
  98. * Linear approximation for temperature
  99. *
  100. * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
  101. *
  102. * The constants a and b are calculated using two triplets of int values PTAT
  103. * and THCODE. PTAT and THCODE can either be read from hardware or use hard
  104. * coded values from driver. The formula to calculate a and b are taken from
  105. * BSP and sparsely documented and understood.
  106. *
  107. * Examining the linear formula and the formula used to calculate constants a
  108. * and b while knowing that the span for PTAT and THCODE values are between
  109. * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
  110. * Integer also needs to be signed so that leaves 7 bits for binary
  111. * fixed point scaling.
  112. */
  113. #define FIXPT_SHIFT 7
  114. #define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)
  115. #define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)
  116. #define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
  117. #define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)
  118. #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
  119. /* no idea where these constants come from */
  120. #define TJ_1 96
  121. #define TJ_3 -41
  122. static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef,
  123. int *ptat, int *thcode)
  124. {
  125. int tj_2;
  126. /* TODO: Find documentation and document constant calculation formula */
  127. /*
  128. * Division is not scaled in BSP and if scaled it might overflow
  129. * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
  130. */
  131. tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 137)
  132. / (ptat[0] - ptat[2])) - FIXPT_INT(41);
  133. coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
  134. tj_2 - FIXPT_INT(TJ_3));
  135. coef->b1 = FIXPT_INT(thcode[2]) - coef->a1 * TJ_3;
  136. coef->a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
  137. tj_2 - FIXPT_INT(TJ_1));
  138. coef->b2 = FIXPT_INT(thcode[0]) - coef->a2 * TJ_1;
  139. }
  140. static int rcar_gen3_thermal_round(int temp)
  141. {
  142. int result, round_offs;
  143. round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
  144. -RCAR3_THERMAL_GRAN / 2;
  145. result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
  146. return result * RCAR3_THERMAL_GRAN;
  147. }
  148. static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
  149. {
  150. struct rcar_gen3_thermal_tsc *tsc = devdata;
  151. int mcelsius, val1, val2;
  152. u32 reg;
  153. /* Read register and convert to mili Celsius */
  154. reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
  155. val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1);
  156. val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2);
  157. mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2);
  158. /* Make sure we are inside specifications */
  159. if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125)))
  160. return -EIO;
  161. /* Round value to device granularity setting */
  162. *temp = rcar_gen3_thermal_round(mcelsius);
  163. return 0;
  164. }
  165. static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
  166. int mcelsius)
  167. {
  168. int celsius, val1, val2;
  169. celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
  170. val1 = celsius * tsc->coef.a1 + tsc->coef.b1;
  171. val2 = celsius * tsc->coef.a2 + tsc->coef.b2;
  172. return INT_FIXPT((val1 + val2) / 2);
  173. }
  174. static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
  175. {
  176. struct rcar_gen3_thermal_tsc *tsc = devdata;
  177. low = clamp_val(low, -40000, 125000);
  178. high = clamp_val(high, -40000, 125000);
  179. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
  180. rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
  181. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
  182. rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
  183. tsc->low = low;
  184. tsc->high = high;
  185. return 0;
  186. }
  187. static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
  188. .get_temp = rcar_gen3_thermal_get_temp,
  189. .set_trips = rcar_gen3_thermal_set_trips,
  190. };
  191. static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on)
  192. {
  193. unsigned int i;
  194. u32 val = on ? IRQ_TEMPD1 | IRQ_TEMP2 : 0;
  195. for (i = 0; i < priv->num_tscs; i++)
  196. rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQMSK, val);
  197. }
  198. static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
  199. {
  200. struct rcar_gen3_thermal_priv *priv = data;
  201. u32 status;
  202. int i, ret = IRQ_HANDLED;
  203. spin_lock(&priv->lock);
  204. for (i = 0; i < priv->num_tscs; i++) {
  205. status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
  206. rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
  207. if (status)
  208. ret = IRQ_WAKE_THREAD;
  209. }
  210. if (ret == IRQ_WAKE_THREAD)
  211. rcar_thermal_irq_set(priv, false);
  212. spin_unlock(&priv->lock);
  213. return ret;
  214. }
  215. static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
  216. {
  217. struct rcar_gen3_thermal_priv *priv = data;
  218. unsigned long flags;
  219. int i;
  220. for (i = 0; i < priv->num_tscs; i++)
  221. thermal_zone_device_update(priv->tscs[i]->zone,
  222. THERMAL_EVENT_UNSPECIFIED);
  223. spin_lock_irqsave(&priv->lock, flags);
  224. rcar_thermal_irq_set(priv, true);
  225. spin_unlock_irqrestore(&priv->lock, flags);
  226. return IRQ_HANDLED;
  227. }
  228. static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
  229. {
  230. rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR);
  231. rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, 0x0);
  232. usleep_range(1000, 2000);
  233. rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM);
  234. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
  235. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
  236. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
  237. rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
  238. CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
  239. usleep_range(100, 200);
  240. rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
  241. CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN |
  242. CTSR_VMST | CTSR_THSST);
  243. usleep_range(1000, 2000);
  244. }
  245. static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
  246. {
  247. u32 reg_val;
  248. reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
  249. reg_val &= ~THCTR_PONM;
  250. rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
  251. usleep_range(1000, 2000);
  252. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
  253. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
  254. rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
  255. reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
  256. reg_val |= THCTR_THSST;
  257. rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
  258. usleep_range(1000, 2000);
  259. }
  260. static const struct rcar_gen3_thermal_data r8a7795_data = {
  261. .thermal_init = r8a7795_thermal_init,
  262. };
  263. static const struct rcar_gen3_thermal_data r8a7796_data = {
  264. .thermal_init = r8a7796_thermal_init,
  265. };
  266. static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
  267. { .compatible = "renesas,r8a7795-thermal", .data = &r8a7795_data},
  268. { .compatible = "renesas,r8a7796-thermal", .data = &r8a7796_data},
  269. {},
  270. };
  271. MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
  272. static int rcar_gen3_thermal_remove(struct platform_device *pdev)
  273. {
  274. struct device *dev = &pdev->dev;
  275. struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
  276. rcar_thermal_irq_set(priv, false);
  277. pm_runtime_put(dev);
  278. pm_runtime_disable(dev);
  279. return 0;
  280. }
  281. static int rcar_gen3_thermal_probe(struct platform_device *pdev)
  282. {
  283. struct rcar_gen3_thermal_priv *priv;
  284. struct device *dev = &pdev->dev;
  285. struct resource *res;
  286. struct thermal_zone_device *zone;
  287. int ret, irq, i;
  288. char *irqname;
  289. /* default values if FUSEs are missing */
  290. /* TODO: Read values from hardware on supported platforms */
  291. int ptat[3] = { 2351, 1509, 435 };
  292. int thcode[TSC_MAX_NUM][3] = {
  293. { 3248, 2800, 2221 },
  294. { 3245, 2795, 2216 },
  295. { 3250, 2805, 2237 },
  296. };
  297. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  298. if (!priv)
  299. return -ENOMEM;
  300. priv->data = of_device_get_match_data(dev);
  301. spin_lock_init(&priv->lock);
  302. platform_set_drvdata(pdev, priv);
  303. /*
  304. * Request 2 (of the 3 possible) IRQs, the driver only needs to
  305. * to trigger on the low and high trip points of the current
  306. * temp window at this point.
  307. */
  308. for (i = 0; i < 2; i++) {
  309. irq = platform_get_irq(pdev, i);
  310. if (irq < 0)
  311. return irq;
  312. irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
  313. dev_name(dev), i);
  314. if (!irqname)
  315. return -ENOMEM;
  316. ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq,
  317. rcar_gen3_thermal_irq_thread,
  318. IRQF_SHARED, irqname, priv);
  319. if (ret)
  320. return ret;
  321. }
  322. pm_runtime_enable(dev);
  323. pm_runtime_get_sync(dev);
  324. for (i = 0; i < TSC_MAX_NUM; i++) {
  325. struct rcar_gen3_thermal_tsc *tsc;
  326. res = platform_get_resource(pdev, IORESOURCE_MEM, i);
  327. if (!res)
  328. break;
  329. tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
  330. if (!tsc) {
  331. ret = -ENOMEM;
  332. goto error_unregister;
  333. }
  334. tsc->base = devm_ioremap_resource(dev, res);
  335. if (IS_ERR(tsc->base)) {
  336. ret = PTR_ERR(tsc->base);
  337. goto error_unregister;
  338. }
  339. priv->tscs[i] = tsc;
  340. priv->data->thermal_init(tsc);
  341. rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
  342. zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
  343. &rcar_gen3_tz_of_ops);
  344. if (IS_ERR(zone)) {
  345. dev_err(dev, "Can't register thermal zone\n");
  346. ret = PTR_ERR(zone);
  347. goto error_unregister;
  348. }
  349. tsc->zone = zone;
  350. ret = of_thermal_get_ntrips(tsc->zone);
  351. if (ret < 0)
  352. goto error_unregister;
  353. dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
  354. }
  355. priv->num_tscs = i;
  356. if (!priv->num_tscs) {
  357. ret = -ENODEV;
  358. goto error_unregister;
  359. }
  360. rcar_thermal_irq_set(priv, true);
  361. return 0;
  362. error_unregister:
  363. rcar_gen3_thermal_remove(pdev);
  364. return ret;
  365. }
  366. static int __maybe_unused rcar_gen3_thermal_suspend(struct device *dev)
  367. {
  368. struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
  369. rcar_thermal_irq_set(priv, false);
  370. return 0;
  371. }
  372. static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
  373. {
  374. struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
  375. unsigned int i;
  376. for (i = 0; i < priv->num_tscs; i++) {
  377. struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
  378. priv->data->thermal_init(tsc);
  379. rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high);
  380. }
  381. rcar_thermal_irq_set(priv, true);
  382. return 0;
  383. }
  384. static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, rcar_gen3_thermal_suspend,
  385. rcar_gen3_thermal_resume);
  386. static struct platform_driver rcar_gen3_thermal_driver = {
  387. .driver = {
  388. .name = "rcar_gen3_thermal",
  389. .pm = &rcar_gen3_thermal_pm_ops,
  390. .of_match_table = rcar_gen3_thermal_dt_ids,
  391. },
  392. .probe = rcar_gen3_thermal_probe,
  393. .remove = rcar_gen3_thermal_remove,
  394. };
  395. module_platform_driver(rcar_gen3_thermal_driver);
  396. MODULE_LICENSE("GPL v2");
  397. MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");
  398. MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");