This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Interrupt with GPIO signal using GPIO expander

Other Parts Discussed in Thread: TPS40400, PMP, TMP102

Hello,

In our system, we have a GPIO expander which is used to interface a rotating switch. Whenever there is a change in rotating switch position it suposed to generate an interrupt, so that we can read the position. The GPIO expander is assigned with a base address of 138. It returns with error from gpio_to_interrupt() function with error as "unable to get irq number for GPIO, error -22"

How to configure this GPIO expander? I could able to detect the change in position of rotating switch without interrupt but need to scan for the change in position. Is there any other method to make it interrupt based instead of waiting for the change in position of the rotating switch?

Thanks.

 

  • Hi Jebaraj,
    What GPIO IO expander are you using ?
    Did you enable this IO expander in linux kernel ?
  • Hi Shankari,
    We are using PCA9671 expander. I could able to toggle the GPIO pins.
    Then I have tried to define the GPIO pins from this expander as gpio_buttons in board file. I have rebuilt the uImage. It is detecting the expander IC and the GPIO pins. But gpio-keys driver returns "unable to get irq number for GPIO error -r" error.

    Thanks.
  • Hi,
    Do you want to make one GPIO as input from IO expander ?
    Or need to make one interrupt for whole IO expander GPIO pins (if anything toggling on those GPIOs)?
  • Hi,
    My requirement is, I have to use all 16 GPIO from the expander as input and need to register interrupt for all 16 pins (so 16 interrupts).
  • Hello,
    We are using DM8168.
    We have used the following structure in board file to use the buttons.

    static struct gpio_keys_button gpio_buttons[] = {
    {
    .code = KEY_0,
    .gpio = 64,
    .desc = "user1",
    .wakeup = 1,
    },
    {
    .code = KEY_1,
    .gpio = 65,
    .desc = "user2",
    .wakeup = 1,
    },
    {
    .code = KEY_2,
    .gpio = 66,
    .desc = "user3",
    .wakeup = 1,
    },

    all 16 buttons are updated in this structure.

    static struct gpio_keys_platform_data gpio_key_info = {
    .buttons = gpio_buttons,
    .nbuttons = ARRAY_SIZE(gpio_buttons),
    };

    static struct platform_device keys_gpio = {
    .name = "gpio-keys",
    .id = -1,
    .dev = {
    .platform_data = &gpio_key_info,
    },
    };

    static struct platform_device *ti8168_devices[] __initdata = {
    &keys_gpio,
    };

    In booting time it returns with "gpio-keys gpio-keys: Unable to get irq number for GPIO 64, error -6"

    Any suggestion?

    Thanks.
  • Hi,
    Can you please provide bootup log ?
    I think, you are doing this initialization and registering IRQ before PCA9671 driver comes up.
    After PCA9671 driver initialization only you would get GPIO 64, 65 and 66 right.
  • Thank you for your efforts. I have attached the bootlog. Please go through it.

    Starting kernel ...

    Linux version 2.6.37 (jebaraj@IT0026-PC) (gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203) ) #78 Tue Oct 13 14:54:05 IST 2015
    CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c53c7f
    CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
    Machine: ti8168toii
    vram size = 20971520 at 0x0
    ti81xx_reserve: ### Reserved DDR region @8ff00000
    reserved size = 20971520 at 0x0
    FB: Reserving 20971520 bytes SDRAM for VRAM
    Memory policy: ECC disabled, Data cache writeback
    OMAP chip is TI8168 2.1
    Built 1 zonelists in Zone order, mobility grouping on. Total pages: 59648
    Kernel command line: mem=256M console=ttyO2,115200n8 root=/dev/nfs rw rootwait rootpath=/home/jebaraj/dm8168/DVRRDK_03.50.00.05/target/rfs_816=
    PID hash table entries: 1024 (order: 0, 4096 bytes)
    Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
    Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
    Memory: 234MB 1MB = 235MB total
    Memory: 233452k/233452k available, 28692k reserved, 0K highmem
    Virtual kernel memory layout:
    vector : 0xffff0000 - 0xffff1000 ( 4 kB)
    fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
    DMA : 0xffc00000 - 0xffe00000 ( 2 MB)
    vmalloc : 0xd0800000 - 0xf8000000 ( 632 MB)
    lowmem : 0xc0000000 - 0xd0000000 ( 256 MB)
    pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
    modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
    .init : 0xc0008000 - 0xc0040000 ( 224 kB)
    .text : 0xc0040000 - 0xc0454000 (4176 kB)
    .data : 0xc0454000 - 0xc048f240 ( 237 kB)
    SLUB: Genslabs=11, HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
    NR_IRQS:375
    IRQ: Found an INTC at 0xfa200000 (revision 5.0) with 128 interrupts
    Total of 128 interrupts on 1 active controller
    GPMC revision 6.0
    Trying to install interrupt handler for IRQ368
    Trying to install interrupt handler for IRQ369
    Trying to install interrupt handler for IRQ370
    Trying to install interrupt handler for IRQ371
    Trying to install interrupt handler for IRQ372
    Trying to install interrupt handler for IRQ373
    Trying to install interrupt handler for IRQ374
    Trying to install type control for IRQ375
    Trying to set irq flags for IRQ375
    OMAP clockevent source: GPTIMER1 at 27000000 Hz
    Console: colour dummy device 80x30
    Calibrating delay loop... 1199.30 BogoMIPS (lpj=5996544)
    pid_max: default: 32768 minimum: 301
    Security Framework initialized
    Mount-cache hash table entries: 512
    CPU: Testing write buffer coherency: ok
    devtmpfs: initialized
    TI81XX: Map 0x8ff00000 to 0xfe500000 for dram barrier
    TI81XX: Map 0x40300000 to 0xfe600000 for sram barrier
    omap_voltage_early_init: voltage driver support not added
    regulator: core version 0.5
    regulator: dummy:
    NET: Registered protocol family 16
    omap_voltage_domain_lookup: Voltage driver init not yet happened.Faulting!
    omap_voltage_add_dev: VDD specified does not exist!
    OMAP GPIO hardware version 0.1
    OMAP GPIO hardware version 0.1
    omap_mux_init: Add partition: #1: core, flags: 0
    _omap_mux_get_by_name: Could not find signal i2c2_scl.i2c2_scl
    _omap_mux_get_by_name: Could not find signal i2c2_sda.i2c2_sda
    registered ti816x_sr device
    Cannot clk_get ck_32
    pm_dbg_init: only OMAP3 supported
    registered ti81xx_vpss device
    registered ti81xx_vidout device
    registered ti81xx on-chip HDMI device
    registered ti81xx_fb device
    bio: create slab <bio-0> at 0
    SCSI subsystem initialized
    usbcore: registered new interface driver usbfs
    usbcore: registered new interface driver hub
    usbcore: registered new device driver usb
    omap_i2c omap_i2c.1: bus 1 rev4.0 at 100 kHz
    regulator: pmbus_vr: 800 <--> 1050 mV at 1000 mV
    regulator: tps40400 probe done.
    omap_i2c omap_i2c.2: bus 2 rev4.0 at 100 kHz

    pcf857x 2-0027: gpios 64..79 on a pca9671
    Switching to clocksource gp timer
    NET: Registered protocol family 2
    IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
    TCP established hash table entries: 8192 (order: 4, 65536 bytes)
    TCP bind hash table entries: 8192 (order: 3, 32768 bytes)
    TCP: Hash tables configured (established 8192 bind 8192)
    TCP reno registered
    UDP hash table entries: 256 (order: 0, 4096 bytes)
    UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
    NET: Registered protocol family 1
    RPC: Registered udp transport module.
    RPC: Registered tcp transport module.
    RPC: Registered tcp NFSv4.1 backchannel transport module.
    NetWinder Floating Point Emulator V0.97 (double precision)
    PMU: registered new PMU device of type 0
    omap-iommu omap-iommu.0: ducati registered
    omap-iommu omap-iommu.1: sys registered
    JFFS2 version 2.2. (NAND) �© 2001-2006 Red Hat, Inc.
    msgmni has been set to 455
    io scheduler noop registered
    io scheduler deadline registered
    io scheduler cfq registered (default)
    Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
    enter max14830 init
    Enter max14830 probe
    Enter max14830_1 init
    Enter max14830_1 probe
    Enter max14830_2 init
    Enter max14830_2 probe
    omap_uart.0: ttyO0 at MMIO 0x48020000 (irq = 72) is a OMAP UART0
    omap_uart.1: ttyO1 at MMIO 0x48022000 (irq = 73) is a OMAP UART1
    omap_uart.2: ttyO2 at MMIO 0x48024000 (irq = 74) is a OMAP UART2
    console [ttyO2] enabled
    brd: module loaded
    loop: module loaded
    ad_dpot 2-002f: ad5272 1024-Position Digital Potentiometer registered
    at24 2-0050: 32768 byte 24c256 EEPROM (writable)
    ahci probe: devid name is ahci
    ahci CAP register dump =0x6726ff81
    Modified ahci CAP register dump =0x6f26ff81
    ahci ahci.0: forcing PORTS_IMPL to 0x3
    ahci: SSS flag set, parallel bus scan disabled
    ahci ahci.0: AHCI 0001.0100 32 slots 2 ports 3 Gbps 0x3 impl platform mode
    ahci ahci.0: flags: ncq sntf stag pm led clo only pmp pio slum part ccc
    scsi0 : ahci_platform
    scsi1 : ahci_platform
    ata1: SATA max UDMA/133 mmio [mem 0x4a140000-0x4a150fff] port 0x100 irq 16
    ata2: SATA max UDMA/133 mmio [mem 0x4a140000-0x4a150fff] port 0x180 irq 16
    omap2-nand driver initializing
    ONFI flash detected
    ONFI param page 0 valid
    NAND device: Manufacturer ID: 0x2c, Chip ID: 0xd3 (Micron NAND 1GiB 3,3V 8-bit)
    Creating 8 MTD partitions on "omap2-nand.0":
    0x000000000000-0x000000260000 : "U-Boot"
    0x000000260000-0x000000280000 : "U-Boot Env"
    0x000000280000-0x0000006c0000 : "Kernel"
    0x0000006c0000-0x0000196c0000 : "File System"
    0x0000196c0000-0x000019b00000 : "Secondary Kernel"
    0x000019b00000-0x000032b00000 : "Secondary File System"
    0x000032b00000-0x000032f40000 : "Configuration"
    0x000032f40000-0x000040000000 : "Reserved"
    davinci_mdio davinci_mdio.0: davinci mdio revision 1.6
    davinci_mdio davinci_mdio.0: detected phy mask ffffff7f
    davinci_mdio.0: probed
    davinci_mdio davinci_mdio.0: phy[7]: device 0:07, driver unknown
    mice: PS/2 mouse device common for all mice
    gpio-keys gpio-keys: Unable to get irq number for GPIO 64, error -6
    i2c /dev entries driver
    tmp102 1-0049: initialized
    htu21 2-0040: initialized
    OMAP Watchdog Timer Rev 0x00: initial timeout 60 sec
    usbcore: registered new interface driver usbhid
    usbhid: USB HID core driver
    notify_init : notify drivercreated for remote proc id 2 at physical Address 0xbee00000
    Netfilter messages via NETLINK v0.30.
    ip_tables: (C) 2000-2006 Netfilter Core Team
    TCP cubic registered
    NET: Registered protocol family 17
    VFP support v0.3: implementor 41 architecture 3 part 30 variant c rev 3
    omap_voltage_late_init: Voltage driver support not added
    Power Management for TI81XX.
    smartreflex smartreflex: Driver initialized
    drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
    ata1: SATA link down (SStatus 0 SControl 300)
    ata2: SATA link down (SStatus 0 SControl 300)
    net eth0: attached PHY driver [Generic PHY] (mii_bus:phy_addr=0:07, id=221612)
    IP-Config: Complete:
    device=eth0, addr=192.168.1.125, mask=255.255.255.0, gw=192.168.1.1,
    host=192.168.1.125, domain=, nis-domain=(none),
    bootserver=192.168.1.60, rootserver=192.168.1.60, rootpath=
    Waiting 5sec before mounting root device...
    PHY: 0:07 - Link is Up - 100/Full
    VFS: Mounted root (nfs filesystem) on device 0:14.
    devtmpfs: mounted
    udevd (74): /proc/74/oom_adj is deprecated, please use /proc/74/oom_score_adj instead.
    Root filesystem already rw, not remounting
    Caching udev devnodes
    Populating dev cachemv: cannot rename '/tmp/devices': No such file or directory
    ALSA: Restoring mixer settings...
    /usr/sbin/alsactl: load_state:1625: No soundcards found...
    NOT configuring network interfaces: / is an NFS mount
    hwclock: can't open '/dev/misc/rtc': No such file or directory
    INIT: Entering runlevel: 5
    Starting system message bus: dbus.
    Starting telnet daemon.
    Starting syslogd/klogd: done
    Starting thttpd.

    Thanks.
  • Hi Jebaraj,

    You can use those IO expander GPIOs at run time only.

    Also you can do this while IO expander initialization.

    You can refer to the following board for reference.
    arch/arm/mach-davinci/board-da850-evm.c

    I have modified and it may need some more modification as per your board.

    #define KEYS_DEBOUNCE_MS 10

    #define GPIO_KEYS_POLL_MS 200

    #define IO_EXPANDER 16

    static const char const *dm8168_evm_ui_exp[] = {
    [DA850_EVM_UI_EXP_SEL_C] = "sel_c",
    [DA850_EVM_UI_EXP_SEL_B] = "sel_b",
    [DA850_EVM_UI_EXP_SEL_A] = "sel_a",
    [DA850_EVM_UI_EXP_PB8] = "pb8",
    [DA850_EVM_UI_EXP_PB7] = "pb7",
    [DA850_EVM_UI_EXP_PB6] = "pb6",
    [DA850_EVM_UI_EXP_PB5] = "pb5",
    [DA850_EVM_UI_EXP_PB4] = "pb4",
    [DA850_EVM_UI_EXP_PB3] = "pb3",
    [DA850_EVM_UI_EXP_PB2] = "pb2",
    [DA850_EVM_UI_EXP_PB1] = "pb1",
    };


    static struct gpio_keys_button dm8168_evm_ui_keys[] = {
    [0 ... IO_EXPANDER - 1] = {
    .type = EV_KEY,
    .active_low = 1,
    .wakeup = 0,
    .debounce_interval = KEYS_DEBOUNCE_MS,
    .code = -1, /* assigned at runtime */
    .gpio = -1, /* assigned at runtime */
    .desc = NULL, /* assigned at runtime */
    },
    };

    static struct gpio_keys_platform_data dm8168_evm_ui_keys_pdata = {
    .buttons = dm8168_evm_ui_keys,
    .nbuttons = ARRAY_SIZE(dm8168_evm_ui_keys),
    .poll_interval = GPIO_KEYS_POLL_MS,
    };

    static struct platform_device dm8168_evm_ui_keys_device = {
    .name = "gpio-keys-polled",
    .id = 0,
    .dev = {
    .platform_data = &dm8168_evm_ui_keys_pdata
    },
    };

    static void dm8168_evm_ui_keys_init(unsigned gpio)
    {
    int i;
    struct gpio_keys_button *button;

    for (i = 0; i < IO_EXPANDER; i++) {
    button = &dm8168_evm_ui_keys[i];
    button->code = KEY_F8 - i;
    button->desc = (char *)
    dm8168_evm_ui_exp[IO_EXPANDER + i];
    button->gpio = gpio + IO_EXPANDER + i;
    }
    }
  • Hi Titus,

    Thanks for your effort. I am sorry for my late response. I have tried with your suggestion. But there is no interrupt.


    static const char const *dm8168_toii_exp[] = {
    "user_0",
    "user_1",
    "user_2",
    "user_3",
    "user_4",
    "user_5",
    "user_6",
    "user_7",
    "user_8",
    "user_9",
    "user_10",
    "user_11",
    "user_12",
    "user_13",
    "user_14",
    "user_15",
    };

    static struct gpio_keys_button dm8168_toii_keys[] = {
    [0 ... IO_EXPANDER - 1] = {
    .type = EV_KEY,
    .active_low = 1,
    .wakeup = 0,
    .debounce_interval = KEYS_DEBOUNCE_MS,
    .code = -1, /* assigned at runtime */
    .gpio = -1, /* assigned at runtime */
    .desc = NULL, /* assigned at runtime */
    },
    };


    static struct gpio_keys_platform_data dm8168_toii_keys_pdata = {
    .buttons = dm8168_toii_keys,
    .nbuttons = ARRAY_SIZE(dm8168_toii_keys),
    .poll_interval = GPIO_KEYS_POLL_MS,
    };

    static struct platform_device dm8168_toii_keys_device = {
    .name = "gpio-Rotary-Switches",
    .id = 0,
    .dev = {
    .platform_data = &dm8168_toii_keys_pdata
    },
    };

    static void dm8168_toii_keys_init(unsigned gpio)
    {
    int i;
    struct gpio_keys_button *button;
    printk("Rotary switches initialized\n");
    for (i = 0; i < IO_EXPANDER-1; i++) {
    button = &dm8168_toii_keys[i];
    button->code = KEY_F8 - i;
    button->desc = (char *)dm8168_toii_exp[i];
    button->gpio = gpio + i;
    }
    }

    static struct platform_device *ti8168_devices[] __initdata = {
        &dm8168_toii_keys_device,
        &keys_gpio,
    };

    In the boot log there is no error message and there is no information. Am I missing anything. I am calling the dm8168_toii_keys_init function from board init function with GPIO base address as input argument.