aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorSujith Manoharan <Sujith.Manoharan@atheros.com>2011-04-28 06:44:05 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-29 15:36:15 -0400
commitd244f21e79162b829c9af09845421d9b4fac4253 (patch)
tree5220722b8938e258f4f3eab67f7eaedd3e88800e /drivers/net/wireless/ath
parent22450902e4a13479acf6f4e93475af7ca1829d92 (diff)
ath9k_htc: Revamp LED management
Remove all the convoluted hacks in the driver and simplify things by making use of mac80211's LED triggers. Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h65
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c188
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c6
4 files changed, 85 insertions, 196 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 6bb71e311a4b..dfc7a982fc7e 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -385,25 +385,6 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
385#define ATH_LED_PIN_9287 10 385#define ATH_LED_PIN_9287 10
386#define ATH_LED_PIN_9271 15 386#define ATH_LED_PIN_9271 15
387#define ATH_LED_PIN_7010 12 387#define ATH_LED_PIN_7010 12
388#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */
389#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */
390
391enum ath_led_type {
392 ATH_LED_RADIO,
393 ATH_LED_ASSOC,
394 ATH_LED_TX,
395 ATH_LED_RX
396};
397
398struct ath_led {
399 struct ath9k_htc_priv *priv;
400 struct led_classdev led_cdev;
401 enum ath_led_type led_type;
402 struct delayed_work brightness_work;
403 char name[32];
404 bool registered;
405 int brightness;
406};
407 388
408#define BSTUCK_THRESHOLD 10 389#define BSTUCK_THRESHOLD 10
409 390
@@ -437,14 +418,11 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
437 418
438#define OP_INVALID BIT(0) 419#define OP_INVALID BIT(0)
439#define OP_SCANNING BIT(1) 420#define OP_SCANNING BIT(1)
440#define OP_LED_ASSOCIATED BIT(2) 421#define OP_ENABLE_BEACON BIT(2)
441#define OP_LED_ON BIT(3) 422#define OP_BT_PRIORITY_DETECTED BIT(3)
442#define OP_ENABLE_BEACON BIT(4) 423#define OP_BT_SCAN BIT(4)
443#define OP_LED_DEINIT BIT(5) 424#define OP_ANI_RUNNING BIT(5)
444#define OP_BT_PRIORITY_DETECTED BIT(6) 425#define OP_TSF_RESET BIT(6)
445#define OP_BT_SCAN BIT(7)
446#define OP_ANI_RUNNING BIT(8)
447#define OP_TSF_RESET BIT(9)
448 426
449struct ath9k_htc_priv { 427struct ath9k_htc_priv {
450 struct device *dev; 428 struct device *dev;
@@ -504,15 +482,13 @@ struct ath9k_htc_priv {
504 bool ps_enabled; 482 bool ps_enabled;
505 bool ps_idle; 483 bool ps_idle;
506 484
507 struct ath_led radio_led; 485#ifdef CONFIG_MAC80211_LEDS
508 struct ath_led assoc_led; 486 enum led_brightness brightness;
509 struct ath_led tx_led; 487 bool led_registered;
510 struct ath_led rx_led; 488 char led_name[32];
511 struct delayed_work ath9k_led_blink_work; 489 struct led_classdev led_cdev;
512 int led_on_duration; 490 struct work_struct led_work;
513 int led_off_duration; 491#endif
514 int led_on_cnt;
515 int led_off_cnt;
516 492
517 int beaconq; 493 int beaconq;
518 int cabq; 494 int cabq;
@@ -597,9 +573,24 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
597void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); 573void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
598void ath9k_htc_radio_enable(struct ieee80211_hw *hw); 574void ath9k_htc_radio_enable(struct ieee80211_hw *hw);
599void ath9k_htc_radio_disable(struct ieee80211_hw *hw); 575void ath9k_htc_radio_disable(struct ieee80211_hw *hw);
600void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv); 576
577#ifdef CONFIG_MAC80211_LEDS
601void ath9k_init_leds(struct ath9k_htc_priv *priv); 578void ath9k_init_leds(struct ath9k_htc_priv *priv);
602void ath9k_deinit_leds(struct ath9k_htc_priv *priv); 579void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
580void ath9k_led_work(struct work_struct *work);
581#else
582static inline void ath9k_init_leds(struct ath9k_htc_priv *priv)
583{
584}
585
586static inline void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
587{
588}
589
590static inline void ath9k_led_work(struct work_struct *work)
591{
592}
593#endif
603 594
604int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, 595int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
605 u16 devid, char *product, u32 drv_info); 596 u16 devid, char *product, u32 drv_info);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 26ede1daa304..af57fe5aab98 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -154,140 +154,41 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
154/* LED */ 154/* LED */
155/*******/ 155/*******/
156 156
157static void ath9k_led_blink_work(struct work_struct *work) 157#ifdef CONFIG_MAC80211_LEDS
158void ath9k_led_work(struct work_struct *work)
158{ 159{
159 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, 160 struct ath9k_htc_priv *priv = container_of(work,
160 ath9k_led_blink_work.work); 161 struct ath9k_htc_priv,
161 162 led_work);
162 if (!(priv->op_flags & OP_LED_ASSOCIATED))
163 return;
164 163
165 if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || 164 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
166 (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) 165 (priv->brightness == LED_OFF));
167 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
168 else
169 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
170 (priv->op_flags & OP_LED_ON) ? 1 : 0);
171
172 ieee80211_queue_delayed_work(priv->hw,
173 &priv->ath9k_led_blink_work,
174 (priv->op_flags & OP_LED_ON) ?
175 msecs_to_jiffies(priv->led_off_duration) :
176 msecs_to_jiffies(priv->led_on_duration));
177
178 priv->led_on_duration = priv->led_on_cnt ?
179 max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
180 ATH_LED_ON_DURATION_IDLE;
181 priv->led_off_duration = priv->led_off_cnt ?
182 max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
183 ATH_LED_OFF_DURATION_IDLE;
184 priv->led_on_cnt = priv->led_off_cnt = 0;
185
186 if (priv->op_flags & OP_LED_ON)
187 priv->op_flags &= ~OP_LED_ON;
188 else
189 priv->op_flags |= OP_LED_ON;
190}
191
192static void ath9k_led_brightness_work(struct work_struct *work)
193{
194 struct ath_led *led = container_of(work, struct ath_led,
195 brightness_work.work);
196 struct ath9k_htc_priv *priv = led->priv;
197
198 switch (led->brightness) {
199 case LED_OFF:
200 if (led->led_type == ATH_LED_ASSOC ||
201 led->led_type == ATH_LED_RADIO) {
202 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
203 (led->led_type == ATH_LED_RADIO));
204 priv->op_flags &= ~OP_LED_ASSOCIATED;
205 if (led->led_type == ATH_LED_RADIO)
206 priv->op_flags &= ~OP_LED_ON;
207 } else {
208 priv->led_off_cnt++;
209 }
210 break;
211 case LED_FULL:
212 if (led->led_type == ATH_LED_ASSOC) {
213 priv->op_flags |= OP_LED_ASSOCIATED;
214 ieee80211_queue_delayed_work(priv->hw,
215 &priv->ath9k_led_blink_work, 0);
216 } else if (led->led_type == ATH_LED_RADIO) {
217 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
218 priv->op_flags |= OP_LED_ON;
219 } else {
220 priv->led_on_cnt++;
221 }
222 break;
223 default:
224 break;
225 }
226} 166}
227 167
228static void ath9k_led_brightness(struct led_classdev *led_cdev, 168static void ath9k_led_brightness(struct led_classdev *led_cdev,
229 enum led_brightness brightness) 169 enum led_brightness brightness)
230{ 170{
231 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); 171 struct ath9k_htc_priv *priv = container_of(led_cdev,
232 struct ath9k_htc_priv *priv = led->priv; 172 struct ath9k_htc_priv,
233 173 led_cdev);
234 led->brightness = brightness;
235 if (!(priv->op_flags & OP_LED_DEINIT))
236 ieee80211_queue_delayed_work(priv->hw,
237 &led->brightness_work, 0);
238}
239 174
240void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) 175 /* Not locked, but it's just a tiny green light..*/
241{ 176 priv->brightness = brightness;
242 cancel_delayed_work_sync(&priv->radio_led.brightness_work); 177 ieee80211_queue_work(priv->hw, &priv->led_work);
243 cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
244 cancel_delayed_work_sync(&priv->tx_led.brightness_work);
245 cancel_delayed_work_sync(&priv->rx_led.brightness_work);
246}
247
248static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
249 char *trigger)
250{
251 int ret;
252
253 led->priv = priv;
254 led->led_cdev.name = led->name;
255 led->led_cdev.default_trigger = trigger;
256 led->led_cdev.brightness_set = ath9k_led_brightness;
257
258 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
259 if (ret)
260 ath_err(ath9k_hw_common(priv->ah),
261 "Failed to register led:%s", led->name);
262 else
263 led->registered = 1;
264
265 INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
266
267 return ret;
268}
269
270static void ath9k_unregister_led(struct ath_led *led)
271{
272 if (led->registered) {
273 led_classdev_unregister(&led->led_cdev);
274 led->registered = 0;
275 }
276} 178}
277 179
278void ath9k_deinit_leds(struct ath9k_htc_priv *priv) 180void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
279{ 181{
280 priv->op_flags |= OP_LED_DEINIT; 182 if (!priv->led_registered)
281 ath9k_unregister_led(&priv->assoc_led); 183 return;
282 priv->op_flags &= ~OP_LED_ASSOCIATED; 184
283 ath9k_unregister_led(&priv->tx_led); 185 ath9k_led_brightness(&priv->led_cdev, LED_OFF);
284 ath9k_unregister_led(&priv->rx_led); 186 led_classdev_unregister(&priv->led_cdev);
285 ath9k_unregister_led(&priv->radio_led); 187 cancel_work_sync(&priv->led_work);
286} 188}
287 189
288void ath9k_init_leds(struct ath9k_htc_priv *priv) 190void ath9k_init_leds(struct ath9k_htc_priv *priv)
289{ 191{
290 char *trigger;
291 int ret; 192 int ret;
292 193
293 if (AR_SREV_9287(priv->ah)) 194 if (AR_SREV_9287(priv->ah))
@@ -305,48 +206,21 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
305 /* LED off, active low */ 206 /* LED off, active low */
306 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); 207 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
307 208
308 INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); 209 snprintf(priv->led_name, sizeof(priv->led_name),
309 210 "ath9k_htc-%s", wiphy_name(priv->hw->wiphy));
310 trigger = ieee80211_get_radio_led_name(priv->hw); 211 priv->led_cdev.name = priv->led_name;
311 snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), 212 priv->led_cdev.brightness_set = ath9k_led_brightness;
312 "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
313 ret = ath9k_register_led(priv, &priv->radio_led, trigger);
314 priv->radio_led.led_type = ATH_LED_RADIO;
315 if (ret)
316 goto fail;
317
318 trigger = ieee80211_get_assoc_led_name(priv->hw);
319 snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
320 "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
321 ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
322 priv->assoc_led.led_type = ATH_LED_ASSOC;
323 if (ret)
324 goto fail;
325
326 trigger = ieee80211_get_tx_led_name(priv->hw);
327 snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
328 "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
329 ret = ath9k_register_led(priv, &priv->tx_led, trigger);
330 priv->tx_led.led_type = ATH_LED_TX;
331 if (ret)
332 goto fail;
333
334 trigger = ieee80211_get_rx_led_name(priv->hw);
335 snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
336 "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
337 ret = ath9k_register_led(priv, &priv->rx_led, trigger);
338 priv->rx_led.led_type = ATH_LED_RX;
339 if (ret)
340 goto fail;
341
342 priv->op_flags &= ~OP_LED_DEINIT;
343 213
344 return; 214 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev);
215 if (ret < 0)
216 return;
345 217
346fail: 218 INIT_WORK(&priv->led_work, ath9k_led_work);
347 cancel_delayed_work_sync(&priv->ath9k_led_blink_work); 219 priv->led_registered = true;
348 ath9k_deinit_leds(priv); 220
221 return;
349} 222}
223#endif
350 224
351/*******************/ 225/*******************/
352/* Rfkill */ 226/* Rfkill */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index d2dd5a63e10a..bfdc8a887183 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -117,6 +117,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = {
117 RATE(540, 0x0c, 0), 117 RATE(540, 0x0c, 0),
118}; 118};
119 119
120#ifdef CONFIG_MAC80211_LEDS
121static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
122 { .throughput = 0 * 1024, .blink_time = 334 },
123 { .throughput = 1 * 1024, .blink_time = 260 },
124 { .throughput = 5 * 1024, .blink_time = 220 },
125 { .throughput = 10 * 1024, .blink_time = 190 },
126 { .throughput = 20 * 1024, .blink_time = 170 },
127 { .throughput = 50 * 1024, .blink_time = 150 },
128 { .throughput = 70 * 1024, .blink_time = 130 },
129 { .throughput = 100 * 1024, .blink_time = 110 },
130 { .throughput = 200 * 1024, .blink_time = 80 },
131 { .throughput = 300 * 1024, .blink_time = 50 },
132};
133#endif
134
120static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) 135static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
121{ 136{
122 int time_left; 137 int time_left;
@@ -863,6 +878,13 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
863 if (error != 0) 878 if (error != 0)
864 goto err_rx; 879 goto err_rx;
865 880
881#ifdef CONFIG_MAC80211_LEDS
882 /* must be initialized before ieee80211_register_hw */
883 priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
884 IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink,
885 ARRAY_SIZE(ath9k_htc_tpt_blink));
886#endif
887
866 /* Register with mac80211 */ 888 /* Register with mac80211 */
867 error = ieee80211_register_hw(hw); 889 error = ieee80211_register_hw(hw);
868 if (error) 890 if (error)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index e9746e8ff8dd..5aa104fe7eeb 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1003,9 +1003,11 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
1003 /* Cancel all the running timers/work .. */ 1003 /* Cancel all the running timers/work .. */
1004 cancel_work_sync(&priv->fatal_work); 1004 cancel_work_sync(&priv->fatal_work);
1005 cancel_work_sync(&priv->ps_work); 1005 cancel_work_sync(&priv->ps_work);
1006 cancel_delayed_work_sync(&priv->ath9k_led_blink_work); 1006
1007#ifdef CONFIG_MAC80211_LEDS
1008 cancel_work_sync(&priv->led_work);
1009#endif
1007 ath9k_htc_stop_ani(priv); 1010 ath9k_htc_stop_ani(priv);
1008 ath9k_led_stop_brightness(priv);
1009 1011
1010 mutex_lock(&priv->mutex); 1012 mutex_lock(&priv->mutex);
1011 1013