blob: c1608f0bf6d017d9fc5be100dfd5a25ce3054599 [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};
Joe Perches2ef00c52018-03-23 15:54:37 -070049module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, 0444);
Solomon Peachya910e4a2013-05-24 20:04:38 -040050MODULE_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) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200105 .band = NL80211_BAND_2GHZ, \
Solomon Peachya910e4a2013-05-24 20:04:38 -0400106 .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) { \
Johannes Berg57fbcce2016-04-12 15:56:15 +0200114 .band = NL80211_BAND_5GHZ, \
Solomon Peachya910e4a2013-05-24 20:04:38 -0400115 .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
Johannes Berg30686bf2015-06-02 21:39:54 +0200281 ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
282 ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
283 ieee80211_hw_set(hw, AMPDU_AGGREGATION);
284 ieee80211_hw_set(hw, CONNECTION_MONITOR);
285 ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
286 ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
287 ieee80211_hw_set(hw, SIGNAL_DBM);
288 ieee80211_hw_set(hw, SUPPORTS_PS);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400289
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
Johannes Berg51217ce2013-06-04 12:56:01 +0200298 hw->wiphy->wowlan = &cw1200_wowlan_support;
Solomon Peachy4e17b872013-05-29 22:22:05 -0400299#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400300
301 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
302
Solomon Peachya910e4a2013-05-24 20:04:38 -0400303 hw->queues = 4;
304
305 priv->rts_threshold = -1;
306
307 hw->max_rates = 8;
308 hw->max_rate_tries = 15;
309 hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM +
310 8; /* TKIP IV */
311
312 hw->sta_data_size = sizeof(struct cw1200_sta_priv);
313
Johannes Berg57fbcce2016-04-12 15:56:15 +0200314 hw->wiphy->bands[NL80211_BAND_2GHZ] = &cw1200_band_2ghz;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400315 if (have_5ghz)
Johannes Berg57fbcce2016-04-12 15:56:15 +0200316 hw->wiphy->bands[NL80211_BAND_5GHZ] = &cw1200_band_5ghz;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400317
318 /* Channel params have to be cleared before registering wiphy again */
Johannes Berg57fbcce2016-04-12 15:56:15 +0200319 for (band = 0; band < NUM_NL80211_BANDS; band++) {
Solomon Peachya910e4a2013-05-24 20:04:38 -0400320 struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
321 if (!sband)
322 continue;
323 for (i = 0; i < sband->n_channels; i++) {
324 sband->channels[i].flags = 0;
325 sband->channels[i].max_antenna_gain = 0;
326 sband->channels[i].max_power = 30;
327 }
328 }
329
330 hw->wiphy->max_scan_ssids = 2;
331 hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
332
333 if (macaddr)
334 SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr);
335 else
336 SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template);
337
338 /* Fix up mac address if necessary */
339 if (hw->wiphy->perm_addr[3] == 0 &&
340 hw->wiphy->perm_addr[4] == 0 &&
341 hw->wiphy->perm_addr[5] == 0) {
342 get_random_bytes(&hw->wiphy->perm_addr[3], 3);
343 }
344
345 mutex_init(&priv->wsm_cmd_mux);
346 mutex_init(&priv->conf_mutex);
347 priv->workqueue = create_singlethread_workqueue("cw1200_wq");
Kangjie Lu0ed2a002019-03-12 03:05:02 -0500348 if (!priv->workqueue) {
349 ieee80211_free_hw(hw);
350 return NULL;
351 }
352
Solomon Peachya910e4a2013-05-24 20:04:38 -0400353 sema_init(&priv->scan.lock, 1);
354 INIT_WORK(&priv->scan.work, cw1200_scan_work);
355 INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work);
356 INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout);
357 INIT_DELAYED_WORK(&priv->clear_recent_scan_work,
358 cw1200_clear_recent_scan_work);
359 INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout);
360 INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work);
361 INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work);
362 INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work);
363 INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work);
364 spin_lock_init(&priv->event_queue_lock);
365 INIT_LIST_HEAD(&priv->event_queue);
366 INIT_WORK(&priv->event_handler, cw1200_event_handler);
367 INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work);
368 INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work);
369 spin_lock_init(&priv->bss_loss_lock);
370 spin_lock_init(&priv->ps_state_lock);
371 INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work);
372 INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work);
373 INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work);
374 INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work);
375 INIT_WORK(&priv->link_id_work, cw1200_link_id_work);
376 INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work);
377 INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset);
378 INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
379 INIT_WORK(&priv->set_beacon_wakeup_period_work,
380 cw1200_set_beacon_wakeup_period_work);
Kees Cooke3dcf8b2017-10-24 02:29:00 -0700381 timer_setup(&priv->mcast_timeout, cw1200_mcast_timeout, 0);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400382
383 if (cw1200_queue_stats_init(&priv->tx_queue_stats,
384 CW1200_LINK_ID_MAX,
385 cw1200_skb_dtor,
386 priv)) {
387 ieee80211_free_hw(hw);
388 return NULL;
389 }
390
391 for (i = 0; i < 4; ++i) {
392 if (cw1200_queue_init(&priv->tx_queue[i],
393 &priv->tx_queue_stats, i, 16,
394 cw1200_ttl[i])) {
395 for (; i > 0; i--)
396 cw1200_queue_deinit(&priv->tx_queue[i - 1]);
397 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
398 ieee80211_free_hw(hw);
399 return NULL;
400 }
401 }
402
403 init_waitqueue_head(&priv->channel_switch_done);
404 init_waitqueue_head(&priv->wsm_cmd_wq);
405 init_waitqueue_head(&priv->wsm_startup_done);
406 init_waitqueue_head(&priv->ps_mode_switch_done);
407 wsm_buf_init(&priv->wsm_cmd_buf);
408 spin_lock_init(&priv->wsm_cmd.lock);
409 priv->wsm_cmd.done = 1;
410 tx_policy_init(priv);
411
412 return hw;
413}
414
415static int cw1200_register_common(struct ieee80211_hw *dev)
416{
417 struct cw1200_common *priv = dev->priv;
418 int err;
419
Solomon Peachy4e17b872013-05-29 22:22:05 -0400420#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400421 err = cw1200_pm_init(&priv->pm_state, priv);
422 if (err) {
423 pr_err("Cannot init PM. (%d).\n",
424 err);
425 return err;
426 }
Solomon Peachy4e17b872013-05-29 22:22:05 -0400427#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400428
429 err = ieee80211_register_hw(dev);
430 if (err) {
431 pr_err("Cannot register device (%d).\n",
432 err);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400433#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400434 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400435#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400436 return err;
437 }
438
Solomon Peachya910e4a2013-05-24 20:04:38 -0400439 cw1200_debug_init(priv);
440
441 pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
442 return 0;
443}
444
445static void cw1200_free_common(struct ieee80211_hw *dev)
446{
447 ieee80211_free_hw(dev);
448}
449
450static void cw1200_unregister_common(struct ieee80211_hw *dev)
451{
452 struct cw1200_common *priv = dev->priv;
453 int i;
454
Solomon Peachy19db5772013-06-11 09:49:39 -0400455 ieee80211_unregister_hw(dev);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400456
457 del_timer_sync(&priv->mcast_timeout);
458 cw1200_unregister_bh(priv);
459
460 cw1200_debug_release(priv);
461
462 mutex_destroy(&priv->conf_mutex);
463
464 wsm_buf_deinit(&priv->wsm_cmd_buf);
465
466 destroy_workqueue(priv->workqueue);
467 priv->workqueue = NULL;
468
469 if (priv->sdd) {
470 release_firmware(priv->sdd);
471 priv->sdd = NULL;
472 }
473
474 for (i = 0; i < 4; ++i)
475 cw1200_queue_deinit(&priv->tx_queue[i]);
476
477 cw1200_queue_stats_deinit(&priv->tx_queue_stats);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400478#ifdef CONFIG_PM
Solomon Peachya910e4a2013-05-24 20:04:38 -0400479 cw1200_pm_deinit(&priv->pm_state);
Solomon Peachy4e17b872013-05-29 22:22:05 -0400480#endif
Solomon Peachya910e4a2013-05-24 20:04:38 -0400481}
482
483/* Clock is in KHz */
484u32 cw1200_dpll_from_clk(u16 clk_khz)
485{
486 switch (clk_khz) {
487 case 0x32C8: /* 13000 KHz */
488 return 0x1D89D241;
489 case 0x3E80: /* 16000 KHz */
490 return 0x000001E1;
491 case 0x41A0: /* 16800 KHz */
492 return 0x124931C1;
493 case 0x4B00: /* 19200 KHz */
494 return 0x00000191;
495 case 0x5DC0: /* 24000 KHz */
496 return 0x00000141;
497 case 0x6590: /* 26000 KHz */
498 return 0x0EC4F121;
499 case 0x8340: /* 33600 KHz */
500 return 0x092490E1;
501 case 0x9600: /* 38400 KHz */
502 return 0x100010C1;
503 case 0x9C40: /* 40000 KHz */
504 return 0x000000C1;
505 case 0xBB80: /* 48000 KHz */
506 return 0x000000A1;
507 case 0xCB20: /* 52000 KHz */
508 return 0x07627091;
509 default:
Solomon Peachy7f190232013-08-27 20:17:12 -0400510 pr_err("Unknown Refclk freq (0x%04x), using 26000KHz\n",
Solomon Peachya910e4a2013-05-24 20:04:38 -0400511 clk_khz);
512 return 0x0EC4F121;
513 }
514}
515
Solomon Peachy911373c2013-06-01 08:08:42 -0400516int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
517 struct hwbus_priv *hwbus,
Solomon Peachya910e4a2013-05-24 20:04:38 -0400518 struct device *pdev,
519 struct cw1200_common **core,
520 int ref_clk, const u8 *macaddr,
521 const char *sdd_path, bool have_5ghz)
522{
523 int err = -EINVAL;
524 struct ieee80211_hw *dev;
525 struct cw1200_common *priv;
526 struct wsm_operational_mode mode = {
527 .power_mode = cw1200_power_mode,
528 .disable_more_flag_usage = true,
529 };
530
531 dev = cw1200_init_common(macaddr, have_5ghz);
532 if (!dev)
533 goto err;
534
535 priv = dev->priv;
536 priv->hw_refclk = ref_clk;
537 if (cw1200_refclk)
538 priv->hw_refclk = cw1200_refclk;
539
540 priv->sdd_path = (char *)sdd_path;
541 if (cw1200_sdd_path)
542 priv->sdd_path = cw1200_sdd_path;
543
Solomon Peachy911373c2013-06-01 08:08:42 -0400544 priv->hwbus_ops = hwbus_ops;
545 priv->hwbus_priv = hwbus;
Solomon Peachya910e4a2013-05-24 20:04:38 -0400546 priv->pdev = pdev;
547 SET_IEEE80211_DEV(priv->hw, pdev);
548
549 /* Pass struct cw1200_common back up */
550 *core = priv;
551
552 err = cw1200_register_bh(priv);
553 if (err)
554 goto err1;
555
Solomon Peachya910e4a2013-05-24 20:04:38 -0400556 err = cw1200_load_firmware(priv);
557 if (err)
558 goto err2;
559
560 if (wait_event_interruptible_timeout(priv->wsm_startup_done,
561 priv->firmware_ready,
562 3*HZ) <= 0) {
563 /* TODO: Need to find how to reset device
564 in QUEUE mode properly.
565 */
566 pr_err("Timeout waiting on device startup\n");
567 err = -ETIMEDOUT;
568 goto err2;
569 }
570
571 /* Set low-power mode. */
572 wsm_set_operational_mode(priv, &mode);
573
574 /* Enable multi-TX confirmation */
575 wsm_use_multi_tx_conf(priv, true);
576
Solomon Peachya910e4a2013-05-24 20:04:38 -0400577 err = cw1200_register_common(dev);
578 if (err)
579 goto err2;
580
581 return err;
582
583err2:
584 cw1200_unregister_bh(priv);
585err1:
586 cw1200_free_common(dev);
587err:
588 *core = NULL;
589 return err;
590}
591EXPORT_SYMBOL_GPL(cw1200_core_probe);
592
593void cw1200_core_release(struct cw1200_common *self)
594{
595 /* Disable device interrupts */
Solomon Peachy911373c2013-06-01 08:08:42 -0400596 self->hwbus_ops->lock(self->hwbus_priv);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400597 __cw1200_irq_enable(self, 0);
Solomon Peachy911373c2013-06-01 08:08:42 -0400598 self->hwbus_ops->unlock(self->hwbus_priv);
Solomon Peachya910e4a2013-05-24 20:04:38 -0400599
600 /* And then clean up */
601 cw1200_unregister_common(self->hw);
602 cw1200_free_common(self->hw);
603 return;
604}
605EXPORT_SYMBOL_GPL(cw1200_core_release);