diff options
author | Piotr Haber <phaber@broadcom.com> | 2013-03-03 06:45:20 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-03-06 16:28:20 -0500 |
commit | cd864522b349cfe88903cf6f3415293c39856b6c (patch) | |
tree | af4f249a27c55053f59b6cded29b641535ced413 /drivers/net/wireless/brcm80211/brcmsmac | |
parent | 98929824eec490984e42ac9dc3b96f7f12033996 (diff) |
brcmsmac: radio on led support
Add support for radio on led indicator.
Control led via BCMA gpio driver.
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Piotr Haber <phaber@broadcom.com>
[arend@broadcom.com: modify Makefile for conditional compile led.c]
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmsmac')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/Makefile | 4 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/led.c | 126 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/led.h | 36 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h | 4 |
5 files changed, 174 insertions, 0 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile index d3d4151c3eda..cba19d839b77 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile | |||
@@ -43,6 +43,10 @@ BRCMSMAC_OFILES := \ | |||
43 | brcms_trace_events.o \ | 43 | brcms_trace_events.o \ |
44 | debug.o | 44 | debug.o |
45 | 45 | ||
46 | ifdef CONFIG_BCMA_DRIVER_GPIO | ||
47 | BRCMSMAC_OFILES += led.o | ||
48 | endif | ||
49 | |||
46 | MODULEPFX := brcmsmac | 50 | MODULEPFX := brcmsmac |
47 | 51 | ||
48 | obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o | 52 | obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o |
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 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/led.h b/drivers/net/wireless/brcm80211/brcmsmac/led.h new file mode 100644 index 000000000000..17a0b1f5dbcf --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/led.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Broadcom Corporation | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _BRCM_LED_H_ | ||
18 | #define _BRCM_LED_H_ | ||
19 | struct brcms_led { | ||
20 | char name[32]; | ||
21 | unsigned gpio; | ||
22 | bool active_low; | ||
23 | }; | ||
24 | |||
25 | #ifdef CONFIG_BCMA_DRIVER_GPIO | ||
26 | void brcms_led_unregister(struct brcms_info *wl); | ||
27 | int brcms_led_register(struct brcms_info *wl); | ||
28 | #else | ||
29 | static inline void brcms_led_unregister(struct brcms_info *wl) {}; | ||
30 | static inline int brcms_led_register(struct brcms_info *wl) | ||
31 | { | ||
32 | return -ENOTSUPP; | ||
33 | }; | ||
34 | #endif | ||
35 | |||
36 | #endif /* _BRCM_LED_H_ */ | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index c6451c61407a..c70cf7b654cd 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "mac80211_if.h" | 34 | #include "mac80211_if.h" |
35 | #include "main.h" | 35 | #include "main.h" |
36 | #include "debug.h" | 36 | #include "debug.h" |
37 | #include "led.h" | ||
37 | 38 | ||
38 | #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ | 39 | #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ |
39 | #define BRCMS_FLUSH_TIMEOUT 500 /* msec */ | 40 | #define BRCMS_FLUSH_TIMEOUT 500 /* msec */ |
@@ -904,6 +905,7 @@ static void brcms_remove(struct bcma_device *pdev) | |||
904 | struct brcms_info *wl = hw->priv; | 905 | struct brcms_info *wl = hw->priv; |
905 | 906 | ||
906 | if (wl->wlc) { | 907 | if (wl->wlc) { |
908 | brcms_led_unregister(wl); | ||
907 | wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); | 909 | wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); |
908 | wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); | 910 | wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); |
909 | ieee80211_unregister_hw(hw); | 911 | ieee80211_unregister_hw(hw); |
@@ -1151,6 +1153,8 @@ static int brcms_bcma_probe(struct bcma_device *pdev) | |||
1151 | pr_err("%s: brcms_attach failed!\n", __func__); | 1153 | pr_err("%s: brcms_attach failed!\n", __func__); |
1152 | return -ENODEV; | 1154 | return -ENODEV; |
1153 | } | 1155 | } |
1156 | brcms_led_register(wl); | ||
1157 | |||
1154 | return 0; | 1158 | return 0; |
1155 | } | 1159 | } |
1156 | 1160 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h index 947ccacf43e6..4090032e81a2 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h | |||
@@ -20,8 +20,10 @@ | |||
20 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
23 | #include <linux/leds.h> | ||
23 | 24 | ||
24 | #include "ucode_loader.h" | 25 | #include "ucode_loader.h" |
26 | #include "led.h" | ||
25 | /* | 27 | /* |
26 | * Starting index for 5G rates in the | 28 | * Starting index for 5G rates in the |
27 | * legacy rate table. | 29 | * legacy rate table. |
@@ -81,6 +83,8 @@ struct brcms_info { | |||
81 | struct wiphy *wiphy; | 83 | struct wiphy *wiphy; |
82 | struct brcms_ucode ucode; | 84 | struct brcms_ucode ucode; |
83 | bool mute_tx; | 85 | bool mute_tx; |
86 | struct brcms_led radio_led; | ||
87 | struct led_classdev led_dev; | ||
84 | }; | 88 | }; |
85 | 89 | ||
86 | /* misc callbacks */ | 90 | /* misc callbacks */ |