wm831x_power.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. /*
  2. * PMU driver for Wolfson Microelectronics wm831x PMICs
  3. *
  4. * Copyright 2009 Wolfson Microelectronics PLC.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/module.h>
  11. #include <linux/err.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/power_supply.h>
  14. #include <linux/slab.h>
  15. #include <linux/usb/phy.h>
  16. #include <linux/mfd/wm831x/core.h>
  17. #include <linux/mfd/wm831x/auxadc.h>
  18. #include <linux/mfd/wm831x/pmu.h>
  19. #include <linux/mfd/wm831x/pdata.h>
  20. struct wm831x_power {
  21. struct wm831x *wm831x;
  22. struct power_supply *wall;
  23. struct power_supply *usb;
  24. struct power_supply *battery;
  25. struct power_supply_desc wall_desc;
  26. struct power_supply_desc usb_desc;
  27. struct power_supply_desc battery_desc;
  28. char wall_name[20];
  29. char usb_name[20];
  30. char battery_name[20];
  31. bool have_battery;
  32. struct usb_phy *usb_phy;
  33. struct notifier_block usb_notify;
  34. };
  35. static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
  36. union power_supply_propval *val)
  37. {
  38. int ret;
  39. ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS);
  40. if (ret < 0)
  41. return ret;
  42. if (ret & supply)
  43. val->intval = 1;
  44. else
  45. val->intval = 0;
  46. return 0;
  47. }
  48. static int wm831x_power_read_voltage(struct wm831x *wm831x,
  49. enum wm831x_auxadc src,
  50. union power_supply_propval *val)
  51. {
  52. int ret;
  53. ret = wm831x_auxadc_read_uv(wm831x, src);
  54. if (ret >= 0)
  55. val->intval = ret;
  56. return ret;
  57. }
  58. /*********************************************************************
  59. * WALL Power
  60. *********************************************************************/
  61. static int wm831x_wall_get_prop(struct power_supply *psy,
  62. enum power_supply_property psp,
  63. union power_supply_propval *val)
  64. {
  65. struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev.parent);
  66. struct wm831x *wm831x = wm831x_power->wm831x;
  67. int ret = 0;
  68. switch (psp) {
  69. case POWER_SUPPLY_PROP_ONLINE:
  70. ret = wm831x_power_check_online(wm831x, WM831X_PWR_WALL, val);
  71. break;
  72. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  73. ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_WALL, val);
  74. break;
  75. default:
  76. ret = -EINVAL;
  77. break;
  78. }
  79. return ret;
  80. }
  81. static enum power_supply_property wm831x_wall_props[] = {
  82. POWER_SUPPLY_PROP_ONLINE,
  83. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  84. };
  85. /*********************************************************************
  86. * USB Power
  87. *********************************************************************/
  88. static int wm831x_usb_get_prop(struct power_supply *psy,
  89. enum power_supply_property psp,
  90. union power_supply_propval *val)
  91. {
  92. struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev.parent);
  93. struct wm831x *wm831x = wm831x_power->wm831x;
  94. int ret = 0;
  95. switch (psp) {
  96. case POWER_SUPPLY_PROP_ONLINE:
  97. ret = wm831x_power_check_online(wm831x, WM831X_PWR_USB, val);
  98. break;
  99. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  100. ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_USB, val);
  101. break;
  102. default:
  103. ret = -EINVAL;
  104. break;
  105. }
  106. return ret;
  107. }
  108. static enum power_supply_property wm831x_usb_props[] = {
  109. POWER_SUPPLY_PROP_ONLINE,
  110. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  111. };
  112. /* In milliamps */
  113. static const unsigned int wm831x_usb_limits[] = {
  114. 0,
  115. 2,
  116. 100,
  117. 500,
  118. 900,
  119. 1500,
  120. 1800,
  121. 550,
  122. };
  123. static int wm831x_usb_limit_change(struct notifier_block *nb,
  124. unsigned long limit, void *data)
  125. {
  126. struct wm831x_power *wm831x_power = container_of(nb,
  127. struct wm831x_power,
  128. usb_notify);
  129. unsigned int i, best;
  130. /* Find the highest supported limit */
  131. best = 0;
  132. for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) {
  133. if (limit >= wm831x_usb_limits[i] &&
  134. wm831x_usb_limits[best] < wm831x_usb_limits[i])
  135. best = i;
  136. }
  137. dev_dbg(wm831x_power->wm831x->dev,
  138. "Limiting USB current to %umA", wm831x_usb_limits[best]);
  139. wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE,
  140. WM831X_USB_ILIM_MASK, best);
  141. return 0;
  142. }
  143. /*********************************************************************
  144. * Battery properties
  145. *********************************************************************/
  146. struct chg_map {
  147. int val;
  148. int reg_val;
  149. };
  150. static struct chg_map trickle_ilims[] = {
  151. { 50, 0 << WM831X_CHG_TRKL_ILIM_SHIFT },
  152. { 100, 1 << WM831X_CHG_TRKL_ILIM_SHIFT },
  153. { 150, 2 << WM831X_CHG_TRKL_ILIM_SHIFT },
  154. { 200, 3 << WM831X_CHG_TRKL_ILIM_SHIFT },
  155. };
  156. static struct chg_map vsels[] = {
  157. { 4050, 0 << WM831X_CHG_VSEL_SHIFT },
  158. { 4100, 1 << WM831X_CHG_VSEL_SHIFT },
  159. { 4150, 2 << WM831X_CHG_VSEL_SHIFT },
  160. { 4200, 3 << WM831X_CHG_VSEL_SHIFT },
  161. };
  162. static struct chg_map fast_ilims[] = {
  163. { 0, 0 << WM831X_CHG_FAST_ILIM_SHIFT },
  164. { 50, 1 << WM831X_CHG_FAST_ILIM_SHIFT },
  165. { 100, 2 << WM831X_CHG_FAST_ILIM_SHIFT },
  166. { 150, 3 << WM831X_CHG_FAST_ILIM_SHIFT },
  167. { 200, 4 << WM831X_CHG_FAST_ILIM_SHIFT },
  168. { 250, 5 << WM831X_CHG_FAST_ILIM_SHIFT },
  169. { 300, 6 << WM831X_CHG_FAST_ILIM_SHIFT },
  170. { 350, 7 << WM831X_CHG_FAST_ILIM_SHIFT },
  171. { 400, 8 << WM831X_CHG_FAST_ILIM_SHIFT },
  172. { 450, 9 << WM831X_CHG_FAST_ILIM_SHIFT },
  173. { 500, 10 << WM831X_CHG_FAST_ILIM_SHIFT },
  174. { 600, 11 << WM831X_CHG_FAST_ILIM_SHIFT },
  175. { 700, 12 << WM831X_CHG_FAST_ILIM_SHIFT },
  176. { 800, 13 << WM831X_CHG_FAST_ILIM_SHIFT },
  177. { 900, 14 << WM831X_CHG_FAST_ILIM_SHIFT },
  178. { 1000, 15 << WM831X_CHG_FAST_ILIM_SHIFT },
  179. };
  180. static struct chg_map eoc_iterms[] = {
  181. { 20, 0 << WM831X_CHG_ITERM_SHIFT },
  182. { 30, 1 << WM831X_CHG_ITERM_SHIFT },
  183. { 40, 2 << WM831X_CHG_ITERM_SHIFT },
  184. { 50, 3 << WM831X_CHG_ITERM_SHIFT },
  185. { 60, 4 << WM831X_CHG_ITERM_SHIFT },
  186. { 70, 5 << WM831X_CHG_ITERM_SHIFT },
  187. { 80, 6 << WM831X_CHG_ITERM_SHIFT },
  188. { 90, 7 << WM831X_CHG_ITERM_SHIFT },
  189. };
  190. static struct chg_map chg_times[] = {
  191. { 60, 0 << WM831X_CHG_TIME_SHIFT },
  192. { 90, 1 << WM831X_CHG_TIME_SHIFT },
  193. { 120, 2 << WM831X_CHG_TIME_SHIFT },
  194. { 150, 3 << WM831X_CHG_TIME_SHIFT },
  195. { 180, 4 << WM831X_CHG_TIME_SHIFT },
  196. { 210, 5 << WM831X_CHG_TIME_SHIFT },
  197. { 240, 6 << WM831X_CHG_TIME_SHIFT },
  198. { 270, 7 << WM831X_CHG_TIME_SHIFT },
  199. { 300, 8 << WM831X_CHG_TIME_SHIFT },
  200. { 330, 9 << WM831X_CHG_TIME_SHIFT },
  201. { 360, 10 << WM831X_CHG_TIME_SHIFT },
  202. { 390, 11 << WM831X_CHG_TIME_SHIFT },
  203. { 420, 12 << WM831X_CHG_TIME_SHIFT },
  204. { 450, 13 << WM831X_CHG_TIME_SHIFT },
  205. { 480, 14 << WM831X_CHG_TIME_SHIFT },
  206. { 510, 15 << WM831X_CHG_TIME_SHIFT },
  207. };
  208. static void wm831x_battey_apply_config(struct wm831x *wm831x,
  209. struct chg_map *map, int count, int val,
  210. int *reg, const char *name,
  211. const char *units)
  212. {
  213. int i;
  214. for (i = 0; i < count; i++)
  215. if (val == map[i].val)
  216. break;
  217. if (i == count) {
  218. dev_err(wm831x->dev, "Invalid %s %d%s\n",
  219. name, val, units);
  220. } else {
  221. *reg |= map[i].reg_val;
  222. dev_dbg(wm831x->dev, "Set %s of %d%s\n", name, val, units);
  223. }
  224. }
  225. static void wm831x_config_battery(struct wm831x *wm831x)
  226. {
  227. struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
  228. struct wm831x_battery_pdata *pdata;
  229. int ret, reg1, reg2;
  230. if (!wm831x_pdata || !wm831x_pdata->battery) {
  231. dev_warn(wm831x->dev,
  232. "No battery charger configuration\n");
  233. return;
  234. }
  235. pdata = wm831x_pdata->battery;
  236. reg1 = 0;
  237. reg2 = 0;
  238. if (!pdata->enable) {
  239. dev_info(wm831x->dev, "Battery charger disabled\n");
  240. return;
  241. }
  242. reg1 |= WM831X_CHG_ENA;
  243. if (pdata->off_mask)
  244. reg2 |= WM831X_CHG_OFF_MSK;
  245. if (pdata->fast_enable)
  246. reg1 |= WM831X_CHG_FAST;
  247. wm831x_battey_apply_config(wm831x, trickle_ilims,
  248. ARRAY_SIZE(trickle_ilims),
  249. pdata->trickle_ilim, &reg2,
  250. "trickle charge current limit", "mA");
  251. wm831x_battey_apply_config(wm831x, vsels, ARRAY_SIZE(vsels),
  252. pdata->vsel, &reg2,
  253. "target voltage", "mV");
  254. wm831x_battey_apply_config(wm831x, fast_ilims, ARRAY_SIZE(fast_ilims),
  255. pdata->fast_ilim, &reg2,
  256. "fast charge current limit", "mA");
  257. wm831x_battey_apply_config(wm831x, eoc_iterms, ARRAY_SIZE(eoc_iterms),
  258. pdata->eoc_iterm, &reg1,
  259. "end of charge current threshold", "mA");
  260. wm831x_battey_apply_config(wm831x, chg_times, ARRAY_SIZE(chg_times),
  261. pdata->timeout, &reg2,
  262. "charger timeout", "min");
  263. ret = wm831x_reg_unlock(wm831x);
  264. if (ret != 0) {
  265. dev_err(wm831x->dev, "Failed to unlock registers: %d\n", ret);
  266. return;
  267. }
  268. ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_1,
  269. WM831X_CHG_ENA_MASK |
  270. WM831X_CHG_FAST_MASK |
  271. WM831X_CHG_ITERM_MASK,
  272. reg1);
  273. if (ret != 0)
  274. dev_err(wm831x->dev, "Failed to set charger control 1: %d\n",
  275. ret);
  276. ret = wm831x_set_bits(wm831x, WM831X_CHARGER_CONTROL_2,
  277. WM831X_CHG_OFF_MSK |
  278. WM831X_CHG_TIME_MASK |
  279. WM831X_CHG_FAST_ILIM_MASK |
  280. WM831X_CHG_TRKL_ILIM_MASK |
  281. WM831X_CHG_VSEL_MASK,
  282. reg2);
  283. if (ret != 0)
  284. dev_err(wm831x->dev, "Failed to set charger control 2: %d\n",
  285. ret);
  286. wm831x_reg_lock(wm831x);
  287. }
  288. static int wm831x_bat_check_status(struct wm831x *wm831x, int *status)
  289. {
  290. int ret;
  291. ret = wm831x_reg_read(wm831x, WM831X_SYSTEM_STATUS);
  292. if (ret < 0)
  293. return ret;
  294. if (ret & WM831X_PWR_SRC_BATT) {
  295. *status = POWER_SUPPLY_STATUS_DISCHARGING;
  296. return 0;
  297. }
  298. ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
  299. if (ret < 0)
  300. return ret;
  301. switch (ret & WM831X_CHG_STATE_MASK) {
  302. case WM831X_CHG_STATE_OFF:
  303. *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
  304. break;
  305. case WM831X_CHG_STATE_TRICKLE:
  306. case WM831X_CHG_STATE_FAST:
  307. *status = POWER_SUPPLY_STATUS_CHARGING;
  308. break;
  309. default:
  310. *status = POWER_SUPPLY_STATUS_UNKNOWN;
  311. break;
  312. }
  313. return 0;
  314. }
  315. static int wm831x_bat_check_type(struct wm831x *wm831x, int *type)
  316. {
  317. int ret;
  318. ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
  319. if (ret < 0)
  320. return ret;
  321. switch (ret & WM831X_CHG_STATE_MASK) {
  322. case WM831X_CHG_STATE_TRICKLE:
  323. case WM831X_CHG_STATE_TRICKLE_OT:
  324. *type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
  325. break;
  326. case WM831X_CHG_STATE_FAST:
  327. case WM831X_CHG_STATE_FAST_OT:
  328. *type = POWER_SUPPLY_CHARGE_TYPE_FAST;
  329. break;
  330. default:
  331. *type = POWER_SUPPLY_CHARGE_TYPE_NONE;
  332. break;
  333. }
  334. return 0;
  335. }
  336. static int wm831x_bat_check_health(struct wm831x *wm831x, int *health)
  337. {
  338. int ret;
  339. ret = wm831x_reg_read(wm831x, WM831X_CHARGER_STATUS);
  340. if (ret < 0)
  341. return ret;
  342. if (ret & WM831X_BATT_HOT_STS) {
  343. *health = POWER_SUPPLY_HEALTH_OVERHEAT;
  344. return 0;
  345. }
  346. if (ret & WM831X_BATT_COLD_STS) {
  347. *health = POWER_SUPPLY_HEALTH_COLD;
  348. return 0;
  349. }
  350. if (ret & WM831X_BATT_OV_STS) {
  351. *health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
  352. return 0;
  353. }
  354. switch (ret & WM831X_CHG_STATE_MASK) {
  355. case WM831X_CHG_STATE_TRICKLE_OT:
  356. case WM831X_CHG_STATE_FAST_OT:
  357. *health = POWER_SUPPLY_HEALTH_OVERHEAT;
  358. break;
  359. case WM831X_CHG_STATE_DEFECTIVE:
  360. *health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
  361. break;
  362. default:
  363. *health = POWER_SUPPLY_HEALTH_GOOD;
  364. break;
  365. }
  366. return 0;
  367. }
  368. static int wm831x_bat_get_prop(struct power_supply *psy,
  369. enum power_supply_property psp,
  370. union power_supply_propval *val)
  371. {
  372. struct wm831x_power *wm831x_power = dev_get_drvdata(psy->dev.parent);
  373. struct wm831x *wm831x = wm831x_power->wm831x;
  374. int ret = 0;
  375. switch (psp) {
  376. case POWER_SUPPLY_PROP_STATUS:
  377. ret = wm831x_bat_check_status(wm831x, &val->intval);
  378. break;
  379. case POWER_SUPPLY_PROP_ONLINE:
  380. ret = wm831x_power_check_online(wm831x, WM831X_PWR_SRC_BATT,
  381. val);
  382. break;
  383. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  384. ret = wm831x_power_read_voltage(wm831x, WM831X_AUX_BATT, val);
  385. break;
  386. case POWER_SUPPLY_PROP_HEALTH:
  387. ret = wm831x_bat_check_health(wm831x, &val->intval);
  388. break;
  389. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  390. ret = wm831x_bat_check_type(wm831x, &val->intval);
  391. break;
  392. default:
  393. ret = -EINVAL;
  394. break;
  395. }
  396. return ret;
  397. }
  398. static enum power_supply_property wm831x_bat_props[] = {
  399. POWER_SUPPLY_PROP_STATUS,
  400. POWER_SUPPLY_PROP_ONLINE,
  401. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  402. POWER_SUPPLY_PROP_HEALTH,
  403. POWER_SUPPLY_PROP_CHARGE_TYPE,
  404. };
  405. static const char *wm831x_bat_irqs[] = {
  406. "BATT HOT",
  407. "BATT COLD",
  408. "BATT FAIL",
  409. "OV",
  410. "END",
  411. "TO",
  412. "MODE",
  413. "START",
  414. };
  415. static irqreturn_t wm831x_bat_irq(int irq, void *data)
  416. {
  417. struct wm831x_power *wm831x_power = data;
  418. struct wm831x *wm831x = wm831x_power->wm831x;
  419. dev_dbg(wm831x->dev, "Battery status changed: %d\n", irq);
  420. /* The battery charger is autonomous so we don't need to do
  421. * anything except kick user space */
  422. if (wm831x_power->have_battery)
  423. power_supply_changed(wm831x_power->battery);
  424. return IRQ_HANDLED;
  425. }
  426. /*********************************************************************
  427. * Initialisation
  428. *********************************************************************/
  429. static irqreturn_t wm831x_syslo_irq(int irq, void *data)
  430. {
  431. struct wm831x_power *wm831x_power = data;
  432. struct wm831x *wm831x = wm831x_power->wm831x;
  433. /* Not much we can actually *do* but tell people for
  434. * posterity, we're probably about to run out of power. */
  435. dev_crit(wm831x->dev, "SYSVDD under voltage\n");
  436. return IRQ_HANDLED;
  437. }
  438. static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
  439. {
  440. struct wm831x_power *wm831x_power = data;
  441. struct wm831x *wm831x = wm831x_power->wm831x;
  442. dev_dbg(wm831x->dev, "Power source changed\n");
  443. /* Just notify for everything - little harm in overnotifying. */
  444. if (wm831x_power->have_battery)
  445. power_supply_changed(wm831x_power->battery);
  446. power_supply_changed(wm831x_power->usb);
  447. power_supply_changed(wm831x_power->wall);
  448. return IRQ_HANDLED;
  449. }
  450. static int wm831x_power_probe(struct platform_device *pdev)
  451. {
  452. struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
  453. struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
  454. struct wm831x_power *power;
  455. int ret, irq, i;
  456. power = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_power),
  457. GFP_KERNEL);
  458. if (power == NULL)
  459. return -ENOMEM;
  460. power->wm831x = wm831x;
  461. platform_set_drvdata(pdev, power);
  462. if (wm831x_pdata && wm831x_pdata->wm831x_num) {
  463. snprintf(power->wall_name, sizeof(power->wall_name),
  464. "wm831x-wall.%d", wm831x_pdata->wm831x_num);
  465. snprintf(power->battery_name, sizeof(power->wall_name),
  466. "wm831x-battery.%d", wm831x_pdata->wm831x_num);
  467. snprintf(power->usb_name, sizeof(power->wall_name),
  468. "wm831x-usb.%d", wm831x_pdata->wm831x_num);
  469. } else {
  470. snprintf(power->wall_name, sizeof(power->wall_name),
  471. "wm831x-wall");
  472. snprintf(power->battery_name, sizeof(power->wall_name),
  473. "wm831x-battery");
  474. snprintf(power->usb_name, sizeof(power->wall_name),
  475. "wm831x-usb");
  476. }
  477. /* We ignore configuration failures since we can still read back
  478. * the status without enabling the charger.
  479. */
  480. wm831x_config_battery(wm831x);
  481. power->wall_desc.name = power->wall_name;
  482. power->wall_desc.type = POWER_SUPPLY_TYPE_MAINS;
  483. power->wall_desc.properties = wm831x_wall_props;
  484. power->wall_desc.num_properties = ARRAY_SIZE(wm831x_wall_props);
  485. power->wall_desc.get_property = wm831x_wall_get_prop;
  486. power->wall = power_supply_register(&pdev->dev, &power->wall_desc,
  487. NULL);
  488. if (IS_ERR(power->wall)) {
  489. ret = PTR_ERR(power->wall);
  490. goto err;
  491. }
  492. power->usb_desc.name = power->usb_name,
  493. power->usb_desc.type = POWER_SUPPLY_TYPE_USB;
  494. power->usb_desc.properties = wm831x_usb_props;
  495. power->usb_desc.num_properties = ARRAY_SIZE(wm831x_usb_props);
  496. power->usb_desc.get_property = wm831x_usb_get_prop;
  497. power->usb = power_supply_register(&pdev->dev, &power->usb_desc, NULL);
  498. if (IS_ERR(power->usb)) {
  499. ret = PTR_ERR(power->usb);
  500. goto err_wall;
  501. }
  502. ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_1);
  503. if (ret < 0)
  504. goto err_wall;
  505. power->have_battery = ret & WM831X_CHG_ENA;
  506. if (power->have_battery) {
  507. power->battery_desc.name = power->battery_name;
  508. power->battery_desc.properties = wm831x_bat_props;
  509. power->battery_desc.num_properties = ARRAY_SIZE(wm831x_bat_props);
  510. power->battery_desc.get_property = wm831x_bat_get_prop;
  511. power->battery_desc.use_for_apm = 1;
  512. power->battery = power_supply_register(&pdev->dev,
  513. &power->battery_desc,
  514. NULL);
  515. if (IS_ERR(power->battery)) {
  516. ret = PTR_ERR(power->battery);
  517. goto err_usb;
  518. }
  519. }
  520. irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO"));
  521. ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
  522. IRQF_TRIGGER_RISING | IRQF_ONESHOT, "System power low",
  523. power);
  524. if (ret != 0) {
  525. dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
  526. irq, ret);
  527. goto err_battery;
  528. }
  529. irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC"));
  530. ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq,
  531. IRQF_TRIGGER_RISING | IRQF_ONESHOT, "Power source",
  532. power);
  533. if (ret != 0) {
  534. dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n",
  535. irq, ret);
  536. goto err_syslo;
  537. }
  538. for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
  539. irq = wm831x_irq(wm831x,
  540. platform_get_irq_byname(pdev,
  541. wm831x_bat_irqs[i]));
  542. ret = request_threaded_irq(irq, NULL, wm831x_bat_irq,
  543. IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  544. wm831x_bat_irqs[i],
  545. power);
  546. if (ret != 0) {
  547. dev_err(&pdev->dev,
  548. "Failed to request %s IRQ %d: %d\n",
  549. wm831x_bat_irqs[i], irq, ret);
  550. goto err_bat_irq;
  551. }
  552. }
  553. power->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "phys", 0);
  554. ret = PTR_ERR_OR_ZERO(power->usb_phy);
  555. switch (ret) {
  556. case 0:
  557. power->usb_notify.notifier_call = wm831x_usb_limit_change;
  558. ret = usb_register_notifier(power->usb_phy, &power->usb_notify);
  559. if (ret) {
  560. dev_err(&pdev->dev, "Failed to register notifier: %d\n",
  561. ret);
  562. goto err_bat_irq;
  563. }
  564. break;
  565. case -EINVAL:
  566. case -ENODEV:
  567. /* ignore missing usb-phy, it's optional */
  568. power->usb_phy = NULL;
  569. ret = 0;
  570. break;
  571. default:
  572. dev_err(&pdev->dev, "Failed to find USB phy: %d\n", ret);
  573. /* fall-through */
  574. case -EPROBE_DEFER:
  575. goto err_bat_irq;
  576. break;
  577. }
  578. return ret;
  579. err_bat_irq:
  580. --i;
  581. for (; i >= 0; i--) {
  582. irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
  583. free_irq(irq, power);
  584. }
  585. irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC"));
  586. free_irq(irq, power);
  587. err_syslo:
  588. irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO"));
  589. free_irq(irq, power);
  590. err_battery:
  591. if (power->have_battery)
  592. power_supply_unregister(power->battery);
  593. err_usb:
  594. power_supply_unregister(power->usb);
  595. err_wall:
  596. power_supply_unregister(power->wall);
  597. err:
  598. return ret;
  599. }
  600. static int wm831x_power_remove(struct platform_device *pdev)
  601. {
  602. struct wm831x_power *wm831x_power = platform_get_drvdata(pdev);
  603. struct wm831x *wm831x = wm831x_power->wm831x;
  604. int irq, i;
  605. if (wm831x_power->usb_phy) {
  606. usb_unregister_notifier(wm831x_power->usb_phy,
  607. &wm831x_power->usb_notify);
  608. }
  609. for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
  610. irq = wm831x_irq(wm831x,
  611. platform_get_irq_byname(pdev,
  612. wm831x_bat_irqs[i]));
  613. free_irq(irq, wm831x_power);
  614. }
  615. irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC"));
  616. free_irq(irq, wm831x_power);
  617. irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO"));
  618. free_irq(irq, wm831x_power);
  619. if (wm831x_power->have_battery)
  620. power_supply_unregister(wm831x_power->battery);
  621. power_supply_unregister(wm831x_power->wall);
  622. power_supply_unregister(wm831x_power->usb);
  623. return 0;
  624. }
  625. static struct platform_driver wm831x_power_driver = {
  626. .probe = wm831x_power_probe,
  627. .remove = wm831x_power_remove,
  628. .driver = {
  629. .name = "wm831x-power",
  630. },
  631. };
  632. module_platform_driver(wm831x_power_driver);
  633. MODULE_DESCRIPTION("Power supply driver for WM831x PMICs");
  634. MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
  635. MODULE_LICENSE("GPL");
  636. MODULE_ALIAS("platform:wm831x-power");