charge.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. #include "asm/clock.h"
  2. #include "timer.h"
  3. #include "asm/power/p33.h"
  4. #include "asm/charge.h"
  5. #include "asm/adc_api.h"
  6. #include "uart.h"
  7. #include "device/device.h"
  8. #include "asm/power_interface.h"
  9. #include "system/event.h"
  10. #include "asm/efuse.h"
  11. #include "gpio.h"
  12. #include "app_config.h"
  13. #define LOG_TAG_CONST CHARGE
  14. #define LOG_TAG "[CHARGE]"
  15. #define LOG_INFO_ENABLE
  16. #define LOG_DUMP_ENABLE
  17. #define LOG_ERROR_ENABLE
  18. #define LOG_DEBUG_ENABLE
  19. #include "debug.h"
  20. typedef struct _CHARGE_VAR {
  21. struct charge_platform_data *data;
  22. volatile u8 charge_online_flag;
  23. volatile u8 charge_event_flag;
  24. volatile u8 init_ok;
  25. volatile u8 detect_stop; //检测暂停或者继续
  26. volatile int ldo5v_timer; //检测LDOIN状态变化的usr timer
  27. volatile int charge_timer; //检测充电是否充满的usr timer
  28. volatile int cc_timer; //涓流切恒流的sys timer
  29. } CHARGE_VAR;
  30. #define __this (&charge_var)
  31. static CHARGE_VAR charge_var;
  32. static u8 charge_flag;
  33. extern const int set_to_close_timer0_delay;
  34. #define BIT_LDO5V_IN BIT(0)
  35. #define BIT_LDO5V_OFF BIT(1)
  36. #define BIT_LDO5V_KEEP BIT(2)
  37. u8 get_charge_poweron_en(void)
  38. {
  39. return __this->data->charge_poweron_en;
  40. }
  41. void charge_check_and_set_pinr(u8 level)
  42. {
  43. u8 pinr_io, reg;
  44. reg = P33_CON_GET(P3_PINR1_CON);
  45. //开启LDO5V_DET长按复位
  46. if ((reg & BIT(0)) && ((reg & BIT(3)) == 0)) {
  47. if (level == 0) {
  48. P33_CON_SET(P3_PINR1_CON, 2, 1, 0);
  49. } else {
  50. P33_CON_SET(P3_PINR1_CON, 2, 1, 1);
  51. }
  52. }
  53. }
  54. static void udelay(u32 usec)
  55. {
  56. if (set_to_close_timer0_delay) {
  57. JL_MCPWM->MCPWM_CON0 &= ~BIT(8 + 3);
  58. JL_MCPWM->TMR3_CNT = 0;
  59. JL_MCPWM->TMR3_PR = clk_get("lsb") / 1000000 * usec;
  60. JL_MCPWM->TMR3_CON = BIT(10) | BIT(0);
  61. JL_MCPWM->MCPWM_CON0 |= BIT(8 + 3);
  62. while (!(JL_MCPWM->TMR3_CON & BIT(12)));
  63. JL_MCPWM->TMR3_CON = BIT(10);
  64. JL_MCPWM->MCPWM_CON0 &= ~BIT(8 + 3);
  65. } else {
  66. JL_TIMER0->CON = BIT(14);
  67. JL_TIMER0->CNT = 0;
  68. JL_TIMER0->PRD = clk_get("timer") / 1000000L * usec; //1us
  69. JL_TIMER0->CON = BIT(0) | BIT(2) | BIT(6); //sys clk
  70. while ((JL_TIMER0->CON & BIT(15)) == 0);
  71. JL_TIMER0->CON = BIT(14);
  72. }
  73. }
  74. static u8 check_charge_state(void)
  75. {
  76. u8 online_cnt = 0;
  77. u8 i = 0;
  78. __this->charge_online_flag = 0;
  79. for (i = 0; i < 20; i++) {
  80. if (LVCMP_DET_GET() || LDO5V_DET_GET()) {
  81. online_cnt++;
  82. }
  83. udelay(1000);
  84. }
  85. log_info("online_cnt = %d\n", online_cnt);
  86. if (online_cnt > 5) {
  87. __this->charge_online_flag = 1;
  88. }
  89. return __this->charge_online_flag;
  90. }
  91. void set_charge_online_flag(u8 flag)
  92. {
  93. __this->charge_online_flag = flag;
  94. }
  95. u8 get_charge_online_flag(void)
  96. {
  97. return __this->charge_online_flag;
  98. }
  99. void set_charge_event_flag(u8 flag)
  100. {
  101. __this->charge_event_flag = flag;
  102. }
  103. u8 get_ldo5v_online_hw(void)
  104. {
  105. return LDO5V_DET_GET();
  106. }
  107. u8 get_lvcmp_det(void)
  108. {
  109. return LVCMP_DET_GET();
  110. }
  111. u8 get_ldo5v_pulldown_en(void)
  112. {
  113. if (!__this->data) {
  114. return 0;
  115. }
  116. if (__this->data->ldo5v_pulldown_keep == 0) {
  117. return 0;
  118. }
  119. return __this->data->ldo5v_pulldown_en;
  120. }
  121. u8 get_ldo5v_pulldown_res(void)
  122. {
  123. if (__this->data) {
  124. return __this->data->ldo5v_pulldown_lvl;
  125. }
  126. return CHARGE_PULLDOWN_200K;
  127. }
  128. void charge_event_to_user(u8 event)
  129. {
  130. struct sys_event e;
  131. e.type = SYS_DEVICE_EVENT;
  132. e.arg = (void *)DEVICE_EVENT_FROM_CHARGE;
  133. e.u.dev.event = event;
  134. e.u.dev.value = 0;
  135. sys_event_notify(&e);
  136. }
  137. void power_enter_charge_mode(void)
  138. {
  139. if (TCFG_LOWPOWER_POWER_SEL == PWR_DCDC15) {
  140. power_set_charge_mode(1);
  141. power_set_mode(PWR_DCDC15_FOR_CHARGE);
  142. }
  143. }
  144. void power_exit_charge_mode(void)
  145. {
  146. if (TCFG_LOWPOWER_POWER_SEL == PWR_DCDC15) {
  147. power_set_charge_mode(0);
  148. power_set_mode(TCFG_LOWPOWER_POWER_SEL);
  149. }
  150. }
  151. static void charge_cc_check(void *priv)
  152. {
  153. if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
  154. set_charge_mA(__this->data->charge_mA);
  155. usr_timer_del(__this->cc_timer);
  156. __this->cc_timer = 0;
  157. }
  158. }
  159. void charge_start(void)
  160. {
  161. log_info("%s\n", __func__);
  162. if (__this->charge_timer) {
  163. usr_timer_del(__this->charge_timer);
  164. __this->charge_timer = 0;
  165. }
  166. if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
  167. set_charge_mA(__this->data->charge_mA);
  168. } else {
  169. set_charge_mA(CHARGE_mA_20);
  170. if (!__this->cc_timer) {
  171. __this->cc_timer = usr_timer_add(NULL, charge_cc_check, 1000, 1);
  172. }
  173. }
  174. power_awakeup_enable_with_port(IO_CHGFL_DET);
  175. CHARGE_EN(1);
  176. charge_event_to_user(CHARGE_EVENT_CHARGE_START);
  177. }
  178. void charge_close(void)
  179. {
  180. log_info("%s\n", __func__);
  181. if (charge_flag != BIT_LDO5V_IN) {
  182. CHARGE_EN(0);
  183. }
  184. power_awakeup_disable_with_port(IO_CHGFL_DET);
  185. charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
  186. if (__this->charge_timer) {
  187. usr_timer_del(__this->charge_timer);
  188. __this->charge_timer = 0;
  189. }
  190. if (__this->cc_timer) {
  191. usr_timer_del(__this->cc_timer);
  192. __this->cc_timer = 0;
  193. }
  194. }
  195. static void charge_full_detect(void *priv)
  196. {
  197. static u16 charge_full_cnt = 0;
  198. if (CHARGE_FULL_FLAG_GET() && LVCMP_DET_GET()) {
  199. /* putchar('F'); */
  200. if (charge_full_cnt < 5) {
  201. charge_full_cnt++;
  202. } else {
  203. charge_full_cnt = 0;
  204. usr_timer_del(__this->charge_timer);
  205. __this->charge_timer = 0;
  206. charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
  207. }
  208. } else {
  209. /* putchar('K'); */
  210. charge_full_cnt = 0;
  211. usr_timer_del(__this->charge_timer);
  212. __this->charge_timer = 0;
  213. power_awakeup_enable_with_port(IO_CHGFL_DET);
  214. }
  215. }
  216. static void ldo5v_detect(void *priv)
  217. {
  218. /* log_info("%s\n",__func__); */
  219. static u16 ldo5v_on_cnt = 0;
  220. static u16 ldo5v_keep_cnt = 0;
  221. static u16 ldo5v_off_cnt = 0;
  222. if (__this->detect_stop) {
  223. return;
  224. }
  225. if (LVCMP_DET_GET()) { //ldoin > vbat
  226. /* putchar('X'); */
  227. if (ldo5v_on_cnt < __this->data->ldo5v_on_filter) {
  228. ldo5v_on_cnt++;
  229. } else {
  230. /* printf("ldo5V_IN\n"); */
  231. set_charge_online_flag(1);
  232. ldo5v_off_cnt = 0;
  233. ldo5v_keep_cnt = 0;
  234. //消息线程未准备好接收消息,继续扫描
  235. if (__this->charge_event_flag == 0) {
  236. return;
  237. }
  238. ldo5v_on_cnt = 0;
  239. usr_timer_del(__this->ldo5v_timer);
  240. __this->ldo5v_timer = 0;
  241. power_enter_charge_mode();
  242. if ((charge_flag & BIT_LDO5V_IN) == 0) {
  243. charge_flag = BIT_LDO5V_IN;
  244. charge_event_to_user(CHARGE_EVENT_LDO5V_IN);
  245. }
  246. }
  247. } else if (LDO5V_DET_GET() == 0) { //ldoin<拔出电压(0.6)
  248. /* putchar('Q'); */
  249. if (ldo5v_off_cnt < (__this->data->ldo5v_off_filter + 20)) {
  250. ldo5v_off_cnt++;
  251. } else {
  252. /* printf("ldo5V_OFF\n"); */
  253. set_charge_online_flag(0);
  254. ldo5v_on_cnt = 0;
  255. ldo5v_keep_cnt = 0;
  256. //消息线程未准备好接收消息,继续扫描
  257. if (__this->charge_event_flag == 0) {
  258. return;
  259. }
  260. ldo5v_off_cnt = 0;
  261. usr_timer_del(__this->ldo5v_timer);
  262. __this->ldo5v_timer = 0;
  263. power_exit_charge_mode();
  264. if ((charge_flag & BIT_LDO5V_OFF) == 0) {
  265. charge_flag = BIT_LDO5V_OFF;
  266. charge_event_to_user(CHARGE_EVENT_LDO5V_OFF);
  267. }
  268. }
  269. } else { //拔出电压(0.6左右)< ldoin < vbat
  270. /* putchar('E'); */
  271. if (ldo5v_keep_cnt < __this->data->ldo5v_keep_filter) {
  272. ldo5v_keep_cnt++;
  273. } else {
  274. /* printf("ldo5V_ERR\n"); */
  275. set_charge_online_flag(1);
  276. ldo5v_off_cnt = 0;
  277. ldo5v_on_cnt = 0;
  278. //消息线程未准备好接收消息,继续扫描
  279. if (__this->charge_event_flag == 0) {
  280. return;
  281. }
  282. ldo5v_keep_cnt = 0;
  283. usr_timer_del(__this->ldo5v_timer);
  284. power_exit_charge_mode();
  285. __this->ldo5v_timer = 0;
  286. if ((charge_flag & BIT_LDO5V_KEEP) == 0) {
  287. charge_flag = BIT_LDO5V_KEEP;
  288. if (__this->data->ldo5v_off_filter) {
  289. charge_event_to_user(CHARGE_EVENT_LDO5V_KEEP);
  290. }
  291. }
  292. }
  293. }
  294. }
  295. void ldoin_wakeup_isr(void)
  296. {
  297. if (!__this->init_ok) {
  298. return;
  299. }
  300. /* printf(" %s \n", __func__); */
  301. if (__this->ldo5v_timer == 0) {
  302. __this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
  303. }
  304. }
  305. void charge_wakeup_isr(void)
  306. {
  307. if (!__this->init_ok) {
  308. return;
  309. }
  310. /* printf(" %s \n", __func__); */
  311. power_awakeup_disable_with_port(IO_CHGFL_DET);
  312. if (__this->charge_timer == 0) {
  313. __this->charge_timer = usr_timer_add(0, charge_full_detect, 2, 1);
  314. }
  315. }
  316. void charge_set_ldo5v_detect_stop(u8 stop)
  317. {
  318. __this->detect_stop = stop;
  319. }
  320. u8 get_charge_mA_config(void)
  321. {
  322. return __this->data->charge_mA;
  323. }
  324. void set_charge_mA(u8 charge_mA)
  325. {
  326. static u8 charge_mA_old = 0xff;
  327. if (charge_mA_old != charge_mA) {
  328. charge_mA_old = charge_mA;
  329. CHARGE_mA_SEL(charge_mA);
  330. }
  331. }
  332. const u16 full_table[CHARGE_FULL_V_MAX] = {
  333. 3962, 4002, 4044, 4086, 4130, 4175, 4222, 4270,
  334. 4308, 4349, 4391, 4434, 4472, 4517, 4564, 4611
  335. };
  336. u16 get_charge_full_value(void)
  337. {
  338. ASSERT(__this->init_ok, "charge not init ok!\n");
  339. ASSERT(__this->data->charge_full_V < CHARGE_FULL_V_MAX);
  340. return full_table[__this->data->charge_full_V];
  341. }
  342. static void charge_config(void)
  343. {
  344. u8 charge_4202_trim_val = CHARGE_FULL_V_4222;
  345. u8 offset = 0;
  346. u8 charge_full_v_val = 0;
  347. if (get_vbat_trim() == 0xf) {
  348. log_info("vbat not trim, use default config!!!!!!");
  349. } else {
  350. charge_4202_trim_val = get_vbat_trim(); //4.2V对应的trim出来的实际档位
  351. }
  352. log_info("charge_4202_trim_val = %d\n", charge_4202_trim_val);
  353. if (__this->data->charge_full_V >= CHARGE_FULL_V_4222) {
  354. offset = __this->data->charge_full_V - CHARGE_FULL_V_4222;
  355. charge_full_v_val = charge_4202_trim_val + offset;
  356. if (charge_full_v_val > 0xf) {
  357. charge_full_v_val = 0xf;
  358. }
  359. } else {
  360. offset = CHARGE_FULL_V_4222 - __this->data->charge_full_V;
  361. if (charge_4202_trim_val >= offset) {
  362. charge_full_v_val = charge_4202_trim_val - offset;
  363. } else {
  364. charge_full_v_val = 0;
  365. }
  366. }
  367. log_info("charge_full_v_val = %d\n", charge_full_v_val);
  368. CHARGE_FULL_V_SEL(charge_full_v_val);
  369. CHARGE_FULL_mA_SEL(__this->data->charge_full_mA);
  370. /* CHARGE_mA_SEL(__this->data->charge_mA); */
  371. CHARGE_mA_SEL(CHARGE_mA_20);
  372. }
  373. int charge_init(const struct dev_node *node, void *arg)
  374. {
  375. log_info("%s\n", __func__);
  376. __this->data = (struct charge_platform_data *)arg;
  377. ASSERT(__this->data);
  378. __this->init_ok = 0;
  379. __this->charge_online_flag = 0;
  380. /*先关闭充电使能,后面检测到充电插入再开启*/
  381. power_awakeup_disable_with_port(IO_CHGFL_DET);
  382. CHARGE_EN(0);
  383. /*LDO5V的100K下拉电阻使能*/
  384. L5V_RES_DET_S_SEL(__this->data->ldo5v_pulldown_lvl);
  385. L5V_LOAD_EN(__this->data->ldo5v_pulldown_en);
  386. charge_config();
  387. if (check_charge_state()) {
  388. if (__this->ldo5v_timer == 0) {
  389. __this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
  390. }
  391. } else {
  392. charge_flag = BIT_LDO5V_OFF;
  393. power_exit_charge_mode();
  394. }
  395. __this->init_ok = 1;
  396. return 0;
  397. }
  398. void charge_module_stop(void)
  399. {
  400. if (!__this->init_ok) {
  401. return;
  402. }
  403. charge_close();
  404. power_awakeup_disable_with_port(IO_LDOIN_DET);
  405. power_awakeup_disable_with_port(IO_VBTCH_DET);
  406. if (__this->ldo5v_timer) {
  407. usr_timer_del(__this->ldo5v_timer);
  408. __this->ldo5v_timer = 0;
  409. }
  410. }
  411. void charge_module_restart(void)
  412. {
  413. if (!__this->init_ok) {
  414. return;
  415. }
  416. if (!__this->ldo5v_timer) {
  417. __this->ldo5v_timer = usr_timer_add(NULL, ldo5v_detect, 2, 1);
  418. }
  419. power_awakeup_enable_with_port(IO_LDOIN_DET);
  420. power_awakeup_enable_with_port(IO_VBTCH_DET);
  421. }
  422. int charge_api_init(void *arg)
  423. {
  424. return charge_init(NULL, arg);
  425. }
  426. const struct device_operations charge_dev_ops = {
  427. .init = charge_init,
  428. };