Patchwork [U-Boot] i.MX6: mx6qsabrelite: Add keypress support

login
register
mail settings
Submitter Eric Nelson
Date March 3, 2012, midnight
Message ID <1330732824-15345-1-git-send-email-eric.nelson@boundarydevices.com>
Download mbox | patch
Permalink /patch/144385/
State Rejected
Headers show

Comments

Eric Nelson - March 3, 2012, midnight
This patch adds support for the GPIO keyboard used on MX6Q SabreLite.

This is generally used for invoking Android "recovery mode" in
response to a long press of volume key down during boot.

This can be tested by a boot script like so:
    if keypress voldown && sleep 1 && keypress voldown ; then
          echo "do recovery thing" ;
    fi

Key values can be seen by issuing keypress with no arguments:

	MX6QSABRELITE U-Boot > keypress
	keys: !menu	!back	!search	!home	!volup	!voldown
---
 board/freescale/mx6qsabrelite/mx6qsabrelite.c |   76 +++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)
Eric Nelson - March 3, 2012, 12:11 a.m.
On 03/02/2012 05:00 PM, Eric Nelson wrote:
> This patch adds support for the GPIO keyboard used on MX6Q SabreLite.
>
> This is generally used for invoking Android "recovery mode" in
> response to a long press of volume key down during boot.
>
> This can be tested by a boot script like so:
>      if keypress voldown&&  sleep 1&&  keypress voldown ; then
>            echo "do recovery thing" ;
>      fi
>
> Key values can be seen by issuing keypress with no arguments:
>
> 	MX6QSABRELITE U-Boot>  keypress
> 	keys: !menu	!back	!search	!home	!volup	!voldown
> ---
>   board/freescale/mx6qsabrelite/mx6qsabrelite.c |   76 +++++++++++++++++++++++++
>   1 files changed, 76 insertions(+), 0 deletions(-)
>
 > <snip>

I didn't want to litter the commit message with a lot of extraneous
discussion, but it appears that Android recovery mode can be invoked
either by Android itself or by a user pressing keys.

When Android wants to invoke recovery mode, it creates a special
"recovery" file and then re-boots.

The Freescale U-Boot release accomplishes this by having special
code to detect the keypress or the presence of the magic file.

http://opensource.freescale.com/git?p=imx/uboot-imx.git;a=blob;f=board/freescale/common/recovery.c;h=16e0be479ba543a8ceb865c3c2eee55379186bda;hb=imx_v2009.08_11.11.01

http://opensource.freescale.com/git?p=imx/uboot-imx.git;a=blob;f=board/freescale/mx53_loco/mx53_loco.c;h=fda52dc4abff6482d6cb102002529a3f2edd3bbb;hb=imx_v2009.08_11.11.01#l733

Since U-Boot can test files using the hush parser, it seems cleaner to just
enable keyboard detection and allow express the boot flow in boot commands.

I looked for, but didn't find precedent for testing keys.

Please advise if there's a more standard way to accomplish keypress
detection.

Regards,


