Re: [PATCH v2 3/3] power: supply: bq24735-charger: allow chargers to share the ac-detect gpio

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




[of course I forgot to actually add gpio people, let's try again]

On Wed, Dec 14, 2016 at 05:59:21PM +0100, Sebastian Reichel wrote:
> Hi,
> 
> On Wed, Dec 14, 2016 at 12:56:45AM +0100, Peter Rosin wrote:
> > If several parallel bq24735 chargers have their ac-detect gpios wired
> > together (or if only one of the parallel bq24735 chargers have its
> > ac-detect pin wired to a gpio, and the others are assumed to react the
> > same), then all driver instances need to check the same gpio. But the
> > gpio subsystem does not allow sharing gpios, so handle that locally.
> 
> Adding GPIO subsystem people to see if they can come up with
> something in the gpiod API for this usecase.
> 
> > However, only do this for the polling case, sharing is not supported if
> > the ac detection is handled with interrupts.
> 
> Why? I guess you only added the gpio polling stuff for the shared
> gpio feature, so we can skip the gpio polling if we add shared irq
> support instead?
> 
> > Signed-off-by: Peter Rosin <peda@xxxxxxxxxx>
> > ---
> >  drivers/power/supply/bq24735-charger.c | 111 +++++++++++++++++++++++++++++----
> >  1 file changed, 100 insertions(+), 11 deletions(-)
> > 
> > diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c
> > index f45876927676..c2403c4d5ece 100644
> > --- a/drivers/power/supply/bq24735-charger.c
> > +++ b/drivers/power/supply/bq24735-charger.c
> > @@ -25,6 +25,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/module.h>
> >  #include <linux/of.h>
> > +#include <linux/of_gpio.h>
> >  #include <linux/gpio/consumer.h>
> >  #include <linux/power_supply.h>
> >  #include <linux/slab.h>
> > @@ -43,12 +44,24 @@
> >  #define BQ24735_MANUFACTURER_ID		0xfe
> >  #define BQ24735_DEVICE_ID		0xff
> >  
> > +struct bq24735;
> > +
> > +struct bq24735_shared {
> > +	struct list_head		list;
> > +	struct bq24735			*owner;
> > +	struct gpio_desc		*status_gpio;
> > +};
> > +
> > +static DEFINE_MUTEX(shared_lock);
> > +static LIST_HEAD(shared_list);
> > +
> >  struct bq24735 {
> >  	struct power_supply		*charger;
> >  	struct power_supply_desc	charger_desc;
> >  	struct i2c_client		*client;
> >  	struct bq24735_platform		*pdata;
> >  	struct mutex			lock;
> > +	struct bq24735_shared		*shared;
> >  	struct gpio_desc		*status_gpio;
> >  	struct delayed_work		poll;
> >  	u32				poll_interval;
> > @@ -346,6 +359,75 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
> >  	return pdata;
> >  }
> >  
> > +static struct gpio_desc *bq24735_get_status_gpio(struct bq24735 *charger)
> > +{
> > +	struct device *dev = &charger->client->dev;
> > +	struct bq24735_shared *shared;
> > +	int gpio;
> > +	enum of_gpio_flags flags;
> > +	int active_low;
> > +	struct list_head *pos;
> > +
> > +	if (of_property_read_bool(dev->of_node, "ti,ac-detect-gpios"))
> > +		gpio = of_get_named_gpio_flags(dev->of_node,
> > +					       "ti,ac-detect-gpios", 0, &flags);
> > +	else if (of_property_read_bool(dev->of_node, "ti,ac-detect-gpio"))
> > +		gpio = of_get_named_gpio_flags(dev->of_node,
> > +					       "ti,ac-detect-gpio", 0, &flags);
> > +	else
> > +		return NULL;
> > +
> > +	if (!gpio_is_valid(gpio))
> > +		return ERR_PTR(gpio);
> > +	active_low = flags & OF_GPIO_ACTIVE_LOW;
> > +
> > +	mutex_lock(&shared_lock);
> > +	list_for_each(pos, &shared_list) {
> > +		shared = list_entry(pos, struct bq24735_shared, list);
> > +		if (gpio != desc_to_gpio(shared->status_gpio))
> > +			continue;
> > +		if (!active_low ^ !gpiod_is_active_low(shared->status_gpio))
> > +			continue;
> > +
> > +		get_device(&shared->owner->client->dev);
> > +		dev_dbg(dev, "sharing gpio with %s\n",
> > +			shared->owner->pdata->name);
> > +		charger->shared = shared;
> > +		mutex_unlock(&shared_lock);
> > +		return shared->status_gpio;
> > +	}
> > +
> > +	shared = devm_kzalloc(dev, sizeof(*shared), GFP_KERNEL);
> > +	if (!shared) {
> > +		mutex_unlock(&shared_lock);
> > +		return ERR_PTR(-ENOMEM);
> > +	}
> > +	shared->owner = charger;
> > +	shared->status_gpio = gpiod_get(dev, "ti,ac-detect", GPIOD_IN);
> > +	if (!IS_ERR(shared->status_gpio)) {
> > +		charger->shared = shared;
> > +		list_add(&shared->list, &shared_list);
> > +	}
> > +	mutex_unlock(&shared_lock);
> > +
> > +	return shared->status_gpio;
> > +}
> > +
> > +static void bq24735_put_status_gpio(struct bq24735 *charger)
> > +{
> > +	if (!charger->shared)
> > +		return;
> > +
> > +	mutex_lock(&shared_lock);
> > +	if (charger->shared->owner != charger) {
> > +		put_device(&charger->shared->owner->client->dev);
> > +	} else {
> > +		list_del(&charger->shared->list);
> > +		gpiod_put(charger->shared->status_gpio);
> > +	}
> > +	mutex_unlock(&shared_lock);
> > +}
> > +
> >  static int bq24735_charger_probe(struct i2c_client *client,
> >  				 const struct i2c_device_id *id)
> >  {
> > @@ -402,9 +484,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
> >  
> >  	i2c_set_clientdata(client, charger);
> >  
> > -	charger->status_gpio = devm_gpiod_get_optional(&client->dev,
> > -						       "ti,ac-detect",
> > -						       GPIOD_IN);
> > +	charger->status_gpio = bq24735_get_status_gpio(charger);
> >  	if (IS_ERR(charger->status_gpio)) {
> >  		ret = PTR_ERR(charger->status_gpio);
> >  		dev_err(&client->dev, "Getting gpio failed: %d\n", ret);
> > @@ -416,28 +496,30 @@ static int bq24735_charger_probe(struct i2c_client *client,
> >  		if (ret < 0) {
> >  			dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
> >  				ret);
> > -			return ret;
> > +			goto out;
> >  		} else if (ret != 0x0040) {
> >  			dev_err(&client->dev,
> >  				"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
> > -			return -ENODEV;
> > +			ret = -ENODEV;
> > +			goto out;
> >  		}
> >  
> >  		ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
> >  		if (ret < 0) {
> >  			dev_err(&client->dev, "Failed to read device id : %d\n", ret);
> > -			return ret;
> > +			goto out;
> >  		} else if (ret != 0x000B) {
> >  			dev_err(&client->dev,
> >  				"device id mismatch. 0x000b != 0x%04x\n", ret);
> > -			return -ENODEV;
> > +			ret = -ENODEV;
> > +			goto out;
> >  		}
> >  	}
> >  
> >  	ret = bq24735_config_charger(charger);
> >  	if (ret < 0) {
> >  		dev_err(&client->dev, "failed in configuring charger");
> > -		return ret;
> > +		goto out;
> >  	}
> >  
> >  	/* check for AC adapter presence */
> > @@ -445,7 +527,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
> >  		ret = bq24735_enable_charging(charger);
> >  		if (ret < 0) {
> >  			dev_err(&client->dev, "Failed to enable charging\n");
> > -			return ret;
> > +			goto out;
> >  		}
> >  	}
> >  
> > @@ -455,7 +537,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
> >  		ret = PTR_ERR(charger->charger);
> >  		dev_err(&client->dev, "Failed to register power supply: %d\n",
> >  			ret);
> > -		return ret;
> > +		goto out;
> >  	}
> >  
> >  	if (client->irq) {
> > @@ -470,7 +552,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
> >  			dev_err(&client->dev,
> >  				"Unable to register IRQ %d err %d\n",
> >  				client->irq, ret);
> > -			return ret;
> > +			goto out;
> >  		}
> >  	} else if (charger->status_gpio) {
> >  		ret = of_property_read_u32(client->dev.of_node,
> > @@ -487,6 +569,11 @@ static int bq24735_charger_probe(struct i2c_client *client,
> >  	}
> >  
> >  	return 0;
> > +
> > +out:
> > +	bq24735_put_status_gpio(charger);
> > +
> > +	return ret;
> >  }
> >  
> >  static int bq24735_charger_remove(struct i2c_client *client)
> > @@ -496,6 +583,8 @@ static int bq24735_charger_remove(struct i2c_client *client)
> >  	if (charger->poll_interval)
> >  		cancel_delayed_work_sync(&charger->poll);
> >  
> > +	bq24735_put_status_gpio(charger);
> > +
> >  	return 0;
> >  }
> >  
> > -- 
> > 2.1.4
> > 


Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux