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 /arch/arm/plat-omap/debug-leds.c | |
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>
Diffstat (limited to 'arch/arm/plat-omap/debug-leds.c')
-rw-r--r-- | arch/arm/plat-omap/debug-leds.c | 293 |
1 files changed, 67 insertions, 226 deletions
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; } |