diff options
Diffstat (limited to 'drivers/net/wireless/ti/wl12xx/main.c')
-rw-r--r-- | drivers/net/wireless/ti/wl12xx/main.c | 1388 |
1 files changed, 1388 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c new file mode 100644 index 000000000000..d7dd3def07b5 --- /dev/null +++ b/drivers/net/wireless/ti/wl12xx/main.c | |||
@@ -0,0 +1,1388 @@ | |||
1 | /* | ||
2 | * This file is part of wl1271 | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Nokia Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <linux/err.h> | ||
26 | |||
27 | #include <linux/wl12xx.h> | ||
28 | |||
29 | #include "../wlcore/wlcore.h" | ||
30 | #include "../wlcore/debug.h" | ||
31 | #include "../wlcore/io.h" | ||
32 | #include "../wlcore/acx.h" | ||
33 | #include "../wlcore/tx.h" | ||
34 | #include "../wlcore/rx.h" | ||
35 | #include "../wlcore/io.h" | ||
36 | #include "../wlcore/boot.h" | ||
37 | |||
38 | #include "wl12xx.h" | ||
39 | #include "reg.h" | ||
40 | #include "cmd.h" | ||
41 | #include "acx.h" | ||
42 | |||
43 | static struct wlcore_conf wl12xx_conf = { | ||
44 | .sg = { | ||
45 | .params = { | ||
46 | [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, | ||
47 | [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, | ||
48 | [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, | ||
49 | [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, | ||
50 | [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, | ||
51 | [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, | ||
52 | [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, | ||
53 | [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, | ||
54 | [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, | ||
55 | [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, | ||
56 | [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, | ||
57 | [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, | ||
58 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, | ||
59 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, | ||
60 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, | ||
61 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, | ||
62 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, | ||
63 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, | ||
64 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, | ||
65 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, | ||
66 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, | ||
67 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, | ||
68 | [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, | ||
69 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, | ||
70 | [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, | ||
71 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, | ||
72 | /* active scan params */ | ||
73 | [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, | ||
74 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, | ||
75 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, | ||
76 | /* passive scan params */ | ||
77 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, | ||
78 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, | ||
79 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, | ||
80 | /* passive scan in dual antenna params */ | ||
81 | [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, | ||
82 | [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, | ||
83 | [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, | ||
84 | /* general params */ | ||
85 | [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, | ||
86 | [CONF_SG_ANTENNA_CONFIGURATION] = 0, | ||
87 | [CONF_SG_BEACON_MISS_PERCENT] = 60, | ||
88 | [CONF_SG_DHCP_TIME] = 5000, | ||
89 | [CONF_SG_RXT] = 1200, | ||
90 | [CONF_SG_TXT] = 1000, | ||
91 | [CONF_SG_ADAPTIVE_RXT_TXT] = 1, | ||
92 | [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, | ||
93 | [CONF_SG_HV3_MAX_SERVED] = 6, | ||
94 | [CONF_SG_PS_POLL_TIMEOUT] = 10, | ||
95 | [CONF_SG_UPSD_TIMEOUT] = 10, | ||
96 | [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, | ||
97 | [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, | ||
98 | [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, | ||
99 | /* AP params */ | ||
100 | [CONF_AP_BEACON_MISS_TX] = 3, | ||
101 | [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, | ||
102 | [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, | ||
103 | [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, | ||
104 | [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, | ||
105 | [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, | ||
106 | /* CTS Diluting params */ | ||
107 | [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, | ||
108 | [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, | ||
109 | }, | ||
110 | .state = CONF_SG_PROTECTIVE, | ||
111 | }, | ||
112 | .rx = { | ||
113 | .rx_msdu_life_time = 512000, | ||
114 | .packet_detection_threshold = 0, | ||
115 | .ps_poll_timeout = 15, | ||
116 | .upsd_timeout = 15, | ||
117 | .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, | ||
118 | .rx_cca_threshold = 0, | ||
119 | .irq_blk_threshold = 0xFFFF, | ||
120 | .irq_pkt_threshold = 0, | ||
121 | .irq_timeout = 600, | ||
122 | .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, | ||
123 | }, | ||
124 | .tx = { | ||
125 | .tx_energy_detection = 0, | ||
126 | .sta_rc_conf = { | ||
127 | .enabled_rates = 0, | ||
128 | .short_retry_limit = 10, | ||
129 | .long_retry_limit = 10, | ||
130 | .aflags = 0, | ||
131 | }, | ||
132 | .ac_conf_count = 4, | ||
133 | .ac_conf = { | ||
134 | [CONF_TX_AC_BE] = { | ||
135 | .ac = CONF_TX_AC_BE, | ||
136 | .cw_min = 15, | ||
137 | .cw_max = 63, | ||
138 | .aifsn = 3, | ||
139 | .tx_op_limit = 0, | ||
140 | }, | ||
141 | [CONF_TX_AC_BK] = { | ||
142 | .ac = CONF_TX_AC_BK, | ||
143 | .cw_min = 15, | ||
144 | .cw_max = 63, | ||
145 | .aifsn = 7, | ||
146 | .tx_op_limit = 0, | ||
147 | }, | ||
148 | [CONF_TX_AC_VI] = { | ||
149 | .ac = CONF_TX_AC_VI, | ||
150 | .cw_min = 15, | ||
151 | .cw_max = 63, | ||
152 | .aifsn = CONF_TX_AIFS_PIFS, | ||
153 | .tx_op_limit = 3008, | ||
154 | }, | ||
155 | [CONF_TX_AC_VO] = { | ||
156 | .ac = CONF_TX_AC_VO, | ||
157 | .cw_min = 15, | ||
158 | .cw_max = 63, | ||
159 | .aifsn = CONF_TX_AIFS_PIFS, | ||
160 | .tx_op_limit = 1504, | ||
161 | }, | ||
162 | }, | ||
163 | .max_tx_retries = 100, | ||
164 | .ap_aging_period = 300, | ||
165 | .tid_conf_count = 4, | ||
166 | .tid_conf = { | ||
167 | [CONF_TX_AC_BE] = { | ||
168 | .queue_id = CONF_TX_AC_BE, | ||
169 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
170 | .tsid = CONF_TX_AC_BE, | ||
171 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
172 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
173 | .apsd_conf = {0, 0}, | ||
174 | }, | ||
175 | [CONF_TX_AC_BK] = { | ||
176 | .queue_id = CONF_TX_AC_BK, | ||
177 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
178 | .tsid = CONF_TX_AC_BK, | ||
179 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
180 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
181 | .apsd_conf = {0, 0}, | ||
182 | }, | ||
183 | [CONF_TX_AC_VI] = { | ||
184 | .queue_id = CONF_TX_AC_VI, | ||
185 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
186 | .tsid = CONF_TX_AC_VI, | ||
187 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
188 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
189 | .apsd_conf = {0, 0}, | ||
190 | }, | ||
191 | [CONF_TX_AC_VO] = { | ||
192 | .queue_id = CONF_TX_AC_VO, | ||
193 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
194 | .tsid = CONF_TX_AC_VO, | ||
195 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
196 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
197 | .apsd_conf = {0, 0}, | ||
198 | }, | ||
199 | }, | ||
200 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, | ||
201 | .tx_compl_timeout = 700, | ||
202 | .tx_compl_threshold = 4, | ||
203 | .basic_rate = CONF_HW_BIT_RATE_1MBPS, | ||
204 | .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, | ||
205 | .tmpl_short_retry_limit = 10, | ||
206 | .tmpl_long_retry_limit = 10, | ||
207 | .tx_watchdog_timeout = 5000, | ||
208 | }, | ||
209 | .conn = { | ||
210 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, | ||
211 | .listen_interval = 1, | ||
212 | .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, | ||
213 | .suspend_listen_interval = 3, | ||
214 | .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, | ||
215 | .bcn_filt_ie_count = 2, | ||
216 | .bcn_filt_ie = { | ||
217 | [0] = { | ||
218 | .ie = WLAN_EID_CHANNEL_SWITCH, | ||
219 | .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, | ||
220 | }, | ||
221 | [1] = { | ||
222 | .ie = WLAN_EID_HT_OPERATION, | ||
223 | .rule = CONF_BCN_RULE_PASS_ON_CHANGE, | ||
224 | }, | ||
225 | }, | ||
226 | .synch_fail_thold = 10, | ||
227 | .bss_lose_timeout = 100, | ||
228 | .beacon_rx_timeout = 10000, | ||
229 | .broadcast_timeout = 20000, | ||
230 | .rx_broadcast_in_ps = 1, | ||
231 | .ps_poll_threshold = 10, | ||
232 | .bet_enable = CONF_BET_MODE_ENABLE, | ||
233 | .bet_max_consecutive = 50, | ||
234 | .psm_entry_retries = 8, | ||
235 | .psm_exit_retries = 16, | ||
236 | .psm_entry_nullfunc_retries = 3, | ||
237 | .dynamic_ps_timeout = 40, | ||
238 | .forced_ps = false, | ||
239 | .keep_alive_interval = 55000, | ||
240 | .max_listen_interval = 20, | ||
241 | }, | ||
242 | .itrim = { | ||
243 | .enable = false, | ||
244 | .timeout = 50000, | ||
245 | }, | ||
246 | .pm_config = { | ||
247 | .host_clk_settling_time = 5000, | ||
248 | .host_fast_wakeup_support = false | ||
249 | }, | ||
250 | .roam_trigger = { | ||
251 | .trigger_pacing = 1, | ||
252 | .avg_weight_rssi_beacon = 20, | ||
253 | .avg_weight_rssi_data = 10, | ||
254 | .avg_weight_snr_beacon = 20, | ||
255 | .avg_weight_snr_data = 10, | ||
256 | }, | ||
257 | .scan = { | ||
258 | .min_dwell_time_active = 7500, | ||
259 | .max_dwell_time_active = 30000, | ||
260 | .min_dwell_time_passive = 100000, | ||
261 | .max_dwell_time_passive = 100000, | ||
262 | .num_probe_reqs = 2, | ||
263 | .split_scan_timeout = 50000, | ||
264 | }, | ||
265 | .sched_scan = { | ||
266 | /* | ||
267 | * Values are in TU/1000 but since sched scan FW command | ||
268 | * params are in TUs rounding up may occur. | ||
269 | */ | ||
270 | .base_dwell_time = 7500, | ||
271 | .max_dwell_time_delta = 22500, | ||
272 | /* based on 250bits per probe @1Mbps */ | ||
273 | .dwell_time_delta_per_probe = 2000, | ||
274 | /* based on 250bits per probe @6Mbps (plus a bit more) */ | ||
275 | .dwell_time_delta_per_probe_5 = 350, | ||
276 | .dwell_time_passive = 100000, | ||
277 | .dwell_time_dfs = 150000, | ||
278 | .num_probe_reqs = 2, | ||
279 | .rssi_threshold = -90, | ||
280 | .snr_threshold = 0, | ||
281 | }, | ||
282 | .ht = { | ||
283 | .rx_ba_win_size = 8, | ||
284 | .tx_ba_win_size = 64, | ||
285 | .inactivity_timeout = 10000, | ||
286 | .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, | ||
287 | }, | ||
288 | /* | ||
289 | * Memory config for wl127x chips is given in the | ||
290 | * wl12xx_default_priv_conf struct. The below configuration is | ||
291 | * for wl128x chips. | ||
292 | */ | ||
293 | .mem = { | ||
294 | .num_stations = 1, | ||
295 | .ssid_profiles = 1, | ||
296 | .rx_block_num = 40, | ||
297 | .tx_min_block_num = 40, | ||
298 | .dynamic_memory = 1, | ||
299 | .min_req_tx_blocks = 45, | ||
300 | .min_req_rx_blocks = 22, | ||
301 | .tx_min = 27, | ||
302 | }, | ||
303 | .fm_coex = { | ||
304 | .enable = true, | ||
305 | .swallow_period = 5, | ||
306 | .n_divider_fref_set_1 = 0xff, /* default */ | ||
307 | .n_divider_fref_set_2 = 12, | ||
308 | .m_divider_fref_set_1 = 148, | ||
309 | .m_divider_fref_set_2 = 0xffff, /* default */ | ||
310 | .coex_pll_stabilization_time = 0xffffffff, /* default */ | ||
311 | .ldo_stabilization_time = 0xffff, /* default */ | ||
312 | .fm_disturbed_band_margin = 0xff, /* default */ | ||
313 | .swallow_clk_diff = 0xff, /* default */ | ||
314 | }, | ||
315 | .rx_streaming = { | ||
316 | .duration = 150, | ||
317 | .queues = 0x1, | ||
318 | .interval = 20, | ||
319 | .always = 0, | ||
320 | }, | ||
321 | .fwlog = { | ||
322 | .mode = WL12XX_FWLOG_ON_DEMAND, | ||
323 | .mem_blocks = 2, | ||
324 | .severity = 0, | ||
325 | .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, | ||
326 | .output = WL12XX_FWLOG_OUTPUT_HOST, | ||
327 | .threshold = 0, | ||
328 | }, | ||
329 | .rate = { | ||
330 | .rate_retry_score = 32000, | ||
331 | .per_add = 8192, | ||
332 | .per_th1 = 2048, | ||
333 | .per_th2 = 4096, | ||
334 | .max_per = 8100, | ||
335 | .inverse_curiosity_factor = 5, | ||
336 | .tx_fail_low_th = 4, | ||
337 | .tx_fail_high_th = 10, | ||
338 | .per_alpha_shift = 4, | ||
339 | .per_add_shift = 13, | ||
340 | .per_beta1_shift = 10, | ||
341 | .per_beta2_shift = 8, | ||
342 | .rate_check_up = 2, | ||
343 | .rate_check_down = 12, | ||
344 | .rate_retry_policy = { | ||
345 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
346 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
347 | 0x00, 0x00, 0x00, | ||
348 | }, | ||
349 | }, | ||
350 | .hangover = { | ||
351 | .recover_time = 0, | ||
352 | .hangover_period = 20, | ||
353 | .dynamic_mode = 1, | ||
354 | .early_termination_mode = 1, | ||
355 | .max_period = 20, | ||
356 | .min_period = 1, | ||
357 | .increase_delta = 1, | ||
358 | .decrease_delta = 2, | ||
359 | .quiet_time = 4, | ||
360 | .increase_time = 1, | ||
361 | .window_size = 16, | ||
362 | }, | ||
363 | }; | ||
364 | |||
365 | static struct wl12xx_priv_conf wl12xx_default_priv_conf = { | ||
366 | .rf = { | ||
367 | .tx_per_channel_power_compensation_2 = { | ||
368 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
369 | }, | ||
370 | .tx_per_channel_power_compensation_5 = { | ||
371 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
372 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
373 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
374 | }, | ||
375 | }, | ||
376 | .mem_wl127x = { | ||
377 | .num_stations = 1, | ||
378 | .ssid_profiles = 1, | ||
379 | .rx_block_num = 70, | ||
380 | .tx_min_block_num = 40, | ||
381 | .dynamic_memory = 1, | ||
382 | .min_req_tx_blocks = 100, | ||
383 | .min_req_rx_blocks = 22, | ||
384 | .tx_min = 27, | ||
385 | }, | ||
386 | |||
387 | }; | ||
388 | |||
389 | #define WL12XX_TX_HW_BLOCK_SPARE_DEFAULT 1 | ||
390 | #define WL12XX_TX_HW_BLOCK_GEM_SPARE 2 | ||
391 | #define WL12XX_TX_HW_BLOCK_SIZE 252 | ||
392 | |||
393 | static const u8 wl12xx_rate_to_idx_2ghz[] = { | ||
394 | /* MCS rates are used only with 11n */ | ||
395 | 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */ | ||
396 | 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */ | ||
397 | 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */ | ||
398 | 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */ | ||
399 | 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */ | ||
400 | 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */ | ||
401 | 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */ | ||
402 | 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */ | ||
403 | 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */ | ||
404 | |||
405 | 11, /* WL12XX_CONF_HW_RXTX_RATE_54 */ | ||
406 | 10, /* WL12XX_CONF_HW_RXTX_RATE_48 */ | ||
407 | 9, /* WL12XX_CONF_HW_RXTX_RATE_36 */ | ||
408 | 8, /* WL12XX_CONF_HW_RXTX_RATE_24 */ | ||
409 | |||
410 | /* TI-specific rate */ | ||
411 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */ | ||
412 | |||
413 | 7, /* WL12XX_CONF_HW_RXTX_RATE_18 */ | ||
414 | 6, /* WL12XX_CONF_HW_RXTX_RATE_12 */ | ||
415 | 3, /* WL12XX_CONF_HW_RXTX_RATE_11 */ | ||
416 | 5, /* WL12XX_CONF_HW_RXTX_RATE_9 */ | ||
417 | 4, /* WL12XX_CONF_HW_RXTX_RATE_6 */ | ||
418 | 2, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */ | ||
419 | 1, /* WL12XX_CONF_HW_RXTX_RATE_2 */ | ||
420 | 0 /* WL12XX_CONF_HW_RXTX_RATE_1 */ | ||
421 | }; | ||
422 | |||
423 | static const u8 wl12xx_rate_to_idx_5ghz[] = { | ||
424 | /* MCS rates are used only with 11n */ | ||
425 | 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */ | ||
426 | 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */ | ||
427 | 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */ | ||
428 | 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */ | ||
429 | 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */ | ||
430 | 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */ | ||
431 | 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */ | ||
432 | 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */ | ||
433 | 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */ | ||
434 | |||
435 | 7, /* WL12XX_CONF_HW_RXTX_RATE_54 */ | ||
436 | 6, /* WL12XX_CONF_HW_RXTX_RATE_48 */ | ||
437 | 5, /* WL12XX_CONF_HW_RXTX_RATE_36 */ | ||
438 | 4, /* WL12XX_CONF_HW_RXTX_RATE_24 */ | ||
439 | |||
440 | /* TI-specific rate */ | ||
441 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */ | ||
442 | |||
443 | 3, /* WL12XX_CONF_HW_RXTX_RATE_18 */ | ||
444 | 2, /* WL12XX_CONF_HW_RXTX_RATE_12 */ | ||
445 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_11 */ | ||
446 | 1, /* WL12XX_CONF_HW_RXTX_RATE_9 */ | ||
447 | 0, /* WL12XX_CONF_HW_RXTX_RATE_6 */ | ||
448 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */ | ||
449 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_2 */ | ||
450 | CONF_HW_RXTX_RATE_UNSUPPORTED /* WL12XX_CONF_HW_RXTX_RATE_1 */ | ||
451 | }; | ||
452 | |||
453 | static const u8 *wl12xx_band_rate_to_idx[] = { | ||
454 | [IEEE80211_BAND_2GHZ] = wl12xx_rate_to_idx_2ghz, | ||
455 | [IEEE80211_BAND_5GHZ] = wl12xx_rate_to_idx_5ghz | ||
456 | }; | ||
457 | |||
458 | enum wl12xx_hw_rates { | ||
459 | WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI = 0, | ||
460 | WL12XX_CONF_HW_RXTX_RATE_MCS7, | ||
461 | WL12XX_CONF_HW_RXTX_RATE_MCS6, | ||
462 | WL12XX_CONF_HW_RXTX_RATE_MCS5, | ||
463 | WL12XX_CONF_HW_RXTX_RATE_MCS4, | ||
464 | WL12XX_CONF_HW_RXTX_RATE_MCS3, | ||
465 | WL12XX_CONF_HW_RXTX_RATE_MCS2, | ||
466 | WL12XX_CONF_HW_RXTX_RATE_MCS1, | ||
467 | WL12XX_CONF_HW_RXTX_RATE_MCS0, | ||
468 | WL12XX_CONF_HW_RXTX_RATE_54, | ||
469 | WL12XX_CONF_HW_RXTX_RATE_48, | ||
470 | WL12XX_CONF_HW_RXTX_RATE_36, | ||
471 | WL12XX_CONF_HW_RXTX_RATE_24, | ||
472 | WL12XX_CONF_HW_RXTX_RATE_22, | ||
473 | WL12XX_CONF_HW_RXTX_RATE_18, | ||
474 | WL12XX_CONF_HW_RXTX_RATE_12, | ||
475 | WL12XX_CONF_HW_RXTX_RATE_11, | ||
476 | WL12XX_CONF_HW_RXTX_RATE_9, | ||
477 | WL12XX_CONF_HW_RXTX_RATE_6, | ||
478 | WL12XX_CONF_HW_RXTX_RATE_5_5, | ||
479 | WL12XX_CONF_HW_RXTX_RATE_2, | ||
480 | WL12XX_CONF_HW_RXTX_RATE_1, | ||
481 | WL12XX_CONF_HW_RXTX_RATE_MAX, | ||
482 | }; | ||
483 | |||
484 | static struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = { | ||
485 | [PART_DOWN] = { | ||
486 | .mem = { | ||
487 | .start = 0x00000000, | ||
488 | .size = 0x000177c0 | ||
489 | }, | ||
490 | .reg = { | ||
491 | .start = REGISTERS_BASE, | ||
492 | .size = 0x00008800 | ||
493 | }, | ||
494 | .mem2 = { | ||
495 | .start = 0x00000000, | ||
496 | .size = 0x00000000 | ||
497 | }, | ||
498 | .mem3 = { | ||
499 | .start = 0x00000000, | ||
500 | .size = 0x00000000 | ||
501 | }, | ||
502 | }, | ||
503 | |||
504 | [PART_BOOT] = { /* in wl12xx we can use a mix of work and down | ||
505 | * partition here */ | ||
506 | .mem = { | ||
507 | .start = 0x00040000, | ||
508 | .size = 0x00014fc0 | ||
509 | }, | ||
510 | .reg = { | ||
511 | .start = REGISTERS_BASE, | ||
512 | .size = 0x00008800 | ||
513 | }, | ||
514 | .mem2 = { | ||
515 | .start = 0x00000000, | ||
516 | .size = 0x00000000 | ||
517 | }, | ||
518 | .mem3 = { | ||
519 | .start = 0x00000000, | ||
520 | .size = 0x00000000 | ||
521 | }, | ||
522 | }, | ||
523 | |||
524 | [PART_WORK] = { | ||
525 | .mem = { | ||
526 | .start = 0x00040000, | ||
527 | .size = 0x00014fc0 | ||
528 | }, | ||
529 | .reg = { | ||
530 | .start = REGISTERS_BASE, | ||
531 | .size = 0x0000a000 | ||
532 | }, | ||
533 | .mem2 = { | ||
534 | .start = 0x003004f8, | ||
535 | .size = 0x00000004 | ||
536 | }, | ||
537 | .mem3 = { | ||
538 | .start = 0x00040404, | ||
539 | .size = 0x00000000 | ||
540 | }, | ||
541 | }, | ||
542 | |||
543 | [PART_DRPW] = { | ||
544 | .mem = { | ||
545 | .start = 0x00040000, | ||
546 | .size = 0x00014fc0 | ||
547 | }, | ||
548 | .reg = { | ||
549 | .start = DRPW_BASE, | ||
550 | .size = 0x00006000 | ||
551 | }, | ||
552 | .mem2 = { | ||
553 | .start = 0x00000000, | ||
554 | .size = 0x00000000 | ||
555 | }, | ||
556 | .mem3 = { | ||
557 | .start = 0x00000000, | ||
558 | .size = 0x00000000 | ||
559 | } | ||
560 | } | ||
561 | }; | ||
562 | |||
563 | static const int wl12xx_rtable[REG_TABLE_LEN] = { | ||
564 | [REG_ECPU_CONTROL] = WL12XX_REG_ECPU_CONTROL, | ||
565 | [REG_INTERRUPT_NO_CLEAR] = WL12XX_REG_INTERRUPT_NO_CLEAR, | ||
566 | [REG_INTERRUPT_ACK] = WL12XX_REG_INTERRUPT_ACK, | ||
567 | [REG_COMMAND_MAILBOX_PTR] = WL12XX_REG_COMMAND_MAILBOX_PTR, | ||
568 | [REG_EVENT_MAILBOX_PTR] = WL12XX_REG_EVENT_MAILBOX_PTR, | ||
569 | [REG_INTERRUPT_TRIG] = WL12XX_REG_INTERRUPT_TRIG, | ||
570 | [REG_INTERRUPT_MASK] = WL12XX_REG_INTERRUPT_MASK, | ||
571 | [REG_PC_ON_RECOVERY] = WL12XX_SCR_PAD4, | ||
572 | [REG_CHIP_ID_B] = WL12XX_CHIP_ID_B, | ||
573 | [REG_CMD_MBOX_ADDRESS] = WL12XX_CMD_MBOX_ADDRESS, | ||
574 | |||
575 | /* data access memory addresses, used with partition translation */ | ||
576 | [REG_SLV_MEM_DATA] = WL1271_SLV_MEM_DATA, | ||
577 | [REG_SLV_REG_DATA] = WL1271_SLV_REG_DATA, | ||
578 | |||
579 | /* raw data access memory addresses */ | ||
580 | [REG_RAW_FW_STATUS_ADDR] = FW_STATUS_ADDR, | ||
581 | }; | ||
582 | |||
583 | /* TODO: maybe move to a new header file? */ | ||
584 | #define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" | ||
585 | #define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" | ||
586 | #define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" | ||
587 | |||
588 | #define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" | ||
589 | #define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" | ||
590 | #define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" | ||
591 | |||
592 | static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) | ||
593 | { | ||
594 | if (wl->chip.id != CHIP_ID_1283_PG20) { | ||
595 | struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
596 | struct wl1271_rx_mem_pool_addr rx_mem_addr; | ||
597 | |||
598 | /* | ||
599 | * Choose the block we want to read | ||
600 | * For aggregated packets, only the first memory block | ||
601 | * should be retrieved. The FW takes care of the rest. | ||
602 | */ | ||
603 | u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK; | ||
604 | |||
605 | rx_mem_addr.addr = (mem_block << 8) + | ||
606 | le32_to_cpu(wl_mem_map->packet_memory_pool_start); | ||
607 | |||
608 | rx_mem_addr.addr_extra = rx_mem_addr.addr + 4; | ||
609 | |||
610 | wl1271_write(wl, WL1271_SLV_REG_DATA, | ||
611 | &rx_mem_addr, sizeof(rx_mem_addr), false); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | static int wl12xx_identify_chip(struct wl1271 *wl) | ||
616 | { | ||
617 | int ret = 0; | ||
618 | |||
619 | switch (wl->chip.id) { | ||
620 | case CHIP_ID_1271_PG10: | ||
621 | wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", | ||
622 | wl->chip.id); | ||
623 | |||
624 | /* clear the alignment quirk, since we don't support it */ | ||
625 | wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; | ||
626 | |||
627 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS; | ||
628 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; | ||
629 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; | ||
630 | memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, | ||
631 | sizeof(wl->conf.mem)); | ||
632 | |||
633 | /* read data preparation is only needed by wl127x */ | ||
634 | wl->ops->prepare_read = wl127x_prepare_read; | ||
635 | |||
636 | break; | ||
637 | |||
638 | case CHIP_ID_1271_PG20: | ||
639 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", | ||
640 | wl->chip.id); | ||
641 | |||
642 | /* clear the alignment quirk, since we don't support it */ | ||
643 | wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; | ||
644 | |||
645 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS; | ||
646 | wl->plt_fw_name = WL127X_PLT_FW_NAME; | ||
647 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; | ||
648 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; | ||
649 | memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, | ||
650 | sizeof(wl->conf.mem)); | ||
651 | |||
652 | /* read data preparation is only needed by wl127x */ | ||
653 | wl->ops->prepare_read = wl127x_prepare_read; | ||
654 | |||
655 | break; | ||
656 | |||
657 | case CHIP_ID_1283_PG20: | ||
658 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", | ||
659 | wl->chip.id); | ||
660 | wl->plt_fw_name = WL128X_PLT_FW_NAME; | ||
661 | wl->sr_fw_name = WL128X_FW_NAME_SINGLE; | ||
662 | wl->mr_fw_name = WL128X_FW_NAME_MULTI; | ||
663 | break; | ||
664 | case CHIP_ID_1283_PG10: | ||
665 | default: | ||
666 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); | ||
667 | ret = -ENODEV; | ||
668 | goto out; | ||
669 | } | ||
670 | |||
671 | out: | ||
672 | return ret; | ||
673 | } | ||
674 | |||
675 | static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) | ||
676 | { | ||
677 | /* write address >> 1 + 0x30000 to OCP_POR_CTR */ | ||
678 | addr = (addr >> 1) + 0x30000; | ||
679 | wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); | ||
680 | |||
681 | /* write value to OCP_POR_WDATA */ | ||
682 | wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val); | ||
683 | |||
684 | /* write 1 to OCP_CMD */ | ||
685 | wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); | ||
686 | } | ||
687 | |||
688 | static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr) | ||
689 | { | ||
690 | u32 val; | ||
691 | int timeout = OCP_CMD_LOOP; | ||
692 | |||
693 | /* write address >> 1 + 0x30000 to OCP_POR_CTR */ | ||
694 | addr = (addr >> 1) + 0x30000; | ||
695 | wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); | ||
696 | |||
697 | /* write 2 to OCP_CMD */ | ||
698 | wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); | ||
699 | |||
700 | /* poll for data ready */ | ||
701 | do { | ||
702 | val = wl1271_read32(wl, WL12XX_OCP_DATA_READ); | ||
703 | } while (!(val & OCP_READY_MASK) && --timeout); | ||
704 | |||
705 | if (!timeout) { | ||
706 | wl1271_warning("Top register access timed out."); | ||
707 | return 0xffff; | ||
708 | } | ||
709 | |||
710 | /* check data status and return if OK */ | ||
711 | if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) | ||
712 | return val & 0xffff; | ||
713 | else { | ||
714 | wl1271_warning("Top register access returned error."); | ||
715 | return 0xffff; | ||
716 | } | ||
717 | } | ||
718 | |||
719 | static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) | ||
720 | { | ||
721 | u16 spare_reg; | ||
722 | |||
723 | /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ | ||
724 | spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); | ||
725 | if (spare_reg == 0xFFFF) | ||
726 | return -EFAULT; | ||
727 | spare_reg |= (BIT(3) | BIT(5) | BIT(6)); | ||
728 | wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); | ||
729 | |||
730 | /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ | ||
731 | wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, | ||
732 | WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); | ||
733 | |||
734 | /* Delay execution for 15msec, to let the HW settle */ | ||
735 | mdelay(15); | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static bool wl128x_is_tcxo_valid(struct wl1271 *wl) | ||
741 | { | ||
742 | u16 tcxo_detection; | ||
743 | |||
744 | tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG); | ||
745 | if (tcxo_detection & TCXO_DET_FAILED) | ||
746 | return false; | ||
747 | |||
748 | return true; | ||
749 | } | ||
750 | |||
751 | static bool wl128x_is_fref_valid(struct wl1271 *wl) | ||
752 | { | ||
753 | u16 fref_detection; | ||
754 | |||
755 | fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG); | ||
756 | if (fref_detection & FREF_CLK_DETECT_FAIL) | ||
757 | return false; | ||
758 | |||
759 | return true; | ||
760 | } | ||
761 | |||
762 | static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) | ||
763 | { | ||
764 | wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); | ||
765 | wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); | ||
766 | wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) | ||
772 | { | ||
773 | u16 spare_reg; | ||
774 | u16 pll_config; | ||
775 | u8 input_freq; | ||
776 | |||
777 | /* Mask bits [3:1] in the sys_clk_cfg register */ | ||
778 | spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); | ||
779 | if (spare_reg == 0xFFFF) | ||
780 | return -EFAULT; | ||
781 | spare_reg |= BIT(2); | ||
782 | wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); | ||
783 | |||
784 | /* Handle special cases of the TCXO clock */ | ||
785 | if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || | ||
786 | wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) | ||
787 | return wl128x_manually_configure_mcs_pll(wl); | ||
788 | |||
789 | /* Set the input frequency according to the selected clock source */ | ||
790 | input_freq = (clk & 1) + 1; | ||
791 | |||
792 | pll_config = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG); | ||
793 | if (pll_config == 0xFFFF) | ||
794 | return -EFAULT; | ||
795 | pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); | ||
796 | pll_config |= MCS_PLL_ENABLE_HP; | ||
797 | wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | /* | ||
803 | * WL128x has two clocks input - TCXO and FREF. | ||
804 | * TCXO is the main clock of the device, while FREF is used to sync | ||
805 | * between the GPS and the cellular modem. | ||
806 | * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used | ||
807 | * as the WLAN/BT main clock. | ||
808 | */ | ||
809 | static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) | ||
810 | { | ||
811 | u16 sys_clk_cfg; | ||
812 | |||
813 | /* For XTAL-only modes, FREF will be used after switching from TCXO */ | ||
814 | if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || | ||
815 | wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { | ||
816 | if (!wl128x_switch_tcxo_to_fref(wl)) | ||
817 | return -EINVAL; | ||
818 | goto fref_clk; | ||
819 | } | ||
820 | |||
821 | /* Query the HW, to determine which clock source we should use */ | ||
822 | sys_clk_cfg = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG); | ||
823 | if (sys_clk_cfg == 0xFFFF) | ||
824 | return -EINVAL; | ||
825 | if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) | ||
826 | goto fref_clk; | ||
827 | |||
828 | /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ | ||
829 | if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || | ||
830 | wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { | ||
831 | if (!wl128x_switch_tcxo_to_fref(wl)) | ||
832 | return -EINVAL; | ||
833 | goto fref_clk; | ||
834 | } | ||
835 | |||
836 | /* TCXO clock is selected */ | ||
837 | if (!wl128x_is_tcxo_valid(wl)) | ||
838 | return -EINVAL; | ||
839 | *selected_clock = wl->tcxo_clock; | ||
840 | goto config_mcs_pll; | ||
841 | |||
842 | fref_clk: | ||
843 | /* FREF clock is selected */ | ||
844 | if (!wl128x_is_fref_valid(wl)) | ||
845 | return -EINVAL; | ||
846 | *selected_clock = wl->ref_clock; | ||
847 | |||
848 | config_mcs_pll: | ||
849 | return wl128x_configure_mcs_pll(wl, *selected_clock); | ||
850 | } | ||
851 | |||
852 | static int wl127x_boot_clk(struct wl1271 *wl) | ||
853 | { | ||
854 | u32 pause; | ||
855 | u32 clk; | ||
856 | |||
857 | if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) | ||
858 | wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; | ||
859 | |||
860 | if (wl->ref_clock == CONF_REF_CLK_19_2_E || | ||
861 | wl->ref_clock == CONF_REF_CLK_38_4_E || | ||
862 | wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) | ||
863 | /* ref clk: 19.2/38.4/38.4-XTAL */ | ||
864 | clk = 0x3; | ||
865 | else if (wl->ref_clock == CONF_REF_CLK_26_E || | ||
866 | wl->ref_clock == CONF_REF_CLK_52_E) | ||
867 | /* ref clk: 26/52 */ | ||
868 | clk = 0x5; | ||
869 | else | ||
870 | return -EINVAL; | ||
871 | |||
872 | if (wl->ref_clock != CONF_REF_CLK_19_2_E) { | ||
873 | u16 val; | ||
874 | /* Set clock type (open drain) */ | ||
875 | val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE); | ||
876 | val &= FREF_CLK_TYPE_BITS; | ||
877 | wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); | ||
878 | |||
879 | /* Set clock pull mode (no pull) */ | ||
880 | val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL); | ||
881 | val |= NO_PULL; | ||
882 | wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); | ||
883 | } else { | ||
884 | u16 val; | ||
885 | /* Set clock polarity */ | ||
886 | val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY); | ||
887 | val &= FREF_CLK_POLARITY_BITS; | ||
888 | val |= CLK_REQ_OUTN_SEL; | ||
889 | wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); | ||
890 | } | ||
891 | |||
892 | wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk); | ||
893 | |||
894 | pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS); | ||
895 | |||
896 | wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); | ||
897 | |||
898 | pause &= ~(WU_COUNTER_PAUSE_VAL); | ||
899 | pause |= WU_COUNTER_PAUSE_VAL; | ||
900 | wl1271_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); | ||
901 | |||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | static int wl1271_boot_soft_reset(struct wl1271 *wl) | ||
906 | { | ||
907 | unsigned long timeout; | ||
908 | u32 boot_data; | ||
909 | |||
910 | /* perform soft reset */ | ||
911 | wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); | ||
912 | |||
913 | /* SOFT_RESET is self clearing */ | ||
914 | timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); | ||
915 | while (1) { | ||
916 | boot_data = wl1271_read32(wl, WL12XX_SLV_SOFT_RESET); | ||
917 | wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); | ||
918 | if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) | ||
919 | break; | ||
920 | |||
921 | if (time_after(jiffies, timeout)) { | ||
922 | /* 1.2 check pWhalBus->uSelfClearTime if the | ||
923 | * timeout was reached */ | ||
924 | wl1271_error("soft reset timeout"); | ||
925 | return -1; | ||
926 | } | ||
927 | |||
928 | udelay(SOFT_RESET_STALL_TIME); | ||
929 | } | ||
930 | |||
931 | /* disable Rx/Tx */ | ||
932 | wl1271_write32(wl, WL12XX_ENABLE, 0x0); | ||
933 | |||
934 | /* disable auto calibration on start*/ | ||
935 | wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff); | ||
936 | |||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static int wl12xx_pre_boot(struct wl1271 *wl) | ||
941 | { | ||
942 | int ret = 0; | ||
943 | u32 clk; | ||
944 | int selected_clock = -1; | ||
945 | |||
946 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
947 | ret = wl128x_boot_clk(wl, &selected_clock); | ||
948 | if (ret < 0) | ||
949 | goto out; | ||
950 | } else { | ||
951 | ret = wl127x_boot_clk(wl); | ||
952 | if (ret < 0) | ||
953 | goto out; | ||
954 | } | ||
955 | |||
956 | /* Continue the ELP wake up sequence */ | ||
957 | wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); | ||
958 | udelay(500); | ||
959 | |||
960 | wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); | ||
961 | |||
962 | /* Read-modify-write DRPW_SCRATCH_START register (see next state) | ||
963 | to be used by DRPw FW. The RTRIM value will be added by the FW | ||
964 | before taking DRPw out of reset */ | ||
965 | |||
966 | clk = wl1271_read32(wl, WL12XX_DRPW_SCRATCH_START); | ||
967 | |||
968 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | ||
969 | |||
970 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
971 | clk |= ((selected_clock & 0x3) << 1) << 4; | ||
972 | else | ||
973 | clk |= (wl->ref_clock << 1) << 4; | ||
974 | |||
975 | wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); | ||
976 | |||
977 | wlcore_set_partition(wl, &wl->ptable[PART_WORK]); | ||
978 | |||
979 | /* Disable interrupts */ | ||
980 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | ||
981 | |||
982 | ret = wl1271_boot_soft_reset(wl); | ||
983 | if (ret < 0) | ||
984 | goto out; | ||
985 | |||
986 | out: | ||
987 | return ret; | ||
988 | } | ||
989 | |||
990 | static void wl12xx_pre_upload(struct wl1271 *wl) | ||
991 | { | ||
992 | u32 tmp; | ||
993 | |||
994 | /* write firmware's last address (ie. it's length) to | ||
995 | * ACX_EEPROMLESS_IND_REG */ | ||
996 | wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); | ||
997 | |||
998 | wl1271_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); | ||
999 | |||
1000 | tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); | ||
1001 | |||
1002 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); | ||
1003 | |||
1004 | /* 6. read the EEPROM parameters */ | ||
1005 | tmp = wl1271_read32(wl, WL12XX_SCR_PAD2); | ||
1006 | |||
1007 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly | ||
1008 | * to upload_fw) */ | ||
1009 | |||
1010 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
1011 | wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); | ||
1012 | } | ||
1013 | |||
1014 | static void wl12xx_enable_interrupts(struct wl1271 *wl) | ||
1015 | { | ||
1016 | u32 polarity; | ||
1017 | |||
1018 | polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY); | ||
1019 | |||
1020 | /* We use HIGH polarity, so unset the LOW bit */ | ||
1021 | polarity &= ~POLARITY_LOW; | ||
1022 | wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); | ||
1023 | |||
1024 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR); | ||
1025 | |||
1026 | wlcore_enable_interrupts(wl); | ||
1027 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, | ||
1028 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | ||
1029 | |||
1030 | wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); | ||
1031 | } | ||
1032 | |||
1033 | static int wl12xx_boot(struct wl1271 *wl) | ||
1034 | { | ||
1035 | int ret; | ||
1036 | |||
1037 | ret = wl12xx_pre_boot(wl); | ||
1038 | if (ret < 0) | ||
1039 | goto out; | ||
1040 | |||
1041 | ret = wlcore_boot_upload_nvs(wl); | ||
1042 | if (ret < 0) | ||
1043 | goto out; | ||
1044 | |||
1045 | wl12xx_pre_upload(wl); | ||
1046 | |||
1047 | ret = wlcore_boot_upload_firmware(wl); | ||
1048 | if (ret < 0) | ||
1049 | goto out; | ||
1050 | |||
1051 | ret = wlcore_boot_run_firmware(wl); | ||
1052 | if (ret < 0) | ||
1053 | goto out; | ||
1054 | |||
1055 | wl12xx_enable_interrupts(wl); | ||
1056 | |||
1057 | out: | ||
1058 | return ret; | ||
1059 | } | ||
1060 | |||
1061 | static void wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, | ||
1062 | void *buf, size_t len) | ||
1063 | { | ||
1064 | wl1271_write(wl, cmd_box_addr, buf, len, false); | ||
1065 | wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD); | ||
1066 | } | ||
1067 | |||
1068 | static void wl12xx_ack_event(struct wl1271 *wl) | ||
1069 | { | ||
1070 | wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_EVENT_ACK); | ||
1071 | } | ||
1072 | |||
1073 | static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) | ||
1074 | { | ||
1075 | u32 blk_size = WL12XX_TX_HW_BLOCK_SIZE; | ||
1076 | u32 align_len = wlcore_calc_packet_alignment(wl, len); | ||
1077 | |||
1078 | return (align_len + blk_size - 1) / blk_size + spare_blks; | ||
1079 | } | ||
1080 | |||
1081 | static void | ||
1082 | wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | ||
1083 | u32 blks, u32 spare_blks) | ||
1084 | { | ||
1085 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
1086 | desc->wl128x_mem.total_mem_blocks = blks; | ||
1087 | } else { | ||
1088 | desc->wl127x_mem.extra_blocks = spare_blks; | ||
1089 | desc->wl127x_mem.total_mem_blocks = blks; | ||
1090 | } | ||
1091 | } | ||
1092 | |||
1093 | static void | ||
1094 | wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | ||
1095 | struct sk_buff *skb) | ||
1096 | { | ||
1097 | u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len); | ||
1098 | |||
1099 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
1100 | desc->wl128x_mem.extra_bytes = aligned_len - skb->len; | ||
1101 | desc->length = cpu_to_le16(aligned_len >> 2); | ||
1102 | |||
1103 | wl1271_debug(DEBUG_TX, | ||
1104 | "tx_fill_hdr: hlid: %d len: %d life: %d mem: %d extra: %d", | ||
1105 | desc->hlid, | ||
1106 | le16_to_cpu(desc->length), | ||
1107 | le16_to_cpu(desc->life_time), | ||
1108 | desc->wl128x_mem.total_mem_blocks, | ||
1109 | desc->wl128x_mem.extra_bytes); | ||
1110 | } else { | ||
1111 | /* calculate number of padding bytes */ | ||
1112 | int pad = aligned_len - skb->len; | ||
1113 | desc->tx_attr |= | ||
1114 | cpu_to_le16(pad << TX_HW_ATTR_OFST_LAST_WORD_PAD); | ||
1115 | |||
1116 | /* Store the aligned length in terms of words */ | ||
1117 | desc->length = cpu_to_le16(aligned_len >> 2); | ||
1118 | |||
1119 | wl1271_debug(DEBUG_TX, | ||
1120 | "tx_fill_hdr: pad: %d hlid: %d len: %d life: %d mem: %d", | ||
1121 | pad, desc->hlid, | ||
1122 | le16_to_cpu(desc->length), | ||
1123 | le16_to_cpu(desc->life_time), | ||
1124 | desc->wl127x_mem.total_mem_blocks); | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | static enum wl_rx_buf_align | ||
1129 | wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) | ||
1130 | { | ||
1131 | if (rx_desc & RX_BUF_UNALIGNED_PAYLOAD) | ||
1132 | return WLCORE_RX_BUF_UNALIGNED; | ||
1133 | |||
1134 | return WLCORE_RX_BUF_ALIGNED; | ||
1135 | } | ||
1136 | |||
1137 | static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, | ||
1138 | u32 data_len) | ||
1139 | { | ||
1140 | struct wl1271_rx_descriptor *desc = rx_data; | ||
1141 | |||
1142 | /* invalid packet */ | ||
1143 | if (data_len < sizeof(*desc) || | ||
1144 | data_len < sizeof(*desc) + desc->pad_len) | ||
1145 | return 0; | ||
1146 | |||
1147 | return data_len - sizeof(*desc) - desc->pad_len; | ||
1148 | } | ||
1149 | |||
1150 | static void wl12xx_tx_delayed_compl(struct wl1271 *wl) | ||
1151 | { | ||
1152 | if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff)) | ||
1153 | return; | ||
1154 | |||
1155 | wl1271_tx_complete(wl); | ||
1156 | } | ||
1157 | |||
1158 | static int wl12xx_hw_init(struct wl1271 *wl) | ||
1159 | { | ||
1160 | int ret; | ||
1161 | |||
1162 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
1163 | u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; | ||
1164 | |||
1165 | ret = wl128x_cmd_general_parms(wl); | ||
1166 | if (ret < 0) | ||
1167 | goto out; | ||
1168 | ret = wl128x_cmd_radio_parms(wl); | ||
1169 | if (ret < 0) | ||
1170 | goto out; | ||
1171 | |||
1172 | if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) | ||
1173 | /* Enable SDIO padding */ | ||
1174 | host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; | ||
1175 | |||
1176 | /* Must be before wl1271_acx_init_mem_config() */ | ||
1177 | ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); | ||
1178 | if (ret < 0) | ||
1179 | goto out; | ||
1180 | } else { | ||
1181 | ret = wl1271_cmd_general_parms(wl); | ||
1182 | if (ret < 0) | ||
1183 | goto out; | ||
1184 | ret = wl1271_cmd_radio_parms(wl); | ||
1185 | if (ret < 0) | ||
1186 | goto out; | ||
1187 | ret = wl1271_cmd_ext_radio_parms(wl); | ||
1188 | if (ret < 0) | ||
1189 | goto out; | ||
1190 | } | ||
1191 | out: | ||
1192 | return ret; | ||
1193 | } | ||
1194 | |||
1195 | static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl, | ||
1196 | struct wl12xx_vif *wlvif) | ||
1197 | { | ||
1198 | return wlvif->rate_set; | ||
1199 | } | ||
1200 | |||
1201 | static int wl12xx_identify_fw(struct wl1271 *wl) | ||
1202 | { | ||
1203 | unsigned int *fw_ver = wl->chip.fw_ver; | ||
1204 | |||
1205 | /* Only new station firmwares support routing fw logs to the host */ | ||
1206 | if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && | ||
1207 | (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) | ||
1208 | wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; | ||
1209 | |||
1210 | /* This feature is not yet supported for AP mode */ | ||
1211 | if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) | ||
1212 | wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; | ||
1213 | |||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static void wl12xx_conf_init(struct wl1271 *wl) | ||
1218 | { | ||
1219 | struct wl12xx_priv *priv = wl->priv; | ||
1220 | |||
1221 | /* apply driver default configuration */ | ||
1222 | memcpy(&wl->conf, &wl12xx_conf, sizeof(wl12xx_conf)); | ||
1223 | |||
1224 | /* apply default private configuration */ | ||
1225 | memcpy(&priv->conf, &wl12xx_default_priv_conf, sizeof(priv->conf)); | ||
1226 | } | ||
1227 | |||
1228 | static bool wl12xx_mac_in_fuse(struct wl1271 *wl) | ||
1229 | { | ||
1230 | bool supported = false; | ||
1231 | u8 major, minor; | ||
1232 | |||
1233 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
1234 | major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); | ||
1235 | minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); | ||
1236 | |||
1237 | /* in wl128x we have the MAC address if the PG is >= (2, 1) */ | ||
1238 | if (major > 2 || (major == 2 && minor >= 1)) | ||
1239 | supported = true; | ||
1240 | } else { | ||
1241 | major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver); | ||
1242 | minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver); | ||
1243 | |||
1244 | /* in wl127x we have the MAC address if the PG is >= (3, 1) */ | ||
1245 | if (major == 3 && minor >= 1) | ||
1246 | supported = true; | ||
1247 | } | ||
1248 | |||
1249 | wl1271_debug(DEBUG_PROBE, | ||
1250 | "PG Ver major = %d minor = %d, MAC %s present", | ||
1251 | major, minor, supported ? "is" : "is not"); | ||
1252 | |||
1253 | return supported; | ||
1254 | } | ||
1255 | |||
1256 | static void wl12xx_get_fuse_mac(struct wl1271 *wl) | ||
1257 | { | ||
1258 | u32 mac1, mac2; | ||
1259 | |||
1260 | wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); | ||
1261 | |||
1262 | mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); | ||
1263 | mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); | ||
1264 | |||
1265 | /* these are the two parts of the BD_ADDR */ | ||
1266 | wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + | ||
1267 | ((mac1 & 0xff000000) >> 24); | ||
1268 | wl->fuse_nic_addr = mac1 & 0xffffff; | ||
1269 | |||
1270 | wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); | ||
1271 | } | ||
1272 | |||
1273 | static s8 wl12xx_get_pg_ver(struct wl1271 *wl) | ||
1274 | { | ||
1275 | u32 die_info; | ||
1276 | |||
1277 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
1278 | die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); | ||
1279 | else | ||
1280 | die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); | ||
1281 | |||
1282 | return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; | ||
1283 | } | ||
1284 | |||
1285 | static void wl12xx_get_mac(struct wl1271 *wl) | ||
1286 | { | ||
1287 | if (wl12xx_mac_in_fuse(wl)) | ||
1288 | wl12xx_get_fuse_mac(wl); | ||
1289 | } | ||
1290 | |||
1291 | static struct wlcore_ops wl12xx_ops = { | ||
1292 | .identify_chip = wl12xx_identify_chip, | ||
1293 | .identify_fw = wl12xx_identify_fw, | ||
1294 | .boot = wl12xx_boot, | ||
1295 | .trigger_cmd = wl12xx_trigger_cmd, | ||
1296 | .ack_event = wl12xx_ack_event, | ||
1297 | .calc_tx_blocks = wl12xx_calc_tx_blocks, | ||
1298 | .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks, | ||
1299 | .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len, | ||
1300 | .get_rx_buf_align = wl12xx_get_rx_buf_align, | ||
1301 | .get_rx_packet_len = wl12xx_get_rx_packet_len, | ||
1302 | .tx_immediate_compl = NULL, | ||
1303 | .tx_delayed_compl = wl12xx_tx_delayed_compl, | ||
1304 | .hw_init = wl12xx_hw_init, | ||
1305 | .init_vif = NULL, | ||
1306 | .sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask, | ||
1307 | .get_pg_ver = wl12xx_get_pg_ver, | ||
1308 | .get_mac = wl12xx_get_mac, | ||
1309 | }; | ||
1310 | |||
1311 | static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { | ||
1312 | .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | | ||
1313 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), | ||
1314 | .ht_supported = true, | ||
1315 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, | ||
1316 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, | ||
1317 | .mcs = { | ||
1318 | .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, | ||
1319 | .rx_highest = cpu_to_le16(72), | ||
1320 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
1321 | }, | ||
1322 | }; | ||
1323 | |||
1324 | static int __devinit wl12xx_probe(struct platform_device *pdev) | ||
1325 | { | ||
1326 | struct wl1271 *wl; | ||
1327 | struct ieee80211_hw *hw; | ||
1328 | struct wl12xx_priv *priv; | ||
1329 | |||
1330 | hw = wlcore_alloc_hw(sizeof(*priv)); | ||
1331 | if (IS_ERR(hw)) { | ||
1332 | wl1271_error("can't allocate hw"); | ||
1333 | return PTR_ERR(hw); | ||
1334 | } | ||
1335 | |||
1336 | wl = hw->priv; | ||
1337 | wl->ops = &wl12xx_ops; | ||
1338 | wl->ptable = wl12xx_ptable; | ||
1339 | wl->rtable = wl12xx_rtable; | ||
1340 | wl->num_tx_desc = 16; | ||
1341 | wl->normal_tx_spare = WL12XX_TX_HW_BLOCK_SPARE_DEFAULT; | ||
1342 | wl->gem_tx_spare = WL12XX_TX_HW_BLOCK_GEM_SPARE; | ||
1343 | wl->band_rate_to_idx = wl12xx_band_rate_to_idx; | ||
1344 | wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; | ||
1345 | wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0; | ||
1346 | wl->fw_status_priv_len = 0; | ||
1347 | memcpy(&wl->ht_cap, &wl12xx_ht_cap, sizeof(wl12xx_ht_cap)); | ||
1348 | wl12xx_conf_init(wl); | ||
1349 | |||
1350 | return wlcore_probe(wl, pdev); | ||
1351 | } | ||
1352 | |||
1353 | static const struct platform_device_id wl12xx_id_table[] __devinitconst = { | ||
1354 | { "wl12xx", 0 }, | ||
1355 | { } /* Terminating Entry */ | ||
1356 | }; | ||
1357 | MODULE_DEVICE_TABLE(platform, wl12xx_id_table); | ||
1358 | |||
1359 | static struct platform_driver wl12xx_driver = { | ||
1360 | .probe = wl12xx_probe, | ||
1361 | .remove = __devexit_p(wlcore_remove), | ||
1362 | .id_table = wl12xx_id_table, | ||
1363 | .driver = { | ||
1364 | .name = "wl12xx_driver", | ||
1365 | .owner = THIS_MODULE, | ||
1366 | } | ||
1367 | }; | ||
1368 | |||
1369 | static int __init wl12xx_init(void) | ||
1370 | { | ||
1371 | return platform_driver_register(&wl12xx_driver); | ||
1372 | } | ||
1373 | module_init(wl12xx_init); | ||
1374 | |||
1375 | static void __exit wl12xx_exit(void) | ||
1376 | { | ||
1377 | platform_driver_unregister(&wl12xx_driver); | ||
1378 | } | ||
1379 | module_exit(wl12xx_exit); | ||
1380 | |||
1381 | MODULE_LICENSE("GPL v2"); | ||
1382 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | ||
1383 | MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); | ||
1384 | MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); | ||
1385 | MODULE_FIRMWARE(WL127X_PLT_FW_NAME); | ||
1386 | MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); | ||
1387 | MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); | ||
1388 | MODULE_FIRMWARE(WL128X_PLT_FW_NAME); | ||