Eric
Marek Vasut - March 3, 2012, 2:18 a.m.
> This patch adds support for the GPIO keyboard used on MX6Q SabreLite.
> 
> This is generally used for invoking Android "recovery mode" in
> response to a long press of volume key down during boot.
> 
> This can be tested by a boot script like so:
>     if keypress voldown && sleep 1 && keypress voldown ; then
>           echo "do recovery thing" ;
>     fi
> 
> Key values can be seen by issuing keypress with no arguments:
> 
> 	MX6QSABRELITE U-Boot > keypress
> 	keys: !menu	!back	!search	!home	!volup	!voldown
> ---
>  board/freescale/mx6qsabrelite/mx6qsabrelite.c |   76
> +++++++++++++++++++++++++ 1 files changed, 76 insertions(+), 0
> deletions(-)
> 
> diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c
> b/board/freescale/mx6qsabrelite/mx6qsabrelite.c index e0ba6a4..0d45615
> 100644
> --- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c
> +++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c
> @@ -50,6 +50,10 @@ DECLARE_GLOBAL_DATA_PTR;
>  	PAD_CTL_PUS_100K_DOWN | PAD_CTL_SPEED_MED |		\
>  	PAD_CTL_DSE_40ohm     | PAD_CTL_SRE_FAST)
> 
> +#define BUTTON_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE |		\
> +	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED   |		\
> +	PAD_CTL_DSE_40ohm   | PAD_CTL_HYS)
> +
>  int dram_init(void)
>  {
>         gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
> @@ -122,6 +126,15 @@ iomux_v3_cfg_t enet_pads2[] = {
>  	MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL	| MUX_PAD_CTRL(ENET_PAD_CTRL),
>  };
> 
> +static iomux_v3_cfg_t const button_pads[] = {
> +	MX6Q_PAD_NANDF_D1__GPIO_2_1	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 
-
> Menu Button */ +	MX6Q_PAD_NANDF_D2__GPIO_2_2	|
> MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Back Button */
> +	MX6Q_PAD_NANDF_D3__GPIO_2_3	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 
-
> Search Button */ +	MX6Q_PAD_NANDF_D4__GPIO_2_4	|
> MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Home Button */
> +	MX6Q_PAD_GPIO_19__GPIO_4_5	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 
-
> Volume Down */ +	MX6Q_PAD_GPIO_18__GPIO_7_13	|
> MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Volume Up */ +};
> +
>  static void setup_iomux_enet(void)
>  {
>  	gpio_direction_output(87, 0);  /* GPIO 3-23 */
> @@ -323,10 +336,18 @@ int setup_sata(void)
>  }
>  #endif
> 
> +static void setup_buttons(void)
> +{
> +	imx_iomux_v3_setup_multiple_pads(button_pads,
> +					 ARRAY_SIZE(button_pads));
> +}
> +
>  int board_early_init_f(void)
>  {
>         setup_iomux_uart();
> 
> +       setup_buttons();
> +
>  #ifdef CONFIG_CMD_SATA
>  	setup_sata();
>  #endif
> @@ -350,3 +371,58 @@ int checkboard(void)
> 
>         return 0;
>  }
> +
> +struct button_key {
> +	char const	*name;
> +	unsigned	gpnum;
> +};
> +
> +static struct button_key const buttons[] = {
> +	{"menu",	GPIO_NUMBER(2, 1)},
> +	{"back",	GPIO_NUMBER(2, 2)},
> +	{"search",	GPIO_NUMBER(2, 3)},
> +	{"home",	GPIO_NUMBER(2, 4)},
> +	{"voldown",	GPIO_NUMBER(4, 5)},
> +	{"volup",	GPIO_NUMBER(7, 13)},
> +};
> +
> +static int keypress(cmd_tbl_t *cmdtp, int flag, int argc, char * const
> argv[]) +{
> +	if (1 < argc) {
> +		int arg;
> +		int pressed = 1 ;
> +		for (arg=1; arg<argc; arg++) {
> +			char const *keyname=argv[arg];
> +			int i;
> +			for (i=0; pressed && (i < ARRAY_SIZE(buttons)); i++) {
> +				if (0 == strcmp(buttons[i].name,keyname)) {
> +					pressed = pressed && (0 == 
gpio_get_value(buttons[i].gpnum));
> +					break;
> +				}
> +			}
> +			if (ARRAY_SIZE(buttons) == i) {
> +				printf ("unrecognized key %s\n", keyname);
> +				pressed = 0;
> +				break;
> +			}
> +		}
> +		return (0 == pressed);
> +	} else {
> +		int i;
> +		printf ("keys: ");
> +		for (i=0; i<ARRAY_SIZE(buttons); i++) {
> +			if (0 != gpio_get_value(buttons[i].gpnum))
> +				printf("!");
> +			printf("%s\t",buttons[i].name);
> +		}
> +		printf("\n");
> +		return 0 ;
> +	}
> +}
> +
> +U_BOOT_CMD(
> +	keypress, CONFIG_SYS_MAXARGS, 1, keypress,
> +	"Display or test keypresses",
> +	"    keypress		- show key(s) pressed\n"
> +	"    keypress name	- test key name (return 0 if pressed)\n"
> +);

Why not make it an STDIN device as any other keyboard?

M
Wolfgang Denk - March 3, 2012, 9:15 a.m.
Dear Eric Nelson,

In message <1330732824-15345-1-git-send-email-eric.nelson@boundarydevices.com> you wrote:
> This patch adds support for the GPIO keyboard used on MX6Q SabreLite.
> 
> This is generally used for invoking Android "recovery mode" in
> response to a long press of volume key down during boot.
> 
> This can be tested by a boot script like so:
>     if keypress voldown && sleep 1 && keypress voldown ; then
>           echo "do recovery thing" ;
>     fi
> 
> Key values can be seen by issuing keypress with no arguments:

I don't like introducing yet another way to handle key presses and
create menu like interfaces from this.

We already have two of these:

- We have the powerful and flexible method to map key preesses to
  envrionment variables which can in turn hold commands (variables
  "magic_keys" and "key_magic*") as used for example on the enbw_cmc,
  lwmon5, hmi1001, mucmc52, pcs440ep, r360mpi and mucmc52 boards.

- We have the menu system as implemented by common/menu.c etc.


Please use either of these, but don't invent a new one.  Thanks.

Best regards,

Wolfgang Denk
Eric Nelson - March 3, 2012, 3:30 p.m.
On 03/02/2012 07:18 PM, Marek Vasut wrote:
>> This patch adds support for the GPIO keyboard used on MX6Q SabreLite.
>>
>> This is generally used for invoking Android "recovery mode" in
>> response to a long press of volume key down during boot.
>>
>> This can be tested by a boot script like so:
>>      if keypress voldown&&  sleep 1&&  keypress voldown ; then
>>            echo "do recovery thing" ;
>>      fi
>>
>> Key values can be seen by issuing keypress with no arguments:
>>
>> 	MX6QSABRELITE U-Boot>  keypress
>> 	keys: !menu	!back	!search	!home	!volup	!voldown
>> ---
>>   board/freescale/mx6qsabrelite/mx6qsabrelite.c |   76
>> +++++++++++++++++++++++++ 1 files changed, 76 insertions(+), 0
>> deletions(-)
>>
>> diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c
>> b/board/freescale/mx6qsabrelite/mx6qsabrelite.c index e0ba6a4..0d45615
>> 100644
>> --- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c
>> +++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c
>> @@ -50,6 +50,10 @@ DECLARE_GLOBAL_DATA_PTR;
>>   	PAD_CTL_PUS_100K_DOWN | PAD_CTL_SPEED_MED |		\
>>   	PAD_CTL_DSE_40ohm     | PAD_CTL_SRE_FAST)
>>
>> +#define BUTTON_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE |		\
>> +	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED   |		\
>> +	PAD_CTL_DSE_40ohm   | PAD_CTL_HYS)
>> +
>>   int dram_init(void)
>>   {
>>          gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
>> @@ -122,6 +126,15 @@ iomux_v3_cfg_t enet_pads2[] = {
>>   	MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL	| MUX_PAD_CTRL(ENET_PAD_CTRL),
>>   };
>>
>> +static iomux_v3_cfg_t const button_pads[] = {
>> +	MX6Q_PAD_NANDF_D1__GPIO_2_1	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14
> -
>> Menu Button */ +	MX6Q_PAD_NANDF_D2__GPIO_2_2	|
>> MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Back Button */
>> +	MX6Q_PAD_NANDF_D3__GPIO_2_3	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14
> -
>> Search Button */ +	MX6Q_PAD_NANDF_D4__GPIO_2_4	|
>> MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Home Button */
>> +	MX6Q_PAD_GPIO_19__GPIO_4_5	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14
> -
>> Volume Down */ +	MX6Q_PAD_GPIO_18__GPIO_7_13	|
>> MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Volume Up */ +};
>> +
>>   static void setup_iomux_enet(void)
>>   {
>>   	gpio_direction_output(87, 0);  /* GPIO 3-23 */
>> @@ -323,10 +336,18 @@ int setup_sata(void)
>>   }
>>   #endif
>>
>> +static void setup_buttons(void)
>> +{
>> +	imx_iomux_v3_setup_multiple_pads(button_pads,
>> +					 ARRAY_SIZE(button_pads));
>> +}
>> +
>>   int board_early_init_f(void)
>>   {
>>          setup_iomux_uart();
>>
>> +       setup_buttons();
>> +
>>   #ifdef CONFIG_CMD_SATA
>>   	setup_sata();
>>   #endif
>> @@ -350,3 +371,58 @@ int checkboard(void)
>>
>>          return 0;
>>   }
>> +
>> +struct button_key {
>> +	char const	*name;
>> +	unsigned	gpnum;
>> +};
>> +
>> +static struct button_key const buttons[] = {
>> +	{"menu",	GPIO_NUMBER(2, 1)},
>> +	{"back",	GPIO_NUMBER(2, 2)},
>> +	{"search",	GPIO_NUMBER(2, 3)},
>> +	{"home",	GPIO_NUMBER(2, 4)},
>> +	{"voldown",	GPIO_NUMBER(4, 5)},
>> +	{"volup",	GPIO_NUMBER(7, 13)},
>> +};
>> +
>> +static int keypress(cmd_tbl_t *cmdtp, int flag, int argc, char * const
>> argv[]) +{
>> +	if (1<  argc) {
>> +		int arg;
>> +		int pressed = 1 ;
>> +		for (arg=1; arg<argc; arg++) {
>> +			char const *keyname=argv[arg];
>> +			int i;
>> +			for (i=0; pressed&&  (i<  ARRAY_SIZE(buttons)); i++) {
>> +				if (0 == strcmp(buttons[i].name,keyname)) {
>> +					pressed = pressed&&  (0 ==
> gpio_get_value(buttons[i].gpnum));
>> +					break;
>> +				}
>> +			}
>> +			if (ARRAY_SIZE(buttons) == i) {
>> +				printf ("unrecognized key %s\n", keyname);
>> +				pressed = 0;
>> +				break;
>> +			}
>> +		}
>> +		return (0 == pressed);
>> +	} else {
>> +		int i;
>> +		printf ("keys: ");
>> +		for (i=0; i<ARRAY_SIZE(buttons); i++) {
>> +			if (0 != gpio_get_value(buttons[i].gpnum))
>> +				printf("!");
>> +			printf("%s\t",buttons[i].name);
>> +		}
>> +		printf("\n");
>> +		return 0 ;
>> +	}
>> +}
>> +
>> +U_BOOT_CMD(
>> +	keypress, CONFIG_SYS_MAXARGS, 1, keypress,
>> +	"Display or test keypresses",
>> +	"    keypress		- show key(s) pressed\n"
>> +	"    keypress name	- test key name (return 0 if pressed)\n"
>> +);
>
> Why not make it an STDIN device as any other keyboard?
>
Is there a non-blocking read from stdin available to boot script?

How would we represent keys like "Menu", "Home", "Volume up" and "Volume down"?

Through ANSI escape sequences?

Please advise,


Eric
Eric Nelson - March 3, 2012, 3:35 p.m.
On 03/03/2012 02:15 AM, Wolfgang Denk wrote:
> Dear Eric Nelson,
>
> In message<1330732824-15345-1-git-send-email-eric.nelson@boundarydevices.com>  you wrote:
>> This patch adds support for the GPIO keyboard used on MX6Q SabreLite.
>>
>> This is generally used for invoking Android "recovery mode" in
>> response to a long press of volume key down during boot.
>>
>> This can be tested by a boot script like so:
>>      if keypress voldown&&  sleep 1&&  keypress voldown ; then
>>            echo "do recovery thing" ;
>>      fi
>>
>> Key values can be seen by issuing keypress with no arguments:
>
> I don't like introducing yet another way to handle key presses and
> create menu like interfaces from this.
>
> We already have two of these:
>
> - We have the powerful and flexible method to map key preesses to
>    envrionment variables which can in turn hold commands (variables
>    "magic_keys" and "key_magic*") as used for example on the enbw_cmc,
>    lwmon5, hmi1001, mucmc52, pcs440ep, r360mpi and mucmc52 boards.
>
> - We have the menu system as implemented by common/menu.c etc.
>
> Please use either of these, but don't invent a new one.  Thanks.
>

Thanks for the pointers. I'll rework accordingly.

Grepping the sources rarely results in this kind of insight.

Regards,


Eric
Wolfgang Denk - March 3, 2012, 3:48 p.m.
Dear Eric Nelson,

In message <4F52390C.4080108@boundarydevices.com> you wrote:
>
> > Why not make it an STDIN device as any other keyboard?
> >
> Is there a non-blocking read from stdin available to boot script?
> 
> How would we represent keys like "Menu", "Home", "Volume up" and "Volume down"?
> 
> Through ANSI escape sequences?

No.  You don't have to.  Mapping key presses to functions (bind them to
commands) is a different thing.  Keys could be "1", "2", "3" and "4",
and could be mapped to "run cmd_1", ... "run cmd_4" respectively.
Then the user can define what "cmd_1" etc. does.

