OpenWrt Forum Archive

Topic: register pca953x gpio extender

The content of this topic has been archived on 14 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

I have some troubles to get my PCA9555 gpio extender registered as something like /sys/class/gpio/gpiochipX. The I²C-adapter is the i2c-tiny-usb, connected to a TL-WR1043ND. While other devices can be added through sysfs without any problems like this:

root@OpenWrt:/# echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device 
root@OpenWrt:/# dmesg | tail
i2c i2c-1: Added multiplexed i2c bus 2
i2c i2c-1: Added multiplexed i2c bus 3
i2c i2c-1: Added multiplexed i2c bus 4
i2c i2c-1: Added multiplexed i2c bus 5
i2c i2c-1: Added multiplexed i2c bus 6
i2c i2c-1: Added multiplexed i2c bus 7
i2c i2c-1: Added multiplexed i2c bus 8
i2c i2c-1: Added multiplexed i2c bus 9
pca954x 1-0070: registered 8 multiplexed busses for I2C switch pca9548
i2c i2c-1: new_device: Instantiated device pca9548 at 0x70

it just doesn't work with the PCA9555:

root@OpenWrt:/# echo pca9555 0x21 > /sys/bus/i2c/devices/i2c-1/new_device 
root@OpenWrt:/# dmesg | tail
pca953x 1-0021: no platform data
pca953x: probe of 1-0021 failed with error -22
i2c i2c-1: new_device: Instantiated device pca9555 at 0x21

My researches so far got me to the point, that the platform data (as indicated) needs to be extended. So I added the following lines to my arch/mips/ar71xx/mach-tl-wr1043nd.c:

#include <linux/i2c.h>
#include <linux/i2c/pca953x.h>
static struct pca953x_platform_data pca9555_0 = {
    .gpio_base = 32,
};

static struct i2c_board_info __initdata i2c_tiny_board_info[] = {
  {
    I2C_BOARD_INFO("pca9555",0x21),
    .platform_data = &pca9555_0,
  }
};
#endif

static struct platform_device i2c_tiny_usb_device = {
  .name    = "i2c-tiny-usb",
  .id    = 0,
};
static void __devinit i2c_tiny_usb_init(void)
{
 i2c_register_board_info(0,i2c_tiny_board_info, ARRAY_SIZE(i2c_tiny_board_info));
 platform_device_register(&i2c_tiny_usb_device); 
};

And in the __init section:

i2c_tiny_usb_init();

It compiles without any issues, but now my I²C-adapter is registered as i2c-1 (instead of i2c-0) and the PCA9555 is not registered as gpiochip1.
How can I tell the kernel to bind the PCA9555 to the I²C-bus provided by the i2c-tiny-usb (or later on to one of the switched busses provided by a PCA9548 mux connected inbetween)? Or is there any other way to do a userspace configuration at runtime?

To whom it may concern, I've got it working someway:
After inspecting the source code i2c-tiny-usb.c I realized that the driver calls i2c_add_adapter(&dev->adapter) to register the i2c-adapter. That function will check which buses are already declared (obviously including the board-info stuff) and pick the next free number for the bus. So here is my change:

//    i2c_add_adapter(&dev->adapter);
dev->adapter.nr = 4;
i2c_add_numbered_adapter(&dev->adapter);

Which means the original function is commented out, the desired bus number is declared (4) and the function to register a bus of a specified number is called.
Now, to get it working, my changes of mach-tl-wr1043nd.c look like this:

#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/* PCA9555 */
static struct pca953x_platform_data pca9555_0 = {
    .gpio_base = 32,
};
static struct i2c_board_info __initdata i2c_tiny_board_info[] = {
  {
    I2C_BOARD_INFO("pca9555",0x21),
    .platform_data = &pca9555_0,
  }
};
#endif
static void __devinit i2c_tiny_usb_init(void)
{
i2c_register_board_info(4,i2c_tiny_board_info, ARRAY_SIZE(i2c_tiny_board_info));
};

and in __init section, still:

    i2c_tiny_usb_init();

As a result, I now have a /sys/class/gpio/gpiochip32. First attempt to export gpio32 also works fine.
Next step: configuring the mux. Any help is highly appreciated.

