linux/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c
<<
>>
Prefs
   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
  20static 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. */
  36static 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
  44void 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
  52int 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