htc_drv_init.c revision 8ae2e12f1534e647d4a816755e5a09c2de6f9fca
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
25b68138e5659cbfd5df2879d17f9ba0b66477fecSujith Manoharan * Copyright (c) 2010-2011 Atheros Communications Inc.
3fb9987d0f748c983bb795a86f47522313f701a08Sujith *
4fb9987d0f748c983bb795a86f47522313f701a08Sujith * Permission to use, copy, modify, and/or distribute this software for any
5fb9987d0f748c983bb795a86f47522313f701a08Sujith * purpose with or without fee is hereby granted, provided that the above
6fb9987d0f748c983bb795a86f47522313f701a08Sujith * copyright notice and this permission notice appear in all copies.
7fb9987d0f748c983bb795a86f47522313f701a08Sujith *
8fb9987d0f748c983bb795a86f47522313f701a08Sujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9fb9987d0f748c983bb795a86f47522313f701a08Sujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10fb9987d0f748c983bb795a86f47522313f701a08Sujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11fb9987d0f748c983bb795a86f47522313f701a08Sujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12fb9987d0f748c983bb795a86f47522313f701a08Sujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13fb9987d0f748c983bb795a86f47522313f701a08Sujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14fb9987d0f748c983bb795a86f47522313f701a08Sujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15fb9987d0f748c983bb795a86f47522313f701a08Sujith */
16fb9987d0f748c983bb795a86f47522313f701a08Sujith
17fb9987d0f748c983bb795a86f47522313f701a08Sujith#include "htc.h"
18fb9987d0f748c983bb795a86f47522313f701a08Sujith
19fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_AUTHOR("Atheros Communications");
20fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_LICENSE("Dual BSD/GPL");
21fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices");
22fb9987d0f748c983bb795a86f47522313f701a08Sujith
23fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic unsigned int ath9k_debug = ATH_DBG_DEFAULT;
24fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_param_named(debug, ath9k_debug, uint, 0);
25fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_PARM_DESC(debug, "Debugging mask");
26fb9987d0f748c983bb795a86f47522313f701a08Sujith
27e1572c5eeca8ef87a250322364584458b2dadb35Sujithint htc_modparam_nohwcrypt;
28e1572c5eeca8ef87a250322364584458b2dadb35Sujithmodule_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444);
29fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
30fb9987d0f748c983bb795a86f47522313f701a08Sujith
31fb9987d0f748c983bb795a86f47522313f701a08Sujith#define CHAN2G(_freq, _idx)  { \
32fb9987d0f748c983bb795a86f47522313f701a08Sujith	.center_freq = (_freq), \
33fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value = (_idx), \
34fb9987d0f748c983bb795a86f47522313f701a08Sujith	.max_power = 20, \
35fb9987d0f748c983bb795a86f47522313f701a08Sujith}
36fb9987d0f748c983bb795a86f47522313f701a08Sujith
37ea46e644e80bd4ac778964afd998df4f666486d4Sujith#define CHAN5G(_freq, _idx) { \
38ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.band = IEEE80211_BAND_5GHZ, \
39ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.center_freq = (_freq), \
40ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.hw_value = (_idx), \
41ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.max_power = 20, \
42ea46e644e80bd4ac778964afd998df4f666486d4Sujith}
43ea46e644e80bd4ac778964afd998df4f666486d4Sujith
4421cb987914cb5334af78378141efed77505ea987Vivek Natarajan#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
4521cb987914cb5334af78378141efed77505ea987Vivek Natarajan
46fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_channel ath9k_2ghz_channels[] = {
47fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2412, 0), /* Channel 1 */
48fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2417, 1), /* Channel 2 */
49fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2422, 2), /* Channel 3 */
50fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2427, 3), /* Channel 4 */
51fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2432, 4), /* Channel 5 */
52fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2437, 5), /* Channel 6 */
53fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2442, 6), /* Channel 7 */
54fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2447, 7), /* Channel 8 */
55fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2452, 8), /* Channel 9 */
56fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2457, 9), /* Channel 10 */
57fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2462, 10), /* Channel 11 */
58fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2467, 11), /* Channel 12 */
59fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2472, 12), /* Channel 13 */
60fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2484, 13), /* Channel 14 */
61fb9987d0f748c983bb795a86f47522313f701a08Sujith};
62fb9987d0f748c983bb795a86f47522313f701a08Sujith
63ea46e644e80bd4ac778964afd998df4f666486d4Sujithstatic struct ieee80211_channel ath9k_5ghz_channels[] = {
64ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 1 */
65ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5180, 14), /* Channel 36 */
66ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5200, 15), /* Channel 40 */
67ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5220, 16), /* Channel 44 */
68ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5240, 17), /* Channel 48 */
69ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 2 */
70ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5260, 18), /* Channel 52 */
71ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5280, 19), /* Channel 56 */
72ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5300, 20), /* Channel 60 */
73ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5320, 21), /* Channel 64 */
74ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this "Middle band" */
75ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5500, 22), /* Channel 100 */
76ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5520, 23), /* Channel 104 */
77ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5540, 24), /* Channel 108 */
78ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5560, 25), /* Channel 112 */
79ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5580, 26), /* Channel 116 */
80ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5600, 27), /* Channel 120 */
81ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5620, 28), /* Channel 124 */
82ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5640, 29), /* Channel 128 */
83ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5660, 30), /* Channel 132 */
84ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5680, 31), /* Channel 136 */
85ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5700, 32), /* Channel 140 */
86ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 3 */
87ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5745, 33), /* Channel 149 */
88ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5765, 34), /* Channel 153 */
89ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5785, 35), /* Channel 157 */
90ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5805, 36), /* Channel 161 */
91ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5825, 37), /* Channel 165 */
92ea46e644e80bd4ac778964afd998df4f666486d4Sujith};
93ea46e644e80bd4ac778964afd998df4f666486d4Sujith
94fb9987d0f748c983bb795a86f47522313f701a08Sujith/* Atheros hardware rate code addition for short premble */
95fb9987d0f748c983bb795a86f47522313f701a08Sujith#define SHPCHECK(__hw_rate, __flags) \
96fb9987d0f748c983bb795a86f47522313f701a08Sujith	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
97fb9987d0f748c983bb795a86f47522313f701a08Sujith
98fb9987d0f748c983bb795a86f47522313f701a08Sujith#define RATE(_bitrate, _hw_rate, _flags) {		\
99fb9987d0f748c983bb795a86f47522313f701a08Sujith	.bitrate	= (_bitrate),			\
100fb9987d0f748c983bb795a86f47522313f701a08Sujith	.flags		= (_flags),			\
101fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value	= (_hw_rate),			\
102fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value_short = (SHPCHECK(_hw_rate, _flags))	\
103fb9987d0f748c983bb795a86f47522313f701a08Sujith}
104fb9987d0f748c983bb795a86f47522313f701a08Sujith
105fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_rate ath9k_legacy_rates[] = {
106fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(10, 0x1b, 0),
107fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */
108fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
109fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
110fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(60, 0x0b, 0),
111fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(90, 0x0f, 0),
112fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(120, 0x0a, 0),
113fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(180, 0x0e, 0),
114fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(240, 0x09, 0),
115fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(360, 0x0d, 0),
116fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(480, 0x08, 0),
117fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(540, 0x0c, 0),
118fb9987d0f748c983bb795a86f47522313f701a08Sujith};
119fb9987d0f748c983bb795a86f47522313f701a08Sujith
120d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#ifdef CONFIG_MAC80211_LEDS
121d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharanstatic const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
122d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 0 * 1024, .blink_time = 334 },
123d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 1 * 1024, .blink_time = 260 },
124d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 5 * 1024, .blink_time = 220 },
125d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 10 * 1024, .blink_time = 190 },
126d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 20 * 1024, .blink_time = 170 },
127d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 50 * 1024, .blink_time = 150 },
128d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 70 * 1024, .blink_time = 130 },
129d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 100 * 1024, .blink_time = 110 },
130d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 200 * 1024, .blink_time = 80 },
131d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 300 * 1024, .blink_time = 50 },
132d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan};
133d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#endif
134d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan
135fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
136fb9987d0f748c983bb795a86f47522313f701a08Sujith{
137fb9987d0f748c983bb795a86f47522313f701a08Sujith	int time_left;
138fb9987d0f748c983bb795a86f47522313f701a08Sujith
139d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	if (atomic_read(&priv->htc->tgt_ready) > 0) {
140d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com		atomic_dec(&priv->htc->tgt_ready);
141d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com		return 0;
142d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	}
143d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com
144fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Firmware can take up to 50ms to get ready, to be safe use 1 second */
145fb9987d0f748c983bb795a86f47522313f701a08Sujith	time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ);
146fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!time_left) {
147fb9987d0f748c983bb795a86f47522313f701a08Sujith		dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n");
148fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ETIMEDOUT;
149fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
150fb9987d0f748c983bb795a86f47522313f701a08Sujith
151d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	atomic_dec(&priv->htc->tgt_ready);
152d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com
153fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
154fb9987d0f748c983bb795a86f47522313f701a08Sujith}
155fb9987d0f748c983bb795a86f47522313f701a08Sujith
156fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
157fb9987d0f748c983bb795a86f47522313f701a08Sujith{
158fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_deinit(priv->ah);
159fb9987d0f748c983bb795a86f47522313f701a08Sujith	kfree(priv->ah);
160fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = NULL;
161fb9987d0f748c983bb795a86f47522313f701a08Sujith}
162fb9987d0f748c983bb795a86f47522313f701a08Sujith
163fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_device(struct ath9k_htc_priv *priv)
164fb9987d0f748c983bb795a86f47522313f701a08Sujith{
165fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
166fb9987d0f748c983bb795a86f47522313f701a08Sujith
167fb9987d0f748c983bb795a86f47522313f701a08Sujith	wiphy_rfkill_stop_polling(hw->wiphy);
168fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_leds(priv);
169fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_unregister_hw(hw);
170fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
171fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_tx_cleanup(priv);
172fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_priv(priv);
173fb9987d0f748c983bb795a86f47522313f701a08Sujith}
174fb9987d0f748c983bb795a86f47522313f701a08Sujith
175fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
176fb9987d0f748c983bb795a86f47522313f701a08Sujith					u16 service_id,
177fb9987d0f748c983bb795a86f47522313f701a08Sujith					void (*tx) (void *,
178fb9987d0f748c983bb795a86f47522313f701a08Sujith						    struct sk_buff *,
179fb9987d0f748c983bb795a86f47522313f701a08Sujith						    enum htc_endpoint_id,
180fb9987d0f748c983bb795a86f47522313f701a08Sujith						    bool txok),
181fb9987d0f748c983bb795a86f47522313f701a08Sujith					enum htc_endpoint_id *ep_id)
182fb9987d0f748c983bb795a86f47522313f701a08Sujith{
183fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct htc_service_connreq req;
184fb9987d0f748c983bb795a86f47522313f701a08Sujith
185fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&req, 0, sizeof(struct htc_service_connreq));
186fb9987d0f748c983bb795a86f47522313f701a08Sujith
187fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.service_id = service_id;
188fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.priv = priv;
189fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.rx = ath9k_htc_rxep;
190fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.tx = tx;
191fb9987d0f748c983bb795a86f47522313f701a08Sujith
192fb9987d0f748c983bb795a86f47522313f701a08Sujith	return htc_connect_service(priv->htc, &req, ep_id);
193fb9987d0f748c983bb795a86f47522313f701a08Sujith}
194fb9987d0f748c983bb795a86f47522313f701a08Sujith
195fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharanstatic int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
196fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan				   u32 drv_info)
197fb9987d0f748c983bb795a86f47522313f701a08Sujith{
198fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
199fb9987d0f748c983bb795a86f47522313f701a08Sujith
200fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* WMI CMD*/
201fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep);
202fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
203fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
204fb9987d0f748c983bb795a86f47522313f701a08Sujith
205fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Beacon */
2069c6dda4e2dfea970a7105e3805f0195bc3079f2fSujith	ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep,
207fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->beacon_ep);
208fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
209fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
210fb9987d0f748c983bb795a86f47522313f701a08Sujith
211fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* CAB */
212fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep,
213fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->cab_ep);
214fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
215fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
216fb9987d0f748c983bb795a86f47522313f701a08Sujith
217fb9987d0f748c983bb795a86f47522313f701a08Sujith
218fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* UAPSD */
219fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep,
220fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->uapsd_ep);
221fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
222fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
223fb9987d0f748c983bb795a86f47522313f701a08Sujith
224fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* MGMT */
225fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep,
226fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->mgmt_ep);
227fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
228fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
229fb9987d0f748c983bb795a86f47522313f701a08Sujith
230fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA BE */
231fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep,
232fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_be_ep);
233fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
234fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
235fb9987d0f748c983bb795a86f47522313f701a08Sujith
236fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA BK */
237fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep,
238fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_bk_ep);
239fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
240fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
241fb9987d0f748c983bb795a86f47522313f701a08Sujith
242fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA VI */
243fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep,
244fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_vi_ep);
245fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
246fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
247fb9987d0f748c983bb795a86f47522313f701a08Sujith
248fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA VO */
249fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep,
250fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_vo_ep);
251fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
252fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
253fb9987d0f748c983bb795a86f47522313f701a08Sujith
2546267dc709c6ef1c0926e18ff2859238992dea658Sujith	/*
2556267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * Setup required credits before initializing HTC.
2566267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * This is a bit hacky, but, since queuing is done in
2576267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * the HIF layer, shouldn't matter much.
2586267dc709c6ef1c0926e18ff2859238992dea658Sujith	 */
2596267dc709c6ef1c0926e18ff2859238992dea658Sujith
2600b5ead91cda63e0db964dadc77601233434f60cbSujith Manoharan	if (IS_AR7010_DEVICE(drv_info))
261d108e8b9320b77e3fa165757fd40f298bdd89d1cSujith Manoharan		priv->htc->credits = 45;
262fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	else
2634e63f768c3b85ae2b3ea6251231fd5cc46ec598dSujith		priv->htc->credits = 33;
2646267dc709c6ef1c0926e18ff2859238992dea658Sujith
265fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = htc_init(priv->htc);
266fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
267fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
268fb9987d0f748c983bb795a86f47522313f701a08Sujith
2696267dc709c6ef1c0926e18ff2859238992dea658Sujith	dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n",
2706267dc709c6ef1c0926e18ff2859238992dea658Sujith		 priv->htc->credits);
2716267dc709c6ef1c0926e18ff2859238992dea658Sujith
272fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
273fb9987d0f748c983bb795a86f47522313f701a08Sujith
274fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
275fb9987d0f748c983bb795a86f47522313f701a08Sujith	dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n");
276fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
277fb9987d0f748c983bb795a86f47522313f701a08Sujith}
278fb9987d0f748c983bb795a86f47522313f701a08Sujith
279fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_reg_notifier(struct wiphy *wiphy,
280fb9987d0f748c983bb795a86f47522313f701a08Sujith			      struct regulatory_request *request)
281fb9987d0f748c983bb795a86f47522313f701a08Sujith{
282fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
283fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = hw->priv;
284fb9987d0f748c983bb795a86f47522313f701a08Sujith
285fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ath_reg_notifier_apply(wiphy, request,
286fb9987d0f748c983bb795a86f47522313f701a08Sujith				      ath9k_hw_regulatory(priv->ah));
287fb9987d0f748c983bb795a86f47522313f701a08Sujith}
288fb9987d0f748c983bb795a86f47522313f701a08Sujith
2894a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
290fb9987d0f748c983bb795a86f47522313f701a08Sujith{
291fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
292fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
293fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
294fb9987d0f748c983bb795a86f47522313f701a08Sujith	__be32 val, reg = cpu_to_be32(reg_offset);
295fb9987d0f748c983bb795a86f47522313f701a08Sujith	int r;
296fb9987d0f748c983bb795a86f47522313f701a08Sujith
297fb9987d0f748c983bb795a86f47522313f701a08Sujith	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
298fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &reg, sizeof(reg),
299fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &val, sizeof(val),
300fb9987d0f748c983bb795a86f47522313f701a08Sujith			  100);
301fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (unlikely(r)) {
302226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		ath_dbg(common, ATH_DBG_WMI,
303226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"REGISTER READ FAILED: (0x%04x, %d)\n",
304226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			reg_offset, r);
305fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -EIO;
306fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
307fb9987d0f748c983bb795a86f47522313f701a08Sujith
308fb9987d0f748c983bb795a86f47522313f701a08Sujith	return be32_to_cpu(val);
309fb9987d0f748c983bb795a86f47522313f701a08Sujith}
310fb9987d0f748c983bb795a86f47522313f701a08Sujith
31109a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharanstatic void ath9k_multi_regread(void *hw_priv, u32 *addr,
31209a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan				u32 *val, u16 count)
31309a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan{
31409a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	struct ath_hw *ah = (struct ath_hw *) hw_priv;
31509a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	struct ath_common *common = ath9k_hw_common(ah);
31609a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
31709a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	__be32 tmpaddr[8];
31809a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	__be32 tmpval[8];
31909a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	int i, ret;
32009a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
32109a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       for (i = 0; i < count; i++) {
32209a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	       tmpaddr[i] = cpu_to_be32(addr[i]);
32309a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       }
32409a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
32509a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
32609a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			   (u8 *)tmpaddr , sizeof(u32) * count,
32709a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			   (u8 *)tmpval, sizeof(u32) * count,
32809a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			   100);
32909a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	if (unlikely(ret)) {
33009a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan		ath_dbg(common, ATH_DBG_WMI,
33109a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			"Multiple REGISTER READ FAILED (count: %d)\n", count);
33209a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	}
33309a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
33409a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       for (i = 0; i < count; i++) {
33509a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	       val[i] = be32_to_cpu(tmpval[i]);
33609a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       }
33709a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan}
33809a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
3394a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
340fb9987d0f748c983bb795a86f47522313f701a08Sujith{
341fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
342fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
343fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
34407b2fa5a2368accf0fe6cb16e7eca6d1150554edJoe Perches	const __be32 buf[2] = {
345fb9987d0f748c983bb795a86f47522313f701a08Sujith		cpu_to_be32(reg_offset),
346fb9987d0f748c983bb795a86f47522313f701a08Sujith		cpu_to_be32(val),
347fb9987d0f748c983bb795a86f47522313f701a08Sujith	};
348fb9987d0f748c983bb795a86f47522313f701a08Sujith	int r;
349fb9987d0f748c983bb795a86f47522313f701a08Sujith
350fb9987d0f748c983bb795a86f47522313f701a08Sujith	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
351fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &buf, sizeof(buf),
352fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &val, sizeof(val),
353fb9987d0f748c983bb795a86f47522313f701a08Sujith			  100);
354fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (unlikely(r)) {
355226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		ath_dbg(common, ATH_DBG_WMI,
356226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"REGISTER WRITE FAILED:(0x%04x, %d)\n",
357226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			reg_offset, r);
358fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
359fb9987d0f748c983bb795a86f47522313f701a08Sujith}
360fb9987d0f748c983bb795a86f47522313f701a08Sujith
3614a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
3624a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3634a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3644a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3654a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3664a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	u32 rsp_status;
3674a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	int r;
3684a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3694a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_lock(&priv->wmi->multi_write_mutex);
3704a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3714a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	/* Store the register/value */
3724a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
3734a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		cpu_to_be32(reg_offset);
3744a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
3754a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		cpu_to_be32(val);
3764a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3774a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write_idx++;
3784a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3794a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	/* If the buffer is full, send it out. */
3804a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
3814a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
3824a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &priv->wmi->multi_write,
3834a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
3844a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &rsp_status, sizeof(rsp_status),
3854a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  100);
3864a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		if (unlikely(r)) {
387226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			ath_dbg(common, ATH_DBG_WMI,
388226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"REGISTER WRITE FAILED, multi len: %d\n",
389226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				priv->wmi->multi_write_idx);
3904a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		}
3914a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		priv->wmi->multi_write_idx = 0;
3924a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	}
3934a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3944a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_unlock(&priv->wmi->multi_write_mutex);
3954a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
3964a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3974a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
3984a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3994a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4004a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
4014a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4024a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4034a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (atomic_read(&priv->wmi->mwrite_cnt))
4044a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		ath9k_regwrite_buffer(hw_priv, val, reg_offset);
4054a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	else
4064a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		ath9k_regwrite_single(hw_priv, val, reg_offset);
4074a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
4084a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4094a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_enable_regwrite_buffer(void *hw_priv)
4104a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
4114a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4124a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
4134a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4144a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4154a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	atomic_inc(&priv->wmi->mwrite_cnt);
4164a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
4174a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4184a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_flush(void *hw_priv)
4194a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
4204a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4214a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
4224a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4234a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	u32 rsp_status;
4244a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	int r;
4254a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
426435c1610f46dc4d86a6633adb037b18109e6ffdcFelix Fietkau	atomic_dec(&priv->wmi->mwrite_cnt);
427435c1610f46dc4d86a6633adb037b18109e6ffdcFelix Fietkau
4284a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_lock(&priv->wmi->multi_write_mutex);
4294a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4304a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (priv->wmi->multi_write_idx) {
4314a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
4324a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &priv->wmi->multi_write,
4334a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
4344a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &rsp_status, sizeof(rsp_status),
4354a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  100);
4364a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		if (unlikely(r)) {
437226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			ath_dbg(common, ATH_DBG_WMI,
438226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"REGISTER WRITE FAILED, multi len: %d\n",
439226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				priv->wmi->multi_write_idx);
4404a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		}
4414a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		priv->wmi->multi_write_idx = 0;
4424a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	}
4434a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4444a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_unlock(&priv->wmi->multi_write_mutex);
4454a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
4464a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
447845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkaustatic u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
448845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau{
449845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	u32 val;
450845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau
451845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	val = ath9k_regread(hw_priv, reg_offset);
452845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	val &= ~clr;
453845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	val |= set;
454845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	ath9k_regwrite(hw_priv, val, reg_offset);
455845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	return val;
456845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau}
457845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau
458fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath_usb_read_cachesize(struct ath_common *common, int *csz)
459fb9987d0f748c983bb795a86f47522313f701a08Sujith{
460fb9987d0f748c983bb795a86f47522313f701a08Sujith	*csz = L1_CACHE_BYTES >> 2;
461fb9987d0f748c983bb795a86f47522313f701a08Sujith}
462fb9987d0f748c983bb795a86f47522313f701a08Sujith
463fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
464fb9987d0f748c983bb795a86f47522313f701a08Sujith{
465fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) common->ah;
466fb9987d0f748c983bb795a86f47522313f701a08Sujith
467fb9987d0f748c983bb795a86f47522313f701a08Sujith	(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
468fb9987d0f748c983bb795a86f47522313f701a08Sujith
469fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath9k_hw_wait(ah,
470fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA,
471fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA_BUSY |
472fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
473fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AH_WAIT_TIMEOUT))
474fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
475fb9987d0f748c983bb795a86f47522313f701a08Sujith
476fb9987d0f748c983bb795a86f47522313f701a08Sujith	*data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
477fb9987d0f748c983bb795a86f47522313f701a08Sujith		   AR_EEPROM_STATUS_DATA_VAL);
478fb9987d0f748c983bb795a86f47522313f701a08Sujith
479fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
480fb9987d0f748c983bb795a86f47522313f701a08Sujith}
481fb9987d0f748c983bb795a86f47522313f701a08Sujith
482fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic const struct ath_bus_ops ath9k_usb_bus_ops = {
483497ad9adf44013dc9054f80c627acc44d4c90d37Sujith	.ath_bus_type = ATH_USB,
484fb9987d0f748c983bb795a86f47522313f701a08Sujith	.read_cachesize = ath_usb_read_cachesize,
485fb9987d0f748c983bb795a86f47522313f701a08Sujith	.eeprom_read = ath_usb_eeprom_read,
486fb9987d0f748c983bb795a86f47522313f701a08Sujith};
487fb9987d0f748c983bb795a86f47522313f701a08Sujith
488fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void setup_ht_cap(struct ath9k_htc_priv *priv,
489fb9987d0f748c983bb795a86f47522313f701a08Sujith			 struct ieee80211_sta_ht_cap *ht_info)
490fb9987d0f748c983bb795a86f47522313f701a08Sujith{
4916debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
4926debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	u8 tx_streams, rx_streams;
4936debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	int i;
4946debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
495fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ht_supported = true;
496fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
497fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_SM_PS |
498fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_SGI_40 |
499fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_DSSSCCK40;
500fb9987d0f748c983bb795a86f47522313f701a08Sujith
501b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
502b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
503b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith
50417525f96aeeed156bd4a6dee21816100f77b0c71Sujith	ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
50517525f96aeeed156bd4a6dee21816100f77b0c71Sujith
506fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
507fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
508fb9987d0f748c983bb795a86f47522313f701a08Sujith
509fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
5106debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
5116debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	/* ath9k_htc supports only 1 or 2 stream devices */
5126debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
5136debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
5146debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
515226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches	ath_dbg(common, ATH_DBG_CONFIG,
516226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		"TX streams %d, RX streams: %d\n",
517226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		tx_streams, rx_streams);
5186debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
5196debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	if (tx_streams != rx_streams) {
5206debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
5216debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.tx_params |= ((tx_streams - 1) <<
5226debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith					   IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
5236debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	}
5246debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
5256debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	for (i = 0; i < rx_streams; i++)
5266debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.rx_mask[i] = 0xff;
5276debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
528fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
529fb9987d0f748c983bb795a86f47522313f701a08Sujith}
530fb9987d0f748c983bb795a86f47522313f701a08Sujith
531fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_init_queues(struct ath9k_htc_priv *priv)
532fb9987d0f748c983bb795a86f47522313f701a08Sujith{
533fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
534fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i;
535fb9987d0f748c983bb795a86f47522313f701a08Sujith
536fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
537fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->hwq_map[i] = -1;
538fb9987d0f748c983bb795a86f47522313f701a08Sujith
539ca74b83b66dbd289a395c6243695d746c76676ccSujith	priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
540ca74b83b66dbd289a395c6243695d746c76676ccSujith	if (priv->beaconq == -1) {
5413800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup BEACON xmit queue\n");
542ca74b83b66dbd289a395c6243695d746c76676ccSujith		goto err;
543ca74b83b66dbd289a395c6243695d746c76676ccSujith	}
544ca74b83b66dbd289a395c6243695d746c76676ccSujith
545ca74b83b66dbd289a395c6243695d746c76676ccSujith	priv->cabq = ath9k_htc_cabq_setup(priv);
546ca74b83b66dbd289a395c6243695d746c76676ccSujith	if (priv->cabq == -1) {
5473800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup CAB xmit queue\n");
548ca74b83b66dbd289a395c6243695d746c76676ccSujith		goto err;
549ca74b83b66dbd289a395c6243695d746c76676ccSujith	}
550ca74b83b66dbd289a395c6243695d746c76676ccSujith
551e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
5523800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for BE traffic\n");
553fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
554fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
555fb9987d0f748c983bb795a86f47522313f701a08Sujith
556e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
5573800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for BK traffic\n");
558fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
559fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
560e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
5613800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for VI traffic\n");
562fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
563fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
564e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
5653800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for VO traffic\n");
566fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
567fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
568fb9987d0f748c983bb795a86f47522313f701a08Sujith
569fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
570fb9987d0f748c983bb795a86f47522313f701a08Sujith
571fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
572fb9987d0f748c983bb795a86f47522313f701a08Sujith	return -EINVAL;
573fb9987d0f748c983bb795a86f47522313f701a08Sujith}
574fb9987d0f748c983bb795a86f47522313f701a08Sujith
575fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_crypto(struct ath9k_htc_priv *priv)
576fb9987d0f748c983bb795a86f47522313f701a08Sujith{
577fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
578fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i = 0;
579fb9987d0f748c983bb795a86f47522313f701a08Sujith
580fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Get the hardware key cache size. */
5816de12a1bcef0145436e815d30a3d48b9fadb199dFelix Fietkau	common->keymax = AR_KEYTABLE_SIZE;
582fb9987d0f748c983bb795a86f47522313f701a08Sujith
583e2b626248b0799bd14be40ce290c6681a8419512Rajkumar Manoharan	if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
584e2b626248b0799bd14be40ce290c6681a8419512Rajkumar Manoharan		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
585e2b626248b0799bd14be40ce290c6681a8419512Rajkumar Manoharan
586fb9987d0f748c983bb795a86f47522313f701a08Sujith	/*
587fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * Reset the key cache since some parts do not
588fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * reset the contents on initial power up.
589fb9987d0f748c983bb795a86f47522313f701a08Sujith	 */
590fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < common->keymax; i++)
591040e539e8e8d5585e1c3d7d15fa7215d3a691258Bruno Randolf		ath_hw_keyreset(common, (u16) i);
592fb9987d0f748c983bb795a86f47522313f701a08Sujith}
593fb9987d0f748c983bb795a86f47522313f701a08Sujith
594fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
595fb9987d0f748c983bb795a86f47522313f701a08Sujith{
596d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
597fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].channels =
598fb9987d0f748c983bb795a86f47522313f701a08Sujith			ath9k_2ghz_channels;
599fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
600fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
601fb9987d0f748c983bb795a86f47522313f701a08Sujith			ARRAY_SIZE(ath9k_2ghz_channels);
602fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
603fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
604fb9987d0f748c983bb795a86f47522313f701a08Sujith			ARRAY_SIZE(ath9k_legacy_rates);
605fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
606ea46e644e80bd4ac778964afd998df4f666486d4Sujith
607d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
608ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
609ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
610ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
611ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ARRAY_SIZE(ath9k_5ghz_channels);
612ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
613ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ath9k_legacy_rates + 4;
614ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
615ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ARRAY_SIZE(ath9k_legacy_rates) - 4;
616ea46e644e80bd4ac778964afd998df4f666486d4Sujith	}
617fb9987d0f748c983bb795a86f47522313f701a08Sujith}
618fb9987d0f748c983bb795a86f47522313f701a08Sujith
619fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_misc(struct ath9k_htc_priv *priv)
620fb9987d0f748c983bb795a86f47522313f701a08Sujith{
621fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
622fb9987d0f748c983bb795a86f47522313f701a08Sujith
623fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->tx_chainmask = priv->ah->caps.tx_chainmask;
624fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->rx_chainmask = priv->ah->caps.rx_chainmask;
625fb9987d0f748c983bb795a86f47522313f701a08Sujith
626364734fafbba0c3133e482db78149b9a823ae7a5Felix Fietkau	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
627fb9987d0f748c983bb795a86f47522313f701a08Sujith
6289f01a84e81d10e38daa504348217895fe414a24bSujith	priv->ah->opmode = NL80211_IFTYPE_STATION;
629fb9987d0f748c983bb795a86f47522313f701a08Sujith}
630fb9987d0f748c983bb795a86f47522313f701a08Sujith
63121cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic void ath9k_init_btcoex(struct ath9k_htc_priv *priv)
63221cb987914cb5334af78378141efed77505ea987Vivek Natarajan{
63321cb987914cb5334af78378141efed77505ea987Vivek Natarajan	int qnum;
63421cb987914cb5334af78378141efed77505ea987Vivek Natarajan
63521cb987914cb5334af78378141efed77505ea987Vivek Natarajan	switch (priv->ah->btcoex_hw.scheme) {
63621cb987914cb5334af78378141efed77505ea987Vivek Natarajan	case ATH_BTCOEX_CFG_NONE:
63721cb987914cb5334af78378141efed77505ea987Vivek Natarajan		break;
63821cb987914cb5334af78378141efed77505ea987Vivek Natarajan	case ATH_BTCOEX_CFG_3WIRE:
63921cb987914cb5334af78378141efed77505ea987Vivek Natarajan		priv->ah->btcoex_hw.btactive_gpio = 7;
64021cb987914cb5334af78378141efed77505ea987Vivek Natarajan		priv->ah->btcoex_hw.btpriority_gpio = 6;
64121cb987914cb5334af78378141efed77505ea987Vivek Natarajan		priv->ah->btcoex_hw.wlanactive_gpio = 8;
64221cb987914cb5334af78378141efed77505ea987Vivek Natarajan		priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
64321cb987914cb5334af78378141efed77505ea987Vivek Natarajan		ath9k_hw_btcoex_init_3wire(priv->ah);
64421cb987914cb5334af78378141efed77505ea987Vivek Natarajan		ath_htc_init_btcoex_work(priv);
64521cb987914cb5334af78378141efed77505ea987Vivek Natarajan		qnum = priv->hwq_map[WME_AC_BE];
64621cb987914cb5334af78378141efed77505ea987Vivek Natarajan		ath9k_hw_init_btcoex_hw(priv->ah, qnum);
64721cb987914cb5334af78378141efed77505ea987Vivek Natarajan		break;
64821cb987914cb5334af78378141efed77505ea987Vivek Natarajan	default:
64921cb987914cb5334af78378141efed77505ea987Vivek Natarajan		WARN_ON(1);
65021cb987914cb5334af78378141efed77505ea987Vivek Natarajan		break;
65121cb987914cb5334af78378141efed77505ea987Vivek Natarajan	}
65221cb987914cb5334af78378141efed77505ea987Vivek Natarajan}
65321cb987914cb5334af78378141efed77505ea987Vivek Natarajan
65421cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic int ath9k_init_priv(struct ath9k_htc_priv *priv,
655fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			   u16 devid, char *product,
656fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			   u32 drv_info)
657fb9987d0f748c983bb795a86f47522313f701a08Sujith{
658fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = NULL;
659fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common;
660832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan	int i, ret = 0, csz = 0;
661fb9987d0f748c983bb795a86f47522313f701a08Sujith
662fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->op_flags |= OP_INVALID;
663fb9987d0f748c983bb795a86f47522313f701a08Sujith
664fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
665fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ah)
666fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ENOMEM;
667fb9987d0f748c983bb795a86f47522313f701a08Sujith
668fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah->hw_version.devid = devid;
669fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah->hw_version.subsysid = 0; /* FIXME */
6700b5ead91cda63e0db964dadc77601233434f60cbSujith Manoharan	ah->hw_version.usbdev = drv_info;
671f8afa42b01c7a9f45b7cbaadb0481a0eeb96f18dFelix Fietkau	ah->ah_flags |= AH_USE_EEPROM;
672f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.read = ath9k_regread;
673f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.multi_read = ath9k_multi_regread;
674f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.write = ath9k_regwrite;
675f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
676f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.write_flush = ath9k_regwrite_flush;
677845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	ah->reg_ops.rmw = ath9k_reg_rmw;
678fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = ah;
679fb9987d0f748c983bb795a86f47522313f701a08Sujith
680fb9987d0f748c983bb795a86f47522313f701a08Sujith	common = ath9k_hw_common(ah);
681f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	common->ops = &ah->reg_ops;
682fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->bus_ops = &ath9k_usb_bus_ops;
683fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->ah = ah;
684fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->hw = priv->hw;
685fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->priv = priv;
686fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->debug_mask = ath9k_debug;
687fb9987d0f748c983bb795a86f47522313f701a08Sujith
688fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->beacon_lock);
689658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan	spin_lock_init(&priv->tx.tx_lock);
690fb9987d0f748c983bb795a86f47522313f701a08Sujith	mutex_init(&priv->mutex);
691bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	mutex_init(&priv->htc_pm_lock);
692fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
693fb9987d0f748c983bb795a86f47522313f701a08Sujith		     (unsigned long)priv);
69427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
69573908674c6957082e8ab57daed57d2bb97a1ebbaSujith Manoharan		     (unsigned long)priv);
696a236254c35f04a4d47c701ed3ec4a0b5dcb097b0Sujith Manoharan	INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
697bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	INIT_WORK(&priv->ps_work, ath9k_ps_work);
69873908674c6957082e8ab57daed57d2bb97a1ebbaSujith Manoharan	INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
699859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
700859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		    (unsigned long)priv);
701fb9987d0f748c983bb795a86f47522313f701a08Sujith
702fb9987d0f748c983bb795a86f47522313f701a08Sujith	/*
703fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * Cache line size is used to size and align various
704fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * structures used to communicate with the hardware.
705fb9987d0f748c983bb795a86f47522313f701a08Sujith	 */
706fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath_read_cachesize(common, &csz);
707fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->cachelsz = csz << 2; /* convert to bytes */
708fb9987d0f748c983bb795a86f47522313f701a08Sujith
709fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_hw_init(ah);
710fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret) {
7113800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common,
7123800276a40751539a920ef8e0537ef2e19126799Joe Perches			"Unable to initialize hardware; initialization status: %d\n",
7133800276a40751539a920ef8e0537ef2e19126799Joe Perches			ret);
714fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_hw;
715fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
716fb9987d0f748c983bb795a86f47522313f701a08Sujith
717fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_init_queues(priv);
718fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
719fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_queues;
720fb9987d0f748c983bb795a86f47522313f701a08Sujith
721832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
722832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan		priv->cur_beacon_conf.bslot[i] = NULL;
723832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan
724fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_crypto(priv);
725fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_channels_rates(priv);
726fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_misc(priv);
727fb9987d0f748c983bb795a86f47522313f701a08Sujith
72821cb987914cb5334af78378141efed77505ea987Vivek Natarajan	if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
72921cb987914cb5334af78378141efed77505ea987Vivek Natarajan		ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
73021cb987914cb5334af78378141efed77505ea987Vivek Natarajan		ath9k_init_btcoex(priv);
73121cb987914cb5334af78378141efed77505ea987Vivek Natarajan	}
73221cb987914cb5334af78378141efed77505ea987Vivek Natarajan
733fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
734fb9987d0f748c983bb795a86f47522313f701a08Sujith
735fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_queues:
736fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_deinit(ah);
737fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_hw:
738fb9987d0f748c983bb795a86f47522313f701a08Sujith
739fb9987d0f748c983bb795a86f47522313f701a08Sujith	kfree(ah);
740fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = NULL;
741fb9987d0f748c983bb795a86f47522313f701a08Sujith
742fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
743fb9987d0f748c983bb795a86f47522313f701a08Sujith}
744fb9987d0f748c983bb795a86f47522313f701a08Sujith
745fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
746fb9987d0f748c983bb795a86f47522313f701a08Sujith			       struct ieee80211_hw *hw)
747fb9987d0f748c983bb795a86f47522313f701a08Sujith{
748fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
749fb9987d0f748c983bb795a86f47522313f701a08Sujith
750fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->flags = IEEE80211_HW_SIGNAL_DBM |
751fb9987d0f748c983bb795a86f47522313f701a08Sujith		IEEE80211_HW_AMPDU_AGGREGATION |
752fb9987d0f748c983bb795a86f47522313f701a08Sujith		IEEE80211_HW_SPECTRUM_MGMT |
75332fbccafed7e935432b601f0453c2b702a385a25Sujith		IEEE80211_HW_HAS_RATE_CONTROL |
754bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		IEEE80211_HW_RX_INCLUDES_FCS |
755bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		IEEE80211_HW_SUPPORTS_PS |
7567d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan		IEEE80211_HW_PS_NULLFUNC_STACK |
7578ae2e12f1534e647d4a816755e5a09c2de6f9fcaRajkumar Manoharan		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
7587d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
759fb9987d0f748c983bb795a86f47522313f701a08Sujith
760fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->wiphy->interface_modes =
761fb9987d0f748c983bb795a86f47522313f701a08Sujith		BIT(NL80211_IFTYPE_STATION) |
76209d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_ADHOC) |
76309d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_AP) |
76409d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_P2P_GO) |
76509d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_P2P_CLIENT);
766fb9987d0f748c983bb795a86f47522313f701a08Sujith
767bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
768bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
769fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->queues = 4;
770fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->channel_change_time = 5000;
771fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->max_listen_interval = 10;
7723a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan
773fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->vif_data_size = sizeof(struct ath9k_htc_vif);
774fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->sta_data_size = sizeof(struct ath9k_htc_sta);
775fb9987d0f748c983bb795a86f47522313f701a08Sujith
776fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* tx_frame_hdr is larger than tx_mgmt_hdr anyway */
777fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) +
778fb9987d0f748c983bb795a86f47522313f701a08Sujith		sizeof(struct htc_frame_hdr) + 4;
779fb9987d0f748c983bb795a86f47522313f701a08Sujith
780d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
781fb9987d0f748c983bb795a86f47522313f701a08Sujith		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
782fb9987d0f748c983bb795a86f47522313f701a08Sujith			&priv->sbands[IEEE80211_BAND_2GHZ];
783d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
784ea46e644e80bd4ac778964afd998df4f666486d4Sujith		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
785ea46e644e80bd4ac778964afd998df4f666486d4Sujith			&priv->sbands[IEEE80211_BAND_5GHZ];
786fb9987d0f748c983bb795a86f47522313f701a08Sujith
787fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
788d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
789fb9987d0f748c983bb795a86f47522313f701a08Sujith			setup_ht_cap(priv,
790fb9987d0f748c983bb795a86f47522313f701a08Sujith				     &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
791d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
792ea46e644e80bd4ac778964afd998df4f666486d4Sujith			setup_ht_cap(priv,
793ea46e644e80bd4ac778964afd998df4f666486d4Sujith				     &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
794fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
795fb9987d0f748c983bb795a86f47522313f701a08Sujith
796fb9987d0f748c983bb795a86f47522313f701a08Sujith	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
797fb9987d0f748c983bb795a86f47522313f701a08Sujith}
798fb9987d0f748c983bb795a86f47522313f701a08Sujith
79929bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharanstatic int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
80029bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan{
80129bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	struct ieee80211_hw *hw = priv->hw;
80229bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	struct wmi_fw_version cmd_rsp;
80329bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	int ret;
80429bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
80529bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
80629bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
80729bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	WMI_CMD(WMI_GET_FW_VERSION);
80829bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	if (ret)
80929bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		return -EINVAL;
81029bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
81129bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
81229bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
81329bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
81429bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
81529bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_major,
81629bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_minor);
81729bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
81829bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
81929bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_major,
82029bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_minor);
82129bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
8223a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	/*
8233a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	 * Check if the available FW matches the driver's
8243a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	 * required version.
8253a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	 */
8263a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	if (priv->fw_version_major != MAJOR_VERSION_REQ ||
8273a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	    priv->fw_version_minor != MINOR_VERSION_REQ) {
8283a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan		dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
8293a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan			MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
8303a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan		return -EINVAL;
8313a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	}
8323a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan
83329bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	return 0;
83429bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan}
83529bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
83621cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic int ath9k_init_device(struct ath9k_htc_priv *priv,
837fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			     u16 devid, char *product, u32 drv_info)
838fb9987d0f748c983bb795a86f47522313f701a08Sujith{
839fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
840fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common;
841fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah;
842fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error = 0;
843fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_regulatory *reg;
8443e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan	char hw_name[64];
845fb9987d0f748c983bb795a86f47522313f701a08Sujith
846fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Bring up device */
847fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	error = ath9k_init_priv(priv, devid, product, drv_info);
848fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
849fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
850fb9987d0f748c983bb795a86f47522313f701a08Sujith
851fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah = priv->ah;
852fb9987d0f748c983bb795a86f47522313f701a08Sujith	common = ath9k_hw_common(ah);
853fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_set_hw_capab(priv, hw);
854fb9987d0f748c983bb795a86f47522313f701a08Sujith
85529bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	error = ath9k_init_firmware_version(priv);
85629bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	if (error != 0)
85729bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		goto err_fw;
85829bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
859fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Initialize regulatory */
860fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
861fb9987d0f748c983bb795a86f47522313f701a08Sujith			      ath9k_reg_notifier);
862fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error)
863fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_regd;
864fb9987d0f748c983bb795a86f47522313f701a08Sujith
865fb9987d0f748c983bb795a86f47522313f701a08Sujith	reg = &common->regulatory;
866fb9987d0f748c983bb795a86f47522313f701a08Sujith
867fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Setup TX */
868fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_tx_init(priv);
869fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
870fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_tx;
871fb9987d0f748c983bb795a86f47522313f701a08Sujith
872fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Setup RX */
873fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_rx_init(priv);
874fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
875fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_rx;
876fb9987d0f748c983bb795a86f47522313f701a08Sujith
877d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#ifdef CONFIG_MAC80211_LEDS
878d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	/* must be initialized before ieee80211_register_hw */
879d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
880d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan		IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink,
881d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan		ARRAY_SIZE(ath9k_htc_tpt_blink));
882d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#endif
883d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan
884fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Register with mac80211 */
885fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ieee80211_register_hw(hw);
886fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error)
887fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_register;
888fb9987d0f748c983bb795a86f47522313f701a08Sujith
889fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Handle world regulatory */
890fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath_is_world_regd(reg)) {
891fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = regulatory_hint(hw->wiphy, reg->alpha2);
892fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (error)
893fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto err_world;
894fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
895fb9987d0f748c983bb795a86f47522313f701a08Sujith
896e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	error = ath9k_htc_init_debug(priv->ah);
897e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	if (error) {
898e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan		ath_err(common, "Unable to create debugfs files\n");
899e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan		goto err_world;
900e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	}
901e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan
9023e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan	ath_dbg(common, ATH_DBG_CONFIG,
9033e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, "
9043e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		"BE:%d, BK:%d, VI:%d, VO:%d\n",
9053e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->wmi_cmd_ep,
9063e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->beacon_ep,
9073e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->cab_ep,
9083e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->uapsd_ep,
9093e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->mgmt_ep,
9103e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_be_ep,
9113e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_bk_ep,
9123e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_vi_ep,
9133e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_vo_ep);
9143e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan
9153e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan	ath9k_hw_name(priv->ah, hw_name, sizeof(hw_name));
9163e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan	wiphy_info(hw->wiphy, "%s\n", hw_name);
9173e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan
918fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_leds(priv);
919fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_start_rfkill_poll(priv);
920fb9987d0f748c983bb795a86f47522313f701a08Sujith
921fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
922fb9987d0f748c983bb795a86f47522313f701a08Sujith
923fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_world:
924fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_unregister_hw(hw);
925fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_register:
926fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
927fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_rx:
928fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_tx_cleanup(priv);
929fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_tx:
930fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Nothing */
931fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_regd:
93229bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	/* Nothing */
93329bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharanerr_fw:
934fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_priv(priv);
935fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init:
936fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
937fb9987d0f748c983bb795a86f47522313f701a08Sujith}
938fb9987d0f748c983bb795a86f47522313f701a08Sujith
939fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
940fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			   u16 devid, char *product, u32 drv_info)
941fb9987d0f748c983bb795a86f47522313f701a08Sujith{
942fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw;
943fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv;
944fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
945fb9987d0f748c983bb795a86f47522313f701a08Sujith
946fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
947fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!hw)
948fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ENOMEM;
949fb9987d0f748c983bb795a86f47522313f701a08Sujith
950fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv = hw->priv;
951fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->hw = hw;
952fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->htc = htc_handle;
953fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->dev = dev;
954fb9987d0f748c983bb795a86f47522313f701a08Sujith	htc_handle->drv_priv = priv;
955fb9987d0f748c983bb795a86f47522313f701a08Sujith	SET_IEEE80211_DEV(hw, priv->dev);
956fb9987d0f748c983bb795a86f47522313f701a08Sujith
957fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_wait_for_target(priv);
958fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
959fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_free;
960fb9987d0f748c983bb795a86f47522313f701a08Sujith
961fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->wmi = ath9k_init_wmi(priv);
962fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!priv->wmi) {
963fb9987d0f748c983bb795a86f47522313f701a08Sujith		ret = -EINVAL;
964fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_free;
965fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
966fb9987d0f748c983bb795a86f47522313f701a08Sujith
967fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_init_htc_services(priv, devid, drv_info);
968fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
969fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
970fb9987d0f748c983bb795a86f47522313f701a08Sujith
971fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_init_device(priv, devid, product, drv_info);
972fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
973fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
974fb9987d0f748c983bb795a86f47522313f701a08Sujith
975fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
976fb9987d0f748c983bb795a86f47522313f701a08Sujith
977fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init:
978fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_wmi(priv);
979fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_free:
980fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_free_hw(hw);
981fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
982fb9987d0f748c983bb795a86f47522313f701a08Sujith}
983fb9987d0f748c983bb795a86f47522313f701a08Sujith
984fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
985fb9987d0f748c983bb795a86f47522313f701a08Sujith{
986fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (htc_handle->drv_priv) {
987a3be14b76da111ebe4d245b0542613f9317104e7Sujith
988a3be14b76da111ebe4d245b0542613f9317104e7Sujith		/* Check if the device has been yanked out. */
989a3be14b76da111ebe4d245b0542613f9317104e7Sujith		if (hotunplug)
99097dcec5715a381362c88d1542e52c63147764d3cSujith Manoharan			htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED;
991a3be14b76da111ebe4d245b0542613f9317104e7Sujith
992fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_deinit_device(htc_handle->drv_priv);
993fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_deinit_wmi(htc_handle->drv_priv);
994fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_free_hw(htc_handle->drv_priv->hw);
995fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
996fb9987d0f748c983bb795a86f47522313f701a08Sujith}
997fb9987d0f748c983bb795a86f47522313f701a08Sujith
998fb9987d0f748c983bb795a86f47522313f701a08Sujith#ifdef CONFIG_PM
999f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan
1000f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharanvoid ath9k_htc_suspend(struct htc_target *htc_handle)
1001f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan{
1002f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan	ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP);
1003f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan}
1004f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan
1005fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_resume(struct htc_target *htc_handle)
1006fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1007fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	struct ath9k_htc_priv *priv = htc_handle->drv_priv;
1008fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
1009fb9987d0f748c983bb795a86f47522313f701a08Sujith
1010fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_htc_wait_for_target(priv);
1011fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
1012fb9987d0f748c983bb795a86f47522313f701a08Sujith		return ret;
1013fb9987d0f748c983bb795a86f47522313f701a08Sujith
1014fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,
10150b5ead91cda63e0db964dadc77601233434f60cbSujith Manoharan				      priv->ah->hw_version.usbdev);
1016fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
1017fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1018fb9987d0f748c983bb795a86f47522313f701a08Sujith#endif
1019fb9987d0f748c983bb795a86f47522313f701a08Sujith
1020fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int __init ath9k_htc_init(void)
1021fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1022e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	if (ath9k_hif_usb_init() < 0) {
1023fb9987d0f748c983bb795a86f47522313f701a08Sujith		printk(KERN_ERR
1024fb9987d0f748c983bb795a86f47522313f701a08Sujith			"ath9k_htc: No USB devices found,"
1025fb9987d0f748c983bb795a86f47522313f701a08Sujith			" driver not installed.\n");
1026e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan		return -ENODEV;
1027fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
1028fb9987d0f748c983bb795a86f47522313f701a08Sujith
1029fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
1030fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1031fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_init(ath9k_htc_init);
1032fb9987d0f748c983bb795a86f47522313f701a08Sujith
1033fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void __exit ath9k_htc_exit(void)
1034fb9987d0f748c983bb795a86f47522313f701a08Sujith{
1035fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hif_usb_exit();
1036fb9987d0f748c983bb795a86f47522313f701a08Sujith	printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
1037fb9987d0f748c983bb795a86f47522313f701a08Sujith}
1038fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_exit(ath9k_htc_exit);
1039