bq24196.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370
  1. #include <linux/interrupt.h>
  2. #include <linux/i2c.h>
  3. #include <linux/irq.h>
  4. #include <linux/delay.h>
  5. #include <linux/input.h>
  6. #include <linux/workqueue.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/gpio.h>
  9. #include <linux/reboot.h>
  10. #include <linux/switch.h>
  11. #include <linux/of.h>
  12. #include <linux/of_gpio.h>
  13. #include <linux/regulator/consumer.h>
  14. #include "bq24196.h"
  15. #include "mt_charging.h"
  16. #include <mt-plat/upmu_common.h>
  17. #include <mt-plat/mt_reboot.h>
  18. #include <mt-plat/mt_boot.h>
  19. /**********************************************************
  20. *
  21. * [Define]
  22. *
  23. **********************************************************/
  24. #define STATUS_OK 0
  25. #define STATUS_UNSUPPORTED -1
  26. #define GETARRAYNUM(array) (sizeof(array)/sizeof(array[0]))
  27. #define bq24196_REG_NUM 11
  28. #define bq24196_SLAVE_ADDR_WRITE 0xD6
  29. #define bq24196_SLAVE_ADDR_READ 0xD7
  30. /**********************************************************
  31. *
  32. * [Global Variable]
  33. *
  34. *********************************************************/
  35. static struct i2c_client *new_client;
  36. static struct switch_dev bq24196_reg09;
  37. static u8 bq24196_reg[bq24196_REG_NUM] = { 0 };
  38. static u8 g_reg_value_bq24196;
  39. static const u32 VBAT_CV_VTH[] = {
  40. 3504000, 3520000, 3536000, 3552000,
  41. 3568000, 3584000, 3600000, 3616000,
  42. 3632000, 3648000, 3664000, 3680000,
  43. 3696000, 3712000, 3728000, 3744000,
  44. 3760000, 3776000, 3792000, 3808000,
  45. 3824000, 3840000, 3856000, 3872000,
  46. 3888000, 3904000, 3920000, 3936000,
  47. 3952000, 3968000, 3984000, 4000000,
  48. 4016000, 4032000, 4048000, 4064000,
  49. 4080000, 4096000, 4112000, 4128000,
  50. 4144000, 4160000, 4176000, 4192000,
  51. 4208000, 4224000, 4240000, 4256000,
  52. 4272000, 4288000, 4304000
  53. };
  54. static const u32 CS_VTH[] = {
  55. 51200, 57600, 64000, 70400,
  56. 76800, 83200, 89600, 96000,
  57. 102400, 108800, 115200, 121600,
  58. 128000, 134400, 140800, 147200,
  59. 153600, 160000, 166400, 172800,
  60. 179200, 185600, 192000, 198400,
  61. 204800, 211200, 217600, 224000
  62. };
  63. static const u32 INPUT_CS_VTH[] = {
  64. CHARGE_CURRENT_100_00_MA, CHARGE_CURRENT_150_00_MA, CHARGE_CURRENT_500_00_MA,
  65. CHARGE_CURRENT_900_00_MA,
  66. CHARGE_CURRENT_1000_00_MA, CHARGE_CURRENT_1500_00_MA, CHARGE_CURRENT_2000_00_MA,
  67. CHARGE_CURRENT_2000_00_MA
  68. };
  69. /* for MT6391 */
  70. static const u32 VCDT_HV_VTH[] = {
  71. BATTERY_VOLT_04_000000_V, BATTERY_VOLT_04_100000_V, BATTERY_VOLT_04_150000_V,
  72. BATTERY_VOLT_04_200000_V,
  73. BATTERY_VOLT_04_250000_V, BATTERY_VOLT_04_300000_V, BATTERY_VOLT_04_350000_V,
  74. BATTERY_VOLT_04_400000_V,
  75. BATTERY_VOLT_04_450000_V, BATTERY_VOLT_04_500000_V, BATTERY_VOLT_04_550000_V,
  76. BATTERY_VOLT_04_600000_V,
  77. BATTERY_VOLT_07_000000_V, BATTERY_VOLT_07_500000_V, BATTERY_VOLT_08_500000_V,
  78. BATTERY_VOLT_10_500000_V
  79. };
  80. /**********************************************************
  81. *
  82. * [I2C Function For Read/Write bq24196]
  83. *
  84. *********************************************************/
  85. int bq24196_read_byte(u8 cmd, u8 *data)
  86. {
  87. int ret;
  88. struct i2c_msg msg[2];
  89. if (!new_client) {
  90. pr_err("error: access bq24196 before driver ready\n");
  91. return 0;
  92. }
  93. msg[0].addr = new_client->addr;
  94. msg[0].buf = &cmd;
  95. msg[0].flags = 0;
  96. msg[0].len = 1;
  97. msg[1].addr = new_client->addr;
  98. msg[1].buf = data;
  99. msg[1].flags = I2C_M_RD;
  100. msg[1].len = 1;
  101. ret = i2c_transfer(new_client->adapter, msg, 2);
  102. if (ret != 2)
  103. pr_err("%s: err=%d\n", __func__, ret);
  104. return ret == 2 ? 1 : 0;
  105. }
  106. int bq24196_write_byte(u8 cmd, u8 data)
  107. {
  108. char buf[2];
  109. int ret;
  110. if (!new_client) {
  111. pr_err("error: access bq24196 before driver ready\n");
  112. return 0;
  113. }
  114. buf[0] = cmd;
  115. buf[1] = data;
  116. ret = i2c_master_send(new_client, buf, 2);
  117. if (ret != 2)
  118. pr_err("%s: err=%d\n", __func__, ret);
  119. return ret == 2 ? 1 : 0;
  120. }
  121. u32 bq24196_read_interface(u8 RegNum, u8 *val, u8 MASK, u8 SHIFT)
  122. {
  123. u8 bq24196_reg = 0;
  124. int ret = 0;
  125. ret = bq24196_read_byte(RegNum, &bq24196_reg);
  126. bq24196_reg &= (MASK << SHIFT);
  127. *val = (bq24196_reg >> SHIFT);
  128. return ret;
  129. }
  130. u32 bq24196_config_interface(u8 RegNum, u8 val, u8 MASK, u8 SHIFT)
  131. {
  132. u8 bq24196_reg = 0;
  133. int ret = 0;
  134. ret = bq24196_read_byte(RegNum, &bq24196_reg);
  135. bq24196_reg &= ~(MASK << SHIFT);
  136. bq24196_reg |= (val << SHIFT);
  137. ret = bq24196_write_byte(RegNum, bq24196_reg);
  138. return ret;
  139. }
  140. /**********************************************************
  141. *
  142. * [Internal Function]
  143. *
  144. *********************************************************/
  145. /* CON0---------------------------------------------------- */
  146. void bq24196_set_en_hiz(u32 val)
  147. {
  148. u32 ret = 0;
  149. ret = bq24196_config_interface((u8) (bq24196_CON0),
  150. (u8) (val), (u8) (CON0_EN_HIZ_MASK), (u8) (CON0_EN_HIZ_SHIFT)
  151. );
  152. }
  153. void bq24196_set_vindpm(u32 val)
  154. {
  155. u32 ret = 0;
  156. ret = bq24196_config_interface((u8) (bq24196_CON0),
  157. (u8) (val), (u8) (CON0_VINDPM_MASK), (u8) (CON0_VINDPM_SHIFT)
  158. );
  159. }
  160. void bq24196_set_iinlim(u32 val)
  161. {
  162. u32 ret = 0;
  163. ret = bq24196_config_interface((u8) (bq24196_CON0),
  164. (u8) (val), (u8) (CON0_IINLIM_MASK), (u8) (CON0_IINLIM_SHIFT)
  165. );
  166. }
  167. u32 bq24196_get_iinlim(void)
  168. {
  169. u32 ret = 0;
  170. u8 val = 0;
  171. ret = bq24196_read_interface((u8) (bq24196_CON0),
  172. (&val), (u8) (CON0_IINLIM_MASK), (u8) (CON0_IINLIM_SHIFT)
  173. );
  174. return val;
  175. }
  176. /* CON1---------------------------------------------------- */
  177. void bq24196_set_reg_rst(u32 val)
  178. {
  179. u32 ret = 0;
  180. ret = bq24196_config_interface((u8) (bq24196_CON1),
  181. (u8) (val),
  182. (u8) (CON1_REG_RST_MASK), (u8) (CON1_REG_RST_SHIFT)
  183. );
  184. }
  185. void bq24196_set_wdt_rst(u32 val)
  186. {
  187. u32 ret = 0;
  188. ret = bq24196_config_interface((u8) (bq24196_CON1),
  189. (u8) (val),
  190. (u8) (CON1_WDT_RST_MASK), (u8) (CON1_WDT_RST_SHIFT)
  191. );
  192. }
  193. void bq24196_set_otg_config(u32 val)
  194. {
  195. u32 ret = 0;
  196. ret = bq24196_config_interface((u8) (bq24196_CON1),
  197. (u8) (val),
  198. (u8) (CON1_OTG_CONFIG_MASK), (u8) (CON1_OTG_CONFIG_SHIFT)
  199. );
  200. }
  201. void bq24196_set_chg_config(u32 val)
  202. {
  203. u32 ret = 0;
  204. ret = bq24196_config_interface((u8) (bq24196_CON1),
  205. (u8) (val),
  206. (u8) (CON1_CHG_CONFIG_MASK), (u8) (CON1_CHG_CONFIG_SHIFT)
  207. );
  208. }
  209. void bq24196_set_sys_min(u32 val)
  210. {
  211. u32 ret = 0;
  212. ret = bq24196_config_interface((u8) (bq24196_CON1),
  213. (u8) (val),
  214. (u8) (CON1_SYS_MIN_MASK), (u8) (CON1_SYS_MIN_SHIFT)
  215. );
  216. }
  217. void bq24196_set_boost_lim(u32 val)
  218. {
  219. u32 ret = 0;
  220. ret = bq24196_config_interface((u8) (bq24196_CON1),
  221. (u8) (val),
  222. (u8) (CON1_BOOST_LIM_MASK), (u8) (CON1_BOOST_LIM_SHIFT)
  223. );
  224. }
  225. /* CON2---------------------------------------------------- */
  226. void bq24196_set_ichg(u32 val)
  227. {
  228. u32 ret = 0;
  229. ret = bq24196_config_interface((u8) (bq24196_CON2),
  230. (u8) (val), (u8) (CON2_ICHG_MASK), (u8) (CON2_ICHG_SHIFT)
  231. );
  232. }
  233. void bq24196_set_force_20pct(u32 val)
  234. {
  235. u32 ret = 0;
  236. ret = bq24196_config_interface((u8) (bq24196_CON2),
  237. (u8) (val),
  238. (u8) (CON2_FORCE_20PCT_MASK), (u8) (CON2_FORCE_20PCT_SHIFT)
  239. );
  240. }
  241. /* CON3---------------------------------------------------- */
  242. void bq24196_set_iprechg(u32 val)
  243. {
  244. u32 ret = 0;
  245. ret = bq24196_config_interface((u8) (bq24196_CON3),
  246. (u8) (val),
  247. (u8) (CON3_IPRECHG_MASK), (u8) (CON3_IPRECHG_SHIFT)
  248. );
  249. }
  250. void bq24196_set_iterm(u32 val)
  251. {
  252. u32 ret = 0;
  253. ret = bq24196_config_interface((u8) (bq24196_CON3),
  254. (u8) (val), (u8) (CON3_ITERM_MASK), (u8) (CON3_ITERM_SHIFT)
  255. );
  256. }
  257. /* CON4---------------------------------------------------- */
  258. void bq24196_set_vreg(u32 val)
  259. {
  260. u32 ret = 0;
  261. ret = bq24196_config_interface((u8) (bq24196_CON4),
  262. (u8) (val), (u8) (CON4_VREG_MASK), (u8) (CON4_VREG_SHIFT)
  263. );
  264. }
  265. void bq24196_set_batlowv(u32 val)
  266. {
  267. u32 ret = 0;
  268. ret = bq24196_config_interface((u8) (bq24196_CON4),
  269. (u8) (val),
  270. (u8) (CON4_BATLOWV_MASK), (u8) (CON4_BATLOWV_SHIFT)
  271. );
  272. }
  273. void bq24196_set_vrechg(u32 val)
  274. {
  275. u32 ret = 0;
  276. ret = bq24196_config_interface((u8) (bq24196_CON4),
  277. (u8) (val), (u8) (CON4_VRECHG_MASK), (u8) (CON4_VRECHG_SHIFT)
  278. );
  279. }
  280. /* CON5---------------------------------------------------- */
  281. void bq24196_set_en_term(u32 val)
  282. {
  283. u32 ret = 0;
  284. ret = bq24196_config_interface((u8) (bq24196_CON5),
  285. (u8) (val),
  286. (u8) (CON5_EN_TERM_MASK), (u8) (CON5_EN_TERM_SHIFT)
  287. );
  288. }
  289. void bq24196_set_term_stat(u32 val)
  290. {
  291. u32 ret = 0;
  292. ret = bq24196_config_interface((u8) (bq24196_CON5),
  293. (u8) (val),
  294. (u8) (CON5_TERM_STAT_MASK), (u8) (CON5_TERM_STAT_SHIFT)
  295. );
  296. }
  297. void bq24196_set_watchdog(u32 val)
  298. {
  299. u32 ret = 0;
  300. ret = bq24196_config_interface((u8) (bq24196_CON5),
  301. (u8) (val),
  302. (u8) (CON5_WATCHDOG_MASK), (u8) (CON5_WATCHDOG_SHIFT)
  303. );
  304. }
  305. void bq24196_set_en_timer(u32 val)
  306. {
  307. u32 ret = 0;
  308. ret = bq24196_config_interface((u8) (bq24196_CON5),
  309. (u8) (val),
  310. (u8) (CON5_EN_TIMER_MASK), (u8) (CON5_EN_TIMER_SHIFT)
  311. );
  312. }
  313. void bq24196_set_chg_timer(u32 val)
  314. {
  315. u32 ret = 0;
  316. ret = bq24196_config_interface((u8) (bq24196_CON5),
  317. (u8) (val),
  318. (u8) (CON5_CHG_TIMER_MASK), (u8) (CON5_CHG_TIMER_SHIFT)
  319. );
  320. }
  321. /* CON6---------------------------------------------------- */
  322. void bq24196_set_treg(u32 val)
  323. {
  324. u32 ret = 0;
  325. ret = bq24196_config_interface((u8) (bq24196_CON6),
  326. (u8) (val), (u8) (CON6_TREG_MASK), (u8) (CON6_TREG_SHIFT)
  327. );
  328. }
  329. /* CON7---------------------------------------------------- */
  330. u32 bq24196_get_dpdm_status(void)
  331. {
  332. u32 ret = 0;
  333. u8 val = 0;
  334. ret = bq24196_read_interface((u8) (bq24196_CON7),
  335. (&val), (u8) (CON7_DPDM_EN_MASK), (u8) (CON7_DPDM_EN_SHIFT)
  336. );
  337. return val;
  338. }
  339. void bq24196_set_dpdm_en(u32 val)
  340. {
  341. u32 ret = 0;
  342. ret = bq24196_config_interface((u8) (bq24196_CON7),
  343. (u8) (val),
  344. (u8) (CON7_DPDM_EN_MASK), (u8) (CON7_DPDM_EN_SHIFT)
  345. );
  346. }
  347. void bq24196_set_tmr2x_en(u32 val)
  348. {
  349. u32 ret = 0;
  350. ret = bq24196_config_interface((u8) (bq24196_CON7),
  351. (u8) (val),
  352. (u8) (CON7_TMR2X_EN_MASK), (u8) (CON7_TMR2X_EN_SHIFT)
  353. );
  354. }
  355. void bq24196_set_batfet_disable(u32 val)
  356. {
  357. u32 ret = 0;
  358. ret = bq24196_config_interface((u8) (bq24196_CON7),
  359. (u8) (val),
  360. (u8) (CON7_BATFET_Disable_MASK),
  361. (u8) (CON7_BATFET_Disable_SHIFT)
  362. );
  363. }
  364. void bq24196_set_int_mask(u32 val)
  365. {
  366. u32 ret = 0;
  367. ret = bq24196_config_interface((u8) (bq24196_CON7),
  368. (u8) (val),
  369. (u8) (CON7_INT_MASK_MASK), (u8) (CON7_INT_MASK_SHIFT)
  370. );
  371. }
  372. /* CON8---------------------------------------------------- */
  373. u32 bq24196_get_system_status(void)
  374. {
  375. u32 ret = 0;
  376. u8 val = 0;
  377. ret = bq24196_read_interface((u8) (bq24196_CON8), (&val), (u8) (0xFF), (u8) (0x0)
  378. );
  379. return val;
  380. }
  381. u32 bq24196_get_vbus_stat(void)
  382. {
  383. u32 ret = 0;
  384. u8 val = 0;
  385. ret = bq24196_read_interface((u8) (bq24196_CON8),
  386. (&val), (u8) (CON8_VBUS_STAT_MASK), (u8) (CON8_VBUS_STAT_SHIFT)
  387. );
  388. return val;
  389. }
  390. u32 bq24196_get_chrg_stat(void)
  391. {
  392. u32 ret = 0;
  393. u8 val = 0;
  394. ret = bq24196_read_interface((u8) (bq24196_CON8),
  395. (&val), (u8) (CON8_CHRG_STAT_MASK), (u8) (CON8_CHRG_STAT_SHIFT)
  396. );
  397. return val;
  398. }
  399. u32 bq24196_get_pg_stat(void)
  400. {
  401. u32 ret = 0;
  402. u8 val = 0;
  403. ret = bq24196_read_interface((u8) (bq24196_CON8),
  404. (&val), (u8) (CON8_PG_STAT_MASK), (u8) (CON8_PG_STAT_SHIFT)
  405. );
  406. return val;
  407. }
  408. u32 bq24196_get_vsys_stat(void)
  409. {
  410. u32 ret = 0;
  411. u8 val = 0;
  412. ret = bq24196_read_interface((u8) (bq24196_CON8),
  413. (&val), (u8) (CON8_VSYS_STAT_MASK), (u8) (CON8_VSYS_STAT_SHIFT)
  414. );
  415. return val;
  416. }
  417. /* CON10---------------------------------------------------- */
  418. u32 bq24196_get_pn(void)
  419. {
  420. u32 ret = 0;
  421. u8 val = 0;
  422. ret = bq24196_read_interface((u8) (bq24196_CON10),
  423. (&val), (u8) (CON10_PN_MASK), (u8) (CON10_PN_SHIFT)
  424. );
  425. return val;
  426. }
  427. /**********************************************************
  428. *
  429. * [Internal Function]
  430. *
  431. *********************************************************/
  432. static u32 charging_parameter_to_value(const u32 *parameter, const u32 array_size, const u32 val)
  433. {
  434. u32 i;
  435. for (i = 0; i < array_size; i++) {
  436. if (val == *(parameter + i))
  437. return i;
  438. }
  439. battery_log(BAT_LOG_CRTI, "NO register value match. val=%d\r\n", val);
  440. /* TODO: ASSERT(0); // not find the value */
  441. return 0;
  442. }
  443. static u32 bmt_find_closest_level(const u32 *pList, u32 number, u32 level)
  444. {
  445. u32 i;
  446. u32 max_value_in_last_element;
  447. if (pList[0] < pList[1])
  448. max_value_in_last_element = true;
  449. else
  450. max_value_in_last_element = false;
  451. if (max_value_in_last_element == true) {
  452. for (i = (number - 1); i != 0; i--) { /* max value in the last element */
  453. if (pList[i] <= level)
  454. return pList[i];
  455. }
  456. battery_log(BAT_LOG_CRTI, "Can't find closest level, small value first \r\n");
  457. return pList[0];
  458. }
  459. for (i = 0; i < number; i++) { /* max value in the first element */
  460. if (pList[i] <= level)
  461. return pList[i];
  462. }
  463. battery_log(BAT_LOG_CRTI, "Can't find closest level, large value first \r\n");
  464. return pList[number - 1];
  465. }
  466. static u32 charging_hw_init(void *data)
  467. {
  468. u32 status = STATUS_OK;
  469. upmu_set_rg_bc11_bb_ctrl(1); /* BC11_BB_CTRL */
  470. upmu_set_rg_bc11_rst(1); /* BC11_RST */
  471. bq24196_set_en_hiz(0x0);
  472. bq24196_set_vindpm(0x9); /* VIN DPM check 4.60V */
  473. bq24196_set_reg_rst(0x0);
  474. bq24196_set_wdt_rst(0x1); /* Kick watchdog */
  475. bq24196_set_sys_min(0x5); /* Minimum system voltage 3.5V */
  476. #if defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
  477. bq24196_set_iprechg(0x1); /* Precharge current 256mA */
  478. #else
  479. bq24196_set_iprechg(0x3); /* Precharge current 512mA */
  480. #endif
  481. bq24196_set_iterm(0x0); /* Termination current 128mA */
  482. #if !defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
  483. bq24196_set_vreg(0x2C); /* VREG 4.208V */
  484. #endif
  485. bq24196_set_batlowv(0x1); /* BATLOWV 3.0V */
  486. bq24196_set_vrechg(0x0); /* VRECHG 0.1V (4.108V) */
  487. bq24196_set_en_term(0x1); /* Enable termination */
  488. bq24196_set_term_stat(0x0); /* Match ITERM */
  489. bq24196_set_watchdog(0x1); /* WDT 40s */
  490. #if !defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)
  491. bq24196_set_en_timer(0x0); /* Disable charge timer */
  492. #endif
  493. bq24196_set_int_mask(0x1); /* Disable CHRG fault interrupt */
  494. return status;
  495. }
  496. static u32 charging_dump_register(void *data)
  497. {
  498. u32 status = STATUS_OK;
  499. battery_log(BAT_LOG_CRTI, "charging_dump_register\r\n");
  500. bq24196_dump_register();
  501. return status;
  502. }
  503. static u32 charging_enable(void *data)
  504. {
  505. u32 status = STATUS_OK;
  506. u32 enable = *(u32 *) (data);
  507. if (true == enable) {
  508. bq24196_set_en_hiz(0x0);
  509. bq24196_set_chg_config(0x1);
  510. } else
  511. bq24196_set_chg_config(0x0);
  512. return status;
  513. }
  514. static u32 charging_set_cv_voltage(void *data)
  515. {
  516. u32 status = STATUS_OK;
  517. u16 register_value;
  518. u32 cv_value = *(u32 *) (data);
  519. if (cv_value == BATTERY_VOLT_04_200000_V) {
  520. /* use nearest value */
  521. cv_value = 4208000;
  522. }
  523. register_value =
  524. charging_parameter_to_value(VBAT_CV_VTH, GETARRAYNUM(VBAT_CV_VTH), cv_value);
  525. bq24196_set_vreg(register_value);
  526. return status;
  527. }
  528. static u32 charging_get_current(void *data)
  529. {
  530. u32 status = STATUS_OK;
  531. u32 data_val = 0;
  532. u8 ret_val = 0;
  533. u8 ret_force_20pct = 0;
  534. bq24196_read_interface(bq24196_CON2, &ret_val, CON2_ICHG_MASK, CON2_ICHG_SHIFT);
  535. bq24196_read_interface(bq24196_CON2, &ret_force_20pct, CON2_FORCE_20PCT_MASK,
  536. CON2_FORCE_20PCT_SHIFT);
  537. data_val = (ret_val * 64) + 512;
  538. if (ret_force_20pct == 0)
  539. *(u32 *) data = data_val;
  540. else
  541. *(u32 *) data = data_val / 5;
  542. return status;
  543. }
  544. static u32 charging_set_current(void *data)
  545. {
  546. u32 status = STATUS_OK;
  547. u32 set_chr_current;
  548. u32 array_size;
  549. u32 register_value;
  550. u32 current_value = *(u32 *) data;
  551. if (current_value == 25600) {
  552. bq24196_set_force_20pct(0x1);
  553. bq24196_set_ichg(0xC);
  554. return status;
  555. }
  556. bq24196_set_force_20pct(0x0);
  557. array_size = GETARRAYNUM(CS_VTH);
  558. set_chr_current = bmt_find_closest_level(CS_VTH, array_size, current_value);
  559. register_value = charging_parameter_to_value(CS_VTH, array_size, set_chr_current);
  560. bq24196_set_ichg(register_value);
  561. return status;
  562. }
  563. static u32 charging_set_input_current(void *data)
  564. {
  565. u32 status = STATUS_OK;
  566. u32 set_chr_current;
  567. u32 array_size;
  568. u32 register_value;
  569. array_size = GETARRAYNUM(INPUT_CS_VTH);
  570. set_chr_current = bmt_find_closest_level(INPUT_CS_VTH, array_size, *(u32 *) data);
  571. register_value = charging_parameter_to_value(INPUT_CS_VTH, array_size, set_chr_current);
  572. bq24196_set_iinlim(register_value);
  573. return status;
  574. }
  575. static u32 charging_get_input_current(void *data)
  576. {
  577. u32 register_value;
  578. register_value = bq24196_get_iinlim();
  579. *(u32 *) data = INPUT_CS_VTH[register_value];
  580. return STATUS_OK;
  581. }
  582. static u32 charging_get_charging_status(void *data)
  583. {
  584. u32 status = STATUS_OK;
  585. u32 ret_val;
  586. ret_val = bq24196_get_chrg_stat();
  587. if (ret_val == 0x3)
  588. *(u32 *) data = true;
  589. else
  590. *(u32 *) data = false;
  591. return status;
  592. }
  593. static u32 charging_reset_watch_dog_timer(void *data)
  594. {
  595. u32 status = STATUS_OK;
  596. battery_log(BAT_LOG_FULL, "charging_reset_watch_dog_timer\r\n");
  597. bq24196_set_wdt_rst(0x1); /* Kick watchdog */
  598. return status;
  599. }
  600. static u32 charging_set_hv_threshold(void *data)
  601. {
  602. u32 status = STATUS_OK;
  603. u32 set_hv_voltage;
  604. u32 array_size;
  605. u16 register_value;
  606. u32 voltage = *(u32 *) (data);
  607. array_size = GETARRAYNUM(VCDT_HV_VTH);
  608. set_hv_voltage = bmt_find_closest_level(VCDT_HV_VTH, array_size, voltage);
  609. register_value = charging_parameter_to_value(VCDT_HV_VTH, array_size, set_hv_voltage);
  610. upmu_set_rg_vcdt_hv_vth(register_value);
  611. return status;
  612. }
  613. static u32 charging_get_hv_status(void *data)
  614. {
  615. u32 status = STATUS_OK;
  616. *(bool *) (data) = upmu_get_rgs_vcdt_hv_det();
  617. return status;
  618. }
  619. static u32 charging_get_battery_status(void *data)
  620. {
  621. u32 status = STATUS_OK;
  622. /* upmu_set_baton_tdet_en(1); */
  623. upmu_set_rg_baton_en(1);
  624. *(bool *) (data) = upmu_get_rgs_baton_undet();
  625. return status;
  626. }
  627. static u32 charging_get_charger_det_status(void *data)
  628. {
  629. u32 status = STATUS_OK;
  630. *(bool *) (data) = upmu_get_rgs_chrdet();
  631. return status;
  632. }
  633. static u32 charging_get_charger_type(void *data)
  634. {
  635. u32 status = STATUS_OK;
  636. #if 0 /*defined(CONFIG_POWER_EXT) */
  637. *(CHARGER_TYPE *) (data) = STANDARD_HOST;
  638. #else
  639. *(int *)(data) = hw_charger_type_detection();
  640. #endif
  641. return status;
  642. }
  643. static u32 charging_get_is_pcm_timer_trigger(void *data)
  644. {
  645. u32 status = STATUS_OK;
  646. if (slp_get_wake_reason() == 3)
  647. *(bool *) (data) = true;
  648. else
  649. *(bool *) (data) = false;
  650. battery_log(BAT_LOG_CRTI, "slp_get_wake_reason=%d\n", slp_get_wake_reason());
  651. return status;
  652. }
  653. static u32 charging_set_platform_reset(void *data)
  654. {
  655. u32 status = STATUS_OK;
  656. battery_log(BAT_LOG_CRTI, "charging_set_platform_reset\n");
  657. #if 0 /* need porting of orderly_reboot(). */
  658. if (system_state == SYSTEM_BOOTING)
  659. arch_reset(0, NULL);
  660. else
  661. orderly_reboot(true);
  662. #endif
  663. arch_reset(0, NULL);
  664. return status;
  665. }
  666. static u32 charging_get_platform_boot_mode(void *data)
  667. {
  668. u32 status = STATUS_OK;
  669. *(u32 *) (data) = get_boot_mode();
  670. battery_log(BAT_LOG_CRTI, "get_boot_mode=%d\n", get_boot_mode());
  671. return status;
  672. }
  673. static u32 charging_enable_powerpath(void *data)
  674. {
  675. u32 status = STATUS_OK;
  676. u32 enable = *(u32 *) (data);
  677. if (true == enable)
  678. bq24196_set_en_hiz(0x0);
  679. else
  680. bq24196_set_en_hiz(0x1);
  681. return status;
  682. }
  683. static u32 charging_boost_enable(void *data)
  684. {
  685. u32 status = STATUS_OK;
  686. u32 enable = *(u32 *) (data);
  687. if (true == enable) {
  688. bq24196_set_boost_lim(0x1); /* 1.5A on VBUS */
  689. bq24196_set_en_hiz(0x0);
  690. bq24196_set_chg_config(0); /* Charge disabled */
  691. bq24196_set_otg_config(0x1); /* OTG */
  692. #ifdef CONFIG_POWER_EXT
  693. bq24196_set_watchdog(0);
  694. #endif
  695. } else {
  696. bq24196_set_otg_config(0x0); /* OTG & Charge disabled */
  697. #ifdef CONFIG_POWER_EXT
  698. bq24196_set_watchdog(1);
  699. #endif
  700. }
  701. return status;
  702. }
  703. static u32 charging_set_ta_current_pattern(void *data)
  704. {
  705. u32 increase = *(u32 *) (data);
  706. u32 charging_status = false;
  707. #if defined(HIGH_BATTERY_VOLTAGE_SUPPORT)
  708. u32 cv_voltage = BATTERY_VOLT_04_340000_V;
  709. #else
  710. u32 cv_voltage = BATTERY_VOLT_04_200000_V;
  711. #endif
  712. charging_get_charging_status(&charging_status);
  713. if (false == charging_status) {
  714. charging_set_cv_voltage(&cv_voltage); /* Set CV */
  715. bq24196_set_ichg(0x0); /* Set charging current 500ma */
  716. bq24196_set_chg_config(0x1); /* Enable Charging */
  717. }
  718. if (increase == true) {
  719. bq24196_set_iinlim(0x0); /* 100mA */
  720. msleep(85);
  721. bq24196_set_iinlim(0x2); /* 500mA */
  722. pr_debug("mtk_ta_increase() on 1");
  723. msleep(85);
  724. bq24196_set_iinlim(0x0); /* 100mA */
  725. pr_debug("mtk_ta_increase() off 1");
  726. msleep(85);
  727. bq24196_set_iinlim(0x2); /* 500mA */
  728. pr_debug("mtk_ta_increase() on 2");
  729. msleep(85);
  730. bq24196_set_iinlim(0x0); /* 100mA */
  731. pr_debug("mtk_ta_increase() off 2");
  732. msleep(85);
  733. bq24196_set_iinlim(0x2); /* 500mA */
  734. pr_debug("mtk_ta_increase() on 3");
  735. msleep(281);
  736. bq24196_set_iinlim(0x0); /* 100mA */
  737. pr_debug("mtk_ta_increase() off 3");
  738. msleep(85);
  739. bq24196_set_iinlim(0x2); /* 500mA */
  740. pr_debug("mtk_ta_increase() on 4");
  741. msleep(281);
  742. bq24196_set_iinlim(0x0); /* 100mA */
  743. pr_debug("mtk_ta_increase() off 4");
  744. msleep(85);
  745. bq24196_set_iinlim(0x2); /* 500mA */
  746. pr_debug("mtk_ta_increase() on 5");
  747. msleep(281);
  748. bq24196_set_iinlim(0x0); /* 100mA */
  749. pr_debug("mtk_ta_increase() off 5");
  750. msleep(85);
  751. bq24196_set_iinlim(0x2); /* 500mA */
  752. pr_debug("mtk_ta_increase() on 6");
  753. msleep(485);
  754. bq24196_set_iinlim(0x0); /* 100mA */
  755. pr_debug("mtk_ta_increase() off 6");
  756. msleep(50);
  757. pr_debug("mtk_ta_increase() end\n");
  758. bq24196_set_iinlim(0x2); /* 500mA */
  759. msleep(200);
  760. } else {
  761. bq24196_set_iinlim(0x0); /* 100mA */
  762. msleep(85);
  763. bq24196_set_iinlim(0x2); /* 500mA */
  764. pr_debug("mtk_ta_decrease() on 1");
  765. msleep(281);
  766. bq24196_set_iinlim(0x0); /* 100mA */
  767. pr_debug("mtk_ta_decrease() off 1");
  768. msleep(85);
  769. bq24196_set_iinlim(0x2); /* 500mA */
  770. pr_debug("mtk_ta_decrease() on 2");
  771. msleep(281);
  772. bq24196_set_iinlim(0x0); /* 100mA */
  773. pr_debug("mtk_ta_decrease() off 2");
  774. msleep(85);
  775. bq24196_set_iinlim(0x2); /* 500mA */
  776. pr_debug("mtk_ta_decrease() on 3");
  777. msleep(281);
  778. bq24196_set_iinlim(0x0); /* 100mA */
  779. pr_debug("mtk_ta_decrease() off 3");
  780. msleep(85);
  781. bq24196_set_iinlim(0x2); /* 500mA */
  782. pr_debug("mtk_ta_decrease() on 4");
  783. msleep(85);
  784. bq24196_set_iinlim(0x0); /* 100mA */
  785. pr_debug("mtk_ta_decrease() off 4");
  786. msleep(85);
  787. bq24196_set_iinlim(0x2); /* 500mA */
  788. pr_debug("mtk_ta_decrease() on 5");
  789. msleep(85);
  790. bq24196_set_iinlim(0x0); /* 100mA */
  791. pr_debug("mtk_ta_decrease() off 5");
  792. msleep(85);
  793. bq24196_set_iinlim(0x2); /* 500mA */
  794. pr_debug("mtk_ta_decrease() on 6");
  795. msleep(485);
  796. bq24196_set_iinlim(0x0); /* 100mA */
  797. pr_debug("mtk_ta_decrease() off 6");
  798. msleep(50);
  799. pr_debug("mtk_ta_decrease() end\n");
  800. bq24196_set_iinlim(0x2); /* 500mA */
  801. }
  802. return STATUS_OK;
  803. }
  804. static u32(*charging_func[CHARGING_CMD_NUMBER]) (void *data);
  805. int bq24196_control_interface(int cmd, void *data)
  806. {
  807. int status;
  808. static bool is_init;
  809. if (is_init == false) {
  810. charging_func[CHARGING_CMD_INIT] = charging_hw_init;
  811. charging_func[CHARGING_CMD_DUMP_REGISTER] = charging_dump_register;
  812. charging_func[CHARGING_CMD_ENABLE] = charging_enable;
  813. charging_func[CHARGING_CMD_SET_CV_VOLTAGE] = charging_set_cv_voltage;
  814. charging_func[CHARGING_CMD_GET_CURRENT] = charging_get_current;
  815. charging_func[CHARGING_CMD_SET_CURRENT] = charging_set_current;
  816. charging_func[CHARGING_CMD_GET_INPUT_CURRENT] = charging_get_input_current;
  817. charging_func[CHARGING_CMD_SET_INPUT_CURRENT] = charging_set_input_current;
  818. charging_func[CHARGING_CMD_GET_CHARGING_STATUS] = charging_get_charging_status;
  819. charging_func[CHARGING_CMD_RESET_WATCH_DOG_TIMER] = charging_reset_watch_dog_timer;
  820. charging_func[CHARGING_CMD_SET_HV_THRESHOLD] = charging_set_hv_threshold;
  821. charging_func[CHARGING_CMD_GET_HV_STATUS] = charging_get_hv_status;
  822. charging_func[CHARGING_CMD_GET_BATTERY_STATUS] = charging_get_battery_status;
  823. charging_func[CHARGING_CMD_GET_CHARGER_DET_STATUS] =
  824. charging_get_charger_det_status;
  825. charging_func[CHARGING_CMD_GET_CHARGER_TYPE] = charging_get_charger_type;
  826. charging_func[CHARGING_CMD_GET_IS_PCM_TIMER_TRIGGER] =
  827. charging_get_is_pcm_timer_trigger;
  828. charging_func[CHARGING_CMD_SET_PLATFORM_RESET] = charging_set_platform_reset;
  829. charging_func[CHARGING_CMD_GET_PLATFORM_BOOT_MODE] =
  830. charging_get_platform_boot_mode;
  831. charging_func[CHARGING_CMD_ENABLE_POWERPATH] = charging_enable_powerpath;
  832. charging_func[CHARGING_CMD_BOOST_ENABLE] = charging_boost_enable;
  833. charging_func[CHARGING_CMD_SET_TA_CURRENT_PATTERN] =
  834. charging_set_ta_current_pattern;
  835. is_init = true;
  836. }
  837. if (cmd < CHARGING_CMD_NUMBER && charging_func[cmd])
  838. status = charging_func[cmd] (data);
  839. else {
  840. pr_err("Unsupported charging command:%d!\n", cmd);
  841. return STATUS_UNSUPPORTED;
  842. }
  843. return status;
  844. }
  845. void bq24196_dump_register(void)
  846. {
  847. int i = 0;
  848. for (i = 0; i < bq24196_REG_NUM; i++) {
  849. bq24196_read_byte(i, &bq24196_reg[i]);
  850. battery_log(BAT_LOG_FULL,
  851. "[bq24196_dump_register] Reg[0x%X]=0x%X\n", i, bq24196_reg[i]);
  852. }
  853. }
  854. u8 bq24196_get_reg9_fault_type(u8 reg9_fault)
  855. {
  856. u8 ret = 0;
  857. /* if((reg9_fault & (CON9_WATCHDOG_FAULT_MASK << CON9_WATCHDOG_FAULT_SHIFT)) !=0){
  858. ret = BQ_WATCHDOG_FAULT;
  859. } else
  860. */
  861. if ((reg9_fault & (CON9_OTG_FAULT_MASK << CON9_OTG_FAULT_SHIFT)) != 0) {
  862. ret = BQ_OTG_FAULT;
  863. } else if ((reg9_fault & (CON9_CHRG_FAULT_MASK << CON9_CHRG_FAULT_SHIFT)) != 0) {
  864. if ((reg9_fault & (CON9_CHRG_INPUT_FAULT_MASK << CON9_CHRG_FAULT_SHIFT)) != 0)
  865. ret = BQ_CHRG_INPUT_FAULT;
  866. else if ((reg9_fault &
  867. (CON9_CHRG_THERMAL_SHUTDOWN_FAULT_MASK << CON9_CHRG_FAULT_SHIFT)) != 0)
  868. ret = BQ_CHRG_THERMAL_FAULT;
  869. else if ((reg9_fault &
  870. (CON9_CHRG_TIMER_EXPIRATION_FAULT_MASK << CON9_CHRG_FAULT_SHIFT)) != 0)
  871. ret = BQ_CHRG_TIMER_EXPIRATION_FAULT;
  872. } else if ((reg9_fault & (CON9_BAT_FAULT_MASK << CON9_BAT_FAULT_SHIFT)) != 0)
  873. ret = BQ_BAT_FAULT;
  874. else if ((reg9_fault & (CON9_NTC_FAULT_MASK << CON9_NTC_FAULT_SHIFT)) != 0) {
  875. if ((reg9_fault & (CON9_NTC_COLD_FAULT_MASK << CON9_NTC_FAULT_SHIFT)) != 0)
  876. ret = BQ_NTC_COLD_FAULT;
  877. else if ((reg9_fault & (CON9_NTC_HOT_FAULT_MASK << CON9_NTC_FAULT_SHIFT)) != 0)
  878. ret = BQ_NTC_HOT_FAULT;
  879. }
  880. return ret;
  881. }
  882. void bq24196_polling_reg09(void)
  883. {
  884. int i, i2;
  885. u8 reg1;
  886. for (i2 = i = 0; i < 4 && i2 < 10; i++, i2++) {
  887. bq24196_read_byte((u8) (bq24196_CON9), &bq24196_reg[bq24196_CON9]);
  888. if ((bq24196_reg[bq24196_CON9] & 0x40) != 0) { /* OTG_FAULT bit */
  889. /* Disable OTG */
  890. bq24196_read_byte(1, &reg1);
  891. reg1 &= ~0x20; /* 0 = OTG Disable */
  892. bq24196_write_byte(1, reg1);
  893. msleep(20);
  894. /* Enable OTG */
  895. reg1 |= 0x20; /* 1 = OTG Enable */
  896. bq24196_write_byte(1, reg1);
  897. }
  898. if (bq24196_reg[bq24196_CON9] != 0) {
  899. i = 0; /* keep on polling if reg9 is not 0. This is to filter noises */
  900. /* need filter fault type here */
  901. switch_set_state(&bq24196_reg09,
  902. bq24196_get_reg9_fault_type(bq24196_reg[bq24196_CON9]));
  903. }
  904. msleep(20);
  905. }
  906. /* send normal fault state to UI */
  907. switch_set_state(&bq24196_reg09, BQ_NORMAL_FAULT);
  908. }
  909. static irqreturn_t ops_bq24196_int_handler(int irq, void *dev_id)
  910. {
  911. bq24196_polling_reg09();
  912. return IRQ_HANDLED;
  913. }
  914. static int bq24196_driver_suspend(struct i2c_client *client, pm_message_t mesg)
  915. {
  916. pr_debug("[bq24196_driver_suspend] client->irq(%d)\n", client->irq);
  917. if (client->irq > 0)
  918. disable_irq(client->irq);
  919. return 0;
  920. }
  921. static int bq24196_driver_resume(struct i2c_client *client)
  922. {
  923. pr_debug("[bq24196_driver_resume] client->irq(%d)\n", client->irq);
  924. if (client->irq > 0)
  925. enable_irq(client->irq);
  926. return 0;
  927. }
  928. static void bq24196_driver_shutdown(struct i2c_client *client)
  929. {
  930. pr_debug("[bq24196_driver_shutdown] client->irq(%d)\n", client->irq);
  931. if (client->irq > 0)
  932. disable_irq(client->irq);
  933. }
  934. static int bq24196_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
  935. {
  936. int ret = 0;
  937. struct regulator *i2c_reg = devm_regulator_get(&client->dev, "reg-i2c");
  938. pr_debug("[bq24196_driver_probe]\n");
  939. new_client = client;
  940. if (!IS_ERR(i2c_reg)) {
  941. ret = regulator_set_voltage(i2c_reg, 1800000, 1800000);
  942. if (ret != 0)
  943. dev_err(&client->dev, "Fail to set 1.8V to reg-i2c: %d\n", ret);
  944. ret = regulator_get_voltage(i2c_reg);
  945. pr_debug("bq24196 i2c voltage: %d\n", ret);
  946. ret = regulator_enable(i2c_reg);
  947. if (ret != 0)
  948. dev_err(&client->dev, "Fail to enable reg-i2c: %d\n", ret);
  949. }
  950. if (bq24196_get_pn() == 0x5) {
  951. pr_warn("bq24196 device is found. register charger control.\n");
  952. bat_charger_register(bq24196_control_interface);
  953. } else {
  954. pr_warn("No bq24196 device part number is found.\n");
  955. return 0;
  956. }
  957. bq24196_dump_register();
  958. bq24196_reg09.name = "bq24196_reg09";
  959. bq24196_reg09.index = 0;
  960. bq24196_reg09.state = 0;
  961. ret = switch_dev_register(&bq24196_reg09);
  962. if (ret < 0)
  963. pr_err("[bq24196_driver_probe] switch_dev_register() error(%d)\n", ret);
  964. if (client->irq > 0) {
  965. pr_debug("[bq24196_driver_probe] enable interrupt: %d\n", client->irq);
  966. /* make sure we clean REG9 before enable fault interrupt */
  967. bq24196_read_byte((u8) (bq24196_CON9), &bq24196_reg[9]);
  968. if (bq24196_reg[9] != 0)
  969. bq24196_polling_reg09();
  970. bq24196_set_int_mask(0x1); /* Disable CHRG fault interrupt */
  971. ret = request_threaded_irq(client->irq, NULL, ops_bq24196_int_handler,
  972. IRQF_TRIGGER_FALLING |
  973. IRQF_ONESHOT, "ops_bq24196_int_handler", NULL);
  974. if (ret)
  975. pr_err
  976. ("[bq24196_driver_probe] fault interrupt registration failed err = %d\n",
  977. ret);
  978. }
  979. return 0;
  980. }
  981. static const struct i2c_device_id bq24196_i2c_id[] = { {"bq24196", 0}, {} };
  982. #ifdef CONFIG_OF
  983. static const struct of_device_id bq24196_id[] = {
  984. {.compatible = "ti,bq24196"},
  985. {},
  986. };
  987. MODULE_DEVICE_TABLE(of, bq24196_id);
  988. #endif
  989. static struct i2c_driver bq24196_driver = {
  990. .driver = {
  991. .name = "bq24196",
  992. #ifdef CONFIG_OF
  993. .of_match_table = of_match_ptr(bq24196_id),
  994. #endif
  995. },
  996. .probe = bq24196_driver_probe,
  997. .shutdown = bq24196_driver_shutdown,
  998. .suspend = bq24196_driver_suspend,
  999. .resume = bq24196_driver_resume,
  1000. .id_table = bq24196_i2c_id,
  1001. };
  1002. static ssize_t show_bq24196_access(struct device *dev, struct device_attribute *attr, char *buf)
  1003. {
  1004. pr_debug("[show_bq24196_access] 0x%x\n", g_reg_value_bq24196);
  1005. return sprintf(buf, "0x%x\n", g_reg_value_bq24196);
  1006. }
  1007. static ssize_t store_bq24196_access(struct device *dev, struct device_attribute *attr,
  1008. const char *buf, size_t size)
  1009. {
  1010. int ret = 0;
  1011. char *pvalue, temp_buf[16];
  1012. unsigned int reg_value = 0;
  1013. unsigned int reg_address = 0;
  1014. if (buf != NULL && size != 0) {
  1015. strcpy(temp_buf, buf);
  1016. pvalue = temp_buf;
  1017. if (size > 4) {
  1018. ret = kstrtouint(strsep(&pvalue, " "), 0, &reg_address);
  1019. if (ret) {
  1020. pr_err("wrong format!\n");
  1021. return size;
  1022. }
  1023. ret = kstrtouint(pvalue, 0, &reg_value);
  1024. if (ret) {
  1025. pr_err("wrong format!\n");
  1026. return size;
  1027. }
  1028. pr_debug("[store_bq24196_access] write bq24196 reg 0x%x with value 0x%x !\n",
  1029. reg_address, reg_value);
  1030. bq24196_config_interface(reg_address, reg_value, 0xFF, 0x0);
  1031. } else {
  1032. ret = kstrtouint(pvalue, 0, &reg_address);
  1033. if (ret) {
  1034. pr_err("wrong format!\n");
  1035. return size;
  1036. }
  1037. bq24196_read_interface(reg_address, &g_reg_value_bq24196, 0xFF, 0x0);
  1038. pr_debug("[store_bq24196_access] read bq24196 reg 0x%x with value 0x%x !\n",
  1039. reg_address, g_reg_value_bq24196);
  1040. pr_debug
  1041. ("[store_bq24196_access] Please use \"cat bq24196_access\" to get value\r\n");
  1042. }
  1043. }
  1044. return size;
  1045. }
  1046. static DEVICE_ATTR(bq24196_access, S_IWUSR | S_IRUGO, show_bq24196_access, store_bq24196_access);
  1047. static int bq24196_user_space_probe(struct platform_device *dev)
  1048. {
  1049. int ret_device_file = 0;
  1050. pr_debug("bq24196_user_space_probe!\n");
  1051. ret_device_file = device_create_file(&(dev->dev), &dev_attr_bq24196_access);
  1052. return 0;
  1053. }
  1054. struct platform_device bq24196_user_space_device = {
  1055. .name = "bq24196-user",
  1056. .id = -1,
  1057. };
  1058. static struct platform_driver bq24196_user_space_driver = {
  1059. .probe = bq24196_user_space_probe,
  1060. .driver = {
  1061. .name = "bq24196-user",
  1062. },
  1063. };
  1064. static int __init bq24196_init(void)
  1065. {
  1066. int ret = 0;
  1067. if (i2c_add_driver(&bq24196_driver) != 0)
  1068. pr_err("[bq24196_init] failed to register bq24196 i2c driver.\n");
  1069. else
  1070. pr_debug("[bq24196_init] Success to register bq24196 i2c driver.\n");
  1071. /* bq24196 user space access interface */
  1072. ret = platform_device_register(&bq24196_user_space_device);
  1073. if (ret) {
  1074. pr_err("[bq24196_init] Unable to device register(%d)\n", ret);
  1075. return ret;
  1076. }
  1077. ret = platform_driver_register(&bq24196_user_space_driver);
  1078. if (ret) {
  1079. pr_err("[bq24196_init] Unable to register driver (%d)\n", ret);
  1080. return ret;
  1081. }
  1082. return 0;
  1083. }
  1084. static void __exit bq24196_exit(void)
  1085. {
  1086. i2c_del_driver(&bq24196_driver);
  1087. }
  1088. module_init(bq24196_init);
  1089. module_exit(bq24196_exit);
  1090. MODULE_LICENSE("GPL");
  1091. MODULE_DESCRIPTION("I2C bq24196 Driver");
  1092. MODULE_AUTHOR("Tank Hung<tank.hung@mediatek.com>");