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.

Linux/AM3358: GPIO wake up from standby

Part Number: AM3358
Other Parts Discussed in Thread: SYSCONFIG

Tool/software: Linux

Hello

I am currently using a custom built kernel based on 4.11.12, but I have confirmed the same configuration exists in the latest 4.9 ti-sdk.

I have the latest PM main line patches applied, I am able to suspend and resume from DeepSleep0 and Standby via a GPIO0 line and UART0.  So the functionality is there in my configuration.

I need to wake from Standby via a GPIO2 pin.  I have narrowed my issue to the ENAWAKEUP bit in the GPIO_SYSCONFIG.  It is not being set by the drivers in the SDK nor mainline source.

While digging into that, I am noticing there are register offsets being manipulated for wakeup enables that are not defined in the technical ref for the AM335x family.

Namely,  #define OMAP4_GPIO_WAKE_EN 0x0120

That offset is not listed in the GPIO register definition, and so far I have not been able to find who is actually setting the wakeup enable bit.  I am able to manually poke the register with dev2mem, get a sucessful wakeup cycle, but when I look at the register again it has been put back to disabled.  I have a feeling the context restore in the driver is doing it, but I find no direct reference to the register.

The mainline and SDK drivers are the same, so it seems to exist across the board.  I find alot of threads about trying to wake from a non GPIO0 pin, but no reference to this bit which seems to make it work.

Any thoughts from the software team?