Best regards,

Wolfgang Denk
Wolfgang Denk - March 3, 2012, 3:50 p.m.
Dear Eric Nelson,

In message <4F523A24.8020406@boundarydevices.com> you wrote:
>
> Thanks for the pointers. I'll rework accordingly.

Thanks.

> Grepping the sources rarely results in this kind of insight.

I know.  I can find the stuff myself only because I have an idea what
to search for...

Best regards,

Wolfgang Denk
Eric Nelson - March 3, 2012, 3:51 p.m.
On 03/03/2012 08:48 AM, Wolfgang Denk wrote:
> Dear Eric Nelson,
>
> In message<4F52390C.4080108@boundarydevices.com>  you wrote:
>>
>>> Why not make it an STDIN device as any other keyboard?
>>>
>> Is there a non-blocking read from stdin available to boot script?
>>
>> How would we represent keys like "Menu", "Home", "Volume up" and "Volume down"?
>>
>> Through ANSI escape sequences?
>
> No.  You don't have to.  Mapping key presses to functions (bind them to
> commands) is a different thing.  Keys could be "1", "2", "3" and "4",
> and could be mapped to "run cmd_1", ... "run cmd_4" respectively.
> Then the user can define what "cmd_1" etc. does.
>

That's perfect. All that's left is the details...

