blob: ef4b0b915f8743c85b7b692cf0b2e32705337fd6 [file] [log] [blame]
Solomon Peachya910e4a2013-05-24 20:04:38 -04001/*
2 * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
3 *
4 * Copyright (c) 2010, ST-Ericsson
5 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
6 *
7 * Based on:
8 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
9 * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
10 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
11 *
12 * Based on:
13 * - the islsm (softmac prism54) driver, which is:
14 * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
15 * - stlc45xx driver
16 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License version 2 as
20 * published by the Free Software Foundation.
21 */
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/firmware.h>
26#include <linux/etherdevice.h>
27#include <linux/vmalloc.h>
28#include <linux/random.h>
29#include <linux/sched.h>
30#include <net/mac80211.h>
31
32#include "cw1200.h"
33#include "txrx.h"
34#include "sbus.h"
35#include "fwio.h"
36#include "hwio.h"
37#include "bh.h"
38#include "sta.h"
39#include "scan.h"
40#include "debug.h"
41#include "pm.h"
42
43MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
44MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code");
45MODULE_LICENSE("GPL");
46MODULE_ALIAS("cw1200_core");
47
48/* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */
49static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00};
50module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, S_IRUGO);
51MODULE_PARM_DESC(macaddr, "Override platform_data MAC address");
52
53static char *cw1200_sdd_path;
54module_param(cw1200_sdd_path, charp, 0644);
55MODULE_PARM_DESC(cw1200_sdd_path, "Override platform_data SDD file");
56static int cw1200_refclk;
57module_param(cw1200_refclk, int, 0644);
58MODULE_PARM_DESC(cw1200_refclk, "Override platform_data reference clock");
59
60int cw1200_power_mode = wsm_power_mode_quiescent;
61module_param(cw1200_power_mode, int, 0644);
62MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode. 0 == active, 1 == doze, 2 == quiescent (default)");
63
64#ifdef CONFIG_CW1200_ETF
65int etf_mode;
66module_param(etf_mode, int, 0644);
67MODULE_PARM_DESC(etf_mode, "Enable EngineeringTestingFramework operation");
68#endif
69
70#define RATETAB_ENT(_rate, _rateid, _flags) \
71 { \
72 .bitrate = (_rate), \
73 .hw_value = (_rateid), \
74 .flags = (_flags), \
75 }
76
77static struct ieee80211_rate cw1200_rates[] = {
78 RATETAB_ENT(10, 0, 0),
79 RATETAB_ENT(20, 1, 0),
80 RATETAB_ENT(55, 2, 0),
81 RATETAB_ENT(110, 3, 0),
82 RATETAB_ENT(60, 6, 0),
83 RATETAB_ENT(90, 7, 0),
84 RATETAB_ENT(120, 8, 0),
85 RATETAB_ENT(180, 9, 0),
86 RATETAB_ENT(240, 10, 0),
87 RATETAB_ENT(360, 11, 0),
88 RATETAB_ENT(480, 12, 0),
89 RATETAB_ENT(540, 13, 0),
90};
91
92static struct ieee80211_rate cw1200_mcs_rates[] = {
93 RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS),
94 RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS),
95 RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS),
96 RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS),
97 RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS),
98 RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS),
99 RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS),
100 RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS),
101};
102
103#define cw1200_a_rates (cw1200_rates + 4)
104#define cw1200_a_rates_size (ARRAY_SIZE(cw1200_rates) - 4)
105#define cw1200_g_rates (cw1200_rates + 0)
106#define cw1200_g_rates_size (ARRAY_SIZE(cw1200_rates))
107#define cw1200_n_rates (cw1200_mcs_rates)
108#define cw1200_n_rates_size (ARRAY_SIZE(cw1200_mcs_rates))
109
110
111#define CHAN2G(_channel, _freq, _flags) { \
112 .band = IEEE80211_BAND_2GHZ, \
113 .center_freq = (_freq), \
114 .hw_value = (_channel), \
115 .flags = (_flags), \
116 .max_antenna_gain = 0, \
117 .max_power = 30, \
118}
119
120#define CHAN5G(_channel, _flags) { \
121 .band = IEEE80211_BAND_5GHZ, \
122 .center_freq = 5000 + (5 * (_channel)), \
123 .hw_value = (_channel), \
124 .flags = (_flags), \
125 .max_antenna_gain = 0, \
126 .max_power = 30, \
127}
128
129static struct ieee80211_channel cw1200_2ghz_chantable[] = {
130 CHAN2G(1, 2412, 0),
131 CHAN2G(2, 2417, 0),
132 CHAN2G(3, 2422, 0),
133 CHAN2G(4, 2427, 0),
134 CHAN2G(5, 2432, 0),
135 CHAN2G(6, 2437, 0),
136 CHAN2G(7, 2442, 0),
137 CHAN2G(8, 2447, 0),
138 CHAN2G(9, 2452, 0),
139 CHAN2G(10, 2457, 0),
140 CHAN2G(11, 2462, 0),
141 CHAN2G(12, 2467, 0),
142 CHAN2G(13, 2472, 0),
143 CHAN2G(14, 2484, 0),
144};
145
146static struct ieee80211_channel cw1200_5ghz_chantable[] = {
147 CHAN5G(34, 0), CHAN5G(36, 0),
148 CHAN5G(38, 0), CHAN5G(40, 0),
149 CHAN5G(42, 0), CHAN5G(44, 0),
150 CHAN5G(46, 0), CHAN5G(48, 0),
151 CHAN5G(52, 0), CHAN5G(56, 0),
152 CHAN5G(60, 0), CHAN5G(64, 0),
153 CHAN5G(100, 0), CHAN5G(104, 0),
154 CHAN5G(108, 0), CHAN5G(112, 0),
155 CHAN5G(116, 0), CHAN5G(120, 0),
156 CHAN5G(124, 0), CHAN5G(128, 0),
157 CHAN5G(132, 0), CHAN5G(136, 0),
158 CHAN5G(140, 0), CHAN5G(149, 0),
159 CHAN5G(153, 0), CHAN5G(157, 0),
160 CHAN5G(161, 0), CHAN5G(165, 0),
161 CHAN5G(184, 0), CHAN5G(188, 0),
162 CHAN5G(192, 0), CHAN5G(196, 0),
163 CHAN5G(200, 0), CHAN5G(204, 0),
164 CHAN5G(208, 0), CHAN5G(212, 0),
165 CHAN5G(216, 0),
166};
167
168static struct ieee80211_supported_band cw1200_band_2ghz = {
169 .channels = cw1200_2ghz_chantable,
170 .n_channels = ARRAY_SIZE(cw1200_2ghz_chantable),
171 .bitrates = cw1200_g_rates,
172 .n_bitrates = cw1200_g_rates_size,
173 .ht_cap = {
174 .cap = IEEE80211_HT_CAP_GRN_FLD |
175 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
176 IEEE80211_HT_CAP_MAX_AMSDU,
177 .ht_supported = 1,
178 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
179 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
180 .mcs = {
181 .rx_mask[0] = 0xFF,
182 .rx_highest = __cpu_to_le16(0x41),
183 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
184 },
185 },
186};
187
188static struct ieee80211_supported_band cw1200_band_5ghz = {
189 .channels = cw1200_5ghz_chantable,
190 .n_channels = ARRAY_SIZE(cw1200_5ghz_chantable),
191 .bitrates = cw1200_a_rates,
192 .n_bitrates = cw1200_a_rates_size,
193 .ht_cap = {
194 .cap = IEEE80211_HT_CAP_GRN_FLD |
195 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
196 IEEE80211_HT_CAP_MAX_AMSDU,
197 .ht_supported = 1,
198 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
199 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
200 .mcs = {
201 .rx_mask[0] = 0xFF,
202 .rx_highest = __cpu_to_le16(0x41),
203 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
204 },
205 },
206};
207
208static const unsigned long cw1200_ttl[] = {
209 1 * HZ, /* VO */
210 2 * HZ, /* VI */
211 5 * HZ, /* BE */
212 10 * HZ /* BK */
213};
214
215static const struct ieee80211_ops cw1200_ops = {
216 .start = cw1200_start,
217 .stop = cw1200_stop,
218 .add_interface = cw1200_add_interface,
219 .remove_interface = cw1200_remove_interface,
220 .change_interface = cw1200_change_interface,
221 .tx = cw1200_tx,
222 .hw_scan = cw1200_hw_scan,
223 .set_tim = cw1200_set_tim,
224 .sta_notify = cw1200_sta_notify,
225 .sta_add = cw1200_sta_add,
226 .sta_remove = cw1200_sta_remove,
227 .set_key = cw1200_set_key,
228 .set_rts_threshold = cw1200_set_rts_threshold,
229 .config = cw1200_config,
230 .bss_info_changed = cw1200_bss_info_changed,
231 .prepare_multicast = cw1200_prepare_multicast,
232 .configure_filter = cw1200_configure_filter,
233 .conf_tx = cw1200_conf_tx,
234 .get_stats = cw1200_get_stats,
235 .ampdu_action = cw1200_ampdu_action,
236 .flush = cw1200_flush,
Solomon Peachy4e17b872013-05-29 22:22:05 -0400237#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400238 .suspend = cw1200_wow_suspend,
239 .resume = cw1200_wow_resume,
Solomon Peachy4e17b872013-05-29 22:22:05 -0400240#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400241 /* Intentionally not offloaded: */
242 /*.channel_switch = cw1200_channel_switch, */
243 /*.remain_on_channel = cw1200_remain_on_channel, */
244 /*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel, */
245};
246
247int cw1200_ba_rx_tids = -1;
248int cw1200_ba_tx_tids = -1;
249module_param(cw1200_ba_rx_tids, int, 0644);
250module_param(cw1200_ba_tx_tids, int, 0644);
251MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
252MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
253
254static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
255 const bool have_5ghz)
256{
257 int i, band;
258 struct ieee80211_hw *hw;
259 struct cw1200_common *priv;
260
261 hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops);
262 if (!hw)
263 return NULL;
264
265 priv = hw->priv;
266 priv->hw = hw;
267 priv->hw_type = -1;
268 priv->mode = NL80211_IFTYPE_UNSPECIFIED;
269 priv->rates = cw1200_rates; /* TODO: fetch from FW */
270 priv->mcs_rates = cw1200_n_rates;
271 if (cw1200_ba_rx_tids != -1)
272 priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
273 else
274 priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */
275 if (cw1200_ba_tx_tids != -1)
276 priv->ba_tx_tid_mask = cw1200_ba_tx_tids;
277 else
278 priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
279
280 hw->flags = IEEE80211_HW_SIGNAL_DBM |
281 IEEE80211_HW_SUPPORTS_PS |
282 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
283 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
284 IEEE80211_HW_SUPPORTS_UAPSD |
285 IEEE80211_HW_CONNECTION_MONITOR |
286 IEEE80211_HW_AMPDU_AGGREGATION |
287 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
288 IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC;
289
290 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
291 BIT(NL80211_IFTYPE_ADHOC) |
292 BIT(NL80211_IFTYPE_AP) |
293 BIT(NL80211_IFTYPE_MESH_POINT) |
294 BIT(NL80211_IFTYPE_P2P_CLIENT) |
295 BIT(NL80211_IFTYPE_P2P_GO);
296
Solomon Peachy4e17b872013-05-29 22:22:05 -0400297#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400298 /* Support only for limited wowlan functionalities */
299 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY |
300 WIPHY_WOWLAN_DISCONNECT;
301 hw->wiphy->wowlan.n_patterns = 0;
Solomon Peachy4e17b872013-05-29 22:22:05 -0400302#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400303
304 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
305
306 hw->channel_change_time = 1000; /* TODO: find actual value */
307 hw->queues = 4;
308
309 priv->rts_threshold = -1;
310
311 hw->max_rates = 8;
312 hw->max_rate_tries = 15;
313 hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM +
314 8; /* TKIP IV */
315
316 hw->sta_data_size = sizeof(struct cw1200_sta_priv);
317
318 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz;
319 if (have_5ghz)
320 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz;
321
322 /* Channel params have to be cleared before registering wiphy again */
323 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
324 struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
325 if (!sband)
326 continue;
327 for (i = 0; i < sband->n_channels; i++) {
328 sband->channels[i].flags = 0;
329 sband->channels[i].max_antenna_gain = 0;
330 sband->channels[i].max_power = 30;
331 }
332 }
333
334 hw->wiphy->max_scan_ssids = 2;
335 hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
336
337 if (macaddr)
338 SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr);
339 else
340 SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template);
341
342 /* Fix up mac address if necessary */
343 if (hw->wiphy->perm_addr[3] == 0 &&
344 hw->wiphy->perm_addr[4] == 0 &&
345 hw->wiphy->perm_addr[5] == 0) {
346 get_random_bytes(&hw->wiphy->perm_addr[3], 3);
347 }
348
349 mutex_init(&priv->wsm_cmd_mux);
350 mutex_init(&priv->conf_mutex);
351 priv->workqueue = create_singlethread_workqueue("cw1200_wq");
352 sema_init(&priv->scan.lock, 1);
353 INIT_WORK(&priv->scan.work, cw1200_scan_work);
354 INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
355 INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout);
356 INIT_DELAYED_WORK(&priv->clear_recent_scan_work,
357 cw1200_clear_recent_scan_work);
358 INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout);
359 INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work);
360 INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work);
361 INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work);
362 INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work);
363 spin_lock_init(&priv->event_queue_lock);
364 INIT_LIST_HEAD(&priv->event_queue);
365 INIT_WORK(&priv->event_handler, cw1200_event_handler);
366 INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work);
367 INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work);
368 spin_lock_init(&priv->bss_loss_lock);
369 spin_lock_init(&priv->ps_state_lock);
370 INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work);
371 INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work);
372 INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work);
373 INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work);
374 INIT_WORK(&priv->link_id_work, cw1200_link_id_work);
375 INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work);
376 INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
377 INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
378 INIT_WORK(&priv->set_beacon_wakeup_period_work,
379 cw1200_set_beacon_wakeup_period_work);
380 init_timer(&priv->mcast_timeout);
381 priv->mcast_timeout.data = (unsigned long)priv;
382 priv->mcast_timeout.function = cw1200_mcast_timeout;
383
384 if (cw1200_queue_stats_init(&priv->tx_queue_stats,
385 CW1200_LINK_ID_MAX,
386 cw1200_skb_dtor,
387 priv)) {
388 ieee80211_free_hw(hw);
389 return NULL;
390 }
391
392 for (i = 0; i < 4; ++i) {
393 if (cw1200_queue_init(&priv->tx_queue[i],
394 &priv->tx_queue_stats, i, 16,
395 cw1200_ttl[i])) {
396 for (; i > 0; i--)
397 cw1200_queue_deinit(&priv->tx_queue[i - 1]);
398 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
399 ieee80211_free_hw(hw);
400 return NULL;
401 }
402 }
403
404 init_waitqueue_head(&priv->channel_switch_done);
405 init_waitqueue_head(&priv->wsm_cmd_wq);
406 init_waitqueue_head(&priv->wsm_startup_done);
407 init_waitqueue_head(&priv->ps_mode_switch_done);
408 wsm_buf_init(&priv->wsm_cmd_buf);
409 spin_lock_init(&priv->wsm_cmd.lock);
410 priv->wsm_cmd.done = 1;
411 tx_policy_init(priv);
412
413 return hw;
414}
415
416static int cw1200_register_common(struct ieee80211_hw *dev)
417{
418 struct cw1200_common *priv = dev->priv;
419 int err;
420
421#ifdef CONFIG_CW1200_ETF
422 if (etf_mode)
423 goto done;
424#endif
425
Solomon Peachy4e17b872013-05-29 22:22:05 -0400426#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400427 err = cw1200_pm_init(&priv->pm_state, priv);
428 if (err) {
429 pr_err("Cannot init PM. (%d).\n",
430 err);
431 return err;
432 }
Solomon Peachy4e17b872013-05-29 22:22:05 -0400433#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400434
435 err = ieee80211_register_hw(dev);
436 if (err) {
437 pr_err("Cannot register device (%d).\n",
438 err);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400439#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400440 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400441#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400442 return err;
443 }
444
445#ifdef CONFIG_CW1200_ETF
446done:
447#endif
448 cw1200_debug_init(priv);
449
450 pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
451 return 0;
452}
453
454static void cw1200_free_common(struct ieee80211_hw *dev)
455{
456 ieee80211_free_hw(dev);
457}
458
459static void cw1200_unregister_common(struct ieee80211_hw *dev)
460{
461 struct cw1200_common *priv = dev->priv;
462 int i;
463
464#ifdef CONFIG_CW1200_ETF
465 if (!etf_mode) {
466#endif
467 ieee80211_unregister_hw(dev);
468#ifdef CONFIG_CW1200_ETF
469 }
470#endif
471
472 del_timer_sync(&priv->mcast_timeout);
473 cw1200_unregister_bh(priv);
474
475 cw1200_debug_release(priv);
476
477 mutex_destroy(&priv->conf_mutex);
478
479 wsm_buf_deinit(&priv->wsm_cmd_buf);
480
481 destroy_workqueue(priv->workqueue);
482 priv->workqueue = NULL;
483
484 if (priv->sdd) {
485 release_firmware(priv->sdd);
486 priv->sdd = NULL;
487 }
488
489 for (i = 0; i < 4; ++i)
490 cw1200_queue_deinit(&priv->tx_queue[i]);
491
492 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400493#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400494 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400495#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400496}
497
498/* Clock is in KHz */
499u32 cw1200_dpll_from_clk(u16 clk_khz)
500{
501 switch (clk_khz) {
502 case 0x32C8: /* 13000 KHz */
503 return 0x1D89D241;
504 case 0x3E80: /* 16000 KHz */
505 return 0x000001E1;
506 case 0x41A0: /* 16800 KHz */
507 return 0x124931C1;
508 case 0x4B00: /* 19200 KHz */
509 return 0x00000191;
510 case 0x5DC0: /* 24000 KHz */
511 return 0x00000141;
512 case 0x6590: /* 26000 KHz */
513 return 0x0EC4F121;
514 case 0x8340: /* 33600 KHz */
515 return 0x092490E1;
516 case 0x9600: /* 38400 KHz */
517 return 0x100010C1;
518 case 0x9C40: /* 40000 KHz */
519 return 0x000000C1;
520 case 0xBB80: /* 48000 KHz */
521 return 0x000000A1;
522 case 0xCB20: /* 52000 KHz */
523 return 0x07627091;
524 default:
525 pr_err("Unknown Refclk freq (0x%04x), using 2600KHz\n",
526 clk_khz);
527 return 0x0EC4F121;
528 }
529}
530
531int cw1200_core_probe(const struct sbus_ops *sbus_ops,
532 struct sbus_priv *sbus,
533 struct device *pdev,
534 struct cw1200_common **core,
535 int ref_clk, const u8 *macaddr,
536 const char *sdd_path, bool have_5ghz)
537{
538 int err = -EINVAL;
539 struct ieee80211_hw *dev;
540 struct cw1200_common *priv;
541 struct wsm_operational_mode mode = {
542 .power_mode = cw1200_power_mode,
543 .disable_more_flag_usage = true,
544 };
545
546 dev = cw1200_init_common(macaddr, have_5ghz);
547 if (!dev)
548 goto err;
549
550 priv = dev->priv;
551 priv->hw_refclk = ref_clk;
552 if (cw1200_refclk)
553 priv->hw_refclk = cw1200_refclk;
554
555 priv->sdd_path = (char *)sdd_path;
556 if (cw1200_sdd_path)
557 priv->sdd_path = cw1200_sdd_path;
558
559 priv->sbus_ops = sbus_ops;
560 priv->sbus_priv = sbus;
561 priv->pdev = pdev;
562 SET_IEEE80211_DEV(priv->hw, pdev);
563
564 /* Pass struct cw1200_common back up */
565 *core = priv;
566
567 err = cw1200_register_bh(priv);
568 if (err)
569 goto err1;
570
571#ifdef CONFIG_CW1200_ETF
572 if (etf_mode)
573 goto skip_fw;
574#endif
575
576 err = cw1200_load_firmware(priv);
577 if (err)
578 goto err2;
579
580 if (wait_event_interruptible_timeout(priv->wsm_startup_done,
581 priv->firmware_ready,
582 3*HZ) <= 0) {
583 /* TODO: Need to find how to reset device
584 in QUEUE mode properly.
585 */
586 pr_err("Timeout waiting on device startup\n");
587 err = -ETIMEDOUT;
588 goto err2;
589 }
590
591 /* Set low-power mode. */
592 wsm_set_operational_mode(priv, &mode);
593
594 /* Enable multi-TX confirmation */
595 wsm_use_multi_tx_conf(priv, true);
596
597#ifdef CONFIG_CW1200_ETF
598skip_fw:
599#endif
600 err = cw1200_register_common(dev);
601 if (err)
602 goto err2;
603
604 return err;
605
606err2:
607 cw1200_unregister_bh(priv);
608err1:
609 cw1200_free_common(dev);
610err:
611 *core = NULL;
612 return err;
613}
614EXPORT_SYMBOL_GPL(cw1200_core_probe);
615
616void cw1200_core_release(struct cw1200_common *self)
617{
618 /* Disable device interrupts */
619 self->sbus_ops->lock(self->sbus_priv);
620 __cw1200_irq_enable(self, 0);
621 self->sbus_ops->unlock(self->sbus_priv);
622
623 /* And then clean up */
624 cw1200_unregister_common(self->hw);
625 cw1200_free_common(self->hw);
626 return;
627}
628EXPORT_SYMBOL_GPL(cw1200_core_release);