qcom-vadc-common.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/bug.h>
  3. #include <linux/kernel.h>
  4. #include <linux/bitops.h>
  5. #include <linux/math64.h>
  6. #include <linux/log2.h>
  7. #include <linux/err.h>
  8. #include <linux/module.h>
  9. #include "qcom-vadc-common.h"
  10. /* Voltage to temperature */
  11. static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
  12. {1758, -40},
  13. {1742, -35},
  14. {1719, -30},
  15. {1691, -25},
  16. {1654, -20},
  17. {1608, -15},
  18. {1551, -10},
  19. {1483, -5},
  20. {1404, 0},
  21. {1315, 5},
  22. {1218, 10},
  23. {1114, 15},
  24. {1007, 20},
  25. {900, 25},
  26. {795, 30},
  27. {696, 35},
  28. {605, 40},
  29. {522, 45},
  30. {448, 50},
  31. {383, 55},
  32. {327, 60},
  33. {278, 65},
  34. {237, 70},
  35. {202, 75},
  36. {172, 80},
  37. {146, 85},
  38. {125, 90},
  39. {107, 95},
  40. {92, 100},
  41. {79, 105},
  42. {68, 110},
  43. {59, 115},
  44. {51, 120},
  45. {44, 125}
  46. };
  47. static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
  48. u32 tablesize, s32 input, s64 *output)
  49. {
  50. bool descending = 1;
  51. u32 i = 0;
  52. if (!pts)
  53. return -EINVAL;
  54. /* Check if table is descending or ascending */
  55. if (tablesize > 1) {
  56. if (pts[0].x < pts[1].x)
  57. descending = 0;
  58. }
  59. while (i < tablesize) {
  60. if ((descending) && (pts[i].x < input)) {
  61. /* table entry is less than measured*/
  62. /* value and table is descending, stop */
  63. break;
  64. } else if ((!descending) &&
  65. (pts[i].x > input)) {
  66. /* table entry is greater than measured*/
  67. /*value and table is ascending, stop */
  68. break;
  69. }
  70. i++;
  71. }
  72. if (i == 0) {
  73. *output = pts[0].y;
  74. } else if (i == tablesize) {
  75. *output = pts[tablesize - 1].y;
  76. } else {
  77. /* result is between search_index and search_index-1 */
  78. /* interpolate linearly */
  79. *output = (((s32)((pts[i].y - pts[i - 1].y) *
  80. (input - pts[i - 1].x)) /
  81. (pts[i].x - pts[i - 1].x)) +
  82. pts[i - 1].y);
  83. }
  84. return 0;
  85. }
  86. static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
  87. u16 adc_code,
  88. bool absolute,
  89. s64 *scale_voltage)
  90. {
  91. *scale_voltage = (adc_code - calib_graph->gnd);
  92. *scale_voltage *= calib_graph->dx;
  93. *scale_voltage = div64_s64(*scale_voltage, calib_graph->dy);
  94. if (absolute)
  95. *scale_voltage += calib_graph->dx;
  96. if (*scale_voltage < 0)
  97. *scale_voltage = 0;
  98. }
  99. static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
  100. const struct vadc_prescale_ratio *prescale,
  101. bool absolute, u16 adc_code,
  102. int *result_uv)
  103. {
  104. s64 voltage = 0, result = 0;
  105. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  106. voltage = voltage * prescale->den;
  107. result = div64_s64(voltage, prescale->num);
  108. *result_uv = result;
  109. return 0;
  110. }
  111. static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
  112. const struct vadc_prescale_ratio *prescale,
  113. bool absolute, u16 adc_code,
  114. int *result_mdec)
  115. {
  116. s64 voltage = 0, result = 0;
  117. int ret;
  118. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  119. if (absolute)
  120. voltage = div64_s64(voltage, 1000);
  121. ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
  122. ARRAY_SIZE(adcmap_100k_104ef_104fb),
  123. voltage, &result);
  124. if (ret)
  125. return ret;
  126. result *= 1000;
  127. *result_mdec = result;
  128. return 0;
  129. }
  130. static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
  131. const struct vadc_prescale_ratio *prescale,
  132. bool absolute,
  133. u16 adc_code, int *result_mdec)
  134. {
  135. s64 voltage = 0;
  136. u64 temp; /* Temporary variable for do_div */
  137. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  138. if (voltage > 0) {
  139. temp = voltage * prescale->den;
  140. do_div(temp, prescale->num * 2);
  141. voltage = temp;
  142. } else {
  143. voltage = 0;
  144. }
  145. voltage -= KELVINMIL_CELSIUSMIL;
  146. *result_mdec = voltage;
  147. return 0;
  148. }
  149. static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
  150. const struct vadc_prescale_ratio *prescale,
  151. bool absolute,
  152. u16 adc_code, int *result_mdec)
  153. {
  154. s64 voltage = 0, result = 0;
  155. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  156. voltage = voltage * prescale->den;
  157. voltage = div64_s64(voltage, prescale->num);
  158. voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
  159. voltage = (voltage + PMI_CHG_SCALE_2);
  160. result = div64_s64(voltage, 1000000);
  161. *result_mdec = result;
  162. return 0;
  163. }
  164. int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
  165. const struct vadc_linear_graph *calib_graph,
  166. const struct vadc_prescale_ratio *prescale,
  167. bool absolute,
  168. u16 adc_code, int *result)
  169. {
  170. switch (scaletype) {
  171. case SCALE_DEFAULT:
  172. return qcom_vadc_scale_volt(calib_graph, prescale,
  173. absolute, adc_code,
  174. result);
  175. case SCALE_THERM_100K_PULLUP:
  176. case SCALE_XOTHERM:
  177. return qcom_vadc_scale_therm(calib_graph, prescale,
  178. absolute, adc_code,
  179. result);
  180. case SCALE_PMIC_THERM:
  181. return qcom_vadc_scale_die_temp(calib_graph, prescale,
  182. absolute, adc_code,
  183. result);
  184. case SCALE_PMI_CHG_TEMP:
  185. return qcom_vadc_scale_chg_temp(calib_graph, prescale,
  186. absolute, adc_code,
  187. result);
  188. default:
  189. return -EINVAL;
  190. }
  191. }
  192. EXPORT_SYMBOL(qcom_vadc_scale);
  193. int qcom_vadc_decimation_from_dt(u32 value)
  194. {
  195. if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
  196. value > VADC_DECIMATION_MAX)
  197. return -EINVAL;
  198. return __ffs64(value / VADC_DECIMATION_MIN);
  199. }
  200. EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
  201. MODULE_LICENSE("GPL v2");
  202. MODULE_DESCRIPTION("Qualcomm ADC common functionality");