qcom-vadc-common.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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. /*
  48. * Voltage to temperature table for 100k pull up for NTCG104EF104 with
  49. * 1.875V reference.
  50. */
  51. static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
  52. { 1831, -40000 },
  53. { 1814, -35000 },
  54. { 1791, -30000 },
  55. { 1761, -25000 },
  56. { 1723, -20000 },
  57. { 1675, -15000 },
  58. { 1616, -10000 },
  59. { 1545, -5000 },
  60. { 1463, 0 },
  61. { 1370, 5000 },
  62. { 1268, 10000 },
  63. { 1160, 15000 },
  64. { 1049, 20000 },
  65. { 937, 25000 },
  66. { 828, 30000 },
  67. { 726, 35000 },
  68. { 630, 40000 },
  69. { 544, 45000 },
  70. { 467, 50000 },
  71. { 399, 55000 },
  72. { 340, 60000 },
  73. { 290, 65000 },
  74. { 247, 70000 },
  75. { 209, 75000 },
  76. { 179, 80000 },
  77. { 153, 85000 },
  78. { 130, 90000 },
  79. { 112, 95000 },
  80. { 96, 100000 },
  81. { 82, 105000 },
  82. { 71, 110000 },
  83. { 62, 115000 },
  84. { 53, 120000 },
  85. { 46, 125000 },
  86. };
  87. static int qcom_vadc_scale_hw_calib_volt(
  88. const struct vadc_prescale_ratio *prescale,
  89. const struct adc5_data *data,
  90. u16 adc_code, int *result_uv);
  91. static int qcom_vadc_scale_hw_calib_therm(
  92. const struct vadc_prescale_ratio *prescale,
  93. const struct adc5_data *data,
  94. u16 adc_code, int *result_mdec);
  95. static int qcom_vadc_scale_hw_smb_temp(
  96. const struct vadc_prescale_ratio *prescale,
  97. const struct adc5_data *data,
  98. u16 adc_code, int *result_mdec);
  99. static int qcom_vadc_scale_hw_chg5_temp(
  100. const struct vadc_prescale_ratio *prescale,
  101. const struct adc5_data *data,
  102. u16 adc_code, int *result_mdec);
  103. static int qcom_vadc_scale_hw_calib_die_temp(
  104. const struct vadc_prescale_ratio *prescale,
  105. const struct adc5_data *data,
  106. u16 adc_code, int *result_mdec);
  107. static struct qcom_adc5_scale_type scale_adc5_fn[] = {
  108. [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
  109. [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
  110. [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
  111. [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp},
  112. [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp},
  113. [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp},
  114. };
  115. static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
  116. u32 tablesize, s32 input, int *output)
  117. {
  118. bool descending = 1;
  119. u32 i = 0;
  120. if (!pts)
  121. return -EINVAL;
  122. /* Check if table is descending or ascending */
  123. if (tablesize > 1) {
  124. if (pts[0].x < pts[1].x)
  125. descending = 0;
  126. }
  127. while (i < tablesize) {
  128. if ((descending) && (pts[i].x < input)) {
  129. /* table entry is less than measured*/
  130. /* value and table is descending, stop */
  131. break;
  132. } else if ((!descending) &&
  133. (pts[i].x > input)) {
  134. /* table entry is greater than measured*/
  135. /*value and table is ascending, stop */
  136. break;
  137. }
  138. i++;
  139. }
  140. if (i == 0) {
  141. *output = pts[0].y;
  142. } else if (i == tablesize) {
  143. *output = pts[tablesize - 1].y;
  144. } else {
  145. /* result is between search_index and search_index-1 */
  146. /* interpolate linearly */
  147. *output = (((s32)((pts[i].y - pts[i - 1].y) *
  148. (input - pts[i - 1].x)) /
  149. (pts[i].x - pts[i - 1].x)) +
  150. pts[i - 1].y);
  151. }
  152. return 0;
  153. }
  154. static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
  155. u16 adc_code,
  156. bool absolute,
  157. s64 *scale_voltage)
  158. {
  159. *scale_voltage = (adc_code - calib_graph->gnd);
  160. *scale_voltage *= calib_graph->dx;
  161. *scale_voltage = div64_s64(*scale_voltage, calib_graph->dy);
  162. if (absolute)
  163. *scale_voltage += calib_graph->dx;
  164. if (*scale_voltage < 0)
  165. *scale_voltage = 0;
  166. }
  167. static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
  168. const struct vadc_prescale_ratio *prescale,
  169. bool absolute, u16 adc_code,
  170. int *result_uv)
  171. {
  172. s64 voltage = 0, result = 0;
  173. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  174. voltage = voltage * prescale->den;
  175. result = div64_s64(voltage, prescale->num);
  176. *result_uv = result;
  177. return 0;
  178. }
  179. static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
  180. const struct vadc_prescale_ratio *prescale,
  181. bool absolute, u16 adc_code,
  182. int *result_mdec)
  183. {
  184. s64 voltage = 0;
  185. int ret;
  186. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  187. if (absolute)
  188. voltage = div64_s64(voltage, 1000);
  189. ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
  190. ARRAY_SIZE(adcmap_100k_104ef_104fb),
  191. voltage, result_mdec);
  192. if (ret)
  193. return ret;
  194. *result_mdec *= 1000;
  195. return 0;
  196. }
  197. static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
  198. const struct vadc_prescale_ratio *prescale,
  199. bool absolute,
  200. u16 adc_code, int *result_mdec)
  201. {
  202. s64 voltage = 0;
  203. u64 temp; /* Temporary variable for do_div */
  204. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  205. if (voltage > 0) {
  206. temp = voltage * prescale->den;
  207. do_div(temp, prescale->num * 2);
  208. voltage = temp;
  209. } else {
  210. voltage = 0;
  211. }
  212. voltage -= KELVINMIL_CELSIUSMIL;
  213. *result_mdec = voltage;
  214. return 0;
  215. }
  216. static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
  217. const struct vadc_prescale_ratio *prescale,
  218. bool absolute,
  219. u16 adc_code, int *result_mdec)
  220. {
  221. s64 voltage = 0, result = 0;
  222. qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
  223. voltage = voltage * prescale->den;
  224. voltage = div64_s64(voltage, prescale->num);
  225. voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
  226. voltage = (voltage + PMI_CHG_SCALE_2);
  227. result = div64_s64(voltage, 1000000);
  228. *result_mdec = result;
  229. return 0;
  230. }
  231. static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
  232. const struct vadc_prescale_ratio *prescale,
  233. const struct adc5_data *data,
  234. unsigned int factor)
  235. {
  236. s64 voltage, temp, adc_vdd_ref_mv = 1875;
  237. /*
  238. * The normal data range is between 0V to 1.875V. On cases where
  239. * we read low voltage values, the ADC code can go beyond the
  240. * range and the scale result is incorrect so we clamp the values
  241. * for the cases where the code represents a value below 0V
  242. */
  243. if (adc_code > VADC5_MAX_CODE)
  244. adc_code = 0;
  245. /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
  246. voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
  247. voltage = div64_s64(voltage, data->full_scale_code_volt);
  248. if (voltage > 0) {
  249. voltage *= prescale->den;
  250. temp = prescale->num * factor;
  251. voltage = div64_s64(voltage, temp);
  252. } else {
  253. voltage = 0;
  254. }
  255. return (int) voltage;
  256. }
  257. static int qcom_vadc_scale_hw_calib_volt(
  258. const struct vadc_prescale_ratio *prescale,
  259. const struct adc5_data *data,
  260. u16 adc_code, int *result_uv)
  261. {
  262. *result_uv = qcom_vadc_scale_code_voltage_factor(adc_code,
  263. prescale, data, 1);
  264. return 0;
  265. }
  266. static int qcom_vadc_scale_hw_calib_therm(
  267. const struct vadc_prescale_ratio *prescale,
  268. const struct adc5_data *data,
  269. u16 adc_code, int *result_mdec)
  270. {
  271. int voltage;
  272. voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
  273. prescale, data, 1000);
  274. /* Map voltage to temperature from look-up table */
  275. return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
  276. ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
  277. voltage, result_mdec);
  278. }
  279. static int qcom_vadc_scale_hw_calib_die_temp(
  280. const struct vadc_prescale_ratio *prescale,
  281. const struct adc5_data *data,
  282. u16 adc_code, int *result_mdec)
  283. {
  284. *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
  285. prescale, data, 2);
  286. *result_mdec -= KELVINMIL_CELSIUSMIL;
  287. return 0;
  288. }
  289. static int qcom_vadc_scale_hw_smb_temp(
  290. const struct vadc_prescale_ratio *prescale,
  291. const struct adc5_data *data,
  292. u16 adc_code, int *result_mdec)
  293. {
  294. *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code * 100,
  295. prescale, data, PMIC5_SMB_TEMP_SCALE_FACTOR);
  296. *result_mdec = PMIC5_SMB_TEMP_CONSTANT - *result_mdec;
  297. return 0;
  298. }
  299. static int qcom_vadc_scale_hw_chg5_temp(
  300. const struct vadc_prescale_ratio *prescale,
  301. const struct adc5_data *data,
  302. u16 adc_code, int *result_mdec)
  303. {
  304. *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
  305. prescale, data, 4);
  306. *result_mdec = PMIC5_CHG_TEMP_SCALE_FACTOR - *result_mdec;
  307. return 0;
  308. }
  309. int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
  310. const struct vadc_linear_graph *calib_graph,
  311. const struct vadc_prescale_ratio *prescale,
  312. bool absolute,
  313. u16 adc_code, int *result)
  314. {
  315. switch (scaletype) {
  316. case SCALE_DEFAULT:
  317. return qcom_vadc_scale_volt(calib_graph, prescale,
  318. absolute, adc_code,
  319. result);
  320. case SCALE_THERM_100K_PULLUP:
  321. case SCALE_XOTHERM:
  322. return qcom_vadc_scale_therm(calib_graph, prescale,
  323. absolute, adc_code,
  324. result);
  325. case SCALE_PMIC_THERM:
  326. return qcom_vadc_scale_die_temp(calib_graph, prescale,
  327. absolute, adc_code,
  328. result);
  329. case SCALE_PMI_CHG_TEMP:
  330. return qcom_vadc_scale_chg_temp(calib_graph, prescale,
  331. absolute, adc_code,
  332. result);
  333. default:
  334. return -EINVAL;
  335. }
  336. }
  337. EXPORT_SYMBOL(qcom_vadc_scale);
  338. int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
  339. const struct vadc_prescale_ratio *prescale,
  340. const struct adc5_data *data,
  341. u16 adc_code, int *result)
  342. {
  343. if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
  344. scaletype < SCALE_HW_CALIB_INVALID)) {
  345. pr_err("Invalid scale type %d\n", scaletype);
  346. return -EINVAL;
  347. }
  348. return scale_adc5_fn[scaletype].scale_fn(prescale, data,
  349. adc_code, result);
  350. }
  351. EXPORT_SYMBOL(qcom_adc5_hw_scale);
  352. int qcom_vadc_decimation_from_dt(u32 value)
  353. {
  354. if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
  355. value > VADC_DECIMATION_MAX)
  356. return -EINVAL;
  357. return __ffs64(value / VADC_DECIMATION_MIN);
  358. }
  359. EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
  360. MODULE_LICENSE("GPL v2");
  361. MODULE_DESCRIPTION("Qualcomm ADC common functionality");