diff mbox

[V2,1/2] power: twl4030_charger: detect battery presence prior to enabling charger

Message ID 1401313610-14252-2-git-send-email-nm@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nishanth Menon May 28, 2014, 9:46 p.m. UTC
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>
---
V2: just a rebase, picked up tony's tested-by, minor formatting fix
V1: https://patchwork.kernel.org/patch/4124751/
 drivers/power/twl4030_charger.c |   44 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

Comments

Tony Lindgren July 23, 2014, 9:24 a.m. UTC | #1
* Nishanth Menon <nm@ti.com> [140528 14:48]:
> 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>

Dmitry, can we please get this first patch merged? This is needed
on some omap3 platforms for DT based booting when no battery is
present.

Only the second patch in this series is still being discussed AFAIK.

Regards,

Tony

> ---
> V2: just a rebase, picked up tony's tested-by, minor formatting fix
> V1: https://patchwork.kernel.org/patch/4124751/
>  drivers/power/twl4030_charger.c |   44 ++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 43 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
> index f141088..2598c58 100644
> --- a/drivers/power/twl4030_charger.c
> +++ b/drivers/power/twl4030_charger.c
> @@ -28,10 +28,13 @@
>  #define TWL4030_BCIICHG		0x08
>  #define TWL4030_BCIVAC		0x0a
>  #define TWL4030_BCIVBUS		0x0c
> +#define TWL4030_BCIMFSTS3	0x0F
>  #define TWL4030_BCIMFSTS4	0x10
>  #define TWL4030_BCICTL1		0x23
>  #define TWL4030_BB_CFG		0x12
>  
> +#define TWL4030_BCIMFSTS1	0x01
> +
>  #define TWL4030_BCIAUTOWEN	BIT(5)
>  #define TWL4030_CONFIG_DONE	BIT(4)
>  #define TWL4030_BCIAUTOUSB	BIT(1)
> @@ -52,6 +55,9 @@
>  #define TWL4030_BBISEL_500uA	0x02
>  #define TWL4030_BBISEL_1000uA	0x03
>  
> +#define TWL4030_BATSTSPCHG	BIT(2)
> +#define TWL4030_BATSTSMCHG	BIT(6)
> +
>  /* BCI interrupts */
>  #define TWL4030_WOVF		BIT(0) /* Watchdog overflow */
>  #define TWL4030_TMOVF		BIT(1) /* Timer overflow */
> @@ -145,6 +151,35 @@ static int twl4030bci_read_adc_val(u8 reg)
>  }
>  
>  /*
> + * Check if Battery Pack was present
> + */
> +static int twl4030_is_battery_present(struct twl4030_bci *bci)
> +{
> +	int ret;
> +	u8 val = 0;
> +
> +	/* Battery presence in Main charge? */
> +	ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMFSTS3);
> +	if (ret)
> +		return ret;
> +	if (val & TWL4030_BATSTSMCHG)
> +		return 0;
> +
> +	/*
> +	 * OK, It could be that bootloader did not enable main charger,
> +	 * pre-charge is h/w auto. So, Battery presence in Pre-charge?
> +	 */
> +	ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &val,
> +			      TWL4030_BCIMFSTS1);
> +	if (ret)
> +		return ret;
> +	if (val & TWL4030_BATSTSPCHG)
> +		return 0;
> +
> +	return -ENODEV;
> +}
> +
> +/*
>   * Check if VBUS power is present
>   */
>  static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
> @@ -541,8 +576,14 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
>  	bci->irq_chg = platform_get_irq(pdev, 0);
>  	bci->irq_bci = platform_get_irq(pdev, 1);
>  
> -	platform_set_drvdata(pdev, bci);
> +	/* Only proceed further *IF* battery is physically present */
> +	ret = twl4030_is_battery_present(bci);
> +	if  (ret) {
> +		dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret);
> +		goto fail_no_battery;
> +	}
>  
> +	platform_set_drvdata(pdev, bci);
>  	bci->ac.name = "twl4030_ac";
>  	bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
>  	bci->ac.properties = twl4030_charger_props;
> @@ -633,6 +674,7 @@ fail_chg_irq:
>  fail_register_usb:
>  	power_supply_unregister(&bci->ac);
>  fail_register_ac:
> +fail_no_battery:
>  	kfree(bci);
>  
>  	return ret;
> -- 
> 1.7.9.5
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sebastian Reichel July 23, 2014, 12:03 p.m. UTC | #2
On Wed, Jul 23, 2014 at 02:24:20AM -0700, Tony Lindgren wrote:
> * Nishanth Menon <nm@ti.com> [140528 14:48]:
> > 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>
> 
> Dmitry, can we please get this first patch merged? This is needed
> on some omap3 platforms for DT based booting when no battery is
> present.
> 
> Only the second patch in this series is still being discussed AFAIK.