Got it working now. After crawling through the pca953x.c code to make it work without providing platform data I realized that the same issue has been fixed in pcf857x driver last year. So I applied similar changes, setting sane default values for gpiobase (-1) and invert (0) and avoiding access to pdata-children. See if my patches will make it into the main kernel.
So far, I got a PCA9555 and a PCF8575, hooked up on a PCA9548 I2C-switch, dynamically registered at runtime on my desktop pc as /sys/class/gpio/gpiochip240 respectively gpiochip224. Mission accomplished :-)
BTW: no need to change the I2C bus drivers (i2c-tiny-usb/i2c-mux) any more.

(Last edited by MBS on 21 Jun 2011, 22:00)

MBS, was wondering if you had a link to your patches at all? Rather not go through the motions when you've done some hard work.

well, the patch got into kernel 3.1. Although, from what I've seen so far, there has not been any approach yet to update openwrt trunk to that new kernel. So I'd say, get the recent source file here: https://github.com/torvalds/linux/blob/ … -pca953x.c
copy it to your kernel build dir (rename it to pca953x.c) and build your kernel. Worked for me during development.

ah, nice work - thanks!

Hi All,

I am facing a problem with GPIO PCA9555 chip registering with i2c(SMBus) in intel Advantech PCM9362 board.


#echo pca9555 ox20 >/sys/bus/i2c/devices/i2c-0/new_device

after executing the command, we are getting the debug messgaes in the pca953x probe function:

pca953x 0-0020: probe
client address= 20
clinet name= pca9555
adapter name= SMBus I801 dapter at 0400
device name= pca953x
bus type= i2c
IRQ= 0

pca953x 0-0020: no platform data
pca953x: probe of 0-0020 failed with error -22

as u explained in ur mails PCA9555 chip info added in the arch/mips/ar71xx/mach-tl-wr1043nd.c:

but we are not having any info abt our board in the kernel directory, can you please explain me the steps
where can i include the header files & the code as you mentioned in ur mails.

my arch/x86/ directory contents are as below,

boot        configs  ia32     Kbuild   Kconfig.cpu    kernel  lguest  Makefile         math-emu  modules.builtin  oprofile  platform  tools  video
built-in.o  crypto   include  Kconfig  Kconfig.debug  kvm     lib     Makefile_32.cpu  mm        modules.order    pci       power     vdso   xen


kind reagrds,
Manju

Seems like you are running a kernel prior to 3.1. Best way is to upgrade your kernel to at least 3.1. If that is not possible, you can still take the gpio-pca953x.c file from either git (link in my previous post) or any recent kernel tree and copy/rename it to your kernel tree as pca953x.c for custom compilation.

thanks for the info, i will try with kernel 3.1.

As per your guideline  i am using 3.1.10 kernel version after also i am getting same problem as follows


In pca953x_probe function
i am not getting any pdata values from the following statement,getting NULL
pdata = client->dev.platform_data;
when pdata getting NULL it enter into else part trying to getting pdata values from
pdata=pca953x_get_alt_pdata(client);
when control transfer to the pca953x_get_alt_pdata() function in this function
  node = client->dev.of_node;
here node is become NULL thats why it is coming out that function its not getting any pdata values.
Plz tell me where i am getting stuck in this driver.

are you using openfirmware/devicetree?

I am fresher to linux device driver if dont mind plz can you explain about  openfirmware/devicetree?

There are two versions of that pca953x_get_alt_pdata() function - one (starting line 649) gets compiled if openfirmware is enabled (#ifdef CONFIG_OF_GPIO in line 544), the other one (starting line 577) if it is disabled. My devices don't have openfirmware, so I'm not very experienced with openfirmware/devicetree related topics.

actually my control going into the pca953x_get_alt_pdata() function  because as you told #ifdef CONFIG_OF_GPIO openfirmware is enabled.In said the pca953x_get_alt_pdata() function i am getting node equal to  NULL then returns from pca953x_get_alt_pdata() function.

   node = client->dev.of_node;
        printk("i am in pdata alt dta\n");

        if (node == NULL)
        {
                printk("node is null\n");
                return;
}


Can you guide me How to solve the issue its very urgent.

Well, I see two options:
- proper solution: create a node in your openfirmware for the gpio chip (I have no experience with that)
- dirty hack: change #ifdef CONFIG_OF_GPIO to #ifndef CONFIG_OF_GPIO in this case

(Last edited by MBS on 27 Feb 2012, 19:18)

The discussion might have continued from here.