sec_adc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. /*
  2. * sec_adc.c
  3. * Samsung Mobile Battery Driver
  4. *
  5. * Copyright (C) 2012 Samsung Electronics
  6. *
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/version.h>
  13. #include "sec_adc.h"
  14. #define DEBUG
  15. #if defined(CONFIG_SEC_KUNIT)
  16. #include <kunit/mock.h>
  17. #endif
  18. struct adc_list {
  19. const char *name;
  20. struct iio_channel *channel;
  21. bool is_used;
  22. int prev_value;
  23. };
  24. static DEFINE_MUTEX(adclock);
  25. static struct adc_list batt_adc_list[SEC_BAT_ADC_CHANNEL_NUM] = {
  26. {.name = "adc-cable"},
  27. {.name = "adc-bat-id"},
  28. {.name = "adc-temp"},
  29. {.name = "adc-temp-amb"},
  30. {.name = "adc-full"},
  31. {.name = "adc-volt"},
  32. {.name = "adc-chg-temp"},
  33. {.name = "adc-in-bat"},
  34. {.name = "adc-dischg"},
  35. {.name = "adc-dischg-ntc"},
  36. {.name = "adc-wpc-temp"},
  37. {.name = "adc-sub-chg-temp"},
  38. {.name = "adc-usb-temp"},
  39. {.name = "adc-sub-bat"},
  40. {.name = "adc-blkt-temp"},
  41. };
  42. static int adc_init_count;
  43. #if defined(CONFIG_SEC_KUNIT)
  44. int __mockable adc_read_type(struct device *dev, int channel, int batt_adc_type)
  45. #else
  46. int adc_read_type(struct device *dev, int channel, int batt_adc_type)
  47. #endif
  48. {
  49. int adc = -1;
  50. int ret = 0;
  51. int retry_cnt = RETRY_CNT;
  52. /* adc init retry because adc init was failed when probe time */
  53. if (!adc_init_count) {
  54. int i = 0;
  55. struct iio_channel *temp_adc;
  56. pr_err("%s: ADC init retry!!\n", __func__);
  57. for (i = 0; i < SEC_BAT_ADC_CHANNEL_NUM; i++) {
  58. temp_adc = iio_channel_get(dev, batt_adc_list[i].name);
  59. batt_adc_list[i].channel = temp_adc;
  60. batt_adc_list[i].is_used = !IS_ERR_OR_NULL(temp_adc);
  61. if (batt_adc_list[i].is_used)
  62. adc_init_count++;
  63. }
  64. }
  65. if (batt_adc_list[channel].is_used) {
  66. do {
  67. switch (batt_adc_type) {
  68. case SEC_BATTERY_ADC_RAW:
  69. ret = iio_read_channel_raw(batt_adc_list[channel].channel, &adc);
  70. break;
  71. default:
  72. /* SEC_BATTERY_ADC_PROCESSED */
  73. ret = iio_read_channel_processed(batt_adc_list[channel].channel, &adc);
  74. break;
  75. }
  76. retry_cnt--;
  77. } while ((retry_cnt > 0) && (adc < 0));
  78. } else {
  79. ret = 0;
  80. }
  81. if (retry_cnt <= 0) {
  82. pr_err("%s: Error in ADC\n", __func__);
  83. adc = batt_adc_list[channel].prev_value;
  84. } else {
  85. batt_adc_list[channel].prev_value = adc;
  86. }
  87. pr_debug("%s: [%d] ADC (type:%s) = %d\n", __func__, channel,
  88. (batt_adc_type ? "raw" : "proc."), adc);
  89. return adc;
  90. }
  91. int sec_bat_get_adc_data(struct device *dev, int adc_ch, int count, int batt_adc_type)
  92. {
  93. int adc_data = 0;
  94. int adc_max = 0;
  95. int adc_min = 0xFFFF;
  96. int adc_total = 0;
  97. int i = 0;
  98. if (count < 3)
  99. count = 3;
  100. for (i = 0; i < count; i++) {
  101. mutex_lock(&adclock);
  102. adc_data = adc_read_type(dev, adc_ch, batt_adc_type);
  103. mutex_unlock(&adclock);
  104. if (i != 0) {
  105. if (adc_data > adc_max)
  106. adc_max = adc_data;
  107. else if (adc_data < adc_min)
  108. adc_min = adc_data;
  109. } else {
  110. adc_max = adc_data;
  111. adc_min = adc_data;
  112. }
  113. adc_total += adc_data;
  114. }
  115. return (adc_total - adc_max - adc_min) / (count - 2);
  116. }
  117. EXPORT_SYMBOL(sec_bat_get_adc_data);
  118. int sec_bat_get_charger_type_adc(struct sec_battery_info *battery)
  119. {
  120. /* It is true something valid is connected to the device for charging.
  121. * By default this something is considered to be USB.
  122. */
  123. int result = SEC_BATTERY_CABLE_USB;
  124. int adc = 0;
  125. int i = 0;
  126. /* Do NOT check cable type when cable_switch_check() returns false
  127. * and keep current cable type
  128. */
  129. if (battery->pdata->cable_switch_check && !battery->pdata->cable_switch_check())
  130. return battery->cable_type;
  131. adc = sec_bat_get_adc_data(battery->dev, SEC_BAT_ADC_CHANNEL_CABLE_CHECK,
  132. battery->pdata->adc_check_count, battery->pdata->adc_read_type);
  133. /* Do NOT check cable type when cable_switch_normal() returns false
  134. * and keep current cable type
  135. */
  136. if (battery->pdata->cable_switch_normal && !battery->pdata->cable_switch_normal())
  137. return battery->cable_type;
  138. for (i = 0; i < SEC_BATTERY_CABLE_MAX; i++)
  139. if ((adc > battery->pdata->cable_adc_value[i].min) && (adc < battery->pdata->cable_adc_value[i].max))
  140. break;
  141. if (i >= SEC_BATTERY_CABLE_MAX)
  142. dev_err(battery->dev, "%s: default USB\n", __func__);
  143. else
  144. result = i;
  145. dev_dbg(battery->dev, "%s: result(%d), adc(%d)\n", __func__, result, adc);
  146. return result;
  147. }
  148. EXPORT_SYMBOL(sec_bat_get_charger_type_adc);
  149. bool sec_bat_convert_adc_to_val(int adc, int offset, sec_bat_adc_table_data_t *adc_table, int size, int *value)
  150. {
  151. int temp = 0;
  152. int low = 0;
  153. int high = 0;
  154. int mid = 0;
  155. if (size <= 0)
  156. return false;
  157. adc = (offset) ? (offset - adc) : (adc);
  158. if (adc_table[0].adc >= adc) {
  159. temp = adc_table[0].data;
  160. goto temp_by_adc_goto;
  161. } else if (adc_table[size-1].adc <= adc) {
  162. temp = adc_table[size-1].data;
  163. goto temp_by_adc_goto;
  164. }
  165. high = size - 1;
  166. while (low <= high) {
  167. mid = (low + high) / 2;
  168. if (adc_table[mid].adc > adc)
  169. high = mid - 1;
  170. else if (adc_table[mid].adc < adc)
  171. low = mid + 1;
  172. else {
  173. temp = adc_table[mid].data;
  174. goto temp_by_adc_goto;
  175. }
  176. }
  177. temp = adc_table[high].data;
  178. temp += ((adc_table[low].data - adc_table[high].data) *
  179. (adc - adc_table[high].adc)) /
  180. (adc_table[low].adc - adc_table[high].adc);
  181. temp_by_adc_goto:
  182. *value = temp;
  183. pr_debug("%s: Temp(%d), Temp-ADC(%d)\n", __func__, temp, adc);
  184. return true;
  185. }
  186. EXPORT_SYMBOL(sec_bat_convert_adc_to_val);
  187. int sec_bat_get_inbat_vol_by_adc(struct sec_battery_info *battery)
  188. {
  189. int inbat = 0;
  190. int inbat_adc;
  191. int low = 0;
  192. int high = 0;
  193. int mid = 0;
  194. const sec_bat_adc_table_data_t *inbat_adc_table;
  195. unsigned int inbat_adc_table_size;
  196. if (!battery->pdata->inbat_adc_table) {
  197. dev_err(battery->dev, "%s: not designed to read in-bat voltage\n", __func__);
  198. return -1;
  199. }
  200. inbat_adc_table = battery->pdata->inbat_adc_table;
  201. inbat_adc_table_size = battery->pdata->inbat_adc_table_size;
  202. inbat_adc = sec_bat_get_adc_data(battery->dev, SEC_BAT_ADC_CHANNEL_INBAT_VOLTAGE,
  203. battery->pdata->adc_check_count, battery->pdata->adc_read_type);
  204. if (inbat_adc <= 0)
  205. return inbat_adc;
  206. battery->inbat_adc = inbat_adc;
  207. if (inbat_adc_table[0].adc <= inbat_adc) {
  208. inbat = inbat_adc_table[0].data;
  209. goto inbat_by_adc_goto;
  210. } else if (inbat_adc_table[inbat_adc_table_size-1].adc >= inbat_adc) {
  211. inbat = inbat_adc_table[inbat_adc_table_size-1].data;
  212. goto inbat_by_adc_goto;
  213. }
  214. high = inbat_adc_table_size - 1;
  215. while (low <= high) {
  216. mid = (low + high) / 2;
  217. if (inbat_adc_table[mid].adc < inbat_adc)
  218. high = mid - 1;
  219. else if (inbat_adc_table[mid].adc > inbat_adc)
  220. low = mid + 1;
  221. else {
  222. inbat = inbat_adc_table[mid].data;
  223. goto inbat_by_adc_goto;
  224. }
  225. }
  226. inbat = inbat_adc_table[high].data;
  227. inbat +=
  228. ((inbat_adc_table[low].data - inbat_adc_table[high].data) *
  229. (inbat_adc - inbat_adc_table[high].adc)) /
  230. (inbat_adc_table[low].adc - inbat_adc_table[high].adc);
  231. if (inbat < 0)
  232. inbat = 0;
  233. inbat_by_adc_goto:
  234. dev_info(battery->dev, "%s: inbat(%d), inbat-ADC(%d)\n", __func__, inbat, inbat_adc);
  235. return inbat;
  236. }
  237. EXPORT_SYMBOL(sec_bat_get_inbat_vol_by_adc);
  238. bool sec_bat_check_vf_adc(struct sec_battery_info *battery)
  239. {
  240. int adc = 0;
  241. adc = sec_bat_get_adc_data(battery->dev,
  242. SEC_BAT_ADC_CHANNEL_BATID_CHECK,
  243. battery->pdata->adc_check_count,
  244. battery->pdata->adc_read_type);
  245. if (adc < 0) {
  246. dev_err(battery->dev, "%s: VF ADC error\n", __func__);
  247. adc = battery->check_adc_value;
  248. } else
  249. battery->check_adc_value = adc;
  250. if ((battery->check_adc_value <= battery->pdata->check_adc_max) &&
  251. (battery->check_adc_value >= battery->pdata->check_adc_min)) {
  252. return true;
  253. } else {
  254. dev_info(battery->dev, "%s: VF_ADC(%d) is out of range(min:%d, max:%d)\n",
  255. __func__, battery->check_adc_value, battery->pdata->check_adc_min, battery->pdata->check_adc_max);
  256. return false;
  257. }
  258. }
  259. EXPORT_SYMBOL(sec_bat_check_vf_adc);
  260. #if IS_ENABLED(CONFIG_DIRECT_CHARGING)
  261. int sec_bat_get_direct_chg_temp_adc(
  262. struct sec_battery_info *battery, int adc_data, int count, int check_type)
  263. {
  264. int temp = 0;
  265. int temp_adc;
  266. int low = 0;
  267. int high = 0;
  268. int mid = 0;
  269. const sec_bat_adc_table_data_t *temp_adc_table = {0 , };
  270. unsigned int temp_adc_table_size = 0;
  271. int offset = battery->pdata->dchg_thm_info.offset;
  272. if (check_type == SEC_BATTERY_TEMP_CHECK_FAKE)
  273. return FAKE_TEMP;
  274. temp_adc = (offset) ? (offset - adc_data) : (adc_data);
  275. if (temp_adc < 0)
  276. return 0;
  277. temp_adc_table = battery->pdata->dchg_thm_info.adc_table;
  278. temp_adc_table_size = battery->pdata->dchg_thm_info.adc_table_size;
  279. battery->pdata->dchg_thm_info.adc = temp_adc;
  280. if (temp_adc_table[0].adc >= temp_adc) {
  281. temp = temp_adc_table[0].data;
  282. goto direct_chg_temp_goto;
  283. } else if (temp_adc_table[temp_adc_table_size - 1].adc <= temp_adc) {
  284. temp = temp_adc_table[temp_adc_table_size - 1].data;
  285. goto direct_chg_temp_goto;
  286. }
  287. high = temp_adc_table_size - 1;
  288. while (low <= high) {
  289. mid = (low + high) / 2;
  290. if (temp_adc_table[mid].adc > temp_adc)
  291. high = mid - 1;
  292. else if (temp_adc_table[mid].adc < temp_adc)
  293. low = mid + 1;
  294. else {
  295. temp = temp_adc_table[mid].data;
  296. goto direct_chg_temp_goto;
  297. }
  298. }
  299. temp = temp_adc_table[high].data;
  300. temp += ((temp_adc_table[low].data - temp_adc_table[high].data) *
  301. (temp_adc - temp_adc_table[high].adc)) /
  302. (temp_adc_table[low].adc - temp_adc_table[high].adc);
  303. direct_chg_temp_goto:
  304. dev_info(battery->dev, "%s: temp(%d), direct-chg-temp-ADC(%d)\n", __func__, temp, adc_data);
  305. return temp;
  306. }
  307. EXPORT_SYMBOL(sec_bat_get_direct_chg_temp_adc);
  308. #endif
  309. void adc_init(struct platform_device *pdev, struct sec_battery_info *battery)
  310. {
  311. int i = 0;
  312. struct iio_channel *temp_adc;
  313. for (i = 0; i < SEC_BAT_ADC_CHANNEL_NUM; i++) {
  314. temp_adc = iio_channel_get(&pdev->dev, batt_adc_list[i].name);
  315. batt_adc_list[i].channel = temp_adc;
  316. batt_adc_list[i].is_used = !IS_ERR_OR_NULL(temp_adc);
  317. if (batt_adc_list[i].is_used)
  318. battery->adc_init_count++;
  319. }
  320. for (i = 0; i < SEC_BAT_ADC_CHANNEL_NUM; i++)
  321. pr_info("%s: %s - %s\n", __func__,
  322. batt_adc_list[i].name, batt_adc_list[i].is_used ? "used" : "not used");
  323. }
  324. EXPORT_SYMBOL(adc_init);
  325. void adc_exit(struct sec_battery_info *battery)
  326. {
  327. int i = 0;
  328. for (i = 0; i < SEC_BAT_ADC_CHANNEL_NUM; i++) {
  329. if (batt_adc_list[i].is_used)
  330. iio_channel_release(batt_adc_list[i].channel);
  331. }
  332. }
  333. EXPORT_SYMBOL(adc_exit);