1 // SPDX-License-Identifier: GPL-2.0 2 #include <net/mac80211.h> 3 #include <linux/bcma/bcma_driver_chipcommon.h> 4 #include <linux/gpio/driver.h> 5 #include <linux/gpio/machine.h> 6 #include <linux/gpio/consumer.h> 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 { 24 if (!wl->radio_led.gpiod) 25 return; 26 27 if (state) 28 gpiod_set_value(wl->radio_led.gpiod, 1); 29 else 30 gpiod_set_value(wl->radio_led.gpiod, 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.gpiod) 48 gpiochip_free_own_desc(wl->radio_led.gpiod); 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 int hwnum = -1; 64 enum gpio_lookup_flags lflags = GPIO_ACTIVE_HIGH; 65 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) { 70 hwnum = i; 71 if (led & BRCMS_LED_AL_MASK) 72 lflags = GPIO_ACTIVE_LOW; 73 break; 74 } 75 } 76 77 /* No LED, bail out */ 78 if (hwnum == -1) 79 return -ENODEV; 80 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); 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 108 wiphy_info(wl->wiphy, "registered radio enabled led device: %s\n", 109 wl->radio_led.name); 110 111 return 0; 112 } 113