Thanks for your help.
Dirk Behme - March 24, 2012, 7:13 a.m.
Hi Eric,

On 03.03.2012 16:51, Eric Nelson wrote:
> On 03/03/2012 08:48 AM, Wolfgang Denk wrote:
>> Dear Eric Nelson,
>>
>> In message<4F52390C.4080108@boundarydevices.com> you wrote:
>>>
>>>> Why not make it an STDIN device as any other keyboard?
>>>>
>>> Is there a non-blocking read from stdin available to boot script?
>>>
>>> How would we represent keys like "Menu", "Home", "Volume up" and
>>> "Volume down"?
>>>
>>> Through ANSI escape sequences?
>>
>> No. You don't have to. Mapping key presses to functions (bind them to
>> commands) is a different thing. Keys could be "1", "2", "3" and "4",
>> and could be mapped to "run cmd_1", ... "run cmd_4" respectively.
>> Then the user can define what "cmd_1" etc. does.
>>
>
> That's perfect. All that's left is the details...

Do you plan an update of this patch?

Many thanks,

Dirk
Eric Nelson - March 24, 2012, 10:39 p.m.
On 03/24/2012 12:13 AM, Dirk Behme wrote:
> Hi Eric,
>
> On 03.03.2012 16:51, Eric Nelson wrote:
>> On 03/03/2012 08:48 AM, Wolfgang Denk wrote:
>>> Dear Eric Nelson,
>>>
>>> In message<4F52390C.4080108@boundarydevices.com> you wrote:
>>>>
>>>>> Why not make it an STDIN device as any other keyboard?
>>>>>
>>>> Is there a non-blocking read from stdin available to boot script?
>>>>
>>>> How would we represent keys like "Menu", "Home", "Volume up" and
>>>> "Volume down"?
>>>>
>>>> Through ANSI escape sequences?
>>>
>>> No. You don't have to. Mapping key presses to functions (bind them to
>>> commands) is a different thing. Keys could be "1", "2", "3" and "4",
>>> and could be mapped to "run cmd_1", ... "run cmd_4" respectively.
>>> Then the user can define what "cmd_1" etc. does.
>>>
>> That's perfect. All that's left is the details...
>
> Do you plan an update of this patch?
>

