diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmsmac/led.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/led.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/led.c b/drivers/net/wireless/brcm80211/brcmsmac/led.c new file mode 100644 index 000000000000..74b17cecb189 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/led.c | |||
@@ -0,0 +1,126 @@ | |||
1 | #include <net/mac80211.h> | ||
2 | #include <linux/bcma/bcma_driver_chipcommon.h> | ||
3 | #include <linux/gpio.h> | ||
4 | |||
5 | #include "mac80211_if.h" | ||
6 | #include "pub.h" | ||
7 | #include "main.h" | ||
8 | #include "led.h" | ||
9 | |||
10 | /* number of leds */ | ||
11 | #define BRCMS_LED_NO 4 | ||
12 | /* behavior mask */ | ||
13 | #define BRCMS_LED_BEH_MASK 0x7f | ||
14 | /* activelow (polarity) bit */ | ||
15 | #define BRCMS_LED_AL_MASK 0x80 | ||
16 | /* radio enabled */ | ||
17 | #define BRCMS_LED_RADIO 3 | ||
18 | |||
19 | static void brcms_radio_led_ctrl(struct brcms_info *wl, bool state) | ||
20 | { | ||
21 | if (wl->radio_led.gpio == -1) | ||
22 | return; | ||
23 | |||
24 | if (wl->radio_led.active_low) | ||
25 | state = !state; | ||
26 | |||
27 | if (state) | ||
28 | gpio_set_value(wl->radio_led.gpio, 1); | ||
29 | else | ||
30 | gpio_set_value(wl->radio_led.gpio, 0); | ||
31 | } | ||
32 | |||
33 | |||
34 | /* Callback from the LED subsystem. */ | ||
35 | static void brcms_led_brightness_set(struct led_classdev *led_dev, | ||
36 | enum led_brightness brightness) | ||
37 | { | ||
38 | struct brcms_info *wl = container_of(led_dev, | ||
39 | struct brcms_info, led_dev); | ||
40 | brcms_radio_led_ctrl(wl, brightness); | ||
41 | } | ||
42 | |||
43 | void brcms_led_unregister(struct brcms_info *wl) | ||
44 | { | ||
45 | if (wl->led_dev.dev) | ||
46 | led_classdev_unregister(&wl->led_dev); | ||
47 | if (wl->radio_led.gpio != -1) | ||
48 | gpio_free(wl->radio_led.gpio); | ||
49 | } | ||
50 | |||
51 | int brcms_led_register(struct brcms_info *wl) | ||
52 | { | ||
53 | int i, err; | ||
54 | struct brcms_led *radio_led = &wl->radio_led; | ||
55 | /* get CC core */ | ||
56 | struct bcma_drv_cc *cc_drv = &wl->wlc->hw->d11core->bus->drv_cc; | ||
57 | struct gpio_chip *bcma_gpio = &cc_drv->gpio; | ||
58 | struct ssb_sprom *sprom = &wl->wlc->hw->d11core->bus->sprom; | ||
59 | u8 *leds[] = { &sprom->gpio0, | ||
60 | &sprom->gpio1, | ||
61 | &sprom->gpio2, | ||
62 | &sprom->gpio3 }; | ||
63 | unsigned gpio = -1; | ||
64 | bool active_low = false; | ||
65 | |||
66 | /* none by default */ | ||
67 | radio_led->gpio = -1; | ||
68 | radio_led->active_low = false; | ||
69 | |||
70 | if (!bcma_gpio || !gpio_is_valid(bcma_gpio->base)) | ||
71 | return -ENODEV; | ||
72 | |||
73 | /* find radio enabled LED */ | ||
74 | for (i = 0; i < BRCMS_LED_NO; i++) { | ||
75 | u8 led = *leds[i]; | ||
76 | if ((led & BRCMS_LED_BEH_MASK) == BRCMS_LED_RADIO) { | ||
77 | gpio = bcma_gpio->base + i; | ||
78 | if (led & BRCMS_LED_AL_MASK) | ||
79 | active_low = true; | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | if (gpio == -1 || !gpio_is_valid(gpio)) | ||
85 | return -ENODEV; | ||
86 | |||
87 | /* request and configure LED gpio */ | ||
88 | err = gpio_request_one(gpio, | ||
89 | active_low ? GPIOF_OUT_INIT_HIGH | ||
90 | : GPIOF_OUT_INIT_LOW, | ||
91 | "radio on"); | ||
92 | if (err) { | ||
93 | wiphy_err(wl->wiphy, "requesting led gpio %d failed (err: %d)\n", | ||
94 | gpio, err); | ||
95 | return err; | ||
96 | } | ||
97 | err = gpio_direction_output(gpio, 1); | ||
98 | if (err) { | ||
99 | wiphy_err(wl->wiphy, "cannot set led gpio %d to output (err: %d)\n", | ||
100 | gpio, err); | ||
101 | return err; | ||
102 | } | ||
103 | |||
104 | snprintf(wl->radio_led.name, sizeof(wl->radio_led.name), | ||
105 | "brcmsmac-%s:radio", wiphy_name(wl->wiphy)); | ||
106 | |||
107 | wl->led_dev.name = wl->radio_led.name; | ||
108 | wl->led_dev.default_trigger = | ||
109 | ieee80211_get_radio_led_name(wl->pub->ieee_hw); | ||
110 | wl->led_dev.brightness_set = brcms_led_brightness_set; | ||
111 | err = led_classdev_register(wiphy_dev(wl->wiphy), &wl->led_dev); | ||
112 | |||
113 | if (err) { | ||
114 | wiphy_err(wl->wiphy, "cannot register led device: %s (err: %d)\n", | ||
115 | wl->radio_led.name, err); | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | wiphy_info(wl->wiphy, "registered radio enabled led device: %s gpio: %d\n", | ||
120 | wl->radio_led.name, | ||
121 | gpio); | ||
122 | radio_led->gpio = gpio; | ||
123 | radio_led->active_low = active_low; | ||
124 | |||
125 | return 0; | ||
126 | } | ||