blob: 9f9adb4fbfb8795b7d0518202b59a9d142bf1453 [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
Solomon Peachya910e4a2013-05-24 20:04:38 -040064#define RATETAB_ENT(_rate, _rateid, _flags) \
65 { \
66 .bitrate = (_rate), \
67 .hw_value = (_rateid), \
68 .flags = (_flags), \
69 }
70
71static struct ieee80211_rate cw1200_rates[] = {
72 RATETAB_ENT(10, 0, 0),
73 RATETAB_ENT(20, 1, 0),
74 RATETAB_ENT(55, 2, 0),
75 RATETAB_ENT(110, 3, 0),
76 RATETAB_ENT(60, 6, 0),
77 RATETAB_ENT(90, 7, 0),
78 RATETAB_ENT(120, 8, 0),
79 RATETAB_ENT(180, 9, 0),
80 RATETAB_ENT(240, 10, 0),
81 RATETAB_ENT(360, 11, 0),
82 RATETAB_ENT(480, 12, 0),
83 RATETAB_ENT(540, 13, 0),
84};
85
86static struct ieee80211_rate cw1200_mcs_rates[] = {
87 RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS),
88 RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS),
89 RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS),
90 RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS),
91 RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS),
92 RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS),
93 RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS),
94 RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS),
95};
96
97#define cw1200_a_rates (cw1200_rates + 4)
98#define cw1200_a_rates_size (ARRAY_SIZE(cw1200_rates) - 4)
99#define cw1200_g_rates (cw1200_rates + 0)
100#define cw1200_g_rates_size (ARRAY_SIZE(cw1200_rates))
101#define cw1200_n_rates (cw1200_mcs_rates)
102#define cw1200_n_rates_size (ARRAY_SIZE(cw1200_mcs_rates))
103
104
105#define CHAN2G(_channel, _freq, _flags) { \
106 .band = IEEE80211_BAND_2GHZ, \
107 .center_freq = (_freq), \
108 .hw_value = (_channel), \
109 .flags = (_flags), \
110 .max_antenna_gain = 0, \
111 .max_power = 30, \
112}
113
114#define CHAN5G(_channel, _flags) { \
115 .band = IEEE80211_BAND_5GHZ, \
116 .center_freq = 5000 + (5 * (_channel)), \
117 .hw_value = (_channel), \
118 .flags = (_flags), \
119 .max_antenna_gain = 0, \
120 .max_power = 30, \
121}
122
123static struct ieee80211_channel cw1200_2ghz_chantable[] = {
124 CHAN2G(1, 2412, 0),
125 CHAN2G(2, 2417, 0),
126 CHAN2G(3, 2422, 0),
127 CHAN2G(4, 2427, 0),
128 CHAN2G(5, 2432, 0),
129 CHAN2G(6, 2437, 0),
130 CHAN2G(7, 2442, 0),
131 CHAN2G(8, 2447, 0),
132 CHAN2G(9, 2452, 0),
133 CHAN2G(10, 2457, 0),
134 CHAN2G(11, 2462, 0),
135 CHAN2G(12, 2467, 0),
136 CHAN2G(13, 2472, 0),
137 CHAN2G(14, 2484, 0),
138};
139
140static struct ieee80211_channel cw1200_5ghz_chantable[] = {
141 CHAN5G(34, 0), CHAN5G(36, 0),
142 CHAN5G(38, 0), CHAN5G(40, 0),
143 CHAN5G(42, 0), CHAN5G(44, 0),
144 CHAN5G(46, 0), CHAN5G(48, 0),
145 CHAN5G(52, 0), CHAN5G(56, 0),
146 CHAN5G(60, 0), CHAN5G(64, 0),
147 CHAN5G(100, 0), CHAN5G(104, 0),
148 CHAN5G(108, 0), CHAN5G(112, 0),
149 CHAN5G(116, 0), CHAN5G(120, 0),
150 CHAN5G(124, 0), CHAN5G(128, 0),
151 CHAN5G(132, 0), CHAN5G(136, 0),
152 CHAN5G(140, 0), CHAN5G(149, 0),
153 CHAN5G(153, 0), CHAN5G(157, 0),
154 CHAN5G(161, 0), CHAN5G(165, 0),
155 CHAN5G(184, 0), CHAN5G(188, 0),
156 CHAN5G(192, 0), CHAN5G(196, 0),
157 CHAN5G(200, 0), CHAN5G(204, 0),
158 CHAN5G(208, 0), CHAN5G(212, 0),
159 CHAN5G(216, 0),
160};
161
162static struct ieee80211_supported_band cw1200_band_2ghz = {
163 .channels = cw1200_2ghz_chantable,
164 .n_channels = ARRAY_SIZE(cw1200_2ghz_chantable),
165 .bitrates = cw1200_g_rates,
166 .n_bitrates = cw1200_g_rates_size,
167 .ht_cap = {
168 .cap = IEEE80211_HT_CAP_GRN_FLD |
169 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
170 IEEE80211_HT_CAP_MAX_AMSDU,
171 .ht_supported = 1,
172 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
173 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
174 .mcs = {
175 .rx_mask[0] = 0xFF,
176 .rx_highest = __cpu_to_le16(0x41),
177 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
178 },
179 },
180};
181
182static struct ieee80211_supported_band cw1200_band_5ghz = {
183 .channels = cw1200_5ghz_chantable,
184 .n_channels = ARRAY_SIZE(cw1200_5ghz_chantable),
185 .bitrates = cw1200_a_rates,
186 .n_bitrates = cw1200_a_rates_size,
187 .ht_cap = {
188 .cap = IEEE80211_HT_CAP_GRN_FLD |
189 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) |
190 IEEE80211_HT_CAP_MAX_AMSDU,
191 .ht_supported = 1,
192 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
193 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE,
194 .mcs = {
195 .rx_mask[0] = 0xFF,
196 .rx_highest = __cpu_to_le16(0x41),
197 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
198 },
199 },
200};
201
202static const unsigned long cw1200_ttl[] = {
203 1 * HZ, /* VO */
204 2 * HZ, /* VI */
205 5 * HZ, /* BE */
206 10 * HZ /* BK */
207};
208
209static const struct ieee80211_ops cw1200_ops = {
210 .start = cw1200_start,
211 .stop = cw1200_stop,
212 .add_interface = cw1200_add_interface,
213 .remove_interface = cw1200_remove_interface,
214 .change_interface = cw1200_change_interface,
215 .tx = cw1200_tx,
216 .hw_scan = cw1200_hw_scan,
217 .set_tim = cw1200_set_tim,
218 .sta_notify = cw1200_sta_notify,
219 .sta_add = cw1200_sta_add,
220 .sta_remove = cw1200_sta_remove,
221 .set_key = cw1200_set_key,
222 .set_rts_threshold = cw1200_set_rts_threshold,
223 .config = cw1200_config,
224 .bss_info_changed = cw1200_bss_info_changed,
225 .prepare_multicast = cw1200_prepare_multicast,
226 .configure_filter = cw1200_configure_filter,
227 .conf_tx = cw1200_conf_tx,
228 .get_stats = cw1200_get_stats,
229 .ampdu_action = cw1200_ampdu_action,
230 .flush = cw1200_flush,
Solomon Peachy4e17b872013-05-29 22:22:05 -0400231#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400232 .suspend = cw1200_wow_suspend,
233 .resume = cw1200_wow_resume,
Solomon Peachy4e17b872013-05-29 22:22:05 -0400234#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400235 /* Intentionally not offloaded: */
236 /*.channel_switch = cw1200_channel_switch, */
237 /*.remain_on_channel = cw1200_remain_on_channel, */
238 /*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel, */
239};
240
241int cw1200_ba_rx_tids = -1;
242int cw1200_ba_tx_tids = -1;
243module_param(cw1200_ba_rx_tids, int, 0644);
244module_param(cw1200_ba_tx_tids, int, 0644);
245MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
246MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
247
248static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
249 const bool have_5ghz)
250{
251 int i, band;
252 struct ieee80211_hw *hw;
253 struct cw1200_common *priv;
254
255 hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops);
256 if (!hw)
257 return NULL;
258
259 priv = hw->priv;
260 priv->hw = hw;
261 priv->hw_type = -1;
262 priv->mode = NL80211_IFTYPE_UNSPECIFIED;
263 priv->rates = cw1200_rates; /* TODO: fetch from FW */
264 priv->mcs_rates = cw1200_n_rates;
265 if (cw1200_ba_rx_tids != -1)
266 priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
267 else
268 priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */
269 if (cw1200_ba_tx_tids != -1)
270 priv->ba_tx_tid_mask = cw1200_ba_tx_tids;
271 else
272 priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */
273
274 hw->flags = IEEE80211_HW_SIGNAL_DBM |
275 IEEE80211_HW_SUPPORTS_PS |
276 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
277 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
278 IEEE80211_HW_SUPPORTS_UAPSD |
279 IEEE80211_HW_CONNECTION_MONITOR |
280 IEEE80211_HW_AMPDU_AGGREGATION |
281 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
282 IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC;
283
284 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
285 BIT(NL80211_IFTYPE_ADHOC) |
286 BIT(NL80211_IFTYPE_AP) |
287 BIT(NL80211_IFTYPE_MESH_POINT) |
288 BIT(NL80211_IFTYPE_P2P_CLIENT) |
289 BIT(NL80211_IFTYPE_P2P_GO);
290
Solomon Peachy4e17b872013-05-29 22:22:05 -0400291#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400292 /* Support only for limited wowlan functionalities */
293 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY |
294 WIPHY_WOWLAN_DISCONNECT;
295 hw->wiphy->wowlan.n_patterns = 0;
Solomon Peachy4e17b872013-05-29 22:22:05 -0400296#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400297
298 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
299
300 hw->channel_change_time = 1000; /* TODO: find actual value */
301 hw->queues = 4;
302
303 priv->rts_threshold = -1;
304
305 hw->max_rates = 8;
306 hw->max_rate_tries = 15;
307 hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM +
308 8; /* TKIP IV */
309
310 hw->sta_data_size = sizeof(struct cw1200_sta_priv);
311
312 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz;
313 if (have_5ghz)
314 hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz;
315
316 /* Channel params have to be cleared before registering wiphy again */
317 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
318 struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
319 if (!sband)
320 continue;
321 for (i = 0; i < sband->n_channels; i++) {
322 sband->channels[i].flags = 0;
323 sband->channels[i].max_antenna_gain = 0;
324 sband->channels[i].max_power = 30;
325 }
326 }
327
328 hw->wiphy->max_scan_ssids = 2;
329 hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
330
331 if (macaddr)
332 SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr);
333 else
334 SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template);
335
336 /* Fix up mac address if necessary */
337 if (hw->wiphy->perm_addr[3] == 0 &&
338 hw->wiphy->perm_addr[4] == 0 &&
339 hw->wiphy->perm_addr[5] == 0) {
340 get_random_bytes(&hw->wiphy->perm_addr[3], 3);
341 }
342
343 mutex_init(&priv->wsm_cmd_mux);
344 mutex_init(&priv->conf_mutex);
345 priv->workqueue = create_singlethread_workqueue("cw1200_wq");
346 sema_init(&priv->scan.lock, 1);
347 INIT_WORK(&priv->scan.work, cw1200_scan_work);
348 INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
349 INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout);
350 INIT_DELAYED_WORK(&priv->clear_recent_scan_work,
351 cw1200_clear_recent_scan_work);
352 INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout);
353 INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work);
354 INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work);
355 INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work);
356 INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work);
357 spin_lock_init(&priv->event_queue_lock);
358 INIT_LIST_HEAD(&priv->event_queue);
359 INIT_WORK(&priv->event_handler, cw1200_event_handler);
360 INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work);
361 INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work);
362 spin_lock_init(&priv->bss_loss_lock);
363 spin_lock_init(&priv->ps_state_lock);
364 INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work);
365 INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work);
366 INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work);
367 INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work);
368 INIT_WORK(&priv->link_id_work, cw1200_link_id_work);
369 INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work);
370 INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
371 INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
372 INIT_WORK(&priv->set_beacon_wakeup_period_work,
373 cw1200_set_beacon_wakeup_period_work);
374 init_timer(&priv->mcast_timeout);
375 priv->mcast_timeout.data = (unsigned long)priv;
376 priv->mcast_timeout.function = cw1200_mcast_timeout;
377
378 if (cw1200_queue_stats_init(&priv->tx_queue_stats,
379 CW1200_LINK_ID_MAX,
380 cw1200_skb_dtor,
381 priv)) {
382 ieee80211_free_hw(hw);
383 return NULL;
384 }
385
386 for (i = 0; i < 4; ++i) {
387 if (cw1200_queue_init(&priv->tx_queue[i],
388 &priv->tx_queue_stats, i, 16,
389 cw1200_ttl[i])) {
390 for (; i > 0; i--)
391 cw1200_queue_deinit(&priv->tx_queue[i - 1]);
392 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
393 ieee80211_free_hw(hw);
394 return NULL;
395 }
396 }
397
398 init_waitqueue_head(&priv->channel_switch_done);
399 init_waitqueue_head(&priv->wsm_cmd_wq);
400 init_waitqueue_head(&priv->wsm_startup_done);
401 init_waitqueue_head(&priv->ps_mode_switch_done);
402 wsm_buf_init(&priv->wsm_cmd_buf);
403 spin_lock_init(&priv->wsm_cmd.lock);
404 priv->wsm_cmd.done = 1;
405 tx_policy_init(priv);
406
407 return hw;
408}
409
410static int cw1200_register_common(struct ieee80211_hw *dev)
411{
412 struct cw1200_common *priv = dev->priv;
413 int err;
414
Solomon Peachy4e17b872013-05-29 22:22:05 -0400415#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400416 err = cw1200_pm_init(&priv->pm_state, priv);
417 if (err) {
418 pr_err("Cannot init PM. (%d).\n",
419 err);
420 return err;
421 }
Solomon Peachy4e17b872013-05-29 22:22:05 -0400422#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400423
424 err = ieee80211_register_hw(dev);
425 if (err) {
426 pr_err("Cannot register device (%d).\n",
427 err);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400428#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400429 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400430#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400431 return err;
432 }
433
Solomon Peachya910e4a2013-05-24 20:04:38 -0400434 cw1200_debug_init(priv);
435
436 pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
437 return 0;
438}
439
440static void cw1200_free_common(struct ieee80211_hw *dev)
441{
442 ieee80211_free_hw(dev);
443}
444
445static void cw1200_unregister_common(struct ieee80211_hw *dev)
446{
447 struct cw1200_common *priv = dev->priv;
448 int i;
449
Solomon Peachy19db5772013-06-11 09:49:39 -0400450 ieee80211_unregister_hw(dev);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400451
452 del_timer_sync(&priv->mcast_timeout);
453 cw1200_unregister_bh(priv);
454
455 cw1200_debug_release(priv);
456
457 mutex_destroy(&priv->conf_mutex);
458
459 wsm_buf_deinit(&priv->wsm_cmd_buf);
460
461 destroy_workqueue(priv->workqueue);
462 priv->workqueue = NULL;
463
464 if (priv->sdd) {
465 release_firmware(priv->sdd);
466 priv->sdd = NULL;
467 }
468
469 for (i = 0; i < 4; ++i)
470 cw1200_queue_deinit(&priv->tx_queue[i]);
471
472 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400473#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400474 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400475#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400476}
477
478/* Clock is in KHz */
479u32 cw1200_dpll_from_clk(u16 clk_khz)
480{
481 switch (clk_khz) {
482 case 0x32C8: /* 13000 KHz */
483 return 0x1D89D241;
484 case 0x3E80: /* 16000 KHz */
485 return 0x000001E1;
486 case 0x41A0: /* 16800 KHz */
487 return 0x124931C1;
488 case 0x4B00: /* 19200 KHz */
489 return 0x00000191;
490 case 0x5DC0: /* 24000 KHz */
491 return 0x00000141;
492 case 0x6590: /* 26000 KHz */
493 return 0x0EC4F121;
494 case 0x8340: /* 33600 KHz */
495 return 0x092490E1;
496 case 0x9600: /* 38400 KHz */
497 return 0x100010C1;
498 case 0x9C40: /* 40000 KHz */
499 return 0x000000C1;
500 case 0xBB80: /* 48000 KHz */
501 return 0x000000A1;
502 case 0xCB20: /* 52000 KHz */
503 return 0x07627091;
504 default:
505 pr_err("Unknown Refclk freq (0x%04x), using 2600KHz\n",
506 clk_khz);
507 return 0x0EC4F121;
508 }
509}
510
Solomon Peachy911373c2013-06-01 08:08:42 -0400511int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
512 struct hwbus_priv *hwbus,
Solomon Peachya910e4a2013-05-24 20:04:38 -0400513 struct device *pdev,
514 struct cw1200_common **core,
515 int ref_clk, const u8 *macaddr,
516 const char *sdd_path, bool have_5ghz)
517{
518 int err = -EINVAL;
519 struct ieee80211_hw *dev;
520 struct cw1200_common *priv;
521 struct wsm_operational_mode mode = {
522 .power_mode = cw1200_power_mode,
523 .disable_more_flag_usage = true,
524 };
525
526 dev = cw1200_init_common(macaddr, have_5ghz);
527 if (!dev)
528 goto err;
529
530 priv = dev->priv;
531 priv->hw_refclk = ref_clk;
532 if (cw1200_refclk)
533 priv->hw_refclk = cw1200_refclk;
534
535 priv->sdd_path = (char *)sdd_path;
536 if (cw1200_sdd_path)
537 priv->sdd_path = cw1200_sdd_path;
538
Solomon Peachy911373c2013-06-01 08:08:42 -0400539 priv->hwbus_ops = hwbus_ops;
540 priv->hwbus_priv = hwbus;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400541 priv->pdev = pdev;
542 SET_IEEE80211_DEV(priv->hw, pdev);
543
544 /* Pass struct cw1200_common back up */
545 *core = priv;
546
547 err = cw1200_register_bh(priv);
548 if (err)
549 goto err1;
550
Solomon Peachya910e4a2013-05-24 20:04:38 -0400551 err = cw1200_load_firmware(priv);
552 if (err)
553 goto err2;
554
555 if (wait_event_interruptible_timeout(priv->wsm_startup_done,
556 priv->firmware_ready,
557 3*HZ) <= 0) {
558 /* TODO: Need to find how to reset device
559 in QUEUE mode properly.
560 */
561 pr_err("Timeout waiting on device startup\n");
562 err = -ETIMEDOUT;
563 goto err2;
564 }
565
566 /* Set low-power mode. */
567 wsm_set_operational_mode(priv, &mode);
568
569 /* Enable multi-TX confirmation */
570 wsm_use_multi_tx_conf(priv, true);
571
Solomon Peachya910e4a2013-05-24 20:04:38 -0400572 err = cw1200_register_common(dev);
573 if (err)
574 goto err2;
575
576 return err;
577
578err2:
579 cw1200_unregister_bh(priv);
580err1:
581 cw1200_free_common(dev);
582err:
583 *core = NULL;
584 return err;
585}
586EXPORT_SYMBOL_GPL(cw1200_core_probe);
587
588void cw1200_core_release(struct cw1200_common *self)
589{
590 /* Disable device interrupts */
Solomon Peachy911373c2013-06-01 08:08:42 -0400591 self->hwbus_ops->lock(self->hwbus_priv);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400592 __cw1200_irq_enable(self, 0);
Solomon Peachy911373c2013-06-01 08:08:42 -0400593 self->hwbus_ops->unlock(self->hwbus_priv);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400594
595 /* And then clean up */
596 cw1200_unregister_common(self->hw);
597 cw1200_free_common(self->hw);
598 return;
599}
600EXPORT_SYMBOL_GPL(cw1200_core_release);