rn5t618_power.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Power supply driver for the RICOH RN5T618 power management chip family
  4. *
  5. * Copyright (C) 2020 Andreas Kemnade
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/device.h>
  9. #include <linux/bitops.h>
  10. #include <linux/errno.h>
  11. #include <linux/iio/consumer.h>
  12. #include <linux/init.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/module.h>
  15. #include <linux/mfd/rn5t618.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/power_supply.h>
  18. #include <linux/regmap.h>
  19. #include <linux/slab.h>
  20. #define CHG_STATE_ADP_INPUT 0x40
  21. #define CHG_STATE_USB_INPUT 0x80
  22. #define CHG_STATE_MASK 0x1f
  23. #define CHG_STATE_CHG_OFF 0
  24. #define CHG_STATE_CHG_READY_VADP 1
  25. #define CHG_STATE_CHG_TRICKLE 2
  26. #define CHG_STATE_CHG_RAPID 3
  27. #define CHG_STATE_CHG_COMPLETE 4
  28. #define CHG_STATE_SUSPEND 5
  29. #define CHG_STATE_VCHG_OVER_VOL 6
  30. #define CHG_STATE_BAT_ERROR 7
  31. #define CHG_STATE_NO_BAT 8
  32. #define CHG_STATE_BAT_OVER_VOL 9
  33. #define CHG_STATE_BAT_TEMP_ERR 10
  34. #define CHG_STATE_DIE_ERR 11
  35. #define CHG_STATE_DIE_SHUTDOWN 12
  36. #define CHG_STATE_NO_BAT2 13
  37. #define CHG_STATE_CHG_READY_VUSB 14
  38. #define GCHGDET_TYPE_MASK 0x30
  39. #define GCHGDET_TYPE_SDP 0x00
  40. #define GCHGDET_TYPE_CDP 0x10
  41. #define GCHGDET_TYPE_DCP 0x20
  42. #define FG_ENABLE 1
  43. /*
  44. * Formula seems accurate for battery current, but for USB current around 70mA
  45. * per step was seen on Kobo Clara HD but all sources show the same formula
  46. * also fur USB current. To avoid accidentially unwanted high currents we stick
  47. * to that formula
  48. */
  49. #define TO_CUR_REG(x) ((x) / 100000 - 1)
  50. #define FROM_CUR_REG(x) ((((x) & 0x1f) + 1) * 100000)
  51. #define CHG_MIN_CUR 100000
  52. #define CHG_MAX_CUR 1800000
  53. #define ADP_MAX_CUR 2500000
  54. #define USB_MAX_CUR 1400000
  55. struct rn5t618_power_info {
  56. struct rn5t618 *rn5t618;
  57. struct platform_device *pdev;
  58. struct power_supply *battery;
  59. struct power_supply *usb;
  60. struct power_supply *adp;
  61. struct iio_channel *channel_vusb;
  62. struct iio_channel *channel_vadp;
  63. int irq;
  64. };
  65. static enum power_supply_property rn5t618_usb_props[] = {
  66. /* input current limit is not very accurate */
  67. POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
  68. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  69. POWER_SUPPLY_PROP_STATUS,
  70. POWER_SUPPLY_PROP_USB_TYPE,
  71. POWER_SUPPLY_PROP_ONLINE,
  72. };
  73. static enum power_supply_property rn5t618_adp_props[] = {
  74. /* input current limit is not very accurate */
  75. POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
  76. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  77. POWER_SUPPLY_PROP_STATUS,
  78. POWER_SUPPLY_PROP_ONLINE,
  79. };
  80. static enum power_supply_property rn5t618_battery_props[] = {
  81. POWER_SUPPLY_PROP_STATUS,
  82. POWER_SUPPLY_PROP_PRESENT,
  83. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  84. POWER_SUPPLY_PROP_CURRENT_NOW,
  85. POWER_SUPPLY_PROP_CAPACITY,
  86. POWER_SUPPLY_PROP_TEMP,
  87. POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
  88. POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
  89. POWER_SUPPLY_PROP_TECHNOLOGY,
  90. POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
  91. POWER_SUPPLY_PROP_CHARGE_FULL,
  92. POWER_SUPPLY_PROP_CHARGE_NOW,
  93. };
  94. static int rn5t618_battery_read_doublereg(struct rn5t618_power_info *info,
  95. u8 reg, u16 *result)
  96. {
  97. int ret, i;
  98. u8 data[2];
  99. u16 old, new;
  100. old = 0;
  101. /* Prevent races when registers are changing. */
  102. for (i = 0; i < 3; i++) {
  103. ret = regmap_bulk_read(info->rn5t618->regmap,
  104. reg, data, sizeof(data));
  105. if (ret)
  106. return ret;
  107. new = data[0] << 8;
  108. new |= data[1];
  109. if (new == old)
  110. break;
  111. old = new;
  112. }
  113. *result = new;
  114. return 0;
  115. }
  116. static int rn5t618_decode_status(unsigned int status)
  117. {
  118. switch (status & CHG_STATE_MASK) {
  119. case CHG_STATE_CHG_OFF:
  120. case CHG_STATE_SUSPEND:
  121. case CHG_STATE_VCHG_OVER_VOL:
  122. case CHG_STATE_DIE_SHUTDOWN:
  123. return POWER_SUPPLY_STATUS_DISCHARGING;
  124. case CHG_STATE_CHG_TRICKLE:
  125. case CHG_STATE_CHG_RAPID:
  126. return POWER_SUPPLY_STATUS_CHARGING;
  127. case CHG_STATE_CHG_COMPLETE:
  128. return POWER_SUPPLY_STATUS_FULL;
  129. default:
  130. return POWER_SUPPLY_STATUS_NOT_CHARGING;
  131. }
  132. }
  133. static int rn5t618_battery_status(struct rn5t618_power_info *info,
  134. union power_supply_propval *val)
  135. {
  136. unsigned int v;
  137. int ret;
  138. ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
  139. if (ret)
  140. return ret;
  141. val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
  142. if (v & 0xc0) { /* USB or ADP plugged */
  143. val->intval = rn5t618_decode_status(v);
  144. } else
  145. val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
  146. return ret;
  147. }
  148. static int rn5t618_battery_present(struct rn5t618_power_info *info,
  149. union power_supply_propval *val)
  150. {
  151. unsigned int v;
  152. int ret;
  153. ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &v);
  154. if (ret)
  155. return ret;
  156. v &= CHG_STATE_MASK;
  157. if ((v == CHG_STATE_NO_BAT) || (v == CHG_STATE_NO_BAT2))
  158. val->intval = 0;
  159. else
  160. val->intval = 1;
  161. return ret;
  162. }
  163. static int rn5t618_battery_voltage_now(struct rn5t618_power_info *info,
  164. union power_supply_propval *val)
  165. {
  166. u16 res;
  167. int ret;
  168. ret = rn5t618_battery_read_doublereg(info, RN5T618_VOLTAGE_1, &res);
  169. if (ret)
  170. return ret;
  171. val->intval = res * 2 * 2500 / 4095 * 1000;
  172. return 0;
  173. }
  174. static int rn5t618_battery_current_now(struct rn5t618_power_info *info,
  175. union power_supply_propval *val)
  176. {
  177. u16 res;
  178. int ret;
  179. ret = rn5t618_battery_read_doublereg(info, RN5T618_CC_AVEREG1, &res);
  180. if (ret)
  181. return ret;
  182. /* current is negative when discharging */
  183. val->intval = sign_extend32(res, 13) * 1000;
  184. return 0;
  185. }
  186. static int rn5t618_battery_capacity(struct rn5t618_power_info *info,
  187. union power_supply_propval *val)
  188. {
  189. unsigned int v;
  190. int ret;
  191. ret = regmap_read(info->rn5t618->regmap, RN5T618_SOC, &v);
  192. if (ret)
  193. return ret;
  194. val->intval = v;
  195. return 0;
  196. }
  197. static int rn5t618_battery_temp(struct rn5t618_power_info *info,
  198. union power_supply_propval *val)
  199. {
  200. u16 res;
  201. int ret;
  202. ret = rn5t618_battery_read_doublereg(info, RN5T618_TEMP_1, &res);
  203. if (ret)
  204. return ret;
  205. val->intval = sign_extend32(res, 11) * 10 / 16;
  206. return 0;
  207. }
  208. static int rn5t618_battery_tte(struct rn5t618_power_info *info,
  209. union power_supply_propval *val)
  210. {
  211. u16 res;
  212. int ret;
  213. ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_EMPTY_H, &res);
  214. if (ret)
  215. return ret;
  216. if (res == 65535)
  217. return -ENODATA;
  218. val->intval = res * 60;
  219. return 0;
  220. }
  221. static int rn5t618_battery_ttf(struct rn5t618_power_info *info,
  222. union power_supply_propval *val)
  223. {
  224. u16 res;
  225. int ret;
  226. ret = rn5t618_battery_read_doublereg(info, RN5T618_TT_FULL_H, &res);
  227. if (ret)
  228. return ret;
  229. if (res == 65535)
  230. return -ENODATA;
  231. val->intval = res * 60;
  232. return 0;
  233. }
  234. static int rn5t618_battery_set_current_limit(struct rn5t618_power_info *info,
  235. const union power_supply_propval *val)
  236. {
  237. if (val->intval < CHG_MIN_CUR)
  238. return -EINVAL;
  239. if (val->intval >= CHG_MAX_CUR)
  240. return -EINVAL;
  241. return regmap_update_bits(info->rn5t618->regmap,
  242. RN5T618_CHGISET,
  243. 0x1F, TO_CUR_REG(val->intval));
  244. }
  245. static int rn5t618_battery_get_current_limit(struct rn5t618_power_info *info,
  246. union power_supply_propval *val)
  247. {
  248. unsigned int regval;
  249. int ret;
  250. ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGISET,
  251. &regval);
  252. if (ret < 0)
  253. return ret;
  254. val->intval = FROM_CUR_REG(regval);
  255. return 0;
  256. }
  257. static int rn5t618_battery_charge_full(struct rn5t618_power_info *info,
  258. union power_supply_propval *val)
  259. {
  260. u16 res;
  261. int ret;
  262. ret = rn5t618_battery_read_doublereg(info, RN5T618_FA_CAP_H, &res);
  263. if (ret)
  264. return ret;
  265. val->intval = res * 1000;
  266. return 0;
  267. }
  268. static int rn5t618_battery_charge_now(struct rn5t618_power_info *info,
  269. union power_supply_propval *val)
  270. {
  271. u16 res;
  272. int ret;
  273. ret = rn5t618_battery_read_doublereg(info, RN5T618_RE_CAP_H, &res);
  274. if (ret)
  275. return ret;
  276. val->intval = res * 1000;
  277. return 0;
  278. }
  279. static int rn5t618_battery_get_property(struct power_supply *psy,
  280. enum power_supply_property psp,
  281. union power_supply_propval *val)
  282. {
  283. int ret = 0;
  284. struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
  285. switch (psp) {
  286. case POWER_SUPPLY_PROP_STATUS:
  287. ret = rn5t618_battery_status(info, val);
  288. break;
  289. case POWER_SUPPLY_PROP_PRESENT:
  290. ret = rn5t618_battery_present(info, val);
  291. break;
  292. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  293. ret = rn5t618_battery_voltage_now(info, val);
  294. break;
  295. case POWER_SUPPLY_PROP_CURRENT_NOW:
  296. ret = rn5t618_battery_current_now(info, val);
  297. break;
  298. case POWER_SUPPLY_PROP_CAPACITY:
  299. ret = rn5t618_battery_capacity(info, val);
  300. break;
  301. case POWER_SUPPLY_PROP_TEMP:
  302. ret = rn5t618_battery_temp(info, val);
  303. break;
  304. case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
  305. ret = rn5t618_battery_tte(info, val);
  306. break;
  307. case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
  308. ret = rn5t618_battery_ttf(info, val);
  309. break;
  310. case POWER_SUPPLY_PROP_TECHNOLOGY:
  311. val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
  312. break;
  313. case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
  314. ret = rn5t618_battery_get_current_limit(info, val);
  315. break;
  316. case POWER_SUPPLY_PROP_CHARGE_FULL:
  317. ret = rn5t618_battery_charge_full(info, val);
  318. break;
  319. case POWER_SUPPLY_PROP_CHARGE_NOW:
  320. ret = rn5t618_battery_charge_now(info, val);
  321. break;
  322. default:
  323. return -EINVAL;
  324. }
  325. return ret;
  326. }
  327. static int rn5t618_battery_set_property(struct power_supply *psy,
  328. enum power_supply_property psp,
  329. const union power_supply_propval *val)
  330. {
  331. struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
  332. switch (psp) {
  333. case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
  334. return rn5t618_battery_set_current_limit(info, val);
  335. default:
  336. return -EINVAL;
  337. }
  338. }
  339. static int rn5t618_battery_property_is_writeable(struct power_supply *psy,
  340. enum power_supply_property psp)
  341. {
  342. switch (psp) {
  343. case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
  344. return true;
  345. default:
  346. return false;
  347. }
  348. }
  349. static int rn5t618_adp_get_property(struct power_supply *psy,
  350. enum power_supply_property psp,
  351. union power_supply_propval *val)
  352. {
  353. struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
  354. unsigned int chgstate;
  355. unsigned int regval;
  356. bool online;
  357. int ret;
  358. ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
  359. if (ret)
  360. return ret;
  361. online = !!(chgstate & CHG_STATE_ADP_INPUT);
  362. switch (psp) {
  363. case POWER_SUPPLY_PROP_ONLINE:
  364. val->intval = online;
  365. break;
  366. case POWER_SUPPLY_PROP_STATUS:
  367. if (!online) {
  368. val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  369. break;
  370. }
  371. val->intval = rn5t618_decode_status(chgstate);
  372. if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
  373. val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  374. break;
  375. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  376. ret = regmap_read(info->rn5t618->regmap,
  377. RN5T618_REGISET1, &regval);
  378. if (ret < 0)
  379. return ret;
  380. val->intval = FROM_CUR_REG(regval);
  381. break;
  382. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  383. if (!info->channel_vadp)
  384. return -ENODATA;
  385. ret = iio_read_channel_processed_scale(info->channel_vadp, &val->intval, 1000);
  386. if (ret < 0)
  387. return ret;
  388. break;
  389. default:
  390. return -EINVAL;
  391. }
  392. return 0;
  393. }
  394. static int rn5t618_adp_set_property(struct power_supply *psy,
  395. enum power_supply_property psp,
  396. const union power_supply_propval *val)
  397. {
  398. struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
  399. int ret;
  400. switch (psp) {
  401. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  402. if (val->intval > ADP_MAX_CUR)
  403. return -EINVAL;
  404. if (val->intval < CHG_MIN_CUR)
  405. return -EINVAL;
  406. ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET1,
  407. TO_CUR_REG(val->intval));
  408. if (ret < 0)
  409. return ret;
  410. break;
  411. default:
  412. return -EINVAL;
  413. }
  414. return 0;
  415. }
  416. static int rn5t618_adp_property_is_writeable(struct power_supply *psy,
  417. enum power_supply_property psp)
  418. {
  419. switch (psp) {
  420. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  421. return true;
  422. default:
  423. return false;
  424. }
  425. }
  426. static int rc5t619_usb_get_type(struct rn5t618_power_info *info,
  427. union power_supply_propval *val)
  428. {
  429. unsigned int regval;
  430. int ret;
  431. ret = regmap_read(info->rn5t618->regmap, RN5T618_GCHGDET, &regval);
  432. if (ret < 0)
  433. return ret;
  434. switch (regval & GCHGDET_TYPE_MASK) {
  435. case GCHGDET_TYPE_SDP:
  436. val->intval = POWER_SUPPLY_USB_TYPE_SDP;
  437. break;
  438. case GCHGDET_TYPE_CDP:
  439. val->intval = POWER_SUPPLY_USB_TYPE_CDP;
  440. break;
  441. case GCHGDET_TYPE_DCP:
  442. val->intval = POWER_SUPPLY_USB_TYPE_DCP;
  443. break;
  444. default:
  445. val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
  446. }
  447. return 0;
  448. }
  449. static int rn5t618_usb_get_property(struct power_supply *psy,
  450. enum power_supply_property psp,
  451. union power_supply_propval *val)
  452. {
  453. struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
  454. unsigned int chgstate;
  455. unsigned int regval;
  456. bool online;
  457. int ret;
  458. ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGSTATE, &chgstate);
  459. if (ret)
  460. return ret;
  461. online = !!(chgstate & CHG_STATE_USB_INPUT);
  462. switch (psp) {
  463. case POWER_SUPPLY_PROP_ONLINE:
  464. val->intval = online;
  465. break;
  466. case POWER_SUPPLY_PROP_STATUS:
  467. if (!online) {
  468. val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  469. break;
  470. }
  471. val->intval = rn5t618_decode_status(chgstate);
  472. if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
  473. val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  474. break;
  475. case POWER_SUPPLY_PROP_USB_TYPE:
  476. if (!online || (info->rn5t618->variant != RC5T619))
  477. return -ENODATA;
  478. return rc5t619_usb_get_type(info, val);
  479. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  480. ret = regmap_read(info->rn5t618->regmap, RN5T618_CHGCTL1,
  481. &regval);
  482. if (ret < 0)
  483. return ret;
  484. val->intval = 0;
  485. if (regval & 2) {
  486. ret = regmap_read(info->rn5t618->regmap,
  487. RN5T618_REGISET2,
  488. &regval);
  489. if (ret < 0)
  490. return ret;
  491. val->intval = FROM_CUR_REG(regval);
  492. }
  493. break;
  494. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  495. if (!info->channel_vusb)
  496. return -ENODATA;
  497. ret = iio_read_channel_processed_scale(info->channel_vusb, &val->intval, 1000);
  498. if (ret < 0)
  499. return ret;
  500. break;
  501. default:
  502. return -EINVAL;
  503. }
  504. return 0;
  505. }
  506. static int rn5t618_usb_set_property(struct power_supply *psy,
  507. enum power_supply_property psp,
  508. const union power_supply_propval *val)
  509. {
  510. struct rn5t618_power_info *info = power_supply_get_drvdata(psy);
  511. int ret;
  512. switch (psp) {
  513. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  514. if (val->intval > USB_MAX_CUR)
  515. return -EINVAL;
  516. if (val->intval < CHG_MIN_CUR)
  517. return -EINVAL;
  518. ret = regmap_write(info->rn5t618->regmap, RN5T618_REGISET2,
  519. 0xE0 | TO_CUR_REG(val->intval));
  520. if (ret < 0)
  521. return ret;
  522. break;
  523. default:
  524. return -EINVAL;
  525. }
  526. return 0;
  527. }
  528. static int rn5t618_usb_property_is_writeable(struct power_supply *psy,
  529. enum power_supply_property psp)
  530. {
  531. switch (psp) {
  532. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  533. return true;
  534. default:
  535. return false;
  536. }
  537. }
  538. static const struct power_supply_desc rn5t618_battery_desc = {
  539. .name = "rn5t618-battery",
  540. .type = POWER_SUPPLY_TYPE_BATTERY,
  541. .properties = rn5t618_battery_props,
  542. .num_properties = ARRAY_SIZE(rn5t618_battery_props),
  543. .get_property = rn5t618_battery_get_property,
  544. .set_property = rn5t618_battery_set_property,
  545. .property_is_writeable = rn5t618_battery_property_is_writeable,
  546. };
  547. static const struct power_supply_desc rn5t618_adp_desc = {
  548. .name = "rn5t618-adp",
  549. .type = POWER_SUPPLY_TYPE_MAINS,
  550. .properties = rn5t618_adp_props,
  551. .num_properties = ARRAY_SIZE(rn5t618_adp_props),
  552. .get_property = rn5t618_adp_get_property,
  553. .set_property = rn5t618_adp_set_property,
  554. .property_is_writeable = rn5t618_adp_property_is_writeable,
  555. };
  556. static const struct power_supply_desc rn5t618_usb_desc = {
  557. .name = "rn5t618-usb",
  558. .type = POWER_SUPPLY_TYPE_USB,
  559. .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |
  560. BIT(POWER_SUPPLY_USB_TYPE_CDP) |
  561. BIT(POWER_SUPPLY_USB_TYPE_DCP) |
  562. BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
  563. .properties = rn5t618_usb_props,
  564. .num_properties = ARRAY_SIZE(rn5t618_usb_props),
  565. .get_property = rn5t618_usb_get_property,
  566. .set_property = rn5t618_usb_set_property,
  567. .property_is_writeable = rn5t618_usb_property_is_writeable,
  568. };
  569. static irqreturn_t rn5t618_charger_irq(int irq, void *data)
  570. {
  571. struct device *dev = data;
  572. struct rn5t618_power_info *info = dev_get_drvdata(dev);
  573. unsigned int ctrl, stat1, stat2, err;
  574. regmap_read(info->rn5t618->regmap, RN5T618_CHGERR_IRR, &err);
  575. regmap_read(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, &ctrl);
  576. regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, &stat1);
  577. regmap_read(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, &stat2);
  578. regmap_write(info->rn5t618->regmap, RN5T618_CHGERR_IRR, 0);
  579. regmap_write(info->rn5t618->regmap, RN5T618_CHGCTRL_IRR, 0);
  580. regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR1, 0);
  581. regmap_write(info->rn5t618->regmap, RN5T618_CHGSTAT_IRR2, 0);
  582. dev_dbg(dev, "chgerr: %x chgctrl: %x chgstat: %x chgstat2: %x\n",
  583. err, ctrl, stat1, stat2);
  584. power_supply_changed(info->usb);
  585. power_supply_changed(info->adp);
  586. power_supply_changed(info->battery);
  587. return IRQ_HANDLED;
  588. }
  589. static int rn5t618_power_probe(struct platform_device *pdev)
  590. {
  591. int ret = 0;
  592. unsigned int v;
  593. struct power_supply_config psy_cfg = {};
  594. struct rn5t618_power_info *info;
  595. info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
  596. if (!info)
  597. return -ENOMEM;
  598. info->pdev = pdev;
  599. info->rn5t618 = dev_get_drvdata(pdev->dev.parent);
  600. info->irq = -1;
  601. platform_set_drvdata(pdev, info);
  602. info->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb");
  603. if (IS_ERR(info->channel_vusb)) {
  604. if (PTR_ERR(info->channel_vusb) == -ENODEV)
  605. return -EPROBE_DEFER;
  606. return PTR_ERR(info->channel_vusb);
  607. }
  608. info->channel_vadp = devm_iio_channel_get(&pdev->dev, "vadp");
  609. if (IS_ERR(info->channel_vadp)) {
  610. if (PTR_ERR(info->channel_vadp) == -ENODEV)
  611. return -EPROBE_DEFER;
  612. return PTR_ERR(info->channel_vadp);
  613. }
  614. ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v);
  615. if (ret)
  616. return ret;
  617. if (!(v & FG_ENABLE)) {
  618. /* E.g. the vendor kernels of various Kobo and Tolino Ebook
  619. * readers disable the fuel gauge on shutdown. If a kernel
  620. * without fuel gauge support is booted after that, the fuel
  621. * gauge will get decalibrated.
  622. */
  623. dev_info(&pdev->dev, "Fuel gauge not enabled, enabling now\n");
  624. dev_info(&pdev->dev, "Expect imprecise results\n");
  625. regmap_update_bits(info->rn5t618->regmap, RN5T618_CONTROL,
  626. FG_ENABLE, FG_ENABLE);
  627. }
  628. psy_cfg.drv_data = info;
  629. info->battery = devm_power_supply_register(&pdev->dev,
  630. &rn5t618_battery_desc,
  631. &psy_cfg);
  632. if (IS_ERR(info->battery)) {
  633. ret = PTR_ERR(info->battery);
  634. dev_err(&pdev->dev, "failed to register battery: %d\n", ret);
  635. return ret;
  636. }
  637. info->adp = devm_power_supply_register(&pdev->dev,
  638. &rn5t618_adp_desc,
  639. &psy_cfg);
  640. if (IS_ERR(info->adp)) {
  641. ret = PTR_ERR(info->adp);
  642. dev_err(&pdev->dev, "failed to register adp: %d\n", ret);
  643. return ret;
  644. }
  645. info->usb = devm_power_supply_register(&pdev->dev,
  646. &rn5t618_usb_desc,
  647. &psy_cfg);
  648. if (IS_ERR(info->usb)) {
  649. ret = PTR_ERR(info->usb);
  650. dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
  651. return ret;
  652. }
  653. if (info->rn5t618->irq_data)
  654. info->irq = regmap_irq_get_virq(info->rn5t618->irq_data,
  655. RN5T618_IRQ_CHG);
  656. if (info->irq < 0)
  657. info->irq = -1;
  658. else {
  659. ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
  660. rn5t618_charger_irq,
  661. IRQF_ONESHOT,
  662. "rn5t618_power",
  663. &pdev->dev);
  664. if (ret < 0) {
  665. dev_err(&pdev->dev, "request IRQ:%d fail\n",
  666. info->irq);
  667. info->irq = -1;
  668. }
  669. }
  670. return 0;
  671. }
  672. static struct platform_driver rn5t618_power_driver = {
  673. .driver = {
  674. .name = "rn5t618-power",
  675. },
  676. .probe = rn5t618_power_probe,
  677. };
  678. module_platform_driver(rn5t618_power_driver);
  679. MODULE_ALIAS("platform:rn5t618-power");
  680. MODULE_DESCRIPTION("Power supply driver for RICOH RN5T618");
  681. MODULE_LICENSE("GPL");