diff mbox

[v7,09/15] power: bq24257: Add SW-based approach for Power Good determination

Message ID 1443196460-26156-10-git-send-email-dannenberg@ti.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Andreas Dannenberg Sept. 25, 2015, 3:54 p.m. UTC
A software-based approach for determining the charger's input voltage
"Power Good" state is introduced for devices like the bq24250 which
don't have a dedicated hardware pin for that purpose. This SW-based
approach is also used for other devices (with dedicated PG pin) as a
fall back solution if that pin is not configured to be used through
"pg-gpios".

Signed-off-by: Andreas Dannenberg <dannenberg@ti.com>
---
 drivers/power/bq24257_charger.c | 49 ++++++++++++++++++++++++++++++++---------
 1 file changed, 39 insertions(+), 10 deletions(-)

Comments

Sebastian Reichel Sept. 27, 2015, 8:20 p.m. UTC | #1
Hi,

On Fri, Sep 25, 2015 at 10:54:14AM -0500, Andreas Dannenberg wrote:
> @@ -651,15 +670,18 @@ static int bq24257_power_supply_init(struct bq24257_device *bq)
>  	return PTR_ERR_OR_ZERO(bq->charger);
>  }
>  
> -static int bq24257_pg_gpio_probe(struct bq24257_device *bq)
> +static void bq24257_pg_gpio_probe(struct bq24257_device *bq)
>  {
> -	bq->pg = devm_gpiod_get_index(bq->dev, BQ24257_PG_GPIO, 0, GPIOD_IN);
> +	bq->pg = devm_gpiod_get_optional(bq->dev, BQ24257_PG_GPIO, GPIOD_IN);
> +
>  	if (IS_ERR(bq->pg)) {
> -		dev_err(bq->dev, "could not probe PG pin\n");
> -		return PTR_ERR(bq->pg);
> +		dev_err(bq->dev, "error probing PG pin\n");
> +		bq->pg = NULL;
> +		return;
>  	}

You should handle -EPROBE_DEFER here.

-- Sebastian
Andreas Dannenberg Sept. 28, 2015, 12:04 p.m. UTC | #2
On Sun, Sep 27, 2015 at 10:20:26PM +0200, Sebastian Reichel wrote:
> Hi,
> 
> On Fri, Sep 25, 2015 at 10:54:14AM -0500, Andreas Dannenberg wrote:
> > @@ -651,15 +670,18 @@ static int bq24257_power_supply_init(struct bq24257_device *bq)
> >  	return PTR_ERR_OR_ZERO(bq->charger);
> >  }
> >  
> > -static int bq24257_pg_gpio_probe(struct bq24257_device *bq)
> > +static void bq24257_pg_gpio_probe(struct bq24257_device *bq)
> >  {
> > -	bq->pg = devm_gpiod_get_index(bq->dev, BQ24257_PG_GPIO, 0, GPIOD_IN);
> > +	bq->pg = devm_gpiod_get_optional(bq->dev, BQ24257_PG_GPIO, GPIOD_IN);
> > +
> >  	if (IS_ERR(bq->pg)) {
> > -		dev_err(bq->dev, "could not probe PG pin\n");
> > -		return PTR_ERR(bq->pg);
> > +		dev_err(bq->dev, "error probing PG pin\n");
> > +		bq->pg = NULL;
> > +		return;
> >  	}
> 
> You should handle -EPROBE_DEFER here.

Hi Sebastian. From having a quick look at the Kernel tree it seems like
this error shouldn't get exposed to the user (which it doesn't since it
would get zeroe'd out) and the error itself suggests that I should
"retry" which none of the things I looked at in the Kernel through "git
grep" seemed to do. So before making any assumptions I wanted to see if
I'm missing something or you could give me any pointers how to proceed.

Thanks,

--
Andreas Dannenberg
Texas Instruments Inc
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andreas Dannenberg Sept. 28, 2015, 3:49 p.m. UTC | #3
On Mon, Sep 28, 2015 at 07:04:12AM -0500, Andreas Dannenberg wrote:
> On Sun, Sep 27, 2015 at 10:20:26PM +0200, Sebastian Reichel wrote:
> > Hi,
> > 
> > On Fri, Sep 25, 2015 at 10:54:14AM -0500, Andreas Dannenberg wrote:
> > > @@ -651,15 +670,18 @@ static int bq24257_power_supply_init(struct bq24257_device *bq)
> > >  	return PTR_ERR_OR_ZERO(bq->charger);
> > >  }
> > >  
> > > -static int bq24257_pg_gpio_probe(struct bq24257_device *bq)
> > > +static void bq24257_pg_gpio_probe(struct bq24257_device *bq)
> > >  {
> > > -	bq->pg = devm_gpiod_get_index(bq->dev, BQ24257_PG_GPIO, 0, GPIOD_IN);
> > > +	bq->pg = devm_gpiod_get_optional(bq->dev, BQ24257_PG_GPIO, GPIOD_IN);
> > > +
> > >  	if (IS_ERR(bq->pg)) {
> > > -		dev_err(bq->dev, "could not probe PG pin\n");
> > > -		return PTR_ERR(bq->pg);
> > > +		dev_err(bq->dev, "error probing PG pin\n");
> > > +		bq->pg = NULL;
> > > +		return;
> > >  	}
> > 
> > You should handle -EPROBE_DEFER here.
> 
> Hi Sebastian. From having a quick look at the Kernel tree it seems like
> this error shouldn't get exposed to the user (which it doesn't since it
> would get zeroe'd out) and the error itself suggests that I should
> "retry" which none of the things I looked at in the Kernel through "git
> grep" seemed to do. So before making any assumptions I wanted to see if
> I'm missing something or you could give me any pointers how to proceed.

Ok after checking drivers/base/dd.c it seems like what I should be doing
here is to simply exit the probe function and pass on -EPROBE_DEFER as
the return value of the probe function, and the system would then
automatically take care of re-trying the probe later, correct? Please
let know, I want to make sure this patch series is converging into an
acceptable state.

Regards,

--
Andreas Dannenberg
Texas Instruments Inc

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sebastian Reichel Sept. 28, 2015, 4:02 p.m. UTC | #4
Hi,

On Mon, Sep 28, 2015 at 07:04:12AM -0500, Andreas Dannenberg wrote:
> On Sun, Sep 27, 2015 at 10:20:26PM +0200, Sebastian Reichel wrote:
> > On Fri, Sep 25, 2015 at 10:54:14AM -0500, Andreas Dannenberg wrote:
> > > @@ -651,15 +670,18 @@ static int bq24257_power_supply_init(struct bq24257_device *bq)
> > >  	return PTR_ERR_OR_ZERO(bq->charger);
> > >  }
> > >  
> > > -static int bq24257_pg_gpio_probe(struct bq24257_device *bq)
> > > +static void bq24257_pg_gpio_probe(struct bq24257_device *bq)
> > >  {
> > > -	bq->pg = devm_gpiod_get_index(bq->dev, BQ24257_PG_GPIO, 0, GPIOD_IN);
> > > +	bq->pg = devm_gpiod_get_optional(bq->dev, BQ24257_PG_GPIO, GPIOD_IN);
> > > +
> > >  	if (IS_ERR(bq->pg)) {
> > > -		dev_err(bq->dev, "could not probe PG pin\n");
> > > -		return PTR_ERR(bq->pg);
> > > +		dev_err(bq->dev, "error probing PG pin\n");
> > > +		bq->pg = NULL;
> > > +		return;
> > >  	}
> > 
> > You should handle -EPROBE_DEFER here.
> 
> Hi Sebastian. From having a quick look at the Kernel tree it seems like
> this error shouldn't get exposed to the user (which it doesn't since it
> would get zeroe'd out) and the error itself suggests that I should
> "retry" which none of the things I looked at in the Kernel through "git
> grep" seemed to do. So before making any assumptions I wanted to see if
> I'm missing something or you could give me any pointers how to proceed.

If you return -EPROBE_DEFER from your driver's probe function, the
driver probe will fail. In opposit to other error codes it will be
marked for retry at a later point, though. You will get
EPROBE_DEFER, if you try to access a GPIO from a not-yet initialized
GPIO controller (e.g. if you load the charger driver before the
gpio driver).

Correct handling is simple: Just forward it, making sure, that all
non-devm probed resources are correctly free'd.

-- Sebastian
diff mbox

Patch

diff --git a/drivers/power/bq24257_charger.c b/drivers/power/bq24257_charger.c
index 7bbff80..5800697 100644
--- a/drivers/power/bq24257_charger.c
+++ b/drivers/power/bq24257_charger.c
@@ -359,7 +359,26 @@  static int bq24257_get_chip_state(struct bq24257_device *bq,
 
 	state->fault = ret;
 
-	state->power_good = !gpiod_get_value_cansleep(bq->pg);
+	if (bq->pg)
+		state->power_good = !gpiod_get_value_cansleep(bq->pg);
+	else
+		/*
+		 * If we have a chip without a dedicated power-good GPIO or
+		 * some other explicit bit that would provide this information
+		 * assume the power is good if there is no supply related
+		 * fault - and not good otherwise. There is a possibility for
+		 * other errors to mask that power in fact is not good but this
+		 * is probably the best we can do here.
+		 */
+		switch (state->fault) {
+		case FAULT_INPUT_OVP:
+		case FAULT_INPUT_UVLO:
+		case FAULT_INPUT_LDO_LOW:
+			state->power_good = false;
+			break;
+		default:
+			state->power_good = true;
+		}
 
 	return 0;
 }
@@ -651,15 +670,18 @@  static int bq24257_power_supply_init(struct bq24257_device *bq)
 	return PTR_ERR_OR_ZERO(bq->charger);
 }
 
