1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/delay.h>
27#include <linux/skbuff.h>
28#include <linux/netdevice.h>
29#include <net/mac80211.h>
30#include <linux/etherdevice.h>
31#include <asm/unaligned.h>
32#include "iwl-io.h"
33#include "iwl-trans.h"
34#include "iwl-modparams.h"
35#include "dev.h"
36#include "agn.h"
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51static const struct ieee80211_tpt_blink iwl_blink[] = {
52 { .throughput = 0, .blink_time = 334 },
53 { .throughput = 1 * 1024 - 1, .blink_time = 260 },
54 { .throughput = 5 * 1024 - 1, .blink_time = 220 },
55 { .throughput = 10 * 1024 - 1, .blink_time = 190 },
56 { .throughput = 20 * 1024 - 1, .blink_time = 170 },
57 { .throughput = 50 * 1024 - 1, .blink_time = 150 },
58 { .throughput = 70 * 1024 - 1, .blink_time = 130 },
59 { .throughput = 100 * 1024 - 1, .blink_time = 110 },
60 { .throughput = 200 * 1024 - 1, .blink_time = 80 },
61 { .throughput = 300 * 1024 - 1, .blink_time = 50 },
62};
63
64
65void iwlagn_led_enable(struct iwl_priv *priv)
66{
67 iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON);
68}
69
70
71
72
73
74
75
76
77
78
79
80
81static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
82 u8 time, u16 compensation)
83{
84 if (!compensation) {
85 IWL_ERR(priv, "undefined blink compensation: "
86 "use pre-defined blinking time\n");
87 return time;
88 }
89
90 return (u8)((time * compensation) >> 6);
91}
92
93static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
94{
95 struct iwl_host_cmd cmd = {
96 .id = REPLY_LEDS_CMD,
97 .len = { sizeof(struct iwl_led_cmd), },
98 .data = { led_cmd, },
99 .flags = CMD_ASYNC,
100 };
101 u32 reg;
102
103 reg = iwl_read32(priv->trans, CSR_LED_REG);
104 if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
105 iwl_write32(priv->trans, CSR_LED_REG,
106 reg & CSR_LED_BSM_CTRL_MSK);
107
108 return iwl_dvm_send_cmd(priv, &cmd);
109}
110
111
112static int iwl_led_cmd(struct iwl_priv *priv,
113 unsigned long on,
114 unsigned long off)
115{
116 struct iwl_led_cmd led_cmd = {
117 .id = IWL_LED_LINK,
118 .interval = IWL_DEF_LED_INTRVL
119 };
120 int ret;
121
122 if (!test_bit(STATUS_READY, &priv->status))
123 return -EBUSY;
124
125 if (priv->blink_on == on && priv->blink_off == off)
126 return 0;
127
128 if (off == 0) {
129
130 on = IWL_LED_SOLID;
131 }
132
133 led_cmd.on = iwl_blink_compensation(priv, on,
134 priv->cfg->base_params->led_compensation);
135 led_cmd.off = iwl_blink_compensation(priv, off,
136 priv->cfg->base_params->led_compensation);
137
138 ret = iwl_send_led_cmd(priv, &led_cmd);
139 if (!ret) {
140 priv->blink_on = on;
141 priv->blink_off = off;
142 }
143 return ret;
144}
145
146static void iwl_led_brightness_set(struct led_classdev *led_cdev,
147 enum led_brightness brightness)
148{
149 struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
150 unsigned long on = 0;
151 unsigned long off = 0;
152
153 if (brightness > 0)
154 on = IWL_LED_SOLID;
155 else
156 off = IWL_LED_SOLID;
157
158 iwl_led_cmd(priv, on, off);
159}
160
161static int iwl_led_blink_set(struct led_classdev *led_cdev,
162 unsigned long *delay_on,
163 unsigned long *delay_off)
164{
165 struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
166
167 return iwl_led_cmd(priv, *delay_on, *delay_off);
168}
169
170void iwl_leds_init(struct iwl_priv *priv)
171{
172 int mode = iwlwifi_mod_params.led_mode;
173 int ret;
174
175 if (mode == IWL_LED_DISABLE) {
176 IWL_INFO(priv, "Led disabled\n");
177 return;
178 }
179 if (mode == IWL_LED_DEFAULT)
180 mode = priv->cfg->led_mode;
181
182 priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
183 wiphy_name(priv->hw->wiphy));
184 priv->led.brightness_set = iwl_led_brightness_set;
185 priv->led.blink_set = iwl_led_blink_set;
186 priv->led.max_brightness = 1;
187
188 switch (mode) {
189 case IWL_LED_DEFAULT:
190 WARN_ON(1);
191 break;
192 case IWL_LED_BLINK:
193 priv->led.default_trigger =
194 ieee80211_create_tpt_led_trigger(priv->hw,
195 IEEE80211_TPT_LEDTRIG_FL_CONNECTED,
196 iwl_blink, ARRAY_SIZE(iwl_blink));
197 break;
198 case IWL_LED_RF_STATE:
199 priv->led.default_trigger =
200 ieee80211_get_radio_led_name(priv->hw);
201 break;
202 }
203
204 ret = led_classdev_register(priv->trans->dev, &priv->led);
205 if (ret) {
206 kfree(priv->led.name);
207 return;
208 }
209
210 priv->led_registered = true;
211}
212
213void iwl_leds_exit(struct iwl_priv *priv)
214{
215 if (!priv->led_registered)
216 return;
217
218 led_classdev_unregister(&priv->led);
219 kfree(priv->led.name);
220}
221