wsa881x-temp-sensor.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/bitops.h>
  13. #include <linux/kernel.h>
  14. #include <linux/errno.h>
  15. #include <linux/delay.h>
  16. #include <linux/thermal.h>
  17. #include <sound/soc.h>
  18. #include "wsa881x-temp-sensor.h"
  19. #define T1_TEMP -10
  20. #define T2_TEMP 150
  21. #define LOW_TEMP_THRESHOLD 5
  22. #define HIGH_TEMP_THRESHOLD 45
  23. #define TEMP_INVALID 0xFFFF
  24. #define WSA881X_TEMP_RETRY 3
  25. /*
  26. * wsa881x_get_temp - get wsa temperature
  27. * @thermal: thermal zone device
  28. * @temp: temperature value
  29. *
  30. * Get the temperature of wsa881x.
  31. *
  32. * Return: 0 on success or negative error code on failure.
  33. */
  34. int wsa881x_get_temp(struct thermal_zone_device *thermal,
  35. int *temp)
  36. {
  37. struct wsa881x_tz_priv *pdata;
  38. struct snd_soc_codec *codec;
  39. struct wsa_temp_register reg;
  40. int dmeas, d1, d2;
  41. int ret = 0;
  42. int temp_val;
  43. int t1 = T1_TEMP;
  44. int t2 = T2_TEMP;
  45. u8 retry = WSA881X_TEMP_RETRY;
  46. if (!thermal)
  47. return -EINVAL;
  48. if (thermal->devdata) {
  49. pdata = thermal->devdata;
  50. if (pdata->codec) {
  51. codec = pdata->codec;
  52. } else {
  53. pr_err("%s: codec is NULL\n", __func__);
  54. return -EINVAL;
  55. }
  56. } else {
  57. pr_err("%s: pdata is NULL\n", __func__);
  58. return -EINVAL;
  59. }
  60. temp_retry:
  61. if (pdata->wsa_temp_reg_read) {
  62. ret = pdata->wsa_temp_reg_read(codec, &reg);
  63. if (ret) {
  64. pr_err("%s: temperature register read failed: %d\n",
  65. __func__, ret);
  66. return ret;
  67. }
  68. } else {
  69. pr_err("%s: wsa_temp_reg_read is NULL\n", __func__);
  70. return -EINVAL;
  71. }
  72. /*
  73. * Temperature register values are expected to be in the
  74. * following range.
  75. * d1_msb = 68 - 92 and d1_lsb = 0, 64, 128, 192
  76. * d2_msb = 185 -218 and d2_lsb = 0, 64, 128, 192
  77. */
  78. if ((reg.d1_msb < 68 || reg.d1_msb > 92) ||
  79. (!(reg.d1_lsb == 0 || reg.d1_lsb == 64 || reg.d1_lsb == 128 ||
  80. reg.d1_lsb == 192)) ||
  81. (reg.d2_msb < 185 || reg.d2_msb > 218) ||
  82. (!(reg.d2_lsb == 0 || reg.d2_lsb == 64 || reg.d2_lsb == 128 ||
  83. reg.d2_lsb == 192))) {
  84. printk_ratelimited("%s: Temperature registers[%d %d %d %d] are out of range\n",
  85. __func__, reg.d1_msb, reg.d1_lsb, reg.d2_msb,
  86. reg.d2_lsb);
  87. }
  88. dmeas = ((reg.dmeas_msb << 0x8) | reg.dmeas_lsb) >> 0x6;
  89. d1 = ((reg.d1_msb << 0x8) | reg.d1_lsb) >> 0x6;
  90. d2 = ((reg.d2_msb << 0x8) | reg.d2_lsb) >> 0x6;
  91. if (d1 == d2)
  92. temp_val = TEMP_INVALID;
  93. else
  94. temp_val = t1 + (((dmeas - d1) * (t2 - t1))/(d2 - d1));
  95. if (temp_val <= LOW_TEMP_THRESHOLD ||
  96. temp_val >= HIGH_TEMP_THRESHOLD) {
  97. printk_ratelimited("%s: T0: %d is out of range[%d, %d]\n",
  98. __func__, temp_val, LOW_TEMP_THRESHOLD,
  99. HIGH_TEMP_THRESHOLD);
  100. if (retry--) {
  101. msleep(20);
  102. goto temp_retry;
  103. }
  104. }
  105. if (temp)
  106. *temp = temp_val;
  107. pr_debug("%s: t0 measured: %d dmeas = %d, d1 = %d, d2 = %d\n",
  108. __func__, temp_val, dmeas, d1, d2);
  109. return ret;
  110. }
  111. EXPORT_SYMBOL(wsa881x_get_temp);
  112. static struct thermal_zone_device_ops wsa881x_thermal_ops = {
  113. .get_temp = wsa881x_get_temp,
  114. };
  115. int wsa881x_init_thermal(struct wsa881x_tz_priv *tz_pdata)
  116. {
  117. struct thermal_zone_device *tz_dev;
  118. if (tz_pdata == NULL) {
  119. pr_err("%s: thermal pdata is NULL\n", __func__);
  120. return -EINVAL;
  121. }
  122. /* Register with the thermal zone */
  123. tz_dev = thermal_zone_device_register(tz_pdata->name,
  124. 0, 0, tz_pdata,
  125. &wsa881x_thermal_ops, NULL, 0, 0);
  126. if (IS_ERR(tz_dev)) {
  127. pr_err("%s: thermal device register failed.\n", __func__);
  128. return -EINVAL;
  129. }
  130. tz_pdata->tz_dev = tz_dev;
  131. return 0;
  132. }
  133. EXPORT_SYMBOL(wsa881x_init_thermal);
  134. void wsa881x_deinit_thermal(struct thermal_zone_device *tz_dev)
  135. {
  136. if (tz_dev)
  137. thermal_zone_device_unregister(tz_dev);
  138. }
  139. EXPORT_SYMBOL(wsa881x_deinit_thermal);