/drivers/hwmon/m_adcproc.c

https://bitbucket.org/cresqo/cm7-p500-kernel · C · 474 lines · 387 code · 39 blank · 48 comment · 43 complexity · 96ad4dceebbd7daee89d7e7cc52a8ab2 MD5 · raw file

  1. /* Copyright (c) 2010, Code Aurora Forum. 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. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. * 02110-1301, USA.
  16. */
  17. #include <linux/kernel.h>
  18. #include <linux/m_adc.h>
  19. #define KELVINMIL_DEGMIL 273160
  20. static const struct adc_map_pt adcmap_batttherm[] = {
  21. {2020, -30},
  22. {1923, -20},
  23. {1796, -10},
  24. {1640, 0},
  25. {1459, 10},
  26. {1260, 20},
  27. {1159, 25},
  28. {1059, 30},
  29. {871, 40},
  30. {706, 50},
  31. {567, 60},
  32. {453, 70},
  33. {364, 80}
  34. };
  35. static const struct adc_map_pt adcmap_msmtherm[] = {
  36. {2150, -30},
  37. {2107, -20},
  38. {2037, -10},
  39. {1929, 0},
  40. {1776, 10},
  41. {1579, 20},
  42. {1467, 25},
  43. {1349, 30},
  44. {1108, 40},
  45. {878, 50},
  46. {677, 60},
  47. {513, 70},
  48. {385, 80},
  49. {287, 90},
  50. {215, 100},
  51. {186, 110},
  52. {107, 120}
  53. };
  54. static const struct adc_map_pt adcmap_ntcg104ef104fb[] = {
  55. {696483, -40960},
  56. {649148, -39936},
  57. {605368, -38912},
  58. {564809, -37888},
  59. {527215, -36864},
  60. {492322, -35840},
  61. {460007, -34816},
  62. {429982, -33792},
  63. {402099, -32768},
  64. {376192, -31744},
  65. {352075, -30720},
  66. {329714, -29696},
  67. {308876, -28672},
  68. {289480, -27648},
  69. {271417, -26624},
  70. {254574, -25600},
  71. {238903, -24576},
  72. {224276, -23552},
  73. {210631, -22528},
  74. {197896, -21504},
  75. {186007, -20480},
  76. {174899, -19456},
  77. {164521, -18432},
  78. {154818, -17408},
  79. {145744, -16384},
  80. {137265, -15360},
  81. {129307, -14336},
  82. {121866, -13312},
  83. {114896, -12288},
  84. {108365, -11264},
  85. {102252, -10240},
  86. {96499, -9216},
  87. {91111, -8192},
  88. {86055, -7168},
  89. {81308, -6144},
  90. {76857, -5120},
  91. {72660, -4096},
  92. {68722, -3072},
  93. {65020, -2048},
  94. {61538, -1024},
  95. {58261, 0},
  96. {55177, 1024},
  97. {52274, 2048},
  98. {49538, 3072},
  99. {46962, 4096},
  100. {44531, 5120},
  101. {42243, 6144},
  102. {40083, 7168},
  103. {38045, 8192},
  104. {36122, 9216},
  105. {34308, 10240},
  106. {32592, 11264},
  107. {30972, 12288},
  108. {29442, 13312},
  109. {27995, 14336},
  110. {26624, 15360},
  111. {25333, 16384},
  112. {24109, 17408},
  113. {22951, 18432},
  114. {21854, 19456},
  115. {20807, 20480},
  116. {19831, 21504},
  117. {18899, 22528},
  118. {18016, 23552},
  119. {17178, 24576},
  120. {16384, 25600},
  121. {15631, 26624},
  122. {14916, 27648},
  123. {14237, 28672},
  124. {13593, 29696},
  125. {12976, 30720},
  126. {12400, 31744},
  127. {11848, 32768},
  128. {11324, 33792},
  129. {10825, 34816},
  130. {10354, 35840},
  131. {9900, 36864},
  132. {9471, 37888},
  133. {9062, 38912},
  134. {8674, 39936},
  135. {8306, 40960},
  136. {7951, 41984},
  137. {7616, 43008},
  138. {7296, 44032},
  139. {6991, 45056},
  140. {6701, 46080},
  141. {6424, 47104},
  142. {6160, 48128},
  143. {5908, 49152},
  144. {5667, 50176},
  145. {5439, 51200},
  146. {5219, 52224},
  147. {5010, 53248},
  148. {4810, 54272},
  149. {4619, 55296},
  150. {4440, 56320},
  151. {4263, 57344},
  152. {4097, 58368},
  153. {3938, 59392},
  154. {3785, 60416},
  155. {3637, 61440},
  156. {3501, 62464},
  157. {3368, 63488},
  158. {3240, 64512},
  159. {3118, 65536},
  160. {2998, 66560},
  161. {2889, 67584},
  162. {2782, 68608},
  163. {2680, 69632},
  164. {2581, 70656},
  165. {2490, 71680},
  166. {2397, 72704},
  167. {2310, 73728},
  168. {2227, 74752},
  169. {2147, 75776},
  170. {2064, 76800},
  171. {1998, 77824},
  172. {1927, 78848},
  173. {1860, 79872},
  174. {1795, 80896},
  175. {1736, 81920},
  176. {1673, 82944},
  177. {1615, 83968},
  178. {1560, 84992},
  179. {1507, 86016},
  180. {1456, 87040},
  181. {1407, 88064},
  182. {1360, 89088},
  183. {1314, 90112},
  184. {1271, 91136},
  185. {1228, 92160},
  186. {1189, 93184},
  187. {1150, 94208},
  188. {1112, 95232},
  189. {1076, 96256},
  190. {1042, 97280},
  191. {1008, 98304},
  192. {976, 99328},
  193. {945, 100352},
  194. {915, 101376},
  195. {886, 102400},
  196. {859, 103424},
  197. {832, 104448},
  198. {807, 105472},
  199. {782, 106496},
  200. {756, 107520},
  201. {735, 108544},
  202. {712, 109568},
  203. {691, 110592},
  204. {670, 111616},
  205. {650, 112640},
  206. {631, 113664},
  207. {612, 114688},
  208. {594, 115712},
  209. {577, 116736},
  210. {560, 117760},
  211. {544, 118784},
  212. {528, 119808},
  213. {513, 120832},
  214. {498, 121856},
  215. {483, 122880},
  216. {470, 123904},
  217. {457, 124928},
  218. {444, 125952},
  219. {431, 126976},
  220. {419, 128000}
  221. };
  222. static int32_t
  223. adc_map_linear(const struct adc_map_pt *pts,
  224. uint32_t tablesize, int32_t input, int64_t *output)
  225. {
  226. bool descending = 1;
  227. uint32_t i = 0;
  228. if ((pts == NULL) || (output == NULL))
  229. return -EINVAL;
  230. /* Check if table is descending or ascending */
  231. if (tablesize > 1) {
  232. if (pts[0].x < pts[1].x)
  233. descending = 0;
  234. }
  235. while (i < tablesize) {
  236. if ((descending == 1) && (pts[i].x < input)) {
  237. /* table entry is less than measured
  238. value and table is descending, stop */
  239. break;
  240. } else if ((descending == 0) &&
  241. (pts[i].x > input)) {
  242. /* table entry is greater than measured
  243. value and table is ascending, stop */
  244. break;
  245. } else
  246. i++;
  247. }
  248. if (i == 0)
  249. *output = pts[0].y;
  250. else if (i == tablesize)
  251. *output = pts[tablesize-1].y;
  252. else {
  253. /* result is between search_index and search_index-1 */
  254. /* interpolate linearly */
  255. *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
  256. (input - pts[i-1].x))/
  257. (pts[i].x - pts[i-1].x))+
  258. pts[i-1].y);
  259. }
  260. return 0;
  261. }
  262. int32_t scale_default(int32_t adc_code,
  263. const struct adc_properties *adc_properties,
  264. const struct chan_properties *chan_properties,
  265. struct adc_chan_result *adc_chan_result)
  266. {
  267. bool negative_rawfromoffset = 0;
  268. int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
  269. if (!chan_properties->gain_numerator ||
  270. !chan_properties->gain_denominator)
  271. return -EINVAL;
  272. adc_chan_result->adc_code = adc_code;
  273. if (rawfromoffset < 0) {
  274. if (adc_properties->bipolar) {
  275. rawfromoffset = (rawfromoffset ^ -1) + 1;
  276. negative_rawfromoffset = 1;
  277. } else
  278. rawfromoffset = 0;
  279. }
  280. if (rawfromoffset >= 1 << adc_properties->bitresolution)
  281. rawfromoffset = (1 << adc_properties->bitresolution) - 1;
  282. adc_chan_result->measurement = (int64_t)rawfromoffset*
  283. chan_properties->adc_graph->dx*
  284. chan_properties->gain_denominator;
  285. /* do_div only perform positive integer division! */
  286. do_div(adc_chan_result->measurement, chan_properties->adc_graph->dy*
  287. chan_properties->gain_numerator);
  288. if (negative_rawfromoffset)
  289. adc_chan_result->measurement =
  290. (adc_chan_result->measurement ^ -1) + 1;
  291. /* Note: adc_chan_result->measurement is in the unit of
  292. * adc_properties.adc_reference. For generic channel processing,
  293. * channel measurement is a scale/ratio relative to the adc
  294. * reference input */
  295. adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
  296. return 0;
  297. }
  298. int32_t scale_batt_therm(int32_t adc_code,
  299. const struct adc_properties *adc_properties,
  300. const struct chan_properties *chan_properties,
  301. struct adc_chan_result *adc_chan_result)
  302. {
  303. scale_default(adc_code, adc_properties, chan_properties,
  304. adc_chan_result);
  305. /* convert mV ---> degC using the table */
  306. return adc_map_linear(
  307. adcmap_batttherm,
  308. sizeof(adcmap_batttherm)/sizeof(adcmap_batttherm[0]),
  309. adc_chan_result->physical,
  310. &adc_chan_result->physical);
  311. }
  312. int32_t scale_msm_therm(int32_t adc_code,
  313. const struct adc_properties *adc_properties,
  314. const struct chan_properties *chan_properties,
  315. struct adc_chan_result *adc_chan_result)
  316. {
  317. scale_default(adc_code, adc_properties, chan_properties,
  318. adc_chan_result);
  319. /* convert mV ---> degC using the table */
  320. return adc_map_linear(
  321. adcmap_msmtherm,
  322. sizeof(adcmap_msmtherm)/sizeof(adcmap_msmtherm[0]),
  323. adc_chan_result->physical,
  324. &adc_chan_result->physical);
  325. }
  326. int32_t scale_pmic_therm(int32_t adc_code,
  327. const struct adc_properties *adc_properties,
  328. const struct chan_properties *chan_properties,
  329. struct adc_chan_result *adc_chan_result)
  330. {
  331. /* 2mV/K */
  332. int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
  333. if (!chan_properties->gain_numerator ||
  334. !chan_properties->gain_denominator)
  335. return -EINVAL;
  336. adc_chan_result->adc_code = adc_code;
  337. if (rawfromoffset > 0) {
  338. if (rawfromoffset >= 1 << adc_properties->bitresolution)
  339. rawfromoffset = (1 << adc_properties->bitresolution)
  340. - 1;
  341. adc_chan_result->measurement = (int64_t)rawfromoffset*
  342. chan_properties->adc_graph->dx*
  343. chan_properties->gain_denominator*1000;
  344. do_div(adc_chan_result->measurement,
  345. chan_properties->adc_graph->dy*
  346. chan_properties->gain_numerator*2);
  347. } else {
  348. adc_chan_result->measurement = 0;
  349. }
  350. /* Note: adc_chan_result->measurement is in the unit of
  351. adc_properties.adc_reference */
  352. adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
  353. /* Change to .001 deg C */
  354. adc_chan_result->physical -= KELVINMIL_DEGMIL;
  355. adc_chan_result->measurement <<= 1;
  356. return 0;
  357. }
  358. /* Scales the ADC code to 0.001 degrees C using the map
  359. * table for the XO thermistor.
  360. */
  361. int32_t tdkntcgtherm(int32_t adc_code,
  362. const struct adc_properties *adc_properties,
  363. const struct chan_properties *chan_properties,
  364. struct adc_chan_result *adc_chan_result)
  365. {
  366. int32_t offset = chan_properties->adc_graph->offset,
  367. dy = chan_properties->adc_graph->dy,
  368. dx = chan_properties->adc_graph->dx,
  369. fullscale_calibrated_adc_code;
  370. uint32_t rt_r25;
  371. uint32_t num1, num2, denom;
  372. adc_chan_result->adc_code = adc_code;
  373. fullscale_calibrated_adc_code = dy + offset;
  374. /* The above is a short cut in math that would reduce a lot of
  375. computation whereas the below expression
  376. (adc_properties->adc_reference*dy+dx*offset+(dx>>1))/dx
  377. is a more generic formula when the 2 reference voltages are
  378. different than 0 and full scale voltage. */
  379. if ((dy == 0) || (dx == 0) ||
  380. (offset >= fullscale_calibrated_adc_code)) {
  381. return -EINVAL;
  382. } else {
  383. if (adc_code >= fullscale_calibrated_adc_code) {
  384. rt_r25 = (uint32_t)-1;
  385. } else if (adc_code <= offset) {
  386. rt_r25 = 0;
  387. } else {
  388. /* The formula used is (adc_code of current reading - offset)/
  389. * (the calibrated fullscale adc code - adc_code of current reading).
  390. * For this channel, at this time, chan_properties->gain_numerator =
  391. * chan_properties->gain_denominator = 1, so no need to incorporate
  392. * into the formula even though we could and multiply/divide by 1
  393. * which yields the same result but expensive on computation. */
  394. num1 = (adc_code - offset) << 14;
  395. num2 = (fullscale_calibrated_adc_code - adc_code) >> 1;
  396. denom = fullscale_calibrated_adc_code - adc_code;
  397. if ((int)denom <= 0)
  398. rt_r25 = 0x7FFFFFFF;
  399. else
  400. rt_r25 = (num1 + num2) / denom;
  401. }
  402. if (rt_r25 > 0x7FFFFFFF)
  403. rt_r25 = 0x7FFFFFFF;
  404. adc_map_linear(adcmap_ntcg104ef104fb,
  405. sizeof(adcmap_ntcg104ef104fb)/sizeof(adcmap_ntcg104ef104fb[0]),
  406. (int32_t)rt_r25, &adc_chan_result->physical);
  407. }
  408. return 0;
  409. }
  410. int32_t scale_xtern_chgr_cur(int32_t adc_code,
  411. const struct adc_properties *adc_properties,
  412. const struct chan_properties *chan_properties,
  413. struct adc_chan_result *adc_chan_result)
  414. {
  415. int32_t rawfromoffset = adc_code - chan_properties->adc_graph->offset;
  416. if (!chan_properties->gain_numerator ||
  417. !chan_properties->gain_denominator)
  418. return -EINVAL;
  419. adc_chan_result->adc_code = adc_code;
  420. if (rawfromoffset > 0) {
  421. if (rawfromoffset >= 1 << adc_properties->bitresolution)
  422. rawfromoffset = (1 << adc_properties->bitresolution)
  423. - 1;
  424. adc_chan_result->measurement = ((int64_t)rawfromoffset << 1)*
  425. chan_properties->adc_graph->dx*
  426. chan_properties->gain_denominator;
  427. do_div(adc_chan_result->measurement,
  428. chan_properties->adc_graph->dy*
  429. chan_properties->gain_numerator);
  430. } else {
  431. adc_chan_result->measurement = 0;
  432. }
  433. adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
  434. return 0;
  435. }