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.

Advice on using kernel module "GPIO Buttons" ( "GPIO Keys") with DM8168 ?

My goal is to use the "GPIO Keys" or gpio-keys driver rather than /sys/class/gpio. I understand the gpio-keys solution will allow a button press to generate an event as if it came from a keyboard.

Here is what I have done so far:

  • I connected a push button to GPO_IO6 (pin G5).
  • I verified that pushing button pulls voltage down to ground.  
  • I configured and built a new uImage kernel using menuconfig to add support for InputDeviceSupport-Keyboards->"GPIO Buttons" in addition to /sys/class/gpio/ and Basic memory-mapped GPI controllers support.
  • After boot I see only a mouse under /dev/input/
--- GPIO Support  
[ ]   Debug GPIO calls
[*]   /sys/class/gpio/... (sysfs interface)
      *** Memory mapped GPIO expanders: ***
<*>   Basic memory-mapped GPIO controllers support 
< >   IT8761E GPIO support 
When using the sys interface, I see no change in value when pressing or releasing the button:
/sys/devices/virtual/gpio/gpio6# cat value
0
When I read PINCTRL297 associated with GPO6 it is set to 0x02:
root@dm816x-evm:/dev/input# devmem2 0x48140CA0
/dev/mem opened.
Memory mapped at address 0x40258000.
Read at address  0x48140CA0 (0x40258ca0): 0x00000002
I tried setting PINCTRL297 to 000 MUXMODE[2:0].  I assumed it should be in this mode  with no change in the sys cat value reported when I push a button.
Using devmen2 to read from GPIO0 @ 0x48032000:
GPIO_DATAIN offset 138h, the state remains the same regardless of button status.
root@dm816x-evm:/sys/devices/virtual/gpio/gpio6# devmem2 0x48032138
/dev/mem opened.
Memory mapped at address 0x400e4000.
Read at address  0x48032138 (0x400e4138): 0x00000008
The value read at GPIO_OE offset 134h indicates GP06 is configured as an input:
root@dm816x-evm:/sys/devices/virtual/gpio/gpio6# devmem2 0x48032134
/dev/mem opened.
Memory mapped at address 0x40250000.
Read at address  0x48032134 (0x40250134): 0xFFEFFFF0
Are there additional kernel configuration required?  Or is there a possible conflict between loading multiple GPIO associated drivers such as /sys/class/gpio and "GPIO Buttons"?  I see no GPIO messages in the boot up either good or bad.  I am running out of ideas.  Any tips or suggestions are much appreciated.
Thanks in advance for any direction,
-Ed

 

  • Hi Ed,

    The first thing we should verify is that the PINCTRL297[2:0] MUXMODE is 0x0 (GP0[6]), not 0x2 (GPMC_A[23]). From your post, I can not be sure that you achieve to set 0x0 in PINCTRL297[2:0] MUXMODE bit field. Could you please confirm that you achieved? If not, I will check how this can be set to 0x0.

    Regards,

    Pavel

  • Hi Pavel,

    Once again thank you for your valued assistance.

    It appears that writing 0x0 to PINCTRL297 is not accepted.  It remains at 0x02.

    1. When I use devmen2 to read PINCTRL297 it is 0x2.  
    2. When I write a 0x0 to PINCTRL297 the readback displays 0 and appears it succeeded.
    3. When I read read PINCTRL297 a second time it is back to 0x2?



    Output captured from script running in console: 

    PINCTRL297 @ 0x48140CA0

    Read PINCTRL
    devmem2 0x48140CA0 w
    /dev/mem opened.
    Memory mapped at address 0x4030c000.
    Read at address  0x48140CA0 (0x4030cca0): 0x00000002

    Configure PINCTRL to MUXMODE 0x0 (GPO[6])
    devmem2 0x48140CA0 w 0x0
    /dev/mem opened.
    Memory mapped at address 0x4024f000.
    Read at address  0x48140CA0 (0x4024fca0): 0x00000002
    Write at address 0x48140CA0 (0x4024fca0): 0x00000000, readback 0x00000000

    Read PINCTRL after set to 0x0
    devmem2 0x48140CA0 w
    /dev/mem opened.
    Memory mapped at address 0x400ae000.
    Read at address  0x48140CA0 (0x400aeca0): 0x00000002

    *** Error PINCTRL returned 0x02, expected to be 0x0
  • Ed,

    I also can not change the value of PINCTRL297 to 0x0 from user space. Thus we need to change it from the linux kernel. You should modify the below file as:

    {EZSDK}/board-support/linux-2.6.37-psp04.04.00.01/arch/arm/mach-omap2/board-ti8168evm.c

    static struct omap_board_mux board_mux[] __initdata = {

        /* PIN mux for non-muxed NOR */
        TI816X_MUX(TIM7_OUT, OMAP_MUX_MODE1),    /* gpmc_a12 */
        TI816X_MUX(UART1_CTSN, OMAP_MUX_MODE1),    /* gpmc_a13 */
        TI816X_MUX(UART1_RTSN, OMAP_MUX_MODE1),    /* gpmc_a14 */
        TI816X_MUX(UART2_RTSN, OMAP_MUX_MODE1),    /* gpmc_a15 */
        /* REVISIT: why 2 lines configured as gpmc_a15 */
        TI816X_MUX(SC1_RST, OMAP_MUX_MODE1),    /* gpmc_a15 */
        TI816X_MUX(UART2_CTSN, OMAP_MUX_MODE1),    /* gpmc_a16 */
        TI816X_MUX(UART0_RIN, OMAP_MUX_MODE1),    /* gpmc_a17 */
        TI816X_MUX(UART0_DCDN, OMAP_MUX_MODE1),    /* gpmc_a18 */
        TI816X_MUX(UART0_DSRN, OMAP_MUX_MODE1),    /* gpmc_a19 */
        TI816X_MUX(UART0_DTRN, OMAP_MUX_MODE1),    /* gpmc_a20 */
        TI816X_MUX(SPI_SCS3, OMAP_MUX_MODE1),    /* gpmc_a21 */
        TI816X_MUX(SPI_SCS2, OMAP_MUX_MODE1),    /* gpmc_a22 */
        //TI816X_MUX(GP0_IO6, OMAP_MUX_MODE2),    /* gpmc_a23 */
        TI816X_MUX(TIM6_OUT, OMAP_MUX_MODE1),    /* gpmc-a24 */
        TI816X_MUX(SC0_DATA, OMAP_MUX_MODE1),    /* gpmc_a25 */
        /* for controlling high address */
        TI816X_MUX(GPMC_A27, OMAP_MUX_MODE1),    /* gpio-20 */
        { .reg_offset = OMAP_MUX_TERMINATOR },
    };

    Now you should build new uImage and use it when booting the board. The value should be 0x0.

    Regards,

    Pavel

  • Thank you Pavel!  PICCTRL297 is now MUXMODE 0x0 and I can access GP0_I06 status using devmem2 and see the button status change.

    When rebuilding the uImage is it good practice to do a clean first?  Or a "make clean" and a "make distclean" command?  And should the CROSS_COMPILE and ARCH arguments be present?  All I did was:

    cd board-support/linux-2.6.37-psp04.04.00.01/
    make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm uImage
    
    
    Hopefully I can make sense on how to use gpio-keys now and connect GP0_I04 (brighness+) and GP0_I05 (brightness-) to the PWM control you had helped me get working.
    According to this article, I expected to see /dev/input/event* folder to appear but it did not:
    http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:drivers:gpio-keys
    
    
    Could there be a gpio-keys board support source file that needs editing first?  There are many source files under /arch/arm that include gpio_keys.h but I cannot find one associated with the ti8168 EVM.  
    /board-support/linux-2.6.37-psp04.04.00.01/arch/arm 
    
    
    There are 8 that source files that include gpio_keys.h under mach-omap2:
    
    
    find mach-omap2 -iname '*' | xargs grep 'gpio_keys.h' -sl
    mach-omap2/board-rx51-peripherals.c
    mach-omap2/board-omap3beagle.c
    mach-omap2/board-ldp.c
    mach-omap2/board-omap3stalker.c
    mach-omap2/board-omap3touchbook.c
    mach-omap2/board-devkit8000.c
    mach-omap2/board-omap3pandora.c
    mach-omap2/board-4430sdp.c
    
    
    
    
    
    
    -Ed
  • I am getting the feeling the answer may be "there is no existing gpio-keys support built-in for the TI DM8168 EVM". Is this correct?

    And if I want support for gpio-keys  I will need to add it myself to:

    ${EZSDK}/board-support/linux-2.6.37-psp04.04.00.01/arch/arm/mach-omap2/board-ti8168evm.c 

    At first this sounds like a daunting task to me.  However after looking at this ADI article on GPIO-keys, is it possible adding support requires only a few paragraphs of code?

    ${EZSDK}/board-support/linux-2.6.37-psp04.04.00.01/arch/blackfin/mach-bf533/boards/stamp.c 

    #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
    #include <linux/input.h>
    #include <linux/gpio_keys.h>
    static struct gpio_keys_button bfin_gpio_keys_table[] = {
    {BTN_0, GPIO_PF5, 0, "gpio-keys: BTN0"},
    {BTN_1, GPIO_PF6, 0, "gpio-keys: BTN1"},
    {BTN_2, GPIO_PF8, 0, "gpio-keys: BTN2"},
    };
    static struct gpio_keys_platform_data bfin_gpio_keys_data = {
    .buttons        = bfin_gpio_keys_table,
    .nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
    };
    static struct platform_device bfin_device_gpiokeys = {
    .name      = "gpio-keys",
    .dev = {
    .platform_data = &bfin_gpio_keys_data,
    },
    };
    #endif

    I am guessing it is not that straight forward on a non BlackFin processor?  

    Or maybe it is straight forward?  The board-omap3beagle.c implementation only appears to be a few paragraphs of data structures:

    static struct gpio_keys_button gpio_buttons[] = {
    {
    .code = BTN_EXTRA,
    .gpio = 7,
    .desc = "user",
    .wakeup = 1,
    },
    };
    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 *omap3_beagle_devices[] __initdata = {
    &leds_gpio,
    &keys_gpio,
    &beagle_dss_device,
    };

    Could I be on the right track?
    -Ed
  • In an attempt to add  gpio-keys support to the board-ti8168evm.c I copied and modified source from board-ti8168evm.c.  It sort of works.  Or at least I can see a new /dev/input/event0.  Also it has taken over the /sys/class/gpio4 - gpio6 access which now reports that it can not be opened.

    However, when I cat /dev/input/event0 and press my button (normally high) nothing happens.  I tried macking active_low=1 with same result.

    cat /sys/devices/platform/gpio-keys/input/input0/event0/dev
    13:64
    cat /proc/bus/input/devices 
    I: Bus=0019 Vendor=0001 Product=0001 Version=0100
    N: Name="gpio-keys"
    P: Phys=gpio-keys/input0
    S: Sysfs=/devices/platform/gpio-keys/input/input0
    U: Uniq=
    H: Handlers=kbd event0 
    B: EV=3
    B: KEY=3 0 0 0 40 0 0 0

    // EES - Add support for GPIO (gpio-keys)
    // Copied from board-omap3beagle.c
    static struct gpio_keys_button gpio_buttons[] = {
            {
                    .code = KEY_BRIGHTNESSUP,
                    .gpio = 4,
                    .active_low = 1,
                    .desc = "brightness+",
                    .wakeup = 1,
            },
            {
                    .code = KEY_BRIGHTNESSDOWN,
                    .gpio = 5,
                    .active_low = 1,
                    .desc = "brightness-",
                    .wakeup = 1,
            },
            {
                    .code = KEY_HOME,
                    .gpio = 6,
                    .active_low = 1,
                    .desc = "home",
                    .wakeup = 1,
            },
    };

    static void __init ti8168_evm_init(void)
    {
            // EES
            platform_add_devices(ti8168_devices, ARRAY_SIZE(ti8168_devices));

    I will keep investigating.

    -Ed

     

  • I checked the button was pulling voltage to ground again.  I guess that was not really necessary since devmem2 could see the button status change.   Or at least devmem2 could see the change before I added GPIO keys support.  My input handlers display as:

    cat /proc/bus/input/handlers 
    N: Number=0 Name=kbd
    N: Number=1 Name=sysrq (filter)
    N: Number=2 Name=mousedev Minor=32
    N: Number=3 Name=evdev Minor=64
  • Hi Ed,

    Regarding gpio_keys, I searched our DM81xx forums and wiki pages, but did not find anything useful. The same with the Linux forum.

    I found something that might be in help in the Android forum:

    http://e2e.ti.com/support/embedded/android/f/509/p/134217/489984.aspx

    http://e2e.ti.com/support/embedded/android/f/509/p/207734/747366.aspx

    Please check if these two threads can help. I will continue to investigate and let you know when I have something.

    Regards,

    Pavel

  • Hi Pavel,

    It is working now.  Thank you for your help!  I had seen those links but re-reading them made me think it sounded like a mux mode problem even though you had showed me how get it working using devmem2.  Adding the config for "GPIO Buttons" ( a.k.a gpio-keys ) apparently changes the mux mode or something that had been working previously with devmem2.  

    Now I can cat device input events and the event is actually working when I press GP0_IO6 defined as KEY_HOME. 

    The following first 2 lines are from GP0_IO6 button down and the last 2 lines are the button up.  

    root@dm816x-evm:~# cat /dev/input/event0 |hexdump -C                            
    00000000  5e 57 76 50 bb 5f 09 00  01 00 66 00 01 00 00 00  |^WvP._....f.....|  
    00000010  5e 57 76 50 c1 5f 09 00  00 00 00 00 00 00 00 00  |^WvP._..........|  
    00000020  5f 57 76 50 5c 50 08 00  01 00 66 00 00 00 00 00  |_WvP\P....f.....|  
    00000030  5f 57 76 50 61 50 08 00  00 00 00 00 00 00 00 00  |_WvPaP..........| 
    

    It was a puzzling problem. You showed me how to get the devmem2 interface working by commenting out the omap_board_mux board_mux[] data for GPO_IO6 in the board-ti8168evm.c file.  This worked and devmem2 could definitely display button state changes.  I am not sure if commenting out made it default to mode0 or whatever was defined in the mux81xx.c file.  Incidentally I am not sure if mux81xx.c just defines the default state or simply declares the mux capable I/O.  I think it is the later.  
    Anyway after adding an explicit OMAP_MUX_MODE0 statements to omap_board_mux board_mux[]  for the desired GPIO all is good!

    File: board-ti8168evm.c

    #ifdef CONFIG_OMAP_MUX
    static struct omap_board_mux board_mux[] __initdata = {
    
    	/* PIN mux for non-muxed NOR */
    	TI816X_MUX(TIM7_OUT, OMAP_MUX_MODE1),	/* gpmc_a12 */
    	TI816X_MUX(UART1_CTSN, OMAP_MUX_MODE1),	/* gpmc_a13 */
    	TI816X_MUX(UART1_RTSN, OMAP_MUX_MODE1),	/* gpmc_a14 */
    	TI816X_MUX(UART2_RTSN, OMAP_MUX_MODE1),	/* gpmc_a15 */
    	/* REVISIT: why 2 lines configured as gpmc_a15 */
    	TI816X_MUX(SC1_RST, OMAP_MUX_MODE1),	/* gpmc_a15 */
    	TI816X_MUX(UART2_CTSN, OMAP_MUX_MODE1),	/* gpmc_a16 */
    	TI816X_MUX(UART0_RIN, OMAP_MUX_MODE1),	/* gpmc_a17 */
    	TI816X_MUX(UART0_DCDN, OMAP_MUX_MODE1),	/* gpmc_a18 */
    	TI816X_MUX(UART0_DSRN, OMAP_MUX_MODE1),	/* gpmc_a19 */
    	TI816X_MUX(UART0_DTRN, OMAP_MUX_MODE1),	/* gpmc_a20 */
    	TI816X_MUX(SPI_SCS3, OMAP_MUX_MODE1),	/* gpmc_a21 */
    	TI816X_MUX(SPI_SCS2, OMAP_MUX_MODE1),	/* gpmc_a22 */
    
            // EES - GP0_IO4, GP0_IO5, GP0_IO6 are connected to the bezel buttons on the prototype
            // Configure GPIO used by gpio-keys ( CONFIG_KEYBOARD_GPIO=y ) to OMAP_MUX_MODE0
            TI816X_MUX(GP0_IO4, OMAP_MUX_MODE0),
            TI816X_MUX(GP0_IO5, OMAP_MUX_MODE0),	/* gpmc_a24 */
            TI816X_MUX(GP0_IO6, OMAP_MUX_MODE0),	/* gpmc_a23 */
    
    	TI816X_MUX(TIM6_OUT, OMAP_MUX_MODE1),	/* gpmc-a24 */
    	TI816X_MUX(SC0_DATA, OMAP_MUX_MODE1),	/* gpmc_a25 */
    	/* for controlling high address */
    	TI816X_MUX(GPMC_A27, OMAP_MUX_MODE1),	/* gpio-20 */
    	{ .reg_offset = OMAP_MUX_TERMINATOR },
    };
    #else
    
    So with your help, all is good once again!  This embedded Linux stuff is starting to become more enjoyable finally.
    -Ed