iwlwifi: change default led mode for different devices
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / iwl-led.c
CommitLineData
ab53d8af
MA
1/******************************************************************************
2 *
1f447808 3 * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
ab53d8af
MA
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
759ef89f 22 * Intel Linux Wireless <ilw@linux.intel.com>
ab53d8af
MA
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27
28#include <linux/kernel.h>
29#include <linux/module.h>
ab53d8af
MA
30#include <linux/init.h>
31#include <linux/pci.h>
32#include <linux/dma-mapping.h>
33#include <linux/delay.h>
34#include <linux/skbuff.h>
35#include <linux/netdevice.h>
36#include <linux/wireless.h>
37#include <net/mac80211.h>
38#include <linux/etherdevice.h>
39#include <asm/unaligned.h>
40
3e0d4cb1 41#include "iwl-dev.h"
ab53d8af 42#include "iwl-core.h"
fee1247a 43#include "iwl-io.h"
ab53d8af 44
02f5dac0
WYG
45/* default: IWL_LED_BLINK(0) using blinking index table */
46static int led_mode;
47module_param(led_mode, int, S_IRUGO);
564b344c
WYG
48MODULE_PARM_DESC(led_mode, "led mode: 0=system default, "
49 "1=On(RF On)/Off(RF Off), 2=blinking");
0eee6127 50
ab53d8af 51static const struct {
e5108d07 52 u16 tpt; /* Mb/s */
ab53d8af 53 u8 on_time;
0eee6127 54 u8 off_time;
ab53d8af
MA
55} blink_tbl[] =
56{
57 {300, 25, 25},
58 {200, 40, 40},
59 {100, 55, 55},
60 {70, 65, 65},
61 {50, 75, 75},
62 {20, 85, 85},
85fecff1
WYG
63 {10, 95, 95},
64 {5, 110, 110},
65 {1, 130, 130},
ec1a7460 66 {0, 167, 167},
e932a609 67 /* SOLID_ON */
ec1a7460 68 {-1, IWL_LED_SOLID, 0}
ab53d8af
MA
69};
70
ec1a7460
TW
71#define IWL_1MB_RATE (128 * 1024)
72#define IWL_LED_THRESHOLD (16)
73#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */
74#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
75
f2d0d0e2
WYG
76/*
77 * Adjust led blink rate to compensate on a MAC Clock difference on every HW
78 * Led blink rate analysis showed an average deviation of 0% on 3945,
79 * 5% on 4965 HW and 20% on 5000 series and up.
80 * Need to compensate on the led on/off time per HW according to the deviation
81 * to achieve the desired led frequency
82 * The calculation is: (100-averageDeviation)/100 * blinkTime
83 * For code efficiency the calculation will be:
84 * compensation = (100 - averageDeviation) * 64 / 100
85 * NewBlinkTime = (compensation * BlinkTime) / 64
86 */
87static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
88 u8 time, u16 compensation)
89{
90 if (!compensation) {
91 IWL_ERR(priv, "undefined blink compensation: "
92 "use pre-defined blinking time\n");
93 return time;
94 }
95
96 return (u8)((time * compensation) >> 6);
97}
98
ec1a7460 99/* Set led pattern command */
e932a609 100static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx)
ab53d8af 101{
ec1a7460 102 struct iwl_led_cmd led_cmd = {
e932a609 103 .id = IWL_LED_LINK,
ab53d8af
MA
104 .interval = IWL_DEF_LED_INTRVL
105 };
ab53d8af 106
ec1a7460
TW
107 BUG_ON(idx > IWL_MAX_BLINK_TBL);
108
f2d0d0e2 109 IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n",
7cb1b088 110 priv->cfg->base_params->led_compensation);
f2d0d0e2
WYG
111 led_cmd.on =
112 iwl_blink_compensation(priv, blink_tbl[idx].on_time,
7cb1b088 113 priv->cfg->base_params->led_compensation);
f2d0d0e2
WYG
114 led_cmd.off =
115 iwl_blink_compensation(priv, blink_tbl[idx].off_time,
7cb1b088 116 priv->cfg->base_params->led_compensation);
ec1a7460 117
e932a609 118 return priv->cfg->ops->led->cmd(priv, &led_cmd);
ab53d8af 119}
ab53d8af 120
e932a609 121int iwl_led_start(struct iwl_priv *priv)
ab53d8af 122{
e932a609 123 return priv->cfg->ops->led->on(priv);
ab53d8af 124}
e932a609 125EXPORT_SYMBOL(iwl_led_start);
ab53d8af 126
e932a609 127int iwl_led_associate(struct iwl_priv *priv)
c785d1d5 128{
e1623446 129 IWL_DEBUG_LED(priv, "Associated\n");
564b344c 130 if (priv->cfg->led_mode == IWL_LED_BLINK)
02f5dac0 131 priv->allow_blinking = 1;
e932a609 132 priv->last_blink_time = jiffies;
ab53d8af 133
ab53d8af
MA
134 return 0;
135}
2295c66b 136EXPORT_SYMBOL(iwl_led_associate);
ab53d8af 137
e932a609 138int iwl_led_disassociate(struct iwl_priv *priv)
ab53d8af 139{
e932a609 140 priv->allow_blinking = 0;
a571ea4e 141
ab53d8af
MA
142 return 0;
143}
2295c66b 144EXPORT_SYMBOL(iwl_led_disassociate);
ab53d8af 145
ab53d8af 146/*
e5108d07 147 * calculate blink rate according to last second Tx/Rx activities
ab53d8af 148 */
ec1a7460 149static int iwl_get_blink_rate(struct iwl_priv *priv)
ab53d8af
MA
150{
151 int i;
e5108d07
WYG
152 /* count both tx and rx traffic to be able to
153 * handle traffic in either direction
154 */
22fdf3c9
WYG
155 u64 current_tpt = priv->tx_stats.data_bytes +
156 priv->rx_stats.data_bytes;
ab53d8af
MA
157 s64 tpt = current_tpt - priv->led_tpt;
158
a96a27f9 159 if (tpt < 0) /* wraparound */
ab53d8af
MA
160 tpt = -tpt;
161
e1623446 162 IWL_DEBUG_LED(priv, "tpt %lld current_tpt %llu\n",
03121104
AM
163 (long long)tpt,
164 (unsigned long long)current_tpt);
ab53d8af
MA
165 priv->led_tpt = current_tpt;
166
ec1a7460 167 if (!priv->allow_blinking)
ab53d8af 168 i = IWL_MAX_BLINK_TBL;
ec1a7460 169 else
ab53d8af 170 for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
e932a609 171 if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
ab53d8af 172 break;
ab53d8af 173
e1623446 174 IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i);
ec1a7460 175 return i;
ab53d8af
MA
176}
177
ab53d8af
MA
178/*
179 * this function called from handler. Since setting Led command can
180 * happen very frequent we postpone led command to be called from
181 * REPLY handler so we know ucode is up
182 */
183void iwl_leds_background(struct iwl_priv *priv)
184{
ec1a7460 185 u8 blink_idx;
ab53d8af
MA
186
187 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
188 priv->last_blink_time = 0;
189 return;
190 }
c785d1d5 191 if (iwl_is_rfkill(priv)) {
ab53d8af
MA
192 priv->last_blink_time = 0;
193 return;
194 }
195
196 if (!priv->allow_blinking) {
197 priv->last_blink_time = 0;
ec1a7460
TW
198 if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
199 priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
e932a609 200 iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX);
ab53d8af
MA
201 }
202 return;
203 }
204 if (!priv->last_blink_time ||
205 !time_after(jiffies, priv->last_blink_time +
206 msecs_to_jiffies(1000)))
207 return;
208
ec1a7460 209 blink_idx = iwl_get_blink_rate(priv);
ab53d8af
MA
210
211 /* call only if blink rate change */
ec1a7460 212 if (blink_idx != priv->last_blink_rate)
e932a609 213 iwl_led_pattern(priv, blink_idx);
ab53d8af 214
0eee6127 215 priv->last_blink_time = jiffies;
ec1a7460 216 priv->last_blink_rate = blink_idx;
ab53d8af 217}
e932a609 218EXPORT_SYMBOL(iwl_leds_background);
ab53d8af 219
e932a609 220void iwl_leds_init(struct iwl_priv *priv)
ab53d8af 221{
ab53d8af 222 priv->last_blink_rate = 0;
ab53d8af
MA
223 priv->last_blink_time = 0;
224 priv->allow_blinking = 0;
564b344c
WYG
225 if (led_mode != IWL_LED_DEFAULT &&
226 led_mode != priv->cfg->led_mode)
227 priv->cfg->led_mode = led_mode;
ab53d8af 228}
e932a609 229EXPORT_SYMBOL(iwl_leds_init);
This page took 0.42111 seconds and 5 git commands to generate.