act8945a_charger.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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/module.h>
  14. #include <linux/of.h>
  15. #include <linux/of_gpio.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/power_supply.h>
  18. #include <linux/regmap.h>
  19. static const char *act8945a_charger_model = "ACT8945A";
  20. static const char *act8945a_charger_manufacturer = "Active-semi";
  21. /**
  22. * ACT8945A Charger Register Map
  23. */
  24. /* 0x70: Reserved */
  25. #define ACT8945A_APCH_CFG 0x71
  26. #define ACT8945A_APCH_STATUS 0x78
  27. #define ACT8945A_APCH_CTRL 0x79
  28. #define ACT8945A_APCH_STATE 0x7A
  29. /* ACT8945A_APCH_CFG */
  30. #define APCH_CFG_OVPSET (0x3 << 0)
  31. #define APCH_CFG_OVPSET_6V6 (0x0 << 0)
  32. #define APCH_CFG_OVPSET_7V (0x1 << 0)
  33. #define APCH_CFG_OVPSET_7V5 (0x2 << 0)
  34. #define APCH_CFG_OVPSET_8V (0x3 << 0)
  35. #define APCH_CFG_PRETIMO (0x3 << 2)
  36. #define APCH_CFG_PRETIMO_40_MIN (0x0 << 2)
  37. #define APCH_CFG_PRETIMO_60_MIN (0x1 << 2)
  38. #define APCH_CFG_PRETIMO_80_MIN (0x2 << 2)
  39. #define APCH_CFG_PRETIMO_DISABLED (0x3 << 2)
  40. #define APCH_CFG_TOTTIMO (0x3 << 4)
  41. #define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4)
  42. #define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4)
  43. #define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4)
  44. #define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4)
  45. #define APCH_CFG_SUSCHG (0x1 << 7)
  46. #define APCH_STATUS_CHGDAT BIT(0)
  47. #define APCH_STATUS_INDAT BIT(1)
  48. #define APCH_STATUS_TEMPDAT BIT(2)
  49. #define APCH_STATUS_TIMRDAT BIT(3)
  50. #define APCH_STATUS_CHGSTAT BIT(4)
  51. #define APCH_STATUS_INSTAT BIT(5)
  52. #define APCH_STATUS_TEMPSTAT BIT(6)
  53. #define APCH_STATUS_TIMRSTAT BIT(7)
  54. #define APCH_CTRL_CHGEOCOUT BIT(0)
  55. #define APCH_CTRL_INDIS BIT(1)
  56. #define APCH_CTRL_TEMPOUT BIT(2)
  57. #define APCH_CTRL_TIMRPRE BIT(3)
  58. #define APCH_CTRL_CHGEOCIN BIT(4)
  59. #define APCH_CTRL_INCON BIT(5)
  60. #define APCH_CTRL_TEMPIN BIT(6)
  61. #define APCH_CTRL_TIMRTOT BIT(7)
  62. #define APCH_STATE_ACINSTAT (0x1 << 1)
  63. #define APCH_STATE_CSTATE (0x3 << 4)
  64. #define APCH_STATE_CSTATE_SHIFT 4
  65. #define APCH_STATE_CSTATE_DISABLED 0x00
  66. #define APCH_STATE_CSTATE_EOC 0x01
  67. #define APCH_STATE_CSTATE_FAST 0x02
  68. #define APCH_STATE_CSTATE_PRE 0x03
  69. struct act8945a_charger {
  70. struct regmap *regmap;
  71. bool battery_temperature;
  72. };
  73. static int act8945a_get_charger_state(struct regmap *regmap, int *val)
  74. {
  75. int ret;
  76. unsigned int status, state;
  77. ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  78. if (ret < 0)
  79. return ret;
  80. ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
  81. if (ret < 0)
  82. return ret;
  83. state &= APCH_STATE_CSTATE;
  84. state >>= APCH_STATE_CSTATE_SHIFT;
  85. if (state == APCH_STATE_CSTATE_EOC) {
  86. if (status & APCH_STATUS_CHGDAT)
  87. *val = POWER_SUPPLY_STATUS_FULL;
  88. else
  89. *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
  90. } else if ((state == APCH_STATE_CSTATE_FAST) ||
  91. (state == APCH_STATE_CSTATE_PRE)) {
  92. *val = POWER_SUPPLY_STATUS_CHARGING;
  93. } else {
  94. *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
  95. }
  96. return 0;
  97. }
  98. static int act8945a_get_charge_type(struct regmap *regmap, int *val)
  99. {
  100. int ret;
  101. unsigned int state;
  102. ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
  103. if (ret < 0)
  104. return ret;
  105. state &= APCH_STATE_CSTATE;
  106. state >>= APCH_STATE_CSTATE_SHIFT;
  107. switch (state) {
  108. case APCH_STATE_CSTATE_PRE:
  109. *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
  110. break;
  111. case APCH_STATE_CSTATE_FAST:
  112. *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
  113. break;
  114. case APCH_STATE_CSTATE_EOC:
  115. case APCH_STATE_CSTATE_DISABLED:
  116. default:
  117. *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
  118. }
  119. return 0;
  120. }
  121. static int act8945a_get_battery_health(struct act8945a_charger *charger,
  122. struct regmap *regmap, int *val)
  123. {
  124. int ret;
  125. unsigned int status;
  126. ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
  127. if (ret < 0)
  128. return ret;
  129. if (charger->battery_temperature && !(status & APCH_STATUS_TEMPDAT))
  130. *val = POWER_SUPPLY_HEALTH_OVERHEAT;
  131. else if (!(status & APCH_STATUS_INDAT))
  132. *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
  133. else if (status & APCH_STATUS_TIMRDAT)
  134. *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
  135. else
  136. *val = POWER_SUPPLY_HEALTH_GOOD;
  137. return 0;
  138. }
  139. static enum power_supply_property act8945a_charger_props[] = {
  140. POWER_SUPPLY_PROP_STATUS,
  141. POWER_SUPPLY_PROP_CHARGE_TYPE,
  142. POWER_SUPPLY_PROP_TECHNOLOGY,
  143. POWER_SUPPLY_PROP_HEALTH,
  144. POWER_SUPPLY_PROP_MODEL_NAME,
  145. POWER_SUPPLY_PROP_MANUFACTURER
  146. };
  147. static int act8945a_charger_get_property(struct power_supply *psy,
  148. enum power_supply_property prop,
  149. union power_supply_propval *val)
  150. {
  151. struct act8945a_charger *charger = power_supply_get_drvdata(psy);
  152. struct regmap *regmap = charger->regmap;
  153. int ret = 0;
  154. switch (prop) {
  155. case POWER_SUPPLY_PROP_STATUS:
  156. ret = act8945a_get_charger_state(regmap, &val->intval);
  157. break;
  158. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  159. ret = act8945a_get_charge_type(regmap, &val->intval);
  160. break;
  161. case POWER_SUPPLY_PROP_TECHNOLOGY:
  162. val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
  163. break;
  164. case POWER_SUPPLY_PROP_HEALTH:
  165. ret = act8945a_get_battery_health(charger,
  166. regmap, &val->intval);
  167. break;
  168. case POWER_SUPPLY_PROP_MODEL_NAME:
  169. val->strval = act8945a_charger_model;
  170. break;
  171. case POWER_SUPPLY_PROP_MANUFACTURER:
  172. val->strval = act8945a_charger_manufacturer;
  173. break;
  174. default:
  175. return -EINVAL;
  176. }
  177. return ret;
  178. }
  179. static const struct power_supply_desc act8945a_charger_desc = {
  180. .name = "act8945a-charger",
  181. .type = POWER_SUPPLY_TYPE_BATTERY,
  182. .get_property = act8945a_charger_get_property,
  183. .properties = act8945a_charger_props,
  184. .num_properties = ARRAY_SIZE(act8945a_charger_props),
  185. };
  186. #define DEFAULT_TOTAL_TIME_OUT 3
  187. #define DEFAULT_PRE_TIME_OUT 40
  188. #define DEFAULT_INPUT_OVP_THRESHOLD 6600
  189. static int act8945a_charger_config(struct device *dev,
  190. struct act8945a_charger *charger)
  191. {
  192. struct device_node *np = dev->of_node;
  193. enum of_gpio_flags flags;
  194. struct regmap *regmap = charger->regmap;
  195. u32 total_time_out;
  196. u32 pre_time_out;
  197. u32 input_voltage_threshold;
  198. int chglev_pin;
  199. unsigned int value = 0;
  200. if (!np) {
  201. dev_err(dev, "no charger of node\n");
  202. return -EINVAL;
  203. }
  204. charger->battery_temperature = of_property_read_bool(np,
  205. "active-semi,check-battery-temperature");
  206. chglev_pin = of_get_named_gpio_flags(np,
  207. "active-semi,chglev-gpios", 0, &flags);
  208. if (gpio_is_valid(chglev_pin)) {
  209. gpio_set_value(chglev_pin,
  210. ((flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1));
  211. }
  212. if (of_property_read_u32(np,
  213. "active-semi,input-voltage-threshold-microvolt",
  214. &input_voltage_threshold))
  215. input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
  216. if (of_property_read_u32(np,
  217. "active-semi,precondition-timeout",
  218. &pre_time_out))
  219. pre_time_out = DEFAULT_PRE_TIME_OUT;
  220. if (of_property_read_u32(np, "active-semi,total-timeout",
  221. &total_time_out))
  222. total_time_out = DEFAULT_TOTAL_TIME_OUT;
  223. switch (input_voltage_threshold) {
  224. case 8000:
  225. value |= APCH_CFG_OVPSET_8V;
  226. break;
  227. case 7500:
  228. value |= APCH_CFG_OVPSET_7V5;
  229. break;
  230. case 7000:
  231. value |= APCH_CFG_OVPSET_7V;
  232. break;
  233. case 6600:
  234. default:
  235. value |= APCH_CFG_OVPSET_6V6;
  236. break;
  237. }
  238. switch (pre_time_out) {
  239. case 60:
  240. value |= APCH_CFG_PRETIMO_60_MIN;
  241. break;
  242. case 80:
  243. value |= APCH_CFG_PRETIMO_80_MIN;
  244. break;
  245. case 0:
  246. value |= APCH_CFG_PRETIMO_DISABLED;
  247. break;
  248. case 40:
  249. default:
  250. value |= APCH_CFG_PRETIMO_40_MIN;
  251. break;
  252. }
  253. switch (total_time_out) {
  254. case 4:
  255. value |= APCH_CFG_TOTTIMO_4_HOUR;
  256. break;
  257. case 5:
  258. value |= APCH_CFG_TOTTIMO_5_HOUR;
  259. break;
  260. case 0:
  261. value |= APCH_CFG_TOTTIMO_DISABLED;
  262. break;
  263. case 3:
  264. default:
  265. value |= APCH_CFG_TOTTIMO_3_HOUR;
  266. break;
  267. }
  268. return regmap_write(regmap, ACT8945A_APCH_CFG, value);
  269. }
  270. static int act8945a_charger_probe(struct platform_device *pdev)
  271. {
  272. struct act8945a_charger *charger;
  273. struct power_supply *psy;
  274. struct power_supply_config psy_cfg = {};
  275. int ret;
  276. charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
  277. if (!charger)
  278. return -ENOMEM;
  279. charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
  280. if (!charger->regmap) {
  281. dev_err(&pdev->dev, "Parent did not provide regmap\n");
  282. return -EINVAL;
  283. }
  284. ret = act8945a_charger_config(pdev->dev.parent, charger);
  285. if (ret)
  286. return ret;
  287. psy_cfg.of_node = pdev->dev.parent->of_node;
  288. psy_cfg.drv_data = charger;
  289. psy = devm_power_supply_register(&pdev->dev,
  290. &act8945a_charger_desc,
  291. &psy_cfg);
  292. if (IS_ERR(psy)) {
  293. dev_err(&pdev->dev, "failed to register power supply\n");
  294. return PTR_ERR(psy);
  295. }
  296. return 0;
  297. }
  298. static struct platform_driver act8945a_charger_driver = {
  299. .driver = {
  300. .name = "act8945a-charger",
  301. },
  302. .probe = act8945a_charger_probe,
  303. };
  304. module_platform_driver(act8945a_charger_driver);
  305. MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
  306. MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
  307. MODULE_LICENSE("GPL");