--- arch/arm/mach-ixp4xx/nas100d-power.c | 68 ++++++++++++++++++++++++++++++++-- include/asm-arm/arch-ixp4xx/nas100d.h | 18 +++++---- 2 files changed, 75 insertions(+), 11 deletions(-) Index: linux-2.6.22-rc5-armeb/arch/arm/mach-ixp4xx/nas100d-power.c =================================================================== --- linux-2.6.22-rc5-armeb.orig/arch/arm/mach-ixp4xx/nas100d-power.c +++ linux-2.6.22-rc5-armeb/arch/arm/mach-ixp4xx/nas100d-power.c @@ -21,15 +21,60 @@ #include #include #include +#include +#include #include -static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) +extern void ctrl_alt_del(void); + +/* This is used to make sure the power-button pusher is serious. The button + * must be held until the value of this counter reaches zero. + */ +static volatile int power_button_countdown; + +/* Must hold the button down for at least this many counts to be processed */ +#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */ + +static void nas100d_power_handler(unsigned long data); +static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0); + +static void nas100d_power_handler(unsigned long data) { - /* Signal init to do the ctrlaltdel action, this will bypass init if - * it hasn't started and do a kernel_restart. + /* This routine is called twice per second to check the + * state of the power button. */ - ctrl_alt_del(); + + if (*IXP4XX_GPIO_GPINR & NAS100D_PB_BM) { + + /* IO Pin is 1 (button pushed) */ + if (power_button_countdown > 0) { + power_button_countdown--; + } + + } else { + + /* Done on button release, to allow for auto-power-on mods. */ + if (power_button_countdown == 0) { + /* Signal init to do the ctrlaltdel action, this will bypass + * init if it hasn't started and do a kernel_restart. + */ + ctrl_alt_del(); + + /* Change the state of the power LED to "blink" */ + gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW); + } else { + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + } + } + + mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); +} + +static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) +{ + /* This is the paper-clip reset, it shuts the machine down directly. */ + machine_power_off(); return IRQ_HANDLED; } @@ -50,6 +95,19 @@ return -EIO; } + /* The power button on the Iomega NAS100d is on GPIO 14, but + * it cannot handle interrupts on that GPIO line. So we'll + * have to poll it with a kernel timer. + */ + + /* Make sure that the power button GPIO is set up as an input */ + gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN); + + /* Set the initial value for the power button IRQ handler */ + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + + mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); + return 0; } @@ -58,6 +116,8 @@ if (!(machine_is_nas100d())) return; + del_timer_sync(&nas100d_power_timer); + free_irq(NAS100D_RB_IRQ, NULL); } Index: linux-2.6.22-rc5-armeb/include/asm-arm/arch-ixp4xx/nas100d.h =================================================================== --- linux-2.6.22-rc5-armeb.orig/include/asm-arm/arch-ixp4xx/nas100d.h +++ linux-2.6.22-rc5-armeb/include/asm-arm/arch-ixp4xx/nas100d.h @@ -39,14 +39,18 @@ /* Buttons */ #define NAS100D_PB_GPIO 14 +#define NAS100D_PB_BM (1L << NAS100D_PB_GPIO) + #define NAS100D_RB_GPIO 4 -#define NAS100D_PO_GPIO 12 /* power off */ -#define NAS100D_PB_IRQ IRQ_IXP4XX_GPIO14 #define NAS100D_RB_IRQ IRQ_IXP4XX_GPIO4 -/* -#define NAS100D_PB_BM (1L << NAS100D_PB_GPIO) -#define NAS100D_PO_BM (1L << NAS100D_PO_GPIO) -#define NAS100D_RB_BM (1L << NAS100D_RB_GPIO) -*/ +#define NAS100D_PO_GPIO 12 /* power off */ + +/* LEDs */ + +#define NAS100D_LED_PWR_GPIO 15 +#define NAS100D_LED_PWR_BM (1L << NAS100D_LED_PWR_GPIO) + +#define NAS100D_LED_WLAN_GPIO 0 +#define NAS100D_LED_WLAN_BM (1L << NAS100D_LED_WLAN_GPIO)