blob: c934ec52d129a32a012394e22ca5cbd2961f41a5 [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"
Solomon Peachy911373c2013-06-01 08:08:42 -040034#include "hwbus.h"
Solomon Peachya910e4a2013-05-24 20:04:38 -040035#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
Johannes Berg51217ce2013-06-04 12:56:01 +0200254#ifdef CONFIG_PM
255static const struct wiphy_wowlan_support cw1200_wowlan_support = {
256 /* Support only for limited wowlan functionalities */
257 .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
258};
259#endif
260
261
Solomon Peachya910e4a2013-05-24 20:04:38 -0400262static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
263 const bool have_5ghz)
264{
265 int i, band;
266 struct ieee80211_hw *hw;
267 struct cw1200_common *priv;
268
269 hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops);
270 if (!hw)
271 return NULL;
272
273 priv = hw->priv;
274 priv->hw = hw;
275 priv->hw_type = -1;
276 priv->mode = NL80211_IFTYPE_UNSPECIFIED;
277 priv->rates = cw1200_rates; /* TODO: fetch from FW */
278 priv->mcs_rates = cw1200_n_rates;
279 if (cw1200_ba_rx_tids != -1)
280 priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
281 else
282 priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */
283 if (cw1200_ba_tx_tids != -1)
284 priv->ba_tx_tid_mask = cw1200_ba_tx_tids;
285 else
286 priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
287
288 hw->flags = IEEE80211_HW_SIGNAL_DBM |
289 IEEE80211_HW_SUPPORTS_PS |
290 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
291 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
292 IEEE80211_HW_SUPPORTS_UAPSD |
293 IEEE80211_HW_CONNECTION_MONITOR |
294 IEEE80211_HW_AMPDU_AGGREGATION |
295 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
296 IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC;
297
298 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
299 BIT(NL80211_IFTYPE_ADHOC) |
300 BIT(NL80211_IFTYPE_AP) |
301 BIT(NL80211_IFTYPE_MESH_POINT) |
302 BIT(NL80211_IFTYPE_P2P_CLIENT) |
303 BIT(NL80211_IFTYPE_P2P_GO);
304
Solomon Peachy4e17b872013-05-29 22:22:05 -0400305#ifdef CONFIG_PM
Johannes Berg51217ce2013-06-04 12:56:01 +0200306 hw->wiphy->wowlan = &cw1200_wowlan_support;
Solomon Peachy4e17b872013-05-29 22:22:05 -0400307#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400308
309 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
310
311 hw->channel_change_time = 1000; /* TODO: find actual value */
312 hw->queues = 4;
313
314 priv->rts_threshold = -1;
315
316 hw->max_rates = 8;
317 hw->max_rate_tries = 15;
318 hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM +
319 8; /* TKIP IV */
320
321 hw->sta_data_size = sizeof(struct cw1200_sta_priv);
322
323 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz;
324 if (have_5ghz)
325 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz;
326
327 /* Channel params have to be cleared before registering wiphy again */
328 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
329 struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
330 if (!sband)
331 continue;
332 for (i = 0; i < sband->n_channels; i++) {
333 sband->channels[i].flags = 0;
334 sband->channels[i].max_antenna_gain = 0;
335 sband->channels[i].max_power = 30;
336 }
337 }
338
339 hw->wiphy->max_scan_ssids = 2;
340 hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
341
342 if (macaddr)
343 SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr);
344 else
345 SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template);
346
347 /* Fix up mac address if necessary */
348 if (hw->wiphy->perm_addr[3] == 0 &&
349 hw->wiphy->perm_addr[4] == 0 &&
350 hw->wiphy->perm_addr[5] == 0) {
351 get_random_bytes(&hw->wiphy->perm_addr[3], 3);
352 }
353
354 mutex_init(&priv->wsm_cmd_mux);
355 mutex_init(&priv->conf_mutex);
356 priv->workqueue = create_singlethread_workqueue("cw1200_wq");
357 sema_init(&priv->scan.lock, 1);
358 INIT_WORK(&priv->scan.work, cw1200_scan_work);
359 INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
360 INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout);
361 INIT_DELAYED_WORK(&priv->clear_recent_scan_work,
362 cw1200_clear_recent_scan_work);
363 INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout);
364 INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work);
365 INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work);
366 INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work);
367 INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work);
368 spin_lock_init(&priv->event_queue_lock);
369 INIT_LIST_HEAD(&priv->event_queue);
370 INIT_WORK(&priv->event_handler, cw1200_event_handler);
371 INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work);
372 INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work);
373 spin_lock_init(&priv->bss_loss_lock);
374 spin_lock_init(&priv->ps_state_lock);
375 INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work);
376 INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work);
377 INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work);
378 INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work);
379 INIT_WORK(&priv->link_id_work, cw1200_link_id_work);
380 INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work);
381 INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
382 INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
383 INIT_WORK(&priv->set_beacon_wakeup_period_work,
384 cw1200_set_beacon_wakeup_period_work);
385 init_timer(&priv->mcast_timeout);
386 priv->mcast_timeout.data = (unsigned long)priv;
387 priv->mcast_timeout.function = cw1200_mcast_timeout;
388
389 if (cw1200_queue_stats_init(&priv->tx_queue_stats,
390 CW1200_LINK_ID_MAX,
391 cw1200_skb_dtor,
392 priv)) {
393 ieee80211_free_hw(hw);
394 return NULL;
395 }
396
397 for (i = 0; i < 4; ++i) {
398 if (cw1200_queue_init(&priv->tx_queue[i],
399 &priv->tx_queue_stats, i, 16,
400 cw1200_ttl[i])) {
401 for (; i > 0; i--)
402 cw1200_queue_deinit(&priv->tx_queue[i - 1]);
403 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
404 ieee80211_free_hw(hw);
405 return NULL;
406 }
407 }
408
409 init_waitqueue_head(&priv->channel_switch_done);
410 init_waitqueue_head(&priv->wsm_cmd_wq);
411 init_waitqueue_head(&priv->wsm_startup_done);
412 init_waitqueue_head(&priv->ps_mode_switch_done);
413 wsm_buf_init(&priv->wsm_cmd_buf);
414 spin_lock_init(&priv->wsm_cmd.lock);
415 priv->wsm_cmd.done = 1;
416 tx_policy_init(priv);
417
418 return hw;
419}
420
421static int cw1200_register_common(struct ieee80211_hw *dev)
422{
423 struct cw1200_common *priv = dev->priv;
424 int err;
425
426#ifdef CONFIG_CW1200_ETF
427 if (etf_mode)
428 goto done;
429#endif
430
Solomon Peachy4e17b872013-05-29 22:22:05 -0400431#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400432 err = cw1200_pm_init(&priv->pm_state, priv);
433 if (err) {
434 pr_err("Cannot init PM. (%d).\n",
435 err);
436 return err;
437 }
Solomon Peachy4e17b872013-05-29 22:22:05 -0400438#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400439
440 err = ieee80211_register_hw(dev);
441 if (err) {
442 pr_err("Cannot register device (%d).\n",
443 err);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400444#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400445 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400446#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400447 return err;
448 }
449
450#ifdef CONFIG_CW1200_ETF
451done:
452#endif
453 cw1200_debug_init(priv);
454
455 pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
456 return 0;
457}
458
459static void cw1200_free_common(struct ieee80211_hw *dev)
460{
461 ieee80211_free_hw(dev);
462}
463
464static void cw1200_unregister_common(struct ieee80211_hw *dev)
465{
466 struct cw1200_common *priv = dev->priv;
467 int i;
468
469#ifdef CONFIG_CW1200_ETF
470 if (!etf_mode) {
471#endif
472 ieee80211_unregister_hw(dev);
473#ifdef CONFIG_CW1200_ETF
474 }
475#endif
476
477 del_timer_sync(&priv->mcast_timeout);
478 cw1200_unregister_bh(priv);
479
480 cw1200_debug_release(priv);
481
482 mutex_destroy(&priv->conf_mutex);
483
484 wsm_buf_deinit(&priv->wsm_cmd_buf);
485
486 destroy_workqueue(priv->workqueue);
487 priv->workqueue = NULL;
488
489 if (priv->sdd) {
490 release_firmware(priv->sdd);
491 priv->sdd = NULL;
492 }
493
494 for (i = 0; i < 4; ++i)
495 cw1200_queue_deinit(&priv->tx_queue[i]);
496
497 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400498#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400499 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400500#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400501}
502
503/* Clock is in KHz */
504u32 cw1200_dpll_from_clk(u16 clk_khz)
505{
506 switch (clk_khz) {
507 case 0x32C8: /* 13000 KHz */
508 return 0x1D89D241;
509 case 0x3E80: /* 16000 KHz */
510 return 0x000001E1;
511 case 0x41A0: /* 16800 KHz */
512 return 0x124931C1;
513 case 0x4B00: /* 19200 KHz */
514 return 0x00000191;
515 case 0x5DC0: /* 24000 KHz */
516 return 0x00000141;
517 case 0x6590: /* 26000 KHz */
518 return 0x0EC4F121;
519 case 0x8340: /* 33600 KHz */
520 return 0x092490E1;
521 case 0x9600: /* 38400 KHz */
522 return 0x100010C1;
523 case 0x9C40: /* 40000 KHz */
524 return 0x000000C1;
525 case 0xBB80: /* 48000 KHz */
526 return 0x000000A1;
527 case 0xCB20: /* 52000 KHz */
528 return 0x07627091;
529 default:
530 pr_err("Unknown Refclk freq (0x%04x), using 2600KHz\n",
531 clk_khz);
532 return 0x0EC4F121;
533 }
534}
535
Solomon Peachy911373c2013-06-01 08:08:42 -0400536int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
537 struct hwbus_priv *hwbus,
Solomon Peachya910e4a2013-05-24 20:04:38 -0400538 struct device *pdev,
539 struct cw1200_common **core,
540 int ref_clk, const u8 *macaddr,
541 const char *sdd_path, bool have_5ghz)
542{
543 int err = -EINVAL;
544 struct ieee80211_hw *dev;
545 struct cw1200_common *priv;
546 struct wsm_operational_mode mode = {
547 .power_mode = cw1200_power_mode,
548 .disable_more_flag_usage = true,
549 };
550
551 dev = cw1200_init_common(macaddr, have_5ghz);
552 if (!dev)
553 goto err;
554
555 priv = dev->priv;
556 priv->hw_refclk = ref_clk;
557 if (cw1200_refclk)
558 priv->hw_refclk = cw1200_refclk;
559
560 priv->sdd_path = (char *)sdd_path;
561 if (cw1200_sdd_path)
562 priv->sdd_path = cw1200_sdd_path;
563
Solomon Peachy911373c2013-06-01 08:08:42 -0400564 priv->hwbus_ops = hwbus_ops;
565 priv->hwbus_priv = hwbus;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400566 priv->pdev = pdev;
567 SET_IEEE80211_DEV(priv->hw, pdev);
568
569 /* Pass struct cw1200_common back up */
570 *core = priv;
571
572 err = cw1200_register_bh(priv);
573 if (err)
574 goto err1;
575
576#ifdef CONFIG_CW1200_ETF
577 if (etf_mode)
578 goto skip_fw;
579#endif
580
581 err = cw1200_load_firmware(priv);
582 if (err)
583 goto err2;
584
585 if (wait_event_interruptible_timeout(priv->wsm_startup_done,
586 priv->firmware_ready,
587 3*HZ) <= 0) {
588 /* TODO: Need to find how to reset device
589 in QUEUE mode properly.
590 */
591 pr_err("Timeout waiting on device startup\n");
592 err = -ETIMEDOUT;
593 goto err2;
594 }
595
596 /* Set low-power mode. */
597 wsm_set_operational_mode(priv, &mode);
598
599 /* Enable multi-TX confirmation */
600 wsm_use_multi_tx_conf(priv, true);
601
602#ifdef CONFIG_CW1200_ETF
603skip_fw:
604#endif
605 err = cw1200_register_common(dev);
606 if (err)
607 goto err2;
608
609 return err;
610
611err2:
612 cw1200_unregister_bh(priv);
613err1:
614 cw1200_free_common(dev);
615err:
616 *core = NULL;
617 return err;
618}
619EXPORT_SYMBOL_GPL(cw1200_core_probe);
620
621void cw1200_core_release(struct cw1200_common *self)
622{
623 /* Disable device interrupts */
Solomon Peachy911373c2013-06-01 08:08:42 -0400624 self->hwbus_ops->lock(self->hwbus_priv);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400625 __cw1200_irq_enable(self, 0);
Solomon Peachy911373c2013-06-01 08:08:42 -0400626 self->hwbus_ops->unlock(self->hwbus_priv);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400627
628 /* And then clean up */
629 cw1200_unregister_common(self->hw);
630 cw1200_free_common(self->hw);
631 return;
632}
633EXPORT_SYMBOL_GPL(cw1200_core_release);