act8945a_charger.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /*
  2. * Power supply driver for the Active-semi ACT8945A PMIC
  3. *
  4. * Copyright (C) 2015 Atmel Corporation
  5. *
  6. * Author: Wenyou Yang <wenyou.yang@atmel.com>
  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. */
  13. #include <linux/interrupt.h>
  14. #include <linux/module.h>
  15. #include <linux/of.h>
  16. #include <linux/of_irq.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/power_supply.h>
  19. #include <linux/regmap.h>
  20. #include <linux/gpio/consumer.h>
  21. static const char *act8945a_charger_model = "ACT8945A";
  22. static const char *act8945a_charger_manufacturer = "Active-semi";
  23. /**
  24. * ACT8945A Charger Register Map
  25. */
  26. /* 0x70: Reserved */
  27. #define ACT8945A_APCH_CFG 0x71
  28. #define ACT8945A_APCH_STATUS 0x78
  29. #define ACT8945A_APCH_CTRL 0x79
  30. #define ACT8945A_APCH_STATE 0x7A
  31. /* ACT8945A_APCH_CFG */
  32. #define APCH_CFG_OVPSET (0x3 << 0)
  33. #define APCH_CFG_OVPSET_6V6 (0x0 << 0)
  34. #define APCH_CFG_OVPSET_7V (0x1 << 0)
  35. #define APCH_CFG_OVPSET_7V5 (0x2 << 0)
  36. #define APCH_CFG_OVPSET_8V (0x3 << 0)
  37. #define APCH_CFG_PRETIMO (0x3 << 2)
  38. #define APCH_CFG_PRETIMO_40_MIN (0x0 << 2)
  39. #define APCH_CFG_PRETIMO_60_MIN (0x1 << 2)
  40. #define APCH_CFG_PRETIMO_80_MIN (0x2 << 2)
  41. #define APCH_CFG_PRETIMO_DISABLED (0x3 << 2)
  42. #define APCH_CFG_TOTTIMO (0x3 << 4)
  43. #define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4)
  44. #define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4)
  45. #define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4)
  46. #define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4)
  47. #define APCH_CFG_SUSCHG (0x1 << 7)
  48. #define APCH_STATUS_CHGDAT BIT(0)
  49. #define APCH_STATUS_INDAT BIT(1)
  50. #define APCH_STATUS_TEMPDAT BIT(2)
  51. #define APCH_STATUS_TIMRDAT BIT(3)
  52. #define APCH_STATUS_CHGSTAT BIT(4)
  53. #define APCH_STATUS_INSTAT BIT(5)
  54. #define APCH_STATUS_TEMPSTAT BIT(6)
  55. #define APCH_STATUS_TIMRSTAT BIT(7)
  56. #define APCH_CTRL_CHGEOCOUT BIT(0)
  57. #define APCH_CTRL_INDIS BIT(1)
  58. #define APCH_CTRL_TEMPOUT BIT(2)
  59. #define APCH_CTRL_TIMRPRE BIT(3)
  60. #define APCH_CTRL_CHGEOCIN BIT(4)
  61. #define APCH_CTRL_INCON BIT(5)
  62. #define APCH_CTRL_TEMPIN BIT(6)
  63. #define APCH_CTRL_TIMRTOT BIT(7)
  64. #define APCH_STATE_ACINSTAT (0x1 << 1)
  65. #define APCH_STATE_CSTATE (0x3 << 4)
  66. #define APCH_STATE_CSTATE_SHIFT 4
  67. #define APCH_STATE_CSTATE_DISABLED 0x00
  68. #define APCH_STATE_CSTATE_EOC 0x01
  69. #define APCH_STATE_CSTATE_FAST 0x02
  70. #define APCH_STATE_CSTATE_PRE 0x03
  71. struct act8945a_charger {
  72. struct power_supply *psy;
  73. struct power_supply_desc desc;
  74. struct regmap *regmap;
  75. struct work_struct work;
  76. bool init_done;
  77. struct gpio_desc *lbo_gpio;
  78. struct gpio_desc *chglev_gpio;
  79. };
  80. static int act8945a_get_charger_state(struct regmap *regmap, int *val)
  81. {
  82. int ret;
  83. unsigned int status, state;
  84. ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  85. if (ret < 0)
  86. return ret;
  87. ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
  88. if (ret < 0)
  89. return ret;
  90. state &= APCH_STATE_CSTATE;
  91. state >>= APCH_STATE_CSTATE_SHIFT;
  92. switch (state) {
  93. case APCH_STATE_CSTATE_PRE:
  94. case APCH_STATE_CSTATE_FAST:
  95. *val = POWER_SUPPLY_STATUS_CHARGING;
  96. break;
  97. case APCH_STATE_CSTATE_EOC:
  98. if (status & APCH_STATUS_CHGDAT)
  99. *val = POWER_SUPPLY_STATUS_FULL;
  100. else
  101. *val = POWER_SUPPLY_STATUS_CHARGING;
  102. break;
  103. case APCH_STATE_CSTATE_DISABLED:
  104. default:
  105. if (!(status & APCH_STATUS_INDAT))
  106. *val = POWER_SUPPLY_STATUS_DISCHARGING;
  107. else
  108. *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
  109. break;
  110. }
  111. return 0;
  112. }
  113. static int act8945a_get_charge_type(struct regmap *regmap, int *val)
  114. {
  115. int ret;
  116. unsigned int status, state;
  117. ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  118. if (ret < 0)
  119. return ret;
  120. ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
  121. if (ret < 0)
  122. return ret;
  123. state &= APCH_STATE_CSTATE;
  124. state >>= APCH_STATE_CSTATE_SHIFT;
  125. switch (state) {
  126. case APCH_STATE_CSTATE_PRE:
  127. *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
  128. break;
  129. case APCH_STATE_CSTATE_FAST:
  130. *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
  131. break;
  132. case APCH_STATE_CSTATE_EOC:
  133. *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
  134. break;
  135. case APCH_STATE_CSTATE_DISABLED:
  136. default:
  137. if (!(status & APCH_STATUS_INDAT))
  138. *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
  139. else
  140. *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
  141. break;
  142. }
  143. return 0;
  144. }
  145. static int act8945a_get_battery_health(struct regmap *regmap, int *val)
  146. {
  147. int ret;
  148. unsigned int status, state, config;
  149. ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  150. if (ret < 0)
  151. return ret;
  152. ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
  153. if (ret < 0)
  154. return ret;
  155. ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
  156. if (ret < 0)
  157. return ret;
  158. state &= APCH_STATE_CSTATE;
  159. state >>= APCH_STATE_CSTATE_SHIFT;
  160. switch (state) {
  161. case APCH_STATE_CSTATE_DISABLED:
  162. if (config & APCH_CFG_SUSCHG) {
  163. *val = POWER_SUPPLY_HEALTH_UNKNOWN;
  164. } else if (status & APCH_STATUS_INDAT) {
  165. if (!(status & APCH_STATUS_TEMPDAT))
  166. *val = POWER_SUPPLY_HEALTH_OVERHEAT;
  167. else if (status & APCH_STATUS_TIMRDAT)
  168. *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
  169. else
  170. *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
  171. } else {
  172. *val = POWER_SUPPLY_HEALTH_GOOD;
  173. }
  174. break;
  175. case APCH_STATE_CSTATE_PRE:
  176. case APCH_STATE_CSTATE_FAST:
  177. case APCH_STATE_CSTATE_EOC:
  178. default:
  179. *val = POWER_SUPPLY_HEALTH_GOOD;
  180. break;
  181. }
  182. return 0;
  183. }
  184. static int act8945a_get_capacity_level(struct act8945a_charger *charger,
  185. struct regmap *regmap, int *val)
  186. {
  187. int ret;
  188. unsigned int status, state, config;
  189. int lbo_level = gpiod_get_value(charger->lbo_gpio);
  190. ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  191. if (ret < 0)
  192. return ret;
  193. ret = regmap_read(regmap, ACT8945A_APCH_CFG, &config);
  194. if (ret < 0)
  195. return ret;
  196. ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
  197. if (ret < 0)
  198. return ret;
  199. state &= APCH_STATE_CSTATE;
  200. state >>= APCH_STATE_CSTATE_SHIFT;
  201. switch (state) {
  202. case APCH_STATE_CSTATE_PRE:
  203. *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
  204. break;
  205. case APCH_STATE_CSTATE_FAST:
  206. if (lbo_level)
  207. *val = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
  208. else
  209. *val = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
  210. break;
  211. case APCH_STATE_CSTATE_EOC:
  212. if (status & APCH_STATUS_CHGDAT)
  213. *val = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
  214. else
  215. *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
  216. break;
  217. case APCH_STATE_CSTATE_DISABLED:
  218. default:
  219. if (config & APCH_CFG_SUSCHG) {
  220. *val = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
  221. } else {
  222. *val = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
  223. if (!(status & APCH_STATUS_INDAT)) {
  224. if (!lbo_level)
  225. *val = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
  226. }
  227. }
  228. break;
  229. }
  230. return 0;
  231. }
  232. #define MAX_CURRENT_USB_HIGH 450000
  233. #define MAX_CURRENT_USB_LOW 90000
  234. #define MAX_CURRENT_USB_PRE 45000
  235. /*
  236. * Riset(K) = 2336 * (1V/Ichg(mA)) - 0.205
  237. * Riset = 2.43K
  238. */
  239. #define MAX_CURRENT_AC_HIGH 886527
  240. #define MAX_CURRENT_AC_LOW 117305
  241. #define MAX_CURRENT_AC_HIGH_PRE 88653
  242. #define MAX_CURRENT_AC_LOW_PRE 11731
  243. static int act8945a_get_current_max(struct act8945a_charger *charger,
  244. struct regmap *regmap, int *val)
  245. {
  246. int ret;
  247. unsigned int status, state;
  248. unsigned int acin_state;
  249. int chgin_level = gpiod_get_value(charger->chglev_gpio);
  250. ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  251. if (ret < 0)
  252. return ret;
  253. ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
  254. if (ret < 0)
  255. return ret;
  256. acin_state = (state & APCH_STATE_ACINSTAT) >> 1;
  257. state &= APCH_STATE_CSTATE;
  258. state >>= APCH_STATE_CSTATE_SHIFT;
  259. switch (state) {
  260. case APCH_STATE_CSTATE_PRE:
  261. if (acin_state) {
  262. if (chgin_level)
  263. *val = MAX_CURRENT_AC_HIGH_PRE;
  264. else
  265. *val = MAX_CURRENT_AC_LOW_PRE;
  266. } else {
  267. *val = MAX_CURRENT_USB_PRE;
  268. }
  269. break;
  270. case APCH_STATE_CSTATE_FAST:
  271. if (acin_state) {
  272. if (chgin_level)
  273. *val = MAX_CURRENT_AC_HIGH;
  274. else
  275. *val = MAX_CURRENT_AC_LOW;
  276. } else {
  277. if (chgin_level)
  278. *val = MAX_CURRENT_USB_HIGH;
  279. else
  280. *val = MAX_CURRENT_USB_LOW;
  281. }
  282. break;
  283. case APCH_STATE_CSTATE_EOC:
  284. case APCH_STATE_CSTATE_DISABLED:
  285. default:
  286. *val = 0;
  287. break;
  288. }
  289. return 0;
  290. }
  291. static enum power_supply_property act8945a_charger_props[] = {
  292. POWER_SUPPLY_PROP_STATUS,
  293. POWER_SUPPLY_PROP_CHARGE_TYPE,
  294. POWER_SUPPLY_PROP_TECHNOLOGY,
  295. POWER_SUPPLY_PROP_HEALTH,
  296. POWER_SUPPLY_PROP_CAPACITY_LEVEL,
  297. POWER_SUPPLY_PROP_CURRENT_MAX,
  298. POWER_SUPPLY_PROP_MODEL_NAME,
  299. POWER_SUPPLY_PROP_MANUFACTURER
  300. };
  301. static int act8945a_charger_get_property(struct power_supply *psy,
  302. enum power_supply_property prop,
  303. union power_supply_propval *val)
  304. {
  305. struct act8945a_charger *charger = power_supply_get_drvdata(psy);
  306. struct regmap *regmap = charger->regmap;
  307. int ret = 0;
  308. switch (prop) {
  309. case POWER_SUPPLY_PROP_STATUS:
  310. ret = act8945a_get_charger_state(regmap, &val->intval);
  311. break;
  312. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  313. ret = act8945a_get_charge_type(regmap, &val->intval);
  314. break;
  315. case POWER_SUPPLY_PROP_TECHNOLOGY:
  316. val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
  317. break;
  318. case POWER_SUPPLY_PROP_HEALTH:
  319. ret = act8945a_get_battery_health(regmap, &val->intval);
  320. break;
  321. case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
  322. ret = act8945a_get_capacity_level(charger,
  323. regmap, &val->intval);
  324. break;
  325. case POWER_SUPPLY_PROP_CURRENT_MAX:
  326. ret = act8945a_get_current_max(charger,
  327. regmap, &val->intval);
  328. break;
  329. case POWER_SUPPLY_PROP_MODEL_NAME:
  330. val->strval = act8945a_charger_model;
  331. break;
  332. case POWER_SUPPLY_PROP_MANUFACTURER:
  333. val->strval = act8945a_charger_manufacturer;
  334. break;
  335. default:
  336. return -EINVAL;
  337. }
  338. return ret;
  339. }
  340. static int act8945a_enable_interrupt(struct act8945a_charger *charger)
  341. {
  342. struct regmap *regmap = charger->regmap;
  343. unsigned char ctrl;
  344. int ret;
  345. ctrl = APCH_CTRL_CHGEOCOUT | APCH_CTRL_CHGEOCIN |
  346. APCH_CTRL_INDIS | APCH_CTRL_INCON |
  347. APCH_CTRL_TEMPOUT | APCH_CTRL_TEMPIN |
  348. APCH_CTRL_TIMRPRE | APCH_CTRL_TIMRTOT;
  349. ret = regmap_write(regmap, ACT8945A_APCH_CTRL, ctrl);
  350. if (ret)
  351. return ret;
  352. ctrl = APCH_STATUS_CHGSTAT | APCH_STATUS_INSTAT |
  353. APCH_STATUS_TEMPSTAT | APCH_STATUS_TIMRSTAT;
  354. ret = regmap_write(regmap, ACT8945A_APCH_STATUS, ctrl);
  355. if (ret)
  356. return ret;
  357. return 0;
  358. }
  359. static unsigned int act8945a_set_supply_type(struct act8945a_charger *charger,
  360. unsigned int *type)
  361. {
  362. unsigned int status, state;
  363. int ret;
  364. ret = regmap_read(charger->regmap, ACT8945A_APCH_STATUS, &status);
  365. if (ret < 0)
  366. return ret;
  367. ret = regmap_read(charger->regmap, ACT8945A_APCH_STATE, &state);
  368. if (ret < 0)
  369. return ret;
  370. if (status & APCH_STATUS_INDAT) {
  371. if (state & APCH_STATE_ACINSTAT)
  372. *type = POWER_SUPPLY_TYPE_MAINS;
  373. else
  374. *type = POWER_SUPPLY_TYPE_USB;
  375. } else {
  376. *type = POWER_SUPPLY_TYPE_BATTERY;
  377. }
  378. return 0;
  379. }
  380. static void act8945a_work(struct work_struct *work)
  381. {
  382. struct act8945a_charger *charger =
  383. container_of(work, struct act8945a_charger, work);
  384. act8945a_set_supply_type(charger, &charger->desc.type);
  385. power_supply_changed(charger->psy);
  386. }
  387. static irqreturn_t act8945a_status_changed(int irq, void *dev_id)
  388. {
  389. struct act8945a_charger *charger = dev_id;
  390. if (charger->init_done)
  391. schedule_work(&charger->work);
  392. return IRQ_HANDLED;
  393. }
  394. #define DEFAULT_TOTAL_TIME_OUT 3
  395. #define DEFAULT_PRE_TIME_OUT 40
  396. #define DEFAULT_INPUT_OVP_THRESHOLD 6600
  397. static int act8945a_charger_config(struct device *dev,
  398. struct act8945a_charger *charger)
  399. {
  400. struct device_node *np = dev->of_node;
  401. struct regmap *regmap = charger->regmap;
  402. u32 total_time_out;
  403. u32 pre_time_out;
  404. u32 input_voltage_threshold;
  405. int err, ret;
  406. unsigned int tmp;
  407. unsigned int value = 0;
  408. if (!np) {
  409. dev_err(dev, "no charger of node\n");
  410. return -EINVAL;
  411. }
  412. ret = regmap_read(regmap, ACT8945A_APCH_CFG, &tmp);
  413. if (ret)
  414. return ret;
  415. if (tmp & APCH_CFG_SUSCHG) {
  416. value |= APCH_CFG_SUSCHG;
  417. dev_info(dev, "have been suspended\n");
  418. }
  419. charger->lbo_gpio = devm_gpiod_get_optional(dev, "active-semi,lbo",
  420. GPIOD_IN);
  421. if (IS_ERR(charger->lbo_gpio)) {
  422. err = PTR_ERR(charger->lbo_gpio);
  423. dev_err(dev, "unable to claim gpio \"lbo\": %d\n", err);
  424. return err;
  425. }
  426. ret = devm_request_irq(dev, gpiod_to_irq(charger->lbo_gpio),
  427. act8945a_status_changed,
  428. (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
  429. "act8945a_lbo_detect", charger);
  430. if (ret)
  431. dev_info(dev, "failed to request gpio \"lbo\" IRQ\n");
  432. charger->chglev_gpio = devm_gpiod_get_optional(dev,
  433. "active-semi,chglev",
  434. GPIOD_IN);
  435. if (IS_ERR(charger->chglev_gpio)) {
  436. err = PTR_ERR(charger->chglev_gpio);
  437. dev_err(dev, "unable to claim gpio \"chglev\": %d\n", err);
  438. return err;
  439. }
  440. if (of_property_read_u32(np,
  441. "active-semi,input-voltage-threshold-microvolt",
  442. &input_voltage_threshold))
  443. input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
  444. if (of_property_read_u32(np,
  445. "active-semi,precondition-timeout",
  446. &pre_time_out))
  447. pre_time_out = DEFAULT_PRE_TIME_OUT;
  448. if (of_property_read_u32(np, "active-semi,total-timeout",
  449. &total_time_out))
  450. total_time_out = DEFAULT_TOTAL_TIME_OUT;
  451. switch (input_voltage_threshold) {
  452. case 8000:
  453. value |= APCH_CFG_OVPSET_8V;
  454. break;
  455. case 7500:
  456. value |= APCH_CFG_OVPSET_7V5;
  457. break;
  458. case 7000:
  459. value |= APCH_CFG_OVPSET_7V;
  460. break;
  461. case 6600:
  462. default:
  463. value |= APCH_CFG_OVPSET_6V6;
  464. break;
  465. }
  466. switch (pre_time_out) {
  467. case 60:
  468. value |= APCH_CFG_PRETIMO_60_MIN;
  469. break;
  470. case 80:
  471. value |= APCH_CFG_PRETIMO_80_MIN;
  472. break;
  473. case 0:
  474. value |= APCH_CFG_PRETIMO_DISABLED;
  475. break;
  476. case 40:
  477. default:
  478. value |= APCH_CFG_PRETIMO_40_MIN;
  479. break;
  480. }
  481. switch (total_time_out) {
  482. case 4:
  483. value |= APCH_CFG_TOTTIMO_4_HOUR;
  484. break;
  485. case 5:
  486. value |= APCH_CFG_TOTTIMO_5_HOUR;
  487. break;
  488. case 0:
  489. value |= APCH_CFG_TOTTIMO_DISABLED;
  490. break;
  491. case 3:
  492. default:
  493. value |= APCH_CFG_TOTTIMO_3_HOUR;
  494. break;
  495. }
  496. return regmap_write(regmap, ACT8945A_APCH_CFG, value);
  497. }
  498. static int act8945a_charger_probe(struct platform_device *pdev)
  499. {
  500. struct act8945a_charger *charger;
  501. struct power_supply_config psy_cfg = {};
  502. int irq, ret;
  503. charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
  504. if (!charger)
  505. return -ENOMEM;
  506. charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
  507. if (!charger->regmap) {
  508. dev_err(&pdev->dev, "Parent did not provide regmap\n");
  509. return -EINVAL;
  510. }
  511. ret = act8945a_charger_config(&pdev->dev, charger);
  512. if (ret)
  513. return ret;
  514. irq = of_irq_get(pdev->dev.of_node, 0);
  515. if (irq <= 0) {
  516. dev_err(&pdev->dev, "failed to find IRQ number\n");
  517. return irq ?: -ENXIO;
  518. }
  519. ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
  520. IRQF_TRIGGER_FALLING, "act8945a_interrupt",
  521. charger);
  522. if (ret) {
  523. dev_err(&pdev->dev, "failed to request nIRQ pin IRQ\n");
  524. return ret;
  525. }
  526. charger->desc.name = "act8945a-charger";
  527. charger->desc.get_property = act8945a_charger_get_property;
  528. charger->desc.properties = act8945a_charger_props;
  529. charger->desc.num_properties = ARRAY_SIZE(act8945a_charger_props);
  530. ret = act8945a_set_supply_type(charger, &charger->desc.type);
  531. if (ret)
  532. return -EINVAL;
  533. psy_cfg.of_node = pdev->dev.of_node;
  534. psy_cfg.drv_data = charger;
  535. charger->psy = devm_power_supply_register(&pdev->dev,
  536. &charger->desc,
  537. &psy_cfg);
  538. if (IS_ERR(charger->psy)) {
  539. dev_err(&pdev->dev, "failed to register power supply\n");
  540. return PTR_ERR(charger->psy);
  541. }
  542. platform_set_drvdata(pdev, charger);
  543. INIT_WORK(&charger->work, act8945a_work);
  544. ret = act8945a_enable_interrupt(charger);
  545. if (ret)
  546. return -EIO;
  547. charger->init_done = true;
  548. return 0;
  549. }
  550. static int act8945a_charger_remove(struct platform_device *pdev)
  551. {
  552. struct act8945a_charger *charger = platform_get_drvdata(pdev);
  553. charger->init_done = false;
  554. cancel_work_sync(&charger->work);
  555. return 0;
  556. }
  557. static struct platform_driver act8945a_charger_driver = {
  558. .driver = {
  559. .name = "act8945a-charger",
  560. },
  561. .probe = act8945a_charger_probe,
  562. .remove = act8945a_charger_remove,
  563. };
  564. module_platform_driver(act8945a_charger_driver);
  565. MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
  566. MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
  567. MODULE_LICENSE("GPL");