aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/twl4030_charger.c
diff options
context:
space:
mode:
authorNishanth Menon <nm@ti.com>2014-05-28 17:46:49 -0400
committerSebastian Reichel <sre@kernel.org>2014-07-23 07:58:33 -0400
commit61a7784efd3c89ffb6242f29bcee170dd7f55e6b (patch)
treeff9c71cb2d8978b2364d2ce968e9bfe1439f9b80 /drivers/power/twl4030_charger.c
parent030494e75064cb4fcbeb609d845ae0c9ceade2b9 (diff)
power: twl4030_charger: detect battery presence prior to enabling charger
TWL4030's Battery Charger seems to be designed for non-hotpluggable batteries. If battery is not present in the system, BATSTS is always set with the expectation that software will take actions to move to a required safe state (could be power down or disable various charger paths). It does not seem possible even by manipulating the edge detection of the event (using BCIEDR2 register) to have a consistent hotplug handling. This seems to be the result of BATSTS interrupt generated when the thermistor of the battery pack is disconnected from the dedicated ADIN1 pin. Clearing the status just results in the status being regenerated by the monitoring ADC(MADC) and disabling the edges of event just makes hotplug no longer function. The only other option is to disable the detection of the MADC by disabling BCIMFEN4::BATSTSMCHGEN (battery presence detector) - but then, we can never again detect battery reconnection. So, detect battery presence based on precharge(which is hardware automatic state) or default main charger configuration at the time of probe and enable charger logic only if battery was present. Reported-by: Russell King <linux@arm.linux.org.uk> Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Nishanth Menon <nm@ti.com> Signed-off-by: Sebastian Reichel <sre@kernel.org>
Diffstat (limited to 'drivers/power/twl4030_charger.c')
-rw-r--r--drivers/power/twl4030_charger.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index f14108844e1a..2598c588006e 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -28,10 +28,13 @@
28#define TWL4030_BCIICHG 0x08 28#define TWL4030_BCIICHG 0x08
29#define TWL4030_BCIVAC 0x0a 29#define TWL4030_BCIVAC 0x0a
30#define TWL4030_BCIVBUS 0x0c 30#define TWL4030_BCIVBUS 0x0c
31#define TWL4030_BCIMFSTS3 0x0F
31#define TWL4030_BCIMFSTS4 0x10 32#define TWL4030_BCIMFSTS4 0x10
32#define TWL4030_BCICTL1 0x23 33#define TWL4030_BCICTL1 0x23
33#define TWL4030_BB_CFG 0x12 34#define TWL4030_BB_CFG 0x12
34 35
36#define TWL4030_BCIMFSTS1 0x01
37
35#define TWL4030_BCIAUTOWEN BIT(5) 38#define TWL4030_BCIAUTOWEN BIT(5)
36#define TWL4030_CONFIG_DONE BIT(4) 39#define TWL4030_CONFIG_DONE BIT(4)
37#define TWL4030_BCIAUTOUSB BIT(1) 40#define TWL4030_BCIAUTOUSB BIT(1)
@@ -52,6 +55,9 @@
52#define TWL4030_BBISEL_500uA 0x02 55#define TWL4030_BBISEL_500uA 0x02
53#define TWL4030_BBISEL_1000uA 0x03 56#define TWL4030_BBISEL_1000uA 0x03
54 57
58#define TWL4030_BATSTSPCHG BIT(2)
59#define TWL4030_BATSTSMCHG BIT(6)
60
55/* BCI interrupts */ 61/* BCI interrupts */
56#define TWL4030_WOVF BIT(0) /* Watchdog overflow */ 62#define TWL4030_WOVF BIT(0) /* Watchdog overflow */
57#define TWL4030_TMOVF BIT(1) /* Timer overflow */ 63#define TWL4030_TMOVF BIT(1) /* Timer overflow */
@@ -145,6 +151,35 @@ static int twl4030bci_read_adc_val(u8 reg)
145} 151}
146 152
147/* 153/*
154 * Check if Battery Pack was present
155 */
156static int twl4030_is_battery_present(struct twl4030_bci *bci)
157{
158 int ret;
159 u8 val = 0;
160
161 /* Battery presence in Main charge? */
162 ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMFSTS3);
163 if (ret)
164 return ret;
165 if (val & TWL4030_BATSTSMCHG)
166 return 0;
167
168 /*
169 * OK, It could be that bootloader did not enable main charger,
170 * pre-charge is h/w auto. So, Battery presence in Pre-charge?
171 */
172 ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &val,
173 TWL4030_BCIMFSTS1);
174 if (ret)
175 return ret;
176 if (val & TWL4030_BATSTSPCHG)
177 return 0;
178
179 return -ENODEV;
180}
181
182/*
148 * Check if VBUS power is present 183 * Check if VBUS power is present
149 */ 184 */
150static int twl4030_bci_have_vbus(struct twl4030_bci *bci) 185static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
@@ -541,8 +576,14 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
541 bci->irq_chg = platform_get_irq(pdev, 0); 576 bci->irq_chg = platform_get_irq(pdev, 0);
542 bci->irq_bci = platform_get_irq(pdev, 1); 577 bci->irq_bci = platform_get_irq(pdev, 1);
543 578
544 platform_set_drvdata(pdev, bci); 579 /* Only proceed further *IF* battery is physically present */
580 ret = twl4030_is_battery_present(bci);
581 if (ret) {
582 dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret);
583 goto fail_no_battery;
584 }
545 585
586 platform_set_drvdata(pdev, bci);
546 bci->ac.name = "twl4030_ac"; 587 bci->ac.name = "twl4030_ac";
547 bci->ac.type = POWER_SUPPLY_TYPE_MAINS; 588 bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
548 bci->ac.properties = twl4030_charger_props; 589 bci->ac.properties = twl4030_charger_props;
@@ -633,6 +674,7 @@ fail_chg_irq:
633fail_register_usb: 674fail_register_usb:
634 power_supply_unregister(&bci->ac); 675 power_supply_unregister(&bci->ac);
635fail_register_ac: 676fail_register_ac:
677fail_no_battery:
636 kfree(bci); 678 kfree(bci);
637 679
638 return ret; 680 return ret;