aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-led.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-10-02 16:44:03 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-07 16:39:45 -0400
commite932a609e9759cc75db0c234f465a5fd6e20d362 (patch)
treefb4f7d072aa527204f7db4fd11b155e3b12e0b74 /drivers/net/wireless/iwlwifi/iwl-led.c
parentbe1a71a128ed91372d4ad8d54d8fd972a1a356eb (diff)
iwlwifi: LED cleanup
The iwlwifi drivers have LED blinking requirements that mac80211 cannot fulfill due to the use of just a single LED instead of different ones for TX, RX, radio etc. Instead, the single LED blinks according to transfers and is solid on the rest of the time. As such, having LED class devices registered that mac80211 triggers are connected to is pointless as we don't use the triggers anyway. Remove all the useless code and add hooks into the driver itself. At the same time, make the LED code abstracted so the core code that determines blink rate etc. can be shared between 3945 and agn in iwlcore. At the same time, the fact that we removed the use of the mac80211 LED triggers means we can also remove the IWLWIFI_LEDS Kconfig symbol since the LED support is now self-contained. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-led.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c285
1 files changed, 17 insertions, 268 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 685ba9d6f082..478c90511ebf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -48,16 +48,6 @@ module_param(led_mode, int, S_IRUGO);
48MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), " 48MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), "
49 "(default 0)\n"); 49 "(default 0)\n");
50 50
51#ifdef CONFIG_IWLWIFI_DEBUG
52static const char *led_type_str[] = {
53 __stringify(IWL_LED_TRG_TX),
54 __stringify(IWL_LED_TRG_RX),
55 __stringify(IWL_LED_TRG_ASSOC),
56 __stringify(IWL_LED_TRG_RADIO),
57 NULL
58};
59#endif /* CONFIG_IWLWIFI_DEBUG */
60
61 51
62static const struct { 52static const struct {
63 u16 tpt; /* Mb/s */ 53 u16 tpt; /* Mb/s */
@@ -75,7 +65,7 @@ static const struct {
75 {5, 110, 110}, 65 {5, 110, 110},
76 {1, 130, 130}, 66 {1, 130, 130},
77 {0, 167, 167}, 67 {0, 167, 167},
78/* SOLID_ON */ 68 /* SOLID_ON */
79 {-1, IWL_LED_SOLID, 0} 69 {-1, IWL_LED_SOLID, 0}
80}; 70};
81 71
@@ -107,37 +97,11 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
107 return (u8)((time * compensation) >> 6); 97 return (u8)((time * compensation) >> 6);
108} 98}
109 99
110/* [0-256] -> [0..8] FIXME: we need [0..10] */
111static inline int iwl_brightness_to_idx(enum led_brightness brightness)
112{
113 return fls(0x000000FF & (u32)brightness);
114}
115
116/* Send led command */
117static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
118{
119 struct iwl_host_cmd cmd = {
120 .id = REPLY_LEDS_CMD,
121 .len = sizeof(struct iwl_led_cmd),
122 .data = led_cmd,
123 .flags = CMD_ASYNC,
124 .callback = NULL,
125 };
126 u32 reg;
127
128 reg = iwl_read32(priv, CSR_LED_REG);
129 if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
130 iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
131
132 return iwl_send_cmd(priv, &cmd);
133}
134
135/* Set led pattern command */ 100/* Set led pattern command */
136static int iwl_led_pattern(struct iwl_priv *priv, int led_id, 101static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx)
137 unsigned int idx)
138{ 102{
139 struct iwl_led_cmd led_cmd = { 103 struct iwl_led_cmd led_cmd = {
140 .id = led_id, 104 .id = IWL_LED_LINK,
141 .interval = IWL_DEF_LED_INTRVL 105 .interval = IWL_DEF_LED_INTRVL
142 }; 106 };
143 107
@@ -152,153 +116,32 @@ static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
152 iwl_blink_compensation(priv, blink_tbl[idx].off_time, 116 iwl_blink_compensation(priv, blink_tbl[idx].off_time,
153 priv->cfg->led_compensation); 117 priv->cfg->led_compensation);
154 118
155 return iwl_send_led_cmd(priv, &led_cmd); 119 return priv->cfg->ops->led->cmd(priv, &led_cmd);
156}
157
158/* Set led register off */
159static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
160{
161 IWL_DEBUG_LED(priv, "led on %d\n", led_id);
162 iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
163 return 0;
164}
165
166#if 0
167/* Set led on command */
168static int iwl_led_on(struct iwl_priv *priv, int led_id)
169{
170 struct iwl_led_cmd led_cmd = {
171 .id = led_id,
172 .on = IWL_LED_SOLID,
173 .off = 0,
174 .interval = IWL_DEF_LED_INTRVL
175 };
176 return iwl_send_led_cmd(priv, &led_cmd);
177}
178
179/* Set led off command */
180int iwl_led_off(struct iwl_priv *priv, int led_id)
181{
182 struct iwl_led_cmd led_cmd = {
183 .id = led_id,
184 .on = 0,
185 .off = 0,
186 .interval = IWL_DEF_LED_INTRVL
187 };
188 IWL_DEBUG_LED(priv, "led off %d\n", led_id);
189 return iwl_send_led_cmd(priv, &led_cmd);
190} 120}
191#endif
192 121
193 122int iwl_led_start(struct iwl_priv *priv)
194/* Set led register off */
195static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
196{ 123{
197 IWL_DEBUG_LED(priv, "LED Reg off\n"); 124 return priv->cfg->ops->led->on(priv);
198 iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
199 return 0;
200} 125}
126EXPORT_SYMBOL(iwl_led_start);
201 127
202/* 128int iwl_led_associate(struct iwl_priv *priv)
203 * Set led register in case of disassociation according to rfkill state
204 */
205static int iwl_led_associate(struct iwl_priv *priv, int led_id)
206{ 129{
207 IWL_DEBUG_LED(priv, "Associated\n"); 130 IWL_DEBUG_LED(priv, "Associated\n");
208 if (led_mode == IWL_LED_BLINK) 131 if (led_mode == IWL_LED_BLINK)
209 priv->allow_blinking = 1; 132 priv->allow_blinking = 1;
210 return iwl_led_on_reg(priv, led_id); 133 priv->last_blink_time = jiffies;
211}
212static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
213{
214 priv->allow_blinking = 0;
215
216 return 0;
217}
218
219/*
220 * brightness call back function for Tx/Rx LED
221 */
222static int iwl_led_associated(struct iwl_priv *priv, int led_id)
223{
224 if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
225 !test_bit(STATUS_READY, &priv->status))
226 return 0;
227
228 134
229 /* start counting Tx/Rx bytes */
230 if (!priv->last_blink_time && priv->allow_blinking)
231 priv->last_blink_time = jiffies;
232 return 0; 135 return 0;
233} 136}
234 137
235/* 138int iwl_led_disassociate(struct iwl_priv *priv)
236 * brightness call back for association and radio
237 */
238static void iwl_led_brightness_set(struct led_classdev *led_cdev,
239 enum led_brightness brightness)
240{ 139{
241 struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev); 140 priv->allow_blinking = 0;
242 struct iwl_priv *priv = led->priv;
243
244 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
245 return;
246
247
248 IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n",
249 led_type_str[led->type], brightness);
250 switch (brightness) {
251 case LED_FULL:
252 if (led->led_on)
253 led->led_on(priv, IWL_LED_LINK);
254 break;
255 case LED_OFF:
256 if (led->led_off)
257 led->led_off(priv, IWL_LED_LINK);
258 break;
259 default:
260 if (led->led_pattern) {
261 int idx = iwl_brightness_to_idx(brightness);
262 led->led_pattern(priv, IWL_LED_LINK, idx);
263 }
264 break;
265 }
266}
267
268
269
270/*
271 * Register led class with the system
272 */
273static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
274 enum led_type type, u8 set_led,
275 char *trigger)
276{
277 struct device *device = wiphy_dev(priv->hw->wiphy);
278 int ret;
279
280 led->led_dev.name = led->name;
281 led->led_dev.brightness_set = iwl_led_brightness_set;
282 led->led_dev.default_trigger = trigger;
283
284 led->priv = priv;
285 led->type = type;
286
287 ret = led_classdev_register(device, &led->led_dev);
288 if (ret) {
289 IWL_ERR(priv, "Error: failed to register led handler.\n");
290 return ret;
291 }
292
293 led->registered = 1;
294
295 if (set_led && led->led_on)
296 led->led_on(priv, IWL_LED_LINK);
297 141
298 return 0; 142 return 0;
299} 143}
300 144
301
302/* 145/*
303 * calculate blink rate according to last second Tx/Rx activities 146 * calculate blink rate according to last second Tx/Rx activities
304 */ 147 */
@@ -324,7 +167,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
324 i = IWL_MAX_BLINK_TBL; 167 i = IWL_MAX_BLINK_TBL;
325 else 168 else
326 for (i = 0; i < IWL_MAX_BLINK_TBL; i++) 169 for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
327 if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) 170 if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
328 break; 171 break;
329 172
330 IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i); 173 IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i);
@@ -353,8 +196,7 @@ void iwl_leds_background(struct iwl_priv *priv)
353 priv->last_blink_time = 0; 196 priv->last_blink_time = 0;
354 if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { 197 if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
355 priv->last_blink_rate = IWL_SOLID_BLINK_IDX; 198 priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
356 iwl_led_pattern(priv, IWL_LED_LINK, 199 iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX);
357 IWL_SOLID_BLINK_IDX);
358 } 200 }
359 return; 201 return;
360 } 202 }
@@ -367,111 +209,18 @@ void iwl_leds_background(struct iwl_priv *priv)
367 209
368 /* call only if blink rate change */ 210 /* call only if blink rate change */
369 if (blink_idx != priv->last_blink_rate) 211 if (blink_idx != priv->last_blink_rate)
370 iwl_led_pattern(priv, IWL_LED_LINK, blink_idx); 212 iwl_led_pattern(priv, blink_idx);
371 213
372 priv->last_blink_time = jiffies; 214 priv->last_blink_time = jiffies;
373 priv->last_blink_rate = blink_idx; 215 priv->last_blink_rate = blink_idx;
374} 216}
217EXPORT_SYMBOL(iwl_leds_background);
375 218
376/* Register all led handler */ 219void iwl_leds_init(struct iwl_priv *priv)
377int iwl_leds_register(struct iwl_priv *priv)
378{ 220{
379 char *trigger;
380 int ret;
381
382 priv->last_blink_rate = 0; 221 priv->last_blink_rate = 0;
383 priv->led_tpt = 0; 222 priv->led_tpt = 0;
384 priv->last_blink_time = 0; 223 priv->last_blink_time = 0;
385 priv->allow_blinking = 0; 224 priv->allow_blinking = 0;
386
387 trigger = ieee80211_get_radio_led_name(priv->hw);
388 snprintf(priv->led[IWL_LED_TRG_RADIO].name,
389 sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
390 wiphy_name(priv->hw->wiphy));
391
392 priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
393 priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
394 priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
395
396 ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
397 IWL_LED_TRG_RADIO, 1, trigger);
398 if (ret)
399 goto exit_fail;
400
401 trigger = ieee80211_get_assoc_led_name(priv->hw);
402 snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
403 sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
404 wiphy_name(priv->hw->wiphy));
405
406 ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
407 IWL_LED_TRG_ASSOC, 0, trigger);
408
409 /* for assoc always turn led on */
410 priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate;
411 priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate;
412 priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
413
414 if (ret)
415 goto exit_fail;
416
417 trigger = ieee80211_get_rx_led_name(priv->hw);
418 snprintf(priv->led[IWL_LED_TRG_RX].name,
419 sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
420 wiphy_name(priv->hw->wiphy));
421
422 ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
423 IWL_LED_TRG_RX, 0, trigger);
424
425 priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
426 priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
427 priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
428
429 if (ret)
430 goto exit_fail;
431
432 trigger = ieee80211_get_tx_led_name(priv->hw);
433 snprintf(priv->led[IWL_LED_TRG_TX].name,
434 sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
435 wiphy_name(priv->hw->wiphy));
436
437 ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
438 IWL_LED_TRG_TX, 0, trigger);
439
440 priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
441 priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
442 priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
443
444 if (ret)
445 goto exit_fail;
446
447 return 0;
448
449exit_fail:
450 iwl_leds_unregister(priv);
451 return ret;
452} 225}
453EXPORT_SYMBOL(iwl_leds_register); 226EXPORT_SYMBOL(iwl_leds_init);
454
455/* unregister led class */
456static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led)
457{
458 if (!led->registered)
459 return;
460
461 led_classdev_unregister(&led->led_dev);
462
463 if (set_led)
464 led->led_dev.brightness_set(&led->led_dev, LED_OFF);
465 led->registered = 0;
466}
467
468/* Unregister all led handlers */
469void iwl_leds_unregister(struct iwl_priv *priv)
470{
471 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
472 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
473 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
474 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
475}
476EXPORT_SYMBOL(iwl_leds_unregister);
477