cps4038_fod.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /*
  2. * mfc_fod.c
  3. * Samsung Mobile MFC FOD 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/battery/sb_wireless.h>
  18. #include <dt-bindings/battery/sec-battery.h>
  19. #include "cps4038_fod.h"
  20. #define fod_log(str, ...) pr_info("[MFC-FOD]:%s: "str, __func__, ##__VA_ARGS__)
  21. #define DEFAULT_TX_IDX 0
  22. #define DEFAULT_OP_MODE WPC_OP_MODE_BPP
  23. #define DEFAULT_VENDOR_ID 0x42
  24. struct mfc_fod_op {
  25. unsigned int flag;
  26. fod_data_t *data[MFC_FOD_BAT_STATE_MAX];
  27. };
  28. struct mfc_fod_tx {
  29. unsigned int id;
  30. struct mfc_fod_op op[WPC_OP_MODE_MAX];
  31. };
  32. struct mfc_fod {
  33. struct device *parent;
  34. mfc_set_fod cb_func;
  35. struct mutex lock;
  36. union mfc_fod_state state;
  37. /* fod data */
  38. struct mfc_fod_tx *list;
  39. unsigned int count;
  40. unsigned int ext[MFC_FOD_EXT_MAX];
  41. /* threshold */
  42. unsigned int bpp_vout;
  43. unsigned int cc_cv_thr;
  44. unsigned int high_swell_cc_cv_thr;
  45. unsigned int vendor_id;
  46. };
  47. static int get_op_mode_by_str(const char *str)
  48. {
  49. if (str == NULL)
  50. return WPC_OP_MODE_NONE;
  51. if (!strncmp(str, "ppde", 4))
  52. return WPC_OP_MODE_PPDE;
  53. if (!strncmp(str, "epp", 3))
  54. return WPC_OP_MODE_EPP;
  55. if (!strncmp(str, "mpp", 3))
  56. return WPC_OP_MODE_MPP;
  57. return WPC_OP_MODE_BPP;
  58. }
  59. static const char *get_ext_str(unsigned int ext_type)
  60. {
  61. switch (ext_type) {
  62. case MFC_FOD_EXT_EPP_REF_QF:
  63. return "epp_ref_qf";
  64. case MFC_FOD_EXT_EPP_REF_RF:
  65. return "epp_ref_rf";
  66. }
  67. return "none";
  68. }
  69. static const char *get_bat_state_str(unsigned int bat_state)
  70. {
  71. switch (bat_state) {
  72. case MFC_FOD_BAT_STATE_CC:
  73. return "cc";
  74. case MFC_FOD_BAT_STATE_CV:
  75. return "cv";
  76. case MFC_FOD_BAT_STATE_FULL:
  77. return "full";
  78. }
  79. return "none";
  80. }
  81. static fod_data_t *mfc_fod_parse_data(struct device_node *np, int bat_state, unsigned int fod_size)
  82. {
  83. fod_data_t *data;
  84. const u32 *p;
  85. int len = 0, t_size = 0, ret;
  86. p = of_get_property(np, get_bat_state_str(bat_state), &len);
  87. if (!p)
  88. return NULL;
  89. t_size = sizeof(fod_data_t);
  90. data = kcalloc(fod_size, t_size, GFP_KERNEL);
  91. if (!data)
  92. return NULL;
  93. if (fod_size != (len / t_size)) {
  94. fod_log("not match the size(%d, %d, %d)\n", fod_size, len, t_size);
  95. goto err_size;
  96. }
  97. switch (t_size) {
  98. case sizeof(u64):
  99. ret = of_property_read_u64_array(np, get_bat_state_str(bat_state),
  100. (u64 *)data, fod_size);
  101. break;
  102. case sizeof(u32):
  103. ret = of_property_read_u32_array(np, get_bat_state_str(bat_state),
  104. (u32 *)data, fod_size);
  105. break;
  106. case sizeof(u16):
  107. ret = of_property_read_u16_array(np, get_bat_state_str(bat_state),
  108. (u16 *)data, fod_size);
  109. break;
  110. case sizeof(u8):
  111. ret = of_property_read_u8_array(np, get_bat_state_str(bat_state),
  112. (u8 *)data, fod_size);
  113. break;
  114. default:
  115. fod_log("invalid t size(%d)\n", t_size);
  116. goto err_size;
  117. }
  118. if (ret < 0) {
  119. fod_log("%s, failed to parse data (ret = %d)\n", get_bat_state_str(bat_state), ret);
  120. goto err_size;
  121. }
  122. return data;
  123. err_size:
  124. kfree(data);
  125. return NULL;
  126. }
  127. static int mfc_fod_parse_op_node(struct device_node *np,
  128. struct mfc_fod *fod, struct mfc_fod_tx *fod_tx, int op_mode, unsigned int fod_size)
  129. {
  130. struct mfc_fod_op *fod_op = &fod_tx->op[op_mode];
  131. unsigned int flag = 0;
  132. int ret = 0, i;
  133. ret = of_property_read_u32(np, "flag", &flag);
  134. if (ret < 0) {
  135. pr_err("%s: failed to get flag of %s\n", __func__, np->name);
  136. return ret;
  137. }
  138. for (i = MFC_FOD_BAT_STATE_CC; i < MFC_FOD_BAT_STATE_MAX; i++) {
  139. switch ((flag >> (i * 4)) & 0xF) {
  140. case FOD_FLAG_ADD:
  141. fod_op->data[i] = mfc_fod_parse_data(np, i, fod_size);
  142. if (fod_op->data[i] == NULL) {
  143. ret = -1;
  144. goto err_data;
  145. }
  146. break;
  147. case FOD_FLAG_USE_CC:
  148. if (fod_op->data[MFC_FOD_BAT_STATE_CC] == NULL) {
  149. ret = -2;
  150. goto err_data;
  151. }
  152. fod_op->data[i] = fod_op->data[MFC_FOD_BAT_STATE_CC];
  153. break;
  154. case FOD_FLAG_USE_CV:
  155. if (fod_op->data[MFC_FOD_BAT_STATE_CV] == NULL) {
  156. ret = -3;
  157. goto err_data;
  158. }
  159. fod_op->data[i] = fod_op->data[MFC_FOD_BAT_STATE_CV];
  160. break;
  161. case FOD_FLAG_USE_FULL:
  162. if (fod_op->data[MFC_FOD_BAT_STATE_FULL] == NULL) {
  163. ret = -4;
  164. goto err_data;
  165. }
  166. fod_op->data[i] = fod_op->data[MFC_FOD_BAT_STATE_FULL];
  167. break;
  168. case FOD_FLAG_USE_DEF_PAD:
  169. {
  170. struct mfc_fod_tx *def_tx = &fod->list[DEFAULT_TX_IDX];
  171. if (def_tx->op[op_mode].data[i] == NULL) {
  172. ret = -5;
  173. goto err_data;
  174. }
  175. fod_op->data[i] = def_tx->op[op_mode].data[i];
  176. }
  177. break;
  178. case FOD_FLAG_USE_DEF_OP:
  179. {
  180. struct mfc_fod_op *def_op = &fod_tx->op[DEFAULT_OP_MODE];
  181. if (def_op->data[i] == NULL) {
  182. ret = -6;
  183. goto err_data;
  184. }
  185. fod_op->data[i] = def_op->data[i];
  186. }
  187. break;
  188. case FOD_FLAG_NONE:
  189. default:
  190. fod_log("%s - %s is not set\n", np->name, get_bat_state_str(i));
  191. break;
  192. }
  193. }
  194. fod_op->flag = flag;
  195. return 0;
  196. err_data:
  197. for (; i >= 0; i--) {
  198. if (((flag >> (i * 4)) & 0xF) == FOD_FLAG_ADD)
  199. kfree(fod_op->data[i]);
  200. }
  201. return ret;
  202. }
  203. static int mfc_fod_init_ext_pad(struct mfc_fod_tx *fod_tx, struct mfc_fod_tx *def_tx)
  204. {
  205. int i, j;
  206. if (fod_tx->id == DEFAULT_TX_IDX)
  207. return 0;
  208. for (j = WPC_OP_MODE_NONE; j < WPC_OP_MODE_MAX; j++) {
  209. if (def_tx->op[j].flag == 0)
  210. continue;
  211. for (i = MFC_FOD_BAT_STATE_CC; i < MFC_FOD_BAT_STATE_MAX; i++)
  212. fod_tx->op[j].data[i] = def_tx->op[j].data[i];
  213. fod_tx->op[j].flag =
  214. (SET_FOD_CC(USE_DEF_PAD) | SET_FOD_CV(USE_DEF_PAD) | SET_FOD_FULL(USE_DEF_PAD));
  215. }
  216. return 0;
  217. }
  218. static int mfc_fod_parse_tx_node(struct device_node *np, struct mfc_fod *fod, unsigned int fod_size)
  219. {
  220. struct device_node *tx_node = NULL;
  221. int ret = 0, tx_idx = 0;
  222. for_each_child_of_node(np, tx_node) {
  223. struct mfc_fod_tx *fod_tx = NULL;
  224. struct device_node *op_node = NULL;
  225. if (tx_idx >= fod->count) {
  226. fod_log("out of range(%d <--> %d)\n", tx_idx, fod->count);
  227. break;
  228. }
  229. fod_tx = &fod->list[tx_idx++];
  230. if (sscanf(tx_node->name, "pad_0x%X", &fod_tx->id) < 0) {
  231. fod_log("failed to get tx id(%s)\n", tx_node->name);
  232. continue;
  233. }
  234. mfc_fod_init_ext_pad(fod_tx, &fod->list[DEFAULT_TX_IDX]);
  235. for_each_child_of_node(tx_node, op_node) {
  236. int op_mode;
  237. op_mode = get_op_mode_by_str(op_node->name);
  238. if (op_mode == WPC_OP_MODE_NONE) {
  239. fod_log("%s, invalid op name\n", op_node->name);
  240. continue;
  241. }
  242. ret = mfc_fod_parse_op_node(op_node, fod, fod_tx, op_mode, fod_size);
  243. if (ret < 0)
  244. fod_log("%s, failed to parse data(ret = %d)\n", op_node->name, ret);
  245. }
  246. }
  247. return 0;
  248. }
  249. static void mfc_fod_print_data(struct mfc_fod *fod, unsigned int fod_size)
  250. {
  251. int x, y, z, k;
  252. struct mfc_fod_tx *fod_tx;
  253. for (x = 0; x < fod->count; x++) {
  254. fod_tx = &fod->list[x];
  255. for (y = WPC_OP_MODE_NONE + 1; y < WPC_OP_MODE_MAX; y++) {
  256. for (z = MFC_FOD_BAT_STATE_CC; z < MFC_FOD_BAT_STATE_MAX; z++) {
  257. char temp_buf[1024] = {0, };
  258. int size = 1024;
  259. if (fod_tx->op[y].data[z] == NULL) {
  260. fod_log("PAD_0x%02X:%s:%s is null!!\n",
  261. fod_tx->id, sb_wrl_op_mode_str(y), get_bat_state_str(z));
  262. continue;
  263. }
  264. for (k = 0; k < fod_size; k++) {
  265. snprintf(temp_buf + strlen(temp_buf), size, "0x%02X ", fod_tx->op[y].data[z][k]);
  266. size = sizeof(temp_buf) - strlen(temp_buf);
  267. }
  268. fod_log("PAD_0x%02X:%s:%s - %s\n",
  269. fod_tx->id, sb_wrl_op_mode_str(y), get_bat_state_str(z), temp_buf);
  270. }
  271. }
  272. }
  273. }
  274. static void mfc_fod_print_ext(struct mfc_fod *fod)
  275. {
  276. char ext_buf[1024] = {0, };
  277. int x, ext_size = 1024;
  278. for (x = 0; x < MFC_FOD_EXT_MAX; x++) {
  279. snprintf(ext_buf + strlen(ext_buf), ext_size, "%02d:0x%X ", x, fod->ext[x]);
  280. ext_size = sizeof(ext_buf) - strlen(ext_buf);
  281. }
  282. fod_log("EXT - %s\n", ext_buf);
  283. }
  284. static int mfc_fod_parse_dt(struct device_node *np, struct mfc_fod *fod, unsigned int fod_size)
  285. {
  286. int ret = 0, i;
  287. np = of_find_node_by_name(np, "fod_list");
  288. if (!np) {
  289. fod_log("fod list is null!!!!\n");
  290. return -ENODEV;
  291. }
  292. ret = of_property_read_u32(np, "count", &fod->count);
  293. if (ret < 0) {
  294. fod_log("count is null(ret = %d)\n", ret);
  295. return ret;
  296. }
  297. fod->list = kcalloc(fod->count, sizeof(struct mfc_fod_tx), GFP_KERNEL);
  298. if (!fod->list) {
  299. fod_log("failed to alloc fod list\n");
  300. return -ENOMEM;
  301. }
  302. ret = mfc_fod_parse_tx_node(np, fod, fod_size);
  303. if (ret < 0) {
  304. kfree(fod->list);
  305. return ret;
  306. }
  307. /* parse ext */
  308. for (i = 0; i < MFC_FOD_EXT_MAX; i++) {
  309. ret = of_property_read_u32(np, get_ext_str(i), (unsigned int *)&fod->ext[i]);
  310. if (ret < 0)
  311. fod_log("%s is null(ret = %d)!!\n", get_ext_str(i), ret);
  312. }
  313. mfc_fod_print_data(fod, fod_size);
  314. mfc_fod_print_ext(fod);
  315. return 0;
  316. }
  317. static int mfc_fod_thr_parse_dt(struct device_node *np, struct mfc_fod *fod)
  318. {
  319. int ret = 0;
  320. ret = of_property_read_u32(np, "bpp_vout", &fod->bpp_vout);
  321. if (ret < 0)
  322. fod->bpp_vout = 7000;
  323. ret = of_property_read_u32(np, "cc_cv_thr", &fod->cc_cv_thr);
  324. if (ret < 0)
  325. fod->cc_cv_thr = 85;
  326. ret = of_property_read_u32(np, "high_swell_cc_cv_thr", &fod->high_swell_cc_cv_thr);
  327. if (ret < 0)
  328. fod->high_swell_cc_cv_thr = 70;
  329. ret = of_property_read_u32(np, "vendor_id", (unsigned int *)&fod->vendor_id);
  330. if (ret < 0) {
  331. fod_log("vendor_id is null(ret = %d)!!\n", ret);
  332. fod->vendor_id = DEFAULT_VENDOR_ID;
  333. }
  334. fod_log("bpp_vout = %d, cc_cv_thr = %d, high_swell_cc_cv_thr = %d, vendor_id = 0x%x\n",
  335. fod->bpp_vout, fod->cc_cv_thr, fod->high_swell_cc_cv_thr, fod->vendor_id);
  336. return 0;
  337. }
  338. static struct mfc_fod_tx *get_fod_tx(struct mfc_fod *fod, unsigned int tx_id)
  339. {
  340. int i;
  341. for (i = 0; i < fod->count; i++) {
  342. if (fod->list[i].id == tx_id)
  343. return &fod->list[i];
  344. }
  345. return &fod->list[DEFAULT_TX_IDX];
  346. }
  347. static bool check_vendor_id_to_set_op_mode_by_vout(union mfc_fod_state *state, int vendor_id)
  348. {
  349. return (state->vendor_id == vendor_id);
  350. }
  351. static int check_op_mode_vout(struct mfc_fod *fod, union mfc_fod_state *state)
  352. {
  353. if (!check_vendor_id_to_set_op_mode_by_vout(state, fod->vendor_id))
  354. return state->op_mode;
  355. switch (state->op_mode) {
  356. case WPC_OP_MODE_EPP:
  357. case WPC_OP_MODE_PPDE:
  358. if (state->vout <= fod->bpp_vout)
  359. return WPC_OP_MODE_BPP;
  360. break;
  361. case WPC_OP_MODE_MPP:
  362. break;
  363. default:
  364. /* default op mode */
  365. return WPC_OP_MODE_BPP;
  366. }
  367. return state->op_mode;
  368. }
  369. static fod_data_t *mfc_fod_get_data(struct mfc_fod *fod)
  370. {
  371. union mfc_fod_state *fod_state = &fod->state;
  372. struct mfc_fod_tx *fod_tx;
  373. if (fod->count <= 0)
  374. return NULL;
  375. fod_tx = get_fod_tx(fod, fod_state->tx_id);
  376. fod_state->fake_op_mode = check_op_mode_vout(fod, fod_state);
  377. return fod_tx->op[fod_state->fake_op_mode].data[fod_state->bat_state];
  378. }
  379. struct mfc_fod *mfc_fod_init(struct device *dev, unsigned int fod_size, mfc_set_fod cb_func)
  380. {
  381. struct mfc_fod *fod;
  382. int ret = 0;
  383. if (IS_ERR_OR_NULL(dev) ||
  384. (fod_size <= 0) ||
  385. (fod_size > MFC_FOD_MAX_SIZE) ||
  386. (cb_func == NULL))
  387. return ERR_PTR(-EINVAL);
  388. fod = kzalloc(sizeof(struct mfc_fod), GFP_KERNEL);
  389. if (!fod)
  390. return ERR_PTR(-ENOMEM);
  391. ret = mfc_fod_parse_dt(dev->of_node, fod, fod_size);
  392. if (ret < 0) {
  393. kfree(fod);
  394. return ERR_PTR(ret);
  395. }
  396. mfc_fod_thr_parse_dt(dev->of_node, fod);
  397. mutex_init(&fod->lock);
  398. fod->parent = dev;
  399. fod->cb_func = cb_func;
  400. fod->state.value = 0;
  401. fod_log("DONE!!\n");
  402. return fod;
  403. }
  404. EXPORT_SYMBOL(mfc_fod_init);
  405. int mfc_fod_init_state(struct mfc_fod *fod)
  406. {
  407. if (IS_ERR(fod))
  408. return -EINVAL;
  409. mutex_lock(&fod->lock);
  410. if (fod->state.value != 0) {
  411. fod->state.value = 0;
  412. fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
  413. }
  414. mutex_unlock(&fod->lock);
  415. return 0;
  416. }
  417. EXPORT_SYMBOL(mfc_fod_init_state);
  418. int mfc_fod_refresh(struct mfc_fod *fod)
  419. {
  420. if (IS_ERR(fod))
  421. return -EINVAL;
  422. mutex_lock(&fod->lock);
  423. if (fod->state.value != 0)
  424. fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
  425. mutex_unlock(&fod->lock);
  426. return 0;
  427. }
  428. EXPORT_SYMBOL(mfc_fod_refresh);
  429. int mfc_fod_set_op_mode(struct mfc_fod *fod, int op_mode)
  430. {
  431. if (IS_ERR(fod) ||
  432. (op_mode < WPC_OP_MODE_NONE) ||
  433. (op_mode >= WPC_OP_MODE_MAX))
  434. return -EINVAL;
  435. mutex_lock(&fod->lock);
  436. switch (fod->state.op_mode) {
  437. case WPC_OP_MODE_EPP:
  438. case WPC_OP_MODE_MPP:
  439. case WPC_OP_MODE_PPDE:
  440. fod_log("prevent op mode(%d)!!\n", op_mode);
  441. break;
  442. case WPC_OP_MODE_BPP:
  443. case WPC_OP_MODE_NONE:
  444. default:
  445. if (fod->state.op_mode != op_mode) {
  446. fod->state.op_mode = op_mode;
  447. fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
  448. }
  449. break;
  450. }
  451. mutex_unlock(&fod->lock);
  452. return 0;
  453. }
  454. EXPORT_SYMBOL(mfc_fod_set_op_mode);
  455. int mfc_fod_set_vendor_id(struct mfc_fod *fod, int vendor_id)
  456. {
  457. if (IS_ERR(fod) ||
  458. (vendor_id < 0) ||
  459. (vendor_id > 0xFF))
  460. return -EINVAL;
  461. mutex_lock(&fod->lock);
  462. if (vendor_id != fod->state.vendor_id) {
  463. fod->state.vendor_id = vendor_id;
  464. fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
  465. }
  466. mutex_unlock(&fod->lock);
  467. return 0;
  468. }
  469. EXPORT_SYMBOL(mfc_fod_set_vendor_id);
  470. int mfc_fod_set_tx_id(struct mfc_fod *fod, int tx_id)
  471. {
  472. if (IS_ERR(fod) ||
  473. (tx_id < 0) || (tx_id >= 256))
  474. return -EINVAL;
  475. mutex_lock(&fod->lock);
  476. if (fod->state.tx_id != tx_id) {
  477. fod->state.tx_id = tx_id;
  478. fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
  479. }
  480. mutex_unlock(&fod->lock);
  481. return 0;
  482. }
  483. EXPORT_SYMBOL(mfc_fod_set_tx_id);
  484. static int check_bat_state(struct mfc_fod *fod)
  485. {
  486. if (fod->state.high_swell)
  487. return (fod->state.bat_cap > fod->high_swell_cc_cv_thr) ?
  488. MFC_FOD_BAT_STATE_CV : MFC_FOD_BAT_STATE_CC;
  489. return (fod->state.bat_cap > fod->cc_cv_thr) ?
  490. MFC_FOD_BAT_STATE_CV : MFC_FOD_BAT_STATE_CC;
  491. }
  492. static int set_bat_state(struct mfc_fod *fod, int bat_state)
  493. {
  494. switch (fod->state.bat_state) {
  495. case MFC_FOD_BAT_STATE_FULL:
  496. fod_log("prevent bat state(%d)!!\n", bat_state);
  497. break;
  498. case MFC_FOD_BAT_STATE_CC:
  499. case MFC_FOD_BAT_STATE_CV:
  500. default:
  501. if (fod->state.bat_state != bat_state) {
  502. fod->state.bat_state = bat_state;
  503. fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
  504. }
  505. break;
  506. }
  507. return 0;
  508. }
  509. int mfc_fod_set_bat_state(struct mfc_fod *fod, int bat_state)
  510. {
  511. if (IS_ERR(fod) ||
  512. (bat_state < MFC_FOD_BAT_STATE_CC) ||
  513. (bat_state >= MFC_FOD_BAT_STATE_MAX))
  514. return -EINVAL;
  515. mutex_lock(&fod->lock);
  516. set_bat_state(fod, bat_state);
  517. mutex_unlock(&fod->lock);
  518. return 0;
  519. }
  520. EXPORT_SYMBOL(mfc_fod_set_bat_state);
  521. int mfc_fod_set_bat_cap(struct mfc_fod *fod, int bat_cap)
  522. {
  523. if (IS_ERR(fod) ||
  524. (bat_cap < 0) || (bat_cap > 100))
  525. return -EINVAL;
  526. mutex_lock(&fod->lock);
  527. if (fod->state.bat_cap != bat_cap) {
  528. fod->state.bat_cap = bat_cap;
  529. set_bat_state(fod, check_bat_state(fod));
  530. }
  531. mutex_unlock(&fod->lock);
  532. return 0;
  533. }
  534. EXPORT_SYMBOL(mfc_fod_set_bat_cap);
  535. int mfc_fod_set_vout(struct mfc_fod *fod, int vout)
  536. {
  537. if (IS_ERR(fod) ||
  538. (vout <= 0))
  539. return -EINVAL;
  540. mutex_lock(&fod->lock);
  541. if (fod->state.vout != vout) {
  542. int new_op_mode, old_op_mode;
  543. old_op_mode = check_op_mode_vout(fod, &fod->state);
  544. fod->state.vout = vout;
  545. new_op_mode = check_op_mode_vout(fod, &fod->state);
  546. if (new_op_mode != old_op_mode)
  547. fod->cb_func(fod->parent, &fod->state, mfc_fod_get_data(fod));
  548. }
  549. mutex_unlock(&fod->lock);
  550. return 0;
  551. }
  552. EXPORT_SYMBOL(mfc_fod_set_vout);
  553. int mfc_fod_set_high_swell(struct mfc_fod *fod, bool state)
  554. {
  555. if (IS_ERR(fod))
  556. return -EINVAL;
  557. mutex_lock(&fod->lock);
  558. if (fod->state.high_swell != state) {
  559. fod->state.high_swell = state;
  560. set_bat_state(fod, check_bat_state(fod));
  561. }
  562. mutex_unlock(&fod->lock);
  563. return 0;
  564. }
  565. EXPORT_SYMBOL(mfc_fod_set_high_swell);
  566. int mfc_fod_get_state(struct mfc_fod *fod, union mfc_fod_state *state)
  567. {
  568. if (IS_ERR(fod) ||
  569. (state == NULL))
  570. return -EINVAL;
  571. mutex_lock(&fod->lock);
  572. state->value = fod->state.value;
  573. mutex_unlock(&fod->lock);
  574. return 0;
  575. }
  576. EXPORT_SYMBOL(mfc_fod_get_state);
  577. int mfc_fod_get_ext(struct mfc_fod *fod, int ext_type, int *data)
  578. {
  579. if (IS_ERR(fod) ||
  580. (ext_type < MFC_FOD_EXT_EPP_REF_QF) ||
  581. (ext_type >= MFC_FOD_EXT_MAX) ||
  582. (data == NULL))
  583. return -EINVAL;
  584. mutex_lock(&fod->lock);
  585. *data = fod->ext[ext_type];
  586. mutex_unlock(&fod->lock);
  587. return 0;
  588. }
  589. EXPORT_SYMBOL(mfc_fod_get_ext);