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