aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-led.c
diff options
context:
space:
mode:
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 685ba9d6f08..478c90511eb 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