1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00
linux/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c
Linus Walleij b424808115 brcm80211: brcmsmac: Move LEDs to GPIO descriptors
The code in the BRCM80211 BRCMSMAC driver is using the legacy
GPIO API to to a complex check of the validity of the base of
the GPIO chip and whether it is present at all and then adding
an offset to the base of the chip.

Use the existing function to obtain a GPIO line internally
from a GPIO chip so we can use the offset directly and
modernize the code to use GPIO descriptors instead of integers
from the global GPIO numberspace.

Cc: Wright Feng <wright.feng@cypress.com>
Cc: Frank Kao <frank.kao@cypress.com>
Cc: Kalle Valo <kvalo@codeaurora.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200711210150.4943-1-linus.walleij@linaro.org
2020-07-14 12:51:22 +03:00

115 lines
2.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <net/mac80211.h>
#include <linux/bcma/bcma_driver_chipcommon.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/consumer.h>
#include "mac80211_if.h"
#include "pub.h"
#include "main.h"
#include "led.h"
/* number of leds */
#define BRCMS_LED_NO 4
/* behavior mask */
#define BRCMS_LED_BEH_MASK 0x7f
/* activelow (polarity) bit */
#define BRCMS_LED_AL_MASK 0x80
/* radio enabled */
#define BRCMS_LED_RADIO 3
static void brcms_radio_led_ctrl(struct brcms_info *wl, bool state)
{
if (!wl->radio_led.gpiod)
return;
if (state)
gpiod_set_value(wl->radio_led.gpiod, 1);
else
gpiod_set_value(wl->radio_led.gpiod, 0);
}
/* Callback from the LED subsystem. */
static void brcms_led_brightness_set(struct led_classdev *led_dev,
enum led_brightness brightness)
{
struct brcms_info *wl = container_of(led_dev,
struct brcms_info, led_dev);
brcms_radio_led_ctrl(wl, brightness);
}
void brcms_led_unregister(struct brcms_info *wl)
{
if (wl->led_dev.dev)
led_classdev_unregister(&wl->led_dev);
if (wl->radio_led.gpiod)
gpiochip_free_own_desc(wl->radio_led.gpiod);
}
int brcms_led_register(struct brcms_info *wl)
{
int i, err;
struct brcms_led *radio_led = &wl->radio_led;
/* get CC core */
struct bcma_drv_cc *cc_drv = &wl->wlc->hw->d11core->bus->drv_cc;
struct gpio_chip *bcma_gpio = &cc_drv->gpio;
struct ssb_sprom *sprom = &wl->wlc->hw->d11core->bus->sprom;
u8 *leds[] = { &sprom->gpio0,
&sprom->gpio1,
&sprom->gpio2,
&sprom->gpio3 };
int hwnum = -1;
enum gpio_lookup_flags lflags = GPIO_ACTIVE_HIGH;
if (!bcma_gpio || !gpio_is_valid(bcma_gpio->base))
return -ENODEV;
/* find radio enabled LED */
for (i = 0; i < BRCMS_LED_NO; i++) {
u8 led = *leds[i];
if ((led & BRCMS_LED_BEH_MASK) == BRCMS_LED_RADIO) {
hwnum = i;
if (led & BRCMS_LED_AL_MASK)
lflags = GPIO_ACTIVE_LOW;
break;
}
}
/* No LED, bail out */
if (hwnum == -1)
return -ENODEV;
/* Try to obtain this LED GPIO line */
radio_led->gpiod = gpiochip_request_own_desc(bcma_gpio, hwnum,
"radio on", lflags,
GPIOD_OUT_LOW);
if (IS_ERR(radio_led->gpiod)) {
err = PTR_ERR(radio_led->gpiod);
wiphy_err(wl->wiphy, "requesting led GPIO failed (err: %d)\n",
err);
return err;
}
snprintf(wl->radio_led.name, sizeof(wl->radio_led.name),
"brcmsmac-%s:radio", wiphy_name(wl->wiphy));
wl->led_dev.name = wl->radio_led.name;
wl->led_dev.default_trigger =
ieee80211_get_radio_led_name(wl->pub->ieee_hw);
wl->led_dev.brightness_set = brcms_led_brightness_set;
err = led_classdev_register(wiphy_dev(wl->wiphy), &wl->led_dev);
if (err) {
wiphy_err(wl->wiphy, "cannot register led device: %s (err: %d)\n",
wl->radio_led.name, err);
return err;
}
wiphy_info(wl->wiphy, "registered radio enabled led device: %s\n",
wl->radio_led.name);
return 0;
}