Linus Walleij | b541701 | 2010-07-20 22:32:00 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Driver for the 8 user LEDs found on the RealViews and Versatiles |
| 3 | * Based on DaVinci's DM365 board code |
| 4 | * |
| 5 | * License terms: GNU General Public License (GPL) version 2 |
| 6 | * Author: Linus Walleij <triad@df.lth.se> |
| 7 | */ |
| 8 | #include <linux/kernel.h> |
| 9 | #include <linux/init.h> |
| 10 | #include <linux/io.h> |
| 11 | #include <linux/slab.h> |
| 12 | #include <linux/leds.h> |
| 13 | |
| 14 | #include <mach/hardware.h> |
| 15 | #include <mach/platform.h> |
| 16 | |
| 17 | #ifdef VERSATILE_SYS_BASE |
| 18 | #define LEDREG (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET) |
| 19 | #endif |
| 20 | |
| 21 | #ifdef REALVIEW_SYS_BASE |
| 22 | #define LEDREG (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET) |
| 23 | #endif |
| 24 | |
| 25 | struct versatile_led { |
| 26 | struct led_classdev cdev; |
| 27 | u8 mask; |
| 28 | }; |
| 29 | |
| 30 | /* |
| 31 | * The triggers lines up below will only be used if the |
| 32 | * LED triggers are compiled in. |
| 33 | */ |
| 34 | static const struct { |
| 35 | const char *name; |
| 36 | const char *trigger; |
| 37 | } versatile_leds[] = { |
| 38 | { "versatile:0", "heartbeat", }, |
| 39 | { "versatile:1", "mmc0", }, |
| 40 | { "versatile:2", }, |
| 41 | { "versatile:3", }, |
| 42 | { "versatile:4", }, |
| 43 | { "versatile:5", }, |
| 44 | { "versatile:6", }, |
| 45 | { "versatile:7", }, |
| 46 | }; |
| 47 | |
| 48 | static void versatile_led_set(struct led_classdev *cdev, |
| 49 | enum led_brightness b) |
| 50 | { |
| 51 | struct versatile_led *led = container_of(cdev, |
| 52 | struct versatile_led, cdev); |
| 53 | u32 reg = readl(LEDREG); |
| 54 | |
| 55 | if (b != LED_OFF) |
| 56 | reg |= led->mask; |
| 57 | else |
| 58 | reg &= ~led->mask; |
| 59 | writel(reg, LEDREG); |
| 60 | } |
| 61 | |
| 62 | static enum led_brightness versatile_led_get(struct led_classdev *cdev) |
| 63 | { |
| 64 | struct versatile_led *led = container_of(cdev, |
| 65 | struct versatile_led, cdev); |
| 66 | u32 reg = readl(LEDREG); |
| 67 | |
| 68 | return (reg & led->mask) ? LED_FULL : LED_OFF; |
| 69 | } |
| 70 | |
| 71 | static int __init versatile_leds_init(void) |
| 72 | { |
| 73 | int i; |
| 74 | |
| 75 | /* All ON */ |
| 76 | writel(0xff, LEDREG); |
| 77 | for (i = 0; i < ARRAY_SIZE(versatile_leds); i++) { |
| 78 | struct versatile_led *led; |
| 79 | |
| 80 | led = kzalloc(sizeof(*led), GFP_KERNEL); |
| 81 | if (!led) |
| 82 | break; |
| 83 | |
| 84 | led->cdev.name = versatile_leds[i].name; |
| 85 | led->cdev.brightness_set = versatile_led_set; |
| 86 | led->cdev.brightness_get = versatile_led_get; |
| 87 | led->cdev.default_trigger = versatile_leds[i].trigger; |
| 88 | led->mask = BIT(i); |
| 89 | |
| 90 | if (led_classdev_register(NULL, &led->cdev) < 0) { |
| 91 | kfree(led); |
| 92 | break; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | return 0; |
| 97 | } |
| 98 | |
| 99 | /* |
| 100 | * Since we may have triggers on any subsystem, defer registration |
| 101 | * until after subsystem_init. |
| 102 | */ |
| 103 | fs_initcall(versatile_leds_init); |