]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
cd864522 PH |
2 | #include <net/mac80211.h> |
3 | #include <linux/bcma/bcma_driver_chipcommon.h> | |
b4248081 LW |
4 | #include <linux/gpio/driver.h> |
5 | #include <linux/gpio/machine.h> | |
6 | #include <linux/gpio/consumer.h> | |
cd864522 PH |
7 | |
8 | #include "mac80211_if.h" | |
9 | #include "pub.h" | |
10 | #include "main.h" | |
11 | #include "led.h" | |
12 | ||
13 | /* number of leds */ | |
14 | #define BRCMS_LED_NO 4 | |
15 | /* behavior mask */ | |
16 | #define BRCMS_LED_BEH_MASK 0x7f | |
17 | /* activelow (polarity) bit */ | |
18 | #define BRCMS_LED_AL_MASK 0x80 | |
19 | /* radio enabled */ | |
20 | #define BRCMS_LED_RADIO 3 | |
21 | ||
22 | static void brcms_radio_led_ctrl(struct brcms_info *wl, bool state) | |
23 | { | |
b4248081 | 24 | if (!wl->radio_led.gpiod) |
cd864522 PH |
25 | return; |
26 | ||
cd864522 | 27 | if (state) |
b4248081 | 28 | gpiod_set_value(wl->radio_led.gpiod, 1); |
cd864522 | 29 | else |
b4248081 | 30 | gpiod_set_value(wl->radio_led.gpiod, 0); |
cd864522 PH |
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); | |
b4248081 LW |
47 | if (wl->radio_led.gpiod) |
48 | gpiochip_free_own_desc(wl->radio_led.gpiod); | |
cd864522 PH |
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 }; | |
b4248081 LW |
63 | int hwnum = -1; |
64 | enum gpio_lookup_flags lflags = GPIO_ACTIVE_HIGH; | |
cd864522 | 65 | |
cd864522 PH |
66 | /* find radio enabled LED */ |
67 | for (i = 0; i < BRCMS_LED_NO; i++) { | |
68 | u8 led = *leds[i]; | |
69 | if ((led & BRCMS_LED_BEH_MASK) == BRCMS_LED_RADIO) { | |
b4248081 | 70 | hwnum = i; |
cd864522 | 71 | if (led & BRCMS_LED_AL_MASK) |
b4248081 | 72 | lflags = GPIO_ACTIVE_LOW; |
cd864522 PH |
73 | break; |
74 | } | |
75 | } | |
76 | ||
b4248081 LW |
77 | /* No LED, bail out */ |
78 | if (hwnum == -1) | |
cd864522 PH |
79 | return -ENODEV; |
80 | ||
b4248081 LW |
81 | /* Try to obtain this LED GPIO line */ |
82 | radio_led->gpiod = gpiochip_request_own_desc(bcma_gpio, hwnum, | |
83 | "radio on", lflags, | |
84 | GPIOD_OUT_LOW); | |
85 | ||
86 | if (IS_ERR(radio_led->gpiod)) { | |
87 | err = PTR_ERR(radio_led->gpiod); | |
88 | wiphy_err(wl->wiphy, "requesting led GPIO failed (err: %d)\n", | |
89 | err); | |
cd864522 PH |
90 | return err; |
91 | } | |
92 | ||
93 | snprintf(wl->radio_led.name, sizeof(wl->radio_led.name), | |
94 | "brcmsmac-%s:radio", wiphy_name(wl->wiphy)); | |
95 | ||
96 | wl->led_dev.name = wl->radio_led.name; | |
97 | wl->led_dev.default_trigger = | |
98 | ieee80211_get_radio_led_name(wl->pub->ieee_hw); | |
99 | wl->led_dev.brightness_set = brcms_led_brightness_set; | |
100 | err = led_classdev_register(wiphy_dev(wl->wiphy), &wl->led_dev); | |
101 | ||
102 | if (err) { | |
103 | wiphy_err(wl->wiphy, "cannot register led device: %s (err: %d)\n", | |
104 | wl->radio_led.name, err); | |
105 | return err; | |
106 | } | |
107 | ||
b4248081 LW |
108 | wiphy_info(wl->wiphy, "registered radio enabled led device: %s\n", |
109 | wl->radio_led.name); | |
cd864522 PH |
110 | |
111 | return 0; | |
112 | } |