fan5405.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. #include <linux/types.h>
  2. #include <linux/init.h> /* For init/exit macros */
  3. #include <linux/module.h> /* For MODULE_ marcros */
  4. #include <linux/platform_device.h>
  5. #include <linux/i2c.h>
  6. #include <linux/slab.h>
  7. #ifdef CONFIG_OF
  8. #include <linux/of.h>
  9. #include <linux/of_irq.h>
  10. #include <linux/of_address.h>
  11. #endif
  12. #include <mt-plat/charging.h>
  13. #include "fan5405.h"
  14. #define fan5405_SLAVE_ADDR_WRITE 0xD4
  15. #define fan5405_SLAVE_ADDR_READ 0xD5
  16. static struct i2c_client *new_client;
  17. static const struct i2c_device_id fan5405_i2c_id[] = { {"fan5405", 0}, {} };
  18. kal_bool chargin_hw_init_done = KAL_FALSE;
  19. static int fan5405_driver_probe(struct i2c_client *client, const struct i2c_device_id *id);
  20. #ifdef CONFIG_OF
  21. static const struct of_device_id fan5405_of_match[] = {
  22. {.compatible = "fan5405",},
  23. {},
  24. };
  25. MODULE_DEVICE_TABLE(of, fan5405_of_match);
  26. #endif
  27. static struct i2c_driver fan5405_driver = {
  28. .driver = {
  29. .name = "fan5405",
  30. #ifdef CONFIG_OF
  31. .of_match_table = fan5405_of_match,
  32. #endif
  33. },
  34. .probe = fan5405_driver_probe,
  35. .id_table = fan5405_i2c_id,
  36. };
  37. /**********************************************************
  38. *
  39. * [Global Variable]
  40. *
  41. *********************************************************/
  42. unsigned char fan5405_reg[fan5405_REG_NUM] = { 0 };
  43. static DEFINE_MUTEX(fan5405_i2c_access);
  44. int g_fan5405_hw_exist = 0;
  45. /**********************************************************
  46. *
  47. * [I2C Function For Read/Write fan5405]
  48. *
  49. *********************************************************/
  50. int fan5405_read_byte(unsigned char cmd, unsigned char *returnData)
  51. {
  52. char cmd_buf[1] = { 0x00 };
  53. char readData = 0;
  54. int ret = 0;
  55. mutex_lock(&fan5405_i2c_access);
  56. new_client->ext_flag =
  57. ((new_client->ext_flag) & I2C_MASK_FLAG) | I2C_WR_FLAG | I2C_DIRECTION_FLAG;
  58. cmd_buf[0] = cmd;
  59. ret = i2c_master_send(new_client, &cmd_buf[0], (1 << 8 | 1));
  60. if (ret < 0) {
  61. new_client->ext_flag = 0;
  62. mutex_unlock(&fan5405_i2c_access);
  63. return 0;
  64. }
  65. readData = cmd_buf[0];
  66. *returnData = readData;
  67. new_client->ext_flag = 0;
  68. mutex_unlock(&fan5405_i2c_access);
  69. return 1;
  70. }
  71. int fan5405_write_byte(unsigned char cmd, unsigned char writeData)
  72. {
  73. char write_data[2] = { 0 };
  74. int ret = 0;
  75. mutex_lock(&fan5405_i2c_access);
  76. write_data[0] = cmd;
  77. write_data[1] = writeData;
  78. new_client->ext_flag = ((new_client->ext_flag) & I2C_MASK_FLAG) | I2C_DIRECTION_FLAG;
  79. ret = i2c_master_send(new_client, write_data, 2);
  80. if (ret < 0) {
  81. new_client->ext_flag = 0;
  82. mutex_unlock(&fan5405_i2c_access);
  83. return 0;
  84. }
  85. new_client->ext_flag = 0;
  86. mutex_unlock(&fan5405_i2c_access);
  87. return 1;
  88. }
  89. /**********************************************************
  90. *
  91. * [Read / Write Function]
  92. *
  93. *********************************************************/
  94. unsigned int fan5405_read_interface(unsigned char RegNum, unsigned char *val, unsigned char MASK,
  95. unsigned char SHIFT)
  96. {
  97. unsigned char fan5405_reg = 0;
  98. int ret = 0;
  99. ret = fan5405_read_byte(RegNum, &fan5405_reg);
  100. battery_log(BAT_LOG_FULL, "[fan5405_read_interface] Reg[%x]=0x%x\n", RegNum, fan5405_reg);
  101. fan5405_reg &= (MASK << SHIFT);
  102. *val = (fan5405_reg >> SHIFT);
  103. battery_log(BAT_LOG_FULL, "[fan5405_read_interface] val=0x%x\n", *val);
  104. return ret;
  105. }
  106. unsigned int fan5405_config_interface(unsigned char RegNum, unsigned char val, unsigned char MASK,
  107. unsigned char SHIFT)
  108. {
  109. unsigned char fan5405_reg = 0;
  110. int ret = 0;
  111. ret = fan5405_read_byte(RegNum, &fan5405_reg);
  112. battery_log(BAT_LOG_FULL, "[fan5405_config_interface] Reg[%x]=0x%x\n", RegNum, fan5405_reg);
  113. fan5405_reg &= ~(MASK << SHIFT);
  114. fan5405_reg |= (val << SHIFT);
  115. if (RegNum == fan5405_CON4 && val == 1 && MASK == CON4_RESET_MASK
  116. && SHIFT == CON4_RESET_SHIFT) {
  117. /* RESET bit */
  118. } else if (RegNum == fan5405_CON4) {
  119. fan5405_reg &= ~0x80; /* RESET bit read returs 1, so clear it */
  120. }
  121. ret = fan5405_write_byte(RegNum, fan5405_reg);
  122. battery_log(BAT_LOG_FULL, "[fan5405_config_interface] write Reg[%x]=0x%x\n", RegNum,
  123. fan5405_reg);
  124. return ret;
  125. }
  126. /* write one register directly */
  127. unsigned int fan5405_reg_config_interface(unsigned char RegNum, unsigned char val)
  128. {
  129. int ret = 0;
  130. ret = fan5405_write_byte(RegNum, val);
  131. return ret;
  132. }
  133. /**********************************************************
  134. *
  135. * [Internal Function]
  136. *
  137. *********************************************************/
  138. /* CON0 */
  139. void fan5405_set_tmr_rst(unsigned int val)
  140. {
  141. unsigned int ret = 0;
  142. ret = fan5405_config_interface((unsigned char) (fan5405_CON0),
  143. (unsigned char) (val),
  144. (unsigned char) (CON0_TMR_RST_MASK),
  145. (unsigned char) (CON0_TMR_RST_SHIFT)
  146. );
  147. }
  148. unsigned int fan5405_get_otg_status(void)
  149. {
  150. unsigned int ret = 0;
  151. unsigned char val = 0;
  152. ret = fan5405_read_interface((unsigned char) (fan5405_CON0),
  153. (&val), (unsigned char) (CON0_OTG_MASK),
  154. (unsigned char) (CON0_OTG_SHIFT)
  155. );
  156. return val;
  157. }
  158. void fan5405_set_en_stat(unsigned int val)
  159. {
  160. unsigned int ret = 0;
  161. ret = fan5405_config_interface((unsigned char) (fan5405_CON0),
  162. (unsigned char) (val),
  163. (unsigned char) (CON0_EN_STAT_MASK),
  164. (unsigned char) (CON0_EN_STAT_SHIFT)
  165. );
  166. }
  167. unsigned int fan5405_get_chip_status(void)
  168. {
  169. unsigned int ret = 0;
  170. unsigned char val = 0;
  171. ret = fan5405_read_interface((unsigned char) (fan5405_CON0),
  172. (&val), (unsigned char) (CON0_STAT_MASK),
  173. (unsigned char) (CON0_STAT_SHIFT)
  174. );
  175. return val;
  176. }
  177. unsigned int fan5405_get_boost_status(void)
  178. {
  179. unsigned int ret = 0;
  180. unsigned char val = 0;
  181. ret = fan5405_read_interface((unsigned char) (fan5405_CON0),
  182. (&val), (unsigned char) (CON0_BOOST_MASK),
  183. (unsigned char) (CON0_BOOST_SHIFT)
  184. );
  185. return val;
  186. }
  187. unsigned int fan5405_get_fault_status(void)
  188. {
  189. unsigned int ret = 0;
  190. unsigned char val = 0;
  191. ret = fan5405_read_interface((unsigned char) (fan5405_CON0),
  192. (&val), (unsigned char) (CON0_FAULT_MASK),
  193. (unsigned char) (CON0_FAULT_SHIFT)
  194. );
  195. return val;
  196. }
  197. /* CON1 */
  198. void fan5405_set_input_charging_current(unsigned int val)
  199. {
  200. unsigned int ret = 0;
  201. ret = fan5405_config_interface((unsigned char) (fan5405_CON1),
  202. (unsigned char) (val),
  203. (unsigned char) (CON1_LIN_LIMIT_MASK),
  204. (unsigned char) (CON1_LIN_LIMIT_SHIFT)
  205. );
  206. }
  207. void fan5405_set_v_low(unsigned int val)
  208. {
  209. unsigned int ret = 0;
  210. ret = fan5405_config_interface((unsigned char) (fan5405_CON1),
  211. (unsigned char) (val),
  212. (unsigned char) (CON1_LOW_V_MASK),
  213. (unsigned char) (CON1_LOW_V_SHIFT)
  214. );
  215. }
  216. void fan5405_set_te(unsigned int val)
  217. {
  218. unsigned int ret = 0;
  219. ret = fan5405_config_interface((unsigned char) (fan5405_CON1),
  220. (unsigned char) (val),
  221. (unsigned char) (CON1_TE_MASK),
  222. (unsigned char) (CON1_TE_SHIFT)
  223. );
  224. }
  225. void fan5405_set_ce(unsigned int val)
  226. {
  227. unsigned int ret = 0;
  228. ret = fan5405_config_interface((unsigned char) (fan5405_CON1),
  229. (unsigned char) (val),
  230. (unsigned char) (CON1_CE_MASK),
  231. (unsigned char) (CON1_CE_SHIFT)
  232. );
  233. }
  234. void fan5405_set_hz_mode(unsigned int val)
  235. {
  236. unsigned int ret = 0;
  237. ret = fan5405_config_interface((unsigned char) (fan5405_CON1),
  238. (unsigned char) (val),
  239. (unsigned char) (CON1_HZ_MODE_MASK),
  240. (unsigned char) (CON1_HZ_MODE_SHIFT)
  241. );
  242. }
  243. void fan5405_set_opa_mode(unsigned int val)
  244. {
  245. unsigned int ret = 0;
  246. ret = fan5405_config_interface((unsigned char) (fan5405_CON1),
  247. (unsigned char) (val),
  248. (unsigned char) (CON1_OPA_MODE_MASK),
  249. (unsigned char) (CON1_OPA_MODE_SHIFT)
  250. );
  251. }
  252. /* CON2 */
  253. void fan5405_set_oreg(unsigned int val)
  254. {
  255. unsigned int ret = 0;
  256. ret = fan5405_config_interface((unsigned char) (fan5405_CON2),
  257. (unsigned char) (val),
  258. (unsigned char) (CON2_OREG_MASK),
  259. (unsigned char) (CON2_OREG_SHIFT)
  260. );
  261. }
  262. void fan5405_set_otg_pl(unsigned int val)
  263. {
  264. unsigned int ret = 0;
  265. ret = fan5405_config_interface((unsigned char) (fan5405_CON2),
  266. (unsigned char) (val),
  267. (unsigned char) (CON2_OTG_PL_MASK),
  268. (unsigned char) (CON2_OTG_PL_SHIFT)
  269. );
  270. }
  271. void fan5405_set_otg_en(unsigned int val)
  272. {
  273. unsigned int ret = 0;
  274. ret = fan5405_config_interface((unsigned char) (fan5405_CON2),
  275. (unsigned char) (val),
  276. (unsigned char) (CON2_OTG_EN_MASK),
  277. (unsigned char) (CON2_OTG_EN_SHIFT)
  278. );
  279. }
  280. /* CON3 */
  281. unsigned int fan5405_get_vender_code(void)
  282. {
  283. unsigned int ret = 0;
  284. unsigned char val = 0;
  285. ret = fan5405_read_interface((unsigned char) (fan5405_CON3),
  286. (&val), (unsigned char) (CON3_VENDER_CODE_MASK),
  287. (unsigned char) (CON3_VENDER_CODE_SHIFT)
  288. );
  289. return val;
  290. }
  291. unsigned int fan5405_get_pn(void)
  292. {
  293. unsigned int ret = 0;
  294. unsigned char val = 0;
  295. ret = fan5405_read_interface((unsigned char) (fan5405_CON3),
  296. (&val), (unsigned char) (CON3_PIN_MASK),
  297. (unsigned char) (CON3_PIN_SHIFT)
  298. );
  299. return val;
  300. }
  301. unsigned int fan5405_get_revision(void)
  302. {
  303. unsigned int ret = 0;
  304. unsigned char val = 0;
  305. ret = fan5405_read_interface((unsigned char) (fan5405_CON3),
  306. (&val), (unsigned char) (CON3_REVISION_MASK),
  307. (unsigned char) (CON3_REVISION_SHIFT)
  308. );
  309. return val;
  310. }
  311. /* CON4 */
  312. void fan5405_set_reset(unsigned int val)
  313. {
  314. unsigned int ret = 0;
  315. ret = fan5405_config_interface((unsigned char) (fan5405_CON4),
  316. (unsigned char) (val),
  317. (unsigned char) (CON4_RESET_MASK),
  318. (unsigned char) (CON4_RESET_SHIFT)
  319. );
  320. }
  321. void fan5405_set_iocharge(unsigned int val)
  322. {
  323. unsigned int ret = 0;
  324. ret = fan5405_config_interface((unsigned char) (fan5405_CON4),
  325. (unsigned char) (val),
  326. (unsigned char) (CON4_I_CHR_MASK),
  327. (unsigned char) (CON4_I_CHR_SHIFT)
  328. );
  329. }
  330. void fan5405_set_iterm(unsigned int val)
  331. {
  332. unsigned int ret = 0;
  333. ret = fan5405_config_interface((unsigned char) (fan5405_CON4),
  334. (unsigned char) (val),
  335. (unsigned char) (CON4_I_TERM_MASK),
  336. (unsigned char) (CON4_I_TERM_SHIFT)
  337. );
  338. }
  339. /* CON5 */
  340. void fan5405_set_dis_vreg(unsigned int val)
  341. {
  342. unsigned int ret = 0;
  343. ret = fan5405_config_interface((unsigned char) (fan5405_CON5),
  344. (unsigned char) (val),
  345. (unsigned char) (CON5_DIS_VREG_MASK),
  346. (unsigned char) (CON5_DIS_VREG_SHIFT)
  347. );
  348. }
  349. void fan5405_set_io_level(unsigned int val)
  350. {
  351. unsigned int ret = 0;
  352. ret = fan5405_config_interface((unsigned char) (fan5405_CON5),
  353. (unsigned char) (val),
  354. (unsigned char) (CON5_IO_LEVEL_MASK),
  355. (unsigned char) (CON5_IO_LEVEL_SHIFT)
  356. );
  357. }
  358. unsigned int fan5405_get_sp_status(void)
  359. {
  360. unsigned int ret = 0;
  361. unsigned char val = 0;
  362. ret = fan5405_read_interface((unsigned char) (fan5405_CON5),
  363. (&val), (unsigned char) (CON5_SP_STATUS_MASK),
  364. (unsigned char) (CON5_SP_STATUS_SHIFT)
  365. );
  366. return val;
  367. }
  368. unsigned int fan5405_get_en_level(void)
  369. {
  370. unsigned int ret = 0;
  371. unsigned char val = 0;
  372. ret = fan5405_read_interface((unsigned char) (fan5405_CON5),
  373. (&val), (unsigned char) (CON5_EN_LEVEL_MASK),
  374. (unsigned char) (CON5_EN_LEVEL_SHIFT)
  375. );
  376. return val;
  377. }
  378. void fan5405_set_vsp(unsigned int val)
  379. {
  380. unsigned int ret = 0;
  381. ret = fan5405_config_interface((unsigned char) (fan5405_CON5),
  382. (unsigned char) (val),
  383. (unsigned char) (CON5_VSP_MASK),
  384. (unsigned char) (CON5_VSP_SHIFT)
  385. );
  386. }
  387. /* CON6 */
  388. void fan5405_set_i_safe(unsigned int val)
  389. {
  390. unsigned int ret = 0;
  391. ret = fan5405_config_interface((unsigned char) (fan5405_CON6),
  392. (unsigned char) (val),
  393. (unsigned char) (CON6_ISAFE_MASK),
  394. (unsigned char) (CON6_ISAFE_SHIFT)
  395. );
  396. }
  397. void fan5405_set_v_safe(unsigned int val)
  398. {
  399. unsigned int ret = 0;
  400. ret = fan5405_config_interface((unsigned char) (fan5405_CON6),
  401. (unsigned char) (val),
  402. (unsigned char) (CON6_VSAFE_MASK),
  403. (unsigned char) (CON6_VSAFE_SHIFT)
  404. );
  405. }
  406. /**********************************************************
  407. *
  408. * [Internal Function]
  409. *
  410. *********************************************************/
  411. void fan5405_hw_component_detect(void)
  412. {
  413. unsigned int ret = 0;
  414. unsigned char val = 0;
  415. ret = fan5405_read_interface(0x03, &val, 0xFF, 0x0);
  416. if (val == 0)
  417. g_fan5405_hw_exist = 0;
  418. else
  419. g_fan5405_hw_exist = 1;
  420. battery_log(BAT_LOG_CRTI, "[fan5405_hw_component_detect] exist=%d, Reg[03]=0x%x\n", g_fan5405_hw_exist, val);
  421. }
  422. int is_fan5405_exist(void)
  423. {
  424. battery_log(BAT_LOG_CRTI, "[is_fan5405_exist] g_fan5405_hw_exist=%d\n", g_fan5405_hw_exist);
  425. return g_fan5405_hw_exist;
  426. }
  427. void fan5405_dump_register(void)
  428. {
  429. int i = 0;
  430. battery_log(BAT_LOG_FULL, "[fan5405] ");
  431. for (i = 0; i < fan5405_REG_NUM; i++) {
  432. fan5405_read_byte(i, &fan5405_reg[i]);
  433. battery_log(BAT_LOG_FULL, "[0x%x]=0x%x ", i, fan5405_reg[i]);
  434. }
  435. battery_log(BAT_LOG_FULL, "\n");
  436. }
  437. static int fan5405_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
  438. {
  439. new_client = client;
  440. fan5405_hw_component_detect();
  441. fan5405_dump_register();
  442. chargin_hw_init_done = KAL_TRUE;
  443. return 0;
  444. }
  445. /**********************************************************
  446. *
  447. * [platform_driver API]
  448. *
  449. *********************************************************/
  450. unsigned char g_reg_value_fan5405 = 0;
  451. static ssize_t show_fan5405_access(struct device *dev, struct device_attribute *attr, char *buf)
  452. {
  453. battery_log(BAT_LOG_CRTI, "[show_fan5405_access] 0x%x\n", g_reg_value_fan5405);
  454. return sprintf(buf, "%u\n", g_reg_value_fan5405);
  455. }
  456. static ssize_t store_fan5405_access(struct device *dev, struct device_attribute *attr,
  457. const char *buf, size_t size)
  458. {
  459. int ret = 0;
  460. char *pvalue = NULL, *addr, *val;
  461. unsigned int reg_value = 0;
  462. unsigned int reg_address = 0;
  463. battery_log(BAT_LOG_CRTI, "[store_fan5405_access]\n");
  464. if (buf != NULL && size != 0) {
  465. pvalue = (char *)buf;
  466. if (size > 3) {
  467. addr = strsep(&pvalue, " ");
  468. ret = kstrtou32(addr, 16, (unsigned int *)&reg_address);
  469. } else
  470. ret = kstrtou32(pvalue, 16, (unsigned int *)&reg_address);
  471. if (size > 3) {
  472. val = strsep(&pvalue, " ");
  473. ret = kstrtou32(val, 16, (unsigned int *)&reg_value);
  474. battery_log(BAT_LOG_CRTI,
  475. "[store_fan5405_access] write fan5405 reg 0x%x with value 0x%x !\n",
  476. reg_address, reg_value);
  477. ret = fan5405_config_interface(reg_address, reg_value, 0xFF, 0x0);
  478. } else {
  479. ret = fan5405_read_interface(reg_address, &g_reg_value_fan5405, 0xFF, 0x0);
  480. battery_log(BAT_LOG_CRTI,
  481. "[store_fan5405_access] read fan5405 reg 0x%x with value 0x%x !\n",
  482. reg_address, g_reg_value_fan5405);
  483. battery_log(BAT_LOG_CRTI,
  484. "[store_fan5405_access] Please use \"cat fan5405_access\" to get value\r\n");
  485. }
  486. }
  487. return size;
  488. }
  489. static DEVICE_ATTR(fan5405_access, 0664, show_fan5405_access, store_fan5405_access); /* 664 */
  490. static int fan5405_user_space_probe(struct platform_device *dev)
  491. {
  492. int ret_device_file = 0;
  493. battery_log(BAT_LOG_CRTI, "******** fan5405_user_space_probe!! ********\n");
  494. ret_device_file = device_create_file(&(dev->dev), &dev_attr_fan5405_access);
  495. return 0;
  496. }
  497. struct platform_device fan5405_user_space_device = {
  498. .name = "fan5405-user",
  499. .id = -1,
  500. };
  501. static struct platform_driver fan5405_user_space_driver = {
  502. .probe = fan5405_user_space_probe,
  503. .driver = {
  504. .name = "fan5405-user",
  505. },
  506. };
  507. static int __init fan5405_init(void)
  508. {
  509. int ret = 0;
  510. if (i2c_add_driver(&fan5405_driver) != 0) {
  511. battery_log(BAT_LOG_CRTI,
  512. "[fan5405_init] failed to register fan5405 i2c driver.\n");
  513. } else {
  514. battery_log(BAT_LOG_CRTI,
  515. "[fan5405_init] Success to register fan5405 i2c driver.\n");
  516. }
  517. /* fan5405 user space access interface */
  518. ret = platform_device_register(&fan5405_user_space_device);
  519. if (ret) {
  520. battery_log(BAT_LOG_CRTI, "****[fan5405_init] Unable to device register(%d)\n",
  521. ret);
  522. return ret;
  523. }
  524. ret = platform_driver_register(&fan5405_user_space_driver);
  525. if (ret) {
  526. battery_log(BAT_LOG_CRTI, "****[fan5405_init] Unable to register driver (%d)\n",
  527. ret);
  528. return ret;
  529. }
  530. return 0;
  531. }
  532. static void __exit fan5405_exit(void)
  533. {
  534. i2c_del_driver(&fan5405_driver);
  535. }
  536. subsys_initcall(fan5405_init);
  537. MODULE_LICENSE("GPL");
  538. MODULE_DESCRIPTION("I2C fan5405 Driver");
  539. MODULE_AUTHOR("James Lo<james.lo@mediatek.com>");