pm8058_usb_fix.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /* Copyright (c) 2010, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/errno.h>
  16. #include <linux/mfd/pmic8058.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/delay.h>
  19. #include <linux/bitops.h>
  20. #include <linux/workqueue.h>
  21. #include <linux/debugfs.h>
  22. #include <linux/slab.h>
  23. #include <mach/msm_xo.h>
  24. #include <mach/msm_hsusb.h>
  25. /* Config Regs and their bits*/
  26. #define PM8058_CHG_TEST 0x75
  27. #define IGNORE_LL 2
  28. #define PM8058_CHG_TEST_2 0xEA
  29. #define PM8058_CHG_TEST_3 0xEB
  30. #define PM8058_OVP_TEST_REG 0xF6
  31. #define FORCE_OVP_OFF 3
  32. #define PM8058_CHG_CNTRL 0x1E
  33. #define CHG_TRICKLE_EN 7
  34. #define CHG_USB_SUSPEND 6
  35. #define CHG_IMON_CAL 5
  36. #define CHG_IMON_GAIN 4
  37. #define CHG_VBUS_FROM_BOOST_OVRD 2
  38. #define CHG_CHARGE_DIS 1
  39. #define CHG_VCP_EN 0
  40. #define PM8058_CHG_CNTRL_2 0xD8
  41. #define ATC_DIS 7 /* coincell backed */
  42. #define CHARGE_AUTO_DIS 6
  43. #define DUMB_CHG_OVRD 5 /* coincell backed */
  44. #define ENUM_DONE 4
  45. #define CHG_TEMP_MODE 3
  46. #define CHG_BATT_TEMP_DIS 1 /* coincell backed */
  47. #define CHG_FAILED_CLEAR 0
  48. #define PM8058_CHG_VMAX_SEL 0x21
  49. #define PM8058_CHG_VBAT_DET 0xD9
  50. #define PM8058_CHG_IMAX 0x1F
  51. #define PM8058_CHG_TRICKLE 0xDB
  52. #define PM8058_CHG_ITERM 0xDC
  53. #define PM8058_CHG_TTRKL_MAX 0xE1
  54. #define PM8058_CHG_TCHG_MAX 0xE4
  55. #define PM8058_CHG_TEMP_THRESH 0xE2
  56. #define PM8058_CHG_TEMP_REG 0xE3
  57. #define PM8058_CHG_PULSE 0x22
  58. /* IRQ STATUS and CLEAR */
  59. #define PM8058_CHG_STATUS_CLEAR_IRQ_1 0x31
  60. #define PM8058_CHG_STATUS_CLEAR_IRQ_3 0x33
  61. #define PM8058_CHG_STATUS_CLEAR_IRQ_10 0xB3
  62. #define PM8058_CHG_STATUS_CLEAR_IRQ_11 0xB4
  63. /* IRQ MASKS */
  64. #define PM8058_CHG_MASK_IRQ_1 0x38
  65. #define PM8058_CHG_MASK_IRQ_3 0x3A
  66. #define PM8058_CHG_MASK_IRQ_10 0xBA
  67. #define PM8058_CHG_MASK_IRQ_11 0xBB
  68. /* IRQ Real time status regs */
  69. #define PM8058_CHG_STATUS_RT_1 0x3F
  70. #define STATUS_RTCHGVAL 7
  71. #define STATUS_RTCHGINVAL 6
  72. #define STATUS_RTBATT_REPLACE 5
  73. #define STATUS_RTVBATDET_LOW 4
  74. #define STATUS_RTCHGILIM 3
  75. #define STATUS_RTPCTDONE 1
  76. #define STATUS_RTVCP 0
  77. #define PM8058_CHG_STATUS_RT_3 0x41
  78. #define PM8058_CHG_STATUS_RT_10 0xC1
  79. #define PM8058_CHG_STATUS_RT_11 0xC2
  80. /* VTRIM */
  81. #define PM8058_CHG_VTRIM 0x1D
  82. #define PM8058_CHG_VBATDET_TRIM 0x1E
  83. #define PM8058_CHG_ITRIM 0x1F
  84. #define PM8058_CHG_TTRIM 0x20
  85. #define AUTO_CHARGING_VMAXSEL 4200
  86. #define AUTO_CHARGING_FAST_TIME_MAX_MINUTES 512
  87. #define AUTO_CHARGING_TRICKLE_TIME_MINUTES 30
  88. #define AUTO_CHARGING_VEOC_ITERM 100
  89. #define AUTO_CHARGING_IEOC_ITERM 160
  90. #define AUTO_CHARGING_VBATDET 4150
  91. #define AUTO_CHARGING_VEOC_VBATDET 4100
  92. #define AUTO_CHARGING_VEOC_TCHG 16
  93. #define AUTO_CHARGING_VEOC_TCHG_FINAL_CYCLE 32
  94. #define AUTO_CHARGING_VEOC_BEGIN_TIME_MS 5400000
  95. #define AUTO_CHARGING_VEOC_VBAT_LOW_CHECK_TIME_MS 60000
  96. #define AUTO_CHARGING_RESUME_CHARGE_DETECTION_COUNTER 5
  97. #define PM8058_CHG_I_STEP_MA 50
  98. #define PM8058_CHG_I_MIN_MA 50
  99. #define PM8058_CHG_T_TCHG_SHIFT 2
  100. #define PM8058_CHG_I_TERM_STEP_MA 10
  101. #define PM8058_CHG_V_STEP_MV 25
  102. #define PM8058_CHG_V_MIN_MV 2400
  103. /*
  104. * enum pmic_chg_interrupts: pmic interrupts
  105. * @CHGVAL_IRQ: charger V between 3.3 and 7.9
  106. * @CHGINVAL_IRQ: charger V outside 3.3 and 7.9
  107. * @VBATDET_LOW_IRQ: VBAT < VBATDET
  108. * @VCP_IRQ: VDD went below VBAT: BAT_FET is turned on
  109. * @CHGILIM_IRQ: mA consumed>IMAXSEL: chgloop draws less mA
  110. * @ATC_DONE_IRQ: Auto Trickle done
  111. * @ATCFAIL_IRQ: Auto Trickle fail
  112. * @AUTO_CHGDONE_IRQ: Auto chg done
  113. * @AUTO_CHGFAIL_IRQ: time exceeded w/o reaching term current
  114. * @CHGSTATE_IRQ: something happend causing a state change
  115. * @FASTCHG_IRQ: trkl charging completed: moving to fastchg
  116. * @CHG_END_IRQ: mA has dropped to termination current
  117. * @BATTTEMP_IRQ: batt temp is out of range
  118. * @CHGHOT_IRQ: the pass device is too hot
  119. * @CHGTLIMIT_IRQ: unused
  120. * @CHG_GONE_IRQ: charger was removed
  121. * @VCPMAJOR_IRQ: vcp major
  122. * @VBATDET_IRQ: VBAT >= VBATDET
  123. * @BATFET_IRQ: BATFET closed
  124. * @BATT_REPLACE_IRQ:
  125. * @BATTCONNECT_IRQ:
  126. */
  127. enum pmic_chg_interrupts {
  128. CHGVAL_IRQ,
  129. CHGINVAL_IRQ,
  130. VBATDET_LOW_IRQ,
  131. VCP_IRQ,
  132. CHGILIM_IRQ,
  133. ATC_DONE_IRQ,
  134. ATCFAIL_IRQ,
  135. AUTO_CHGDONE_IRQ,
  136. AUTO_CHGFAIL_IRQ,
  137. CHGSTATE_IRQ,
  138. FASTCHG_IRQ,
  139. CHG_END_IRQ,
  140. BATTTEMP_IRQ,
  141. CHGHOT_IRQ,
  142. CHGTLIMIT_IRQ,
  143. CHG_GONE_IRQ,
  144. VCPMAJOR_IRQ,
  145. VBATDET_IRQ,
  146. BATFET_IRQ,
  147. BATT_REPLACE_IRQ,
  148. BATTCONNECT_IRQ,
  149. PMIC_CHG_MAX_INTS
  150. };
  151. struct pm8058_charger {
  152. struct pmic_charger_pdata *pdata;
  153. struct pm8058_chip *pm_chip;
  154. struct device *dev;
  155. int pmic_chg_irq[PMIC_CHG_MAX_INTS];
  156. DECLARE_BITMAP(enabled_irqs, PMIC_CHG_MAX_INTS);
  157. struct delayed_work check_vbat_low_work;
  158. struct delayed_work veoc_begin_work;
  159. int waiting_for_topoff;
  160. int waiting_for_veoc;
  161. int current_charger_current;
  162. struct msm_xo_voter *voter;
  163. struct dentry *dent;
  164. };
  165. static struct pm8058_charger pm8058_chg;
  166. static int pm_chg_get_rt_status(int irq)
  167. {
  168. int count = 3;
  169. int ret;
  170. while ((ret =
  171. pm8058_irq_get_rt_status(pm8058_chg.pm_chip, irq)) == -EAGAIN
  172. && count--) {
  173. dev_info(pm8058_chg.dev, "%s trycount=%d\n", __func__, count);
  174. cpu_relax();
  175. }
  176. if (ret == -EAGAIN)
  177. return 0;
  178. else
  179. return ret;
  180. }
  181. static int is_chg_plugged_in(void)
  182. {
  183. return pm_chg_get_rt_status(pm8058_chg.pmic_chg_irq[CHGVAL_IRQ]);
  184. }
  185. static irqreturn_t pm8058_chg_chgval_handler(int irq, void *dev_id)
  186. {
  187. u8 old, temp;
  188. int ret;
  189. if (!is_chg_plugged_in()) { /*this debounces it */
  190. ret = pm8058_read(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
  191. &old, 1);
  192. temp = old | BIT(FORCE_OVP_OFF);
  193. ret = pm8058_write(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
  194. &temp, 1);
  195. temp = 0xFC;
  196. ret = pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST,
  197. &temp, 1);
  198. pr_debug("%s forced wrote 0xFC to test ret=%d\n",
  199. __func__, ret);
  200. /* 20 ms sleep is for the VCHG to discharge */
  201. msleep(20);
  202. temp = 0xF0;
  203. ret = pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST,
  204. &temp, 1);
  205. ret = pm8058_write(pm8058_chg.pm_chip, PM8058_OVP_TEST_REG,
  206. &old, 1);
  207. }
  208. return IRQ_HANDLED;
  209. }
  210. static void free_irqs(void)
  211. {
  212. int i;
  213. for (i = 0; i < PMIC_CHG_MAX_INTS; i++)
  214. if (pm8058_chg.pmic_chg_irq[i]) {
  215. free_irq(pm8058_chg.pmic_chg_irq[i], NULL);
  216. pm8058_chg.pmic_chg_irq[i] = 0;
  217. }
  218. }
  219. static int __devinit request_irqs(struct platform_device *pdev)
  220. {
  221. struct resource *res;
  222. int ret;
  223. ret = 0;
  224. bitmap_fill(pm8058_chg.enabled_irqs, PMIC_CHG_MAX_INTS);
  225. res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "CHGVAL");
  226. if (res == NULL) {
  227. dev_err(pm8058_chg.dev,
  228. "%s:couldnt find resource CHGVAL\n", __func__);
  229. goto err_out;
  230. } else {
  231. ret = request_any_context_irq(res->start,
  232. pm8058_chg_chgval_handler,
  233. IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
  234. res->name, NULL);
  235. if (ret < 0) {
  236. dev_err(pm8058_chg.dev, "%s:couldnt request %d %d\n",
  237. __func__, res->start, ret);
  238. goto err_out;
  239. } else {
  240. pm8058_chg.pmic_chg_irq[CHGVAL_IRQ] = res->start;
  241. }
  242. }
  243. return 0;
  244. err_out:
  245. free_irqs();
  246. return -EINVAL;
  247. }
  248. static int pm8058_usb_voltage_lower_limit(void)
  249. {
  250. u8 temp, old;
  251. int ret = 0;
  252. temp = 0x10;
  253. ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);
  254. ret |= pm8058_read(pm8058_chg.pm_chip, PM8058_CHG_TEST, &old, 1);
  255. old = old & ~BIT(IGNORE_LL);
  256. temp = 0x90 | (0xF & old);
  257. pr_debug("%s writing 0x%x to test\n", __func__, temp);
  258. ret |= pm8058_write(pm8058_chg.pm_chip, PM8058_CHG_TEST, &temp, 1);
  259. return ret;
  260. }
  261. static int __devinit pm8058_charger_probe(struct platform_device *pdev)
  262. {
  263. struct pm8058_chip *pm_chip;
  264. pm_chip = dev_get_drvdata(pdev->dev.parent);
  265. if (pm_chip == NULL) {
  266. pr_err("%s:no parent data passed in.\n", __func__);
  267. return -EFAULT;
  268. }
  269. pm8058_chg.pm_chip = pm_chip;
  270. pm8058_chg.pdata = pdev->dev.platform_data;
  271. pm8058_chg.dev = &pdev->dev;
  272. if (request_irqs(pdev)) {
  273. pr_err("%s: couldnt register interrupts\n", __func__);
  274. return -EINVAL;
  275. }
  276. if (pm8058_usb_voltage_lower_limit()) {
  277. pr_err("%s: couldnt write to IGNORE_LL\n", __func__);
  278. return -EINVAL;
  279. }
  280. return 0;
  281. }
  282. static int __devexit pm8058_charger_remove(struct platform_device *pdev)
  283. {
  284. free_irqs();
  285. return 0;
  286. }
  287. static struct platform_driver pm8058_charger_driver = {
  288. .probe = pm8058_charger_probe,
  289. .remove = __devexit_p(pm8058_charger_remove),
  290. .driver = {
  291. .name = "pm-usb-fix",
  292. .owner = THIS_MODULE,
  293. },
  294. };
  295. static int __init pm8058_charger_init(void)
  296. {
  297. return platform_driver_register(&pm8058_charger_driver);
  298. }
  299. static void __exit pm8058_charger_exit(void)
  300. {
  301. platform_driver_unregister(&pm8058_charger_driver);
  302. }
  303. late_initcall(pm8058_charger_init);
  304. module_exit(pm8058_charger_exit);
  305. MODULE_LICENSE("GPL v2");
  306. MODULE_DESCRIPTION("PMIC8058 BATTERY driver");
  307. MODULE_VERSION("1.0");
  308. MODULE_ALIAS("platform:pm8058_charger");