sec_direct_charger.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. /*
  2. * sec_direct_charger.c
  3. * Samsung Mobile Charger Driver
  4. *
  5. * Copyright (C) 2020 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. #define DEBUG
  13. #include "sec_direct_charger.h"
  14. #include "battery_logger.h"
  15. #if IS_ENABLED(CONFIG_SEC_ABC)
  16. #include <linux/sti/abc_common.h>
  17. #endif
  18. char *sec_direct_chg_mode_str[] = {
  19. "OFF", //SEC_DIRECT_CHG_MODE_DIRECT_OFF
  20. "CHECK_VBAT", //SEC_DIRECT_CHG_MODE_DIRECT_CHECK_VBAT
  21. "PRESET", //SEC_DIRECT_CHG_MODE_DIRECT_PRESET
  22. "ON_ADJUST", // SEC_DIRECT_CHG_MODE_DIRECT_ON_ADJUST
  23. "ON", //SEC_DIRECT_CHG_MODE_DIRECT_ON
  24. "DONE", //SEC_DIRECT_CHG_MODE_DIRECT_DONE
  25. "BYPASS", //SEC_DIRECT_CHG_MODE_DIRECT_BYPASS
  26. };
  27. char *sec_direct_charger_mode_str[] = {
  28. "Buck-Off",
  29. "Charging-Off",
  30. "Pass-Through",
  31. "Charging-On",
  32. "OTG-On",
  33. "OTG-Off",
  34. "UNO-On",
  35. "UNO-Off",
  36. "UNO-Only",
  37. "Not-Set",
  38. "Max",
  39. };
  40. #if IS_ENABLED(CONFIG_SEC_ABC)
  41. void sec_direct_abc_check(struct sec_direct_charger_info *charger)
  42. {
  43. if ((charger->charging_source != SEC_CHARGING_SOURCE_DIRECT) ||
  44. !is_pd_apdo_wire_type(charger->cable_type) || !charger->now_isApdo) {
  45. charger->abc_dc_current_cnt = 0;
  46. return;
  47. }
  48. if (charger->dc_input_current < 900) {
  49. if (charger->abc_dc_current_cnt <= ABC_DC_CNT)
  50. charger->abc_dc_current_cnt++;
  51. if (charger->abc_dc_current_cnt == ABC_DC_CNT)
  52. sec_abc_send_event("MODULE=battery@WARN=dc_current");
  53. } else {
  54. charger->abc_dc_current_cnt = 0;
  55. }
  56. }
  57. #else
  58. void sec_direct_abc_check(struct sec_direct_charger_info *charger) {}
  59. #endif
  60. void sec_direct_chg_monitor(struct sec_direct_charger_info *charger)
  61. {
  62. int ret = 0;
  63. union power_supply_propval dc_state = {0, };
  64. dc_state.strval = "NO_CHARGING";
  65. ret = psy_do_property(charger->pdata->direct_charger_name, get,
  66. POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_CHG_STATUS, dc_state);
  67. if (ret < 0) {
  68. pr_info("%s: Failed to get dc_chg status", __func__);
  69. } else if (charger->charging_source == SEC_CHARGING_SOURCE_DIRECT) {
  70. pr_info("%s: Src(%s), direct(%s), switching(%s), Imax(%dmA), Ichg(%dmA), dc_input(%dmA), dc_state(%s)\n",
  71. __func__, charger->charging_source ? "DIRECT" : "SWITCHING",
  72. sec_direct_charger_mode_str[charger->charger_mode_direct],
  73. sec_direct_charger_mode_str[charger->charger_mode_main],
  74. charger->input_current, charger->charging_current, charger->dc_input_current, dc_state.strval);
  75. }
  76. sec_direct_abc_check(charger);
  77. sb_pt_monitor(charger->pt, charger->charging_source);
  78. }
  79. static bool sec_direct_chg_set_direct_charge(
  80. struct sec_direct_charger_info *charger, unsigned int charger_mode)
  81. {
  82. union power_supply_propval value = {0,};
  83. if (charger->ta_alert_wa) {
  84. psy_do_property("battery", get,
  85. POWER_SUPPLY_EXT_PROP_DIRECT_TA_ALERT, value);
  86. charger->ta_alert_mode = value.intval;
  87. }
  88. if (charger->charger_mode_direct == charger_mode && !(charger->dc_retry_cnt) &&
  89. (charger->ta_alert_mode == OCP_NONE)) {
  90. pr_info("%s: charger_mode is same(%s)\n", __func__,
  91. sec_direct_charger_mode_str[charger->charger_mode_direct]);
  92. return false;
  93. }
  94. pr_info("%s: charger_mode(%s->%s)\n", __func__,
  95. sec_direct_charger_mode_str[charger->charger_mode_direct],
  96. sec_direct_charger_mode_str[charger_mode]);
  97. charger->charger_mode_direct = charger_mode;
  98. if (charger_mode == SEC_BAT_CHG_MODE_CHARGING ||
  99. charger_mode == SEC_BAT_CHG_MODE_PASS_THROUGH)
  100. value.intval = true;
  101. else
  102. value.intval = false;
  103. psy_do_property(charger->pdata->direct_charger_name, set,
  104. POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED, value);
  105. return true;
  106. }
  107. static bool sec_direct_chg_set_switching_charge(
  108. struct sec_direct_charger_info *charger, unsigned int charger_mode)
  109. {
  110. union power_supply_propval value = {0,};
  111. pr_info("%s: charger_mode(%s->%s)\n", __func__,
  112. sec_direct_charger_mode_str[charger->charger_mode_main],
  113. sec_direct_charger_mode_str[charger_mode]);
  114. if (charger_mode == SEC_BAT_CHG_MODE_PASS_THROUGH)
  115. charger_mode = SEC_BAT_CHG_MODE_CHARGING_OFF;
  116. charger->charger_mode_main = charger_mode;
  117. value.intval = charger_mode;
  118. psy_do_property(charger->pdata->main_charger_name, set,
  119. POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED, value);
  120. return true;
  121. }
  122. static bool sec_direct_chg_check_temp(struct sec_direct_charger_info *charger)
  123. {
  124. union power_supply_propval value = {0,};
  125. int batt_temp = 0, mix_limit = 0;
  126. #if IS_ENABLED(CONFIG_DUAL_BATTERY)
  127. int sub_batt_temp = 0;
  128. #endif
  129. /* check mix limit */
  130. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_MIX_LIMIT, value);
  131. mix_limit = value.intval;
  132. if (mix_limit) {
  133. pr_info("%s: S/C was selected! mix_limit(%d)\n", __func__, value.intval);
  134. return true;
  135. }
  136. if (charger->pdata->dchg_dc_in_swelling) {
  137. /* do not check batt temp for DC */
  138. return false;
  139. }
  140. value.intval = THM_INFO_BAT;
  141. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_TEMP_CHECK_TYPE, value);
  142. if (value.intval) {
  143. /* check Tbat temperature */
  144. psy_do_property("battery", get, POWER_SUPPLY_PROP_TEMP, value);
  145. batt_temp = value.intval;
  146. if (batt_temp <= charger->pdata->dchg_temp_low_threshold ||
  147. batt_temp >= charger->pdata->dchg_temp_high_threshold) {
  148. pr_info("%s: S/C was selected! Tbat(%d)\n", __func__, batt_temp);
  149. return true;
  150. }
  151. #if IS_ENABLED(CONFIG_DUAL_BATTERY)
  152. /* check Tsub temperature */
  153. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_SUB_TEMP, value);
  154. sub_batt_temp = value.intval;
  155. if (sub_batt_temp <= charger->pdata->dchg_temp_low_threshold ||
  156. sub_batt_temp >= charger->pdata->dchg_temp_high_threshold) {
  157. pr_info("%s: S/C was selected! Tsub(%d)\n", __func__, sub_batt_temp);
  158. return true;
  159. }
  160. #endif
  161. } else {
  162. pr_info("%s: Temperature Control Disabled!\n", __func__);
  163. }
  164. return false;
  165. }
  166. static bool sec_direct_chg_check_event(
  167. struct sec_direct_charger_info *charger, unsigned int current_event, unsigned int tx_retry_case)
  168. {
  169. union power_supply_propval value = {0,};
  170. int batt_volt = 0;
  171. int dc_status = POWER_SUPPLY_STATUS_DISCHARGING;
  172. if (charger->pdata->dchg_dc_in_swelling) {
  173. if (current_event & SEC_BAT_CURRENT_EVENT_HIGH_TEMP_SWELLING) {
  174. /* check Tbat temperature */
  175. psy_do_property("battery", get, POWER_SUPPLY_PROP_VOLTAGE_NOW, value);
  176. batt_volt = value.intval / 1000;
  177. psy_do_property(charger->pdata->direct_charger_name, get,
  178. POWER_SUPPLY_PROP_STATUS, value);
  179. dc_status = value.intval;
  180. if ((batt_volt >= charger->pdata->swelling_high_rechg_voltage) &&
  181. (dc_status != POWER_SUPPLY_STATUS_CHARGING) &&
  182. !charger->pdata->chgen_over_swell_rechg_vol) {
  183. pr_info("%s : volt(%d) rechg_voltage(%d) dc_status(%d)\n", __func__,
  184. batt_volt, charger->pdata->swelling_high_rechg_voltage, dc_status);
  185. return true;
  186. }
  187. if (charger->dc_rcp) {
  188. pr_info("%s : swelling and rcp(%d)\n", __func__,
  189. charger->dc_rcp);
  190. return true;
  191. }
  192. } else
  193. charger->dc_rcp = false;
  194. if (current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_MODE)
  195. return true;
  196. } else {
  197. if (current_event & SEC_BAT_CURRENT_EVENT_SWELLING_MODE)
  198. return true;
  199. }
  200. if (current_event & SEC_BAT_CURRENT_EVENT_HV_DISABLE ||
  201. current_event & SEC_BAT_CURRENT_EVENT_SIOP_LIMIT ||
  202. current_event & SEC_BAT_CURRENT_EVENT_SEND_UVDM ||
  203. (current_event & SEC_BAT_CURRENT_EVENT_DC_ERR && charger->ta_alert_mode == OCP_NONE))
  204. return true;
  205. if (tx_retry_case & SEC_BAT_TX_RETRY_MISALIGN ||
  206. tx_retry_case & SEC_BAT_TX_RETRY_OCP)
  207. return true;
  208. return false;
  209. }
  210. static bool sec_direct_fpdo_dc_check(struct sec_direct_charger_info *charger)
  211. {
  212. union power_supply_propval value = {0,};
  213. int voltage = 0;
  214. /* Works only in FPDO DC */
  215. if (charger->cable_type != SEC_BATTERY_CABLE_FPDO_DC)
  216. return false;
  217. /* check fdpo dc start vbat condition */
  218. psy_do_property("battery", get, POWER_SUPPLY_PROP_VOLTAGE_AVG, value);
  219. voltage = value.intval / 1000;
  220. if (voltage < charger->pdata->fpdo_dc_min_vbat) {
  221. pr_info("%s: FPDO DC, S/C was selected! low vbat(%dmV)\n", __func__, voltage);
  222. return true;
  223. }
  224. if (charger->charging_source == SEC_CHARGING_SOURCE_SWITCHING) {
  225. /* check fdpo dc vbat max condition */
  226. #if IS_ENABLED(CONFIG_DUAL_BATTERY)
  227. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_VOLTAGE_PACK_MAIN, value);
  228. voltage = value.intval;
  229. if (voltage >= charger->pdata->fpdo_dc_max_main_vbat) {
  230. pr_info("%s: FPDO DC, S/C was selected! high main vbat(%dmV/%dmV)\n", __func__,
  231. voltage, charger->pdata->fpdo_dc_max_main_vbat);
  232. return true;
  233. }
  234. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_VOLTAGE_PACK_SUB, value);
  235. voltage = value.intval;
  236. if (voltage >= charger->pdata->fpdo_dc_max_sub_vbat) {
  237. pr_info("%s: FPDO DC, S/C was selected! high sub vbat(%dmV/%dmV)\n", __func__,
  238. voltage, charger->pdata->fpdo_dc_max_sub_vbat);
  239. return true;
  240. }
  241. #else
  242. psy_do_property("battery", get, POWER_SUPPLY_PROP_VOLTAGE_NOW, value);
  243. voltage = value.intval / 1000;
  244. if (voltage >= charger->pdata->fpdo_dc_max_vbat) {
  245. pr_info("%s: FPDO DC, S/C was selected! high vbat(%dmV)\n", __func__, voltage);
  246. return true;
  247. }
  248. #endif
  249. }
  250. /* check fpdo dc thermal condition check */
  251. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_FPDO_DC_THERMAL_CHECK, value);
  252. if (value.intval) {
  253. pr_info("%s: S/C was selected! FPDO_DC_THERMAL_CHECK(%d)\n", __func__, value.intval);
  254. return true;
  255. }
  256. return false;
  257. }
  258. static int sec_direct_chg_check_charging_source(struct sec_direct_charger_info *charger)
  259. {
  260. union power_supply_propval value = {0,};
  261. int ret = SEC_CHARGING_SOURCE_SWITCHING;
  262. int has_apdo = 0, cable_type = 0, voltage_avg = 0;
  263. unsigned int current_event = 0, lrp_chg_src = SEC_CHARGING_SOURCE_DIRECT, tx_retry_case = 0;
  264. int flash_state = 0, mst_en = 0, abnormal_ta = 0;
  265. #if IS_ENABLED(CONFIG_MTK_CHARGER)
  266. int mtk_fg_init = 0;
  267. #endif
  268. pr_info("%s: dc_retry_cnt(%d)\n", __func__, charger->dc_retry_cnt);
  269. if (charger->dc_err) {
  270. if (charger->ta_alert_wa) {
  271. psy_do_property("battery", get,
  272. POWER_SUPPLY_EXT_PROP_DIRECT_TA_ALERT, value);
  273. charger->ta_alert_mode = value.intval;
  274. }
  275. pr_info("%s: dc_err(%d), ta_alert_mode(%d)\n", __func__, charger->dc_err, charger->ta_alert_mode);
  276. value.intval = SEC_BAT_CURRENT_EVENT_DC_ERR;
  277. psy_do_property("battery", set, POWER_SUPPLY_EXT_PROP_CURRENT_EVENT, value);
  278. if (!charger->ta_alert_wa || (charger->ta_alert_mode == OCP_NONE)) {
  279. pr_info("%s: S/C was selected! ta_alert_mode(%d)\n", __func__, charger->ta_alert_mode);
  280. goto end_chg_src;
  281. }
  282. }
  283. if ((charger->charger_mode != SEC_BAT_CHG_MODE_CHARGING) &&
  284. (charger->charger_mode != SEC_BAT_CHG_MODE_PASS_THROUGH)) {
  285. pr_info("%s: S/C was selected! charger_mode(%d)\n", __func__, charger->charger_mode);
  286. goto end_chg_src;
  287. }
  288. #if defined(CONFIG_WIRELESS_TX_MODE)
  289. /* check TX enable*/
  290. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_WIRELESS_TX_ENABLE, value);
  291. charger->wc_tx_enable = value.intval;
  292. if (charger->wc_tx_enable) {
  293. pr_info("@TX_Mode %s: Source Switching charger during Tx mode\n", __func__);
  294. goto end_chg_src;
  295. }
  296. #endif
  297. if (sec_direct_chg_check_temp(charger))
  298. goto end_chg_src;
  299. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_LRP_CHG_SRC, value);
  300. lrp_chg_src = value.intval;
  301. if (lrp_chg_src == SEC_CHARGING_SOURCE_SWITCHING) {
  302. pr_info("%s: S/C was selected! lrp_chg_src is S/C\n", __func__);
  303. goto end_chg_src;
  304. }
  305. /* check current event */
  306. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_CURRENT_EVENT, value);
  307. current_event = value.intval;
  308. psy_do_property("wireless", get, POWER_SUPPLY_EXT_PROP_WIRELESS_TX_RETRY_CASE, value);
  309. tx_retry_case = value.intval;
  310. if (sec_direct_chg_check_event(charger, current_event, tx_retry_case)) {
  311. pr_info("%s: S/C was selected! current_event(0x%x), tx_retry_case(0x%x)\n",
  312. __func__, current_event, tx_retry_case);
  313. goto end_chg_src;
  314. }
  315. /* check test mode */
  316. if (charger->test_mode_source == SEC_CHARGING_SOURCE_SWITCHING) {
  317. pr_info("%s: S/C was selected! tese_mode_source(%d)\n", __func__, charger->test_mode_source);
  318. goto end_chg_src;
  319. }
  320. /* check apdo */
  321. psy_do_property("battery", get, POWER_SUPPLY_PROP_ONLINE, value);
  322. cable_type = value.intval;
  323. if (!is_pd_apdo_wire_type(charger->cable_type) || !is_pd_apdo_wire_type(cable_type)) {
  324. pr_info("%s: S/C was selected! Not APDO(%d, %d)\n",
  325. __func__, charger->cable_type, cable_type);
  326. goto end_chg_src;
  327. }
  328. /* check battery->status */
  329. psy_do_property("battery", get, POWER_SUPPLY_PROP_STATUS, value);
  330. charger->batt_status = value.intval;
  331. if (charger->batt_status == POWER_SUPPLY_STATUS_FULL ||
  332. charger->batt_status == POWER_SUPPLY_STATUS_NOT_CHARGING ||
  333. charger->batt_status == POWER_SUPPLY_STATUS_DISCHARGING) {
  334. pr_info("%s: S/C was selected! battery->status(%d)\n",
  335. __func__, charger->batt_status);
  336. goto end_chg_src;
  337. }
  338. /* check charging status */
  339. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_DIRECT_HAS_APDO, value);
  340. has_apdo = value.intval;
  341. if (charger->cable_type == SEC_BATTERY_CABLE_FPDO_DC)
  342. has_apdo = 1;
  343. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_FLASH_STATE, value);
  344. flash_state = value.intval; /* check only for MTK */
  345. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_MST_EN, value);
  346. mst_en = value.intval; /* check only for MTK */
  347. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_ABNORMAL_TA, value);
  348. abnormal_ta = value.intval;
  349. #if IS_ENABLED(CONFIG_MTK_CHARGER)
  350. psy_do_property("battery", get, POWER_SUPPLY_EXT_PROP_MTK_FG_INIT, value);
  351. mtk_fg_init = value.intval; /* check only for MTK */
  352. #endif
  353. psy_do_property("battery", get, POWER_SUPPLY_PROP_CAPACITY, value);
  354. charger->capacity = value.intval;
  355. if (charger->direct_chg_done || (charger->capacity >= charger->pdata->dchg_end_soc)
  356. || !has_apdo || charger->store_mode || flash_state || mst_en || abnormal_ta
  357. #if IS_ENABLED(CONFIG_MTK_CHARGER)
  358. || !mtk_fg_init
  359. #endif
  360. ) {
  361. pr_info("%s: S/C was selected! dc_done(%s), SoC(%d), has_apdo(%d) mst_en(%d) abnormal_ta(%d)\n",
  362. __func__, charger->direct_chg_done ? "TRUE" : "FALSE",
  363. charger->capacity, has_apdo, mst_en, abnormal_ta);
  364. goto end_chg_src;
  365. }
  366. if (charger->vbat_min_src != LOW_VBAT_OFF) {
  367. psy_do_property("battery", get,
  368. POWER_SUPPLY_PROP_VOLTAGE_AVG, value);
  369. voltage_avg = value.intval / 1000;
  370. if (voltage_avg < charger->pdata->dchg_min_vbat) {
  371. pr_info("%s: S/C was selected! low vbat(%dmV)\n",
  372. __func__, voltage_avg);
  373. charger->vbat_min_src = LOW_VBAT_SET;
  374. goto end_chg_src;
  375. }
  376. charger->vbat_min_src = LOW_VBAT_OFF;
  377. }
  378. if (sec_direct_fpdo_dc_check(charger))
  379. goto end_chg_src;
  380. ret = SEC_CHARGING_SOURCE_DIRECT;
  381. end_chg_src:
  382. if (charger->charging_source != ret) {
  383. store_battery_log("CHG_SRC:SOC(%d),BATT_ST(%d),VOLT_AVG(%d),CHG_MODE(%d)",
  384. charger->capacity, charger->batt_status, voltage_avg, charger->charger_mode);
  385. store_battery_log("CHG_SRC:SRC(%s),CT(%d,%d),CURR_EV(0x%x),DC_ERR(%d),TX(%d),HAS_APDO(%d),DC_DONE(%d)",
  386. ret ? "DIRECT" : "SWITCHING", cable_type, charger->cable_type, current_event, charger->dc_err,
  387. charger->wc_tx_enable, has_apdo, charger->direct_chg_done);
  388. }
  389. return sb_pt_check_chg_src(charger->pt, ret);
  390. }
  391. static int sec_direct_chg_set_charging_source(struct sec_direct_charger_info *charger,
  392. unsigned int charger_mode, int charging_source)
  393. {
  394. union power_supply_propval value = {0,};
  395. mutex_lock(&charger->charger_mutex);
  396. if (charging_source == SEC_CHARGING_SOURCE_DIRECT) {
  397. sec_direct_chg_set_switching_charge(charger, SEC_BAT_CHG_MODE_BUCK_OFF);
  398. sec_direct_chg_set_direct_charge(charger, charger_mode);
  399. value.intval = SEC_INPUT_VOLTAGE_APDO;
  400. psy_do_property("battery", set,
  401. POWER_SUPPLY_EXT_PROP_DIRECT_FIXED_PDO, value);
  402. } else {
  403. if (charger->ta_alert_wa) {
  404. psy_do_property("battery", get,
  405. POWER_SUPPLY_EXT_PROP_DIRECT_TA_ALERT, value);
  406. charger->ta_alert_mode = value.intval;
  407. }
  408. /* Must Charging-off the DC charger before changing voltage */
  409. /* to prevent reverse-current into TA */
  410. sec_direct_chg_set_direct_charge(charger, SEC_BAT_CHG_MODE_CHARGING_OFF);
  411. if (charger->cable_type == SEC_BATTERY_CABLE_FPDO_DC &&
  412. charger->charging_source == SEC_CHARGING_SOURCE_DIRECT)
  413. msleep(100);
  414. value.intval = SEC_INPUT_VOLTAGE_9V;
  415. psy_do_property("battery", set,
  416. POWER_SUPPLY_EXT_PROP_DIRECT_FIXED_PDO, value);
  417. sec_direct_chg_set_switching_charge(charger, charger_mode);
  418. }
  419. charger->charging_source = charging_source;
  420. mutex_unlock(&charger->charger_mutex);
  421. return 0;
  422. }
  423. static void sec_direct_chg_set_charge(struct sec_direct_charger_info *charger, unsigned int charger_mode)
  424. {
  425. int charging_source;
  426. charger->charger_mode = charger_mode;
  427. switch (charger->charger_mode) {
  428. case SEC_BAT_CHG_MODE_BUCK_OFF:
  429. case SEC_BAT_CHG_MODE_CHARGING_OFF:
  430. case SEC_BAT_CHG_MODE_PASS_THROUGH:
  431. charger->is_charging = false;
  432. break;
  433. case SEC_BAT_CHG_MODE_CHARGING:
  434. charger->is_charging = true;
  435. break;
  436. }
  437. charging_source = sec_direct_chg_check_charging_source(charger);
  438. sec_direct_chg_set_charging_source(charger, charger_mode, charging_source);
  439. }
  440. static void sec_direct_chg_do_dc_fullcharged(struct sec_direct_charger_info *charger) {
  441. int charging_source;
  442. pr_info("%s: called\n", __func__);
  443. charger->direct_chg_done = true;
  444. charging_source = sec_direct_chg_check_charging_source(charger);
  445. sec_direct_chg_set_charging_source(charger, charger->charger_mode, charging_source);
  446. }
  447. static int sec_direct_chg_set_input_current(struct sec_direct_charger_info *charger,
  448. enum power_supply_property psp, int input_current) {
  449. union power_supply_propval value = {0,};
  450. pr_info("%s: called(%dmA)\n", __func__, input_current);
  451. value.intval = input_current;
  452. psy_do_property(charger->pdata->main_charger_name, set,
  453. POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, value);
  454. /* direct charger input current is based on charging current */
  455. return 0;
  456. }
  457. static int sec_direct_chg_set_charging_current(struct sec_direct_charger_info *charger,
  458. enum power_supply_property psp, int charging_current) {
  459. union power_supply_propval value = {0,};
  460. int charging_source, cable_type;
  461. psy_do_property("battery", get,
  462. POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_MODE, value);
  463. charger->now_isApdo = value.intval;
  464. psy_do_property("battery", get,
  465. POWER_SUPPLY_PROP_ONLINE, value);
  466. cable_type = value.intval;
  467. pr_info("%s: called(%dmA) now_isApdo(%d) cable_type(%d)\n",
  468. __func__, charging_current, charger->now_isApdo, cable_type);
  469. /* main charger */
  470. value.intval = charging_current;
  471. psy_do_property(charger->pdata->main_charger_name, set,
  472. POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, value);
  473. charger->dc_charging_current = charging_current;
  474. charger->dc_input_current = charger->dc_charging_current / 2;
  475. charging_source = sec_direct_chg_check_charging_source(charger);
  476. value.intval = charger->dc_input_current;
  477. /* direct charger */
  478. if (is_pd_apdo_wire_type(cable_type)) {
  479. psy_do_property(charger->pdata->direct_charger_name, set,
  480. POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, value);
  481. sec_direct_chg_set_charging_source(charger, charger->charger_mode, charging_source);
  482. }
  483. return 0;
  484. }
  485. static void sec_direct_chg_set_initial_status(struct sec_direct_charger_info *charger)
  486. {
  487. union power_supply_propval value = {0,};
  488. if (charger->dc_err) {
  489. value.intval = SEC_BAT_CURRENT_EVENT_DC_ERR;
  490. psy_do_property("battery", set,
  491. POWER_SUPPLY_EXT_PROP_CURRENT_EVENT_CLEAR, value);
  492. }
  493. charger->direct_chg_done = false;
  494. charger->dc_charging_current = charger->pdata->dchg_min_current;
  495. charger->dc_input_current = charger->dc_charging_current / 2;
  496. charger->dc_err = false;
  497. charger->dc_retry_cnt = 0;
  498. charger->dc_rcp = false;
  499. charger->test_mode_source = SEC_CHARGING_SOURCE_DIRECT;
  500. charger->vbat_min_src = LOW_VBAT_NONE;
  501. }
  502. static int sec_direct_chg_get_property(struct power_supply *psy,
  503. enum power_supply_property psp,
  504. union power_supply_propval *val)
  505. {
  506. struct sec_direct_charger_info *charger = power_supply_get_drvdata(psy);
  507. enum power_supply_ext_property ext_psp = (enum power_supply_ext_property) psp;
  508. union power_supply_propval value = {0,};
  509. int ret = 0;
  510. ret = sb_pt_psy_get_property(charger->pt, psp, val);
  511. if (ret) {
  512. pr_info("%s: prevent event for pt(ret = %d)", __func__, ret);
  513. return 0;
  514. }
  515. value.intval = val->intval;
  516. switch ((int)psp) {
  517. case POWER_SUPPLY_PROP_STATUS:
  518. if (charger->charging_source == SEC_CHARGING_SOURCE_DIRECT) {
  519. psy_do_property(charger->pdata->direct_charger_name, get, psp, value);
  520. } else {
  521. psy_do_property(charger->pdata->main_charger_name, get, psp, value);
  522. }
  523. val->intval = value.intval;
  524. break;
  525. case POWER_SUPPLY_PROP_HEALTH:
  526. if (charger->charging_source == SEC_CHARGING_SOURCE_DIRECT) {
  527. psy_do_property(charger->pdata->direct_charger_name, get, psp, value);
  528. if (value.intval == POWER_SUPPLY_EXT_HEALTH_DC_ERR) {
  529. charger->dc_retry_cnt++;
  530. if (charger->dc_retry_cnt > 2) {
  531. charger->dc_err = true;
  532. } else
  533. charger->dc_err = false;
  534. } else {
  535. charger->dc_err = false;
  536. charger->dc_retry_cnt = 0;
  537. }
  538. } else {
  539. psy_do_property(charger->pdata->main_charger_name, get, psp, value);
  540. charger->dc_retry_cnt = 0;
  541. }
  542. val->intval = value.intval;
  543. break;
  544. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: /* get input current which was set */
  545. psy_do_property(charger->pdata->main_charger_name, get, psp, value);
  546. if (is_direct_chg_mode_on(charger->direct_chg_mode)) {
  547. // NEED to CHECK
  548. val->intval = charger->input_current;
  549. } else {
  550. val->intval = value.intval;
  551. }
  552. break;
  553. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: /* get charge current which was set */
  554. psy_do_property(charger->pdata->main_charger_name, get, psp, value);
  555. if (is_direct_chg_mode_on(charger->direct_chg_mode)) {
  556. // NEED to CHECK
  557. val->intval = charger->charging_current;
  558. } else {
  559. val->intval = value.intval;
  560. }
  561. break;
  562. case POWER_SUPPLY_PROP_TEMP:
  563. psy_do_property(charger->pdata->direct_charger_name, get, psp, value);
  564. val->intval = value.intval;
  565. break;
  566. case POWER_SUPPLY_EXT_PROP_MIN ... POWER_SUPPLY_EXT_PROP_MAX:
  567. switch (ext_psp) {
  568. case POWER_SUPPLY_EXT_PROP_MONITOR_WORK:
  569. psy_do_property(charger->pdata->main_charger_name, get, ext_psp, value);
  570. if (is_pd_apdo_wire_type(charger->cable_type)) {
  571. psy_do_property(charger->pdata->direct_charger_name, get, ext_psp, value);
  572. val->intval = charger->vbat_min_src;
  573. } else
  574. val->intval = LOW_VBAT_NONE;
  575. sec_direct_chg_monitor(charger);
  576. break;
  577. case POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_MODE:
  578. val->intval = charger->direct_chg_mode;
  579. break;
  580. case POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC:
  581. psy_do_property(charger->pdata->main_charger_name, get,
  582. POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED, value);
  583. if (value.intval == SEC_BAT_CHG_MODE_CHARGING)
  584. val->intval = true;
  585. else
  586. val->intval = false;
  587. break;
  588. case POWER_SUPPLY_EXT_PROP_DIRECT_DONE:
  589. val->intval = charger->direct_chg_done;
  590. break;
  591. case POWER_SUPPLY_EXT_PROP_MEASURE_INPUT:
  592. psy_do_property(charger->pdata->direct_charger_name, get, ext_psp, value);
  593. val->intval = value.intval;
  594. break;
  595. case POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_CHG_STATUS:
  596. ret = psy_do_property(charger->pdata->direct_charger_name, get, ext_psp, value);
  597. val->strval = value.strval;
  598. break;
  599. case POWER_SUPPLY_EXT_PROP_CHANGE_CHARGING_SOURCE:
  600. val->intval = charger->test_mode_source;
  601. break;
  602. case POWER_SUPPLY_EXT_PROP_DIRECT_CONSTANT_CHARGE_VOLTAGE:
  603. psy_do_property(charger->pdata->direct_charger_name, get,
  604. POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, value);
  605. val->intval = value.intval;
  606. break;
  607. case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE:
  608. case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE_TA_VOL:
  609. ret = psy_do_property(charger->pdata->direct_charger_name, get, ext_psp, value);
  610. val->intval = value.intval;
  611. break;
  612. case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_VOLTAGE:
  613. ret = psy_do_property(charger->pdata->direct_charger_name, get,
  614. ext_psp, value);
  615. val->intval = value.intval;
  616. break;
  617. case POWER_SUPPLY_EXT_PROP_CHARGER_IC_NAME:
  618. psy_do_property(charger->pdata->main_charger_name, get, ext_psp, value);
  619. pr_info("%s: CHARGER_IC_NAME: %s\n", __func__, value.strval);
  620. val->strval = value.strval;
  621. break;
  622. case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_OCP:
  623. ret = psy_do_property(charger->pdata->direct_charger_name, get,
  624. ext_psp, value);
  625. val->intval = value.intval;
  626. break;
  627. case POWER_SUPPLY_EXT_PROP_DC_OP_MODE:
  628. case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_VBUS:
  629. ret = psy_do_property(charger->pdata->direct_charger_name, get,
  630. ext_psp, value);
  631. val->intval = value.intval;
  632. break;
  633. case POWER_SUPPLY_EXT_PROP_CHARGER_MODE_DIRECT:
  634. val->intval = charger->charger_mode_direct;
  635. break;
  636. case POWER_SUPPLY_EXT_PROP_DCHG_READ_BATP_BATN:
  637. ret = psy_do_property(charger->pdata->direct_charger_name, get,
  638. ext_psp, value);
  639. val->intval = value.intval;
  640. break;
  641. default:
  642. ret = psy_do_property(charger->pdata->main_charger_name, get, ext_psp, value);
  643. val->intval = value.intval;
  644. return ret;
  645. }
  646. break;
  647. default:
  648. ret = psy_do_property(charger->pdata->main_charger_name, get, psp, value);
  649. val->intval = value.intval;
  650. return ret;
  651. }
  652. return ret;
  653. }
  654. static int sec_direct_chg_set_property(struct power_supply *psy,
  655. enum power_supply_property psp,
  656. const union power_supply_propval *val)
  657. {
  658. struct sec_direct_charger_info *charger = power_supply_get_drvdata(psy);
  659. enum power_supply_ext_property ext_psp = (enum power_supply_ext_property) psp;
  660. union power_supply_propval value = {0,};
  661. int prev_val;
  662. int ret = 0;
  663. ret = sb_pt_psy_set_property(charger->pt, psp, val);
  664. if (ret) {
  665. pr_info("%s: prevent event for pt(ret = %d)", __func__, ret);
  666. return 0;
  667. }
  668. value.intval = val->intval;
  669. switch ((int)psp) {
  670. case POWER_SUPPLY_PROP_STATUS:
  671. psy_do_property(charger->pdata->main_charger_name, set,
  672. psp, value);
  673. charger->batt_status = val->intval;
  674. pr_info("%s: batt status(%d)\n", __func__, charger->batt_status);
  675. break;
  676. case POWER_SUPPLY_PROP_ONLINE:
  677. prev_val = charger->cable_type;
  678. charger->cable_type = val->intval;
  679. if (charger->cable_type == SEC_BATTERY_CABLE_NONE) {
  680. sec_direct_chg_set_initial_status(charger);
  681. }
  682. #if IS_ENABLED(CONFIG_DUAL_BATTERY)
  683. /* Dual Battery featured model turn on the ADC block during all charging not only DC */
  684. value.intval = (charger->cable_type == SEC_BATTERY_CABLE_NONE) ? 0 : 1;
  685. psy_do_property(charger->pdata->direct_charger_name, set,
  686. POWER_SUPPLY_EXT_PROP_DIRECT_ADC_CTRL, value);
  687. #endif
  688. /* main charger */
  689. value.intval = val->intval;
  690. psy_do_property(charger->pdata->main_charger_name, set,
  691. psp, value);
  692. /* direct charger */
  693. if (is_pd_apdo_wire_type(charger->cable_type)) {
  694. charger->direct_chg_mode = SEC_DIRECT_CHG_MODE_DIRECT_CHECK_VBAT;
  695. value.intval = 1;
  696. psy_do_property(charger->pdata->direct_charger_name, set,
  697. psp, value);
  698. } else {
  699. value.intval = 0;
  700. psy_do_property(charger->pdata->direct_charger_name, set,
  701. psp, value);
  702. }
  703. break;
  704. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  705. charger->input_current = val->intval;
  706. sec_direct_chg_set_input_current(charger, psp, charger->input_current);
  707. break;
  708. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
  709. charger->charging_current = val->intval;
  710. sec_direct_chg_set_charging_current(charger, psp, charger->charging_current);
  711. break;
  712. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
  713. charger->float_voltage = val->intval;
  714. psy_do_property(charger->pdata->main_charger_name, set,
  715. psp, value);
  716. break;
  717. case POWER_SUPPLY_EXT_PROP_MIN ... POWER_SUPPLY_EXT_PROP_MAX:
  718. switch (ext_psp) {
  719. case POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_MODE:
  720. if (val->intval >= SEC_DIRECT_CHG_MODE_MAX) {
  721. pr_info("%s: abnormal direct_chg_mode(%d)\n", __func__, val->intval);
  722. } else {
  723. if (!charger->direct_chg_done) {
  724. pr_info("%s: direct_chg_mode:%s(%d)->%s(%d)\n", __func__,
  725. sec_direct_chg_mode_str[charger->direct_chg_mode], charger->direct_chg_mode,
  726. sec_direct_chg_mode_str[val->intval], val->intval);
  727. charger->direct_chg_mode = val->intval;
  728. if (charger->direct_chg_mode == SEC_DIRECT_CHG_MODE_DIRECT_OFF)
  729. charger->charger_mode_direct = SEC_BAT_CHG_MODE_CHARGING_OFF;
  730. }
  731. }
  732. break;
  733. case POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC:
  734. #if 0
  735. if (val->intval)
  736. sec_direct_chg_check_set_charge(charger, charger->charger_mode,
  737. SEC_BAT_CHG_MODE_BUCK_OFF, SEC_BAT_CHG_MODE_CHARGING);
  738. else
  739. sec_direct_chg_check_set_charge(charger, charger->charger_mode,
  740. SEC_BAT_CHG_MODE_CHARGING, SEC_BAT_CHG_MODE_CHARGING_OFF);
  741. #endif
  742. break;
  743. case POWER_SUPPLY_EXT_PROP_DIRECT_DONE:
  744. pr_info("%s: POWER_SUPPLY_EXT_PROP_DIRECT_DONE(%d)\n", __func__, val->intval);
  745. if (val->intval)
  746. sec_direct_chg_do_dc_fullcharged(charger);
  747. break;
  748. case POWER_SUPPLY_EXT_PROP_CURRENT_MEASURE:
  749. psy_do_property(charger->pdata->main_charger_name, set,
  750. ext_psp, value);
  751. break;
  752. case POWER_SUPPLY_EXT_PROP_DIRECT_WDT_CONTROL:
  753. psy_do_property(charger->pdata->direct_charger_name, set,
  754. ext_psp, value);
  755. break;
  756. case POWER_SUPPLY_EXT_PROP_DIRECT_CONSTANT_CHARGE_VOLTAGE:
  757. psy_do_property(charger->pdata->direct_charger_name, set,
  758. POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, value);
  759. break;
  760. case POWER_SUPPLY_EXT_PROP_DIRECT_CURRENT_MAX:
  761. psy_do_property(charger->pdata->direct_charger_name, set,
  762. ext_psp, value);
  763. break;
  764. case POWER_SUPPLY_EXT_PROP_DIRECT_CONSTANT_CHARGE_VOLTAGE_MAX:
  765. psy_do_property(charger->pdata->direct_charger_name, set,
  766. POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, value);
  767. break;
  768. case POWER_SUPPLY_EXT_PROP_DIRECT_ADC_CTRL:
  769. psy_do_property(charger->pdata->direct_charger_name, set,
  770. ext_psp, value);
  771. break;
  772. case POWER_SUPPLY_EXT_PROP_DIRECT_CLEAR_ERR:
  773. /* If SRCCAP is changed by Src, clear DC err variables */
  774. charger->dc_err = false;
  775. charger->dc_retry_cnt = 0;
  776. if (val->intval) {
  777. value.intval = SEC_BAT_CURRENT_EVENT_DC_ERR;
  778. psy_do_property("battery", set,
  779. POWER_SUPPLY_EXT_PROP_CURRENT_EVENT_CLEAR, value);
  780. }
  781. pr_info("%s: POWER_SUPPLY_EXT_PROP_DIRECT_CLEAR_ERR\n",
  782. __func__);
  783. break;
  784. case POWER_SUPPLY_EXT_PROP_CHANGE_CHARGING_SOURCE:
  785. pr_info("%s: POWER_SUPPLY_EXT_PROP_CHANGE_CHARGING_SOURCE(%d, %d)\n",
  786. __func__, val->strval[0], val->strval[1]);
  787. if (val->strval[0] == SEC_STORE_MODE)
  788. charger->store_mode = true;
  789. if (is_pd_apdo_wire_type(charger->cable_type)) {
  790. charger->test_mode_source = val->strval[1];
  791. if (charger->test_mode_source == SEC_CHARGING_SOURCE_DIRECT)
  792. charger->test_mode_source = sec_direct_chg_check_charging_source(charger);
  793. sec_direct_chg_set_charging_source(charger, charger->charger_mode, charger->test_mode_source);
  794. } else {
  795. pr_info("%s: block to set charging_source (cable:%d, mode:%d, test:%d, store:%d)\n",
  796. __func__, charger->cable_type, charger->charger_mode,
  797. charger->test_mode_source, charger->store_mode);
  798. }
  799. break;
  800. case POWER_SUPPLY_EXT_PROP_REFRESH_CHARGING_SOURCE:
  801. if (is_pd_apdo_wire_type(charger->cable_type)) {
  802. int charging_source;
  803. charging_source = sec_direct_chg_check_charging_source(charger);
  804. sec_direct_chg_set_charging_source(charger, charger->charger_mode, charging_source);
  805. }
  806. break;
  807. case POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED:
  808. sec_direct_chg_set_charge(charger, val->intval);
  809. break;
  810. case POWER_SUPPLY_EXT_PROP_DC_INITIALIZE:
  811. sec_direct_chg_set_initial_status(charger);
  812. break;
  813. case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE:
  814. case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE_TA_VOL:
  815. ret = psy_do_property(charger->pdata->direct_charger_name, set, ext_psp, value);
  816. break;
  817. case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_VOLTAGE:
  818. pr_info("%s: POWER_SUPPLY_EXT_PROP_D2D_REVERSE_VOLTAGE\n", __func__);
  819. psy_do_property(charger->pdata->direct_charger_name, set,
  820. psp, value);
  821. break;
  822. case POWER_SUPPLY_EXT_PROP_DC_OP_MODE:
  823. case POWER_SUPPLY_EXT_PROP_ADC_MODE:
  824. ret = psy_do_property(charger->pdata->direct_charger_name, set, ext_psp, value);
  825. break;
  826. case POWER_SUPPLY_EXT_PROP_OTG_VBUS_CTRL:
  827. pr_info("%s: OTG_CONTROL(%d)\n", __func__, val->intval);
  828. if (val->intval) {
  829. value.intval = 1000000;/* 1000mA */
  830. psy_do_property(charger->pdata->direct_charger_name, set,
  831. POWER_SUPPLY_EXT_PROP_DC_VIN_OVERCURRENT, value);
  832. value.intval = POWER_SUPPLY_DC_REVERSE_BYP;/* Reverse bypass mode */
  833. psy_do_property(charger->pdata->direct_charger_name, set,
  834. POWER_SUPPLY_EXT_PROP_DC_REVERSE_MODE, value);
  835. } else {
  836. value.intval = POWER_SUPPLY_DC_REVERSE_STOP;/* Stop reverse mode */
  837. psy_do_property(charger->pdata->direct_charger_name, set,
  838. POWER_SUPPLY_EXT_PROP_DC_REVERSE_MODE, value);
  839. }
  840. break;
  841. case POWER_SUPPLY_EXT_PROP_DC_RCP:
  842. charger->dc_rcp = val->intval;
  843. break;
  844. default:
  845. ret = psy_do_property(charger->pdata->main_charger_name, set, ext_psp, value);
  846. return ret;
  847. }
  848. break;
  849. default:
  850. ret = psy_do_property(charger->pdata->main_charger_name, set, psp, value);
  851. return ret;
  852. }
  853. return ret;
  854. }
  855. #ifdef CONFIG_OF
  856. static int sec_direct_charger_parse_dt(struct device *dev,
  857. struct sec_direct_charger_info *charger)
  858. {
  859. struct device_node *np = dev->of_node;
  860. if (!np) {
  861. pr_err("%s: np NULL\n", __func__);
  862. return 1;
  863. }
  864. sb_of_parse_str_dt(np, "charger,battery_name", charger->pdata, battery_name);
  865. sb_of_parse_str_dt(np, "charger,main_charger", charger->pdata, main_charger_name);
  866. sb_of_parse_str_dt(np, "charger,direct_charger", charger->pdata, direct_charger_name);
  867. sb_of_parse_u32_dt(np, "charger,dchg_min_current", charger->pdata, dchg_min_current, SEC_DIRECT_CHG_MIN_IOUT);
  868. sb_of_parse_u32_dt(np, "charger,dchg_min_vbat", charger->pdata, dchg_min_vbat, SEC_DIRECT_CHG_MIN_VBAT);
  869. sb_of_parse_u32_dt(np, "charger,fpdo_dc_min_vbat", charger->pdata, fpdo_dc_min_vbat, FPDO_DC_MIN_VBAT);
  870. sb_of_parse_u32_dt(np, "charger,fpdo_dc_max_vbat", charger->pdata, fpdo_dc_max_vbat, FPDO_DC_MAX_VBAT);
  871. #if IS_ENABLED(CONFIG_DUAL_BATTERY)
  872. sb_of_parse_u32_dt(np, "charger,fpdo_dc_max_main_vbat",
  873. charger->pdata, fpdo_dc_max_main_vbat, FPDO_DC_MAX_VBAT);
  874. sb_of_parse_u32_dt(np, "charger,fpdo_dc_max_sub_vbat", charger->pdata, fpdo_dc_max_sub_vbat, FPDO_DC_MAX_VBAT);
  875. #endif
  876. sb_of_parse_u32_dt(np, "charger,end_soc", charger->pdata, dchg_end_soc, 95);
  877. sb_of_parse_bool_dt(np, "charger,ta_alert_wa", charger, ta_alert_wa);
  878. np = of_find_node_by_name(NULL, "battery");
  879. if (!np) {
  880. pr_info("%s: np NULL\n", __func__);
  881. return 1;
  882. }
  883. sb_of_parse_bool_dt(np, "battery,dchg_dc_in_swelling", charger->pdata, dchg_dc_in_swelling);
  884. sb_of_parse_u32_dt(np, "battery,wire_normal_warm_thresh",
  885. charger->pdata, dchg_temp_high_threshold, 420);
  886. sb_of_parse_u32_dt(np, "battery,wire_cool1_normal_thresh",
  887. charger->pdata, dchg_temp_low_threshold, 180);
  888. sb_of_parse_u32_dt(np, "battery,swelling_high_rechg_voltage",
  889. charger->pdata, swelling_high_rechg_voltage, 4050);
  890. sb_of_parse_bool_dt(np, "battery,chgen_over_swell_rechg_vol", charger->pdata, chgen_over_swell_rechg_vol);
  891. return 0;
  892. }
  893. #else
  894. static int sec_direct_charger_parse_dt(struct device *dev,
  895. struct sec_direct_charger_info *charger)
  896. {
  897. return 0;
  898. }
  899. #endif /* CONFIG_OF */
  900. static enum power_supply_property sec_direct_charger_props[] = {
  901. POWER_SUPPLY_PROP_ONLINE,
  902. };
  903. static const struct power_supply_desc sec_direct_charger_power_supply_desc = {
  904. .name = "sec-direct-charger",
  905. .type = POWER_SUPPLY_TYPE_UNKNOWN,
  906. .properties = sec_direct_charger_props,
  907. .num_properties = ARRAY_SIZE(sec_direct_charger_props),
  908. .get_property = sec_direct_chg_get_property,
  909. .set_property = sec_direct_chg_set_property,
  910. };
  911. static int sec_direct_charger_probe(struct platform_device *pdev)
  912. {
  913. struct sec_direct_charger_info *charger;
  914. struct sec_direct_charger_platform_data *pdata = NULL;
  915. struct power_supply_config direct_charger_cfg = {};
  916. int ret = 0;
  917. pr_info("%s: SEC Direct-Charger Driver Loading\n", __func__);
  918. charger = kzalloc(sizeof(*charger), GFP_KERNEL);
  919. if (!charger)
  920. return -ENOMEM;
  921. if (pdev->dev.of_node) {
  922. pdata = devm_kzalloc(&pdev->dev,
  923. sizeof(struct sec_direct_charger_platform_data),
  924. GFP_KERNEL);
  925. if (!pdata) {
  926. dev_err(&pdev->dev, "Failed to allocate memory\n");
  927. ret = -ENOMEM;
  928. goto err_charger_free;
  929. }
  930. charger->pdata = pdata;
  931. if (sec_direct_charger_parse_dt(&pdev->dev, charger)) {
  932. dev_err(&pdev->dev,
  933. "%s: Failed to get sec-direct-charger dt\n", __func__);
  934. ret = -EINVAL;
  935. goto err_pdata_free;
  936. }
  937. } else {
  938. pdata = dev_get_platdata(&pdev->dev);
  939. charger->pdata = pdata;
  940. }
  941. /* init direct charger variables */
  942. charger->direct_chg_done = false;
  943. charger->direct_chg_mode = SEC_DIRECT_CHG_MODE_DIRECT_OFF;
  944. charger->cable_type = SEC_BATTERY_CABLE_NONE;
  945. charger->charger_mode = SEC_BAT_CHG_MODE_CHARGING_OFF;
  946. charger->charger_mode_direct = SEC_BAT_CHG_MODE_CHARGING_OFF;
  947. charger->charger_mode_main = SEC_BAT_CHG_MODE_CHARGING_OFF;
  948. charger->test_mode_source = SEC_CHARGING_SOURCE_DIRECT;
  949. charger->wc_tx_enable = false;
  950. charger->now_isApdo = false;
  951. charger->store_mode = false;
  952. charger->vbat_min_src = LOW_VBAT_NONE;
  953. #if IS_ENABLED(CONFIG_SEC_ABC)
  954. charger->abc_dc_current_cnt = 0;
  955. #endif
  956. platform_set_drvdata(pdev, charger);
  957. charger->dev = &pdev->dev;
  958. direct_charger_cfg.drv_data = charger;
  959. charger->ta_alert_mode = OCP_NONE;
  960. mutex_init(&charger->charger_mutex);
  961. charger->pt = sb_pt_init(charger->dev);
  962. if (IS_ERR(charger->pt)) {
  963. ret = PTR_ERR(charger->pt);
  964. dev_info(charger->dev, "%s: unused pass through (ret = %d)\n", __func__, ret);
  965. charger->pt = NULL;
  966. }
  967. charger->psy_chg = power_supply_register(&pdev->dev,
  968. &sec_direct_charger_power_supply_desc, &direct_charger_cfg);
  969. if (IS_ERR(charger->psy_chg)) {
  970. ret = PTR_ERR(charger->psy_chg);
  971. dev_err(charger->dev,
  972. "%s: Failed to Register psy_chg(%d)\n", __func__, ret);
  973. goto err_power_supply_register;
  974. }
  975. sec_chg_set_dev_init(SC_DEV_SEC_DIR_CHG);
  976. pr_info("%s: SEC Direct-Charger Driver Loaded(%s, %s)\n",
  977. __func__, charger->pdata->main_charger_name, charger->pdata->direct_charger_name);
  978. return 0;
  979. err_power_supply_register:
  980. mutex_destroy(&charger->charger_mutex);
  981. err_pdata_free:
  982. kfree(pdata);
  983. err_charger_free:
  984. kfree(charger);
  985. return ret;
  986. }
  987. static int sec_direct_charger_remove(struct platform_device *pdev)
  988. {
  989. struct sec_direct_charger_info *charger = platform_get_drvdata(pdev);
  990. pr_info("%s: ++\n", __func__);
  991. power_supply_unregister(charger->psy_chg);
  992. mutex_destroy(&charger->charger_mutex);
  993. dev_dbg(charger->dev, "%s: End\n", __func__);
  994. kfree(charger->pdata);
  995. kfree(charger);
  996. pr_info("%s: --\n", __func__);
  997. return 0;
  998. }
  999. static int sec_direct_charger_suspend(struct device *dev)
  1000. {
  1001. return 0;
  1002. }
  1003. static int sec_direct_charger_resume(struct device *dev)
  1004. {
  1005. return 0;
  1006. }
  1007. static void sec_direct_charger_shutdown(struct platform_device *pdev)
  1008. {
  1009. struct sec_direct_charger_info *charger = platform_get_drvdata(pdev);
  1010. union power_supply_propval value = {0,};
  1011. pr_info("%s: ++\n", __func__);
  1012. value.intval = false;
  1013. psy_do_property(charger->pdata->direct_charger_name, set,
  1014. POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED, value);
  1015. value.intval = SEC_INPUT_VOLTAGE_5V;
  1016. psy_do_property("battery", set,
  1017. POWER_SUPPLY_EXT_PROP_DIRECT_FIXED_PDO, value);
  1018. pr_info("%s: --\n", __func__);
  1019. }
  1020. #ifdef CONFIG_OF
  1021. static struct of_device_id sec_direct_charger_dt_ids[] = {
  1022. { .compatible = "samsung,sec-direct-charger" },
  1023. { }
  1024. };
  1025. MODULE_DEVICE_TABLE(of, sec_direct_charger_dt_ids);
  1026. #endif /* CONFIG_OF */
  1027. static const struct dev_pm_ops sec_direct_charger_pm_ops = {
  1028. .suspend = sec_direct_charger_suspend,
  1029. .resume = sec_direct_charger_resume,
  1030. };
  1031. static struct platform_driver sec_direct_charger_driver = {
  1032. .driver = {
  1033. .name = "sec-direct-charger",
  1034. .owner = THIS_MODULE,
  1035. .pm = &sec_direct_charger_pm_ops,
  1036. #ifdef CONFIG_OF
  1037. .of_match_table = sec_direct_charger_dt_ids,
  1038. #endif
  1039. },
  1040. .probe = sec_direct_charger_probe,
  1041. .remove = sec_direct_charger_remove,
  1042. .shutdown = sec_direct_charger_shutdown,
  1043. };
  1044. static int __init sec_direct_charger_init(void)
  1045. {
  1046. pr_info("%s: \n", __func__);
  1047. return platform_driver_register(&sec_direct_charger_driver);
  1048. }
  1049. static void __exit sec_direct_charger_exit(void)
  1050. {
  1051. platform_driver_unregister(&sec_direct_charger_driver);
  1052. }
  1053. device_initcall_sync(sec_direct_charger_init);
  1054. module_exit(sec_direct_charger_exit);
  1055. MODULE_DESCRIPTION("Samsung Direct Charger Driver");
  1056. MODULE_AUTHOR("Samsung Electronics");
  1057. MODULE_LICENSE("GPL");