diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /arch/arm/mach-shark/leds.c | |
Diffstat (limited to 'arch/arm/mach-shark/leds.c')
| -rw-r--r-- | arch/arm/mach-shark/leds.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c new file mode 100644 index 00000000..081c778a --- /dev/null +++ b/arch/arm/mach-shark/leds.c @@ -0,0 +1,117 @@ +/* + * DIGITAL Shark LED control routines. + * + * Driver for the 3 user LEDs found on the Shark + * Based on Versatile and RealView machine LED code + * + * 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/io.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/leds.h> + +#include <asm/mach-types.h> + +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct shark_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; +} 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 void led_reg_write(u16 value) +{ + outw(0x09, 0x24); + outw(value, 0x26); +} + +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(); + + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; + + led_reg_write(reg); +} + +static enum led_brightness shark_led_get(struct led_classdev *cdev) +{ + struct shark_led *led = container_of(cdev, + struct shark_led, cdev); + u16 reg = led_reg_read(); + + return (reg & led->mask) ? LED_FULL : LED_OFF; +} + +static int __init shark_leds_init(void) +{ + int i; + u16 reg; + + if (!machine_is_shark()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(shark_leds); i++) { + struct shark_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + 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; + + /* Count in 5 bits offset */ + led->mask = BIT(i + 5); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + /* Make LEDs independent of power-state */ + request_region(0x24, 4, "led_reg"); + reg = led_reg_read(); + reg |= 1 << 10; + led_reg_write(reg); + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(shark_leds_init); +#endif |
