Add support for radio on led indicator. Control led via BCMA gpio driver. Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Reviewed-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: Piotr Haber <phaber@broadcom.com> [arend@broadcom.com: modify Makefile for conditional compile led.c] Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
		
			
				
	
	
		
			126 lines
		
	
	
	
		
			3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
	
		
			3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
#include <net/mac80211.h>
 | 
						|
#include <linux/bcma/bcma_driver_chipcommon.h>
 | 
						|
#include <linux/gpio.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.gpio == -1)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (wl->radio_led.active_low)
 | 
						|
		state = !state;
 | 
						|
 | 
						|
	if (state)
 | 
						|
		gpio_set_value(wl->radio_led.gpio, 1);
 | 
						|
	else
 | 
						|
		gpio_set_value(wl->radio_led.gpio, 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.gpio != -1)
 | 
						|
		gpio_free(wl->radio_led.gpio);
 | 
						|
}
 | 
						|
 | 
						|
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 };
 | 
						|
	unsigned gpio = -1;
 | 
						|
	bool active_low = false;
 | 
						|
 | 
						|
	/* none by default */
 | 
						|
	radio_led->gpio = -1;
 | 
						|
	radio_led->active_low = false;
 | 
						|
 | 
						|
	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) {
 | 
						|
			gpio = bcma_gpio->base + i;
 | 
						|
			if (led & BRCMS_LED_AL_MASK)
 | 
						|
				active_low = true;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (gpio == -1 || !gpio_is_valid(gpio))
 | 
						|
		return -ENODEV;
 | 
						|
 | 
						|
	/* request and configure LED gpio */
 | 
						|
	err = gpio_request_one(gpio,
 | 
						|
				active_low ? GPIOF_OUT_INIT_HIGH
 | 
						|
					: GPIOF_OUT_INIT_LOW,
 | 
						|
				"radio on");
 | 
						|
	if (err) {
 | 
						|
		wiphy_err(wl->wiphy, "requesting led gpio %d failed (err: %d)\n",
 | 
						|
			  gpio, err);
 | 
						|
		return err;
 | 
						|
	}
 | 
						|
	err = gpio_direction_output(gpio, 1);
 | 
						|
	if (err) {
 | 
						|
		wiphy_err(wl->wiphy, "cannot set led gpio %d to output (err: %d)\n",
 | 
						|
			  gpio, 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 gpio: %d\n",
 | 
						|
		   wl->radio_led.name,
 | 
						|
		   gpio);
 | 
						|
	radio_led->gpio = gpio;
 | 
						|
	radio_led->active_low = active_low;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |