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