bq24260_charger.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  1. /*
  2. * bq24260_charger.c
  3. * Samsung bq24260 Charger Driver
  4. *
  5. * Copyright (C) 2012 Samsung Electronics
  6. *
  7. *
  8. * This software is licensed under the terms of the GNU General Public
  9. * License version 2, as published by the Free Software Foundation, and
  10. * may be copied, distributed, and modified under those terms.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. */
  18. #define DEBUG
  19. #include <linux/battery/sec_charger.h>
  20. extern unsigned int system_rev;
  21. static int bq24260_i2c_write(struct i2c_client *client,
  22. int reg, u8 *buf)
  23. {
  24. int ret;
  25. ret = i2c_smbus_write_i2c_block_data(client, reg, 1, buf);
  26. if (ret < 0)
  27. dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret);
  28. return ret;
  29. }
  30. static int bq24260_i2c_read(struct i2c_client *client,
  31. int reg, u8 *buf)
  32. {
  33. int ret;
  34. ret = i2c_smbus_read_i2c_block_data(client, reg, 1, buf);
  35. if (ret < 0)
  36. dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret);
  37. return ret;
  38. }
  39. #if 0
  40. static void bq24260_i2c_write_array(struct i2c_client *client,
  41. u8 *buf, int size)
  42. {
  43. int i;
  44. for (i = 0; i < size; i += 3)
  45. bq24260_i2c_write(client, (u8) (*(buf + i)), (buf + i) + 1);
  46. }
  47. #endif
  48. static void bq24260_set_command(struct i2c_client *client,
  49. int reg, int datum)
  50. {
  51. int val;
  52. u8 data = 0;
  53. val = bq24260_i2c_read(client, reg, &data);
  54. if (val >= 0) {
  55. dev_dbg(&client->dev, "%s : reg(0x%02x): 0x%02x(0x%02x)",
  56. __func__, reg, data, datum);
  57. if (data != datum) {
  58. data = datum;
  59. if (bq24260_i2c_write(client, reg, &data) < 0)
  60. dev_err(&client->dev,
  61. "%s : error!\n", __func__);
  62. val = bq24260_i2c_read(client, reg, &data);
  63. if (val >= 0)
  64. dev_dbg(&client->dev, " => 0x%02x\n", data);
  65. }
  66. }
  67. }
  68. static void bq24260_test_read(struct i2c_client *client)
  69. {
  70. u8 data = 0;
  71. u32 addr = 0;
  72. for (addr = 0; addr <= 0x06; addr++) {
  73. bq24260_i2c_read(client, addr, &data);
  74. dev_dbg(&client->dev,
  75. "bq24260 addr : 0x%02x data : 0x%02x\n", addr, data);
  76. }
  77. }
  78. static void bq24260_read_regs(struct i2c_client *client, char *str)
  79. {
  80. u8 data = 0;
  81. u32 addr = 0;
  82. for (addr = 0; addr <= 0x06; addr++) {
  83. bq24260_i2c_read(client, addr, &data);
  84. sprintf(str+strlen(str), "0x%x, ", data);
  85. }
  86. }
  87. static int bq24260_get_charging_status(struct i2c_client *client)
  88. {
  89. int status = POWER_SUPPLY_STATUS_UNKNOWN;
  90. u8 data = 0;
  91. bq24260_i2c_read(client, BQ24260_STATUS, &data);
  92. dev_info(&client->dev,
  93. "%s : charger status(0x%02x)\n", __func__, data);
  94. data = (data & 0x30);
  95. switch (data) {
  96. case 0x00:
  97. status = POWER_SUPPLY_STATUS_DISCHARGING;
  98. break;
  99. case 0x10:
  100. status = POWER_SUPPLY_STATUS_CHARGING;
  101. break;
  102. case 0x20:
  103. status = POWER_SUPPLY_STATUS_FULL;
  104. break;
  105. case 0x30:
  106. status = POWER_SUPPLY_STATUS_NOT_CHARGING;
  107. break;
  108. }
  109. return (int)status;
  110. }
  111. static int bq24260_get_charging_health(struct i2c_client *client)
  112. {
  113. int health = POWER_SUPPLY_HEALTH_GOOD;
  114. u8 data = 0;
  115. bq24260_i2c_read(client, BQ24260_STATUS, &data);
  116. dev_info(&client->dev,
  117. "%s : charger status(0x%02x)\n", __func__, data);
  118. if ((data & 0x30) == 0x30) { /* check for fault */
  119. data = (data & 0x07);
  120. switch (data) {
  121. case 0x01:
  122. health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
  123. break;
  124. case 0x02:
  125. health = POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
  126. break;
  127. }
  128. }
  129. return (int)health;
  130. }
  131. static u8 bq24260_get_float_voltage_data(
  132. int float_voltage)
  133. {
  134. u8 data;
  135. if (float_voltage < 3500)
  136. float_voltage = 3500;
  137. data = (float_voltage - 3500) / 20;
  138. return data << 2;
  139. }
  140. static u8 bq24260_get_input_current_limit_data(
  141. int input_current)
  142. {
  143. u8 data = 0x00;
  144. if (system_rev >= 0x01)
  145. if (input_current <= 100)
  146. data = 0x00;
  147. else if (input_current <= 150)
  148. data = 0x01;
  149. else if (input_current <= 500)
  150. data = 0x02;
  151. else if (input_current <= 900)
  152. data = 0x03;/*v2: 1000mA*/
  153. else if (input_current <= 1500)
  154. data = 0x04;/*v2: 1300mA*/
  155. else if (input_current <= 2000)
  156. data = 0x05;/*1950mA, v2: 1800mA*/
  157. else if (input_current <= 2500)
  158. data = 0x06;/*v2: 2200mA*/
  159. else/*1950mA, v2: 1800mA*/
  160. data = 0x07;
  161. else {
  162. if (input_current <= 100)
  163. data = 0x00;
  164. else if (input_current <= 150)
  165. data = 0x01;
  166. else if (input_current <= 500)
  167. data = 0x02;
  168. else if (input_current <= 900)
  169. data = 0x03;
  170. else if (input_current <= 1000)
  171. data = 0x04;
  172. else if (input_current <= 2000)
  173. data = 0x06;/*1950mA*/
  174. else
  175. data = 0x07;
  176. }
  177. return data << 4;
  178. }
  179. static u8 bq24260_get_termination_current_limit_data(
  180. int termination_current)
  181. {
  182. u8 data;
  183. /* default offset 50mA, max 300mA */
  184. data = (termination_current - 50) / 50;
  185. return data;
  186. }
  187. static u8 bq24260_get_fast_charging_current_data(
  188. int fast_charging_current)
  189. {
  190. u8 data;
  191. /* default offset 500mA */
  192. if (fast_charging_current < 500)
  193. fast_charging_current = 500;
  194. data = (fast_charging_current - 500) / 100;
  195. return data << 3;
  196. }
  197. static void bq24260_charger_function_conrol(
  198. struct i2c_client *client)
  199. {
  200. struct sec_charger_info *charger = i2c_get_clientdata(client);
  201. union power_supply_propval val;
  202. int full_check_type;
  203. u8 data;
  204. if (charger->charging_current < 0) {
  205. dev_dbg(&client->dev,
  206. "%s : OTG is activated. Ignore command!\n", __func__);
  207. return;
  208. }
  209. if (charger->cable_type ==
  210. POWER_SUPPLY_TYPE_BATTERY) {
  211. data = 0x00;
  212. bq24260_i2c_read(client, BQ24260_CONTROL, &data);
  213. data |= 0x2;
  214. data &= 0x7f; /* Prevent register reset */
  215. bq24260_set_command(client,
  216. BQ24260_CONTROL, data);
  217. } else {
  218. data = 0x00;
  219. bq24260_i2c_read(client, BQ24260_CONTROL, &data);
  220. /* Enable charging */
  221. data &= 0x7d; /*default enabled*/
  222. psy_do_property("battery", get,
  223. POWER_SUPPLY_PROP_CHARGE_NOW, val);
  224. if (val.intval == SEC_BATTERY_CHARGING_1ST)
  225. full_check_type = charger->pdata->full_check_type;
  226. else
  227. full_check_type = charger->pdata->full_check_type_2nd;
  228. /* Termination setting */
  229. switch (full_check_type) {
  230. case SEC_BATTERY_FULLCHARGED_CHGGPIO:
  231. case SEC_BATTERY_FULLCHARGED_CHGINT:
  232. case SEC_BATTERY_FULLCHARGED_CHGPSY:
  233. /* Enable Current Termination */
  234. data |= 0x04;
  235. break;
  236. default:
  237. data &= 0x7b;
  238. break;
  239. }
  240. /* Input current limit */
  241. if (charger->pdata->cable_source_type &
  242. SEC_BATTERY_CABLE_SOURCE_EXTENDED) {
  243. dev_dbg(&client->dev, "%s : chg max (%dmA)\n",
  244. __func__, charger->charging_current_max);
  245. data &= 0x0F;
  246. data |= bq24260_get_input_current_limit_data(
  247. charger->charging_current_max);
  248. } else {
  249. dev_dbg(&client->dev, "%s : input current (%dmA)\n",
  250. __func__, charger->pdata->charging_current
  251. [charger->cable_type].input_current_limit);
  252. data &= 0x0F;
  253. data |= bq24260_get_input_current_limit_data(
  254. charger->pdata->charging_current
  255. [charger->cable_type].input_current_limit);
  256. }
  257. bq24260_set_command(client,
  258. BQ24260_CONTROL, data);
  259. data = 0x00;
  260. /* Float voltage */
  261. dev_dbg(&client->dev, "%s : float voltage (%dmV)\n",
  262. __func__, charger->pdata->chg_float_voltage);
  263. data |= bq24260_get_float_voltage_data(
  264. charger->pdata->chg_float_voltage);
  265. bq24260_set_command(client,
  266. BQ24260_VOLTAGE, data);
  267. data = 0x00;
  268. /* Fast charge and Termination current */
  269. dev_dbg(&client->dev, "%s : fast charging current (%dmA)\n",
  270. __func__, charger->charging_current);
  271. data |= bq24260_get_fast_charging_current_data(
  272. charger->charging_current);
  273. dev_dbg(&client->dev, "%s : termination current (%dmA)\n",
  274. __func__, charger->pdata->charging_current[
  275. charger->cable_type].full_check_current_1st >= 300 ?
  276. 300 : charger->pdata->charging_current[
  277. charger->cable_type].full_check_current_1st);
  278. data |= bq24260_get_termination_current_limit_data(
  279. charger->pdata->charging_current[
  280. charger->cable_type].full_check_current_1st);
  281. bq24260_set_command(client,
  282. BQ24260_CURRENT, data);
  283. /* Special Charger Voltage
  284. * Normal charge current
  285. */
  286. bq24260_i2c_read(client, BQ24260_SPECIAL, &data);
  287. data &= 0xd8;
  288. data |= 0x4;
  289. bq24260_set_command(client,
  290. BQ24260_SPECIAL, data);
  291. }
  292. }
  293. static void bq24260_charger_otg_conrol(
  294. struct i2c_client *client)
  295. {
  296. struct sec_charger_info *charger = i2c_get_clientdata(client);
  297. u8 data;
  298. bq24260_i2c_read(client, BQ24260_SAFETY, &data);
  299. data &= ~(0x1 << 4);
  300. bq24260_set_command(client, BQ24260_SAFETY, data);
  301. data = 0x00;
  302. if (charger->cable_type !=
  303. POWER_SUPPLY_TYPE_OTG) {
  304. dev_info(&client->dev, "%s : turn off OTG\n", __func__);
  305. /* turn off OTG */
  306. bq24260_i2c_read(client, BQ24260_STATUS, &data);
  307. data &= 0xbf;
  308. bq24260_set_command(client,
  309. BQ24260_STATUS, data);
  310. } else {
  311. dev_info(&client->dev, "%s : turn on OTG\n", __func__);
  312. /* turn on OTG */
  313. bq24260_i2c_read(client, BQ24260_STATUS, &data);
  314. data |= 0x40;
  315. bq24260_set_command(client,
  316. BQ24260_STATUS, data);
  317. }
  318. }
  319. static void bq24260_set_input_current(
  320. struct i2c_client *client, int input_current)
  321. {
  322. u8 data = 0x00;
  323. bq24260_i2c_read(client, BQ24260_CONTROL, &data);
  324. data &= 0x0F;
  325. data |= bq24260_get_input_current_limit_data(input_current);
  326. bq24260_set_command(client, BQ24260_CONTROL, data);
  327. }
  328. static void bq24260_set_charging_current(
  329. struct i2c_client *client, int charging_current)
  330. {
  331. u8 data = 0x00;
  332. bq24260_i2c_read(client, BQ24260_CURRENT, &data);
  333. data |= bq24260_get_fast_charging_current_data(charging_current);
  334. bq24260_set_command(client, BQ24260_CURRENT, data);
  335. }
  336. #if 0
  337. static int bq24260_get_charge_type(struct i2c_client *client)
  338. {
  339. int ret;
  340. u8 data;
  341. bq24260_i2c_read(client, BQ24260_STATUS, &data);
  342. data = (data & 0x30)>>4;
  343. switch (data) {
  344. case 0x01:
  345. ret = POWER_SUPPLY_CHARGE_TYPE_FAST;
  346. break;
  347. default:
  348. ret = POWER_SUPPLY_CHARGE_TYPE_NONE;
  349. break;
  350. }
  351. return ret;
  352. }
  353. #endif
  354. bool bq24260_hal_chg_init(struct i2c_client *client)
  355. {
  356. bq24260_test_read(client);
  357. return true;
  358. }
  359. bool bq24260_hal_chg_suspend(struct i2c_client *client)
  360. {
  361. return true;
  362. }
  363. bool bq24260_hal_chg_resume(struct i2c_client *client)
  364. {
  365. return true;
  366. }
  367. bool bq24260_hal_chg_shutdown(struct i2c_client *client)
  368. {
  369. u8 data = 1;
  370. bq24260_i2c_write(client, BQ24260_CONTROL, &data);
  371. return true;
  372. }
  373. bool bq24260_hal_chg_get_property(struct i2c_client *client,
  374. enum power_supply_property psp,
  375. union power_supply_propval *val)
  376. {
  377. struct sec_charger_info *charger = i2c_get_clientdata(client);
  378. u8 data;
  379. switch (psp) {
  380. case POWER_SUPPLY_PROP_STATUS:
  381. val->intval = bq24260_get_charging_status(client);
  382. break;
  383. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  384. /*val->intval = bq24260_get_charge_type(client);*/
  385. if (charger->is_charging)
  386. val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
  387. else
  388. val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
  389. break;
  390. case POWER_SUPPLY_PROP_HEALTH:
  391. val->intval = bq24260_get_charging_health(client);
  392. break;
  393. /* calculated input current limit value */
  394. case POWER_SUPPLY_PROP_CURRENT_NOW:
  395. case POWER_SUPPLY_PROP_CURRENT_AVG: /* charging current */
  396. if (charger->charging_current) {
  397. /* Rsns 0.068 Ohm */
  398. bq24260_i2c_read(client, BQ24260_CURRENT, &data);
  399. val->intval = (data >> 3) * 100 + 500;
  400. } else
  401. val->intval = 0;
  402. dev_dbg(&client->dev,
  403. "%s : set-current(%dmA), current now(%dmA)\n",
  404. __func__, charger->charging_current, val->intval);
  405. break;
  406. default:
  407. return false;
  408. }
  409. return true;
  410. }
  411. bool bq24260_hal_chg_set_property(struct i2c_client *client,
  412. enum power_supply_property psp,
  413. const union power_supply_propval *val)
  414. {
  415. struct sec_charger_info *charger = i2c_get_clientdata(client);
  416. switch (psp) {
  417. /* val->intval : type */
  418. case POWER_SUPPLY_PROP_ONLINE:
  419. if (charger->pdata->chg_gpio_en) {
  420. if (gpio_request(charger->pdata->chg_gpio_en,
  421. "CHG_EN") < 0) {
  422. dev_err(&client->dev,
  423. "failed to request vbus_in gpio\n");
  424. break;
  425. }
  426. if (charger->cable_type ==
  427. POWER_SUPPLY_TYPE_BATTERY)
  428. gpio_set_value_cansleep(
  429. charger->pdata->chg_gpio_en,
  430. charger->pdata->chg_polarity_en ?
  431. 0 : 1);
  432. else
  433. gpio_set_value_cansleep(
  434. charger->pdata->chg_gpio_en,
  435. charger->pdata->chg_polarity_en ?
  436. 1 : 0);
  437. gpio_free(charger->pdata->chg_gpio_en);
  438. }
  439. if (val->intval == POWER_SUPPLY_TYPE_POWER_SHARING) {
  440. union power_supply_propval ps_status;
  441. psy_do_property("ps", get,
  442. POWER_SUPPLY_PROP_STATUS, ps_status);
  443. if (ps_status.intval) {
  444. charger->cable_type = POWER_SUPPLY_TYPE_OTG;
  445. pr_info("%s: ps enable\n", __func__);
  446. } else {
  447. charger->cable_type = POWER_SUPPLY_TYPE_BATTERY;
  448. pr_info("%s: ps disable\n", __func__);
  449. }
  450. }
  451. #if defined(CONFIG_MUIC_SUPPORT_MULTIMEDIA_DOCK)
  452. if(charger->is_mdock) {
  453. if(charger->is_smartotg)
  454. charger->cable_type = POWER_SUPPLY_TYPE_SMART_OTG;
  455. else
  456. charger->cable_type = POWER_SUPPLY_TYPE_MDOCK_TA;
  457. pr_debug("%s: cable type %d\n", __func__, charger->cable_type);
  458. }
  459. #endif
  460. if (charger->charging_current >= 0)
  461. bq24260_charger_function_conrol(client);
  462. bq24260_charger_otg_conrol(client);
  463. bq24260_test_read(client);
  464. break;
  465. case POWER_SUPPLY_PROP_CURRENT_MAX: /* input current limit set */
  466. /* calculated input current limit value */
  467. case POWER_SUPPLY_PROP_CURRENT_NOW:
  468. bq24260_set_input_current(client, val->intval);
  469. break;
  470. /* val->intval : charging current */
  471. case POWER_SUPPLY_PROP_CURRENT_AVG:
  472. bq24260_set_charging_current(client, val->intval);
  473. break;
  474. default:
  475. return false;
  476. }
  477. return true;
  478. }
  479. ssize_t bq24260_hal_chg_show_attrs(struct device *dev,
  480. const ptrdiff_t offset, char *buf)
  481. {
  482. struct power_supply *psy = dev_get_drvdata(dev);
  483. struct sec_charger_info *chg =
  484. container_of(psy, struct sec_charger_info, psy_chg);
  485. int i = 0;
  486. char *str = NULL;
  487. switch (offset) {
  488. case CHG_REG:
  489. i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n",
  490. chg->reg_addr);
  491. break;
  492. case CHG_DATA:
  493. i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n",
  494. chg->reg_data);
  495. break;
  496. case CHG_REGS:
  497. str = kzalloc(sizeof(char)*1024, GFP_KERNEL);
  498. if (!str)
  499. return -ENOMEM;
  500. bq24260_read_regs(chg->client, str);
  501. i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n",
  502. str);
  503. kfree(str);
  504. break;
  505. default:
  506. i = -EINVAL;
  507. break;
  508. }
  509. return i;
  510. }
  511. ssize_t bq24260_hal_chg_store_attrs(struct device *dev,
  512. const ptrdiff_t offset,
  513. const char *buf, size_t count)
  514. {
  515. struct power_supply *psy = dev_get_drvdata(dev);
  516. struct sec_charger_info *chg =
  517. container_of(psy, struct sec_charger_info, psy_chg);
  518. int ret = 0;
  519. int x = 0;
  520. u8 data = 0;
  521. switch (offset) {
  522. case CHG_REG:
  523. if (sscanf(buf, "%x\n", &x) == 1) {
  524. chg->reg_addr = x;
  525. bq24260_i2c_read(chg->client,
  526. chg->reg_addr, &data);
  527. chg->reg_data = data;
  528. dev_dbg(dev, "%s: (read) addr = 0x%x, data = 0x%x\n",
  529. __func__, chg->reg_addr, chg->reg_data);
  530. ret = count;
  531. }
  532. break;
  533. case CHG_DATA:
  534. if (sscanf(buf, "%x\n", &x) == 1) {
  535. data = (u8)x;
  536. dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%x\n",
  537. __func__, chg->reg_addr, data);
  538. bq24260_i2c_write(chg->client,
  539. chg->reg_addr, &data);
  540. ret = count;
  541. }
  542. break;
  543. default:
  544. ret = -EINVAL;
  545. break;
  546. }
  547. return ret;
  548. }
  549. static struct device_attribute bq24260_charger_attrs[] = {
  550. BQ24260_CHARGER_ATTR(reg),
  551. BQ24260_CHARGER_ATTR(data),
  552. BQ24260_CHARGER_ATTR(regs),
  553. };
  554. static enum power_supply_property bq24260_charger_props[] = {
  555. POWER_SUPPLY_PROP_STATUS,
  556. POWER_SUPPLY_PROP_CHARGE_TYPE,
  557. POWER_SUPPLY_PROP_HEALTH,
  558. POWER_SUPPLY_PROP_ONLINE,
  559. POWER_SUPPLY_PROP_CURRENT_MAX,
  560. POWER_SUPPLY_PROP_CURRENT_AVG,
  561. POWER_SUPPLY_PROP_CURRENT_NOW,
  562. POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
  563. };
  564. static int bq24260_chg_get_property(struct power_supply *psy,
  565. enum power_supply_property psp,
  566. union power_supply_propval *val)
  567. {
  568. struct sec_charger_info *charger =
  569. container_of(psy, struct sec_charger_info, psy_chg);
  570. switch (psp) {
  571. case POWER_SUPPLY_PROP_CURRENT_MAX: /* input current limit set */
  572. val->intval = charger->charging_current_max;
  573. break;
  574. case POWER_SUPPLY_PROP_ONLINE:
  575. case POWER_SUPPLY_PROP_STATUS:
  576. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  577. case POWER_SUPPLY_PROP_HEALTH:
  578. case POWER_SUPPLY_PROP_CURRENT_AVG: /* charging current */
  579. /* calculated input current limit value */
  580. case POWER_SUPPLY_PROP_CURRENT_NOW:
  581. if (!bq24260_hal_chg_get_property(charger->client, psp, val))
  582. return -EINVAL;
  583. break;
  584. default:
  585. return -EINVAL;
  586. }
  587. return 0;
  588. }
  589. static int bq24260_chg_set_property(struct power_supply *psy,
  590. enum power_supply_property psp,
  591. const union power_supply_propval *val)
  592. {
  593. struct sec_charger_info *charger =
  594. container_of(psy, struct sec_charger_info, psy_chg);
  595. union power_supply_propval input_value;
  596. switch (psp) {
  597. case POWER_SUPPLY_PROP_STATUS:
  598. charger->status = val->intval;
  599. break;
  600. /* val->intval : type */
  601. case POWER_SUPPLY_PROP_ONLINE:
  602. charger->cable_type = val->intval;
  603. if (val->intval == POWER_SUPPLY_TYPE_BATTERY || \
  604. val->intval == POWER_SUPPLY_TYPE_OTG || \
  605. val->intval == POWER_SUPPLY_TYPE_POWER_SHARING) {
  606. charger->is_charging = false;
  607. #if defined(CONFIG_MUIC_SUPPORT_MULTIMEDIA_DOCK)
  608. charger->is_mdock = false;
  609. charger->is_smartotg = false;
  610. #endif
  611. }
  612. else {
  613. charger->is_charging = true;
  614. #if defined(CONFIG_MUIC_SUPPORT_MULTIMEDIA_DOCK)
  615. if(val->intval == POWER_SUPPLY_TYPE_SMART_NOTG)
  616. charger->is_smartotg = false;
  617. else if (val->intval == POWER_SUPPLY_TYPE_SMART_OTG)
  618. charger->is_smartotg = true;
  619. if (val->intval == POWER_SUPPLY_TYPE_MDOCK_TA)
  620. charger->is_mdock = true;
  621. #endif
  622. }
  623. /* current setting */
  624. if (!(charger->pdata->cable_source_type &
  625. SEC_BATTERY_CABLE_SOURCE_EXTENDED)) {
  626. charger->charging_current_max =
  627. charger->pdata->charging_current[
  628. val->intval].input_current_limit;
  629. charger->charging_current =
  630. charger->pdata->charging_current[
  631. val->intval].fast_charging_current;
  632. }
  633. if (!bq24260_hal_chg_set_property(charger->client, psp, val))
  634. return -EINVAL;
  635. break;
  636. /* val->intval : input current limit set */
  637. case POWER_SUPPLY_PROP_CURRENT_MAX:
  638. charger->charging_current_max = val->intval;
  639. /* to control charging current,
  640. * use input current limit and set charging current as much as possible
  641. * so we only control input current limit to control charge current
  642. */
  643. case POWER_SUPPLY_PROP_CURRENT_NOW:
  644. if (!bq24260_hal_chg_set_property(charger->client, psp, val))
  645. return -EINVAL;
  646. break;
  647. /* val->intval : charging current */
  648. case POWER_SUPPLY_PROP_CURRENT_AVG:
  649. charger->charging_current = val->intval;
  650. if (!bq24260_hal_chg_set_property(charger->client, psp, val))
  651. return -EINVAL;
  652. break;
  653. /* val->intval : SIOP level (%)
  654. * SIOP charging current setting
  655. */
  656. case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
  657. /* change val as charging current by SIOP level
  658. * do NOT change initial charging current setting
  659. */
  660. input_value.intval =
  661. charger->charging_current * val->intval / 100;
  662. /* charging current should be over than USB charging current */
  663. if (charger->pdata->chg_functions_setting &
  664. SEC_CHARGER_MINIMUM_SIOP_CHARGING_CURRENT) {
  665. if (input_value.intval > 0 &&
  666. input_value.intval <
  667. charger->pdata->charging_current[
  668. POWER_SUPPLY_TYPE_USB].fast_charging_current)
  669. input_value.intval =
  670. charger->pdata->charging_current[
  671. POWER_SUPPLY_TYPE_USB].fast_charging_current;
  672. }
  673. /* set charging current as new value */
  674. if (!bq24260_hal_chg_set_property(charger->client,
  675. POWER_SUPPLY_PROP_CURRENT_AVG, &input_value))
  676. return -EINVAL;
  677. break;
  678. default:
  679. return -EINVAL;
  680. }
  681. return 0;
  682. }
  683. static void bq24260_chg_isr_work(struct work_struct *work)
  684. {
  685. struct sec_charger_info *charger =
  686. container_of(work, struct sec_charger_info, isr_work.work);
  687. union power_supply_propval val;
  688. int full_check_type;
  689. dev_info(&charger->client->dev,
  690. "%s: Charger Interrupt\n", __func__);
  691. psy_do_property("battery", get,
  692. POWER_SUPPLY_PROP_CHARGE_NOW, val);
  693. if (val.intval == SEC_BATTERY_CHARGING_1ST)
  694. full_check_type = charger->pdata->full_check_type;
  695. else
  696. full_check_type = charger->pdata->full_check_type_2nd;
  697. if (full_check_type == SEC_BATTERY_FULLCHARGED_CHGINT) {
  698. if (!bq24260_hal_chg_get_property(charger->client,
  699. POWER_SUPPLY_PROP_STATUS, &val))
  700. return;
  701. switch (val.intval) {
  702. case POWER_SUPPLY_STATUS_DISCHARGING:
  703. dev_err(&charger->client->dev,
  704. "%s: Interrupted but Discharging\n", __func__);
  705. break;
  706. case POWER_SUPPLY_STATUS_NOT_CHARGING:
  707. dev_err(&charger->client->dev,
  708. "%s: Interrupted but NOT Charging\n", __func__);
  709. break;
  710. case POWER_SUPPLY_STATUS_FULL:
  711. dev_info(&charger->client->dev,
  712. "%s: Interrupted by Full\n", __func__);
  713. psy_do_property("battery", set,
  714. POWER_SUPPLY_PROP_STATUS, val);
  715. break;
  716. case POWER_SUPPLY_STATUS_CHARGING:
  717. dev_err(&charger->client->dev,
  718. "%s: Interrupted but Charging\n", __func__);
  719. break;
  720. case POWER_SUPPLY_STATUS_UNKNOWN:
  721. default:
  722. dev_err(&charger->client->dev,
  723. "%s: Invalid Charger Status\n", __func__);
  724. break;
  725. }
  726. }
  727. if (charger->pdata->ovp_uvlo_check_type ==
  728. SEC_BATTERY_OVP_UVLO_CHGINT) {
  729. if (!bq24260_hal_chg_get_property(charger->client,
  730. POWER_SUPPLY_PROP_HEALTH, &val))
  731. return;
  732. switch (val.intval) {
  733. case POWER_SUPPLY_HEALTH_OVERHEAT:
  734. case POWER_SUPPLY_HEALTH_COLD:
  735. dev_err(&charger->client->dev,
  736. "%s: Interrupted but Hot/Cold\n", __func__);
  737. break;
  738. case POWER_SUPPLY_HEALTH_DEAD:
  739. dev_err(&charger->client->dev,
  740. "%s: Interrupted but Dead\n", __func__);
  741. break;
  742. case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
  743. case POWER_SUPPLY_HEALTH_UNDERVOLTAGE:
  744. dev_info(&charger->client->dev,
  745. "%s: Interrupted by OVP/UVLO\n", __func__);
  746. psy_do_property("battery", set,
  747. POWER_SUPPLY_PROP_HEALTH, val);
  748. break;
  749. case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
  750. dev_err(&charger->client->dev,
  751. "%s: Interrupted but Unspec\n", __func__);
  752. break;
  753. case POWER_SUPPLY_HEALTH_GOOD:
  754. dev_err(&charger->client->dev,
  755. "%s: Interrupted but Good\n", __func__);
  756. break;
  757. case POWER_SUPPLY_HEALTH_UNKNOWN:
  758. default:
  759. dev_err(&charger->client->dev,
  760. "%s: Invalid Charger Health\n", __func__);
  761. break;
  762. }
  763. }
  764. if (charger->pdata->cable_check_type & SEC_BATTERY_CABLE_CHECK_CHGINT) {
  765. if (!bq24260_hal_chg_get_property(charger->client,
  766. POWER_SUPPLY_PROP_ONLINE, &val))
  767. return;
  768. /* use SEC_BATTERY_CABLE_SOURCE_EXTERNAL for cable_source_type
  769. * charger would call battery driver to set ONLINE property
  770. * check battery driver loaded or not
  771. */
  772. if (get_power_supply_by_name("battery")) {
  773. psy_do_property("battery", set,
  774. POWER_SUPPLY_PROP_ONLINE, val);
  775. } else
  776. charger->pdata->check_cable_result_callback(val.intval);
  777. }
  778. }
  779. static irqreturn_t bq24260_chg_irq_thread(int irq, void *irq_data)
  780. {
  781. struct sec_charger_info *charger = irq_data;
  782. schedule_delayed_work(&charger->isr_work, 0);
  783. return IRQ_HANDLED;
  784. }
  785. static int bq24260_chg_create_attrs(struct device *dev)
  786. {
  787. int i, rc;
  788. for (i = 0; i < ARRAY_SIZE(bq24260_charger_attrs); i++) {
  789. rc = device_create_file(dev, &bq24260_charger_attrs[i]);
  790. if (rc)
  791. goto create_attrs_failed;
  792. }
  793. goto create_attrs_succeed;
  794. create_attrs_failed:
  795. dev_err(dev, "%s: failed (%d)\n", __func__, rc);
  796. while (i--)
  797. device_remove_file(dev, &bq24260_charger_attrs[i]);
  798. create_attrs_succeed:
  799. return rc;
  800. }
  801. ssize_t bq24260_chg_show_attrs(struct device *dev,
  802. struct device_attribute *attr, char *buf)
  803. {
  804. const ptrdiff_t offset = attr - bq24260_charger_attrs;
  805. int i = 0;
  806. switch (offset) {
  807. case CHG_REG:
  808. case CHG_DATA:
  809. case CHG_REGS:
  810. i = bq24260_hal_chg_show_attrs(dev, offset, buf);
  811. break;
  812. default:
  813. i = -EINVAL;
  814. break;
  815. }
  816. return i;
  817. }
  818. ssize_t bq24260_chg_store_attrs(struct device *dev,
  819. struct device_attribute *attr,
  820. const char *buf, size_t count)
  821. {
  822. const ptrdiff_t offset = attr - bq24260_charger_attrs;
  823. int ret = 0;
  824. switch (offset) {
  825. case CHG_REG:
  826. case CHG_DATA:
  827. ret = bq24260_hal_chg_store_attrs(dev, offset, buf, count);
  828. break;
  829. default:
  830. ret = -EINVAL;
  831. break;
  832. }
  833. return ret;
  834. }
  835. #ifdef CONFIG_OF
  836. static int bq24260_charger_read_u32_index_dt(const struct device_node *np,
  837. const char *propname,
  838. u32 index, u32 *out_value)
  839. {
  840. struct property *prop = of_find_property(np, propname, NULL);
  841. u32 len = (index + 1) * sizeof(*out_value);
  842. if (!prop)
  843. return (-EINVAL);
  844. if (!prop->value)
  845. return (-ENODATA);
  846. if (len > prop->length)
  847. return (-EOVERFLOW);
  848. *out_value = be32_to_cpup(((__be32 *)prop->value) + index);
  849. return 0;
  850. }
  851. static int bq24260_charger_parse_dt(struct sec_charger_info *charger)
  852. {
  853. struct device_node *np = of_find_node_by_name(NULL, "charger");
  854. sec_battery_platform_data_t *pdata = charger->pdata;
  855. int ret = 0;
  856. int i, len;
  857. const u32 *p;
  858. if (np == NULL) {
  859. pr_err("%s np NULL\n", __func__);
  860. } else {
  861. ret = of_property_read_u32(np, "battery,chg_float_voltage",
  862. &pdata->chg_float_voltage);
  863. ret = of_property_read_u32(np, "battery,ovp_uvlo_check_type",
  864. &pdata->ovp_uvlo_check_type);
  865. ret = of_property_read_u32(np, "battery,full_check_type",
  866. &pdata->full_check_type);
  867. p = of_get_property(np, "battery,input_current_limit", &len);
  868. len = len / sizeof(u32);
  869. pdata->charging_current = kzalloc(sizeof(sec_charging_current_t) * len,
  870. GFP_KERNEL);
  871. for(i = 0; i < len; i++) {
  872. ret = bq24260_charger_read_u32_index_dt(np,
  873. "battery,input_current_limit", i,
  874. &pdata->charging_current[i].input_current_limit);
  875. ret = bq24260_charger_read_u32_index_dt(np,
  876. "battery,fast_charging_current", i,
  877. &pdata->charging_current[i].fast_charging_current);
  878. ret = bq24260_charger_read_u32_index_dt(np,
  879. "battery,full_check_current_1st", i,
  880. &pdata->charging_current[i].full_check_current_1st);
  881. ret = bq24260_charger_read_u32_index_dt(np,
  882. "battery,full_check_current_2nd", i,
  883. &pdata->charging_current[i].full_check_current_2nd);
  884. }
  885. }
  886. return ret;
  887. }
  888. #endif
  889. static int __devinit bq24260_charger_probe(
  890. struct i2c_client *client,
  891. const struct i2c_device_id *id)
  892. {
  893. struct i2c_adapter *adapter =
  894. to_i2c_adapter(client->dev.parent);
  895. struct sec_charger_info *charger;
  896. int ret = 0;
  897. dev_info(&client->dev,
  898. "%s: BQ24260 Charger Driver Loading\n", __func__);
  899. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
  900. return -EIO;
  901. charger = kzalloc(sizeof(*charger), GFP_KERNEL);
  902. if (!charger)
  903. return -ENOMEM;
  904. charger->client = client;
  905. if (client->dev.of_node) {
  906. void * pdata = kzalloc(sizeof(sec_battery_platform_data_t), GFP_KERNEL);
  907. if (!pdata)
  908. goto err_free1;
  909. charger->pdata = pdata;
  910. if (bq24260_charger_parse_dt(charger))
  911. dev_err(&client->dev,
  912. "%s : Failed to get charger dt\n", __func__);
  913. } else
  914. charger->pdata = client->dev.platform_data;
  915. i2c_set_clientdata(client, charger);
  916. charger->psy_chg.name = "bq24260";
  917. charger->psy_chg.type = POWER_SUPPLY_TYPE_UNKNOWN;
  918. charger->psy_chg.get_property = bq24260_chg_get_property;
  919. charger->psy_chg.set_property = bq24260_chg_set_property;
  920. charger->psy_chg.properties = bq24260_charger_props;
  921. charger->psy_chg.num_properties = ARRAY_SIZE(bq24260_charger_props);
  922. if (!bq24260_hal_chg_init(charger->client)) {
  923. dev_err(&client->dev,
  924. "%s: Failed to Initialize Charger\n", __func__);
  925. goto err_free;
  926. }
  927. ret = power_supply_register(&client->dev, &charger->psy_chg);
  928. if (ret) {
  929. dev_err(&client->dev,
  930. "%s: Failed to Register psy_chg\n", __func__);
  931. goto err_free;
  932. }
  933. if (charger->pdata->chg_irq) {
  934. INIT_DELAYED_WORK_DEFERRABLE(
  935. &charger->isr_work, bq24260_chg_isr_work);
  936. ret = request_threaded_irq(charger->pdata->chg_irq,
  937. NULL, bq24260_chg_irq_thread,
  938. charger->pdata->chg_irq_attr,
  939. "charger-irq", charger);
  940. if (ret) {
  941. dev_err(&client->dev,
  942. "%s: Failed to Reqeust IRQ\n", __func__);
  943. goto err_supply_unreg;
  944. }
  945. ret = enable_irq_wake(charger->pdata->chg_irq);
  946. if (ret < 0)
  947. dev_err(&client->dev,
  948. "%s: Failed to Enable Wakeup Source(%d)\n",
  949. __func__, ret);
  950. }
  951. ret = bq24260_chg_create_attrs(charger->psy_chg.dev);
  952. if (ret) {
  953. dev_err(&client->dev,
  954. "%s : Failed to create_attrs\n", __func__);
  955. goto err_req_irq;
  956. }
  957. dev_dbg(&client->dev,
  958. "%s: BQ24260 Charger Driver Loaded\n", __func__);
  959. return 0;
  960. err_req_irq:
  961. if (charger->pdata->chg_irq)
  962. free_irq(charger->pdata->chg_irq, charger);
  963. err_supply_unreg:
  964. power_supply_unregister(&charger->psy_chg);
  965. err_free:
  966. kfree(charger->pdata);
  967. err_free1:
  968. kfree(charger);
  969. return ret;
  970. }
  971. static int __devexit bq24260_charger_remove(
  972. struct i2c_client *client)
  973. {
  974. return 0;
  975. }
  976. static int bq24260_charger_suspend(struct i2c_client *client,
  977. pm_message_t state)
  978. {
  979. if (!bq24260_hal_chg_suspend(client))
  980. dev_err(&client->dev,
  981. "%s: Failed to Suspend Charger\n", __func__);
  982. return 0;
  983. }
  984. static int bq24260_charger_resume(struct i2c_client *client)
  985. {
  986. if (!bq24260_hal_chg_resume(client))
  987. dev_err(&client->dev,
  988. "%s: Failed to Resume Charger\n", __func__);
  989. return 0;
  990. }
  991. static void bq24260_charger_shutdown(struct i2c_client *client)
  992. {
  993. #if defined(CONFIG_CHARGER_BQ24260)
  994. bq24260_hal_chg_shutdown(client);
  995. #endif
  996. }
  997. static const struct i2c_device_id bq24260_charger_id[] = {
  998. {"bq24260", 0},
  999. {}
  1000. };
  1001. MODULE_DEVICE_TABLE(i2c, bq24260_charger_id);
  1002. static struct of_device_id bq24260_i2c_match_table[] = {
  1003. { .compatible = "bq24260,i2c", },
  1004. { },
  1005. };
  1006. MODULE_DEVICE_TABLE(i2c, bq24260_i2c_match_table);
  1007. static struct i2c_driver bq24260_charger_driver = {
  1008. .driver = {
  1009. .name = "bq24260",
  1010. .owner = THIS_MODULE,
  1011. .of_match_table = bq24260_i2c_match_table,
  1012. },
  1013. .probe = bq24260_charger_probe,
  1014. .remove = __devexit_p(bq24260_charger_remove),
  1015. .suspend = bq24260_charger_suspend,
  1016. .resume = bq24260_charger_resume,
  1017. .shutdown = bq24260_charger_shutdown,
  1018. .id_table = bq24260_charger_id,
  1019. };
  1020. static int __init bq24260_charger_init(void)
  1021. {
  1022. return i2c_add_driver(&bq24260_charger_driver);
  1023. }
  1024. static void __exit bq24260_charger_exit(void)
  1025. {
  1026. i2c_del_driver(&bq24260_charger_driver);
  1027. }
  1028. module_init(bq24260_charger_init);
  1029. module_exit(bq24260_charger_exit);
  1030. MODULE_DESCRIPTION("Samsung bq24260 Charger Driver");
  1031. MODULE_AUTHOR("Samsung Electronics");
  1032. MODULE_LICENSE("GPL");