qcom-vadc-common.c 5.1 KB

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