sec_fuelgauge.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. /*
  2. * sec_fuelgauge.c
  3. * Samsung Mobile Fuel Gauge Driver
  4. *
  5. * Copyright (C) 2012 Samsung Electronics
  6. *
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/battery/sec_fuelgauge.h>
  13. #include <linux/battery/sec_charger.h>
  14. #include <linux/battery/sec_battery.h>
  15. #include <linux/of_gpio.h>
  16. static struct device_attribute sec_fg_attrs[] = {
  17. SEC_FG_ATTR(reg),
  18. SEC_FG_ATTR(data),
  19. SEC_FG_ATTR(regs),
  20. };
  21. static enum power_supply_property sec_fuelgauge_props[] = {
  22. POWER_SUPPLY_PROP_STATUS,
  23. POWER_SUPPLY_PROP_PRESENT,
  24. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  25. POWER_SUPPLY_PROP_VOLTAGE_AVG,
  26. POWER_SUPPLY_PROP_CURRENT_NOW,
  27. POWER_SUPPLY_PROP_CURRENT_AVG,
  28. POWER_SUPPLY_PROP_CHARGE_FULL,
  29. POWER_SUPPLY_PROP_ENERGY_NOW,
  30. POWER_SUPPLY_PROP_CAPACITY,
  31. POWER_SUPPLY_PROP_TEMP,
  32. POWER_SUPPLY_PROP_TEMP_AMBIENT,
  33. POWER_SUPPLY_PROP_ENERGY_FULL,
  34. POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
  35. };
  36. /* capacity is 0.1% unit */
  37. static void sec_fg_get_scaled_capacity(
  38. struct sec_fuelgauge_info *fuelgauge,
  39. union power_supply_propval *val)
  40. {
  41. val->intval = (val->intval < fuelgauge->pdata->capacity_min) ?
  42. 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 /
  43. (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min));
  44. dev_info(&fuelgauge->client->dev,
  45. "%s: scaled capacity (%d.%d)\n",
  46. __func__, val->intval/10, val->intval%10);
  47. #if defined(CONFIG_MACH_KLIMT)|| defined(CONFIG_MACH_CHAGALL)
  48. /* Reduce soc jump when battery is full
  49. change capacity_max to initial value */
  50. if (fuelgauge->is_charging) {
  51. if (fuelgauge->capacity_max > fuelgauge->pdata->capacity_max)
  52. fuelgauge->capacity_max--;
  53. }
  54. #endif
  55. }
  56. /* capacity is integer */
  57. static void sec_fg_get_atomic_capacity(
  58. struct sec_fuelgauge_info *fuelgauge,
  59. union power_supply_propval *val)
  60. {
  61. if (fuelgauge->pdata->capacity_calculation_type &
  62. SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC) {
  63. if (fuelgauge->capacity_old < val->intval)
  64. val->intval = fuelgauge->capacity_old + 1;
  65. else if (fuelgauge->capacity_old > val->intval)
  66. val->intval = fuelgauge->capacity_old - 1;
  67. }
  68. /* keep SOC stable in abnormal status */
  69. if (fuelgauge->pdata->capacity_calculation_type &
  70. SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL) {
  71. if (!fuelgauge->is_charging &&
  72. fuelgauge->capacity_old < val->intval) {
  73. dev_err(&fuelgauge->client->dev,
  74. "%s: capacity (old %d : new %d)\n",
  75. __func__, fuelgauge->capacity_old, val->intval);
  76. val->intval = fuelgauge->capacity_old;
  77. }
  78. }
  79. /* updated old capacity */
  80. fuelgauge->capacity_old = val->intval;
  81. }
  82. static int sec_fg_get_property(struct power_supply *psy,
  83. enum power_supply_property psp,
  84. union power_supply_propval *val)
  85. {
  86. struct sec_fuelgauge_info *fuelgauge =
  87. container_of(psy, struct sec_fuelgauge_info, psy_fg);
  88. int soc_type = val->intval;
  89. switch (psp) {
  90. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  91. case POWER_SUPPLY_PROP_VOLTAGE_AVG:
  92. case POWER_SUPPLY_PROP_CURRENT_NOW:
  93. case POWER_SUPPLY_PROP_CURRENT_AVG:
  94. case POWER_SUPPLY_PROP_ENERGY_NOW:
  95. case POWER_SUPPLY_PROP_CAPACITY:
  96. case POWER_SUPPLY_PROP_TEMP:
  97. case POWER_SUPPLY_PROP_TEMP_AMBIENT:
  98. case POWER_SUPPLY_PROP_ENERGY_FULL:
  99. if (!sec_hal_fg_get_property(fuelgauge->client, psp, val))
  100. return -EINVAL;
  101. if (psp == POWER_SUPPLY_PROP_CAPACITY) {
  102. if (soc_type == SEC_FUELGAUGE_CAPACITY_TYPE_RAW)
  103. break;
  104. /* check whether doing the __pm_relax */
  105. if ((val->intval > fuelgauge->pdata->fuel_alert_soc) &&
  106. fuelgauge->is_fuel_alerted) {
  107. __pm_relax(&fuelgauge->fuel_alert_ws);
  108. sec_hal_fg_fuelalert_init(fuelgauge->client,
  109. fuelgauge->pdata->fuel_alert_soc);
  110. }
  111. if (fuelgauge->pdata->capacity_calculation_type &
  112. (SEC_FUELGAUGE_CAPACITY_TYPE_SCALE |
  113. SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE))
  114. sec_fg_get_scaled_capacity(fuelgauge, val);
  115. /* capacity should be between 0% and 100%
  116. * (0.1% degree)
  117. */
  118. if (val->intval > 1000)
  119. val->intval = 1000;
  120. if (val->intval < 0)
  121. val->intval = 0;
  122. /* get only integer part */
  123. val->intval /= 10;
  124. /* (Only for atomic capacity)
  125. * In initial time, capacity_old is 0.
  126. * and in resume from sleep,
  127. * capacity_old is too different from actual soc.
  128. * should update capacity_old
  129. * by val->intval in booting or resume.
  130. */
  131. if (fuelgauge->initial_update_of_soc) {
  132. /* updated old capacity */
  133. fuelgauge->capacity_old = val->intval;
  134. fuelgauge->initial_update_of_soc = false;
  135. break;
  136. }
  137. if (fuelgauge->pdata->capacity_calculation_type &
  138. (SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC |
  139. SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL))
  140. sec_fg_get_atomic_capacity(fuelgauge, val);
  141. }
  142. break;
  143. case POWER_SUPPLY_PROP_PRESENT:
  144. if (fuelgauge->pdata->bat_irq_gpio > 0) {
  145. val->intval = !gpio_get_value(fuelgauge->pdata->bat_irq_gpio);
  146. if (val->intval == 0) {
  147. dev_info(&fuelgauge->client->dev, "%s: Battery status(%d)\n",
  148. __func__, val->intval);
  149. }
  150. } else {
  151. dev_err(&fuelgauge->client->dev, "%s: bat irq gpio is invalid (%d)\n",
  152. __func__, fuelgauge->pdata->bat_irq_gpio);
  153. val->intval = 1;
  154. }
  155. break;
  156. case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
  157. val->intval = fuelgauge->capacity_max;
  158. break;
  159. case POWER_SUPPLY_PROP_STATUS:
  160. case POWER_SUPPLY_PROP_CHARGE_FULL:
  161. return -ENODATA;
  162. default:
  163. return -EINVAL;
  164. }
  165. return 0;
  166. }
  167. static int sec_fg_calculate_dynamic_scale(
  168. struct sec_fuelgauge_info *fuelgauge)
  169. {
  170. union power_supply_propval raw_soc_val;
  171. raw_soc_val.intval = SEC_FUELGAUGE_CAPACITY_TYPE_RAW;
  172. if (!sec_hal_fg_get_property(fuelgauge->client,
  173. POWER_SUPPLY_PROP_CAPACITY,
  174. &raw_soc_val))
  175. return -EINVAL;
  176. raw_soc_val.intval /= 10;
  177. if (raw_soc_val.intval <
  178. fuelgauge->pdata->capacity_max -
  179. fuelgauge->pdata->capacity_max_margin) {
  180. fuelgauge->capacity_max =
  181. fuelgauge->pdata->capacity_max -
  182. fuelgauge->pdata->capacity_max_margin;
  183. dev_dbg(&fuelgauge->client->dev, "%s: capacity_max (%d)",
  184. __func__, fuelgauge->capacity_max);
  185. } else {
  186. fuelgauge->capacity_max =
  187. (raw_soc_val.intval >
  188. fuelgauge->pdata->capacity_max +
  189. fuelgauge->pdata->capacity_max_margin) ?
  190. (fuelgauge->pdata->capacity_max +
  191. fuelgauge->pdata->capacity_max_margin) :
  192. raw_soc_val.intval;
  193. dev_dbg(&fuelgauge->client->dev, "%s: raw soc (%d)",
  194. __func__, fuelgauge->capacity_max);
  195. }
  196. fuelgauge->capacity_max =
  197. (fuelgauge->capacity_max * 99 / 100);
  198. /* update capacity_old for sec_fg_get_atomic_capacity algorithm */
  199. fuelgauge->capacity_old = 100;
  200. dev_info(&fuelgauge->client->dev, "%s: %d is used for capacity_max\n",
  201. __func__, fuelgauge->capacity_max);
  202. return fuelgauge->capacity_max;
  203. }
  204. static int sec_fg_set_property(struct power_supply *psy,
  205. enum power_supply_property psp,
  206. const union power_supply_propval *val)
  207. {
  208. struct sec_fuelgauge_info *fuelgauge =
  209. container_of(psy, struct sec_fuelgauge_info, psy_fg);
  210. sec_battery_platform_data_t *pdata = fuelgauge->pdata;
  211. switch (psp) {
  212. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  213. if (!pdata->jig_irq)
  214. sec_hal_fg_set_property(fuelgauge->client, psp, val);
  215. break;
  216. case POWER_SUPPLY_PROP_STATUS:
  217. if (val->intval == POWER_SUPPLY_STATUS_FULL)
  218. sec_hal_fg_full_charged(fuelgauge->client);
  219. break;
  220. case POWER_SUPPLY_PROP_CHARGE_FULL:
  221. if (val->intval == POWER_SUPPLY_TYPE_BATTERY) {
  222. if (fuelgauge->pdata->capacity_calculation_type &
  223. SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE)
  224. sec_fg_calculate_dynamic_scale(fuelgauge);
  225. }
  226. break;
  227. case POWER_SUPPLY_PROP_ONLINE:
  228. fuelgauge->cable_type = val->intval;
  229. if (val->intval == POWER_SUPPLY_TYPE_BATTERY)
  230. fuelgauge->is_charging = false;
  231. else
  232. fuelgauge->is_charging = true;
  233. /* fall through */
  234. case POWER_SUPPLY_PROP_CAPACITY:
  235. if (val->intval == SEC_FUELGAUGE_CAPACITY_TYPE_RESET) {
  236. fuelgauge->initial_update_of_soc = true;
  237. if (!sec_hal_fg_reset(fuelgauge->client))
  238. return -EINVAL;
  239. else
  240. break;
  241. }
  242. case POWER_SUPPLY_PROP_TEMP:
  243. case POWER_SUPPLY_PROP_TEMP_AMBIENT:
  244. if (!sec_hal_fg_set_property(fuelgauge->client, psp, val))
  245. return -EINVAL;
  246. break;
  247. case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
  248. dev_info(&fuelgauge->client->dev,
  249. "%s: capacity_max changed, %d -> %d\n",
  250. __func__, fuelgauge->capacity_max, val->intval);
  251. fuelgauge->capacity_max = val->intval;
  252. fuelgauge->initial_update_of_soc = true;
  253. break;
  254. default:
  255. return -EINVAL;
  256. }
  257. return 0;
  258. }
  259. static void sec_fg_isr_work(struct work_struct *work)
  260. {
  261. struct sec_fuelgauge_info *fuelgauge =
  262. container_of(work, struct sec_fuelgauge_info, isr_work.work);
  263. /* process for fuel gauge chip */
  264. sec_hal_fg_fuelalert_process(fuelgauge, fuelgauge->is_fuel_alerted);
  265. /* process for others */
  266. if (fuelgauge->pdata->fuelalert_process != NULL)
  267. fuelgauge->pdata->fuelalert_process(fuelgauge->is_fuel_alerted);
  268. }
  269. static irqreturn_t sec_fg_irq_thread(int irq, void *irq_data)
  270. {
  271. struct sec_fuelgauge_info *fuelgauge = irq_data;
  272. bool fuel_alerted;
  273. if (fuelgauge->pdata->fuel_alert_soc >= 0) {
  274. fuel_alerted =
  275. sec_hal_fg_is_fuelalerted(fuelgauge->client);
  276. dev_info(&fuelgauge->client->dev,
  277. "%s: Fuel-alert %salerted!\n",
  278. __func__, fuel_alerted ? "" : "NOT ");
  279. if (fuel_alerted == fuelgauge->is_fuel_alerted) {
  280. if (!fuelgauge->pdata->repeated_fuelalert) {
  281. dev_dbg(&fuelgauge->client->dev,
  282. "%s: Fuel-alert Repeated (%d)\n",
  283. __func__, fuelgauge->is_fuel_alerted);
  284. return IRQ_HANDLED;
  285. }
  286. }
  287. if (fuel_alerted)
  288. __pm_stay_awake(&fuelgauge->fuel_alert_ws);
  289. else
  290. __pm_relax(&fuelgauge->fuel_alert_ws);
  291. schedule_delayed_work(&fuelgauge->isr_work, 0);
  292. fuelgauge->is_fuel_alerted = fuel_alerted;
  293. }
  294. return IRQ_HANDLED;
  295. }
  296. static int sec_fg_create_attrs(struct device *dev)
  297. {
  298. int i, rc;
  299. for (i = 0; i < ARRAY_SIZE(sec_fg_attrs); i++) {
  300. rc = device_create_file(dev, &sec_fg_attrs[i]);
  301. if (rc)
  302. goto create_attrs_failed;
  303. }
  304. goto create_attrs_succeed;
  305. create_attrs_failed:
  306. dev_err(dev, "%s: failed (%d)\n", __func__, rc);
  307. while (i--)
  308. device_remove_file(dev, &sec_fg_attrs[i]);
  309. create_attrs_succeed:
  310. return rc;
  311. }
  312. ssize_t sec_fg_show_attrs(struct device *dev,
  313. struct device_attribute *attr, char *buf)
  314. {
  315. const ptrdiff_t offset = attr - sec_fg_attrs;
  316. int i = 0;
  317. switch (offset) {
  318. case FG_REG:
  319. case FG_DATA:
  320. case FG_REGS:
  321. i = sec_hal_fg_show_attrs(dev, offset, buf);
  322. break;
  323. default:
  324. i = -EINVAL;
  325. break;
  326. }
  327. return i;
  328. }
  329. ssize_t sec_fg_store_attrs(struct device *dev,
  330. struct device_attribute *attr,
  331. const char *buf, size_t count)
  332. {
  333. const ptrdiff_t offset = attr - sec_fg_attrs;
  334. int ret = 0;
  335. switch (offset) {
  336. case FG_REG:
  337. case FG_DATA:
  338. ret = sec_hal_fg_store_attrs(dev, offset, buf, count);
  339. break;
  340. default:
  341. ret = -EINVAL;
  342. break;
  343. }
  344. return ret;
  345. }
  346. #ifdef CONFIG_OF
  347. static int fuelgauge_parse_dt(struct device *dev,
  348. struct sec_fuelgauge_info *fuelgauge)
  349. {
  350. struct device_node *np = dev->of_node;
  351. #if !defined(CONFIG_FUELGAUGE_MAX17050)
  352. struct device_node *bnp = of_find_node_by_name(NULL, "battery");
  353. #endif
  354. sec_battery_platform_data_t *pdata = fuelgauge->pdata;
  355. int ret;
  356. #if 0
  357. int ta_int_gpio;
  358. sec_battery_platform_data_t sec_battery_pdata;
  359. #endif
  360. /*#if defined(CONFIG_FUELGAUGE_MAX17050)*/
  361. #if 0
  362. int cn, rn;
  363. u32 low_battery_table_temp[CURRENT_RANGE_MAX_NUM*ELEMENT_N];
  364. u32 temp_adjust_table_temp[TEMP_RANGE_MAX_NUM*ELEMENT_N];
  365. #endif
  366. /* reset, irq gpio info */
  367. if (np == NULL) {
  368. pr_err("%s np NULL\n", __func__);
  369. } else {
  370. #if defined(CONFIG_FUELGAUGE_MAX17050)
  371. pdata->fg_irq = of_get_named_gpio(np, "fuelgauge,fuel_int", 0);
  372. if (pdata->fg_irq < 0)
  373. pr_err("%s error reading fg_irq = %d\n", __func__, pdata->fg_irq);
  374. ret = of_property_read_u32(np, "fuelgauge,capacity_calculation_type",
  375. &pdata->capacity_calculation_type);
  376. if (ret < 0)
  377. pr_err("%s error reading capacity_calculation_type %d\n",
  378. __func__, ret);
  379. ret = of_property_read_u32(np, "fuelgauge,fuel_alert_soc",
  380. &pdata->fuel_alert_soc);
  381. if (ret < 0)
  382. pr_err("%s error reading pdata->fuel_alert_soc %d\n",
  383. __func__, ret);
  384. pdata->repeated_fuelalert = of_property_read_bool(np,
  385. "fuelgaguge,repeated_fuelalert");
  386. pdata->jig_irq = of_get_named_gpio(np, "fuelgauge,jig_gpio", 0);
  387. if (pdata->jig_irq < 0) {
  388. pr_err("%s error reading jig_gpio = %d\n",
  389. __func__,pdata->jig_irq);
  390. pdata->jig_irq = 0;
  391. } else {
  392. pdata->jig_irq_attr = IRQF_TRIGGER_RISING;
  393. }
  394. pr_info("%s: fg_irq: %d, "
  395. "calculation_type: 0x%x, fuel_alert_soc: %d,"
  396. "repeated_fuelalert: %d, jig_irq : %d\n", __func__, pdata->fg_irq,
  397. pdata->capacity_calculation_type,
  398. pdata->fuel_alert_soc, pdata->repeated_fuelalert, pdata->jig_irq);
  399. #else
  400. pdata->charger_name = "sec-charger";
  401. if (bnp == NULL) {
  402. pr_err("%s bnp NULL, Forced set to sec-charger\n", __func__);
  403. } else {
  404. ret = of_property_read_string(bnp,
  405. "battery,charger_name", (char const **)&pdata->charger_name);
  406. if (ret)
  407. pr_info("%s: Vendor is Empty. Forced set to sec-charger\n", __func__);
  408. }
  409. ret = of_get_named_gpio(np, "fuelgauge,fuel_int", 0);
  410. if (ret > 0) {
  411. pdata->fg_irq = ret;
  412. pr_info("%s reading fg_irq = %d\n", __func__, ret);
  413. }
  414. ret = of_get_named_gpio(np, "fuelgauge,bat_int", 0);
  415. if (ret > 0) {
  416. pdata->bat_irq_gpio = ret;
  417. pdata->bat_irq = gpio_to_irq(ret);
  418. pr_info("%s reading bat_int_gpio = %d\n", __func__, ret);
  419. }
  420. ret = of_property_read_u32(np, "fuelgauge,capacity_calculation_type",
  421. &pdata->capacity_calculation_type);
  422. if (ret < 0)
  423. pr_err("%s error reading capacity_calculation_type %d\n",
  424. __func__, ret);
  425. ret = of_property_read_u32(np, "fuelgauge,fuel_alert_soc",
  426. &pdata->fuel_alert_soc);
  427. if (ret < 0)
  428. pr_err("%s error reading pdata->fuel_alert_soc %d\n",
  429. __func__, ret);
  430. pdata->repeated_fuelalert = of_property_read_bool(np,
  431. "fuelgaguge,repeated_fuelalert");
  432. pr_info("%s: fg_irq: %d, "
  433. "calculation_type: 0x%x, fuel_alert_soc: %d,\n"
  434. "repeated_fuelalert: %d\n", __func__, pdata->fg_irq,
  435. pdata->capacity_calculation_type,
  436. pdata->fuel_alert_soc, pdata->repeated_fuelalert
  437. );
  438. #endif
  439. }
  440. return 0;
  441. }
  442. #else
  443. static int fuelgauge_parse_dt(struct device *dev,
  444. struct synaptics_rmi4_power_data *pdata)
  445. {
  446. return -ENODEV;
  447. }
  448. #endif
  449. static int __devinit sec_fuelgauge_probe(struct i2c_client *client,
  450. const struct i2c_device_id *id)
  451. {
  452. struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
  453. struct sec_fuelgauge_info *fuelgauge;
  454. sec_battery_platform_data_t *pdata = NULL;
  455. struct battery_data_t *battery_data = NULL;
  456. int ret = 0;
  457. union power_supply_propval raw_soc_val;
  458. dev_info(&client->dev,
  459. "%s: SEC Fuelgauge Driver Loading\n", __func__);
  460. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
  461. return -EIO;
  462. fuelgauge = kzalloc(sizeof(*fuelgauge), GFP_KERNEL);
  463. if (!fuelgauge)
  464. return -ENOMEM;
  465. mutex_init(&fuelgauge->fg_lock);
  466. fuelgauge->client = client;
  467. if (client->dev.of_node) {
  468. int error;
  469. pdata = devm_kzalloc(&client->dev,
  470. sizeof(sec_battery_platform_data_t),
  471. GFP_KERNEL);
  472. if (!pdata) {
  473. dev_err(&client->dev, "Failed to allocate memory\n");
  474. ret = -ENOMEM;
  475. goto err_free;
  476. }
  477. fuelgauge->pdata = pdata;
  478. error = fuelgauge_parse_dt(&client->dev, fuelgauge);
  479. if (error) {
  480. dev_err(&client->dev,
  481. "%s: Failed to get fuel_int\n", __func__);
  482. }
  483. } else {
  484. dev_err(&client->dev,
  485. "%s: Failed to get of_node\n", __func__);
  486. fuelgauge->pdata = client->dev.platform_data;
  487. }
  488. i2c_set_clientdata(client, fuelgauge);
  489. if (fuelgauge->pdata->fg_gpio_init != NULL) {
  490. if (!fuelgauge->pdata->fg_gpio_init()) {
  491. dev_err(&client->dev,
  492. "%s: Failed to Initialize GPIO\n", __func__);
  493. goto err_devm_free;
  494. }
  495. }
  496. if (!sec_hal_fg_init(fuelgauge->client)) {
  497. dev_err(&client->dev,
  498. "%s: Failed to Initialize Fuelgauge\n", __func__);
  499. goto err_devm_free;
  500. }
  501. fuelgauge->psy_fg.name = "sec-fuelgauge";
  502. fuelgauge->psy_fg.type = POWER_SUPPLY_TYPE_UNKNOWN;
  503. fuelgauge->psy_fg.get_property = sec_fg_get_property;
  504. fuelgauge->psy_fg.set_property = sec_fg_set_property;
  505. fuelgauge->psy_fg.properties = sec_fuelgauge_props;
  506. fuelgauge->psy_fg.num_properties =
  507. ARRAY_SIZE(sec_fuelgauge_props);
  508. fuelgauge->capacity_max = fuelgauge->pdata->capacity_max;
  509. raw_soc_val.intval = SEC_FUELGAUGE_CAPACITY_TYPE_RAW;
  510. sec_hal_fg_get_property(fuelgauge->client,
  511. POWER_SUPPLY_PROP_CAPACITY, &raw_soc_val);
  512. raw_soc_val.intval /= 10;
  513. if(raw_soc_val.intval > fuelgauge->pdata->capacity_max)
  514. sec_fg_calculate_dynamic_scale(fuelgauge);
  515. ret = power_supply_register(&client->dev, &fuelgauge->psy_fg);
  516. if (ret) {
  517. dev_err(&client->dev,
  518. "%s: Failed to Register psy_fg\n", __func__);
  519. goto err_devm_free;
  520. }
  521. fuelgauge->is_fuel_alerted = false;
  522. if (fuelgauge->pdata->fuel_alert_soc >= 0) {
  523. if (sec_hal_fg_fuelalert_init(fuelgauge->client,
  524. fuelgauge->pdata->fuel_alert_soc))
  525. wakeup_source_init(&fuelgauge->fuel_alert_ws, "fuel_alerted");
  526. else {
  527. dev_err(&client->dev,
  528. "%s: Failed to Initialize Fuel-alert\n",
  529. __func__);
  530. goto err_supply_unreg;
  531. }
  532. }
  533. if (fuelgauge->pdata->fg_irq > 0) {
  534. INIT_DELAYED_WORK_DEFERRABLE(
  535. &fuelgauge->isr_work, sec_fg_isr_work);
  536. fuelgauge->fg_irq = gpio_to_irq(fuelgauge->pdata->fg_irq);
  537. dev_info(&client->dev,
  538. "%s: fg_irq = %d\n", __func__, fuelgauge->fg_irq);
  539. if (fuelgauge->fg_irq > 0) {
  540. ret = request_threaded_irq(fuelgauge->fg_irq,
  541. NULL, sec_fg_irq_thread,
  542. IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
  543. "fuelgauge-irq", fuelgauge);
  544. if (ret) {
  545. dev_err(&client->dev,
  546. "%s: Failed to Reqeust IRQ\n", __func__);
  547. goto err_supply_unreg;
  548. }
  549. ret = enable_irq_wake(fuelgauge->fg_irq);
  550. if (ret < 0)
  551. dev_err(&client->dev,
  552. "%s: Failed to Enable Wakeup Source(%d)\n",
  553. __func__, ret);
  554. } else {
  555. dev_err(&client->dev, "%s: Failed gpio_to_irq(%d)\n",
  556. __func__, fuelgauge->fg_irq);
  557. goto err_supply_unreg;
  558. }
  559. }
  560. fuelgauge->initial_update_of_soc = true;
  561. ret = sec_fg_create_attrs(fuelgauge->psy_fg.dev);
  562. if (ret) {
  563. dev_err(&client->dev,
  564. "%s : Failed to create_attrs\n", __func__);
  565. goto err_irq;
  566. }
  567. dev_info(&client->dev,
  568. "%s: SEC Fuelgauge Driver Loaded\n", __func__);
  569. return 0;
  570. err_irq:
  571. if (fuelgauge->fg_irq > 0)
  572. free_irq(fuelgauge->fg_irq, fuelgauge);
  573. wakeup_source_trash(&fuelgauge->fuel_alert_ws);
  574. err_supply_unreg:
  575. power_supply_unregister(&fuelgauge->psy_fg);
  576. err_devm_free:
  577. if(pdata)
  578. devm_kfree(&client->dev, pdata);
  579. if(battery_data)
  580. devm_kfree(&client->dev, battery_data);
  581. err_free:
  582. mutex_destroy(&fuelgauge->fg_lock);
  583. kfree(fuelgauge);
  584. dev_info(&client->dev, "%s: Fuel gauge probe failed\n", __func__);
  585. return ret;
  586. }
  587. static int __devexit sec_fuelgauge_remove(
  588. struct i2c_client *client)
  589. {
  590. struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client);
  591. if (fuelgauge->pdata->fuel_alert_soc >= 0)
  592. wakeup_source_trash(&fuelgauge->fuel_alert_ws);
  593. return 0;
  594. }
  595. static int sec_fuelgauge_suspend(struct device *dev)
  596. {
  597. struct sec_fuelgauge_info *fuelgauge = dev_get_drvdata(dev);
  598. struct power_supply *psy_battery;
  599. psy_battery = get_power_supply_by_name("battery");
  600. if (!psy_battery) {
  601. pr_err("%s : can't get battery psy\n", __func__);
  602. } else {
  603. struct sec_battery_info *battery;
  604. battery = container_of(psy_battery, struct sec_battery_info, psy_bat);
  605. battery->fuelgauge_in_sleep = true;
  606. dev_info(&fuelgauge->client->dev, "%s fuelgauge in sleep (%d)\n",
  607. __func__, battery->fuelgauge_in_sleep);
  608. }
  609. if (!sec_hal_fg_suspend(fuelgauge->client))
  610. dev_err(&fuelgauge->client->dev,
  611. "%s: Failed to Suspend Fuelgauge\n", __func__);
  612. return 0;
  613. }
  614. static int sec_fuelgauge_resume(struct device *dev)
  615. {
  616. struct sec_fuelgauge_info *fuelgauge = dev_get_drvdata(dev);
  617. struct power_supply *psy_battery;
  618. psy_battery = get_power_supply_by_name("battery");
  619. if (!psy_battery) {
  620. pr_err("%s : can't get battery psy\n", __func__);
  621. } else {
  622. struct sec_battery_info *battery;
  623. battery = container_of(psy_battery, struct sec_battery_info, psy_bat);
  624. battery->fuelgauge_in_sleep = false;
  625. dev_info(&fuelgauge->client->dev, "%s fuelgauge in sleep (%d)\n",
  626. __func__, battery->fuelgauge_in_sleep);
  627. }
  628. if (!sec_hal_fg_resume(fuelgauge->client))
  629. dev_err(&fuelgauge->client->dev,
  630. "%s: Failed to Resume Fuelgauge\n", __func__);
  631. return 0;
  632. }
  633. static void sec_fuelgauge_shutdown(struct i2c_client *client)
  634. {
  635. }
  636. static const struct i2c_device_id sec_fuelgauge_id[] = {
  637. {"sec-fuelgauge", 0},
  638. {}
  639. };
  640. static const struct dev_pm_ops sec_fuelgauge_pm_ops = {
  641. .suspend = sec_fuelgauge_suspend,
  642. .resume = sec_fuelgauge_resume,
  643. };
  644. MODULE_DEVICE_TABLE(i2c, sec_fuelgauge_id);
  645. static struct of_device_id fuelgague_i2c_match_table[] = {
  646. { .compatible = "sec-fuelgauge,i2c", },
  647. { },
  648. };
  649. MODULE_DEVICE_TABLE(i2c, fuelgague_i2c_match_table);
  650. static struct i2c_driver sec_fuelgauge_driver = {
  651. .driver = {
  652. .name = "sec-fuelgauge",
  653. .owner = THIS_MODULE,
  654. .of_match_table = fuelgague_i2c_match_table,
  655. #ifdef CONFIG_PM
  656. .pm = &sec_fuelgauge_pm_ops,
  657. #endif
  658. },
  659. .probe = sec_fuelgauge_probe,
  660. .remove = __devexit_p(sec_fuelgauge_remove),
  661. .shutdown = sec_fuelgauge_shutdown,
  662. .id_table = sec_fuelgauge_id,
  663. };
  664. static int __init sec_fuelgauge_init(void)
  665. {
  666. return i2c_add_driver(&sec_fuelgauge_driver);
  667. }
  668. static void __exit sec_fuelgauge_exit(void)
  669. {
  670. i2c_del_driver(&sec_fuelgauge_driver);
  671. }
  672. module_init(sec_fuelgauge_init);
  673. module_exit(sec_fuelgauge_exit);
  674. MODULE_DESCRIPTION("Samsung Fuel Gauge Driver");
  675. MODULE_AUTHOR("Samsung Electronics");
  676. MODULE_LICENSE("GPL");