wsa881x-temp-sensor.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved.
  3. */
  4. #include <linux/bitops.h>
  5. #include <linux/kernel.h>
  6. #include <linux/suspend.h>
  7. #include <linux/errno.h>
  8. #include <linux/delay.h>
  9. #include <linux/thermal.h>
  10. #include <sound/soc.h>
  11. #include "wsa881x-temp-sensor.h"
  12. #define T1_TEMP -10
  13. #define T2_TEMP 150
  14. #define LOW_TEMP_THRESHOLD 5
  15. #define HIGH_TEMP_THRESHOLD 45
  16. #define TEMP_INVALID 0xFFFF
  17. #define WSA881X_TEMP_RETRY 3
  18. /*
  19. * wsa881x_get_temp - get wsa temperature
  20. * @thermal: thermal zone device
  21. * @temp: temperature value
  22. *
  23. * Get the temperature of wsa881x.
  24. *
  25. * Return: 0 on success or negative error code on failure.
  26. */
  27. int wsa881x_get_temp(struct thermal_zone_device *thermal,
  28. int *temp)
  29. {
  30. struct wsa881x_tz_priv *pdata;
  31. struct snd_soc_component *component;
  32. struct wsa_temp_register reg;
  33. int dmeas, d1, d2;
  34. int ret = 0;
  35. int temp_val;
  36. int t1 = T1_TEMP;
  37. int t2 = T2_TEMP;
  38. u8 retry = WSA881X_TEMP_RETRY;
  39. if (!thermal)
  40. return -EINVAL;
  41. if (thermal->devdata) {
  42. pdata = thermal->devdata;
  43. if (pdata->component) {
  44. component = pdata->component;
  45. } else {
  46. pr_err("%s: codec is NULL\n", __func__);
  47. return -EINVAL;
  48. }
  49. } else {
  50. pr_err("%s: pdata is NULL\n", __func__);
  51. return -EINVAL;
  52. }
  53. if (atomic_cmpxchg(&pdata->is_suspend_spk, 1, 0)) {
  54. /*
  55. * get_temp query happens as part of POST_PM_SUSPEND
  56. * from thermal core. To avoid calls to slimbus
  57. * as part of this thermal query, return default temp
  58. * and reset the suspend flag.
  59. */
  60. if (!pdata->t0_init) {
  61. if (temp)
  62. *temp = pdata->curr_temp;
  63. return 0;
  64. }
  65. }
  66. temp_retry:
  67. if (pdata->wsa_temp_reg_read) {
  68. ret = pdata->wsa_temp_reg_read(component, &reg);
  69. if (ret) {
  70. pr_err("%s: temp read failed: %d, current temp: %d\n",
  71. __func__, ret, pdata->curr_temp);
  72. if (temp)
  73. *temp = pdata->curr_temp;
  74. return 0;
  75. }
  76. } else {
  77. pr_err("%s: wsa_temp_reg_read is NULL\n", __func__);
  78. return -EINVAL;
  79. }
  80. /*
  81. * Temperature register values are expected to be in the
  82. * following range.
  83. * d1_msb = 68 - 92 and d1_lsb = 0, 64, 128, 192
  84. * d2_msb = 185 -218 and d2_lsb = 0, 64, 128, 192
  85. */
  86. if ((reg.d1_msb < 68 || reg.d1_msb > 92) ||
  87. (!(reg.d1_lsb == 0 || reg.d1_lsb == 64 || reg.d1_lsb == 128 ||
  88. reg.d1_lsb == 192)) ||
  89. (reg.d2_msb < 185 || reg.d2_msb > 218) ||
  90. (!(reg.d2_lsb == 0 || reg.d2_lsb == 64 || reg.d2_lsb == 128 ||
  91. reg.d2_lsb == 192))) {
  92. printk_ratelimited("%s: Temperature registers[%d %d %d %d] are out of range\n",
  93. __func__, reg.d1_msb, reg.d1_lsb, reg.d2_msb,
  94. reg.d2_lsb);
  95. }
  96. dmeas = ((reg.dmeas_msb << 0x8) | reg.dmeas_lsb) >> 0x6;
  97. d1 = ((reg.d1_msb << 0x8) | reg.d1_lsb) >> 0x6;
  98. d2 = ((reg.d2_msb << 0x8) | reg.d2_lsb) >> 0x6;
  99. if (d1 == d2)
  100. temp_val = TEMP_INVALID;
  101. else
  102. temp_val = t1 + (((dmeas - d1) * (t2 - t1))/(d2 - d1));
  103. if (temp_val <= LOW_TEMP_THRESHOLD ||
  104. temp_val >= HIGH_TEMP_THRESHOLD) {
  105. printk_ratelimited("%s: T0: %d is out of range[%d, %d]\n",
  106. __func__, temp_val, LOW_TEMP_THRESHOLD,
  107. HIGH_TEMP_THRESHOLD);
  108. if (retry--) {
  109. msleep(20);
  110. goto temp_retry;
  111. }
  112. }
  113. pdata->curr_temp = temp_val;
  114. if (temp)
  115. *temp = temp_val;
  116. pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n",
  117. __func__, temp_val, dmeas, d1, d2);
  118. return ret;
  119. }
  120. EXPORT_SYMBOL(wsa881x_get_temp);
  121. static struct thermal_zone_device_ops wsa881x_thermal_ops = {
  122. .get_temp = wsa881x_get_temp,
  123. };
  124. static int wsa881x_pm_notify(struct notifier_block *nb,
  125. unsigned long mode, void *_unused)
  126. {
  127. struct wsa881x_tz_priv *pdata =
  128. container_of(nb, struct wsa881x_tz_priv, pm_nb);
  129. switch (mode) {
  130. case PM_SUSPEND_PREPARE:
  131. atomic_set(&pdata->is_suspend_spk, 1);
  132. break;
  133. default:
  134. break;
  135. }
  136. return 0;
  137. }
  138. int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata)
  139. {
  140. struct thermal_zone_device *tz_dev;
  141. if (tz_pdata == NULL) {
  142. pr_err("%s: thermal pdata is NULL\n", __func__);
  143. return -EINVAL;
  144. }
  145. /* Register with the thermal zone */
  146. tz_dev = thermal_zone_device_register(tz_pdata->name,
  147. 0, 0, tz_pdata,
  148. &wsa881x_thermal_ops, NULL, 0, 0);
  149. if (IS_ERR(tz_dev)) {
  150. pr_err("%s: thermal device register failed.\n", __func__);
  151. return -EINVAL;
  152. }
  153. tz_pdata->tz_dev = tz_dev;
  154. tz_pdata->pm_nb.notifier_call = wsa881x_pm_notify;
  155. register_pm_notifier(&tz_pdata->pm_nb);
  156. atomic_set(&tz_pdata->is_suspend_spk, 0);
  157. return 0;
  158. }
  159. EXPORT_SYMBOL(wsa881x_init_thermal);
  160. void wsa881x_deinit_thermal(struct thermal_zone_device *tz_dev)
  161. {
  162. struct wsa881x_tz_priv *pdata;
  163. if (tz_dev && tz_dev->devdata) {
  164. pdata = tz_dev->devdata;
  165. if (pdata)
  166. unregister_pm_notifier(&pdata->pm_nb);
  167. }
  168. if (tz_dev)
  169. thermal_zone_device_unregister(tz_dev);
  170. }
  171. EXPORT_SYMBOL(wsa881x_deinit_thermal);