diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-08-13 16:45:48 +0200 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-08-13 16:45:48 +0200 |
commit | 19e4ab54e7f5fe46a3c931afa7e786f11d57b558 (patch) | |
tree | aeada0b9d0800b94cb795020a856c625ddc4f41c | |
parent | 0d7614f09c1ebdbaa1599a5aba7593f147bf96ee (diff) | |
parent | fa8bbb13ab49e77c00fa09e5504ec25b7176fb4b (diff) |
Merge branch 'for-arm-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds into next/drivers
From Bryan Wu <bryan.wu@canonical.com>:
Based on Linus Walleij's ARM LED consolidation work, this patchset introduce a
new generic led trigger for CPU not only for ARM but also for others.
For enabling CPU idle event, CPU arch code should call ledtrig_cpu() stub to
trigger idle start or idle end event.
These patches convert old style LED driver in arch/arm to gpio_led or new led
driver interface. Against 3.5 release and build successfully for all the machines.
Test ledtrig-cpu driver on OMAP4 Panda board.
v9 --> v10
* fix compiling issue on versatile_defconfig reported by Russell King
* rebase to 3.5 kernel and move patches to new git tree
v8 --> v9:
* use mutex to replace rw_sema pointed out by Tim Gardner
* add a new struct led_trigger_cpu
* add lock_is_inited to record mutex lock initialization
v6 --> v7:
* add a patch to unify the led-trigger name
* fix some typo pointed
* use BUG_ON to detect CPU numbers during building stage
v5 --> v6:
* replace __get_cpu_var() to per_cpu()
* remove smp_processor_id() which is wrong with for_each_possible_cpu()
* test on real OMAP4 Panda board
* add comments about CPU hotplug in the CPU LED trigger driver
v4 --> v5:
* rebase all the patches on top of latest linux-next
* replace on_each_cpu() with for_each_possible_cpu()
* add some description of ledtrig_cpu() API
* remove old leds code from driver nwflash.c, which should use a new led trigger then
* this trigger driver can be built as module now
v3 --> v4:
* fix a typo pointed by Jochen Friedrich
* fix some building errors
* add Reviewed-by and Tested-by into patch log
v2 --> v3:
* almost rewrote the whole ledtrig-cpu driver, which is more simple
* every CPU will have a per-CPU trigger
* cpu trigger can be assigned to any leds
* fix a lockdep issue in led-trigger common code
* other fix according to review
v1 --> v2:
* remove select operations in Kconfig of every machines
* add back supporting of led in core module of mach-integrator
* solidate name scheme in ledtrig-cpu.c
* add comments of CPU_LED_* cpu led events
* fold patches of RealView and Versatile together
* add machine_is_ check during assabet led driver init
* add some Acked-by in patch logs
* remove code for simpad machine in machine-sa11000, since Jochen Friedrich
introduced gpiolib and gpio-led driver for simpad
* on Assabet and Netwinder machine, LED operations is reversed like:
setting bit means turn off leds
clearing bit means turn on leds
* add a new function to read CM_CTRL register for led driver
* 'for-arm-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds:
ARM: use new LEDS CPU trigger stub to replace old one
ARM: mach-sa1100: retire custom LED code
ARM: mach-omap1: retire custom LED code
ARM: mach-pnx4008: remove including old leds event API header file
ARM: plat-samsung: remove including old leds event API header file
ARM: mach-pxa: retire custom LED code
char: nwflash: remove old led event code
ARM: mach-footbridge: retire custom LED code
ARM: mach-ebsa110: retire custom LED code
ARM: mach-clps711x: retire custom LED code of P720T machine
ARM: mach-integrator: retire custom LED code
ARM: mach-integrator: move CM_CTRL to header file for accessing by other functions
ARM: mach-orion5x: convert custom LED code to gpio_led and LED CPU trigger
ARM: mach-shark: retire custom LED code
ARM: mach-ks8695: remove leds driver, since nobody use it
ARM: mach-realview and mach-versatile: retire custom LED code
ARM: at91: convert old leds drivers to gpio_led and led_trigger drivers
led-triggers: create a trigger for CPU activity
Conflicts:
arch/arm/mach-clps711x/p720t.c
arch/arm/mach-sa1100/leds-cerf.c
arch/arm/mach-sa1100/leds-lart.c
Let's hope this is the last time we pull this and it doesn't cause
more trouble. I have verified that version 10 causes no build
warnings or errors any more, and the patches still look good.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
97 files changed, 1441 insertions, 2983 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e91c7cdc6fe..ac353cf0180 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1787,59 +1787,6 @@ config FORCE_MAX_ZONEORDER This config option is actually maximum order plus one. For example, a value of 11 means that the largest free memory block is 2^10 pages. -config LEDS - bool "Timer and CPU usage LEDs" - depends on ARCH_CDB89712 || ARCH_EBSA110 || \ - ARCH_EBSA285 || ARCH_INTEGRATOR || \ - ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \ - ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \ - ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \ - ARCH_AT91 || ARCH_DAVINCI || \ - ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW - help - If you say Y here, the LEDs on your machine will be used - to provide useful information about your current system status. - - If you are compiling a kernel for a NetWinder or EBSA-285, you will - be able to select which LEDs are active using the options below. If - you are compiling a kernel for the EBSA-110 or the LART however, the - red LED will simply flash regularly to indicate that the system is - still functional. It is safe to say Y here if you have a CATS - system, but the driver will do nothing. - -config LEDS_TIMER - bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \ - OMAP_OSK_MISTRAL || MACH_OMAP_H2 \ - || MACH_OMAP_PERSEUS2 - depends on LEDS - depends on !GENERIC_CLOCKEVENTS - default y if ARCH_EBSA110 - help - If you say Y here, one of the system LEDs (the green one on the - NetWinder, the amber one on the EBSA285, or the red one on the LART) - will flash regularly to indicate that the system is still - operational. This is mainly useful to kernel hackers who are - debugging unstable kernels. - - The LART uses the same LED for both Timer LED and CPU usage LED - functions. You may choose to use both, but the Timer LED function - will overrule the CPU usage LED. - -config LEDS_CPU - bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \ - !ARCH_OMAP) \ - || OMAP_OSK_MISTRAL || MACH_OMAP_H2 \ - || MACH_OMAP_PERSEUS2 - depends on LEDS - help - If you say Y here, the red LED will be used to give a good real - time indication of CPU usage, by lighting whenever the idle task - is not currently executing. - - The LART uses the same LED for both Timer LED and CPU usage LED - functions. You may choose to use both, but the Timer LED function - will overrule the CPU usage LED. - config ALIGNMENT_TRAP bool depends on CPU_CP15_MMU diff --git a/arch/arm/include/asm/leds.h b/arch/arm/include/asm/leds.h deleted file mode 100644 index c545739f39b..00000000000 --- a/arch/arm/include/asm/leds.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * arch/arm/include/asm/leds.h - * - * Copyright (C) 1998 Russell King - * - * 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. - * - * Event-driven interface for LEDs on machines - * Added led_start and led_stop- Alex Holden, 28th Dec 1998. - */ -#ifndef ASM_ARM_LEDS_H -#define ASM_ARM_LEDS_H - - -typedef enum { - led_idle_start, - led_idle_end, - led_timer, - led_start, - led_stop, - led_claim, /* override idle & timer leds */ - led_release, /* restore idle & timer leds */ - led_start_timer_mode, - led_stop_timer_mode, - led_green_on, - led_green_off, - led_amber_on, - led_amber_off, - led_red_on, - led_red_off, - led_blue_on, - led_blue_off, - /* - * I want this between led_timer and led_start, but - * someone has decided to export this to user space - */ - led_halted -} led_event_t; - -/* Use this routine to handle LEDs */ - -#ifdef CONFIG_LEDS -extern void (*leds_event)(led_event_t); -#else -#define leds_event(e) -#endif - -#endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 7ad2d5cf700..8951577c4ce 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -21,7 +21,6 @@ obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o -obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_OC_ETM) += etm.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ISA_DMA_API) += dma.o diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c deleted file mode 100644 index 1911dae19e4..00000000000 --- a/arch/arm/kernel/leds.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * LED support code, ripped out of arch/arm/kernel/time.c - * - * Copyright (C) 1994-2001 Russell King - * - * 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 <linux/export.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/syscore_ops.h> -#include <linux/string.h> - -#include <asm/leds.h> - -static void dummy_leds_event(led_event_t evt) -{ -} - -void (*leds_event)(led_event_t) = dummy_leds_event; - -struct leds_evt_name { - const char name[8]; - int on; - int off; -}; - -static const struct leds_evt_name evt_names[] = { - { "amber", led_amber_on, led_amber_off }, - { "blue", led_blue_on, led_blue_off }, - { "green", led_green_on, led_green_off }, - { "red", led_red_on, led_red_off }, -}; - -static ssize_t leds_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - int ret = -EINVAL, len = strcspn(buf, " "); - - if (len > 0 && buf[len] == '\0') - len--; - - if (strncmp(buf, "claim", len) == 0) { - leds_event(led_claim); - ret = size; - } else if (strncmp(buf, "release", len) == 0) { - leds_event(led_release); - ret = size; - } else { - int i; - - for (i = 0; i < ARRAY_SIZE(evt_names); i++) { - if (strlen(evt_names[i].name) != len || - strncmp(buf, evt_names[i].name, len) != 0) - continue; - if (strncmp(buf+len, " on", 3) == 0) { - leds_event(evt_names[i].on); - ret = size; - } else if (strncmp(buf+len, " off", 4) == 0) { - leds_event(evt_names[i].off); - ret = size; - } - break; - } - } - return ret; -} - -static DEVICE_ATTR(event, 0200, NULL, leds_store); - -static struct bus_type leds_subsys = { - .name = "leds", - .dev_name = "leds", -}; - -static struct device leds_device = { - .id = 0, - .bus = &leds_subsys, -}; - -static int leds_suspend(void) -{ - leds_event(led_stop); - return 0; -} - -static void leds_resume(void) -{ - leds_event(led_start); -} - -static void leds_shutdown(void) -{ - leds_event(led_halted); -} - -static struct syscore_ops leds_syscore_ops = { - .shutdown = leds_shutdown, - .suspend = leds_suspend, - .resume = leds_resume, -}; - -static int __init leds_init(void) -{ - int ret; - ret = subsys_system_register(&leds_subsys, NULL); - if (ret == 0) - ret = device_register(&leds_device); - if (ret == 0) - ret = device_create_file(&leds_device, &dev_attr_event); - if (ret == 0) - register_syscore_ops(&leds_syscore_ops); - return ret; -} - -device_initcall(leds_init); - -EXPORT_SYMBOL(leds_event); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 693b744fd57..04eea22d795 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -31,9 +31,9 @@ #include <linux/random.h> #include <linux/hw_breakpoint.h> #include <linux/cpuidle.h> +#include <linux/leds.h> #include <asm/cacheflush.h> -#include <asm/leds.h> #include <asm/processor.h> #include <asm/thread_notify.h> #include <asm/stacktrace.h> @@ -189,7 +189,7 @@ void cpu_idle(void) while (1) { tick_nohz_idle_enter(); rcu_idle_enter(); - leds_event(led_idle_start); + ledtrig_cpu(CPU_LED_IDLE_START); while (!need_resched()) { #ifdef CONFIG_HOTPLUG_CPU if (cpu_is_offline(smp_processor_id())) @@ -220,7 +220,7 @@ void cpu_idle(void) } else local_irq_enable(); } - leds_event(led_idle_end); + ledtrig_cpu(CPU_LED_IDLE_END); rcu_idle_exit(); tick_nohz_idle_exit(); schedule_preempt_disabled(); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index af2afb01967..09be0c3c906 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -25,7 +25,6 @@ #include <linux/timer.h> #include <linux/irq.h> -#include <asm/leds.h> #include <asm/thread_info.h> #include <asm/sched_clock.h> #include <asm/stacktrace.h> @@ -80,21 +79,6 @@ u32 arch_gettimeoffset(void) } #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ -#ifdef CONFIG_LEDS_TIMER -static inline void do_leds(void) -{ - static unsigned int count = HZ/2; - - if (--count == 0) { - count = HZ/2; - leds_event(led_timer); - } -} -#else -#define do_leds() -#endif - - #ifndef CONFIG_GENERIC_CLOCKEVENTS /* * Kernel system timer support. @@ -102,7 +86,6 @@ static inline void do_leds(void) void timer_tick(void) { profile_tick(CPU_PROFILING); - do_leds(); xtime_update(1); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c index 462bc319cbc..32396bb4a4c 100644 --- a/arch/arm/mach-at91/board-csb337.c +++ b/arch/arm/mach-at91/board-csb337.c @@ -220,8 +220,6 @@ static struct gpio_led csb_leds[] = { static void __init csb337_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); /* Serial */ /* DBGU on ttyS0 */ at91_register_uart(0, 0, 0); diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c index 9c24cb25707..192ec76579c 100644 --- a/arch/arm/mach-at91/board-ecbat91.c +++ b/arch/arm/mach-at91/board-ecbat91.c @@ -138,11 +138,20 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = { }, }; +/* + * LEDs + */ +static struct gpio_led ecb_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PC7, + .active_low = 1, + .default_trigger = "heartbeat", + } +}; + static void __init ecb_at91board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -165,6 +174,9 @@ static void __init ecb_at91board_init(void) /* SPI */ at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices)); + + /* LEDs */ + at91_gpio_leds(ecb_leds, ARRAY_SIZE(ecb_leds)); } MACHINE_START(ECBAT91, "emQbit's ECB_AT91") diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c index 82bdfde3405..d2d4580df48 100644 --- a/arch/arm/mach-at91/board-eco920.c +++ b/arch/arm/mach-at91/board-eco920.c @@ -93,10 +93,26 @@ static struct spi_board_info eco920_spi_devices[] = { }, }; +/* + * LEDs + */ +static struct gpio_led eco920_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PB0, + .active_low = 1, + .default_trigger = "heartbeat", + }, + { /* D2 */ + .name = "led2", + .gpio = AT91_PIN_PB1, + .active_low = 1, + .default_trigger = "timer", + } +}; + static void __init eco920_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); /* DBGU on ttyS0. (Rx & Tx only */ at91_register_uart(0, 0, 0); at91_add_device_serial(); @@ -127,6 +143,8 @@ static void __init eco920_board_init(void) ); at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices)); + /* LEDs */ + at91_gpio_leds(eco920_leds, ARRAY_SIZE(eco920_leds)); } MACHINE_START(ECO920, "eco920") diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c index 64c1dbf88a0..86050da3ba5 100644 --- a/arch/arm/mach-at91/board-kafa.c +++ b/arch/arm/mach-at91/board-kafa.c @@ -66,11 +66,20 @@ static struct at91_udc_data __initdata kafa_udc_data = { .pullup_pin = AT91_PIN_PB7, }; +/* + * LEDs + */ +static struct gpio_led kafa_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PB4, + .active_low = 1, + .default_trigger = "heartbeat", + }, +}; + static void __init kafa_board_init(void) { - /* Set up the LEDs */ - at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -88,6 +97,8 @@ static void __init kafa_board_init(void) at91_add_device_i2c(NULL, 0); /* SPI */ at91_add_device_spi(NULL, 0); + /* LEDs */ + at91_gpio_leds(kafa_leds, ARRAY_SIZE(kafa_leds)); } MACHINE_START(KAFA, "Sperry-Sun KAFA") diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c index 5d96cb85175..00d60071770 100644 --- a/arch/arm/mach-at91/board-kb9202.c +++ b/arch/arm/mach-at91/board-kb9202.c @@ -96,11 +96,26 @@ static struct atmel_nand_data __initdata kb9202_nand_data = { .num_parts = ARRAY_SIZE(kb9202_nand_partition), }; +/* + * LEDs + */ +static struct gpio_led kb9202_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PC19, + .active_low = 1, + .default_trigger = "heartbeat", + }, + { /* D2 */ + .name = "led2", + .gpio = AT91_PIN_PC18, + .active_low = 1, + .default_trigger = "timer", + } +}; + static void __init kb9202_board_init(void) { - /* Set up the LEDs */ - at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -128,6 +143,8 @@ static void __init kb9202_board_init(void) at91_add_device_spi(NULL, 0); /* NAND */ at91_add_device_nand(&kb9202_nand_data); + /* LEDs */ + at91_gpio_leds(kb9202_leds, ARRAY_SIZE(kb9202_leds)); } MACHINE_START(KB9200, "KB920x") diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c index cc2bf979607..2526ad759b5 100644 --- a/arch/arm/mach-at91/board-rm9200dk.c +++ b/arch/arm/mach-at91/board-rm9200dk.c @@ -177,9 +177,6 @@ static struct gpio_led dk_leds[] = { static void __init dk_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c index 62e19e64c9d..06f2ce543e2 100644 --- a/arch/arm/mach-at91/board-rm9200ek.c +++ b/arch/arm/mach-at91/board-rm9200ek.c @@ -148,9 +148,6 @@ static struct gpio_led ek_leds[] = { static void __init ek_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c index c3b43aefdb7..93b8e3a45e2 100644 --- a/arch/arm/mach-at91/board-rsi-ews.c +++ b/arch/arm/mach-at91/board-rsi-ews.c @@ -185,9 +185,6 @@ static struct platform_device rsiews_nor_flash = { */ static void __init rsi_ews_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ /* This one is for debugging */ diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c index 7bf6da70d7d..46e1eb55053 100644 --- a/arch/arm/mach-at91/board-sam9-l9260.c +++ b/arch/arm/mach-at91/board-sam9-l9260.c @@ -166,11 +166,26 @@ static struct at91_mmc_data __initdata ek_mmc_data = { .vcc_pin = -EINVAL, }; +/* + * LEDs + */ +static struct gpio_led ek_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PA9, + .active_low = 1, + .default_trigger = "heartbeat", + }, + { /* D2 */ + .name = "led2", + .gpio = AT91_PIN_PA6, + .active_low = 1, + .default_trigger = "timer", + } +}; + static void __init ek_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -197,6 +212,8 @@ static void __init ek_board_init(void) at91_add_device_mmc(0, &ek_mmc_data); /* I2C */ at91_add_device_i2c(NULL, 0); + /* LEDs */ + at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); } MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260") diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 2269be5fa38..802d4946bb3 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -569,9 +569,6 @@ static struct gpio_led ek_leds[] = { static void __init ek_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c index 516d340549d..9fd57bcac69 100644 --- a/arch/arm/mach-at91/board-yl-9200.c +++ b/arch/arm/mach-at91/board-yl-9200.c @@ -541,9 +541,6 @@ void __init yl9200_add_device_video(void) {} static void __init yl9200_board_init(void) { - /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */ - at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index 369afc2ffc5..c55a4364ffb 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -187,7 +187,6 @@ struct at91_can_data { extern void __init at91_add_device_can(struct at91_can_data *data); /* LEDs */ -extern void __init at91_init_leds(u8 cpu_led, u8 timer_led); extern void __init at91_gpio_leds(struct gpio_led *leds, int nr); extern void __init at91_pwm_leds(struct gpio_led *leds, int nr); diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c index 8dfafe76ffe..1b1e62b5f41 100644 --- a/arch/arm/mach-at91/leds.c +++ b/arch/arm/mach-at91/leds.c @@ -90,108 +90,3 @@ void __init at91_pwm_leds(struct gpio_led *leds, int nr) #else void __init at91_pwm_leds(struct gpio_led *leds, int nr){} #endif - - -/* ------------------------------------------------------------------------- */ - -#if defined(CONFIG_LEDS) - -#include <asm/leds.h> - -/* - * Old ARM-specific LED framework; not fully functional when generic time is - * in use. - */ - -static u8 at91_leds_cpu; -static u8 at91_leds_timer; - -static inline void at91_led_on(unsigned int led) -{ - at91_set_gpio_value(led, 0); -} - -static inline void at91_led_off(unsigned int led) -{ - at91_set_gpio_value(led, 1); -} - -static inline void at91_led_toggle(unsigned int led) -{ - unsigned long is_off = at91_get_gpio_value(led); - if (is_off) - at91_led_on(led); - else - at91_led_off(led); -} - - -/* - * Handle LED events. - */ -static void at91_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: /* System startup */ - at91_led_on(at91_leds_cpu); - break; - - case led_stop: /* System stop / suspend */ - at91_led_off(at91_leds_cpu); - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: /* Every 50 timer ticks */ - at91_led_toggle(at91_leds_timer); - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: /* Entering idle state */ - at91_led_off(at91_leds_cpu); - break; - - case led_idle_end: /* Exit idle state */ - at91_led_on(at91_leds_cpu); - break; -#endif - - default: - break; - } - - local_irq_restore(flags); -} - - -static int __init leds_init(void) -{ - if (!at91_leds_timer || !at91_leds_cpu) - return -ENODEV; - - leds_event = at91_leds_event; - - leds_event(led_start); - return 0; -} - -__initcall(leds_init); - - -void __init at91_init_leds(u8 cpu_led, u8 timer_led) -{ - /* Enable GPIO to access the LEDs */ - at91_set_gpio_output(cpu_led, 1); - at91_set_gpio_output(timer_led, 1); - - at91_leds_cpu = cpu_led; - at91_leds_timer = timer_led; -} - -#else -void __init at91_init_leds(u8 cpu_led, u8 timer_led) {} -#endif diff --git a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile index f2f0256232e..5872b49bfae 100644 --- a/arch/arm/mach-clps711x/Makefile +++ b/arch/arm/mach-clps711x/Makefile @@ -16,5 +16,3 @@ obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o obj-$(CONFIG_ARCH_P720T) += p720t.o -leds-$(CONFIG_ARCH_P720T) += p720t-leds.o -obj-$(CONFIG_LEDS) += $(leds-y) diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c index f15293bd797..3a4af00db9e 100644 --- a/arch/arm/mach-clps711x/common.c +++ b/arch/arm/mach-clps711x/common.c @@ -30,7 +30,6 @@ #include <asm/sizes.h> #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/pgtable.h> #include <asm/page.h> #include <asm/mach/map.h> diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c deleted file mode 100644 index bbc449fbe14..00000000000 --- a/arch/arm/mach-clps711x/p720t-leds.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/arch/arm/mach-clps711x/leds.c - * - * Integrator LED control routines - * - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -static void p720t_leds_event(led_event_t ledevt) -{ - unsigned long flags; - u32 pddr; - - local_irq_save(flags); - switch(ledevt) { - case led_idle_start: - break; - - case led_idle_end: - break; - - case led_timer: - pddr = clps_readb(PDDR); - clps_writeb(pddr ^ 1, PDDR); - break; - - default: - break; - } - - local_irq_restore(flags); -} - -static int __init leds_init(void) -{ - if (machine_is_p720t()) - leds_event = p720t_leds_event; - - return 0; -} - -arch_initcall(leds_init); diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c index f266d90b9ef..b752b586fc2 100644 --- a/arch/arm/mach-clps711x/p720t.c +++ b/arch/arm/mach-clps711x/p720t.c @@ -23,6 +23,8 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <mach/hardware.h> #include <asm/pgtable.h> @@ -34,6 +36,8 @@ #include <asm/mach/map.h> #include <mach/syspld.h> +#include <asm/hardware/clps7111.h> + #include "common.h" /* @@ -107,6 +111,64 @@ static void __init p720t_init_early(void) } } +/* + * LED controled by CPLD + */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +static void p720t_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + u8 reg = clps_readb(PDDR); + + if (b != LED_OFF) + reg |= 0x1; + else + reg &= ~0x1; + + clps_writeb(reg, PDDR); +} + +static enum led_brightness p720t_led_get(struct led_classdev *cdev) +{ + u8 reg = clps_readb(PDDR); + + return (reg & 0x1) ? LED_FULL : LED_OFF; +} + +static int __init p720t_leds_init(void) +{ + + struct led_classdev *cdev; + int ret; + + if (!machine_is_p720t()) + return -ENODEV; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->name = "p720t:0"; + cdev->brightness_set = p720t_led_set; + cdev->brightness_get = p720t_led_get; + cdev->default_trigger = "heartbeat"; + + ret = led_classdev_register(NULL, cdev); + if (ret < 0) { + kfree(cdev); + return ret; + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(p720t_leds_init); +#endif + MACHINE_START(P720T, "ARM-Prospector720T") /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ .atag_offset = 0x100, diff --git a/arch/arm/mach-ebsa110/Makefile b/arch/arm/mach-ebsa110/Makefile index 6520ac83580..935e4af01a2 100644 --- a/arch/arm/mach-ebsa110/Makefile +++ b/arch/arm/mach-ebsa110/Makefile @@ -4,9 +4,7 @@ # Object file lists. -obj-y := core.o io.o +obj-y := core.o io.o leds.o obj-m := obj-n := obj- := - -obj-$(CONFIG_LEDS) += leds.o diff --git a/arch/arm/mach-ebsa110/leds.c b/arch/arm/mach-ebsa110/leds.c index 99e14e36250..0398258c20c 100644 --- a/arch/arm/mach-ebsa110/leds.c +++ b/arch/arm/mach-ebsa110/leds.c @@ -1,52 +1,71 @@ /* - * linux/arch/arm/mach-ebsa110/leds.c + * Driver for the LED found on the EBSA110 machine + * Based on Versatile and RealView machine LED code * - * Copyright (C) 1998 Russell King - * - * 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. - * - * EBSA-110 LED control routines. We use the led as follows: - * - * - Red - toggles state every 50 timer interrupts + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> */ -#include <linux/module.h> -#include <linux/spinlock.h> +#include <linux/kernel.h> #include <linux/init.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> -#include <mach/hardware.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include "core.h" -static spinlock_t leds_lock; - -static void ebsa110_leds_event(led_event_t ledevt) +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +static void ebsa110_led_set(struct led_classdev *cdev, + enum led_brightness b) { - unsigned long flags; + u8 reg = __raw_readb(SOFT_BASE); - spin_lock_irqsave(&leds_lock, flags); + if (b != LED_OFF) + reg |= 0x80; + else + reg &= ~0x80; - switch(ledevt) { - case led_timer: - *(volatile unsigned char *)SOFT_BASE ^= 128; - break; + __raw_writeb(reg, SOFT_BASE); +} - default: - break; - } +static enum led_brightness ebsa110_led_get(struct led_classdev *cdev) +{ + u8 reg = __raw_readb(SOFT_BASE); - spin_unlock_irqrestore(&leds_lock, flags); + return (reg & 0x80) ? LED_FULL : LED_OFF; } -static int __init leds_init(void) +static int __init ebsa110_leds_init(void) { - if (machine_is_ebsa110()) - leds_event = ebsa110_leds_event; + + struct led_classdev *cdev; + int ret; + + if (!machine_is_ebsa110()) + return -ENODEV; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->name = "ebsa110:0"; + cdev->brightness_set = ebsa110_led_set; + cdev->brightness_get = ebsa110_led_get; + cdev->default_trigger = "heartbeat"; + + ret = led_classdev_register(NULL, cdev); + if (ret < 0) { + kfree(cdev); + return ret; + } return 0; } -__initcall(leds_init); +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(ebsa110_leds_init); +#endif diff --git a/arch/arm/mach-footbridge/Makefile b/arch/arm/mach-footbridge/Makefile index 3afb1b25946..0b64dd430d6 100644 --- a/arch/arm/mach-footbridge/Makefile +++ b/arch/arm/mach-footbridge/Makefile @@ -14,15 +14,11 @@ pci-$(CONFIG_ARCH_EBSA285_HOST) += ebsa285-pci.o pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o -leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o -leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o - obj-$(CONFIG_ARCH_CATS) += cats-hw.o isa-timer.o obj-$(CONFIG_ARCH_EBSA285) += ebsa285.o dc21285-timer.o obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o isa-timer.o obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o obj-$(CONFIG_PCI) +=$(pci-y) -obj-$(CONFIG_LEDS) +=$(leds-y) obj-$(CONFIG_ISA) += isa.o isa-rtc.o diff --git a/arch/arm/mach-footbridge/ebsa285-leds.c b/arch/arm/mach-footbridge/ebsa285-leds.c deleted file mode 100644 index 5bd266754b9..00000000000 --- a/arch/arm/mach-footbridge/ebsa285-leds.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * linux/arch/arm/mach-footbridge/ebsa285-leds.c - * - * Copyright (C) 1998-1999 Russell King - * - * 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. - * EBSA-285 control routines. - * - * The EBSA-285 uses the leds as follows: - * - Green - toggles state every 50 timer interrupts - * - Amber - On if system is not idle - * - Red - currently unused - * - * Changelog: - * 02-05-1999 RMK Various cleanups - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/spinlock.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 -static char led_state; -static char hw_led_state; - -static DEFINE_SPINLOCK(leds_lock); - -static void ebsa285_leds_event(led_event_t evt) -{ - unsigned long flags; - - spin_lock_irqsave(&leds_lock, flags); - - switch (evt) { - case led_start: - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN; -#ifndef CONFIG_LEDS_CPU - hw_led_state |= XBUS_LED_AMBER; -#endif - led_state |= LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= XBUS_LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= XBUS_LED_AMBER; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~XBUS_LED_AMBER; - break; -#endif - - case led_halted: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~XBUS_LED_RED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_GREEN; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_AMBER; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_AMBER; - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_RED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - *XBUS_LEDS = hw_led_state; - - spin_unlock_irqrestore(&leds_lock, flags); -} - -static int __init leds_init(void) -{ - if (machine_is_ebsa285()) - leds_event = ebsa285_leds_event; - - leds_event(led_start); - - return 0; -} - -__initcall(leds_init); diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c index 27716a7e5fc..b09551ef89c 100644 --- a/arch/arm/mach-footbridge/ebsa285.c +++ b/arch/arm/mach-footbridge/ebsa285.c @@ -5,6 +5,8 @@ */ #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <asm/hardware/dec21285.h> #include <asm/mach-types.h> @@ -13,6 +15,85 @@ #include "common.h" +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct ebsa285_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} ebsa285_leds[] = { + { "ebsa285:amber", "heartbeat", }, + { "ebsa285:green", "cpu0", }, + { "ebsa285:red",}, +}; + +static void ebsa285_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct ebsa285_led *led = container_of(cdev, + struct ebsa285_led, cdev); + + if (b != LED_OFF) + *XBUS_LEDS |= led->mask; + else + *XBUS_LEDS &= ~led->mask; +} + +static enum led_brightness ebsa285_led_get(struct led_classdev *cdev) +{ + struct ebsa285_led *led = container_of(cdev, + struct ebsa285_led, cdev); + + return (*XBUS_LEDS & led->mask) ? LED_FULL : LED_OFF; +} + +static int __init ebsa285_leds_init(void) +{ + int i; + + if (machine_is_ebsa285()) + return -ENODEV; + + /* 3 LEDS All ON */ + *XBUS_LEDS |= XBUS_LED_AMBER | XBUS_LED_GREEN | XBUS_LED_RED; + + for (i = 0; i < ARRAY_SIZE(ebsa285_leds); i++) { + struct ebsa285_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = ebsa285_leds[i].name; + led->cdev.brightness_set = ebsa285_led_set; + led->cdev.brightness_get = ebsa285_led_get; + led->cdev.default_trigger = ebsa285_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(ebsa285_leds_init); +#endif + MACHINE_START(EBSA285, "EBSA285") /* Maintainer: Russell King */ .atag_offset = 0x100, diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c index cac9f67e7da..d2d14339c6c 100644 --- a/arch/arm/mach-footbridge/netwinder-hw.c +++ b/arch/arm/mach-footbridge/netwinder-hw.c @@ -12,9 +12,10 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <asm/hardware/dec21285.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/setup.h> #include <asm/system_misc.h> @@ -27,13 +28,6 @@ #define GP1_IO_BASE 0x338 #define GP2_IO_BASE 0x33a - -#ifdef CONFIG_LEDS -#define DEFAULT_LEDS 0 -#else -#define DEFAULT_LEDS GPIO_GREEN_LED -#endif - /* * Winbond WB83977F accessibility stuff */ @@ -611,15 +605,9 @@ static void __init rwa010_init(void) static int __init nw_hw_init(void) { if (machine_is_netwinder()) { - unsigned long flags; - wb977_init(); cpld_init(); rwa010_init(); - - raw_spin_lock_irqsave(&nw_gpio_lock, flags); - nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); - raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); } return 0; } @@ -672,6 +660,102 @@ static void netwinder_restart(char mode, const char *cmd) } } +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct netwinder_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} netwinder_leds[] = { + { "netwinder:green", "heartbeat", }, + { "netwinder:red", "cpu0", }, +}; + +/* + * The LED control in Netwinder is reversed: + * - setting bit means turn off LED + * - clearing bit means turn on LED + */ +static void netwinder_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct netwinder_led *led = container_of(cdev, + struct netwinder_led, cdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&nw_gpio_lock, flags); + reg = nw_gpio_read(); + if (b != LED_OFF) + reg &= ~led->mask; + else + reg |= led->mask; + nw_gpio_modify_op(led->mask, reg); + spin_unlock_irqrestore(&nw_gpio_lock, flags); +} + +static enum led_brightness netwinder_led_get(struct led_classdev *cdev) +{ + struct netwinder_led *led = container_of(cdev, + struct netwinder_led, cdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&nw_gpio_lock, flags); + reg = nw_gpio_read(); + spin_unlock_irqrestore(&nw_gpio_lock, flags); + + return (reg & led->mask) ? LED_OFF : LED_FULL; +} + +static int __init netwinder_leds_init(void) +{ + int i; + + if (!machine_is_netwinder()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) { + struct netwinder_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = netwinder_leds[i].name; + led->cdev.brightness_set = netwinder_led_set; + led->cdev.brightness_get = netwinder_led_get; + led->cdev.default_trigger = netwinder_leds[i].trigger; + + if (i == 0) + led->mask = GPIO_GREEN_LED; + else + led->mask = GPIO_RED_LED; + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(netwinder_leds_init); +#endif + MACHINE_START(NETWINDER, "Rebel-NetWinder") /* Maintainer: Russell King/Rebel.com */ .atag_offset = 0x100, diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c deleted file mode 100644 index 5a2bd89cbdc..00000000000 --- a/arch/arm/mach-footbridge/netwinder-leds.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * linux/arch/arm/mach-footbridge/netwinder-leds.c - * - * Copyright (C) 1998-1999 Russell King - * - * 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. - * - * NetWinder LED control routines. - * - * The Netwinder uses the leds as follows: - * - Green - toggles state every 50 timer interrupts - * - Red - On if the system is not idle - * - * Changelog: - * 02-05-1999 RMK Various cleanups - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/spinlock.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 -static char led_state; -static char hw_led_state; - -static DEFINE_RAW_SPINLOCK(leds_lock); - -static void netwinder_leds_event(led_event_t evt) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&leds_lock, flags); - - switch (evt) { - case led_start: - led_state |= LED_STATE_ENABLED; - hw_led_state = GPIO_GREEN_LED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= GPIO_GREEN_LED; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~GPIO_RED_LED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= GPIO_RED_LED; - break; -#endif - - case led_halted: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= GPIO_RED_LED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_GREEN_LED; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~GPIO_GREEN_LED; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED); - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_RED_LED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~GPIO_RED_LED; - break; - - default: - break; - } - - raw_spin_unlock_irqrestore(&leds_lock, flags); - - if (led_state & LED_STATE_ENABLED) { - raw_spin_lock_irqsave(&nw_gpio_lock, flags); - nw_gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state); - raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); - } -} - -static int __init leds_init(void) -{ - if (machine_is_netwinder()) - leds_event = netwinder_leds_event; - - leds_event(led_start); - - return 0; -} - -__initcall(leds_init); diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index ebeef966e1f..5521d18bf19 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,11 +4,10 @@ # Object file lists. -obj-y := core.o lm.o +obj-y := core.o lm.o leds.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o -obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_PCI) += pci_v3.o pci.o obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index ebf680bebdf..208c05d9e68 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -27,7 +27,6 @@ #include <mach/cm.h> #include <mach/irqs.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/mach/time.h> #include <asm/pgtable.h> @@ -127,8 +126,6 @@ static struct amba_pl010_data integrator_uart_data = { .set_mctrl = integrator_uart_set_mctrl, }; -#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL) - static DEFINE_RAW_SPINLOCK(cm_lock); /** diff --git a/arch/arm/mach-integrator/include/mach/cm.h b/arch/arm/mach-integrator/include/mach/cm.h index 445d57adb04..1a78692e32a 100644 --- a/arch/arm/mach-integrator/include/mach/cm.h +++ b/arch/arm/mach-integrator/include/mach/cm.h @@ -3,6 +3,8 @@ */ void cm_control(u32, u32); +#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL) + #define CM_CTRL_LED (1 << 0) #define CM_CTRL_nMBDET (1 << 1) #define CM_CTRL_REMAP (1 << 2) diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c index 466defa9784..7a7f6d3273b 100644 --- a/arch/arm/mach-integrator/leds.c +++ b/arch/arm/mach-integrator/leds.c @@ -1,90 +1,125 @@ /* - * linux/arch/arm/mach-integrator/leds.c + * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard + * Based on Versatile and RealView machine LED code * - * Integrator/AP and Integrator/CP LED control routines - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> */ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/smp.h> -#include <linux/spinlock.h> #include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> +#include <mach/cm.h> #include <mach/hardware.h> #include <mach/platform.h> -#include <asm/leds.h> -#include <asm/mach-types.h> -#include <mach/cm.h> -static int saved_leds; +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) + +#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) +#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) -static void integrator_leds_event(led_event_t ledevt) +struct integrator_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} integrator_leds[] = { + { "integrator:green0", "heartbeat", }, + { "integrator:yellow", }, + { "integrator:red", }, + { "integrator:green1", }, + { "integrator:core_module", "cpu0", }, +}; + +static void integrator_led_set(struct led_classdev *cdev, + enum led_brightness b) { - unsigned long flags; - const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE); - unsigned int update_alpha_leds; + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); - // yup, change the LEDs - local_irq_save(flags); - update_alpha_leds = 0; + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; - switch(ledevt) { - case led_idle_start: - cm_control(CM_CTRL_LED, 0); - break; + while (__raw_readl(ALPHA_REG) & 1) + cpu_relax(); - case led_idle_end: - cm_control(CM_CTRL_LED, CM_CTRL_LED); - break; + __raw_writel(reg, LEDREG); +} - case led_timer: - saved_leds ^= GREEN_LED; - update_alpha_leds = 1; - break; +static enum led_brightness integrator_led_get(struct led_classdev *cdev) +{ + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); - case led_red_on: - saved_leds |= RED_LED; - update_alpha_leds = 1; - break; + return (reg & led->mask) ? LED_FULL : LED_OFF; +} - case led_red_off: - saved_leds &= ~RED_LED; - update_alpha_leds = 1; - break; +static void cm_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + if (b != LED_OFF) + cm_control(CM_CTRL_LED, CM_CTRL_LED); + else + cm_control(CM_CTRL_LED, 0); +} - default: - break; - } +static enum led_brightness cm_led_get(struct led_classdev *cdev) +{ + u32 reg = readl(CM_CTRL); - if (update_alpha_leds) { - while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1); - __raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET); - } - local_irq_restore(flags); + return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; } -static int __init leds_init(void) +static int __init integrator_leds_init(void) { - if (machine_is_integrator() || machine_is_cintegrator()) - leds_event = integrator_leds_event; + int i; + + for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { + struct integrator_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + + led->cdev.name = integrator_leds[i].name; + + if (i == 4) { /* Setting for LED in core module */ + led->cdev.brightness_set = cm_led_set; + led->cdev.brightness_get = cm_led_get; + } else { + led->cdev.brightness_set = integrator_led_set; + led->cdev.brightness_get = integrator_led_get; + } + + led->cdev.default_trigger = integrator_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } return 0; } -core_initcall(leds_init); +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(integrator_leds_init); +#endif diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile index 853efd9133c..9324ef965c2 100644 --- a/arch/arm/mach-ks8695/Makefile +++ b/arch/arm/mach-ks8695/Makefile @@ -11,9 +11,6 @@ obj- := # PCI support is optional obj-$(CONFIG_PCI) += pci.o -# LEDs -obj-$(CONFIG_LEDS) += leds.o - # Board-specific support obj-$(CONFIG_MACH_KS8695) += board-micrel.o obj-$(CONFIG_MACH_DSM320) += board-dsm320.o diff --git a/arch/arm/mach-ks8695/devices.c b/arch/arm/mach-ks8695/devices.c index 73bd6381287..47399bc3c02 100644 --- a/arch/arm/mach-ks8695/devices.c +++ b/arch/arm/mach-ks8695/devices.c @@ -182,27 +182,6 @@ static void __init ks8695_add_device_watchdog(void) } -/* -------------------------------------------------------------------- - * LEDs - * -------------------------------------------------------------------- */ - -#if defined(CONFIG_LEDS) -short ks8695_leds_cpu = -1; -short ks8695_leds_timer = -1; - -void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) -{ - /* Enable GPIO to access the LEDs */ - gpio_direction_output(cpu_led, 1); - gpio_direction_output(timer_led, 1); - - ks8695_leds_cpu = cpu_led; - ks8695_leds_timer = timer_led; -} -#else -void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) {} -#endif - /* -------------------------------------------------------------------- */ /* diff --git a/arch/arm/mach-ks8695/include/mach/devices.h b/arch/arm/mach-ks8695/include/mach/devices.h index 85a3c9aa7d1..1e6594a0f29 100644 --- a/arch/arm/mach-ks8695/include/mach/devices.h +++ b/arch/arm/mach-ks8695/include/mach/devices.h @@ -18,11 +18,6 @@ extern void __init ks8695_add_device_wan(void); extern void __init ks8695_add_device_lan(void); extern void __init ks8695_add_device_hpna(void); - /* LEDs */ -extern short ks8695_leds_cpu; -extern short ks8695_leds_timer; -extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led); - /* PCI */ #define KS8695_MODE_PCI 0 #define KS8695_MODE_MINIPCI 1 diff --git a/arch/arm/mach-ks8695/leds.c b/arch/arm/mach-ks8695/leds.c deleted file mode 100644 index 4bd70754729..00000000000 --- a/arch/arm/mach-ks8695/leds.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * LED driver for KS8695-based boards. - * - * Copyright (C) Andrew Victor - * - * 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 <linux/gpio.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> - -#include <asm/leds.h> -#include <mach/devices.h> - - -static inline void ks8695_led_on(unsigned int led) -{ - gpio_set_value(led, 0); -} - -static inline void ks8695_led_off(unsigned int led) -{ - gpio_set_value(led, 1); -} - -static inline void ks8695_led_toggle(unsigned int led) -{ - unsigned long is_off = gpio_get_value(led); - if (is_off) - ks8695_led_on(led); - else - ks8695_led_off(led); -} - - -/* - * Handle LED events. - */ -static void ks8695_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: /* System startup */ - ks8695_led_on(ks8695_leds_cpu); - break; - - case led_stop: /* System stop / suspend */ - ks8695_led_off(ks8695_leds_cpu); - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: /* Every 50 timer ticks */ - ks8695_led_toggle(ks8695_leds_timer); - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: /* Entering idle state */ - ks8695_led_off(ks8695_leds_cpu); - break; - - case led_idle_end: /* Exit idle state */ - ks8695_led_on(ks8695_leds_cpu); - break; -#endif - - default: - break; - } - - local_irq_restore(flags); -} - - -static int __init leds_init(void) -{ - if ((ks8695_leds_timer == -1) || (ks8695_leds_cpu == -1)) - return -ENODEV; - - leds_event = ks8695_leds_event; - - leds_event(led_start); - return 0; -} - -__initcall(leds_init); diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 398e9e53e18..cd169c38616 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -61,14 +61,6 @@ obj-$(CONFIG_ARCH_OMAP850) += gpio7xx.o obj-$(CONFIG_ARCH_OMAP15XX) += gpio15xx.o obj-$(CONFIG_ARCH_OMAP16XX) += gpio16xx.o -# LEDs support -led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o -led-$(CONFIG_MACH_OMAP_H3) += leds-h2p2-debug.o -led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o -led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o -led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o -obj-$(CONFIG_LEDS) += $(led-y) - ifneq ($(CONFIG_FB_OMAP),) obj-y += lcd_dma.o endif diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 44a4ab195fb..cd8836f43f0 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -31,6 +31,7 @@ #include <linux/i2c/tps65010.h> #include <linux/smc91x.h> #include <linux/omapfb.h> +#include <linux/leds.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -306,12 +307,39 @@ static struct platform_device h2_irda_device = { .resource = h2_irda_resources, }; +static struct gpio_led h2_gpio_led_pins[] = { + { + .name = "h2:red", + .default_trigger = "heartbeat", + .gpio = 3, + }, + { + .name = "h2:green", + .default_trigger = "cpu0", + .gpio = OMAP_MPUIO(4), + }, +}; + +static struct gpio_led_platform_data h2_gpio_led_data = { + .leds = h2_gpio_led_pins, + .num_leds = ARRAY_SIZE(h2_gpio_led_pins), +}; + +static struct platform_device h2_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &h2_gpio_led_data, + }, +}; + static struct platform_device *h2_devices[] __initdata = { &h2_nor_device, &h2_nand_device, &h2_smc91x_device, &h2_irda_device, &h2_kp_device, + &h2_gpio_leds, }; static void __init h2_init_smc91x(void) @@ -406,6 +434,10 @@ static void __init h2_init(void) omap_cfg_reg(E19_1610_KBR4); omap_cfg_reg(N19_1610_KBR5); + /* GPIO based LEDs */ + omap_cfg_reg(P18_1610_GPIO3); + omap_cfg_reg(MPUIO4); + h2_smc91x_resources[1].start = gpio_to_irq(0); h2_smc91x_resources[1].end = gpio_to_irq(0); platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index 86cb5a04a40..1fa9c45c1ae 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -31,6 +31,7 @@ #include <linux/i2c/tps65010.h> #include <linux/smc91x.h> #include <linux/omapfb.h> +#include <linux/leds.h> #include <asm/setup.h> #include <asm/page.h> @@ -324,6 +325,32 @@ static struct spi_board_info h3_spi_board_info[] __initdata = { }, }; +static struct gpio_led h3_gpio_led_pins[] = { + { + .name = "h3:red", + .default_trigger = "heartbeat", + .gpio = 3, + }, + { + .name = "h3:green", + .default_trigger = "cpu0", + .gpio = OMAP_MPUIO(4), + }, +}; + +static struct gpio_led_platform_data h3_gpio_led_data = { + .leds = h3_gpio_led_pins, + .num_leds = ARRAY_SIZE(h3_gpio_led_pins), +}; + +static struct platform_device h3_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &h3_gpio_led_data, + }, +}; + static struct platform_device *devices[] __initdata = { &nor_device, &nand_device, @@ -331,6 +358,7 @@ static struct platform_device *devices[] __initdata = { &intlat_device, &h3_kp_device, &h3_lcd_device, + &h3_gpio_leds, }; static struct omap_usb_config h3_usb_config __initdata = { @@ -398,6 +426,10 @@ static void __init h3_init(void) omap_cfg_reg(E19_1610_KBR4); omap_cfg_reg(N19_1610_KBR5); + /* GPIO based LEDs */ + omap_cfg_reg(P18_1610_GPIO3); + omap_cfg_reg(MPUIO4); + smc91x_resources[1].start = gpio_to_irq(40); smc91x_resources[1].end = gpio_to_irq(40); platform_add_devices(devices, ARRAY_SIZE(devices)); diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 8784705edb6..7ee1c1eac35 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -380,10 +380,37 @@ static struct platform_device osk5912_lcd_device = { .id = -1, }; +static struct gpio_led mistral_gpio_led_pins[] = { + { + .name = "mistral:red", + .default_trigger = "heartbeat", + .gpio = 3, + }, + { + .name = "mistral:green", + .default_trigger = "cpu0", + .gpio = OMAP_MPUIO(4), + }, +}; + +static struct gpio_led_platform_data mistral_gpio_led_data = { + .leds = mistral_gpio_led_pins, + .num_leds = ARRAY_SIZE(mistral_gpio_led_pins), +}; + +static struct platform_device mistral_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &mistral_gpio_led_data, + }, +}; + static struct platform_device *mistral_devices[] __initdata = { &osk5912_kp_device, &mistral_bl_device, &osk5912_lcd_device, + &mistral_gpio_leds, }; static int mistral_get_pendown_state(void) @@ -508,6 +535,12 @@ static void __init osk_mistral_init(void) if (gpio_request(2, "lcd_pwr") == 0) gpio_direction_output(2, 1); + /* + * GPIO based LEDs + */ + omap_cfg_reg(P18_1610_GPIO3); + omap_cfg_reg(MPUIO4); + i2c_register_board_info(1, mistral_i2c_board_info, ARRAY_SIZE(mistral_i2c_board_info)); diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c deleted file mode 100644 index f6b14a14a95..00000000000 --- a/arch/arm/mach-omap1/leds-h2p2-debug.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds-h2p2-debug.c - * - * Copyright 2003 by Texas Instruments Incorporated - * - * There are 16 LEDs on the debug board (all green); four may be used - * for logical 'green', 'amber', 'red', and 'blue' (after "claiming"). - * - * The "surfer" expansion board and H2 sample board also have two-color - * green+red LEDs (in parallel), used here for timer and idle indicators. - */ -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/sched.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include <plat/fpga.h> - -#include "leds.h" - - -#define GPIO_LED_RED 3 -#define GPIO_LED_GREEN OMAP_MPUIO(4) - - -#define LED_STATE_ENABLED 0x01 -#define LED_STATE_CLAIMED 0x02 -#define LED_TIMER_ON 0x04 - -#define GPIO_IDLE GPIO_LED_GREEN -#define GPIO_TIMER GPIO_LED_RED - - -void h2p2_dbg_leds_event(led_event_t evt) -{ - unsigned long flags; - - static struct h2p2_dbg_fpga __iomem *fpga; - static u16 led_state, hw_led_state; - - local_irq_save(flags); - - if (!(led_state & LED_STATE_ENABLED) && evt != led_start) - goto done; - - switch (evt) { - case led_start: - if (!fpga) - fpga = ioremap(H2P2_DBG_FPGA_START, - H2P2_DBG_FPGA_SIZE); - if (fpga) { - led_state |= LED_STATE_ENABLED; - __raw_writew(~0, &fpga->leds); - } - break; - - case led_stop: - case led_halted: - /* all leds off during suspend or shutdown */ - - if (! machine_is_omap_perseus2()) { - gpio_set_value(GPIO_TIMER, 0); - gpio_set_value(GPIO_IDLE, 0); - } - - __raw_writew(~0, &fpga->leds); - led_state &= ~LED_STATE_ENABLED; - if (evt == led_halted) { - iounmap(fpga); - fpga = NULL; - } - - goto done; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - led_state ^= LED_TIMER_ON; - - if (machine_is_omap_perseus2()) - hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER; - else { - gpio_set_value(GPIO_TIMER, led_state & LED_TIMER_ON); - goto done; - } - - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (machine_is_omap_perseus2()) - hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 1); - goto done; - } - - break; - - case led_idle_end: - if (machine_is_omap_perseus2()) - hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 0); - goto done; - } - - break; -#endif - - case led_green_on: - hw_led_state |= H2P2_DBG_FPGA_LED_GREEN; - break; - case led_green_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN; - break; - - case led_amber_on: - hw_led_state |= H2P2_DBG_FPGA_LED_AMBER; - break; - case led_amber_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER; - break; - - case led_red_on: - hw_led_state |= H2P2_DBG_FPGA_LED_RED; - break; - case led_red_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_RED; - break; - - case led_blue_on: - hw_led_state |= H2P2_DBG_FPGA_LED_BLUE; - break; - case led_blue_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE; - break; - - default: - break; - } - - - /* - * Actually burn the LEDs - */ - if (led_state & LED_STATE_ENABLED) - __raw_writew(~hw_led_state, &fpga->leds); - -done: - local_irq_restore(flags); -} diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c deleted file mode 100644 index 3a066ee8d02..00000000000 --- a/arch/arm/mach-omap1/leds-innovator.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds-innovator.c - */ -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void innovator_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = 0; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - hw_led_state = 0; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= 0; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= 0; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~0; - break; -#endif - - case led_halted: - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~0; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= 0; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~0; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= 0; - break; - - default: - break; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c deleted file mode 100644 index 936ed426b84..00000000000 --- a/arch/arm/mach-omap1/leds-osk.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds-osk.c - * - * LED driver for OSK with optional Mistral QVGA board - */ -#include <linux/gpio.h> -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED (1 << 0) -#define LED_STATE_CLAIMED (1 << 1) -static u8 led_state; - -#define TIMER_LED (1 << 3) /* Mistral board */ -#define IDLE_LED (1 << 4) /* Mistral board */ -static u8 hw_led_state; - - -#ifdef CONFIG_OMAP_OSK_MISTRAL - -/* For now, all system indicators require the Mistral board, since that - * LED can be manipulated without a task context. This LED is either red, - * or green, but not both; it can't give the full "disco led" effect. - */ - -#define GPIO_LED_RED 3 -#define GPIO_LED_GREEN OMAP_MPUIO(4) - -static void mistral_setled(void) -{ - int red = 0; - int green = 0; - - if (hw_led_state & TIMER_LED) - red = 1; - else if (hw_led_state & IDLE_LED) - green = 1; - /* else both sides are disabled */ - - gpio_set_value(GPIO_LED_GREEN, green); - gpio_set_value(GPIO_LED_RED, red); -} - -#endif - -void osk_leds_event(led_event_t evt) -{ - unsigned long flags; - u16 leds; - - local_irq_save(flags); - - if (!(led_state & LED_STATE_ENABLED) && evt != led_start) - goto done; - - leds = hw_led_state; - switch (evt) { - case led_start: - led_state |= LED_STATE_ENABLED; - hw_led_state = 0; - leds = ~0; - break; - - case led_halted: - case led_stop: - led_state &= ~LED_STATE_ENABLED; - hw_led_state = 0; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - leds = ~0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_OMAP_OSK_MISTRAL - - case led_timer: - hw_led_state ^= TIMER_LED; - mistral_setled(); - break; - - case led_idle_start: /* idle == off */ - hw_led_state &= ~IDLE_LED; - mistral_setled(); - break; - - case led_idle_end: - hw_led_state |= IDLE_LED; - mistral_setled(); - break; - -#endif /* CONFIG_OMAP_OSK_MISTRAL */ - - default: - break; - } - - leds ^= hw_led_state; - -done: - local_irq_restore(flags); -} diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c deleted file mode 100644 index ae6dd93b8dd..00000000000 --- a/arch/arm/mach-omap1/leds.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds.c - * - * OMAP LEDs dispatcher - */ -#include <linux/gpio.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include <plat/mux.h> - -#include "leds.h" - -static int __init -omap_leds_init(void) -{ - if (!cpu_class_is_omap1()) - return -ENODEV; - - if (machine_is_omap_innovator()) - leds_event = innovator_leds_event; - - else if (machine_is_omap_h2() - || machine_is_omap_h3() - || machine_is_omap_perseus2()) - leds_event = h2p2_dbg_leds_event; - - else if (machine_is_omap_osk()) - leds_event = osk_leds_event; - - else - return -1; - - if (machine_is_omap_h2() - || machine_is_omap_h3() -#ifdef CONFIG_OMAP_OSK_MISTRAL - || machine_is_omap_osk() -#endif - ) { - - /* LED1/LED2 pins can be used as GPIO (as done here), or by - * the LPG (works even in deep sleep!), to drive a bicolor - * LED on the H2 sample board, and another on the H2/P2 - * "surfer" expansion board. - * - * The same pins drive a LED on the OSK Mistral board, but - * that's a different kind of LED (just one color at a time). - */ - omap_cfg_reg(P18_1610_GPIO3); - if (gpio_request(3, "LED red") == 0) - gpio_direction_output(3, 1); - else - printk(KERN_WARNING "LED: can't get GPIO3/red?\n"); - - omap_cfg_reg(MPUIO4); - if (gpio_request(OMAP_MPUIO(4), "LED green") == 0) - gpio_direction_output(OMAP_MPUIO(4), 1); - else - printk(KERN_WARNING "LED: can't get MPUIO4/green?\n"); - } - - leds_event(led_start); - return 0; -} - -__initcall(omap_leds_init); diff --git a/arch/arm/mach-omap1/leds.h b/arch/arm/mach-omap1/leds.h deleted file mode 100644 index a1e9fedc376..00000000000 --- a/arch/arm/mach-omap1/leds.h +++ /dev/null @@ -1,3 +0,0 @@ -extern void innovator_leds_event(led_event_t evt); -extern void h2p2_dbg_leds_event(led_event_t evt); -extern void osk_leds_event(led_event_t evt); diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index 4062480bfec..4d4816fd6fc 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -44,7 +44,6 @@ #include <linux/clockchips.h> #include <linux/io.h> -#include <asm/leds.h> #include <asm/irq.h> #include <asm/sched_clock.h> diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c index eae49c3980c..74529549130 100644 --- a/arch/arm/mach-omap1/timer32k.c +++ b/arch/arm/mach-omap1/timer32k.c @@ -46,7 +46,6 @@ #include <linux/clockchips.h> #include <linux/io.h> -#include <asm/leds.h> #include <asm/irq.h> #include <asm/mach/irq.h> #include <asm/mach/time.h> diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c index 78a6a11d821..9b1c9531029 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c @@ -18,7 +18,6 @@ #include <linux/ethtool.h> #include <net/dsa.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c index 2f5dc54cd4c..51ba2b81a10 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c @@ -19,7 +19,6 @@ #include <linux/i2c.h> #include <net/dsa.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c index 399130fac0b..0a56b9444f1 100644 --- a/arch/arm/mach-orion5x/rd88f5182-setup.c +++ b/arch/arm/mach-orion5x/rd88f5182-setup.c @@ -19,8 +19,8 @@ #include <linux/mv643xx_eth.h> #include <linux/ata_platform.h> #include <linux/i2c.h> +#include <linux/leds.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> @@ -53,12 +53,6 @@ #define RD88F5182_PCI_SLOT0_IRQ_A_PIN 7 #define RD88F5182_PCI_SLOT0_IRQ_B_PIN 6 -/* - * GPIO Debug LED - */ - -#define RD88F5182_GPIO_DBG_LED 0 - /***************************************************************************** * 16M NOR Flash on Device bus CS1 ****************************************************************************/ @@ -83,55 +77,32 @@ static struct platform_device rd88f5182_nor_flash = { .resource = &rd88f5182_nor_flash_resource, }; -#ifdef CONFIG_LEDS - /***************************************************************************** - * Use GPIO debug led as CPU active indication + * Use GPIO LED as CPU active indication ****************************************************************************/ -static void rd88f5182_dbgled_event(led_event_t evt) -{ - int val; - - if (evt == led_idle_end) - val = 1; - else if (evt == led_idle_start) - val = 0; - else - return; - - gpio_set_value(RD88F5182_GPIO_DBG_LED, val); -} - -static int __init rd88f5182_dbgled_init(void) -{ - int pin; - - if (machine_is_rd88f5182()) { - pin = RD88F5182_GPIO_DBG_LED; +#define RD88F5182_GPIO_LED 0 - if (gpio_request(pin, "DBGLED") == 0) { - if (gpio_direction_output(pin, 0) != 0) { - printk(KERN_ERR "rd88f5182_dbgled_init failed " - "to set output pin %d\n", pin); - gpio_free(pin); - return 0; - } - } else { - printk(KERN_ERR "rd88f5182_dbgled_init failed " - "to request gpio %d\n", pin); - return 0; - } - - leds_event = rd88f5182_dbgled_event; - } - - return 0; -} +static struct gpio_led rd88f5182_gpio_led_pins[] = { + { + .name = "rd88f5182:cpu", + .default_trigger = "cpu0", + .gpio = RD88F5182_GPIO_LED, + }, +}; -__initcall(rd88f5182_dbgled_init); +static struct gpio_led_platform_data rd88f5182_gpio_led_data = { + .leds = rd88f5182_gpio_led_pins, + .num_leds = ARRAY_SIZE(rd88f5182_gpio_led_pins), +}; -#endif +static struct platform_device rd88f5182_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &rd88f5182_gpio_led_data, + }, +}; /***************************************************************************** * PCI @@ -298,6 +269,7 @@ static void __init rd88f5182_init(void) orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE); platform_device_register(&rd88f5182_nor_flash); + platform_device_register(&rd88f5182_gpio_leds); i2c_register_board_info(0, &rd88f5182_i2c_rtc, 1); } diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c index 92df49c1b62..ed50910b08a 100644 --- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c @@ -20,7 +20,6 @@ #include <linux/ethtool.h> #include <net/dsa.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c index 0cfe8af3d3b..47a7ae96156 100644 --- a/arch/arm/mach-pnx4008/time.c +++ b/arch/arm/mach-pnx4008/time.c @@ -25,7 +25,6 @@ #include <linux/io.h> #include <mach/hardware.h> -#include <asm/leds.h> #include <asm/mach/time.h> #include <asm/errno.h> diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index be0f7df8685..d4337e300ad 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -95,12 +95,4 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o obj-$(CONFIG_MACH_ZIPIT2) += z2.o -# Support for blinky lights -led-y := leds.o -led-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o -led-$(CONFIG_MACH_MAINSTONE) += leds-mainstone.o -led-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o - -obj-$(CONFIG_LEDS) += $(led-y) - obj-$(CONFIG_TOSA_BT) += tosa-bt.o diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 6ff466bd43e..ae1e9977603 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -191,6 +191,87 @@ static void __init idp_map_io(void) iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc)); } +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct idp_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} idp_leds[] = { + { "idp:green", "heartbeat", }, + { "idp:red", "cpu0", }, +}; + +static void idp_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct idp_led *led = container_of(cdev, + struct idp_led, cdev); + u32 reg = IDP_CPLD_LED_CONTROL; + + if (b != LED_OFF) + reg &= ~led->mask; + else + reg |= led->mask; + + IDP_CPLD_LED_CONTROL = reg; +} + +static enum led_brightness idp_led_get(struct led_classdev *cdev) +{ + struct idp_led *led = container_of(cdev, + struct idp_led, cdev); + + return (IDP_CPLD_LED_CONTROL & led->mask) ? LED_OFF : LED_FULL; +} + +static int __init idp_leds_init(void) +{ + int i; + + if (!machine_is_pxa_idp()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(idp_leds); i++) { + struct idp_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = idp_leds[i].name; + led->cdev.brightness_set = idp_led_set; + led->cdev.brightness_get = idp_led_get; + led->cdev.default_trigger = idp_leds[i].trigger; + + if (i == 0) + led->mask = IDP_HB_LED; + else + led->mask = IDP_BUSY_LED; + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(idp_leds_init); +#endif MACHINE_START(PXA_IDP, "Vibren PXA255 IDP") /* Maintainer: Vibren Technologies */ diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c deleted file mode 100644 index 06b060025d1..00000000000 --- a/arch/arm/mach-pxa/leds-idp.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds-idp.c - * - * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> - * - * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> - * - * Original (leds-footbridge.c) by Russell King - * - * Macros for actual LED manipulation should be in machine specific - * files in this 'mach' directory. - */ - - -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include <mach/pxa25x.h> -#include <mach/idp.h> - -#include "leds.h" - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void idp_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = IDP_HB_LED | IDP_BUSY_LED; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = IDP_HB_LED | IDP_BUSY_LED; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = IDP_HB_LED | IDP_BUSY_LED; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= IDP_HB_LED; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~IDP_BUSY_LED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= IDP_BUSY_LED; - break; -#endif - - case led_halted: - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= IDP_HB_LED; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~IDP_HB_LED; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= IDP_BUSY_LED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~IDP_BUSY_LED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state); - else - IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK; - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c deleted file mode 100644 index 0bd85c884a7..00000000000 --- a/arch/arm/mach-pxa/leds-lubbock.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds-lubbock.c - * - * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> - * - * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> - * - * Original (leds-footbridge.c) by Russell King - * - * Major surgery on April 2004 by Nicolas Pitre for less global - * namespace collision. Mostly adapted the Mainstone version. - */ - -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <mach/pxa25x.h> -#include <mach/lubbock.h> - -#include "leds.h" - -/* - * 8 discrete leds available for general use: - * - * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays - * so be sure to not monkey with them here. - */ - -#define D28 (1 << 0) -#define D27 (1 << 1) -#define D26 (1 << 2) -#define D25 (1 << 3) -#define D24 (1 << 4) -#define D23 (1 << 5) -#define D22 (1 << 6) -#define D21 (1 << 7) - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void lubbock_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = 0; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - hw_led_state ^= D26; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - hw_led_state &= ~D27; - break; - - case led_idle_end: - hw_led_state |= D27; - break; -#endif - - case led_halted: - break; - - case led_green_on: - hw_led_state |= D21; - break; - - case led_green_off: - hw_led_state &= ~D21; - break; - - case led_amber_on: - hw_led_state |= D22; - break; - - case led_amber_off: - hw_led_state &= ~D22; - break; - - case led_red_on: - hw_led_state |= D23; - break; - - case led_red_off: - hw_led_state &= ~D23; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - LUB_DISC_BLNK_LED = (LUB_DISC_BLNK_LED | 0xff) & ~hw_led_state; - else - LUB_DISC_BLNK_LED |= 0xff; - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c deleted file mode 100644 index 4058ab340fe..00000000000 --- a/arch/arm/mach-pxa/leds-mainstone.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds-mainstone.c - * - * Author: Nicolas Pitre - * Created: Nov 05, 2002 - * Copyright: MontaVista Software Inc. - * - * 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 <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include <mach/pxa27x.h> -#include <mach/mainstone.h> - -#include "leds.h" - - -/* 8 discrete leds available for general use: */ -#define D28 (1 << 0) -#define D27 (1 << 1) -#define D26 (1 << 2) -#define D25 (1 << 3) -#define D24 (1 << 4) -#define D23 (1 << 5) -#define D22 (1 << 6) -#define D21 (1 << 7) - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void mainstone_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = 0; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - hw_led_state ^= D26; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - hw_led_state &= ~D27; - break; - - case led_idle_end: - hw_led_state |= D27; - break; -#endif - - case led_halted: - break; - - case led_green_on: - hw_led_state |= D21; - break; - - case led_green_off: - hw_led_state &= ~D21; - break; - - case led_amber_on: - hw_led_state |= D22; - break; - - case led_amber_off: - hw_led_state &= ~D22; - break; - - case led_red_on: - hw_led_state |= D23; - break; - - case led_red_off: - hw_led_state &= ~D23; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - MST_LEDCTRL = (MST_LEDCTRL | 0xff) & ~hw_led_state; - else - MST_LEDCTRL |= 0xff; - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c deleted file mode 100644 index bbe4d5f6afa..00000000000 --- a/arch/arm/mach-pxa/leds.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds.c - * - * xscale LEDs dispatcher - * - * Copyright (C) 2001 Nicolas Pitre - * - * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. - */ -#include <linux/compiler.h> -#include <linux/init.h> - -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include "leds.h" - -static int __init -pxa_leds_init(void) -{ - if (machine_is_lubbock()) - leds_event = lubbock_leds_event; - if (machine_is_mainstone()) - leds_event = mainstone_leds_event; - if (machine_is_pxa_idp()) - leds_event = idp_leds_event; - - leds_event(led_start); - return 0; -} - -core_initcall(pxa_leds_init); diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h deleted file mode 100644 index 7f0dfe01345..00000000000 --- a/arch/arm/mach-pxa/leds.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * arch/arm/mach-pxa/leds.h - * - * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. - * - * blinky lights for various PXA-based systems: - * - */ - -extern void idp_leds_event(led_event_t evt); -extern void lubbock_leds_event(led_event_t evt); -extern void mainstone_leds_event(led_event_t evt); -extern void trizeps4_leds_event(led_event_t evt); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 0ca0db78790..3c48035afd6 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/platform_device.h> #include <linux/syscore_ops.h> #include <linux/major.h> @@ -23,6 +24,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/smc91x.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> @@ -549,6 +552,98 @@ static void __init lubbock_map_io(void) PCFR |= PCFR_OPDE; } +/* + * Driver for the 8 discrete LEDs available for general use: + * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays + * so be sure to not monkey with them here. + */ + +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct lubbock_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} lubbock_leds[] = { + { "lubbock:D28", "default-on", }, + { "lubbock:D27", "cpu0", }, + { "lubbock:D26", "heartbeat" }, + { "lubbock:D25", }, + { "lubbock:D24", }, + { "lubbock:D23", }, + { "lubbock:D22", }, + { "lubbock:D21", }, +}; + +static void lubbock_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct lubbock_led *led = container_of(cdev, + struct lubbock_led, cdev); + u32 reg = LUB_DISC_BLNK_LED; + + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; + + LUB_DISC_BLNK_LED = reg; +} + +static enum led_brightness lubbock_led_get(struct led_classdev *cdev) +{ + struct lubbock_led *led = container_of(cdev, + struct lubbock_led, cdev); + u32 reg = LUB_DISC_BLNK_LED; + + return (reg & led->mask) ? LED_FULL : LED_OFF; +} + +static int __init lubbock_leds_init(void) +{ + int i; + + if (!machine_is_lubbock()) + return -ENODEV; + + /* All ON */ + LUB_DISC_BLNK_LED |= 0xff; + for (i = 0; i < ARRAY_SIZE(lubbock_leds); i++) { + struct lubbock_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = lubbock_leds[i].name; + led->cdev.brightness_set = lubbock_led_set; + led->cdev.brightness_get = lubbock_led_get; + led->cdev.default_trigger = lubbock_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(lubbock_leds_init); +#endif + MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") /* Maintainer: MontaVista Software Inc. */ .map_io = lubbock_map_io, diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 1aebaf71946..bdc6c335830 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -28,6 +28,8 @@ #include <linux/pwm_backlight.h> #include <linux/smc91x.h> #include <linux/i2c/pxa-i2c.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <asm/types.h> #include <asm/setup.h> @@ -613,6 +615,98 @@ static void __init mainstone_map_io(void) PCFR = 0x66; } +/* + * Driver for the 8 discrete LEDs available for general use: + * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays + * so be sure to not monkey with them here. + */ + +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct mainstone_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} mainstone_leds[] = { + { "mainstone:D28", "default-on", }, + { "mainstone:D27", "cpu0", }, + { "mainstone:D26", "heartbeat" }, + { "mainstone:D25", }, + { "mainstone:D24", }, + { "mainstone:D23", }, + { "mainstone:D22", }, + { "mainstone:D21", }, +}; + +static void mainstone_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct mainstone_led *led = container_of(cdev, + struct mainstone_led, cdev); + u32 reg = MST_LEDCTRL; + + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; + + MST_LEDCTRL = reg; +} + +static enum led_brightness mainstone_led_get(struct led_classdev *cdev) +{ + struct mainstone_led *led = container_of(cdev, + struct mainstone_led, cdev); + u32 reg = MST_LEDCTRL; + + return (reg & led->mask) ? LED_FULL : LED_OFF; +} + +static int __init mainstone_leds_init(void) +{ + int i; + + if (!machine_is_mainstone()) + return -ENODEV; + + /* All ON */ + MST_LEDCTRL |= 0xff; + for (i = 0; i < ARRAY_SIZE(mainstone_leds); i++) { + struct mainstone_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = mainstone_leds[i].name; + led->cdev.brightness_set = mainstone_led_set; + led->cdev.brightness_get = mainstone_led_get; + led->cdev.default_trigger = mainstone_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(mainstone_leds_init); +#endif + MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") /* Maintainer: MontaVista Software Inc. */ .atag_offset = 0x100, /* BLOB boot parameter setting */ diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 45868bb43cb..d22dee96484 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -35,7 +35,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/hardware/arm_timer.h> #include <asm/hardware/icst.h> @@ -436,44 +435,6 @@ struct clcd_board clcd_plat_data = { .remove = versatile_clcd_remove_dma, }; -#ifdef CONFIG_LEDS -#define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET) - -void realview_leds_event(led_event_t ledevt) -{ - unsigned long flags; - u32 val; - u32 led = 1 << smp_processor_id(); - - local_irq_save(flags); - val = readl(VA_LEDS_BASE); - - switch (ledevt) { - case led_idle_start: - val = val & ~led; - break; - - case led_idle_end: - val = val | led; - break; - - case led_timer: - val = val ^ REALVIEW_SYS_LED7; - break; - - case led_halted: - val = 0; - break; - - default: - break; - } - - writel(val, VA_LEDS_BASE); - local_irq_restore(flags); -} -#endif /* CONFIG_LEDS */ - /* * Where is the timer (VA)? */ diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index f8f2c0ac4c0..f2141ae5a7d 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -26,7 +26,6 @@ #include <linux/io.h> #include <asm/setup.h> -#include <asm/leds.h> #define APB_DEVICE(name, busid, base, plat) \ static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat) @@ -47,7 +46,6 @@ extern void __iomem *timer1_va_base; extern void __iomem *timer2_va_base; extern void __iomem *timer3_va_base; -extern void realview_leds_event(led_event_t ledevt); extern void realview_timer_init(unsigned int timer_irq); extern int realview_flash_register(struct resource *res, u32 num); extern int realview_eth_register(const char *name, struct resource *res); diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index baf382c5e77..21661ade885 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -30,7 +30,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pmu.h> #include <asm/pgtable.h> @@ -462,10 +461,6 @@ static void __init realview_eb_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_EB, "ARM-RealView EB") diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index b1d7cafa1a6..c0ff882c5cb 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -32,7 +32,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pmu.h> #include <asm/pgtable.h> @@ -375,10 +374,6 @@ static void __init realview_pb1176_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176") diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index a98c536e332..30779ae40c0 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -30,7 +30,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pmu.h> #include <asm/pgtable.h> @@ -357,10 +356,6 @@ static void __init realview_pb11mp_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore") diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index 59650174e6e..081cd72c090 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -29,7 +29,6 @@ #include <linux/io.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pmu.h> #include <asm/pgtable.h> @@ -299,10 +298,6 @@ static void __init realview_pba8_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8") diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index 3f2f605624e..1ce62b9f846 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -28,7 +28,6 @@ #include <linux/io.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pmu.h> #include <asm/smp_twd.h> @@ -394,10 +393,6 @@ static void __init realview_pbx_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX") diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 60b97ec0167..1aed9e70465 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -7,21 +7,17 @@ obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o obj-m := obj-n := obj- := -led-y := leds.o obj-$(CONFIG_CPU_FREQ_SA1100) += cpu-sa1100.o obj-$(CONFIG_CPU_FREQ_SA1110) += cpu-sa1110.o # Specific board support obj-$(CONFIG_SA1100_ASSABET) += assabet.o -led-$(CONFIG_SA1100_ASSABET) += leds-assabet.o obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o obj-$(CONFIG_SA1100_BADGE4) += badge4.o -led-$(CONFIG_SA1100_BADGE4) += leds-badge4.o obj-$(CONFIG_SA1100_CERF) += cerf.o -led-$(CONFIG_SA1100_CERF) += leds-cerf.o obj-$(CONFIG_SA1100_COLLIE) += collie.o @@ -29,13 +25,11 @@ obj-$(CONFIG_SA1100_H3100) += h3100.o h3xxx.o obj-$(CONFIG_SA1100_H3600) += h3600.o h3xxx.o obj-$(CONFIG_SA1100_HACKKIT) += hackkit.o -led-$(CONFIG_SA1100_HACKKIT) += leds-hackkit.o obj-$(CONFIG_SA1100_JORNADA720) += jornada720.o obj-$(CONFIG_SA1100_JORNADA720_SSP) += jornada720_ssp.o obj-$(CONFIG_SA1100_LART) += lart.o -led-$(CONFIG_SA1100_LART) += leds-lart.o obj-$(CONFIG_SA1100_NANOENGINE) += nanoengine.o obj-$(CONFIG_PCI_NANOENGINE) += pci-nanoengine.o @@ -46,9 +40,6 @@ obj-$(CONFIG_SA1100_SHANNON) += shannon.o obj-$(CONFIG_SA1100_SIMPAD) += simpad.o -# LEDs support -obj-$(CONFIG_LEDS) += $(led-y) - # Miscellaneous functions obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_SA1100_SSP) += ssp.o diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index d673211f121..1710ed1a0ac 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -20,6 +20,8 @@ #include <linux/mtd/partitions.h> #include <linux/delay.h> #include <linux/mm.h> +#include <linux/leds.h> +#include <linux/slab.h> #include <video/sa1100fb.h> @@ -529,6 +531,89 @@ static void __init assabet_map_io(void) sa1100_register_uart(2, 3); } +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct assabet_led { + struct led_classdev cdev; + u32 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} assabet_leds[] = { + { "assabet:red", "cpu0",}, + { "assabet:green", "heartbeat", }, +}; + +/* + * The LED control in Assabet is reversed: + * - setting bit means turn off LED + * - clearing bit means turn on LED + */ +static void assabet_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct assabet_led *led = container_of(cdev, + struct assabet_led, cdev); + + if (b != LED_OFF) + ASSABET_BCR_clear(led->mask); + else + ASSABET_BCR_set(led->mask); +} + +static enum led_brightness assabet_led_get(struct led_classdev *cdev) +{ + struct assabet_led *led = container_of(cdev, + struct assabet_led, cdev); + + return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL; +} + +static int __init assabet_leds_init(void) +{ + int i; + + if (!machine_is_assabet()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) { + struct assabet_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = assabet_leds[i].name; + led->cdev.brightness_set = assabet_led_set; + led->cdev.brightness_get = assabet_led_get; + led->cdev.default_trigger = assabet_leds[i].trigger; + + if (!i) + led->mask = ASSABET_BCR_LED_RED; + else + led->mask = ASSABET_BCR_LED_GREEN; + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(assabet_leds_init); +#endif MACHINE_START(ASSABET, "Intel-Assabet") .atag_offset = 0x100, diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index b30fb99b587..038df4894b0 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -22,6 +22,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/leds.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -76,8 +78,36 @@ static struct platform_device sa1111_device = { .resource = sa1111_resources, }; +/* LEDs */ +struct gpio_led badge4_gpio_leds[] = { + { + .name = "badge4:red", + .default_trigger = "heartbeat", + .gpio = 7, + }, + { + .name = "badge4:green", + .default_trigger = "cpu0", + .gpio = 9, + }, +}; + +static struct gpio_led_platform_data badge4_gpio_led_info = { + .leds = badge4_gpio_leds, + .num_leds = ARRAY_SIZE(badge4_gpio_leds), +}; + +static struct platform_device badge4_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &badge4_gpio_led_info, + } +}; + static struct platform_device *devices[] __initdata = { &sa1111_device, + &badge4_leds, }; static int __init badge4_sa1111_init(void) diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 09d7f4b4b35..5240f104a3c 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -17,6 +17,8 @@ #include <linux/irq.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/gpio.h> +#include <linux/leds.h> #include <mach/hardware.h> #include <asm/setup.h> @@ -43,8 +45,48 @@ static struct platform_device cerfuart2_device = { .resource = cerfuart2_resources, }; +/* LEDs */ +struct gpio_led cerf_gpio_leds[] = { + { + .name = "cerf:d0", + .default_trigger = "heartbeat", + .gpio = 0, + }, + { + .name = "cerf:d1", + .default_trigger = "cpu0", + .gpio = 1, + }, + { + .name = "cerf:d2", + .default_trigger = "default-on", + .gpio = 2, + }, + { + .name = "cerf:d3", + .default_trigger = "default-on", + .gpio = 3, + }, + +}; + +static struct gpio_led_platform_data cerf_gpio_led_info = { + .leds = cerf_gpio_leds, + .num_leds = ARRAY_SIZE(cerf_gpio_leds), +}; + +static struct platform_device cerf_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &cerf_gpio_led_info, + } +}; + + static struct platform_device *cerf_devices[] __initdata = { &cerfuart2_device, + &cerf_leds, }; #ifdef CONFIG_SA1100_CERF_FLASH_32MB diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c index 7f86bd91182..fc106aab7c7 100644 --- a/arch/arm/mach-sa1100/hackkit.c +++ b/arch/arm/mach-sa1100/hackkit.c @@ -21,6 +21,10 @@ #include <linux/serial_core.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/tty.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/platform_device.h> #include <asm/mach-types.h> #include <asm/setup.h> @@ -183,9 +187,37 @@ static struct flash_platform_data hackkit_flash_data = { static struct resource hackkit_flash_resource = DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M); +/* LEDs */ +struct gpio_led hackkit_gpio_leds[] = { + { + .name = "hackkit:red", + .default_trigger = "cpu0", + .gpio = 22, + }, + { + .name = "hackkit:green", + .default_trigger = "heartbeat", + .gpio = 23, + }, +}; + +static struct gpio_led_platform_data hackkit_gpio_led_info = { + .leds = hackkit_gpio_leds, + .num_leds = ARRAY_SIZE(hackkit_gpio_leds), +}; + +static struct platform_device hackkit_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &hackkit_gpio_led_info, + } +}; + static void __init hackkit_init(void) { sa11x0_register_mtd(&hackkit_flash_data, &hackkit_flash_resource, 1); + platform_device_register(&hackkit_leds); } /********************************************************************** diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index b775a0abec0..b2ce04bf4c9 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -5,6 +5,9 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/tty.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/platform_device.h> #include <video/sa1100fb.h> @@ -126,6 +129,27 @@ static struct map_desc lart_io_desc[] __initdata = { } }; +/* LEDs */ +struct gpio_led lart_gpio_leds[] = { + { + .name = "lart:red", + .default_trigger = "cpu0", + .gpio = 23, + }, +}; + +static struct gpio_led_platform_data lart_gpio_led_info = { + .leds = lart_gpio_leds, + .num_leds = ARRAY_SIZE(lart_gpio_leds), +}; + +static struct platform_device lart_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &lart_gpio_led_info, + } +}; static void __init lart_map_io(void) { sa1100_map_io(); @@ -139,6 +163,8 @@ static void __init lart_map_io(void) GPDR |= GPIO_UART_TXD; GPDR &= ~GPIO_UART_RXD; PPAR |= PPAR_UPR; + + platform_device_register(&lart_leds); } MACHINE_START(LART, "LART") diff --git a/arch/arm/mach-sa1100/leds-assabet.c b/arch/arm/mach-sa1100/leds-assabet.c deleted file mode 100644 index 3699176bca9..00000000000 --- a/arch/arm/mach-sa1100/leds-assabet.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-assabet.c - * - * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> - * - * Original (leds-footbridge.c) by Russell King - * - * Assabet uses the LEDs as follows: - * - Green - toggles state every 50 timer interrupts - * - Red - on if system is not idle - */ -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <mach/assabet.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define ASSABET_BCR_LED_MASK (ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED) - -void assabet_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state); - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= ASSABET_BCR_LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= ASSABET_BCR_LED_RED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~ASSABET_BCR_LED_RED; - break; -#endif - - case led_halted: - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~ASSABET_BCR_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= ASSABET_BCR_LED_GREEN; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~ASSABET_BCR_LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= ASSABET_BCR_LED_RED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state); - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-badge4.c b/arch/arm/mach-sa1100/leds-badge4.c deleted file mode 100644 index f99fac3eedb..00000000000 --- a/arch/arm/mach-sa1100/leds-badge4.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-badge4.c - * - * Author: Christopher Hoover <ch@hpl.hp.com> - * Copyright (C) 2002 Hewlett-Packard Company - * - * 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 <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_RED GPIO_GPIO(7) -#define LED_GREEN GPIO_GPIO(9) -#define LED_MASK (LED_RED|LED_GREEN) - -#define LED_IDLE LED_GREEN -#define LED_TIMER LED_RED - -void badge4_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - GPDR |= LED_MASK; - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_TIMER; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - /* LED off when system is idle */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_IDLE; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_IDLE; - break; -#endif - - case led_red_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_RED; - break; - - case led_red_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_RED; - break; - - case led_green_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_GREEN; - break; - - case led_green_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_GREEN; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-cerf.c b/arch/arm/mach-sa1100/leds-cerf.c deleted file mode 100644 index 30fc3b2bf55..00000000000 --- a/arch/arm/mach-sa1100/leds-cerf.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-cerf.c - * - * Author: ??? - */ -#include <linux/init.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_D0 GPIO_GPIO(0) -#define LED_D1 GPIO_GPIO(1) -#define LED_D2 GPIO_GPIO(2) -#define LED_D3 GPIO_GPIO(3) -#define LED_MASK (LED_D0|LED_D1|LED_D2|LED_D3) - -void cerf_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_D0; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D1; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D1; - break; -#endif - case led_green_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D2; - break; - - case led_green_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D2; - break; - - case led_amber_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D3; - break; - - case led_amber_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D3; - break; - - case led_red_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D1; - break; - - case led_red_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D1; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c deleted file mode 100644 index 6a2352436e6..00000000000 --- a/arch/arm/mach-sa1100/leds-hackkit.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-hackkit.c - * - * based on leds-lart.c - * - * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 - * (C) Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>, 2002 - * - * The HackKit has two leds (GPIO 22/23). The red led (gpio 22) is used - * as cpu led, the green one is used as timer led. - */ -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_GREEN GPIO_GPIO23 -#define LED_RED GPIO_GPIO22 -#define LED_MASK (LED_RED | LED_GREEN) - -void hackkit_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: - /* pin 22/23 are outputs */ - GPDR |= LED_MASK; - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - /* The LART people like the LED to be off when the - system is idle... */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_RED; - break; - - case led_idle_end: - /* ... and on if the system is not idle */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_RED; - break; -#endif - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_RED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_GREEN; - break; - - default: - break; - } - - /* Now set the GPIO state, or nothing will happen at all */ - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-lart.c b/arch/arm/mach-sa1100/leds-lart.c deleted file mode 100644 index 50a5b143b46..00000000000 --- a/arch/arm/mach-sa1100/leds-lart.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-lart.c - * - * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 - * - * LART uses the LED as follows: - * - GPIO23 is the LED, on if system is not idle - * You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same - * time, but in that case the timer events will still dictate the - * pace of the LED. - */ -#include <linux/init.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_23 GPIO_GPIO23 -#define LED_MASK (LED_23) - -void lart_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: - /* pin 23 is output pin */ - GPDR |= LED_23; - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_23; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - /* The LART people like the LED to be off when the - system is idle... */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_23; - break; - - case led_idle_end: - /* ... and on if the system is not idle */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_23; - break; -#endif - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_23; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_23; - break; - - default: - break; - } - - /* Now set the GPIO state, or nothing will happen at all */ - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c deleted file mode 100644 index 5fe71a0f105..00000000000 --- a/arch/arm/mach-sa1100/leds.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds.c - * - * SA1100 LEDs dispatcher - * - * Copyright (C) 2001 Nicolas Pitre - */ -#include <linux/compiler.h> -#include <linux/init.h> - -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include "leds.h" - -static int __init -sa1100_leds_init(void) -{ - if (machine_is_assabet()) - leds_event = assabet_leds_event; - if (machine_is_consus()) - leds_event = consus_leds_event; - if (machine_is_badge4()) - leds_event = badge4_leds_event; - if (machine_is_brutus()) - leds_event = brutus_leds_event; - if (machine_is_cerf()) - leds_event = cerf_leds_event; - if (machine_is_flexanet()) - leds_event = flexanet_leds_event; - if (machine_is_graphicsclient()) - leds_event = graphicsclient_leds_event; - if (machine_is_hackkit()) - leds_event = hackkit_leds_event; - if (machine_is_lart()) - leds_event = lart_leds_event; - if (machine_is_pfs168()) - leds_event = pfs168_leds_event; - if (machine_is_graphicsmaster()) - leds_event = graphicsmaster_leds_event; - if (machine_is_adsbitsy()) - leds_event = adsbitsy_leds_event; - if (machine_is_pt_system3()) - leds_event = system3_leds_event; - - leds_event(led_start); - return 0; -} - -core_initcall(sa1100_leds_init); diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h deleted file mode 100644 index 776b6020f55..00000000000 --- a/arch/arm/mach-sa1100/leds.h +++ /dev/null @@ -1,13 +0,0 @@ -extern void assabet_leds_event(led_event_t evt); -extern void badge4_leds_event(led_event_t evt); -extern void consus_leds_event(led_event_t evt); -extern void brutus_leds_event(led_event_t evt); -extern void cerf_leds_event(led_event_t evt); -extern void flexanet_leds_event(led_event_t evt); -extern void graphicsclient_leds_event(led_event_t evt); -extern void hackkit_leds_event(led_event_t evt); -extern void lart_leds_event(led_event_t evt); -extern void pfs168_leds_event(led_event_t evt); -extern void graphicsmaster_leds_event(led_event_t evt); -extern void adsbitsy_leds_event(led_event_t evt); -extern void system3_leds_event(led_event_t evt); diff --git a/arch/arm/mach-shark/Makefile b/arch/arm/mach-shark/Makefile index 45be9b04e7b..29657183c45 100644 --- a/arch/arm/mach-shark/Makefile +++ b/arch/arm/mach-shark/Makefile @@ -4,9 +4,7 @@ # Object file lists. -obj-y := core.o dma.o irq.o pci.o +obj-y := core.o dma.o irq.o pci.o leds.o obj-m := obj-n := obj- := - -obj-$(CONFIG_LEDS) += leds.o diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index 2704bcd869c..c709979ee75 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -13,7 +13,6 @@ #include <asm/setup.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/param.h> #include <asm/system_misc.h> diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c index 25609076921..081c778a10a 100644 --- a/arch/arm/mach-shark/leds.c +++ b/arch/arm/mach-shark/leds.c @@ -1,165 +1,117 @@ /* - * arch/arm/mach-shark/leds.c - * by Alexander Schulz - * - * derived from: - * arch/arm/kernel/leds-footbridge.c - * Copyright (C) 1998-1999 Russell King - * * DIGITAL Shark LED control routines. * - * The leds use is as follows: - * - Green front - toggles state every 50 timer interrupts - * - Amber front - Unused, this is a dual color led (Amber/Green) - * - Amber back - On if system is not idle + * Driver for the 3 user LEDs found on the Shark + * Based on Versatile and RealView machine LED code * - * Changelog: + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> */ #include <linux/kernel.h> -#include <linux/module.h> #include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/ioport.h> #include <linux/io.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/leds.h> -#include <asm/leds.h> +#include <asm/mach-types.h> -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct shark_led { + struct led_classdev cdev; + u8 mask; +}; -#define SEQUOIA_LED_GREEN (1<<6) -#define SEQUOIA_LED_AMBER (1<<5) -#define SEQUOIA_LED_BACK (1<<7) +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} shark_leds[] = { + { "shark:amber0", "default-on", }, /* Bit 5 */ + { "shark:green", "heartbeat", }, /* Bit 6 */ + { "shark:amber1", "cpu0" }, /* Bit 7 */ +}; + +static u16 led_reg_read(void) +{ + outw(0x09, 0x24); + return inw(0x26); +} -static char led_state; -static short hw_led_state; -static short saved_state; +static void led_reg_write(u16 value) +{ + outw(0x09, 0x24); + outw(value, 0x26); +} -static DEFINE_RAW_SPINLOCK(leds_lock); +static void shark_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct shark_led *led = container_of(cdev, + struct shark_led, cdev); + u16 reg = led_reg_read(); -short sequoia_read(int addr) { - outw(addr,0x24); - return inw(0x26); -} + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; -void sequoia_write(short value,short addr) { - outw(addr,0x24); - outw(value,0x26); + led_reg_write(reg); } -static void sequoia_leds_event(led_event_t evt) +static enum led_brightness shark_led_get(struct led_classdev *cdev) { - unsigned long flags; - - raw_spin_lock_irqsave(&leds_lock, flags); + struct shark_led *led = container_of(cdev, + struct shark_led, cdev); + u16 reg = led_reg_read(); - hw_led_state = sequoia_read(0x09); + return (reg & led->mask) ? LED_FULL : LED_OFF; +} - switch (evt) { - case led_start: - hw_led_state |= SEQUOIA_LED_GREEN; - hw_led_state |= SEQUOIA_LED_AMBER; -#ifdef CONFIG_LEDS_CPU - hw_led_state |= SEQUOIA_LED_BACK; -#else - hw_led_state &= ~SEQUOIA_LED_BACK; -#endif - led_state |= LED_STATE_ENABLED; - break; - - case led_stop: - hw_led_state &= ~SEQUOIA_LED_BACK; - hw_led_state |= SEQUOIA_LED_GREEN; - hw_led_state |= SEQUOIA_LED_AMBER; - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - saved_state = hw_led_state; - hw_led_state &= ~SEQUOIA_LED_BACK; - hw_led_state |= SEQUOIA_LED_GREEN; - hw_led_state |= SEQUOIA_LED_AMBER; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = saved_state; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= SEQUOIA_LED_GREEN; - break; -#endif +static int __init shark_leds_init(void) +{ + int i; + u16 reg; -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~SEQUOIA_LED_BACK; - break; + if (!machine_is_shark()) + return -ENODEV; - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= SEQUOIA_LED_BACK; - break; -#endif + for (i = 0; i < ARRAY_SIZE(shark_leds); i++) { + struct shark_led *led; - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~SEQUOIA_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= SEQUOIA_LED_GREEN; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~SEQUOIA_LED_AMBER; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= SEQUOIA_LED_AMBER; - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= SEQUOIA_LED_BACK; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~SEQUOIA_LED_BACK; - break; - - default: - break; - } + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; - if (led_state & LED_STATE_ENABLED) - sequoia_write(hw_led_state,0x09); + led->cdev.name = shark_leds[i].name; + led->cdev.brightness_set = shark_led_set; + led->cdev.brightness_get = shark_led_get; + led->cdev.default_trigger = shark_leds[i].trigger; - raw_spin_unlock_irqrestore(&leds_lock, flags); -} + /* Count in 5 bits offset */ + led->mask = BIT(i + 5); -static int __init leds_init(void) -{ - extern void (*leds_event)(led_event_t); - short temp; - - leds_event = sequoia_leds_event; + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } /* Make LEDs independent of power-state */ - request_region(0x24,4,"sequoia"); - temp = sequoia_read(0x09); - temp |= 1<<10; - sequoia_write(temp,0x09); - leds_event(led_start); + request_region(0x24, 4, "led_reg"); + reg = led_reg_read(); + reg |= 1 << 10; + led_reg_write(reg); + return 0; } -__initcall(leds_init); +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(shark_leds_init); +#endif diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index cd8ea3588f9..855ca02581e 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -37,7 +37,6 @@ #include <linux/mtd/physmap.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/hardware/arm_timer.h> #include <asm/hardware/icst.h> #include <asm/hardware/vic.h> @@ -763,10 +762,6 @@ void __init versatile_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = versatile_leds_event; -#endif } /* diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index dd36eba9506..13910baae22 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -41,9 +41,8 @@ config OMAP_DEBUG_DEVICES For debug cards on TI reference boards. config OMAP_DEBUG_LEDS - bool + def_bool y if NEW_LEDS depends on OMAP_DEBUG_DEVICES - default y if LEDS_CLASS config POWER_AVS_OMAP bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2" diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c index 39407cbe34c..24e23f3dd6a 100644 --- a/arch/arm/plat-omap/debug-leds.c +++ b/arch/arm/plat-omap/debug-leds.c @@ -1,279 +1,118 @@ /* * linux/arch/arm/plat-omap/debug-leds.c * + * Copyright 2011 by Bryan Wu <bryan.wu@canonical.com> * Copyright 2003 by Texas Instruments Incorporated * * 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 <linux/gpio.h> + +#include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/leds.h> #include <linux/io.h> +#include <linux/slab.h> #include <mach/hardware.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <plat/fpga.h> - /* Many OMAP development platforms reuse the same "debug board"; these * platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the * debug board (all green), accessed through FPGA registers. - * - * The "surfer" expansion board and H2 sample board also have two-color - * green+red LEDs (in parallel), used here for timer and idle indicators - * in preference to the ones on the debug board, for a "Disco LED" effect. - * - * This driver exports either the original ARM LED API, the new generic - * one, or both. - */ - -static spinlock_t lock; -static struct h2p2_dbg_fpga __iomem *fpga; -static u16 led_state, hw_led_state; - - -#ifdef CONFIG_OMAP_DEBUG_LEDS -#define new_led_api() 1 -#else -#define new_led_api() 0 -#endif - - -/*-------------------------------------------------------------------------*/ - -/* original ARM debug LED API: - * - timer and idle leds (some boards use non-FPGA leds here); - * - up to 4 generic leds, easily accessed in-kernel (any context) */ -#define GPIO_LED_RED 3 -#define GPIO_LED_GREEN OMAP_MPUIO(4) - -#define LED_STATE_ENABLED 0x01 -#define LED_STATE_CLAIMED 0x02 -#define LED_TIMER_ON 0x04 - -#define GPIO_IDLE GPIO_LED_GREEN -#define GPIO_TIMER GPIO_LED_RED - -static void h2p2_dbg_leds_event(led_event_t evt) -{ - unsigned long flags; - - spin_lock_irqsave(&lock, flags); - - if (!(led_state & LED_STATE_ENABLED) && evt != led_start) - goto done; - - switch (evt) { - case led_start: - if (fpga) - led_state |= LED_STATE_ENABLED; - break; - - case led_stop: - case led_halted: - /* all leds off during suspend or shutdown */ - - if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) { - gpio_set_value(GPIO_TIMER, 0); - gpio_set_value(GPIO_IDLE, 0); - } - - __raw_writew(~0, &fpga->leds); - led_state &= ~LED_STATE_ENABLED; - goto done; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - led_state ^= LED_TIMER_ON; - - if (machine_is_omap_perseus2() || machine_is_omap_h4()) - hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER; - else { - gpio_set_value(GPIO_TIMER, - led_state & LED_TIMER_ON); - goto done; - } - - break; -#endif - -#ifdef CONFIG_LEDS_CPU - /* LED lit iff busy */ - case led_idle_start: - if (machine_is_omap_perseus2() || machine_is_omap_h4()) - hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 1); - goto done; - } - - break; +static struct h2p2_dbg_fpga __iomem *fpga; - case led_idle_end: - if (machine_is_omap_perseus2() || machine_is_omap_h4()) - hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 0); - goto done; - } - - break; -#endif - - case led_green_on: - hw_led_state |= H2P2_DBG_FPGA_LED_GREEN; - break; - case led_green_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN; - break; - - case led_amber_on: - hw_led_state |= H2P2_DBG_FPGA_LED_AMBER; - break; - case led_amber_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER; - break; - - case led_red_on: - hw_led_state |= H2P2_DBG_FPGA_LED_RED; - break; - case led_red_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_RED; - break; - - case led_blue_on: - hw_led_state |= H2P2_DBG_FPGA_LED_BLUE; - break; - case led_blue_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE; - break; - - default: - break; - } - - - /* - * Actually burn the LEDs - */ - if (led_state & LED_STATE_ENABLED) - __raw_writew(~hw_led_state, &fpga->leds); - -done: - spin_unlock_irqrestore(&lock, flags); -} - -/*-------------------------------------------------------------------------*/ - -/* "new" LED API - * - with syfs access and generic triggering - * - not readily accessible to in-kernel drivers - */ +static u16 fpga_led_state; struct dbg_led { struct led_classdev cdev; u16 mask; }; -static struct dbg_led dbg_leds[] = { - /* REVISIT at least H2 uses different timer & cpu leds... */ -#ifndef CONFIG_LEDS_TIMER - { .mask = 1 << 0, .cdev.name = "d4:green", - .cdev.default_trigger = "heartbeat", }, -#endif -#ifndef CONFIG_LEDS_CPU - { .mask = 1 << 1, .cdev.name = "d5:green", }, /* !idle */ -#endif - { .mask = 1 << 2, .cdev.name = "d6:green", }, - { .mask = 1 << 3, .cdev.name = "d7:green", }, - - { .mask = 1 << 4, .cdev.name = "d8:green", }, - { .mask = 1 << 5, .cdev.name = "d9:green", }, - { .mask = 1 << 6, .cdev.name = "d10:green", }, - { .mask = 1 << 7, .cdev.name = "d11:green", }, - - { .mask = 1 << 8, .cdev.name = "d12:green", }, - { .mask = 1 << 9, .cdev.name = "d13:green", }, - { .mask = 1 << 10, .cdev.name = "d14:green", }, - { .mask = 1 << 11, .cdev.name = "d15:green", }, - -#ifndef CONFIG_LEDS - { .mask = 1 << 12, .cdev.name = "d16:green", }, - { .mask = 1 << 13, .cdev.name = "d17:green", }, - { .mask = 1 << 14, .cdev.name = "d18:green", }, - { .mask = 1 << 15, .cdev.name = "d19:green", }, -#endif +static const struct { + const char *name; + const char *trigger; +} dbg_leds[] = { + { "dbg:d4", "heartbeat", }, + { "dbg:d5", "cpu0", }, + { "dbg:d6", "default-on", }, + { "dbg:d7", }, + { "dbg:d8", }, + { "dbg:d9", }, + { "dbg:d10", }, + { "dbg:d11", }, + { "dbg:d12", }, + { "dbg:d13", }, + { "dbg:d14", }, + { "dbg:d15", }, + { "dbg:d16", }, + { "dbg:d17", }, + { "dbg:d18", }, + { "dbg:d19", }, }; -static void -fpga_led_set(struct led_classdev *cdev, enum led_brightness value) +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static void dbg_led_set(struct led_classdev *cdev, + enum led_brightness b) { - struct dbg_led *led = container_of(cdev, struct dbg_led, cdev); - unsigned long flags; + struct dbg_led *led = container_of(cdev, struct dbg_led, cdev); + u16 reg; - spin_lock_irqsave(&lock, flags); - if (value == LED_OFF) - hw_led_state &= ~led->mask; + reg = __raw_readw(&fpga->leds); + if (b != LED_OFF) + reg |= led->mask; else - hw_led_state |= led->mask; - __raw_writew(~hw_led_state, &fpga->leds); - spin_unlock_irqrestore(&lock, flags); + reg &= ~led->mask; + __raw_writew(reg, &fpga->leds); } -static void __init newled_init(struct device *dev) +static enum led_brightness dbg_led_get(struct led_classdev *cdev) { - unsigned i; - struct dbg_led *led; - int status; + struct dbg_led *led = container_of(cdev, struct dbg_led, cdev); + u16 reg; - for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) { - led->cdev.brightness_set = fpga_led_set; - status = led_classdev_register(dev, &led->cdev); - if (status < 0) - break; - } - return; + reg = __raw_readw(&fpga->leds); + return (reg & led->mask) ? LED_FULL : LED_OFF; } - -/*-------------------------------------------------------------------------*/ - -static int /* __init */ fpga_probe(struct platform_device *pdev) +static int fpga_probe(struct platform_device *pdev) { struct resource *iomem; - - spin_lock_init(&lock); + int i; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) return -ENODEV; fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE); - __raw_writew(~0, &fpga->leds); + __raw_writew(0xff, &fpga->leds); + + for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) { + struct dbg_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; -#ifdef CONFIG_LEDS - leds_event = h2p2_dbg_leds_event; - leds_event(led_start); -#endif + led->cdev.name = dbg_leds[i].name; + led->cdev.brightness_set = dbg_led_set; + led->cdev.brightness_get = dbg_led_get; + led->cdev.default_trigger = dbg_leds[i].trigger; + led->mask = BIT(i); - if (new_led_api()) { - newled_init(&pdev->dev); + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } } return 0; @@ -281,13 +120,15 @@ static int /* __init */ fpga_probe(struct platform_device *pdev) static int fpga_suspend_noirq(struct device *dev) { - __raw_writew(~0, &fpga->leds); + fpga_led_state = __raw_readw(&fpga->leds); + __raw_writew(0xff, &fpga->leds); + return 0; } static int fpga_resume_noirq(struct device *dev) { - __raw_writew(~hw_led_state, &fpga->leds); + __raw_writew(~fpga_led_state, &fpga->leds); return 0; } diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c index 4dcb11c3d89..60552e22f22 100644 --- a/arch/arm/plat-samsung/time.c +++ b/arch/arm/plat-samsung/time.c @@ -28,7 +28,6 @@ #include <linux/io.h> #include <linux/platform_device.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/irq.h> diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig index 8d5c10a5084..2a4ae8a6a08 100644 --- a/arch/arm/plat-versatile/Kconfig +++ b/arch/arm/plat-versatile/Kconfig @@ -16,8 +16,10 @@ config PLAT_VERSATILE_FPGA_IRQ_NR depends on PLAT_VERSATILE_FPGA_IRQ config PLAT_VERSATILE_LEDS - def_bool y if LEDS_CLASS + def_bool y if NEW_LEDS depends on ARCH_REALVIEW || ARCH_VERSATILE + select LEDS_CLASS + select LEDS_TRIGGER config PLAT_VERSATILE_SCHED_CLOCK def_bool y diff --git a/arch/arm/plat-versatile/leds.c b/arch/arm/plat-versatile/leds.c index 3169fa555ea..d2490d00b46 100644 --- a/arch/arm/plat-versatile/leds.c +++ b/arch/arm/plat-versatile/leds.c @@ -37,10 +37,10 @@ static const struct { } versatile_leds[] = { { "versatile:0", "heartbeat", }, { "versatile:1", "mmc0", }, - { "versatile:2", }, - { "versatile:3", }, - { "versatile:4", }, - { "versatile:5", }, + { "versatile:2", "cpu0" }, + { "versatile:3", "cpu1" }, + { "versatile:4", "cpu2" }, + { "versatile:5", "cpu3" }, { "versatile:6", }, { "versatile:7", }, }; diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index d45c3345b4a..a0e2f7d7035 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -30,7 +30,6 @@ #include <asm/hardware/dec21285.h> #include <asm/io.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/uaccess.h> @@ -179,9 +178,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, written = 0; - leds_event(led_claim); - leds_event(led_green_on); - nBlock = (int) p >> 16; //block # of 64K bytes /* @@ -258,11 +254,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written); } - /* - * restore reg on exit - */ - leds_event(led_release); - mutex_unlock(&nwflash_mutex); return written; @@ -334,11 +325,6 @@ static int erase_block(int nBlock) int temp, temp1; /* - * orange LED == erase - */ - leds_event(led_amber_on); - - /* * reset footbridge to the correct offset 0 (...0..3) */ *CSR_ROMWRITEREG = 0; @@ -446,12 +432,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) unsigned long timeout; unsigned long timeout1; - /* - * red LED == write - */ - leds_event(led_amber_off); - leds_event(led_red_on); - pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); /* @@ -558,17 +538,9 @@ static int write_block(unsigned long p, const char __user *buf, int count) pWritePtr - FLASH_BASE); /* - * no LED == waiting - */ - leds_event(led_amber_off); - /* * wait couple ms */ msleep(10); - /* - * red LED == write - */ - leds_event(led_red_on); goto WriteRetry; } else { @@ -583,12 +555,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) } } - /* - * green LED == read/verify - */ - leds_event(led_amber_off); - leds_event(led_green_on); - msleep(10); pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c96bbaadeeb..16578d3b52b 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -506,6 +506,16 @@ config LEDS_TRIGGER_BACKLIGHT If unsure, say N. +config LEDS_TRIGGER_CPU + bool "LED CPU Trigger" + depends on LEDS_TRIGGERS + help + This allows LEDs to be controlled by active CPUs. This shows + the active CPUs across an array of LEDs so you can see which + CPUs are active on the system at any given moment. + + If unsure, say N. + config LEDS_TRIGGER_GPIO tristate "LED GPIO Trigger" depends on LEDS_TRIGGERS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index a4429a9217b..a9b627c4f8b 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -61,5 +61,6 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o +obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c new file mode 100644 index 00000000000..b312056da14 --- /dev/null +++ b/drivers/leds/ledtrig-cpu.c @@ -0,0 +1,163 @@ +/* + * ledtrig-cpu.c - LED trigger based on CPU activity + * + * This LED trigger will be registered for each possible CPU and named as + * cpu0, cpu1, cpu2, cpu3, etc. + * + * It can be bound to any LED just like other triggers using either a + * board file or via sysfs interface. + * + * An API named ledtrig_cpu is exported for any user, who want to add CPU + * activity indication in their code + * + * Copyright 2011 Linus Walleij <linus.walleij@linaro.org> + * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com> + * + * 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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/percpu.h> +#include <linux/syscore_ops.h> +#include <linux/rwsem.h> +#include "leds.h" + +#define MAX_NAME_LEN 8 + +struct led_trigger_cpu { + char name[MAX_NAME_LEN]; + struct led_trigger *_trig; + struct mutex lock; + int lock_is_inited; +}; + +static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig); + +/** + * ledtrig_cpu - emit a CPU event as a trigger + * @evt: CPU event to be emitted + * + * Emit a CPU event on a CPU core, which will trigger a + * binded LED to turn on or turn off. + */ +void ledtrig_cpu(enum cpu_led_event ledevt) +{ + struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig); + + /* mutex lock should be initialized before calling mutex_call() */ + if (!trig->lock_is_inited) + return; + + mutex_lock(&trig->lock); + + /* Locate the correct CPU LED */ + switch (ledevt) { + case CPU_LED_IDLE_END: + case CPU_LED_START: + /* Will turn the LED on, max brightness */ + led_trigger_event(trig->_trig, LED_FULL); + break; + + case CPU_LED_IDLE_START: + case CPU_LED_STOP: + case CPU_LED_HALTED: + /* Will turn the LED off */ + led_trigger_event(trig->_trig, LED_OFF); + break; + + default: + /* Will leave the LED as it is */ + break; + } + + mutex_unlock(&trig->lock); +} +EXPORT_SYMBOL(ledtrig_cpu); + +static int ledtrig_cpu_syscore_suspend(void) +{ + ledtrig_cpu(CPU_LED_STOP); + return 0; +} + +static void ledtrig_cpu_syscore_resume(void) +{ + ledtrig_cpu(CPU_LED_START); +} + +static void ledtrig_cpu_syscore_shutdown(void) +{ + ledtrig_cpu(CPU_LED_HALTED); +} + +static struct syscore_ops ledtrig_cpu_syscore_ops = { + .shutdown = ledtrig_cpu_syscore_shutdown, + .suspend = ledtrig_cpu_syscore_suspend, + .resume = ledtrig_cpu_syscore_resume, +}; + +static int __init ledtrig_cpu_init(void) +{ + int cpu; + + /* Supports up to 9999 cpu cores */ + BUILD_BUG_ON(CONFIG_NR_CPUS > 9999); + + /* + * Registering CPU led trigger for each CPU core here + * ignores CPU hotplug, but after this CPU hotplug works + * fine with this trigger. + */ + for_each_possible_cpu(cpu) { + struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); + + mutex_init(&trig->lock); + + snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); + + mutex_lock(&trig->lock); + led_trigger_register_simple(trig->name, &trig->_trig); + trig->lock_is_inited = 1; + mutex_unlock(&trig->lock); + } + + register_syscore_ops(&ledtrig_cpu_syscore_ops); + + pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n"); + + return 0; +} +module_init(ledtrig_cpu_init); + +static void __exit ledtrig_cpu_exit(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); + + mutex_lock(&trig->lock); + + led_trigger_unregister_simple(trig->_trig); + trig->_trig = NULL; + memset(trig->name, 0, MAX_NAME_LEN); + trig->lock_is_inited = 0; + + mutex_unlock(&trig->lock); + mutex_destroy(&trig->lock); + } + + unregister_syscore_ops(&ledtrig_cpu_syscore_ops); +} +module_exit(ledtrig_cpu_exit); + +MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); +MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>"); +MODULE_DESCRIPTION("CPU LED trigger"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/leds.h b/include/linux/leds.h index 3aade1d8f41..c6f8dad2ceb 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -237,4 +237,20 @@ struct gpio_led_platform_data { struct platform_device *gpio_led_register_device( int id, const struct gpio_led_platform_data *pdata); +enum cpu_led_event { + CPU_LED_IDLE_START, /* CPU enters idle */ + CPU_LED_IDLE_END, /* CPU idle ends */ + CPU_LED_START, /* Machine starts, especially resume */ + CPU_LED_STOP, /* Machine stops, especially suspend */ + CPU_LED_HALTED, /* Machine shutdown */ +}; +#ifdef CONFIG_LEDS_TRIGGER_CPU +extern void ledtrig_cpu(enum cpu_led_event evt); +#else +static inline void ledtrig_cpu(enum cpu_led_event evt) +{ + return; +} +#endif + #endif /* __LINUX_LEDS_H_INCLUDED */ |