Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
2 | * DIGITAL Shark LED control routines. |
3 | * | |
408a4b2e BW |
4 | * Driver for the 3 user LEDs found on the Shark |
5 | * Based on Versatile and RealView machine LED code | |
1da177e4 | 6 | * |
408a4b2e BW |
7 | * License terms: GNU General Public License (GPL) version 2 |
8 | * Author: Bryan Wu <bryan.wu@canonical.com> | |
1da177e4 | 9 | */ |
1da177e4 | 10 | #include <linux/kernel.h> |
1da177e4 | 11 | #include <linux/init.h> |
fced80c7 | 12 | #include <linux/io.h> |
408a4b2e BW |
13 | #include <linux/ioport.h> |
14 | #include <linux/slab.h> | |
15 | #include <linux/leds.h> | |
1da177e4 | 16 | |
408a4b2e | 17 | #include <asm/mach-types.h> |
1da177e4 | 18 | |
408a4b2e BW |
19 | #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) |
20 | struct shark_led { | |
21 | struct led_classdev cdev; | |
22 | u8 mask; | |
23 | }; | |
eab184c2 | 24 | |
408a4b2e BW |
25 | /* |
26 | * The triggers lines up below will only be used if the | |
27 | * LED triggers are compiled in. | |
28 | */ | |
29 | static const struct { | |
30 | const char *name; | |
31 | const char *trigger; | |
32 | } shark_leds[] = { | |
33 | { "shark:amber0", "default-on", }, /* Bit 5 */ | |
34 | { "shark:green", "heartbeat", }, /* Bit 6 */ | |
35 | { "shark:amber1", "cpu0" }, /* Bit 7 */ | |
36 | }; | |
37 | ||
38 | static u16 led_reg_read(void) | |
39 | { | |
40 | outw(0x09, 0x24); | |
41 | return inw(0x26); | |
42 | } | |
eab184c2 | 43 | |
408a4b2e BW |
44 | static void led_reg_write(u16 value) |
45 | { | |
46 | outw(0x09, 0x24); | |
47 | outw(value, 0x26); | |
48 | } | |
1da177e4 | 49 | |
408a4b2e BW |
50 | static void shark_led_set(struct led_classdev *cdev, |
51 | enum led_brightness b) | |
52 | { | |
53 | struct shark_led *led = container_of(cdev, | |
54 | struct shark_led, cdev); | |
55 | u16 reg = led_reg_read(); | |
1da177e4 | 56 | |
408a4b2e BW |
57 | if (b != LED_OFF) |
58 | reg |= led->mask; | |
59 | else | |
60 | reg &= ~led->mask; | |
1da177e4 | 61 | |
408a4b2e | 62 | led_reg_write(reg); |
1da177e4 LT |
63 | } |
64 | ||
408a4b2e | 65 | static enum led_brightness shark_led_get(struct led_classdev *cdev) |
1da177e4 | 66 | { |
408a4b2e BW |
67 | struct shark_led *led = container_of(cdev, |
68 | struct shark_led, cdev); | |
69 | u16 reg = led_reg_read(); | |
1da177e4 | 70 | |
408a4b2e BW |
71 | return (reg & led->mask) ? LED_FULL : LED_OFF; |
72 | } | |
1da177e4 | 73 | |
408a4b2e BW |
74 | static int __init shark_leds_init(void) |
75 | { | |
76 | int i; | |
77 | u16 reg; | |
1da177e4 | 78 | |
408a4b2e BW |
79 | if (!machine_is_shark()) |
80 | return -ENODEV; | |
1da177e4 | 81 | |
408a4b2e BW |
82 | for (i = 0; i < ARRAY_SIZE(shark_leds); i++) { |
83 | struct shark_led *led; | |
1da177e4 | 84 | |
408a4b2e BW |
85 | led = kzalloc(sizeof(*led), GFP_KERNEL); |
86 | if (!led) | |
87 | break; | |
1da177e4 | 88 | |
408a4b2e BW |
89 | led->cdev.name = shark_leds[i].name; |
90 | led->cdev.brightness_set = shark_led_set; | |
91 | led->cdev.brightness_get = shark_led_get; | |
92 | led->cdev.default_trigger = shark_leds[i].trigger; | |
1da177e4 | 93 | |
408a4b2e BW |
94 | /* Count in 5 bits offset */ |
95 | led->mask = BIT(i + 5); | |
1da177e4 | 96 | |
408a4b2e BW |
97 | if (led_classdev_register(NULL, &led->cdev) < 0) { |
98 | kfree(led); | |
99 | break; | |
100 | } | |
101 | } | |
1da177e4 LT |
102 | |
103 | /* Make LEDs independent of power-state */ | |
408a4b2e BW |
104 | request_region(0x24, 4, "led_reg"); |
105 | reg = led_reg_read(); | |
106 | reg |= 1 << 10; | |
107 | led_reg_write(reg); | |
108 | ||
1da177e4 LT |
109 | return 0; |
110 | } | |
111 | ||
408a4b2e BW |
112 | /* |
113 | * Since we may have triggers on any subsystem, defer registration | |
114 | * until after subsystem_init. | |
115 | */ | |
116 | fs_initcall(shark_leds_init); | |
117 | #endif |