sb_full_soc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * sb_full_soc.c
  3. * Samsung Mobile Battery Full SoC Module
  4. *
  5. * Copyright (C) 2023 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/of.h>
  13. #include <linux/slab.h>
  14. #include <linux/mutex.h>
  15. #include <linux/device.h>
  16. #include <linux/module.h>
  17. #include <linux/platform_device.h>
  18. #include "sb_full_soc.h"
  19. #include "sec_battery.h"
  20. #include "battery_logger.h"
  21. struct sb_full_soc {
  22. int full_capacity;
  23. unsigned int full_cap_event;
  24. bool is_eu_eco_rechg;
  25. bool eu_eco_rechg_state;
  26. sec_battery_recharge_condition_t old_recharge_condition_type;
  27. unsigned int old_recharge_condition_soc;
  28. bool eu_eco_chg_done;
  29. struct mutex lock;
  30. struct wakeup_source *ws;
  31. struct delayed_work eu_eco_work;
  32. struct sec_battery_info *battery;
  33. };
  34. enum {
  35. SB_FULL_CAP_EVENT_NONE = 0,
  36. SB_FULL_CAP_EVENT_HIGHSOC,
  37. SB_FULL_CAP_EVENT_SLEEP,
  38. SB_FULL_CAP_EVENT_OPTION,
  39. };
  40. #define MAX_CAP_EVENT_STR 16
  41. #define DEF_ECO_RECHG_DIF 5
  42. #define DEF_RECHG_SOC_DIF 2
  43. static int conv_full_cap_event_value(const char *str)
  44. {
  45. if (str == NULL)
  46. return SB_FULL_CAP_EVENT_NONE;
  47. if (!strncmp(str, "HIGHSOC", MAX_CAP_EVENT_STR))
  48. return SB_FULL_CAP_EVENT_HIGHSOC;
  49. if (!strncmp(str, "SLEEP", MAX_CAP_EVENT_STR))
  50. return SB_FULL_CAP_EVENT_SLEEP;
  51. if (!strncmp(str, "OPTION", MAX_CAP_EVENT_STR))
  52. return SB_FULL_CAP_EVENT_OPTION;
  53. return SB_FULL_CAP_EVENT_NONE;
  54. }
  55. static const char *conv_full_cap_str(unsigned int val)
  56. {
  57. switch (val) {
  58. case SB_FULL_CAP_EVENT_HIGHSOC:
  59. return "HIGHSOC";
  60. case SB_FULL_CAP_EVENT_SLEEP:
  61. return "SLEEP";
  62. case SB_FULL_CAP_EVENT_OPTION:
  63. return "OPTION";
  64. }
  65. return "NONE";
  66. }
  67. int get_full_capacity(struct sb_full_soc *fs)
  68. {
  69. if (fs == NULL)
  70. return 100;
  71. return fs->full_capacity;
  72. }
  73. EXPORT_SYMBOL(get_full_capacity);
  74. static void set_full_capacity(struct sb_full_soc *fs, int new_cap)
  75. {
  76. if (fs == NULL)
  77. return;
  78. fs->full_capacity = new_cap;
  79. }
  80. bool is_full_capacity(struct sb_full_soc *fs)
  81. {
  82. if (fs == NULL)
  83. return false;
  84. return ((fs->full_capacity > 0) && (fs->full_capacity < 100));
  85. }
  86. EXPORT_SYMBOL(is_full_capacity);
  87. static void set_full_cap_event(struct sb_full_soc *fs, unsigned int new_cap_event)
  88. {
  89. if (fs == NULL)
  90. return;
  91. fs->full_cap_event = new_cap_event;
  92. }
  93. static unsigned int get_full_cap_event(struct sb_full_soc *fs)
  94. {
  95. if (fs == NULL)
  96. return 0;
  97. return fs->full_cap_event;
  98. }
  99. static bool is_full_cap_event_highsoc(struct sb_full_soc *fs)
  100. {
  101. if (fs == NULL)
  102. return false;
  103. return (fs->full_cap_event == SB_FULL_CAP_EVENT_HIGHSOC);
  104. }
  105. static void set_eu_eco_rechg(struct sb_full_soc *fs, bool enable)
  106. {
  107. if (fs == NULL)
  108. return;
  109. fs->eu_eco_rechg_state = enable;
  110. }
  111. bool is_eu_eco_rechg(struct sb_full_soc *fs)
  112. {
  113. if (fs == NULL)
  114. return false;
  115. return fs->is_eu_eco_rechg;
  116. }
  117. EXPORT_SYMBOL(is_eu_eco_rechg);
  118. bool check_eu_eco_full_status(struct sec_battery_info *battery)
  119. {
  120. struct sb_full_soc *fs = battery->fs;
  121. if (fs == NULL)
  122. return false;
  123. if ((!fs->is_eu_eco_rechg) ||
  124. (battery->status != POWER_SUPPLY_STATUS_FULL)) {
  125. fs->eu_eco_chg_done = false;
  126. return false;
  127. }
  128. if (battery->capacity >= 100) {
  129. fs->eu_eco_chg_done = true;
  130. } else if (fs->eu_eco_chg_done) {
  131. fs->eu_eco_chg_done = false;
  132. if ((battery->is_recharging) ||
  133. (battery->charging_mode == SEC_BATTERY_CHARGING_2ND)) {
  134. pr_info("%s: fixed the 2nd fullcharged!!!(%d, %d)\n",
  135. __func__, battery->is_recharging, battery->charging_mode);
  136. return true;
  137. }
  138. }
  139. return false;
  140. }
  141. EXPORT_SYMBOL(check_eu_eco_full_status);
  142. static void enable_eu_eco_rechg(struct sec_battery_info *battery)
  143. {
  144. battery->pdata->recharge_condition_type = SEC_BATTERY_RECHARGE_CONDITION_SOC;
  145. battery->pdata->recharge_condition_soc = 100 - DEF_ECO_RECHG_DIF;
  146. }
  147. static void disable_eu_eco_rechg(struct sec_battery_info *battery)
  148. {
  149. struct sb_full_soc *fs = battery->fs;
  150. battery->pdata->recharge_condition_type = fs->old_recharge_condition_type;
  151. battery->pdata->recharge_condition_soc = fs->old_recharge_condition_soc;
  152. }
  153. bool check_eu_eco_rechg_ui_condition(struct sec_battery_info *battery)
  154. {
  155. if (battery->pdata->recharge_condition_type & SEC_BATTERY_RECHARGE_CONDITION_SOC)
  156. return (battery->capacity <= battery->pdata->recharge_condition_soc);
  157. return false;
  158. }
  159. EXPORT_SYMBOL(check_eu_eco_rechg_ui_condition);
  160. static void eu_eco_work(struct work_struct *work)
  161. {
  162. struct sb_full_soc *fs = container_of(work, struct sb_full_soc, eu_eco_work.work);
  163. struct sec_battery_info *battery = fs->battery;
  164. union power_supply_propval value = {0, };
  165. pr_info("%s: start (%d, %d, %d, %d)\n",
  166. __func__,
  167. fs->eu_eco_rechg_state, fs->is_eu_eco_rechg,
  168. battery->status, battery->capacity);
  169. mutex_lock(&fs->lock);
  170. if (fs->is_eu_eco_rechg == fs->eu_eco_rechg_state)
  171. goto end_work;
  172. if ((battery->status != POWER_SUPPLY_STATUS_FULL) ||
  173. (battery->capacity >= 100))
  174. goto update_state;
  175. if (fs->eu_eco_rechg_state) {
  176. pr_info("%s : Update fg scale to %d%%\n", __func__, battery->capacity);
  177. value.intval = 99;
  178. psy_do_property(battery->pdata->fuelgauge_name, set,
  179. POWER_SUPPLY_PROP_CHARGE_FULL, value);
  180. } else {
  181. sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_CHARGING);
  182. battery->is_recharging = false;
  183. battery->charging_mode = SEC_BATTERY_CHARGING_1ST;
  184. if (battery->pdata->change_FV_after_full)
  185. sec_vote(battery->fv_vote, VOTER_FULL_CHARGE, false, battery->pdata->chg_float_voltage);
  186. sec_vote(battery->chgen_vote, VOTER_CABLE, true, SEC_BAT_CHG_MODE_CHARGING);
  187. sec_vote(battery->topoff_vote, VOTER_FULL_CHARGE, false, 0);
  188. sec_vote(battery->chgen_vote, VOTER_FULL_CHARGE, false, 0);
  189. pr_info("%s: battery status full -> charging, Cap(%d)\n",
  190. __func__, battery->capacity);
  191. value.intval = POWER_SUPPLY_STATUS_CHARGING;
  192. psy_do_property(battery->pdata->wireless_charger_name, set,
  193. POWER_SUPPLY_PROP_STATUS, value);
  194. }
  195. /* start polling work */
  196. __pm_stay_awake(battery->monitor_ws);
  197. queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
  198. update_state:
  199. pr_info("%s: update eu eco rechg(%d --> %d)\n",
  200. __func__, fs->is_eu_eco_rechg, fs->eu_eco_rechg_state);
  201. store_battery_log("EUECO:%d->%d,%s,%d%%",
  202. fs->is_eu_eco_rechg, fs->eu_eco_rechg_state,
  203. sb_get_bst_str(battery->status), battery->capacity);
  204. fs->is_eu_eco_rechg = fs->eu_eco_rechg_state;
  205. end_work:
  206. mutex_unlock(&fs->lock);
  207. __pm_relax(fs->ws);
  208. }
  209. static ssize_t
  210. sb_full_soc_show_attrs(struct device *, struct device_attribute *, char *);
  211. static ssize_t
  212. sb_full_soc_store_attrs(struct device *, struct device_attribute *, const char *, size_t);
  213. #define SB_FULL_SOC_ATTR(_name) \
  214. { \
  215. .attr = {.name = #_name, .mode = 0664}, \
  216. .show = sb_full_soc_show_attrs, \
  217. .store = sb_full_soc_store_attrs, \
  218. }
  219. enum sec_bat_attrs {
  220. BATT_FULL_CAPACITY = 0,
  221. BATT_SOC_RECHG,
  222. #if defined(CONFIG_ENG_BATTERY_CONCEPT)
  223. BATT_FULL_CAP_EVENT,
  224. BATT_FULL_SOC_TEST,
  225. #endif
  226. };
  227. static struct device_attribute sb_full_soc_attrs[] = {
  228. SB_FULL_SOC_ATTR(batt_full_capacity),
  229. SB_FULL_SOC_ATTR(batt_soc_rechg),
  230. #if defined(CONFIG_ENG_BATTERY_CONCEPT)
  231. SB_FULL_SOC_ATTR(batt_full_cap_event),
  232. SB_FULL_SOC_ATTR(batt_full_soc_test),
  233. #endif
  234. };
  235. static ssize_t sb_full_soc_show_attrs(struct device *dev,
  236. struct device_attribute *attr, char *buf)
  237. {
  238. struct power_supply *psy = dev_get_drvdata(dev);
  239. struct sec_battery_info *battery = power_supply_get_drvdata(psy);
  240. const ptrdiff_t offset = attr - sb_full_soc_attrs;
  241. int i = 0;
  242. switch (offset) {
  243. case BATT_FULL_CAPACITY:
  244. i += scnprintf(buf, PAGE_SIZE, "%d\n", get_full_capacity(battery->fs));
  245. break;
  246. case BATT_SOC_RECHG:
  247. i += scnprintf(buf, PAGE_SIZE, "%d\n", is_eu_eco_rechg(battery->fs));
  248. break;
  249. #if defined(CONFIG_ENG_BATTERY_CONCEPT)
  250. case BATT_FULL_CAP_EVENT:
  251. i += scnprintf(buf, PAGE_SIZE, "%s\n",
  252. conv_full_cap_str(get_full_cap_event(battery->fs)));
  253. break;
  254. case BATT_FULL_SOC_TEST:
  255. i += scnprintf(buf, PAGE_SIZE, "%d, 0x%x, %d\n",
  256. is_eu_eco_rechg(battery->fs),
  257. battery->pdata->recharge_condition_type,
  258. battery->pdata->recharge_condition_soc);
  259. break;
  260. #endif
  261. default:
  262. return -EINVAL;
  263. }
  264. return i;
  265. }
  266. static ssize_t sb_full_soc_store_attrs(struct device *dev,
  267. struct device_attribute *attr,
  268. const char *buf, size_t count)
  269. {
  270. struct power_supply *psy = dev_get_drvdata(dev);
  271. struct sec_battery_info *battery = power_supply_get_drvdata(psy);
  272. const ptrdiff_t offset = attr - sb_full_soc_attrs;
  273. switch (offset) {
  274. case BATT_FULL_CAPACITY:
  275. {
  276. unsigned int full_cap_event = SB_FULL_CAP_EVENT_NONE;
  277. int x = 0, n = 0;
  278. bool is_changed = false;
  279. if (sscanf(buf, "%10d%n", &x, &n) <= 0) {
  280. pr_info("%s: invalid arguments\n", __func__);
  281. return -EINVAL;
  282. } else if (x < 0 || x > 100) {
  283. pr_info("%s: out of range(%d)\n", __func__, x);
  284. break;
  285. }
  286. if (n > 0) {
  287. char cap_event[MAX_CAP_EVENT_STR] = { 0, };
  288. if ((count - n) > MAX_CAP_EVENT_STR)
  289. pr_info("%s: out of range\n", __func__);
  290. else if (sscanf(buf + n, "%s\n", cap_event) > 0)
  291. full_cap_event = conv_full_cap_event_value(cap_event);
  292. }
  293. if ((get_full_capacity(battery->fs) != x) ||
  294. (get_full_cap_event(battery->fs) != full_cap_event)) {
  295. is_changed = true;
  296. store_battery_log("FCAP:%d%%->%d%%,%s->%s",
  297. get_full_capacity(battery->fs), x,
  298. conv_full_cap_str(get_full_cap_event(battery->fs)), conv_full_cap_str(full_cap_event));
  299. set_full_capacity(battery->fs, x);
  300. set_full_cap_event(battery->fs, full_cap_event);
  301. /* recov full cap */
  302. sec_bat_recov_full_capacity(battery);
  303. __pm_stay_awake(battery->monitor_ws);
  304. queue_delayed_work(battery->monitor_wqueue, &battery->monitor_work, 0);
  305. }
  306. pr_info("%s: %s full cap(%d, %s)\n",
  307. __func__, (is_changed ? "set" : "same"), x, conv_full_cap_str(full_cap_event));
  308. }
  309. break;
  310. case BATT_SOC_RECHG:
  311. {
  312. int x = 0;
  313. if (sscanf(buf, "%10d\n", &x) != 1) {
  314. pr_info("%s: invalid arguments\n", __func__);
  315. return -EINVAL;
  316. }
  317. mutex_lock(&battery->fs->lock);
  318. set_eu_eco_rechg(battery->fs, !!x);
  319. if (x)
  320. enable_eu_eco_rechg(battery);
  321. else
  322. disable_eu_eco_rechg(battery);
  323. /* start eu eco work */
  324. __pm_stay_awake(battery->fs->ws);
  325. queue_delayed_work(battery->monitor_wqueue, &battery->fs->eu_eco_work, 0);
  326. mutex_unlock(&battery->fs->lock);
  327. pr_info("%s: set eu eco rechg(%d)\n",
  328. __func__, is_eu_eco_rechg(battery->fs));
  329. }
  330. break;
  331. #if defined(CONFIG_ENG_BATTERY_CONCEPT)
  332. case BATT_FULL_CAP_EVENT:
  333. break;
  334. case BATT_FULL_SOC_TEST:
  335. {
  336. int x;
  337. if (sscanf(buf, "%10d\n", &x) != 1) {
  338. pr_info("%s: invalid arguments\n", __func__);
  339. return -EINVAL;
  340. }
  341. battery->pdata->recharge_condition_soc = x;
  342. }
  343. break;
  344. #endif
  345. default:
  346. return -EINVAL;
  347. }
  348. return count;
  349. }
  350. static int sb_full_soc_create_attrs(struct device *dev)
  351. {
  352. unsigned long i = 0;
  353. int rc = 0;
  354. for (i = 0; i < ARRAY_SIZE(sb_full_soc_attrs); i++) {
  355. rc = device_create_file(dev, &sb_full_soc_attrs[i]);
  356. if (rc)
  357. goto create_attrs_failed;
  358. }
  359. goto create_attrs_succeed;
  360. create_attrs_failed:
  361. while (i--)
  362. device_remove_file(dev, &sb_full_soc_attrs[i]);
  363. create_attrs_succeed:
  364. return rc;
  365. }
  366. static void sb_full_soc_remove_attrs(struct device *dev)
  367. {
  368. int i = 0;
  369. for (; i < ARRAY_SIZE(sb_full_soc_attrs); i++)
  370. device_remove_file(dev, &sb_full_soc_attrs[i]);
  371. }
  372. void sec_bat_recov_full_capacity(struct sec_battery_info *battery)
  373. {
  374. sec_bat_set_misc_event(battery, 0, BATT_MISC_EVENT_FULL_CAPACITY);
  375. if (battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING
  376. && battery->health == POWER_SUPPLY_HEALTH_GOOD) {
  377. #if defined(CONFIG_ENABLE_FULL_BY_SOC)
  378. if (battery->capacity >= 100)
  379. sec_bat_set_charging_status(battery,
  380. POWER_SUPPLY_STATUS_FULL);
  381. else
  382. #endif
  383. sec_bat_set_charging_status(battery,
  384. POWER_SUPPLY_STATUS_CHARGING);
  385. }
  386. if (!is_full_cap_event_highsoc(battery->fs))
  387. sec_vote(battery->chgen_vote, VOTER_FULL_CAPACITY, false, 0);
  388. }
  389. EXPORT_SYMBOL(sec_bat_recov_full_capacity);
  390. void sec_bat_check_full_capacity(struct sec_battery_info *battery)
  391. {
  392. int now_full_capacity = get_full_capacity(battery->fs);
  393. int rechg_capacity = now_full_capacity - DEF_RECHG_SOC_DIF;
  394. if (is_full_cap_event_highsoc(battery->fs) &&
  395. (battery->capacity <= now_full_capacity)) {
  396. set_full_cap_event(battery->fs, SB_FULL_CAP_EVENT_NONE);
  397. sec_vote(battery->chgen_vote, VOTER_FULL_CAPACITY,
  398. (battery->misc_event & BATT_MISC_EVENT_FULL_CAPACITY), SEC_BAT_CHG_MODE_CHARGING_OFF);
  399. }
  400. if (!is_full_capacity(battery->fs) ||
  401. battery->status == POWER_SUPPLY_STATUS_DISCHARGING) {
  402. if (battery->misc_event & BATT_MISC_EVENT_FULL_CAPACITY) {
  403. pr_info("%s: full_capacity(%d) status(%d)\n",
  404. __func__, now_full_capacity, battery->status);
  405. sec_bat_recov_full_capacity(battery);
  406. }
  407. return;
  408. }
  409. if (battery->misc_event & BATT_MISC_EVENT_FULL_CAPACITY) {
  410. if (battery->capacity <= rechg_capacity ||
  411. battery->status == POWER_SUPPLY_STATUS_CHARGING) {
  412. pr_info("%s : start re-charging(%d, %d) status(%d)\n",
  413. __func__, battery->capacity, rechg_capacity, battery->status);
  414. set_full_cap_event(battery->fs, SB_FULL_CAP_EVENT_NONE);
  415. sec_bat_recov_full_capacity(battery);
  416. }
  417. } else if (battery->capacity >= now_full_capacity) {
  418. union power_supply_propval value = {0, };
  419. pr_info("%s : stop charging(%d, %d, %s)\n", __func__,
  420. battery->capacity, now_full_capacity,
  421. conv_full_cap_str(get_full_cap_event(battery->fs)));
  422. sec_bat_set_misc_event(battery, BATT_MISC_EVENT_FULL_CAPACITY,
  423. BATT_MISC_EVENT_FULL_CAPACITY);
  424. sec_bat_set_charging_status(battery, POWER_SUPPLY_STATUS_NOT_CHARGING);
  425. sec_vote(battery->chgen_vote, VOTER_FULL_CAPACITY, true,
  426. (is_full_cap_event_highsoc(battery->fs) ?
  427. SEC_BAT_CHG_MODE_BUCK_OFF : SEC_BAT_CHG_MODE_CHARGING_OFF));
  428. if (is_wireless_all_type(battery->cable_type)) {
  429. value.intval = POWER_SUPPLY_STATUS_FULL;
  430. psy_do_property(battery->pdata->wireless_charger_name, set,
  431. POWER_SUPPLY_PROP_STATUS, value);
  432. }
  433. }
  434. }
  435. EXPORT_SYMBOL(sec_bat_check_full_capacity);
  436. int sb_full_soc_init(struct sec_battery_info *battery)
  437. {
  438. struct sb_full_soc *fs;
  439. int ret = 0;
  440. fs = kzalloc(sizeof(struct sb_full_soc), GFP_KERNEL);
  441. if (!fs)
  442. return -ENOMEM;
  443. ret = sb_full_soc_create_attrs(&battery->psy_bat->dev);
  444. if (ret) {
  445. pr_err("%s: failed to create attrs(%d)\n", __func__, ret);
  446. goto err_attrs;
  447. }
  448. fs->ws = wakeup_source_register(NULL, "full-soc");
  449. if (!fs->ws) {
  450. pr_err("%s: failed to register wakeup\n", __func__);
  451. goto err_ws;
  452. }
  453. mutex_init(&fs->lock);
  454. INIT_DELAYED_WORK(&fs->eu_eco_work, eu_eco_work);
  455. fs->battery = battery;
  456. fs->full_capacity = 0;
  457. fs->full_cap_event = SB_FULL_CAP_EVENT_NONE;
  458. fs->is_eu_eco_rechg = false;
  459. fs->eu_eco_rechg_state = false;
  460. fs->old_recharge_condition_type = battery->pdata->recharge_condition_type;
  461. fs->old_recharge_condition_soc = battery->pdata->recharge_condition_soc;
  462. battery->fs = fs;
  463. return 0;
  464. err_ws:
  465. sb_full_soc_remove_attrs(&battery->psy_bat->dev);
  466. err_attrs:
  467. kfree(fs);
  468. return ret;
  469. }
  470. EXPORT_SYMBOL(sb_full_soc_init);