ml5238.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include <string.h>
  2. #include "libs/shark_libs.h"
  3. #include "spi.h"
  4. #include "ml5238.h"
  5. #include "libs/logger.h"
  6. static int ml5238_read(uint8_t regaddr, uint8_t *data);
  7. static void ml5238_clear_bits(uint8_t regaddr, uint8_t bit);
  8. static void ml5238_set_bits(uint8_t regaddr, uint8_t bit);
  9. static void irq_hander_in_timer(shark_timer_t *timer);
  10. static ml5238_notify_hander _handler;
  11. static shark_timer_t irq_task = {.handler = irq_hander_in_timer};
  12. void ml5238_init(void){
  13. spi0_init();
  14. ml5238_softreset();
  15. ml5238_irq_enable(1);
  16. }
  17. uint8_t ml5238_noop_register_rw(uint8_t data){
  18. uint8_t value = data;
  19. ml5238_write(ML5238_NOOP, value);
  20. value = 0xFF;
  21. ml5238_read(ML5238_NOOP, &value);
  22. return value;
  23. }
  24. void ml5238_register_notify_handler(ml5238_notify_hander handler){
  25. _handler = handler;
  26. }
  27. //小电流打开等效discharger mos打开
  28. int ml5238_charger_is_disconnect(int small_current_on){
  29. uint8_t value = 0;
  30. uint8_t fet = 0;
  31. ml5238_read(ML5238_FET, &fet);
  32. ml5238_read(ML5238_PSENSE, &value);
  33. if ((fet & FET_DF) || small_current_on){
  34. return (value & PSENSE_PSL);
  35. }
  36. return (value & PSENSE_PSH);
  37. }
  38. int ml5238_enable_load_detect(int enable){
  39. ml5238_clear_bits(ML5238_RSENSE, RSENSE_RRS);
  40. if (enable){
  41. ml5238_set_bits(ML5238_RSENSE, RSENSE_ERS);
  42. }else {
  43. ml5238_clear_bits(ML5238_RSENSE, RSENSE_ERS | RSENSE_IRS);
  44. }
  45. return 0;
  46. }
  47. int ml5238_is_load_disconnect(void){
  48. uint8_t value = 0;
  49. ml5238_read(ML5238_RSENSE, &value);
  50. return (value & RSENSE_RS);
  51. }
  52. #define IRS_IRQ 1 //load disconnect中断
  53. #define IPSL_IRQ 2 //charger over current
  54. #define ICS_IRQ 3 //短路中断
  55. int ml5238_enable_irq(int enable, int irq){
  56. if (irq == IRS_IRQ){
  57. ml5238_clear_bits(ML5238_RSENSE, RSENSE_RRS);
  58. if (enable){
  59. ml5238_set_bits(ML5238_RSENSE, RSENSE_IRS);
  60. }else {
  61. ml5238_clear_bits(ML5238_RSENSE, RSENSE_IRS);
  62. }
  63. }
  64. if (irq == IPSL_IRQ){
  65. ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSL);
  66. if (enable){
  67. ml5238_set_bits(ML5238_PSENSE, PSENSE_IPSL);
  68. }else {
  69. ml5238_clear_bits(ML5238_PSENSE, PSENSE_IPSL);
  70. }
  71. }
  72. if (irq == ICS_IRQ){
  73. ml5238_clear_bits(ML5238_RSENSE, RSENSE_RSC);
  74. if (enable){
  75. ml5238_set_bits(ML5238_RSENSE, RSENSE_ISC);
  76. }else {
  77. ml5238_clear_bits(ML5238_RSENSE, RSENSE_ISC);
  78. }
  79. }
  80. return 0;
  81. }
  82. //小电流打开等效discharger mos打开
  83. int ml5238_enable_charger_detect(int small_current_on, int enable){
  84. uint8_t fet = 0;
  85. ml5238_read(ML5238_FET, &fet);
  86. if ((fet & FET_DF) || small_current_on){ //discharger is on, used to detect charger over current
  87. ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSL);
  88. if (enable){
  89. ml5238_set_bits(ML5238_PSENSE, PSENSE_EPSL);
  90. }else {
  91. ml5238_clear_bits(ML5238_PSENSE, PSENSE_EPSL);
  92. }
  93. }else { //discharger if off, used when powerdown, charger is insert
  94. ml5238_clear_bits(ML5238_PSENSE, PSENSE_RPSH);
  95. if (enable){
  96. ml5238_set_bits(ML5238_PSENSE, PSENSE_EPSH);
  97. }else {
  98. ml5238_clear_bits(ML5238_PSENSE, PSENSE_EPSH);
  99. }
  100. }
  101. return 0;
  102. }
  103. static int __inline__ _charger_mosfet_is_open(void){
  104. uint8_t data;
  105. ml5238_read(ML5238_FET, &data);
  106. return (data & FET_CF) != 0;
  107. }
  108. static int __inline__ _discharger_mosfet_is_open(void){
  109. uint8_t data;
  110. ml5238_read(ML5238_FET, &data);
  111. return (data & FET_DF) != 0;
  112. }
  113. int ml5238_is_charging(void){
  114. return _charger_mosfet_is_open();
  115. }
  116. int ml5238_is_discharging(void){
  117. return _discharger_mosfet_is_open();
  118. }
  119. int ml5238_cell_start_balance(uint16_t balance_mask){
  120. ml5238_write(ML5238_CBALH, (balance_mask >> 8) & 0xFF);
  121. ml5238_write(ML5238_CBALL, balance_mask & 0xFF);
  122. if (balance_mask == 0) { //stop balance need check
  123. uint8_t datah = 0xFF;
  124. uint8_t datal = 0xFF;
  125. if ((ml5238_read(ML5238_CBALH, &datah) == 0) && (ml5238_read(ML5238_CBALL, &datal) == 0)) {
  126. if ((datah == 0) && (datal == 0)) {
  127. return 0;
  128. }
  129. }
  130. }
  131. return 1;
  132. }
  133. int ml5238_enable_discharger_mosfet(int enable){
  134. uint8_t data;
  135. if (ml5238_read(ML5238_FET, &data) == 0){
  136. if ((data & FET_DF) == enable){
  137. return 0; //alread enable/disabled
  138. }
  139. data &= ~(FET_DF);
  140. if (enable){
  141. data |= (FET_DF | FET_DRV);
  142. }else {
  143. if ((data & FET_CF) == 0){
  144. data &= ~(FET_DRV);
  145. }
  146. }
  147. return ml5238_write(ML5238_FET, data);
  148. }
  149. return -1;
  150. }
  151. /* when enable charger the discharger mosfet also must be enabled for charging */
  152. int ml5238_enable_charger_mosfet(int enable){
  153. uint8_t data;
  154. if (ml5238_read(ML5238_FET, &data) == 0){
  155. if (((data & FET_CF) >> 1) == enable){
  156. return 0; //alread enable/disabled
  157. }
  158. data &= ~(FET_CF);
  159. if (enable){
  160. data |= (FET_CF | FET_DRV);
  161. }else {
  162. if ((data & FET_DF) == 0){
  163. data &= ~(FET_DRV);
  164. }
  165. }
  166. return ml5238_write(ML5238_FET, data);
  167. }
  168. return -1;
  169. }
  170. int ml5238_enable_all_mosfet(int enable) {
  171. if (enable) {
  172. return ml5238_write(ML5238_FET, (FET_CF | FET_DF | FET_DRV));
  173. }else {
  174. return ml5238_write(ML5238_FET, 0);
  175. }
  176. }
  177. int ml5238_disable_mosdrv(void){
  178. uint8_t data;
  179. if ((ml5238_read(ML5238_FET, &data) == 0) && (data & FET_DRV)){
  180. data &= ~FET_DRV;
  181. return ml5238_write(ML5238_FET, data);
  182. }
  183. return -1;
  184. }
  185. int ml5238_is_mosdrv_strong(void){
  186. uint8_t data = 0xFF;
  187. if ((ml5238_read(ML5238_FET, &data) == 0) && (data & FET_DRV)){
  188. return 1;
  189. }
  190. return -1;
  191. }
  192. int ml5238_short_current_detect(int mode){
  193. uint8_t rsense = 0;
  194. if (mode >= SHORT_CURRENT_MODE_50A_100A){
  195. if (ml5238_read(ML5238_RSENSE, &rsense) == 0){
  196. if (ml5238_write(ML5238_SETSC, mode) == 0){
  197. rsense |= (RSENSE_ESC | RSENSE_ISC);//enable short current detect && irq
  198. rsense &= ~RSENSE_RSC;
  199. return ml5238_write(ML5238_RSENSE, rsense);
  200. }
  201. }
  202. }else {
  203. if (ml5238_read(ML5238_RSENSE, &rsense) == 0){
  204. rsense &= ~(RSENSE_ESC|RSENSE_ISC|RSENSE_RSC);
  205. return ml5238_write(ML5238_RSENSE, rsense);
  206. }
  207. }
  208. return -1;
  209. }
  210. int ml5238_is_short_current_enabled(int mode){
  211. uint8_t value = 0;
  212. if (ml5238_read(ML5238_SETSC, &value) < 0){
  213. return 0;
  214. }
  215. if (value != mode) {
  216. return 0;
  217. }
  218. value = 0;
  219. if (ml5238_read(ML5238_RSENSE, &value) < 0){
  220. return 0;
  221. }
  222. if ((value & (RSENSE_ESC | RSENSE_ISC)) != (RSENSE_ESC | RSENSE_ISC)){
  223. return 0;
  224. }
  225. if (value & RSENSE_RSC){
  226. return 0;
  227. }
  228. return 1;
  229. }
  230. void ml5238_softreset(void) {
  231. for(unsigned char i = 0u; i < 0x0Au; i++){
  232. ml5238_write((uint8_t)(ML5238_VMON + i), 0x00u);
  233. }
  234. }
  235. void ml5238_reg_log(void){
  236. uint8_t data = 0xFF;
  237. for(unsigned char i = 0u; i < 0x0Au; i++){
  238. ml5238_read((uint8_t)(ML5238_VMON + i), &data);
  239. sys_debug("Reg %d:0x%x\n", (ML5238_VMON + i), data);
  240. }
  241. }
  242. uint8_t ml5238_read_imon(void){
  243. uint8_t data = 0xFF;
  244. if (ml5238_read(ML5238_IMON, &data) < 0) {
  245. return 0xff;
  246. }
  247. return data;
  248. }
  249. void ml5238_power_down(void){
  250. do {
  251. ml5238_write(ML5238_PSENSE, PSENSE_EPSH|PSENSE_IPSH); //before power down, we must enable charger detect
  252. ml5238_write(ML5238_POWER, POWER_PDWN);
  253. }while(1);
  254. }
  255. void ml5238_power_save(int save){
  256. if (save) {
  257. ml5238_write(ML5238_PSENSE, 0);
  258. ML5238_VMON_DISABLE();
  259. ML5238_IMON_DISABLE();
  260. ml5238_write(ML5238_POWER, POWER_PSV);
  261. ml5238_irq_enable(1); //enable charger detect irq, to wakeup bms when charger insert
  262. spi0_deinit();
  263. }else {
  264. spi0_init();
  265. ml5238_write(ML5238_POWER, 0);
  266. }
  267. }
  268. static void __inline__ call_handler(int event){
  269. if (_handler) {
  270. _handler(event);
  271. }
  272. }
  273. static void irq_hander_in_timer(shark_timer_t *timer){
  274. uint8_t status = 0;
  275. ml5238_read(ML5238_STATUS, &status);
  276. if (status & STATUS_RPSL){//chargering over current
  277. sys_error("charger over current\n");
  278. ml5238_enable_charger_detect(0, 0);
  279. ml5238_enable_charger_detect(1, 0);
  280. call_handler(ML5238_Event_Charger_Over_Current);
  281. }
  282. if (status & STATUS_RSC) { //short current detect, close charger/discharger mosfet
  283. sys_error("short current\n");
  284. if (_charger_mosfet_is_open()) {
  285. ml5238_enable_charger_mosfet(0);
  286. }
  287. if (_discharger_mosfet_is_open()) {
  288. ml5238_enable_discharger_mosfet(0);
  289. }
  290. ml5238_short_current_detect(SHORT_CURRENT_MODE_DISABLE);
  291. call_handler(ML5238_Event_Short_Current);
  292. }
  293. if (status & STATUS_RRS) {//load disconnect, if short detect, we must wait load disconnected, and then can open discharger
  294. ml5238_enable_irq(0, IRS_IRQ);
  295. call_handler(ML5238_Event_Load_Disconnect);
  296. }
  297. }
  298. void ml5238_irq_handler(void){
  299. shark_timer_post(&irq_task, 0);
  300. }
  301. static void ml5238_set_bits(uint8_t regaddr, uint8_t bit) {
  302. uint8_t value;
  303. ml5238_read(regaddr, &value);
  304. ml5238_write(regaddr, value|bit);
  305. }
  306. static void ml5238_clear_bits(uint8_t regaddr, uint8_t bit) {
  307. uint8_t value;
  308. ml5238_read(regaddr, &value);
  309. ml5238_write(regaddr, value&(~bit));
  310. }
  311. int ml5238_write(uint8_t regaddr, uint8_t data){
  312. uint16_t send_data=(((uint16_t)regaddr)<<(0x09))|((uint16_t)data);
  313. ml5238_cs(0);
  314. int ret = spi0_send_uint16(send_data, NULL);
  315. ml5238_cs(1);
  316. return ret;
  317. }
  318. static int ml5238_read(uint8_t regaddr, uint8_t *data){
  319. uint16_t send_data=((((uint16_t)regaddr)<<(0x09))|0x0100u)|((uint16_t)0x00u);
  320. ml5238_cs(0);
  321. int ret = spi0_send_uint16(send_data, data);
  322. ml5238_cs(1);
  323. return ret;
  324. }