Search code examples
androidlinux-kernelembeddedpowermanagerinput-devices

How to wake up an Android Embedded Board from Suspend by using a GPIO


I am currently working on porting Android 4.4 (Kitkat) on an embedded system (Freescale i.MX6 based). In order to start my development, I used a few development kits (Wandboard, Boundary Device's BD-SL).

While working on the power management of my custom board, I had no trouble to put the devkits in suspend. However, I couldn't find how to wake them from sleep (other than power cycling them). The expected way of waking the system would be by getting an interrupt on a GPIO (e.g. the on-off button on an Android based phone).

I wanted to know what was the usual way to wake up an android device from suspend with a GPIO's interrupt. Though the question may seem trivial, I had trouble gathering all the information I needed from various searches on Google and specialized forums. I found a lot of information but nothing that covered the whole subject. Probably because I was missing the required background, I had trouble putting everything together without a code example. I guessed I was not the only one in this situation, thus this post.

Here are some of the information I found:


Solution

  • In the end, I was digging too deep. The code example was right under my nose. Everything I needed was in the BD-SL devkit's board specific code (can be found in the BD-SL source tree in mydroid/BD-SL-i.MX6/kernel_imx/arch/arm/mach-mx6/board-mx6_nitrogen6x.c)

    This code is specific to the Freescale i.MX6 provided kernel but the different parts should easily be ported/Adapted to other Android Embedded Platforms.

    GPIO define. I am skipping the GPIO pin mux for simplicity. The pin needs to be multiplexed to the GPIO functionality:

    #define GP_ONOFF_KEY        IMX_GPIO_NR(2, 3)
    

    Definition of the input key

    #define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake)    \
    {                               \
        .gpio       = gpio_num,             \
        .type       = EV_KEY,               \
        .code       = ev_code,              \
        .active_low = act_low,              \
        .desc       = "btn " descr,             \
        .wakeup     = wake,                 \
    }
    
    static struct gpio_keys_button buttons[] = {
        GPIO_BUTTON(GP_ONOFF_KEY, KEY_POWER, 1, "key-power", 1),
    };
    

    Definition of the corresponding platform data and platform device:

    static struct gpio_keys_platform_data button_data = {
        .buttons    = buttons,
        .nbuttons   = ARRAY_SIZE(buttons),
    };
    
    static struct platform_device button_device = {
        .name       = "gpio-keys",
        .id     = -1,
        .num_resources  = 0,
        .dev        = {
            .platform_data = &button_data,
        }
    };
    

    Registering of the platform device

    static void __init add_device_buttons(void)
    {
        platform_device_register(&button_device);
    }
    
    /*!
     * Board specific initialization.
     */
    static void __init board_init(void)
    {
        //...
    
        add_device_buttons();
    
        //...
    }
    

    And for completeness, the initialize data structure that points to the Board specific initialization

    /*
     * initialize data structure.
     */
    MACHINE_START(MX6_NITROGEN6X, "Boundary Devices Nitrogen6X/SABRE Lite Board")
        /* Maintainer: Boundary Devices */
        .boot_params = MX6_PHYS_OFFSET + 0x100,
        .fixup = fixup_mxc_board,
        .map_io = mx6_map_io,
        .init_irq = mx6_init_irq,
        .init_machine = board_init,
        .timer = &timer,
        .reserve = reserve,
    MACHINE_END