diff options
3 files changed, 329 insertions, 0 deletions
| diff --git a/package/mac80211/patches/580-ath9k_extra_leds.patch b/package/mac80211/patches/580-ath9k_extra_leds.patch new file mode 100644 index 000000000..a07960724 --- /dev/null +++ b/package/mac80211/patches/580-ath9k_extra_leds.patch @@ -0,0 +1,258 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -474,6 +474,9 @@ void ath9k_btcoex_timer_pause(struct ath + #ifdef CONFIG_MAC80211_LEDS + void ath_init_leds(struct ath_softc *sc); + void ath_deinit_leds(struct ath_softc *sc); ++int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name, ++                        const char *trigger, bool active_low); ++ + #else + static inline void ath_init_leds(struct ath_softc *sc) + { +@@ -594,6 +597,13 @@ struct ath9k_vif_iter_data { + 	int nothers;   /* number of vifs not specified above. */ + }; +  ++struct ath_led { ++	struct list_head list; ++	struct ath_softc *sc; ++	const struct gpio_led *gpio; ++	struct led_classdev cdev; ++}; ++ + struct ath_softc { + 	struct ieee80211_hw *hw; + 	struct device *dev; +@@ -637,9 +647,8 @@ struct ath_softc { + 	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; +  + #ifdef CONFIG_MAC80211_LEDS +-	bool led_registered; +-	char led_name[32]; +-	struct led_classdev led_cdev; ++	const char *led_default_trigger; ++	struct list_head leds; + #endif +  + 	struct ath9k_hw_cal_data caldata; +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -24,22 +24,89 @@ + static void ath_led_brightness(struct led_classdev *led_cdev, + 			       enum led_brightness brightness) + { +-	struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); +-	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF)); ++	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; + } +  + void ath_deinit_leds(struct ath_softc *sc) + { +-	if (!sc->led_registered) +-		return; ++	struct ath_led *led; +  +-	ath_led_brightness(&sc->led_cdev, LED_OFF); +-	led_classdev_unregister(&sc->led_cdev); ++	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) + { +-	int ret; ++	char led_name[32]; ++	const char *trigger; ++ ++	INIT_LIST_HEAD(&sc->leds); +  + 	if (AR_SREV_9100(sc->sc_ah)) + 		return; +@@ -57,26 +124,15 @@ void ath_init_leds(struct ath_softc *sc) + 			sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + 	} +  +-	/* Configure gpio 1 for output */ +-	ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, +-			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT); +-	/* LED off, active low */ +-	ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); +- +-	if (!led_blink) +-		sc->led_cdev.default_trigger = +-			ieee80211_get_radio_led_name(sc->hw); +- +-	snprintf(sc->led_name, sizeof(sc->led_name), +-		"ath9k-%s", wiphy_name(sc->hw->wiphy)); +-	sc->led_cdev.name = sc->led_name; +-	sc->led_cdev.brightness_set = ath_led_brightness; ++	snprintf(led_name, sizeof(led_name), "ath9k-%s", ++		 wiphy_name(sc->hw->wiphy)); +  +-	ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev); +-	if (ret < 0) +-		return; ++	if (led_blink) ++		trigger = sc->led_default_trigger; ++	else ++		trigger = ieee80211_get_radio_led_name(sc->hw); +  +-	sc->led_registered = true; ++	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1); + } + #endif +  +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -803,7 +803,7 @@ int ath9k_init_device(u16 devid, struct  +  + #ifdef CONFIG_MAC80211_LEDS + 	/* must be initialized before ieee80211_register_hw */ +-	sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, ++	sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, + 		IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink, + 		ARRAY_SIZE(ath9k_tpt_blink)); + #endif +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1304,6 +1304,61 @@ static const struct file_operations fops + 	.llseek = default_llseek, + }; +  ++#ifdef CONFIG_MAC80211_LEDS ++ ++static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf, ++				   size_t count, loff_t *ppos) ++{ ++	struct ath_softc *sc = file->private_data; ++	char buf[32], *str, *name, *c; ++	ssize_t len; ++	unsigned int gpio; ++	bool active_low = false; ++ ++	len = min(count, sizeof(buf) - 1); ++	if (copy_from_user(buf, ubuf, len)) ++		return -EFAULT; ++ ++	buf[len] = '\0'; ++	name = strchr(buf, ','); ++	if (!name) ++		return -EINVAL; ++ ++	*(name++) = 0; ++	if (!*name) ++		return -EINVAL; ++ ++	c = strchr(name, '\n'); ++	if (c) ++		*c = 0; ++ ++	str = buf; ++	if (*str == '!') { ++		str++; ++		active_low = true; ++	} ++ ++	if (kstrtouint(str, 0, &gpio) < 0) ++		return -EINVAL; ++ ++	if (gpio >= sc->sc_ah->caps.num_gpio_pins) ++		return -EINVAL; ++ ++	if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0) ++		return -EINVAL; ++ ++	return count; ++} ++ ++static const struct file_operations fops_gpio_led = { ++	.write = write_file_gpio_led, ++	.open = ath9k_debugfs_open, ++	.owner = THIS_MODULE, ++	.llseek = default_llseek, ++}; ++ ++#endif ++ + void ath9k_debug_samp_bb_mac(struct ath_softc *sc) + { + #define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c) +@@ -1725,6 +1780,11 @@ int ath9k_init_debug(struct ath_hw *ah) + 	debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, + 			    &fops_samps); +  ++#ifdef CONFIG_MAC80211_LEDS ++	debugfs_create_file("gpio_led", S_IWUSR, ++			   sc->debug.debugfs_phy, sc, &fops_gpio_led); ++#endif ++ + 	debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, + 			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); +  diff --git a/package/mac80211/patches/581-ath9k_extra_platform_leds.patch b/package/mac80211/patches/581-ath9k_extra_platform_leds.patch new file mode 100644 index 000000000..0637269b3 --- /dev/null +++ b/package/mac80211/patches/581-ath9k_extra_platform_leds.patch @@ -0,0 +1,68 @@ +--- a/include/linux/ath9k_platform.h ++++ b/include/linux/ath9k_platform.h +@@ -32,6 +32,9 @@ struct ath9k_platform_data { + 	bool is_clk_25mhz; + 	int (*get_mac_revision)(void); + 	int (*external_reset)(void); ++ ++	int num_leds; ++	const struct gpio_led *leds; + }; +  + #endif /* _LINUX_ATH9K_PLATFORM_H */ +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -14,6 +14,7 @@ +  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +  */ +  ++#include <linux/ath9k_platform.h> + #include "ath9k.h" +  + /********************************/ +@@ -88,6 +89,24 @@ int ath_create_gpio_led(struct ath_softc + 	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; +@@ -103,8 +122,10 @@ void ath_deinit_leds(struct ath_softc *s +  + 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); +  +@@ -133,6 +154,9 @@ void ath_init_leds(struct ath_softc *sc) + 		trigger = ieee80211_get_radio_led_name(sc->hw); +  + 	ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, 1); ++ ++	for (i = 0; i < pdata->num_leds; i++) ++		ath_create_platform_led(sc, &pdata->leds[i]); + } + #endif +  diff --git a/target/linux/generic/files/include/linux/ath9k_platform.h b/target/linux/generic/files/include/linux/ath9k_platform.h index 6e3f54f37..b37d23d83 100644 --- a/target/linux/generic/files/include/linux/ath9k_platform.h +++ b/target/linux/generic/files/include/linux/ath9k_platform.h @@ -32,6 +32,9 @@ struct ath9k_platform_data {  	bool is_clk_25mhz;  	int (*get_mac_revision)(void);  	int (*external_reset)(void); + +	int num_leds; +	const struct gpio_led *leds;  };  #endif /* _LINUX_ATH9K_PLATFORM_H */ | 
