arch/arm/Kconfig | 8 - arch/arm/mach-ixp4xx/Makefile | 4 arch/arm/mach-ixp4xx/nslu2-leds.c | 223 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 3 deletions(-) --- linux-2.6.15/arch/arm/Kconfig 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.15/arch/arm/Kconfig 1970-01-01 00:00:00.000000000 +0000 @@ -418,7 +418,8 @@ config LEDS ARCH_EBSA285 || ARCH_IMX || ARCH_INTEGRATOR || \ ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \ ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \ - ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE + ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \ + MACH_NSLU2 help If you say Y here, the LEDs on your machine will be used to provide useful information about your current system status. @@ -432,7 +433,7 @@ config LEDS config LEDS_TIMER bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \ - MACH_OMAP_H2 || MACH_OMAP_PERSEUS2 + MACH_OMAP_H2 || MACH_OMAP_PERSEUS2 || MACH_NSLU2 depends on LEDS default y if ARCH_EBSA110 help @@ -448,7 +449,8 @@ config LEDS_TIMER config LEDS_CPU bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \ - !ARCH_OMAP) || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2 + !ARCH_OMAP) || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2 \ + || MACH_NSLU2 depends on LEDS help If you say Y here, the red LED will be used to give a good real --- linux-2.6.15/arch/arm/mach-ixp4xx/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.15/arch/arm/mach-ixp4xx/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -10,3 +10,7 @@ obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote- obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o gtwx5715-setup.o obj-$(CONFIG_MACH_NSLU2) += nslu2-pci.o nslu2-setup.o nslu2-power.o +leds-$(CONFIG_MACH_NSLU2) += nslu2-leds.o +obj-$(CONFIG_LEDS) += $(leds-y) + + --- linux-2.6.15/arch/arm/mach-ixp4xx/nslu2-leds.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.15/arch/arm/mach-ixp4xx/nslu2-leds.c 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,223 @@ +/* + * arch/arm/mach-ixp4xx/nslu2-leds.c + * + * NSLU2 LEDs driver + * + * Copyright (C) 2005 Tower Technologies + * + * based on nslu2-io.c + * Copyright (C) 2004 Karen Spearel + * and arch/arm/mach-footbridge/netwinder-leds.c + * Copyright (C) 1998-1999 Russell King + * + * Author: Alessandro Zummo + * Maintainers: http://www.nslu2-linux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LED_STATE_ENABLED 0x01 +#define LED_STATE_CLAIMED 0x02 +#define LED_STATE_IDLE 0x04 + +static unsigned char led_state; +static unsigned int hw_led_state; + +#ifdef CONFIG_LEDS_TIMER +static const unsigned long idle_seq[4] = { + NSLU2_LED_GRN_BM, 0, + NSLU2_LED_GRN_BM, 0, +}; + +static const unsigned long busy_seq[4] = { + NSLU2_LED_GRN_BM, 0, + NSLU2_LED_GRN_BM | NSLU2_LED_RED_BM, 0, +}; +#endif + +static unsigned char led_count = 0; + +static DEFINE_SPINLOCK(leds_lock); +extern spinlock_t gpio_lock; + +static void nslu2_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch (evt) { + case led_start: + /* Let's rock! Red led on, all others off. Remember + * that disk1/disk2 works inverted. + */ + led_state = LED_STATE_ENABLED; + hw_led_state = NSLU2_LED_DISK1_BM | NSLU2_LED_DISK2_BM + | NSLU2_LED_RED_BM; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + /* The user claimed the interface, red and green off */ + led_state |= LED_STATE_CLAIMED; + hw_led_state &= ~(NSLU2_LED_RED_BM | NSLU2_LED_GRN_BM); + break; + + case led_release: + /* The user released the interface, preserve the last + * status of the leds, except red/green. + */ + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = *IXP4XX_GPIO_GPOUTR & 0x0000000C; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + /* Pulse green led */ + if (!(led_state & LED_STATE_CLAIMED)) + { + /* clear red and green bits */ + hw_led_state &= ~(NSLU2_LED_RED_BM | NSLU2_LED_GRN_BM); + + /* copy the right sequence in */ + if (led_state & LED_STATE_IDLE) + hw_led_state |= idle_seq[led_count % 4]; + else + hw_led_state |= busy_seq[led_count % 4]; + + led_count++; + } + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + led_state |= LED_STATE_IDLE; +#ifndef CONFIG_LEDS_TIMER + /* green on, red off */ + hw_led_state |= NSLU2_LED_GRN_BM; + hw_led_state &= ~NSLU2_LED_RED_BM; +#endif + break; + + case led_idle_end: + led_state &= ~LED_STATE_IDLE; +#ifndef CONFIG_LEDS_TIMER + /* green on, red on -> amber on */ + hw_led_state |= NSLU2_LED_GRN_BM | NSLU2_LED_RED_BM; +#endif + break; +#endif /* CONFIG_LEDS_CPU */ + + case led_halted: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= NSLU2_LED_RED_BM; + break; + + /* leds */ + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= NSLU2_LED_GRN_BM; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~NSLU2_LED_GRN_BM; + break; + + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= (NSLU2_LED_RED_BM | NSLU2_LED_GRN_BM); + break; + + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~(NSLU2_LED_RED_BM | NSLU2_LED_GRN_BM); + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= NSLU2_LED_RED_BM; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~NSLU2_LED_RED_BM; + break; + + default: + break; + } + + spin_unlock_irqrestore(&leds_lock, flags); + + if (led_state & LED_STATE_ENABLED) { + spin_lock_irqsave(&gpio_lock, flags); + *IXP4XX_GPIO_GPOUTR = (*IXP4XX_GPIO_GPOUTR & 0xFFFFFFF0) | hw_led_state; + spin_unlock_irqrestore(&gpio_lock, flags); + } +} + +static int nslu2_leds_panic_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ +#ifdef CONFIG_LEDS_TIMER + leds_event(led_claim); +#endif + leds_event(led_green_off); + leds_event(led_red_on); + + return NOTIFY_DONE; +} + +static struct notifier_block nslu2_leds_panic_block = { + .notifier_call = nslu2_leds_panic_event, +}; + +static int __init nslu2_leds_init(void) +{ + if (!(machine_is_nslu2())) + return 0; + + printk(KERN_INFO "NSLU2: leds\n"); + + /* register panic notifier */ + notifier_chain_register(&panic_notifier_list, &nslu2_leds_panic_block); + + /* enable gpio 0-3 */ + gpio_line_config(NSLU2_LED_GRN, IXP4XX_GPIO_OUT); + gpio_line_config(NSLU2_LED_RED, IXP4XX_GPIO_OUT); + gpio_line_config(NSLU2_LED_DISK1, IXP4XX_GPIO_OUT); + gpio_line_config(NSLU2_LED_DISK2, IXP4XX_GPIO_OUT); + + leds_event = nslu2_leds_event; + + /* this will also initialize the leds to the + * default state. + */ + + leds_event(led_start); + + return 0; +} + +module_init(nslu2_leds_init);