platform driver:LED与GPIO

http://lxr.free-electrons.com/source/include/linux/gpio_keys.h?v=3.2;a=arm

https://www.kernel.org/doc/Documentation/leds/leds-class.txt

这是无线网卡的LED功能的实现思路,最终还是会回到kernel里面的LED处理routine。

/********************************/
/*	 LED functions		*/
/********************************/

#ifdef CPTCFG_MAC80211_LEDS
static void ath_led_brightness(struct led_classdev *led_cdev,
			       enum led_brightness brightness)
{
	struct ath_led *led = container_of(led_cdev, struct ath_led, cdev);
	struct ath_softc *sc = led->sc;

	ath9k_ps_wakeup(sc);
	ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio,
			  (brightness != LED_OFF) ^ led->gpio->active_low);
	ath9k_ps_restore(sc);
}

static int ath_add_led(struct ath_softc *sc, struct ath_led *led)
{
	const struct gpio_led *gpio = led->gpio;
	int ret;

	led->cdev.name = gpio->name;
	led->cdev.default_trigger = gpio->default_trigger;
	led->cdev.brightness_set = ath_led_brightness;

	ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev);
	if (ret < 0)
		return ret;

	led->sc = sc;
	list_add(&led->list, &sc->leds);

	/* Configure gpio for output */
	ath9k_hw_cfg_output(sc->sc_ah, gpio->gpio,
			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);

	/* LED off */
	ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low);

	return 0;
}

int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name,
			const char *trigger, bool active_low)
{
	struct ath_led *led;
	struct gpio_led *gpio;
	char *_name;
	int ret;

	led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1,
		      GFP_KERNEL);
	if (!led)
		return -ENOMEM;

	led->gpio = gpio = (struct gpio_led *) (led + 1);
	_name = (char *) (led->gpio + 1);

	strcpy(_name, name);
	gpio->name = _name;
	gpio->gpio = gpio_num;
	gpio->active_low = active_low;
	gpio->default_trigger = trigger;

	ret = ath_add_led(sc, led);
	if (unlikely(ret < 0))
		kfree(led);

	return ret;
}

static int ath_create_platform_led(struct ath_softc *sc,
				   const struct gpio_led *gpio)
{
	struct ath_led *led;
	int ret;

	led = kzalloc(sizeof(*led), GFP_KERNEL);
	if (!led)
		return -ENOMEM;

	led->gpio = gpio;
	ret = ath_add_led(sc, led);
	if (ret < 0)
		kfree(led);

	return ret;
}

void ath_deinit_leds(struct ath_softc *sc)
{
	struct ath_led *led;

	while (!list_empty(&sc->leds)) {
		led = list_first_entry(&sc->leds, struct ath_led, list);
		list_del(&led->list);
		ath_led_brightness(&led->cdev, LED_OFF);
		led_classdev_unregister(&led->cdev);
		kfree(led);
	}
}

void ath_init_leds(struct ath_softc *sc)
{
	struct ath9k_platform_data *pdata = sc->dev->platform_data;
	char led_name[32];
	const char *trigger;
	int i;

	INIT_LIST_HEAD(&sc->leds);

	if (AR_SREV_9100(sc->sc_ah))
		return;

	snprintf(led_name, sizeof(led_name), "ath9k-%s",
		 wiphy_name(sc->hw->wiphy));

	if (led_blink)
		trigger = sc->led_default_trigger;
	else
		trigger = ieee80211_get_radio_led_name(sc->hw);

	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1);

	if (!pdata)
		return;

	for (i = 0; i < pdata->num_leds; i++)
		ath_create_platform_led(sc, &pdata->leds[i]);
}

void ath_fill_led_pin(struct ath_softc *sc)
{
	struct ath_hw *ah = sc->sc_ah;

	if (AR_SREV_9100(ah) || (ah->led_pin >= 0))
		return;

	if (AR_SREV_9287(ah))
		ah->led_pin = ATH_LED_PIN_9287;
	else if (AR_SREV_9485(sc->sc_ah))
		ah->led_pin = ATH_LED_PIN_9485;
	else if (AR_SREV_9300(sc->sc_ah))
		ah->led_pin = ATH_LED_PIN_9300;
	else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
		ah->led_pin = ATH_LED_PIN_9462;
	else
		ah->led_pin = ATH_LED_PIN_DEF;

	/* Configure gpio 1 for output */
	ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);

	/* LED off, active low */
	ath9k_hw_set_gpio(ah, ah->led_pin, 1);
}
#endif

转载于:https://my.oschina.net/rinehart/blog/161366

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值