mp2629_charger.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * MP2629 battery charger driver
  4. *
  5. * Copyright 2020 Monolithic Power Systems, Inc
  6. *
  7. * Author: Saravanan Sekar <sravanhome@gmail.com>
  8. */
  9. #include <linux/bits.h>
  10. #include <linux/iio/consumer.h>
  11. #include <linux/iio/types.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/mfd/mp2629.h>
  14. #include <linux/module.h>
  15. #include <linux/mod_devicetable.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/power_supply.h>
  18. #include <linux/regmap.h>
  19. #define MP2629_REG_INPUT_ILIM 0x00
  20. #define MP2629_REG_INPUT_VLIM 0x01
  21. #define MP2629_REG_CHARGE_CTRL 0x04
  22. #define MP2629_REG_CHARGE_ILIM 0x05
  23. #define MP2629_REG_PRECHARGE 0x06
  24. #define MP2629_REG_TERM_CURRENT 0x06
  25. #define MP2629_REG_CHARGE_VLIM 0x07
  26. #define MP2629_REG_TIMER_CTRL 0x08
  27. #define MP2629_REG_IMPEDANCE_COMP 0x09
  28. #define MP2629_REG_INTERRUPT 0x0b
  29. #define MP2629_REG_STATUS 0x0c
  30. #define MP2629_REG_FAULT 0x0d
  31. #define MP2629_MASK_INPUT_TYPE GENMASK(7, 5)
  32. #define MP2629_MASK_CHARGE_TYPE GENMASK(4, 3)
  33. #define MP2629_MASK_CHARGE_CTRL GENMASK(5, 4)
  34. #define MP2629_MASK_WDOG_CTRL GENMASK(5, 4)
  35. #define MP2629_MASK_IMPEDANCE GENMASK(7, 4)
  36. #define MP2629_INPUTSOURCE_CHANGE GENMASK(7, 5)
  37. #define MP2629_CHARGING_CHANGE GENMASK(4, 3)
  38. #define MP2629_FAULT_BATTERY BIT(3)
  39. #define MP2629_FAULT_THERMAL BIT(4)
  40. #define MP2629_FAULT_INPUT BIT(5)
  41. #define MP2629_FAULT_OTG BIT(6)
  42. #define MP2629_MAX_BATT_CAPACITY 100
  43. #define MP2629_PROPS(_idx, _min, _max, _step) \
  44. [_idx] = { \
  45. .min = _min, \
  46. .max = _max, \
  47. .step = _step, \
  48. }
  49. enum mp2629_source_type {
  50. MP2629_SOURCE_TYPE_NO_INPUT,
  51. MP2629_SOURCE_TYPE_NON_STD,
  52. MP2629_SOURCE_TYPE_SDP,
  53. MP2629_SOURCE_TYPE_CDP,
  54. MP2629_SOURCE_TYPE_DCP,
  55. MP2629_SOURCE_TYPE_OTG = 7,
  56. };
  57. enum mp2629_field {
  58. INPUT_ILIM,
  59. INPUT_VLIM,
  60. CHARGE_ILIM,
  61. CHARGE_VLIM,
  62. PRECHARGE,
  63. TERM_CURRENT,
  64. MP2629_MAX_FIELD
  65. };
  66. struct mp2629_charger {
  67. struct device *dev;
  68. int status;
  69. int fault;
  70. struct regmap *regmap;
  71. struct regmap_field *regmap_fields[MP2629_MAX_FIELD];
  72. struct mutex lock;
  73. struct power_supply *usb;
  74. struct power_supply *battery;
  75. struct iio_channel *iiochan[MP2629_ADC_CHAN_END];
  76. };
  77. struct mp2629_prop {
  78. int reg;
  79. int mask;
  80. int min;
  81. int max;
  82. int step;
  83. int shift;
  84. };
  85. static enum power_supply_property mp2629_charger_usb_props[] = {
  86. POWER_SUPPLY_PROP_ONLINE,
  87. POWER_SUPPLY_PROP_USB_TYPE,
  88. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  89. POWER_SUPPLY_PROP_CURRENT_NOW,
  90. POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
  91. POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
  92. };
  93. static enum power_supply_property mp2629_charger_bat_props[] = {
  94. POWER_SUPPLY_PROP_STATUS,
  95. POWER_SUPPLY_PROP_HEALTH,
  96. POWER_SUPPLY_PROP_CHARGE_TYPE,
  97. POWER_SUPPLY_PROP_VOLTAGE_NOW,
  98. POWER_SUPPLY_PROP_CURRENT_NOW,
  99. POWER_SUPPLY_PROP_CAPACITY,
  100. POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
  101. POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
  102. POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
  103. POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
  104. POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
  105. POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
  106. };
  107. static struct mp2629_prop props[] = {
  108. MP2629_PROPS(INPUT_ILIM, 100000, 3250000, 50000),
  109. MP2629_PROPS(INPUT_VLIM, 3800000, 5300000, 100000),
  110. MP2629_PROPS(CHARGE_ILIM, 320000, 4520000, 40000),
  111. MP2629_PROPS(CHARGE_VLIM, 3400000, 4670000, 10000),
  112. MP2629_PROPS(PRECHARGE, 120000, 720000, 40000),
  113. MP2629_PROPS(TERM_CURRENT, 80000, 680000, 40000),
  114. };
  115. static const struct reg_field mp2629_reg_fields[] = {
  116. [INPUT_ILIM] = REG_FIELD(MP2629_REG_INPUT_ILIM, 0, 5),
  117. [INPUT_VLIM] = REG_FIELD(MP2629_REG_INPUT_VLIM, 0, 3),
  118. [CHARGE_ILIM] = REG_FIELD(MP2629_REG_CHARGE_ILIM, 0, 6),
  119. [CHARGE_VLIM] = REG_FIELD(MP2629_REG_CHARGE_VLIM, 1, 7),
  120. [PRECHARGE] = REG_FIELD(MP2629_REG_PRECHARGE, 4, 7),
  121. [TERM_CURRENT] = REG_FIELD(MP2629_REG_TERM_CURRENT, 0, 3),
  122. };
  123. static char *adc_chan_name[] = {
  124. "mp2629-batt-volt",
  125. "mp2629-system-volt",
  126. "mp2629-input-volt",
  127. "mp2629-batt-current",
  128. "mp2629-input-current",
  129. };
  130. static int mp2629_read_adc(struct mp2629_charger *charger,
  131. enum mp2629_adc_chan ch,
  132. union power_supply_propval *val)
  133. {
  134. int ret;
  135. int chval;
  136. ret = iio_read_channel_processed(charger->iiochan[ch], &chval);
  137. if (ret)
  138. return ret;
  139. val->intval = chval * 1000;
  140. return 0;
  141. }
  142. static int mp2629_get_prop(struct mp2629_charger *charger,
  143. enum mp2629_field fld,
  144. union power_supply_propval *val)
  145. {
  146. int ret;
  147. unsigned int rval;
  148. ret = regmap_field_read(charger->regmap_fields[fld], &rval);
  149. if (ret)
  150. return ret;
  151. val->intval = rval * props[fld].step + props[fld].min;
  152. return 0;
  153. }
  154. static int mp2629_set_prop(struct mp2629_charger *charger,
  155. enum mp2629_field fld,
  156. const union power_supply_propval *val)
  157. {
  158. unsigned int rval;
  159. if (val->intval < props[fld].min || val->intval > props[fld].max)
  160. return -EINVAL;
  161. rval = (val->intval - props[fld].min) / props[fld].step;
  162. return regmap_field_write(charger->regmap_fields[fld], rval);
  163. }
  164. static int mp2629_get_battery_capacity(struct mp2629_charger *charger,
  165. union power_supply_propval *val)
  166. {
  167. union power_supply_propval vnow, vlim;
  168. int ret;
  169. ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, &vnow);
  170. if (ret)
  171. return ret;
  172. ret = mp2629_get_prop(charger, CHARGE_VLIM, &vlim);
  173. if (ret)
  174. return ret;
  175. val->intval = (vnow.intval * 100) / vlim.intval;
  176. val->intval = min(val->intval, MP2629_MAX_BATT_CAPACITY);
  177. return 0;
  178. }
  179. static int mp2629_charger_battery_get_prop(struct power_supply *psy,
  180. enum power_supply_property psp,
  181. union power_supply_propval *val)
  182. {
  183. struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
  184. unsigned int rval;
  185. int ret = 0;
  186. switch (psp) {
  187. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  188. ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, val);
  189. break;
  190. case POWER_SUPPLY_PROP_CURRENT_NOW:
  191. ret = mp2629_read_adc(charger, MP2629_BATT_CURRENT, val);
  192. break;
  193. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
  194. val->intval = 4520000;
  195. break;
  196. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
  197. val->intval = 4670000;
  198. break;
  199. case POWER_SUPPLY_PROP_CAPACITY:
  200. ret = mp2629_get_battery_capacity(charger, val);
  201. break;
  202. case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
  203. ret = mp2629_get_prop(charger, TERM_CURRENT, val);
  204. break;
  205. case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
  206. ret = mp2629_get_prop(charger, PRECHARGE, val);
  207. break;
  208. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
  209. ret = mp2629_get_prop(charger, CHARGE_VLIM, val);
  210. break;
  211. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
  212. ret = mp2629_get_prop(charger, CHARGE_ILIM, val);
  213. break;
  214. case POWER_SUPPLY_PROP_HEALTH:
  215. if (!charger->fault)
  216. val->intval = POWER_SUPPLY_HEALTH_GOOD;
  217. if (MP2629_FAULT_BATTERY & charger->fault)
  218. val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
  219. else if (MP2629_FAULT_THERMAL & charger->fault)
  220. val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
  221. else if (MP2629_FAULT_INPUT & charger->fault)
  222. val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
  223. break;
  224. case POWER_SUPPLY_PROP_STATUS:
  225. ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
  226. if (ret)
  227. break;
  228. rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
  229. switch (rval) {
  230. case 0x00:
  231. val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
  232. break;
  233. case 0x01:
  234. case 0x10:
  235. val->intval = POWER_SUPPLY_STATUS_CHARGING;
  236. break;
  237. case 0x11:
  238. val->intval = POWER_SUPPLY_STATUS_FULL;
  239. }
  240. break;
  241. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  242. ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
  243. if (ret)
  244. break;
  245. rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
  246. switch (rval) {
  247. case 0x00:
  248. val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
  249. break;
  250. case 0x01:
  251. val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
  252. break;
  253. case 0x10:
  254. val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
  255. break;
  256. default:
  257. val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
  258. }
  259. break;
  260. default:
  261. return -EINVAL;
  262. }
  263. return ret;
  264. }
  265. static int mp2629_charger_battery_set_prop(struct power_supply *psy,
  266. enum power_supply_property psp,
  267. const union power_supply_propval *val)
  268. {
  269. struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
  270. switch (psp) {
  271. case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
  272. return mp2629_set_prop(charger, TERM_CURRENT, val);
  273. case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
  274. return mp2629_set_prop(charger, PRECHARGE, val);
  275. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
  276. return mp2629_set_prop(charger, CHARGE_VLIM, val);
  277. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
  278. return mp2629_set_prop(charger, CHARGE_ILIM, val);
  279. default:
  280. return -EINVAL;
  281. }
  282. }
  283. static int mp2629_charger_usb_get_prop(struct power_supply *psy,
  284. enum power_supply_property psp,
  285. union power_supply_propval *val)
  286. {
  287. struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
  288. unsigned int rval;
  289. int ret;
  290. switch (psp) {
  291. case POWER_SUPPLY_PROP_ONLINE:
  292. ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
  293. if (ret)
  294. break;
  295. val->intval = !!(rval & MP2629_MASK_INPUT_TYPE);
  296. break;
  297. case POWER_SUPPLY_PROP_USB_TYPE:
  298. ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
  299. if (ret)
  300. break;
  301. rval = (rval & MP2629_MASK_INPUT_TYPE) >> 5;
  302. switch (rval) {
  303. case MP2629_SOURCE_TYPE_SDP:
  304. val->intval = POWER_SUPPLY_USB_TYPE_SDP;
  305. break;
  306. case MP2629_SOURCE_TYPE_CDP:
  307. val->intval = POWER_SUPPLY_USB_TYPE_CDP;
  308. break;
  309. case MP2629_SOURCE_TYPE_DCP:
  310. val->intval = POWER_SUPPLY_USB_TYPE_DCP;
  311. break;
  312. case MP2629_SOURCE_TYPE_OTG:
  313. val->intval = POWER_SUPPLY_USB_TYPE_PD_DRP;
  314. break;
  315. default:
  316. val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
  317. break;
  318. }
  319. break;
  320. case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  321. ret = mp2629_read_adc(charger, MP2629_INPUT_VOLT, val);
  322. break;
  323. case POWER_SUPPLY_PROP_CURRENT_NOW:
  324. ret = mp2629_read_adc(charger, MP2629_INPUT_CURRENT, val);
  325. break;
  326. case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
  327. ret = mp2629_get_prop(charger, INPUT_VLIM, val);
  328. break;
  329. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  330. ret = mp2629_get_prop(charger, INPUT_ILIM, val);
  331. break;
  332. default:
  333. return -EINVAL;
  334. }
  335. return ret;
  336. }
  337. static int mp2629_charger_usb_set_prop(struct power_supply *psy,
  338. enum power_supply_property psp,
  339. const union power_supply_propval *val)
  340. {
  341. struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
  342. switch (psp) {
  343. case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
  344. return mp2629_set_prop(charger, INPUT_VLIM, val);
  345. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  346. return mp2629_set_prop(charger, INPUT_ILIM, val);
  347. default:
  348. return -EINVAL;
  349. }
  350. }
  351. static int mp2629_charger_battery_prop_writeable(struct power_supply *psy,
  352. enum power_supply_property psp)
  353. {
  354. return (psp == POWER_SUPPLY_PROP_PRECHARGE_CURRENT) ||
  355. (psp == POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT) ||
  356. (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT) ||
  357. (psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE);
  358. }
  359. static int mp2629_charger_usb_prop_writeable(struct power_supply *psy,
  360. enum power_supply_property psp)
  361. {
  362. return (psp == POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT) ||
  363. (psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT);
  364. }
  365. static irqreturn_t mp2629_irq_handler(int irq, void *dev_id)
  366. {
  367. struct mp2629_charger *charger = dev_id;
  368. unsigned int rval;
  369. int ret;
  370. mutex_lock(&charger->lock);
  371. ret = regmap_read(charger->regmap, MP2629_REG_FAULT, &rval);
  372. if (ret)
  373. goto unlock;
  374. if (rval) {
  375. charger->fault = rval;
  376. if (MP2629_FAULT_BATTERY & rval)
  377. dev_err(charger->dev, "Battery fault OVP\n");
  378. else if (MP2629_FAULT_THERMAL & rval)
  379. dev_err(charger->dev, "Thermal shutdown fault\n");
  380. else if (MP2629_FAULT_INPUT & rval)
  381. dev_err(charger->dev, "no input or input OVP\n");
  382. else if (MP2629_FAULT_OTG & rval)
  383. dev_err(charger->dev, "VIN overloaded\n");
  384. goto unlock;
  385. }
  386. ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
  387. if (ret)
  388. goto unlock;
  389. if (rval & MP2629_INPUTSOURCE_CHANGE)
  390. power_supply_changed(charger->usb);
  391. else if (rval & MP2629_CHARGING_CHANGE)
  392. power_supply_changed(charger->battery);
  393. unlock:
  394. mutex_unlock(&charger->lock);
  395. return IRQ_HANDLED;
  396. }
  397. static const struct power_supply_desc mp2629_usb_desc = {
  398. .name = "mp2629_usb",
  399. .type = POWER_SUPPLY_TYPE_USB,
  400. .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |
  401. BIT(POWER_SUPPLY_USB_TYPE_CDP) |
  402. BIT(POWER_SUPPLY_USB_TYPE_DCP) |
  403. BIT(POWER_SUPPLY_USB_TYPE_PD_DRP) |
  404. BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
  405. .properties = mp2629_charger_usb_props,
  406. .num_properties = ARRAY_SIZE(mp2629_charger_usb_props),
  407. .get_property = mp2629_charger_usb_get_prop,
  408. .set_property = mp2629_charger_usb_set_prop,
  409. .property_is_writeable = mp2629_charger_usb_prop_writeable,
  410. };
  411. static const struct power_supply_desc mp2629_battery_desc = {
  412. .name = "mp2629_battery",
  413. .type = POWER_SUPPLY_TYPE_BATTERY,
  414. .properties = mp2629_charger_bat_props,
  415. .num_properties = ARRAY_SIZE(mp2629_charger_bat_props),
  416. .get_property = mp2629_charger_battery_get_prop,
  417. .set_property = mp2629_charger_battery_set_prop,
  418. .property_is_writeable = mp2629_charger_battery_prop_writeable,
  419. };
  420. static ssize_t batt_impedance_compensation_show(struct device *dev,
  421. struct device_attribute *attr,
  422. char *buf)
  423. {
  424. struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
  425. unsigned int rval;
  426. int ret;
  427. ret = regmap_read(charger->regmap, MP2629_REG_IMPEDANCE_COMP, &rval);
  428. if (ret)
  429. return ret;
  430. rval = (rval >> 4) * 10;
  431. return sysfs_emit(buf, "%d mohm\n", rval);
  432. }
  433. static ssize_t batt_impedance_compensation_store(struct device *dev,
  434. struct device_attribute *attr,
  435. const char *buf,
  436. size_t count)
  437. {
  438. struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
  439. unsigned int val;
  440. int ret;
  441. ret = kstrtouint(buf, 10, &val);
  442. if (ret)
  443. return ret;
  444. if (val > 140)
  445. return -ERANGE;
  446. /* multiples of 10 mohm so round off */
  447. val = val / 10;
  448. ret = regmap_update_bits(charger->regmap, MP2629_REG_IMPEDANCE_COMP,
  449. MP2629_MASK_IMPEDANCE, val << 4);
  450. if (ret)
  451. return ret;
  452. return count;
  453. }
  454. static DEVICE_ATTR_RW(batt_impedance_compensation);
  455. static struct attribute *mp2629_charger_sysfs_attrs[] = {
  456. &dev_attr_batt_impedance_compensation.attr,
  457. NULL
  458. };
  459. ATTRIBUTE_GROUPS(mp2629_charger_sysfs);
  460. static void mp2629_charger_disable(void *data)
  461. {
  462. struct mp2629_charger *charger = data;
  463. regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
  464. MP2629_MASK_CHARGE_CTRL, 0);
  465. }
  466. static int mp2629_charger_probe(struct platform_device *pdev)
  467. {
  468. struct device *dev = &pdev->dev;
  469. struct mp2629_data *ddata = dev_get_drvdata(dev->parent);
  470. struct mp2629_charger *charger;
  471. struct power_supply_config psy_cfg = {};
  472. int ret, i, irq;
  473. charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL);
  474. if (!charger)
  475. return -ENOMEM;
  476. charger->regmap = ddata->regmap;
  477. charger->dev = dev;
  478. platform_set_drvdata(pdev, charger);
  479. irq = platform_get_irq(to_platform_device(dev->parent), 0);
  480. if (irq < 0)
  481. return irq;
  482. for (i = 0; i < MP2629_MAX_FIELD; i++) {
  483. charger->regmap_fields[i] = devm_regmap_field_alloc(dev,
  484. charger->regmap, mp2629_reg_fields[i]);
  485. if (IS_ERR(charger->regmap_fields[i])) {
  486. dev_err(dev, "regmap field alloc fail %d\n", i);
  487. return PTR_ERR(charger->regmap_fields[i]);
  488. }
  489. }
  490. for (i = 0; i < MP2629_ADC_CHAN_END; i++) {
  491. charger->iiochan[i] = devm_iio_channel_get(dev,
  492. adc_chan_name[i]);
  493. if (IS_ERR(charger->iiochan[i])) {
  494. dev_err(dev, "iio chan get %s err\n", adc_chan_name[i]);
  495. return PTR_ERR(charger->iiochan[i]);
  496. }
  497. }
  498. ret = devm_add_action_or_reset(dev, mp2629_charger_disable, charger);
  499. if (ret)
  500. return ret;
  501. charger->usb = devm_power_supply_register(dev, &mp2629_usb_desc, NULL);
  502. if (IS_ERR(charger->usb)) {
  503. dev_err(dev, "power supply register usb failed\n");
  504. return PTR_ERR(charger->usb);
  505. }
  506. psy_cfg.drv_data = charger;
  507. psy_cfg.attr_grp = mp2629_charger_sysfs_groups;
  508. charger->battery = devm_power_supply_register(dev,
  509. &mp2629_battery_desc, &psy_cfg);
  510. if (IS_ERR(charger->battery)) {
  511. dev_err(dev, "power supply register battery failed\n");
  512. return PTR_ERR(charger->battery);
  513. }
  514. ret = regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
  515. MP2629_MASK_CHARGE_CTRL, BIT(4));
  516. if (ret) {
  517. dev_err(dev, "enable charge fail: %d\n", ret);
  518. return ret;
  519. }
  520. regmap_update_bits(charger->regmap, MP2629_REG_TIMER_CTRL,
  521. MP2629_MASK_WDOG_CTRL, 0);
  522. mutex_init(&charger->lock);
  523. ret = devm_request_threaded_irq(dev, irq, NULL, mp2629_irq_handler,
  524. IRQF_ONESHOT | IRQF_TRIGGER_RISING,
  525. "mp2629-charger", charger);
  526. if (ret) {
  527. dev_err(dev, "failed to request gpio IRQ\n");
  528. return ret;
  529. }
  530. regmap_update_bits(charger->regmap, MP2629_REG_INTERRUPT,
  531. GENMASK(6, 5), BIT(6) | BIT(5));
  532. return 0;
  533. }
  534. static const struct of_device_id mp2629_charger_of_match[] = {
  535. { .compatible = "mps,mp2629_charger"},
  536. {}
  537. };
  538. MODULE_DEVICE_TABLE(of, mp2629_charger_of_match);
  539. static struct platform_driver mp2629_charger_driver = {
  540. .driver = {
  541. .name = "mp2629_charger",
  542. .of_match_table = mp2629_charger_of_match,
  543. },
  544. .probe = mp2629_charger_probe,
  545. };
  546. module_platform_driver(mp2629_charger_driver);
  547. MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
  548. MODULE_DESCRIPTION("MP2629 Charger driver");
  549. MODULE_LICENSE("GPL");