Yes I do. I'm just having trouble finding time these days.

And I seem to be buttonless (without a button board) at the moment.

I even have a fledgling README for keyboard support so the next person
can find out what to do with grep!

Regards,


Eric

Patch

diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c b/board/freescale/mx6qsabrelite/mx6qsabrelite.c
index e0ba6a4..0d45615 100644
--- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c
+++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c
@@ -50,6 +50,10 @@  DECLARE_GLOBAL_DATA_PTR;
 	PAD_CTL_PUS_100K_DOWN | PAD_CTL_SPEED_MED |		\
 	PAD_CTL_DSE_40ohm     | PAD_CTL_SRE_FAST)
 
+#define BUTTON_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE |		\
+	PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED   |		\
+	PAD_CTL_DSE_40ohm   | PAD_CTL_HYS)
+
 int dram_init(void)
 {
        gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
@@ -122,6 +126,15 @@  iomux_v3_cfg_t enet_pads2[] = {
 	MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL	| MUX_PAD_CTRL(ENET_PAD_CTRL),
 };
 
+static iomux_v3_cfg_t const button_pads[] = {
+	MX6Q_PAD_NANDF_D1__GPIO_2_1	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Menu Button */
+	MX6Q_PAD_NANDF_D2__GPIO_2_2	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Back Button */
+	MX6Q_PAD_NANDF_D3__GPIO_2_3	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Search Button */
+	MX6Q_PAD_NANDF_D4__GPIO_2_4	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Home Button */
+	MX6Q_PAD_GPIO_19__GPIO_4_5	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Volume Down */
+	MX6Q_PAD_GPIO_18__GPIO_7_13	| MUX_PAD_CTRL(BUTTON_PAD_CTRL), /* J14 - Volume Up */
+};
+
 static void setup_iomux_enet(void)
 {
 	gpio_direction_output(87, 0);  /* GPIO 3-23 */
@@ -323,10 +336,18 @@  int setup_sata(void)
 }
 #endif
 
+static void setup_buttons(void)
+{
+	imx_iomux_v3_setup_multiple_pads(button_pads,
+					 ARRAY_SIZE(button_pads));
+}
+
 int board_early_init_f(void)
 {
        setup_iomux_uart();
 
+       setup_buttons();
+
 #ifdef CONFIG_CMD_SATA
 	setup_sata();
 #endif
@@ -350,3 +371,58 @@  int checkboard(void)
 
        return 0;
 }
+
+struct button_key {
+	char const	*name;
+	unsigned	gpnum;
+};
+
+static struct button_key const buttons[] = {
+	{"menu",	GPIO_NUMBER(2, 1)},
+	{"back",	GPIO_NUMBER(2, 2)},
+	{"search",	GPIO_NUMBER(2, 3)},
+	{"home",	GPIO_NUMBER(2, 4)},
+	{"voldown",	GPIO_NUMBER(4, 5)},
+	{"volup",	GPIO_NUMBER(7, 13)},
+};
+
+static int keypress(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	if (1 < argc) {
+		int arg;
+		int pressed = 1 ;
+		for (arg=1; arg<argc; arg++) {
+			char const *keyname=argv[arg];
+			int i;
+			for (i=0; pressed && (i < ARRAY_SIZE(buttons)); i++) {
+				if (0 == strcmp(buttons[i].name,keyname)) {
+					pressed = pressed && (0 == gpio_get_value(buttons[i].gpnum));
+					break;
+				}
+			}
+			if (ARRAY_SIZE(buttons) == i) {
+				printf ("unrecognized key %s\n", keyname);
+				pressed = 0;
+				break;
+			}
+		}
+		return (0 == pressed);
+	} else {
+		int i;
+		printf ("keys: ");
+		for (i=0; i<ARRAY_SIZE(buttons); i++) {
+			if (0 != gpio_get_value(buttons[i].gpnum))
+				printf("!");
+			printf("%s\t",buttons[i].name);
+		}
+		printf("\n");
+		return 0 ;
+	}
+}
+
+U_BOOT_CMD(
+	keypress, CONFIG_SYS_MAXARGS, 1, keypress,
+	"Display or test keypresses",
+	"    keypress		- show key(s) pressed\n"
+	"    keypress name	- test key name (return 0 if pressed)\n"
+);