tps65217_charger.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * Battery charger driver for TI's tps65217
  3. *
  4. * Copyright (c) 2015, Collabora Ltd.
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms and conditions of the GNU General Public License,
  7. * version 2, as published by the Free Software Foundation.
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /*
  16. * Battery charger driver for TI's tps65217
  17. */
  18. #include <linux/kernel.h>
  19. #include <linux/kthread.h>
  20. #include <linux/device.h>
  21. #include <linux/module.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/init.h>
  24. #include <linux/interrupt.h>
  25. #include <linux/slab.h>
  26. #include <linux/err.h>
  27. #include <linux/of.h>
  28. #include <linux/of_device.h>
  29. #include <linux/power_supply.h>
  30. #include <linux/mfd/core.h>
  31. #include <linux/mfd/tps65217.h>
  32. #define POLL_INTERVAL (HZ * 2)
  33. struct tps65217_charger {
  34. struct tps65217 *tps;
  35. struct device *dev;
  36. struct power_supply *ac;
  37. int ac_online;
  38. int prev_ac_online;
  39. struct task_struct *poll_task;
  40. };
  41. static enum power_supply_property tps65217_ac_props[] = {
  42. POWER_SUPPLY_PROP_ONLINE,
  43. };
  44. static int tps65217_config_charger(struct tps65217_charger *charger)
  45. {
  46. int ret;
  47. dev_dbg(charger->dev, "%s\n", __func__);
  48. /*
  49. * tps65217 rev. G, p. 31 (see p. 32 for NTC schematic)
  50. *
  51. * The device can be configured to support a 100k NTC (B = 3960) by
  52. * setting the the NTC_TYPE bit in register CHGCONFIG1 to 1. However it
  53. * is not recommended to do so. In sleep mode, the charger continues
  54. * charging the battery, but all register values are reset to default
  55. * values. Therefore, the charger would get the wrong temperature
  56. * information. If 100k NTC setting is required, please contact the
  57. * factory.
  58. *
  59. * ATTENTION, conflicting information, from p. 46
  60. *
  61. * NTC TYPE (for battery temperature measurement)
  62. * 0 – 100k (curve 1, B = 3960)
  63. * 1 – 10k (curve 2, B = 3480) (default on reset)
  64. *
  65. */
  66. ret = tps65217_clear_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
  67. TPS65217_CHGCONFIG1_NTC_TYPE,
  68. TPS65217_PROTECT_NONE);
  69. if (ret) {
  70. dev_err(charger->dev,
  71. "failed to set 100k NTC setting: %d\n", ret);
  72. return ret;
  73. }
  74. return 0;
  75. }
  76. static int tps65217_enable_charging(struct tps65217_charger *charger)
  77. {
  78. int ret;
  79. /* charger already enabled */
  80. if (charger->ac_online)
  81. return 0;
  82. dev_dbg(charger->dev, "%s: enable charging\n", __func__);
  83. ret = tps65217_set_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
  84. TPS65217_CHGCONFIG1_CHG_EN,
  85. TPS65217_CHGCONFIG1_CHG_EN,
  86. TPS65217_PROTECT_NONE);
  87. if (ret) {
  88. dev_err(charger->dev,
  89. "%s: Error in writing CHG_EN in reg 0x%x: %d\n",
  90. __func__, TPS65217_REG_CHGCONFIG1, ret);
  91. return ret;
  92. }
  93. charger->ac_online = 1;
  94. return 0;
  95. }
  96. static int tps65217_ac_get_property(struct power_supply *psy,
  97. enum power_supply_property psp,
  98. union power_supply_propval *val)
  99. {
  100. struct tps65217_charger *charger = power_supply_get_drvdata(psy);
  101. if (psp == POWER_SUPPLY_PROP_ONLINE) {
  102. val->intval = charger->ac_online;
  103. return 0;
  104. }
  105. return -EINVAL;
  106. }
  107. static irqreturn_t tps65217_charger_irq(int irq, void *dev)
  108. {
  109. int ret, val;
  110. struct tps65217_charger *charger = dev;
  111. charger->prev_ac_online = charger->ac_online;
  112. ret = tps65217_reg_read(charger->tps, TPS65217_REG_STATUS, &val);
  113. if (ret < 0) {
  114. dev_err(charger->dev, "%s: Error in reading reg 0x%x\n",
  115. __func__, TPS65217_REG_STATUS);
  116. return IRQ_HANDLED;
  117. }
  118. dev_dbg(charger->dev, "%s: 0x%x\n", __func__, val);
  119. /* check for AC status bit */
  120. if (val & TPS65217_STATUS_ACPWR) {
  121. ret = tps65217_enable_charging(charger);
  122. if (ret) {
  123. dev_err(charger->dev,
  124. "failed to enable charger: %d\n", ret);
  125. return IRQ_HANDLED;
  126. }
  127. } else {
  128. charger->ac_online = 0;
  129. }
  130. if (charger->prev_ac_online != charger->ac_online)
  131. power_supply_changed(charger->ac);
  132. ret = tps65217_reg_read(charger->tps, TPS65217_REG_CHGCONFIG0, &val);
  133. if (ret < 0) {
  134. dev_err(charger->dev, "%s: Error in reading reg 0x%x\n",
  135. __func__, TPS65217_REG_CHGCONFIG0);
  136. return IRQ_HANDLED;
  137. }
  138. if (val & TPS65217_CHGCONFIG0_ACTIVE)
  139. dev_dbg(charger->dev, "%s: charger is charging\n", __func__);
  140. else
  141. dev_dbg(charger->dev,
  142. "%s: charger is NOT charging\n", __func__);
  143. return IRQ_HANDLED;
  144. }
  145. static int tps65217_charger_poll_task(void *data)
  146. {
  147. set_freezable();
  148. while (!kthread_should_stop()) {
  149. schedule_timeout_interruptible(POLL_INTERVAL);
  150. try_to_freeze();
  151. tps65217_charger_irq(-1, data);
  152. }
  153. return 0;
  154. }
  155. static const struct power_supply_desc tps65217_charger_desc = {
  156. .name = "tps65217-ac",
  157. .type = POWER_SUPPLY_TYPE_MAINS,
  158. .get_property = tps65217_ac_get_property,
  159. .properties = tps65217_ac_props,
  160. .num_properties = ARRAY_SIZE(tps65217_ac_props),
  161. };
  162. static int tps65217_charger_probe(struct platform_device *pdev)
  163. {
  164. struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
  165. struct tps65217_charger *charger;
  166. int ret;
  167. dev_dbg(&pdev->dev, "%s\n", __func__);
  168. charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
  169. if (!charger)
  170. return -ENOMEM;
  171. platform_set_drvdata(pdev, charger);
  172. charger->tps = tps;
  173. charger->dev = &pdev->dev;
  174. charger->ac = devm_power_supply_register(&pdev->dev,
  175. &tps65217_charger_desc,
  176. NULL);
  177. if (IS_ERR(charger->ac)) {
  178. dev_err(&pdev->dev, "failed: power supply register\n");
  179. return PTR_ERR(charger->ac);
  180. }
  181. ret = tps65217_config_charger(charger);
  182. if (ret < 0) {
  183. dev_err(charger->dev, "charger config failed, err %d\n", ret);
  184. return ret;
  185. }
  186. charger->poll_task = kthread_run(tps65217_charger_poll_task,
  187. charger, "ktps65217charger");
  188. if (IS_ERR(charger->poll_task)) {
  189. ret = PTR_ERR(charger->poll_task);
  190. dev_err(charger->dev, "Unable to run kthread err %d\n", ret);
  191. return ret;
  192. }
  193. return 0;
  194. }
  195. static int tps65217_charger_remove(struct platform_device *pdev)
  196. {
  197. struct tps65217_charger *charger = platform_get_drvdata(pdev);
  198. kthread_stop(charger->poll_task);
  199. return 0;
  200. }
  201. static const struct of_device_id tps65217_charger_match_table[] = {
  202. { .compatible = "ti,tps65217-charger", },
  203. { /* sentinel */ }
  204. };
  205. MODULE_DEVICE_TABLE(of, tps65217_charger_match_table);
  206. static struct platform_driver tps65217_charger_driver = {
  207. .probe = tps65217_charger_probe,
  208. .remove = tps65217_charger_remove,
  209. .driver = {
  210. .name = "tps65217-charger",
  211. .of_match_table = of_match_ptr(tps65217_charger_match_table),
  212. },
  213. };
  214. module_platform_driver(tps65217_charger_driver);
  215. MODULE_LICENSE("GPL v2");
  216. MODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>");
  217. MODULE_DESCRIPTION("TPS65217 battery charger driver");