sec_pd.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * Copyrights (C) 2017 Samsung Electronics, Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/notifier.h>
  16. #include <linux/battery/sec_pd.h>
  17. #if defined(CONFIG_SEC_KUNIT)
  18. #include <kunit/mock.h>
  19. SEC_PD_SINK_STATUS *g_psink_status;
  20. EXPORT_SYMBOL(g_psink_status);
  21. #else
  22. static SEC_PD_SINK_STATUS *g_psink_status;
  23. #endif
  24. #if defined(CONFIG_ARCH_MTK_PROJECT) || IS_ENABLED(CONFIG_SEC_MTK_CHARGER)
  25. struct pdic_notifier_struct pd_noti;
  26. EXPORT_SYMBOL(pd_noti);
  27. #endif
  28. const char* sec_pd_pdo_type_str(int pdo_type)
  29. {
  30. switch (pdo_type) {
  31. case FPDO_TYPE:
  32. return "FIXED";
  33. case APDO_TYPE:
  34. return "APDO";
  35. case VPDO_TYPE:
  36. return "VPDO";
  37. default:
  38. return "UNKNOWN";
  39. }
  40. }
  41. EXPORT_SYMBOL(sec_pd_pdo_type_str);
  42. int sec_pd_select_pdo(int num)
  43. {
  44. if (!g_psink_status) {
  45. pr_err("%s: g_psink_status is NULL\n", __func__);
  46. return -1;
  47. }
  48. if (!g_psink_status->fp_sec_pd_select_pdo) {
  49. pr_err("%s: not exist\n", __func__);
  50. return -1;
  51. }
  52. g_psink_status->fp_sec_pd_select_pdo(num);
  53. return 0;
  54. }
  55. EXPORT_SYMBOL(sec_pd_select_pdo);
  56. int sec_pd_select_pps(int num, int ppsVol, int ppsCur)
  57. {
  58. if (!g_psink_status) {
  59. pr_err("%s: g_psink_status is NULL\n", __func__);
  60. return -1;
  61. }
  62. if (!g_psink_status->fp_sec_pd_select_pps) {
  63. pr_err("%s: not exist\n", __func__);
  64. return -1;
  65. }
  66. return g_psink_status->fp_sec_pd_select_pps(num, ppsVol, ppsCur);
  67. }
  68. EXPORT_SYMBOL(sec_pd_select_pps);
  69. int sec_pd_get_current_pdo(unsigned int *pdo)
  70. {
  71. if (pdo == NULL) {
  72. pr_err("%s: invalid argument\n", __func__);
  73. return -1;
  74. }
  75. if (!g_psink_status) {
  76. pr_err("%s: g_psink_status is NULL\n", __func__);
  77. return -1;
  78. }
  79. *pdo = g_psink_status->current_pdo_num;
  80. return 0;
  81. }
  82. EXPORT_SYMBOL(sec_pd_get_current_pdo);
  83. int sec_pd_get_selected_pdo(unsigned int *pdo)
  84. {
  85. if (pdo == NULL) {
  86. pr_err("%s: invalid argument\n", __func__);
  87. return -1;
  88. }
  89. if (!g_psink_status) {
  90. pr_err("%s: g_psink_status is NULL\n", __func__);
  91. return -1;
  92. }
  93. *pdo = g_psink_status->selected_pdo_num;
  94. return 0;
  95. }
  96. EXPORT_SYMBOL(sec_pd_get_selected_pdo);
  97. int sec_pd_is_apdo(unsigned int pdo)
  98. {
  99. if (!g_psink_status) {
  100. pr_err("%s: g_psink_status is NULL\n", __func__);
  101. return -1;
  102. }
  103. if (pdo > g_psink_status->available_pdo_num) {
  104. pr_err("%s: invalid argument(%d)\n", __func__, pdo);
  105. return -EINVAL;
  106. }
  107. return ((g_psink_status->power_list[pdo].pdo_type == APDO_TYPE) ? true : false);
  108. }
  109. EXPORT_SYMBOL(sec_pd_is_apdo);
  110. int sec_pd_detach_with_cc(int state)
  111. {
  112. if (!g_psink_status) {
  113. pr_err("%s: g_psink_status is NULL\n", __func__);
  114. return -1;
  115. }
  116. if (!g_psink_status->fp_sec_pd_detach_with_cc) {
  117. pr_err("%s: not exist\n", __func__);
  118. return -1;
  119. }
  120. g_psink_status->fp_sec_pd_detach_with_cc(state);
  121. return 0;
  122. }
  123. EXPORT_SYMBOL(sec_pd_detach_with_cc);
  124. static int sec_pd_check_pdo(unsigned int pdo, unsigned int min_volt, unsigned int max_volt, unsigned int max_curr)
  125. {
  126. POWER_LIST *pwr = &g_psink_status->power_list[pdo];
  127. if (pwr->pdo_type == APDO_TYPE) {
  128. if (min_volt > 0) {
  129. if (min_volt < pwr->min_voltage)
  130. return -1;
  131. if (min_volt > pwr->max_voltage)
  132. return -1;
  133. }
  134. if (max_volt > 0) {
  135. if (max_volt > pwr->max_voltage)
  136. return -1;
  137. if (max_volt < pwr->min_voltage)
  138. return -1;
  139. }
  140. } else {
  141. if (max_volt != pwr->max_voltage)
  142. return -1;
  143. }
  144. if ((max_curr > 0) && (max_curr > pwr->max_current))
  145. return -1;
  146. return sec_pd_get_max_power(pwr->pdo_type,
  147. pwr->min_voltage, pwr->max_voltage, pwr->max_current);
  148. }
  149. #define PROG_0V 0
  150. #define PROG_5V 5900
  151. #define PROG_9V 11000
  152. #define PROG_15V 16000
  153. #define PROG_20V 21000
  154. #define PROG_MIN 3300
  155. int sec_pd_get_apdo_prog_volt(unsigned int pdo_type, unsigned int max_volt)
  156. {
  157. if (pdo_type != APDO_TYPE)
  158. return max_volt;
  159. switch (max_volt) {
  160. case PROG_0V ... (PROG_5V - 1):
  161. return 0;
  162. case PROG_5V ... (PROG_9V - 1):
  163. return 5000;
  164. case PROG_9V ... (PROG_15V - 1):
  165. return 9000;
  166. case PROG_15V ... (PROG_20V - 1):
  167. return 15000;
  168. }
  169. return 20000;
  170. }
  171. EXPORT_SYMBOL(sec_pd_get_apdo_prog_volt);
  172. int sec_pd_get_max_power(unsigned int pdo_type, unsigned int min_volt, unsigned int max_volt, unsigned int max_curr)
  173. {
  174. return sec_pd_get_apdo_prog_volt(pdo_type, max_volt) * max_curr;
  175. }
  176. EXPORT_SYMBOL(sec_pd_get_max_power);
  177. int sec_pd_get_pdo_power(unsigned int *pdo, unsigned int *min_volt, unsigned int *max_volt, unsigned int *max_curr)
  178. {
  179. unsigned int npdo = 0, nmin_volt = 0, nmax_volt = 0, ncurr = 0;
  180. int nidx = 0, npwr = 0;
  181. POWER_LIST *pwr;
  182. if (!g_psink_status) {
  183. pr_err("%s: g_psink_status is NULL\n", __func__);
  184. return -1;
  185. }
  186. npdo = (pdo != NULL) ? (*pdo) : 0;
  187. nmin_volt = (min_volt != NULL) ? (*min_volt) : 0;
  188. nmax_volt = (max_volt != NULL) ? (*max_volt) : 0;
  189. ncurr = (max_curr != NULL) ? (*max_curr) : 0;
  190. if (npdo > g_psink_status->available_pdo_num) {
  191. pr_err("%s: invalid argument(%d)\n", __func__, npdo);
  192. return -EINVAL;
  193. }
  194. if (npdo != 0) {
  195. npwr = sec_pd_check_pdo(npdo, nmin_volt, nmax_volt, ncurr);
  196. nidx = npdo;
  197. } else {
  198. int i, anidx = 0, anpwr = 0, tpwr = 0;
  199. for (i = 1; i <= g_psink_status->available_pdo_num; i++) {
  200. pwr = &g_psink_status->power_list[i];
  201. tpwr = sec_pd_check_pdo(i, nmin_volt, nmax_volt, ncurr);
  202. if (pwr->pdo_type == APDO_TYPE) {
  203. if (anpwr < tpwr) {
  204. anidx = i;
  205. anpwr = tpwr;
  206. }
  207. } else {
  208. if (npwr < tpwr) {
  209. nidx = i;
  210. npwr = tpwr;
  211. }
  212. }
  213. }
  214. if (!npwr) {
  215. nidx = anidx;
  216. npwr = anpwr;
  217. }
  218. }
  219. if ((nidx <= 0) || (npwr <= 0)) {
  220. pr_err("%s: failed to find available pdo(%d)\n", __func__, npwr);
  221. return npwr;
  222. }
  223. /* update values */
  224. pwr = &g_psink_status->power_list[nidx];
  225. if (pdo != NULL)
  226. *pdo = nidx;
  227. if (min_volt != NULL)
  228. *min_volt = pwr->min_voltage;
  229. if (max_volt != NULL)
  230. *max_volt = pwr->max_voltage;
  231. if (max_curr != NULL)
  232. *max_curr = pwr->max_current;
  233. pr_info("%s: success to find pdo idx = %d, pwr = %d\n", __func__, nidx, npwr);
  234. return npwr;
  235. }
  236. EXPORT_SYMBOL(sec_pd_get_pdo_power);
  237. int sec_pd_vpdo_auth(int auth, int d2d_type)
  238. {
  239. if (!g_psink_status) {
  240. pr_err("%s: g_psink_status is NULL\n", __func__);
  241. return -1;
  242. }
  243. if (!g_psink_status->fp_sec_pd_vpdo_auth) {
  244. pr_err("%s: not exist\n", __func__);
  245. return -1;
  246. }
  247. g_psink_status->fp_sec_pd_vpdo_auth(auth, d2d_type);
  248. return 0;
  249. }
  250. EXPORT_SYMBOL(sec_pd_vpdo_auth);
  251. int sec_pd_change_src(int max_cur)
  252. {
  253. if (!g_psink_status) {
  254. pr_err("%s: g_psink_status is NULL\n", __func__);
  255. return -1;
  256. }
  257. if (!g_psink_status->fp_sec_pd_change_src) {
  258. pr_err("%s: not exist\n", __func__);
  259. return -1;
  260. }
  261. g_psink_status->fp_sec_pd_change_src(max_cur);
  262. return 0;
  263. }
  264. EXPORT_SYMBOL(sec_pd_change_src);
  265. int sec_pd_get_apdo_max_power(unsigned int *pdo_pos, unsigned int *taMaxVol, unsigned int *taMaxCur, unsigned int *taMaxPwr)
  266. {
  267. int i;
  268. int fpdo_max_power = 0;
  269. if (!g_psink_status) {
  270. pr_err("%s: g_psink_status is NULL\n", __func__);
  271. return -1;
  272. }
  273. if (!g_psink_status->has_apdo) {
  274. pr_info("%s: pd don't have apdo\n", __func__);
  275. return -1;
  276. }
  277. for (i = 1; i <= g_psink_status->available_pdo_num; i++) {
  278. if (g_psink_status->power_list[i].pdo_type != APDO_TYPE) {
  279. fpdo_max_power =
  280. (g_psink_status->power_list[i].max_voltage * g_psink_status->power_list[i].max_current) > fpdo_max_power ?
  281. (g_psink_status->power_list[i].max_voltage * g_psink_status->power_list[i].max_current) : fpdo_max_power;
  282. }
  283. }
  284. if (*pdo_pos == 0) {
  285. /* min(max power of all fpdo, max power of selected apdo) */
  286. for (i = 1; i <= g_psink_status->available_pdo_num; i++) {
  287. if ((g_psink_status->power_list[i].pdo_type == APDO_TYPE) &&
  288. g_psink_status->power_list[i].accept &&
  289. (g_psink_status->power_list[i].max_voltage >= *taMaxVol)) {
  290. *pdo_pos = i;
  291. *taMaxVol = g_psink_status->power_list[i].max_voltage;
  292. *taMaxCur = g_psink_status->power_list[i].max_current;
  293. *taMaxPwr = min(fpdo_max_power,
  294. (g_psink_status->power_list[i].max_voltage * g_psink_status->power_list[i].max_current));
  295. pr_info("%s : *pdo_pos(%d), *taMaxVol(%d), *maxCur(%d), *maxPwr(%d)\n",
  296. __func__, *pdo_pos, *taMaxVol, *taMaxCur, *taMaxPwr);
  297. return 0;
  298. }
  299. }
  300. } else {
  301. /* If we already have pdo object position, we don't need to search max current */
  302. return -ENOTSUPP;
  303. }
  304. pr_info("mv (%d) and ma (%d) out of range of APDO\n", *taMaxVol, *taMaxCur);
  305. return -EINVAL;
  306. }
  307. EXPORT_SYMBOL(sec_pd_get_apdo_max_power);
  308. void sec_pd_init_data(SEC_PD_SINK_STATUS* psink_status)
  309. {
  310. g_psink_status = psink_status;
  311. if (g_psink_status)
  312. pr_info("%s: done.\n", __func__);
  313. else
  314. pr_err("%s: g_psink_status is NULL\n", __func__);
  315. }
  316. EXPORT_SYMBOL(sec_pd_init_data);
  317. int sec_pd_register_chg_info_cb(void *cb)
  318. {
  319. if (!g_psink_status) {
  320. pr_err("%s: g_psink_status is NULL\n", __func__);
  321. return -1;
  322. }
  323. g_psink_status->fp_sec_pd_ext_cb = cb;
  324. return 0;
  325. }
  326. EXPORT_SYMBOL(sec_pd_register_chg_info_cb);
  327. void sec_pd_get_vid_pid(unsigned short *vid, unsigned short *pid, unsigned int *xid)
  328. {
  329. if (!g_psink_status) {
  330. pr_err("%s: g_psink_status is NULL\n", __func__);
  331. return;
  332. }
  333. *vid = g_psink_status->vid;
  334. *pid = g_psink_status->pid;
  335. *xid = g_psink_status->xid;
  336. }
  337. EXPORT_SYMBOL(sec_pd_get_vid_pid);
  338. void sec_pd_manual_ccopen_req(int is_on)
  339. {
  340. if (!g_psink_status) {
  341. pr_err("%s: g_psink_status is NULL\n", __func__);
  342. return;
  343. }
  344. if (!g_psink_status->fp_sec_pd_manual_ccopen_req) {
  345. pr_err("%s: not exist\n", __func__);
  346. return;
  347. }
  348. g_psink_status->fp_sec_pd_manual_ccopen_req(is_on);
  349. }
  350. EXPORT_SYMBOL(sec_pd_manual_ccopen_req);
  351. void sec_pd_manual_jig_ctrl(bool mode)
  352. {
  353. if (!g_psink_status) {
  354. pr_err("%s: g_psink_status is NULL\n", __func__);
  355. return;
  356. }
  357. if (!g_psink_status->fp_sec_pd_manual_jig_ctrl) {
  358. pr_err("%s: not exist\n", __func__);
  359. return;
  360. }
  361. g_psink_status->fp_sec_pd_manual_jig_ctrl(mode);
  362. }
  363. EXPORT_SYMBOL(sec_pd_manual_jig_ctrl);
  364. static int __init sec_pd_init(void)
  365. {
  366. pr_info("%s: \n", __func__);
  367. return 0;
  368. }
  369. module_init(sec_pd_init);
  370. MODULE_DESCRIPTION("Samsung PD control");
  371. MODULE_AUTHOR("Samsung Electronics");
  372. MODULE_LICENSE("GPL");