-static int bq24257_pg_gpio_probe(struct bq24257_device *bq)
+static void bq24257_pg_gpio_probe(struct bq24257_device *bq)
 {
-	bq->pg = devm_gpiod_get_index(bq->dev, BQ24257_PG_GPIO, 0, GPIOD_IN);
+	bq->pg = devm_gpiod_get_optional(bq->dev, BQ24257_PG_GPIO, GPIOD_IN);
+
 	if (IS_ERR(bq->pg)) {
-		dev_err(bq->dev, "could not probe PG pin\n");
-		return PTR_ERR(bq->pg);
+		dev_err(bq->dev, "error probing PG pin\n");
+		bq->pg = NULL;
+		return;
 	}
 
-	return 0;
+	if (bq->pg)
+		dev_dbg(bq->dev, "probed PG pin = %d\n", desc_to_gpio(bq->pg));
 }
 
 static int bq24257_fw_probe(struct bq24257_device *bq)
@@ -789,10 +811,17 @@  static int bq24257_probe(struct i2c_client *client,
 		INIT_DELAYED_WORK(&bq->iilimit_setup_work,
 				  bq24257_iilimit_setup_work);
 
-	/* we can only check Power Good status by probing the PG pin */
-	ret = bq24257_pg_gpio_probe(bq);
-	if (ret < 0)
-		return ret;
+	/*
+	 * The BQ24250 doesn't have a dedicated Power Good (PG) pin so let's
+	 * not probe for it and instead use a SW-based approach to determine
+	 * the PG state. We also use a SW-based approach for all other devices
+	 * if the PG pin is either not defined or can't be probed.
+	 */
+	if (bq->chip != BQ24250)
+		bq24257_pg_gpio_probe(bq);
+
+	if (!bq->pg)
+		dev_info(bq->dev, "using SW-based power-good detection\n");
 
 	/* reset all registers to defaults */
 	ret = bq24257_field_write(bq, F_RESET, 1);