ml5238.c 8.6 KB

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