[i2c] [RFC PATCH 3/8] Add PCA9536 4 bit I2C GPIO extender support to the pca9539 GPIO driver

David Brownell david-b at pacbell.net
Thu Jan 31 05:52:03 CET 2008


On Wednesday 30 January 2008, eric miao wrote:
> I like this patch, overall looks ok. See my comments below.

I basically like it, but I'd still like to see some changes.  :)

I'd split this patch into two parts (feature addition, and renaming),
and use simpler chip type handling.  Re that latter, in 2.6.26 there
will be an i2c_device_id struct:

  struct i2c_device_id {
        char name[I2C_NAME_SIZE];
        kernel_ulong_t driver_data;     /* Data private to the driver */
  };

A little planning done now will make it easy to use that scheme.
First, don't add a type field to the platform_data; that's what
the i2c_client.name is for.  Then just map those strings to the
number of GPIOs (eventually just use driver_data), and everything
else follows from there.


> > --- a/drivers/gpio/Kconfig
> > +++ b/drivers/gpio/Kconfig
> > @@ -27,15 +27,15 @@ config DEBUG_GPIO
> >
> >  comment "I2C GPIO expanders:"
> >
> > -config GPIO_PCA9539
> > -       tristate "PCA9539 16-bit I/O port"
> > +config GPIO_PCA953X
> > +       tristate "PCA953X I/O port"

"Ports"

> >         depends on I2C
> >         help
> > -         Say yes here to support the PCA9539 16-bit I/O port. These
> > -         parts are made by NXP and TI.
> > +         Say yes here to support PCA9539 16-bit and PCA9536 4-bit I/O ports.

This should IMO list the '38 (8-bit) and '37 (4-bit) parts too.
Same register layout as the '36 (4-bit).  Otherwise the "x" seems
misleading...


> > diff --git a/drivers/gpio/pca9539.c b/drivers/gpio/pca953x.c
> > similarity index 67%
> > rename from drivers/gpio/pca9539.c
> > rename to drivers/gpio/pca953x.c

I'd prefer to see the new feature and the renaming be separate patches.


> > -#define NR_PCA9539_GPIOS       16
> > +struct pca953x_desc {
> > +       unsigned int gpios;
> > +       unsigned int input;
> > +       unsigned int output;
> > +       unsigned int invert;
> > +       unsigned int direction;
> > +};
> 
> I guess the register address can be inferred either from the number
> of GPIOs or a single member field of "shift" may be sufficient.

Yes, inferring that would be simpler.  The number of GPIOs is a
function of the particular chip, and register offsets are 0/1/2/3
except for the 16-GPIO part where they're twice that.

What I'd do is save those four offsets directly in pca953x_chip,
initialized near when gpio_chip.ngpio is set up and with no need
for a separate "desc" type or table.  Eventually there'd be:

	struct i2c_device_id chips [] = {
		{ "pca9536", 4, },
		{ "pca9537", 4, },
		{ "pca9538", 8, },
		{ "pca9539", 16, },
	};
	MODULE_DEVICE_TABLE(i2c, chips);

Meanwhile, the equivalent of that table can come from a few strcmp()
tests in the probe() logic -- like what you already have, except
not using a "desc" type.


> > -static int pca9539_init_gpio(struct pca9539_chip *chip)
> > +static int pca953x_init_gpio(struct pca953x_chip *chip)
> >  {
> >         struct gpio_chip *gc;
> >
> >         gc = &chip->gpio_chip;
> >
> > -       gc->direction_input  = pca9539_gpio_direction_input;
> > -       gc->direction_output = pca9539_gpio_direction_output;
> > -       gc->get = pca9539_gpio_get_value;
> > -       gc->set = pca9539_gpio_set_value;
> > +       gc->direction_input  = pca953x_gpio_direction_input;
> > +       gc->direction_output = pca953x_gpio_direction_output;
> > +       gc->get = pca953x_gpio_get_value;
> > +       gc->set = pca953x_gpio_set_value;
> >
> >         gc->base = chip->gpio_start;
> > -       gc->ngpio = NR_PCA9539_GPIOS;
> > -       gc->label = "pca9539";
> > +       gc->ngpio = chip->desc->gpios;

I'd expect "desc" to vanish, and ngpio to be an input to this function
(see below).  Then ngpio could be used to choose the values to stuff
into chip->{input,output,invert,direction} register offsets.


> > +       gc->label = "pca953x";

Why not just set gc->label to be chip->client->name?

Might as well have /sys/kernel/debug/gpio output be
that little bit more useful.  And save the space that
would otherwise be wasted by that string.  :)


> >
> >         return gpiochip_add(gc);
> >  }
> >
> > -static int __devinit pca9539_probe(struct i2c_client *client)
> > +static int __devinit pca953x_probe(struct i2c_client *client)
> >  {
> > -       struct pca9539_platform_data *pdata;
> > -       struct pca9539_chip *chip;
> > +       struct pca953x_platform_data *pdata;
> > +       struct pca953x_chip *chip;
> >         int ret;
> > +       int variant;
> >
> >         pdata = client->dev.platform_data;
> >         if (pdata == NULL)
> >                 return -ENODEV;
> >
> > -       chip = kzalloc(sizeof(struct pca9539_chip), GFP_KERNEL);
> > +       if (!strcmp("pca9539", pdata->name))

Use client->name instead; there's no need to change pdata.


> > +               variant = PCA9539;
> > +       else if (!strcmp("pca9536", pdata->name))
> > +               variant = PCA9536;
> > +       else
> > +               return -ENODEV;
> > +
> 
> I prefer integer here more than string, for simplicity and efficiency.

Actually I'd use strings right now, and not change pdata at all.  But
compare client->name, using that to figure out how many GPIOs.

When, later, an i2c_device_id is passed in, the driver can get the
number of GPIOs handed to it directly ... and won't need to worry
about that ENODEV case.



> > --- a/include/asm-generic/gpio.h
> > +++ b/include/asm-generic/gpio.h
> > @@ -16,6 +16,10 @@
> >  #define ARCH_NR_GPIOS          256
> >  #endif
> >
> > +#ifndef NO_GPIO
> > +#define NO_GPIO                        ((unsigned int)-1)
> > +#endif
> > +
> 
> I don't understand this.

Me either; *ANY* negative number is invalid as a GPIO number,
not just "-1"...


> > --- a/include/linux/i2c/pca9539.h
> > +++ b/include/linux/i2c/pca953x.h
> > @@ -1,9 +1,12 @@
> > -/* platform data for the PCA9539 16-bit I/O expander driver */
> > +/* platform data for the PCA953x I/O expander driver */
> >
> > -struct pca9539_platform_data {
> > +struct pca953x_platform_data {
> >         /* number of the first GPIO */
> >         unsigned        gpio_base;
> >
> > +       /* chip variant. Currently supported "pca9536" and "pca9539" */
> > +       const char      *name;
> > +

That's not needed; i2c_client.name should identify the chip.

> >         /* initial polarity inversion setting */
> >         uint16_t        invert;
> >
> > 



More information about the i2c mailing list