max77650-charger.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Copyright (C) 2018 BayLibre SAS
  4. // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
  5. //
  6. // Battery charger driver for MAXIM 77650/77651 charger/power-supply.
  7. #include <linux/i2c.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/mfd/max77650.h>
  10. #include <linux/module.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/power_supply.h>
  13. #include <linux/regmap.h>
  14. #define MAX77650_CHARGER_ENABLED BIT(0)
  15. #define MAX77650_CHARGER_DISABLED 0x00
  16. #define MAX77650_CHARGER_CHG_EN_MASK BIT(0)
  17. #define MAX77650_CHG_DETAILS_MASK GENMASK(7, 4)
  18. #define MAX77650_CHG_DETAILS_BITS(_reg) \
  19. (((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4)
  20. /* Charger is OFF. */
  21. #define MAX77650_CHG_OFF 0x00
  22. /* Charger is in prequalification mode. */
  23. #define MAX77650_CHG_PREQ 0x01
  24. /* Charger is in fast-charge constant current mode. */
  25. #define MAX77650_CHG_ON_CURR 0x02
  26. /* Charger is in JEITA modified fast-charge constant-current mode. */
  27. #define MAX77650_CHG_ON_CURR_JEITA 0x03
  28. /* Charger is in fast-charge constant-voltage mode. */
  29. #define MAX77650_CHG_ON_VOLT 0x04
  30. /* Charger is in JEITA modified fast-charge constant-voltage mode. */
  31. #define MAX77650_CHG_ON_VOLT_JEITA 0x05
  32. /* Charger is in top-off mode. */
  33. #define MAX77650_CHG_ON_TOPOFF 0x06
  34. /* Charger is in JEITA modified top-off mode. */
  35. #define MAX77650_CHG_ON_TOPOFF_JEITA 0x07
  36. /* Charger is done. */
  37. #define MAX77650_CHG_DONE 0x08
  38. /* Charger is JEITA modified done. */
  39. #define MAX77650_CHG_DONE_JEITA 0x09
  40. /* Charger is suspended due to a prequalification timer fault. */
  41. #define MAX77650_CHG_SUSP_PREQ_TIM_FAULT 0x0a
  42. /* Charger is suspended due to a fast-charge timer fault. */
  43. #define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT 0x0b
  44. /* Charger is suspended due to a battery temperature fault. */
  45. #define MAX77650_CHG_SUSP_BATT_TEMP_FAULT 0x0c
  46. #define MAX77650_CHGIN_DETAILS_MASK GENMASK(3, 2)
  47. #define MAX77650_CHGIN_DETAILS_BITS(_reg) \
  48. (((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2)
  49. #define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT 0x00
  50. #define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT 0x01
  51. #define MAX77650_CHGIN_OKAY 0x11
  52. #define MAX77650_CHARGER_CHG_MASK BIT(1)
  53. #define MAX77650_CHARGER_CHG_CHARGING(_reg) \
  54. (((_reg) & MAX77650_CHARGER_CHG_MASK) > 1)
  55. #define MAX77650_CHARGER_VCHGIN_MIN_MASK 0xc0
  56. #define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val) ((_val) << 5)
  57. #define MAX77650_CHARGER_ICHGIN_LIM_MASK 0x1c
  58. #define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val) ((_val) << 2)
  59. struct max77650_charger_data {
  60. struct regmap *map;
  61. struct device *dev;
  62. };
  63. static enum power_supply_property max77650_charger_properties[] = {
  64. POWER_SUPPLY_PROP_STATUS,
  65. POWER_SUPPLY_PROP_ONLINE,
  66. POWER_SUPPLY_PROP_CHARGE_TYPE
  67. };
  68. static const unsigned int max77650_charger_vchgin_min_table[] = {
  69. 4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000
  70. };
  71. static const unsigned int max77650_charger_ichgin_lim_table[] = {
  72. 95000, 190000, 285000, 380000, 475000
  73. };
  74. static int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg,
  75. unsigned int val)
  76. {
  77. int i, rv;
  78. for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) {
  79. if (val == max77650_charger_vchgin_min_table[i]) {
  80. rv = regmap_update_bits(chg->map,
  81. MAX77650_REG_CNFG_CHG_B,
  82. MAX77650_CHARGER_VCHGIN_MIN_MASK,
  83. MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i));
  84. if (rv)
  85. return rv;
  86. return 0;
  87. }
  88. }
  89. return -EINVAL;
  90. }
  91. static int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg,
  92. unsigned int val)
  93. {
  94. int i, rv;
  95. for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) {
  96. if (val == max77650_charger_ichgin_lim_table[i]) {
  97. rv = regmap_update_bits(chg->map,
  98. MAX77650_REG_CNFG_CHG_B,
  99. MAX77650_CHARGER_ICHGIN_LIM_MASK,
  100. MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i));
  101. if (rv)
  102. return rv;
  103. return 0;
  104. }
  105. }
  106. return -EINVAL;
  107. }
  108. static int max77650_charger_enable(struct max77650_charger_data *chg)
  109. {
  110. int rv;
  111. rv = regmap_update_bits(chg->map,
  112. MAX77650_REG_CNFG_CHG_B,
  113. MAX77650_CHARGER_CHG_EN_MASK,
  114. MAX77650_CHARGER_ENABLED);
  115. if (rv)
  116. dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
  117. return rv;
  118. }
  119. static int max77650_charger_disable(struct max77650_charger_data *chg)
  120. {
  121. int rv;
  122. rv = regmap_update_bits(chg->map,
  123. MAX77650_REG_CNFG_CHG_B,
  124. MAX77650_CHARGER_CHG_EN_MASK,
  125. MAX77650_CHARGER_DISABLED);
  126. if (rv)
  127. dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
  128. return rv;
  129. }
  130. static irqreturn_t max77650_charger_check_status(int irq, void *data)
  131. {
  132. struct max77650_charger_data *chg = data;
  133. int rv, reg;
  134. rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
  135. if (rv) {
  136. dev_err(chg->dev,
  137. "unable to read the charger status: %d\n", rv);
  138. return IRQ_HANDLED;
  139. }
  140. switch (MAX77650_CHGIN_DETAILS_BITS(reg)) {
  141. case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT:
  142. dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n");
  143. max77650_charger_disable(chg);
  144. break;
  145. case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT:
  146. dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n");
  147. max77650_charger_disable(chg);
  148. break;
  149. case MAX77650_CHGIN_OKAY:
  150. max77650_charger_enable(chg);
  151. break;
  152. default:
  153. /* May be 0x10 - debouncing */
  154. break;
  155. }
  156. return IRQ_HANDLED;
  157. }
  158. static int max77650_charger_get_property(struct power_supply *psy,
  159. enum power_supply_property psp,
  160. union power_supply_propval *val)
  161. {
  162. struct max77650_charger_data *chg = power_supply_get_drvdata(psy);
  163. int rv, reg;
  164. switch (psp) {
  165. case POWER_SUPPLY_PROP_STATUS:
  166. rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
  167. if (rv)
  168. return rv;
  169. if (MAX77650_CHARGER_CHG_CHARGING(reg)) {
  170. val->intval = POWER_SUPPLY_STATUS_CHARGING;
  171. break;
  172. }
  173. switch (MAX77650_CHG_DETAILS_BITS(reg)) {
  174. case MAX77650_CHG_OFF:
  175. case MAX77650_CHG_SUSP_PREQ_TIM_FAULT:
  176. case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT:
  177. case MAX77650_CHG_SUSP_BATT_TEMP_FAULT:
  178. val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  179. break;
  180. case MAX77650_CHG_PREQ:
  181. case MAX77650_CHG_ON_CURR:
  182. case MAX77650_CHG_ON_CURR_JEITA:
  183. case MAX77650_CHG_ON_VOLT:
  184. case MAX77650_CHG_ON_VOLT_JEITA:
  185. case MAX77650_CHG_ON_TOPOFF:
  186. case MAX77650_CHG_ON_TOPOFF_JEITA:
  187. val->intval = POWER_SUPPLY_STATUS_CHARGING;
  188. break;
  189. case MAX77650_CHG_DONE:
  190. val->intval = POWER_SUPPLY_STATUS_FULL;
  191. break;
  192. default:
  193. val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
  194. }
  195. break;
  196. case POWER_SUPPLY_PROP_ONLINE:
  197. rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
  198. if (rv)
  199. return rv;
  200. val->intval = MAX77650_CHARGER_CHG_CHARGING(reg);
  201. break;
  202. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  203. rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, &reg);
  204. if (rv)
  205. return rv;
  206. if (!MAX77650_CHARGER_CHG_CHARGING(reg)) {
  207. val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
  208. break;
  209. }
  210. switch (MAX77650_CHG_DETAILS_BITS(reg)) {
  211. case MAX77650_CHG_PREQ:
  212. case MAX77650_CHG_ON_CURR:
  213. case MAX77650_CHG_ON_CURR_JEITA:
  214. case MAX77650_CHG_ON_VOLT:
  215. case MAX77650_CHG_ON_VOLT_JEITA:
  216. val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
  217. break;
  218. case MAX77650_CHG_ON_TOPOFF:
  219. case MAX77650_CHG_ON_TOPOFF_JEITA:
  220. val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
  221. break;
  222. default:
  223. val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
  224. }
  225. break;
  226. default:
  227. return -EINVAL;
  228. }
  229. return 0;
  230. }
  231. static const struct power_supply_desc max77650_battery_desc = {
  232. .name = "max77650",
  233. .type = POWER_SUPPLY_TYPE_USB,
  234. .get_property = max77650_charger_get_property,
  235. .properties = max77650_charger_properties,
  236. .num_properties = ARRAY_SIZE(max77650_charger_properties),
  237. };
  238. static int max77650_charger_probe(struct platform_device *pdev)
  239. {
  240. struct power_supply_config pscfg = {};
  241. struct max77650_charger_data *chg;
  242. struct power_supply *battery;
  243. struct device *dev, *parent;
  244. int rv, chg_irq, chgin_irq;
  245. unsigned int prop;
  246. dev = &pdev->dev;
  247. parent = dev->parent;
  248. chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
  249. if (!chg)
  250. return -ENOMEM;
  251. platform_set_drvdata(pdev, chg);
  252. chg->map = dev_get_regmap(parent, NULL);
  253. if (!chg->map)
  254. return -ENODEV;
  255. chg->dev = dev;
  256. pscfg.of_node = dev->of_node;
  257. pscfg.drv_data = chg;
  258. chg_irq = platform_get_irq_byname(pdev, "CHG");
  259. if (chg_irq < 0)
  260. return chg_irq;
  261. chgin_irq = platform_get_irq_byname(pdev, "CHGIN");
  262. if (chgin_irq < 0)
  263. return chgin_irq;
  264. rv = devm_request_any_context_irq(dev, chg_irq,
  265. max77650_charger_check_status,
  266. IRQF_ONESHOT, "chg", chg);
  267. if (rv < 0)
  268. return rv;
  269. rv = devm_request_any_context_irq(dev, chgin_irq,
  270. max77650_charger_check_status,
  271. IRQF_ONESHOT, "chgin", chg);
  272. if (rv < 0)
  273. return rv;
  274. battery = devm_power_supply_register(dev,
  275. &max77650_battery_desc, &pscfg);
  276. if (IS_ERR(battery))
  277. return PTR_ERR(battery);
  278. rv = of_property_read_u32(dev->of_node,
  279. "input-voltage-min-microvolt", &prop);
  280. if (rv == 0) {
  281. rv = max77650_charger_set_vchgin_min(chg, prop);
  282. if (rv)
  283. return rv;
  284. }
  285. rv = of_property_read_u32(dev->of_node,
  286. "input-current-limit-microamp", &prop);
  287. if (rv == 0) {
  288. rv = max77650_charger_set_ichgin_lim(chg, prop);
  289. if (rv)
  290. return rv;
  291. }
  292. return max77650_charger_enable(chg);
  293. }
  294. static int max77650_charger_remove(struct platform_device *pdev)
  295. {
  296. struct max77650_charger_data *chg = platform_get_drvdata(pdev);
  297. return max77650_charger_disable(chg);
  298. }
  299. static const struct of_device_id max77650_charger_of_match[] = {
  300. { .compatible = "maxim,max77650-charger" },
  301. { }
  302. };
  303. MODULE_DEVICE_TABLE(of, max77650_charger_of_match);
  304. static struct platform_driver max77650_charger_driver = {
  305. .driver = {
  306. .name = "max77650-charger",
  307. .of_match_table = max77650_charger_of_match,
  308. },
  309. .probe = max77650_charger_probe,
  310. .remove = max77650_charger_remove,
  311. };
  312. module_platform_driver(max77650_charger_driver);
  313. MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver");
  314. MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
  315. MODULE_LICENSE("GPL v2");
  316. MODULE_ALIAS("platform:max77650-charger");