applied to battery-2.6.git:

http://git.infradead.org/battery-2.6.git/commit/61a7784efd3c89ffb6242f29bcee170dd7f55e6b

-- Sebastian
Tony Lindgren July 24, 2014, 6:32 a.m. UTC | #3
* Sebastian Reichel <sre@kernel.org> [140723 05:05]:
> On Wed, Jul 23, 2014 at 02:24:20AM -0700, Tony Lindgren wrote:
> > * Nishanth Menon <nm@ti.com> [140528 14:48]:
> > > 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>
> > 
> > Dmitry, can we please get this first patch merged? This is needed
> > on some omap3 platforms for DT based booting when no battery is
> > present.
> > 
> > Only the second patch in this series is still being discussed AFAIK.
> 
> applied to battery-2.6.git:
> 
> http://git.infradead.org/battery-2.6.git/commit/61a7784efd3c89ffb6242f29bcee170dd7f55e6b

Thanks!

Tony
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index f141088..2598c58 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -28,10 +28,13 @@ 
 #define TWL4030_BCIICHG		0x08
 #define TWL4030_BCIVAC		0x0a
 #define TWL4030_BCIVBUS		0x0c
+#define TWL4030_BCIMFSTS3	0x0F
 #define TWL4030_BCIMFSTS4	0x10
 #define TWL4030_BCICTL1		0x23
 #define TWL4030_BB_CFG		0x12
 
+#define TWL4030_BCIMFSTS1	0x01
+
 #define TWL4030_BCIAUTOWEN	BIT(5)
 #define TWL4030_CONFIG_DONE	BIT(4)
 #define TWL4030_BCIAUTOUSB	BIT(1)
@@ -52,6 +55,9 @@ 
 #define TWL4030_BBISEL_500uA	0x02
 #define TWL4030_BBISEL_1000uA	0x03
 
+#define TWL4030_BATSTSPCHG	BIT(2)
+#define TWL4030_BATSTSMCHG	BIT(6)
+
 /* BCI interrupts */
 #define TWL4030_WOVF		BIT(0) /* Watchdog overflow */
 #define TWL4030_TMOVF		BIT(1) /* Timer overflow */
@@ -145,6 +151,35 @@  static int twl4030bci_read_adc_val(u8 reg)
 }
 
 /*
+ * Check if Battery Pack was present
+ */
+static int twl4030_is_battery_present(struct twl4030_bci *bci)
+{
+	int ret;
+	u8 val = 0;
+
+	/* Battery presence in Main charge? */
+	ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMFSTS3);
+	if (ret)
+		return ret;
+	if (val & TWL4030_BATSTSMCHG)
+		return 0;
+
+	/*
+	 * OK, It could be that bootloader did not enable main charger,
+	 * pre-charge is h/w auto. So, Battery presence in Pre-charge?
+	 */
+	ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &val,
+			      TWL4030_BCIMFSTS1);
+	if (ret)
+		return ret;
+	if (val & TWL4030_BATSTSPCHG)
+		return 0;
+
+	return -ENODEV;
+}
+
+/*
  * Check if VBUS power is present
  */
 static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
@@ -541,8 +576,14 @@  static int __init twl4030_bci_probe(struct platform_device *pdev)
 	bci->irq_chg = platform_get_irq(pdev, 0);
 	bci->irq_bci = platform_get_irq(pdev, 1);
 
-	platform_set_drvdata(pdev, bci);
+	/* Only proceed further *IF* battery is physically present */
+	ret = twl4030_is_battery_present(bci);
+	if  (ret) {
+		dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret);
+		goto fail_no_battery;
+	}
 
+	platform_set_drvdata(pdev, bci);
 	bci->ac.name = "twl4030_ac";
 	bci->ac.type = POWER_SUPPLY_TYPE_MAINS;
 	bci->ac.properties = twl4030_charger_props;
@@ -633,6 +674,7 @@  fail_chg_irq:
 fail_register_usb:
 	power_supply_unregister(&bci->ac);
 fail_register_ac:
+fail_no_battery:
 	kfree(bci);
 
 	return ret;