Matt

  • The PM experts have been notified. They will respond here.
  • Hi Matthew,

    Do you use AM335x TI board (EVM, SK, BBB) or custom board? I would suggest you to first work with AM335x TI PSDK4.1 (kernel 4.9.41) only, once successful you can transfer the code to your 4.11 kernel.

    Do you modify your DTS file with GPIO2 gpio-key,wakeup feature?

    I will check regarding your specific question, meanwhile see if the below links will be in help:

    processors.wiki.ti.com/.../Linux_Core_Power_Management_User's_Guide_(v4.4)
    processors.wiki.ti.com/.../Debugging_AM335x_Suspend-Resume_Issues

    www.ti.com/.../sprac74a.pdf

    e2e.ti.com/.../572939
    e2e.ti.com/.../550811
    e2e.ti.com/.../546397
    e2e.ti.com/.../498933
    e2e.ti.com/.../626971

    Regards,
    Pavel

  • Matthew Harlan said:
     I have narrowed my issue to the ENAWAKEUP bit in the GPIO_SYSCONFIG.  It is not being set by the drivers in the SDK nor mainline source.

    The GPIO linux driver (omap4-gpio) is:

    linux-kernel/drivers/gpio/gpio-omap.c

    linux-kernel/include/linux/platform_data/gpio-omap.h

    I confirm that GPIO_SYSCONFIG[2] ENAWAKEUP is not modified by the GPIO driver.

    This register and bit seems to be described and modified in the below files:

    linux-kernel/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c

    /*
     * 'gpio' class: for gpio 0,1,2,3
     */
    static struct omap_hwmod_class_sysconfig am33xx_gpio_sysc = {
        .rev_offs    = 0x0000,
        .sysc_offs    = 0x0010,
        .syss_offs    = 0x0114,
        .sysc_flags    = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
                  SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
                  SYSS_HAS_RESET_STATUS),
        .idlemodes    = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
                  SIDLE_SMART_WKUP),
        .sysc_fields    = &omap_hwmod_sysc_type1,
    };

    linux-kernel/arch/arm/mach-omap2/omap_hwmod.h

    linux-kernel/arch/arm/mach-omap2/omap_hwmod.c

    Regards,
    Pavel

  • Matthew Harlan said:

    While digging into that, I am noticing there are register offsets being manipulated for wakeup enables that are not defined in the technical ref for the AM335x family.

    Namely,  #define OMAP4_GPIO_WAKE_EN 0x0120

    That offset is not listed in the GPIO register definition, and so far I have not been able to find who is actually setting the wakeup enable bit.

    We do not have such register (at offset 0x120) in AM335x TRM, and this OMAP4_GPIO_WAKE_EN register is not used in the gpio-omap.c driver. The only wake-up related register used in the gpio-omap.c driver is OMAP4_GPIO_IRQWAKEN0 (offset 0x44).

    Regards,
    Pavel

  • Pavel,

    This is on a custom board.

    For my GPIO0 wakeup, i have this dtsi included in my build.

    / {

        vbatt_wakeup {
            compatible = "gpio-keys";
            pinctrl-names = "default";
            pinctrl-0 = <&vbatt_wake_pins>;

            wake@0 {
                label = "wake";
                linux,code = <KEY_WAKEUP>;
                gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
                wakeup-source;
                }; 
        };
    };

    I get proper operation from this input, in both Deepsleep0 and Standby, but I know GPIO0 behaves a but differently due to the wakeup domain vs peripheral.

    For my GPIO2, it is being used as the interrupt from our touch screen controller.  I have removed the touch driver and replaced with a similar device tree entry.

    / {

        LCD_wakeup {
            compatible = "gpio-keys";
            pinctrl-names = "default";
            pinctrl-0 = <&tp_gpio_pins>;

            wake@0 {
                label = "TP";
                linux,code = <KEY_WAKEUP>;
                gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
                wakeup-source;
                };
            };
    };

    This does not work for GPIO2.

    I have dumped the GPIO registers on suspend and resume, my IRQWAKE registers are set correctly.  The module's SYSCONFIG ENWAKEUP never seems to get set.  But if I do it manually it works.

    This happens on a 4.9 SDK based kernel and my 4.11 kernel.

    I have a feeling this is buried somewhere in the hwmod drivers, as I have tracked down the enable_wakeup calls within hwmod.  But as of yet I have not found where the SYSCONFIG value is setup automatically.

    Matt

  • Matt,

    Matthew Harlan said:

    For my GPIO2, it is being used as the interrupt from our touch screen controller.  I have removed the touch driver and replaced with a similar device tree entry.

    / {

        LCD_wakeup {
            compatible = "gpio-keys";
            pinctrl-names = "default";
            pinctrl-0 = <&tp_gpio_pins>;

            wake@0 {
                label = "TP";
                linux,code = <KEY_WAKEUP>;
                gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
                wakeup-source;
                };
            };
    };

    This does not work for GPIO2.

    Your DTS file looks correct. You can also check gpio_keys.c driver, make sure wakeup-source entry is parsed (button->wakeup is set to 1), the functions device_init_wakeup(), enable_irq_wake(), pm_stay_awake(), pm_wakeup_event() are called, CONFIG_PM_SLEEP is defined.

    Make sure also you have the wake-up event at the gpio2_5 pin, check with scope.

    Matthew Harlan said:
    I have dumped the GPIO registers on suspend and resume, my IRQWAKE registers are set correctly.  The module's SYSCONFIG ENWAKEUP never seems to get set.  But if I do it manually it works.

    As you already know, this register/bit is set in omap_hwmod.c driver during boot up and during suspend/resume. Check if the related functions are called: omap_hwmod_enable(), _omap_device_enable_hwmods(), omap_device_enable(), omap_device_build_from_dt(), _omap_device_notifier_call()

    _omap_device_enable_hwmods(), omap_device_enable(), omap_device_build_from_dt(), _omap_device_notifier_call() functions are located at:

    linux-kernel/arch/arm/mach-omap2/omap_device.c

    Regards,
    Pavel

  • I have found a solution.

    Ultimately, it was a hint by Dave Gerlach that turned out to be it.

    Within the hwmod drivers, the ENWAKEUP bit was being set as part of the idle sequence.  _idle_sysc will make the register change if the correct flags are set within the hwmod definition.  I was able to find that with strategic printk's.

    However, the transition to idle also has calls to soc_ops.disable_module, and _disable_clocks.  I'm not sure which one is the offending party, but one of those changes is keeping the GPIO module from generating the wakeup event.  GPIO0 appears to be handled differently as it is within the wakeup power domain.

    My solution is to keep the required GPIO from entering idle all together.  You can do this by adding the devicetree property ti,no-idle to the gpio module.

    I made the change in am33xx.dtsi

    		gpio2: gpio@481ac000 {
    			compatible = "ti,omap4-gpio";
    			ti,hwmods = "gpio3";
    			gpio-controller;
    			#gpio-cells = <2>;
    			interrupt-controller;
    			#interrupt-cells = <2>;
    			reg = <0x481ac000 0x1000>;
    			interrupts = <32>;
    			ti,no-idle;
    		};
    

    Dave mentioned this might break Deepsleep0, but I still seem to be able to wake the device with my GPIO0 source.  We are not using Deepsleep0, so it doesn't really matter to us, so I have not tested it any further.

    Your mileage may very, but it works for us.

    Matt