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
44fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_channel ath9k_2ghz_channels[] = {
45fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2412, 0), /* Channel 1 */
46fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2417, 1), /* Channel 2 */
47fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2422, 2), /* Channel 3 */
48fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2427, 3), /* Channel 4 */
49fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2432, 4), /* Channel 5 */
50fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2437, 5), /* Channel 6 */
51fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2442, 6), /* Channel 7 */
52fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2447, 7), /* Channel 8 */
53fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2452, 8), /* Channel 9 */
54fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2457, 9), /* Channel 10 */
55fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2462, 10), /* Channel 11 */
56fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2467, 11), /* Channel 12 */
57fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2472, 12), /* Channel 13 */
58fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2484, 13), /* Channel 14 */
59fb9987d0f748c983bb795a86f47522313f701a08Sujith};
60fb9987d0f748c983bb795a86f47522313f701a08Sujith
61ea46e644e80bd4ac778964afd998df4f666486d4Sujithstatic struct ieee80211_channel ath9k_5ghz_channels[] = {
62ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 1 */
63ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5180, 14), /* Channel 36 */
64ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5200, 15), /* Channel 40 */
65ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5220, 16), /* Channel 44 */
66ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5240, 17), /* Channel 48 */
67ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 2 */
68ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5260, 18), /* Channel 52 */
69ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5280, 19), /* Channel 56 */
70ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5300, 20), /* Channel 60 */
71ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5320, 21), /* Channel 64 */
72ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this "Middle band" */
73ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5500, 22), /* Channel 100 */
74ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5520, 23), /* Channel 104 */
75ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5540, 24), /* Channel 108 */
76ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5560, 25), /* Channel 112 */
77ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5580, 26), /* Channel 116 */
78ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5600, 27), /* Channel 120 */
79ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5620, 28), /* Channel 124 */
80ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5640, 29), /* Channel 128 */
81ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5660, 30), /* Channel 132 */
82ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5680, 31), /* Channel 136 */
83ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5700, 32), /* Channel 140 */
84ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 3 */
85ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5745, 33), /* Channel 149 */
86ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5765, 34), /* Channel 153 */
87ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5785, 35), /* Channel 157 */
88ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5805, 36), /* Channel 161 */
89ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5825, 37), /* Channel 165 */
90ea46e644e80bd4ac778964afd998df4f666486d4Sujith};
91ea46e644e80bd4ac778964afd998df4f666486d4Sujith
92fb9987d0f748c983bb795a86f47522313f701a08Sujith/* Atheros hardware rate code addition for short premble */
93fb9987d0f748c983bb795a86f47522313f701a08Sujith#define SHPCHECK(__hw_rate, __flags) \
94fb9987d0f748c983bb795a86f47522313f701a08Sujith	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
95fb9987d0f748c983bb795a86f47522313f701a08Sujith
96fb9987d0f748c983bb795a86f47522313f701a08Sujith#define RATE(_bitrate, _hw_rate, _flags) {		\
97fb9987d0f748c983bb795a86f47522313f701a08Sujith	.bitrate	= (_bitrate),			\
98fb9987d0f748c983bb795a86f47522313f701a08Sujith	.flags		= (_flags),			\
99fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value	= (_hw_rate),			\
100fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value_short = (SHPCHECK(_hw_rate, _flags))	\
101fb9987d0f748c983bb795a86f47522313f701a08Sujith}
102fb9987d0f748c983bb795a86f47522313f701a08Sujith
103fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_rate ath9k_legacy_rates[] = {
104fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(10, 0x1b, 0),
105fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */
106fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
107fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
108fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(60, 0x0b, 0),
109fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(90, 0x0f, 0),
110fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(120, 0x0a, 0),
111fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(180, 0x0e, 0),
112fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(240, 0x09, 0),
113fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(360, 0x0d, 0),
114fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(480, 0x08, 0),
115fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(540, 0x0c, 0),
116fb9987d0f748c983bb795a86f47522313f701a08Sujith};
117fb9987d0f748c983bb795a86f47522313f701a08Sujith
118d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#ifdef CONFIG_MAC80211_LEDS
119d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharanstatic const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
120d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 0 * 1024, .blink_time = 334 },
121d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 1 * 1024, .blink_time = 260 },
122d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 5 * 1024, .blink_time = 220 },
123d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 10 * 1024, .blink_time = 190 },
124d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 20 * 1024, .blink_time = 170 },
125d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 50 * 1024, .blink_time = 150 },
126d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 70 * 1024, .blink_time = 130 },
127d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 100 * 1024, .blink_time = 110 },
128d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 200 * 1024, .blink_time = 80 },
129d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	{ .throughput = 300 * 1024, .blink_time = 50 },
130d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan};
131d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#endif
132d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan
133fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
134fb9987d0f748c983bb795a86f47522313f701a08Sujith{
135fb9987d0f748c983bb795a86f47522313f701a08Sujith	int time_left;
136fb9987d0f748c983bb795a86f47522313f701a08Sujith
137d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	if (atomic_read(&priv->htc->tgt_ready) > 0) {
138d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com		atomic_dec(&priv->htc->tgt_ready);
139d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com		return 0;
140d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	}
141d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com
142fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Firmware can take up to 50ms to get ready, to be safe use 1 second */
143fb9987d0f748c983bb795a86f47522313f701a08Sujith	time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ);
144fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!time_left) {
145fb9987d0f748c983bb795a86f47522313f701a08Sujith		dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n");
146fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ETIMEDOUT;
147fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
148fb9987d0f748c983bb795a86f47522313f701a08Sujith
149d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	atomic_dec(&priv->htc->tgt_ready);
150d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com
151fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
152fb9987d0f748c983bb795a86f47522313f701a08Sujith}
153fb9987d0f748c983bb795a86f47522313f701a08Sujith
154fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
155fb9987d0f748c983bb795a86f47522313f701a08Sujith{
156fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_deinit(priv->ah);
157fb9987d0f748c983bb795a86f47522313f701a08Sujith	kfree(priv->ah);
158fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = NULL;
159fb9987d0f748c983bb795a86f47522313f701a08Sujith}
160fb9987d0f748c983bb795a86f47522313f701a08Sujith
161fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_device(struct ath9k_htc_priv *priv)
162fb9987d0f748c983bb795a86f47522313f701a08Sujith{
163fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
164fb9987d0f748c983bb795a86f47522313f701a08Sujith
165fb9987d0f748c983bb795a86f47522313f701a08Sujith	wiphy_rfkill_stop_polling(hw->wiphy);
166fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_leds(priv);
167fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_unregister_hw(hw);
168fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
169fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_tx_cleanup(priv);
170fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_priv(priv);
171fb9987d0f748c983bb795a86f47522313f701a08Sujith}
172fb9987d0f748c983bb795a86f47522313f701a08Sujith
173fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
174fb9987d0f748c983bb795a86f47522313f701a08Sujith					u16 service_id,
175fb9987d0f748c983bb795a86f47522313f701a08Sujith					void (*tx) (void *,
176fb9987d0f748c983bb795a86f47522313f701a08Sujith						    struct sk_buff *,
177fb9987d0f748c983bb795a86f47522313f701a08Sujith						    enum htc_endpoint_id,
178fb9987d0f748c983bb795a86f47522313f701a08Sujith						    bool txok),
179fb9987d0f748c983bb795a86f47522313f701a08Sujith					enum htc_endpoint_id *ep_id)
180fb9987d0f748c983bb795a86f47522313f701a08Sujith{
181fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct htc_service_connreq req;
182fb9987d0f748c983bb795a86f47522313f701a08Sujith
183fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&req, 0, sizeof(struct htc_service_connreq));
184fb9987d0f748c983bb795a86f47522313f701a08Sujith
185fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.service_id = service_id;
186fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.priv = priv;
187fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.rx = ath9k_htc_rxep;
188fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.tx = tx;
189fb9987d0f748c983bb795a86f47522313f701a08Sujith
190fb9987d0f748c983bb795a86f47522313f701a08Sujith	return htc_connect_service(priv->htc, &req, ep_id);
191fb9987d0f748c983bb795a86f47522313f701a08Sujith}
192fb9987d0f748c983bb795a86f47522313f701a08Sujith
193fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharanstatic int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
194fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan				   u32 drv_info)
195fb9987d0f748c983bb795a86f47522313f701a08Sujith{
196fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
197fb9987d0f748c983bb795a86f47522313f701a08Sujith
198fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* WMI CMD*/
199fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep);
200fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
201fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
202fb9987d0f748c983bb795a86f47522313f701a08Sujith
203fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Beacon */
2049c6dda4e2dfea970a7105e3805f0195bc3079f2fSujith	ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep,
205fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->beacon_ep);
206fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
207fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
208fb9987d0f748c983bb795a86f47522313f701a08Sujith
209fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* CAB */
210fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep,
211fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->cab_ep);
212fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
213fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
214fb9987d0f748c983bb795a86f47522313f701a08Sujith
215fb9987d0f748c983bb795a86f47522313f701a08Sujith
216fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* UAPSD */
217fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep,
218fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->uapsd_ep);
219fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
220fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
221fb9987d0f748c983bb795a86f47522313f701a08Sujith
222fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* MGMT */
223fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep,
224fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->mgmt_ep);
225fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
226fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
227fb9987d0f748c983bb795a86f47522313f701a08Sujith
228fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA BE */
229fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep,
230fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_be_ep);
231fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
232fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
233fb9987d0f748c983bb795a86f47522313f701a08Sujith
234fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA BK */
235fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep,
236fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_bk_ep);
237fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
238fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
239fb9987d0f748c983bb795a86f47522313f701a08Sujith
240fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA VI */
241fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep,
242fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_vi_ep);
243fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
244fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
245fb9987d0f748c983bb795a86f47522313f701a08Sujith
246fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA VO */
247fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep,
248fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_vo_ep);
249fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
250fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
251fb9987d0f748c983bb795a86f47522313f701a08Sujith
2526267dc709c6ef1c0926e18ff2859238992dea658Sujith	/*
2536267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * Setup required credits before initializing HTC.
2546267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * This is a bit hacky, but, since queuing is done in
2556267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * the HIF layer, shouldn't matter much.
2566267dc709c6ef1c0926e18ff2859238992dea658Sujith	 */
2576267dc709c6ef1c0926e18ff2859238992dea658Sujith
2580b5ead91cda63e0db964dadc77601233434f60cbSujith Manoharan	if (IS_AR7010_DEVICE(drv_info))
259d108e8b9320b77e3fa165757fd40f298bdd89d1cSujith Manoharan		priv->htc->credits = 45;
260fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	else
2614e63f768c3b85ae2b3ea6251231fd5cc46ec598dSujith		priv->htc->credits = 33;
2626267dc709c6ef1c0926e18ff2859238992dea658Sujith
263fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = htc_init(priv->htc);
264fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
265fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
266fb9987d0f748c983bb795a86f47522313f701a08Sujith
2676267dc709c6ef1c0926e18ff2859238992dea658Sujith	dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n",
2686267dc709c6ef1c0926e18ff2859238992dea658Sujith		 priv->htc->credits);
2696267dc709c6ef1c0926e18ff2859238992dea658Sujith
270fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
271fb9987d0f748c983bb795a86f47522313f701a08Sujith
272fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
273fb9987d0f748c983bb795a86f47522313f701a08Sujith	dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n");
274fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
275fb9987d0f748c983bb795a86f47522313f701a08Sujith}
276fb9987d0f748c983bb795a86f47522313f701a08Sujith
277fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_reg_notifier(struct wiphy *wiphy,
278fb9987d0f748c983bb795a86f47522313f701a08Sujith			      struct regulatory_request *request)
279fb9987d0f748c983bb795a86f47522313f701a08Sujith{
280fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
281fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = hw->priv;
282fb9987d0f748c983bb795a86f47522313f701a08Sujith
283fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ath_reg_notifier_apply(wiphy, request,
284fb9987d0f748c983bb795a86f47522313f701a08Sujith				      ath9k_hw_regulatory(priv->ah));
285fb9987d0f748c983bb795a86f47522313f701a08Sujith}
286fb9987d0f748c983bb795a86f47522313f701a08Sujith
2874a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
288fb9987d0f748c983bb795a86f47522313f701a08Sujith{
289fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
290fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
291fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
292fb9987d0f748c983bb795a86f47522313f701a08Sujith	__be32 val, reg = cpu_to_be32(reg_offset);
293fb9987d0f748c983bb795a86f47522313f701a08Sujith	int r;
294fb9987d0f748c983bb795a86f47522313f701a08Sujith
295fb9987d0f748c983bb795a86f47522313f701a08Sujith	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
296fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &reg, sizeof(reg),
297fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &val, sizeof(val),
298fb9987d0f748c983bb795a86f47522313f701a08Sujith			  100);
299fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (unlikely(r)) {
300d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, WMI, "REGISTER READ FAILED: (0x%04x, %d)\n",
301226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			reg_offset, r);
302fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -EIO;
303fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
304fb9987d0f748c983bb795a86f47522313f701a08Sujith
305fb9987d0f748c983bb795a86f47522313f701a08Sujith	return be32_to_cpu(val);
306fb9987d0f748c983bb795a86f47522313f701a08Sujith}
307fb9987d0f748c983bb795a86f47522313f701a08Sujith
30809a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharanstatic void ath9k_multi_regread(void *hw_priv, u32 *addr,
30909a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan				u32 *val, u16 count)
31009a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan{
31109a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	struct ath_hw *ah = (struct ath_hw *) hw_priv;
31209a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	struct ath_common *common = ath9k_hw_common(ah);
31309a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
31409a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	__be32 tmpaddr[8];
31509a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	__be32 tmpval[8];
31609a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	int i, ret;
31709a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
31809a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       for (i = 0; i < count; i++) {
31909a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	       tmpaddr[i] = cpu_to_be32(addr[i]);
32009a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       }
32109a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
32209a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
32309a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			   (u8 *)tmpaddr , sizeof(u32) * count,
32409a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			   (u8 *)tmpval, sizeof(u32) * count,
32509a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			   100);
32609a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	if (unlikely(ret)) {
327d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, WMI,
32809a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan			"Multiple REGISTER READ FAILED (count: %d)\n", count);
32909a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	}
33009a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
33109a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       for (i = 0; i < count; i++) {
33209a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan	       val[i] = be32_to_cpu(tmpval[i]);
33309a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan       }
33409a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan}
33509a525d33870e8a16076ec0200cc5002f6bef35dSujith Manoharan
3364a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
337fb9987d0f748c983bb795a86f47522313f701a08Sujith{
338fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
339fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
340fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
34107b2fa5a2368accf0fe6cb16e7eca6d1150554edJoe Perches	const __be32 buf[2] = {
342fb9987d0f748c983bb795a86f47522313f701a08Sujith		cpu_to_be32(reg_offset),
343fb9987d0f748c983bb795a86f47522313f701a08Sujith		cpu_to_be32(val),
344fb9987d0f748c983bb795a86f47522313f701a08Sujith	};
345fb9987d0f748c983bb795a86f47522313f701a08Sujith	int r;
346fb9987d0f748c983bb795a86f47522313f701a08Sujith
347fb9987d0f748c983bb795a86f47522313f701a08Sujith	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
348fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &buf, sizeof(buf),
349fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &val, sizeof(val),
350fb9987d0f748c983bb795a86f47522313f701a08Sujith			  100);
351fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (unlikely(r)) {
352d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, WMI, "REGISTER WRITE FAILED:(0x%04x, %d)\n",
353226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			reg_offset, r);
354fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
355fb9987d0f748c983bb795a86f47522313f701a08Sujith}
356fb9987d0f748c983bb795a86f47522313f701a08Sujith
3574a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
3584a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3594a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3604a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3614a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3624a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	u32 rsp_status;
3634a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	int r;
3644a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3654a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_lock(&priv->wmi->multi_write_mutex);
3664a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3674a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	/* Store the register/value */
3684a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
3694a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		cpu_to_be32(reg_offset);
3704a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
3714a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		cpu_to_be32(val);
3724a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3734a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write_idx++;
3744a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3754a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	/* If the buffer is full, send it out. */
3764a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
3774a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
3784a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &priv->wmi->multi_write,
3794a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
3804a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &rsp_status, sizeof(rsp_status),
3814a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  100);
3824a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		if (unlikely(r)) {
383d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, WMI,
384226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"REGISTER WRITE FAILED, multi len: %d\n",
385226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				priv->wmi->multi_write_idx);
3864a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		}
3874a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		priv->wmi->multi_write_idx = 0;
3884a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	}
3894a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3904a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_unlock(&priv->wmi->multi_write_mutex);
3914a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
3924a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3934a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
3944a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3954a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3964a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3974a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3984a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3994a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (atomic_read(&priv->wmi->mwrite_cnt))
4004a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		ath9k_regwrite_buffer(hw_priv, val, reg_offset);
4014a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	else
4024a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		ath9k_regwrite_single(hw_priv, val, reg_offset);
4034a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
4044a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4054a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_enable_regwrite_buffer(void *hw_priv)
4064a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
4074a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4084a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
4094a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4104a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4114a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	atomic_inc(&priv->wmi->mwrite_cnt);
4124a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
4134a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4144a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_flush(void *hw_priv)
4154a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
4164a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4174a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
4184a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4194a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	u32 rsp_status;
4204a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	int r;
4214a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
422435c1610f46dc4d86a6633adb037b18109e6ffdcFelix Fietkau	atomic_dec(&priv->wmi->mwrite_cnt);
423435c1610f46dc4d86a6633adb037b18109e6ffdcFelix Fietkau
4244a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_lock(&priv->wmi->multi_write_mutex);
4254a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4264a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (priv->wmi->multi_write_idx) {
4274a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
4284a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &priv->wmi->multi_write,
4294a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
4304a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &rsp_status, sizeof(rsp_status),
4314a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  100);
4324a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		if (unlikely(r)) {
433d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, WMI,
434226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"REGISTER WRITE FAILED, multi len: %d\n",
435226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				priv->wmi->multi_write_idx);
4364a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		}
4374a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		priv->wmi->multi_write_idx = 0;
4384a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	}
4394a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4404a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_unlock(&priv->wmi->multi_write_mutex);
4414a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
4424a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
443845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkaustatic u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
444845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau{
445845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	u32 val;
446845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau
447845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	val = ath9k_regread(hw_priv, reg_offset);
448845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	val &= ~clr;
449845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	val |= set;
450845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	ath9k_regwrite(hw_priv, val, reg_offset);
451845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	return val;
452845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau}
453845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau
454fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath_usb_read_cachesize(struct ath_common *common, int *csz)
455fb9987d0f748c983bb795a86f47522313f701a08Sujith{
456fb9987d0f748c983bb795a86f47522313f701a08Sujith	*csz = L1_CACHE_BYTES >> 2;
457fb9987d0f748c983bb795a86f47522313f701a08Sujith}
458fb9987d0f748c983bb795a86f47522313f701a08Sujith
459fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
460fb9987d0f748c983bb795a86f47522313f701a08Sujith{
461fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) common->ah;
462fb9987d0f748c983bb795a86f47522313f701a08Sujith
463fb9987d0f748c983bb795a86f47522313f701a08Sujith	(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
464fb9987d0f748c983bb795a86f47522313f701a08Sujith
465fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath9k_hw_wait(ah,
466fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA,
467fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA_BUSY |
468fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
469fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AH_WAIT_TIMEOUT))
470fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
471fb9987d0f748c983bb795a86f47522313f701a08Sujith
472fb9987d0f748c983bb795a86f47522313f701a08Sujith	*data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
473fb9987d0f748c983bb795a86f47522313f701a08Sujith		   AR_EEPROM_STATUS_DATA_VAL);
474fb9987d0f748c983bb795a86f47522313f701a08Sujith
475fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
476fb9987d0f748c983bb795a86f47522313f701a08Sujith}
477fb9987d0f748c983bb795a86f47522313f701a08Sujith
478fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic const struct ath_bus_ops ath9k_usb_bus_ops = {
479497ad9adf44013dc9054f80c627acc44d4c90d37Sujith	.ath_bus_type = ATH_USB,
480fb9987d0f748c983bb795a86f47522313f701a08Sujith	.read_cachesize = ath_usb_read_cachesize,
481fb9987d0f748c983bb795a86f47522313f701a08Sujith	.eeprom_read = ath_usb_eeprom_read,
482fb9987d0f748c983bb795a86f47522313f701a08Sujith};
483fb9987d0f748c983bb795a86f47522313f701a08Sujith
484fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void setup_ht_cap(struct ath9k_htc_priv *priv,
485fb9987d0f748c983bb795a86f47522313f701a08Sujith			 struct ieee80211_sta_ht_cap *ht_info)
486fb9987d0f748c983bb795a86f47522313f701a08Sujith{
4876debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
4886debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	u8 tx_streams, rx_streams;
4896debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	int i;
4906debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
491fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ht_supported = true;
492fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
493fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_SM_PS |
494fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_SGI_40 |
495fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_DSSSCCK40;
496fb9987d0f748c983bb795a86f47522313f701a08Sujith
497b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
498b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
499b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith
50017525f96aeeed156bd4a6dee21816100f77b0c71Sujith	ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
50117525f96aeeed156bd4a6dee21816100f77b0c71Sujith
502fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
503fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
504fb9987d0f748c983bb795a86f47522313f701a08Sujith
505fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
5066debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
5076debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	/* ath9k_htc supports only 1 or 2 stream devices */
50882b2d334314c387ebd857b88a3d889c9a2cfec4aFelix Fietkau	tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2);
50982b2d334314c387ebd857b88a3d889c9a2cfec4aFelix Fietkau	rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2);
5106debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
511d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
512226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		tx_streams, rx_streams);
5136debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
5146debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	if (tx_streams != rx_streams) {
5156debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
5166debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.tx_params |= ((tx_streams - 1) <<
5176debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith					   IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
5186debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	}
5196debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
5206debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	for (i = 0; i < rx_streams; i++)
5216debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.rx_mask[i] = 0xff;
5226debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
523fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
524fb9987d0f748c983bb795a86f47522313f701a08Sujith}
525fb9987d0f748c983bb795a86f47522313f701a08Sujith
526fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_init_queues(struct ath9k_htc_priv *priv)
527fb9987d0f748c983bb795a86f47522313f701a08Sujith{
528fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
529fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i;
530fb9987d0f748c983bb795a86f47522313f701a08Sujith
531fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
532fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->hwq_map[i] = -1;
533fb9987d0f748c983bb795a86f47522313f701a08Sujith
534ca74b83b66dbd289a395c6243695d746c76676ccSujith	priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
535ca74b83b66dbd289a395c6243695d746c76676ccSujith	if (priv->beaconq == -1) {
5363800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup BEACON xmit queue\n");
537ca74b83b66dbd289a395c6243695d746c76676ccSujith		goto err;
538ca74b83b66dbd289a395c6243695d746c76676ccSujith	}
539ca74b83b66dbd289a395c6243695d746c76676ccSujith
540ca74b83b66dbd289a395c6243695d746c76676ccSujith	priv->cabq = ath9k_htc_cabq_setup(priv);
541ca74b83b66dbd289a395c6243695d746c76676ccSujith	if (priv->cabq == -1) {
5423800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup CAB xmit queue\n");
543ca74b83b66dbd289a395c6243695d746c76676ccSujith		goto err;
544ca74b83b66dbd289a395c6243695d746c76676ccSujith	}
545ca74b83b66dbd289a395c6243695d746c76676ccSujith
546e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
5473800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for BE traffic\n");
548fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
549fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
550fb9987d0f748c983bb795a86f47522313f701a08Sujith
551e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
5523800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for BK traffic\n");
553fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
554fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
555e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
5563800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for VI traffic\n");
557fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
558fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
559e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
5603800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common, "Unable to setup xmit queue for VO traffic\n");
561fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
562fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
563fb9987d0f748c983bb795a86f47522313f701a08Sujith
564fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
565fb9987d0f748c983bb795a86f47522313f701a08Sujith
566fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
567fb9987d0f748c983bb795a86f47522313f701a08Sujith	return -EINVAL;
568fb9987d0f748c983bb795a86f47522313f701a08Sujith}
569fb9987d0f748c983bb795a86f47522313f701a08Sujith
570fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
571fb9987d0f748c983bb795a86f47522313f701a08Sujith{
572d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
573fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].channels =
574fb9987d0f748c983bb795a86f47522313f701a08Sujith			ath9k_2ghz_channels;
575fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
576fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
577fb9987d0f748c983bb795a86f47522313f701a08Sujith			ARRAY_SIZE(ath9k_2ghz_channels);
578fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
579fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
580fb9987d0f748c983bb795a86f47522313f701a08Sujith			ARRAY_SIZE(ath9k_legacy_rates);
581fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
582ea46e644e80bd4ac778964afd998df4f666486d4Sujith
583d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
584ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
585ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
586ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
587ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ARRAY_SIZE(ath9k_5ghz_channels);
588ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
589ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ath9k_legacy_rates + 4;
590ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
591ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ARRAY_SIZE(ath9k_legacy_rates) - 4;
592ea46e644e80bd4ac778964afd998df4f666486d4Sujith	}
593fb9987d0f748c983bb795a86f47522313f701a08Sujith}
594fb9987d0f748c983bb795a86f47522313f701a08Sujith
595fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_misc(struct ath9k_htc_priv *priv)
596fb9987d0f748c983bb795a86f47522313f701a08Sujith{
597fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
598fb9987d0f748c983bb795a86f47522313f701a08Sujith
599364734fafbba0c3133e482db78149b9a823ae7a5Felix Fietkau	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
600fb9987d0f748c983bb795a86f47522313f701a08Sujith
6019f01a84e81d10e38daa504348217895fe414a24bSujith	priv->ah->opmode = NL80211_IFTYPE_STATION;
602fb9987d0f748c983bb795a86f47522313f701a08Sujith}
603fb9987d0f748c983bb795a86f47522313f701a08Sujith
60421cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic int ath9k_init_priv(struct ath9k_htc_priv *priv,
605fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			   u16 devid, char *product,
606fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			   u32 drv_info)
607fb9987d0f748c983bb795a86f47522313f701a08Sujith{
608fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = NULL;
609fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common;
610832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan	int i, ret = 0, csz = 0;
611fb9987d0f748c983bb795a86f47522313f701a08Sujith
612fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->op_flags |= OP_INVALID;
613fb9987d0f748c983bb795a86f47522313f701a08Sujith
614fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
615fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ah)
616fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ENOMEM;
617fb9987d0f748c983bb795a86f47522313f701a08Sujith
618fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah->hw_version.devid = devid;
6190b5ead91cda63e0db964dadc77601233434f60cbSujith Manoharan	ah->hw_version.usbdev = drv_info;
620f8afa42b01c7a9f45b7cbaadb0481a0eeb96f18dFelix Fietkau	ah->ah_flags |= AH_USE_EEPROM;
621f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.read = ath9k_regread;
622f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.multi_read = ath9k_multi_regread;
623f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.write = ath9k_regwrite;
624f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
625f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	ah->reg_ops.write_flush = ath9k_regwrite_flush;
626845e03c93dda2c00ffb5c68a1f7c8efc412d7c1aFelix Fietkau	ah->reg_ops.rmw = ath9k_reg_rmw;
627fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = ah;
628fb9987d0f748c983bb795a86f47522313f701a08Sujith
629fb9987d0f748c983bb795a86f47522313f701a08Sujith	common = ath9k_hw_common(ah);
630f9f84e96f6d642aa7b337c22cbb7d6f936039fdaFelix Fietkau	common->ops = &ah->reg_ops;
631fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->bus_ops = &ath9k_usb_bus_ops;
632fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->ah = ah;
633fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->hw = priv->hw;
634fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->priv = priv;
635fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->debug_mask = ath9k_debug;
636fb9987d0f748c983bb795a86f47522313f701a08Sujith
637fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->beacon_lock);
638658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan	spin_lock_init(&priv->tx.tx_lock);
639fb9987d0f748c983bb795a86f47522313f701a08Sujith	mutex_init(&priv->mutex);
640bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	mutex_init(&priv->htc_pm_lock);
641fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
642fb9987d0f748c983bb795a86f47522313f701a08Sujith		     (unsigned long)priv);
64327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan	tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
64473908674c6957082e8ab57daed57d2bb97a1ebbaSujith Manoharan		     (unsigned long)priv);
645a236254c35f04a4d47c701ed3ec4a0b5dcb097b0Sujith Manoharan	INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
646bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	INIT_WORK(&priv->ps_work, ath9k_ps_work);
64773908674c6957082e8ab57daed57d2bb97a1ebbaSujith Manoharan	INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
648859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan	setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
649859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan		    (unsigned long)priv);
650fb9987d0f748c983bb795a86f47522313f701a08Sujith
651fb9987d0f748c983bb795a86f47522313f701a08Sujith	/*
652fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * Cache line size is used to size and align various
653fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * structures used to communicate with the hardware.
654fb9987d0f748c983bb795a86f47522313f701a08Sujith	 */
655fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath_read_cachesize(common, &csz);
656fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->cachelsz = csz << 2; /* convert to bytes */
657fb9987d0f748c983bb795a86f47522313f701a08Sujith
658fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_hw_init(ah);
659fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret) {
6603800276a40751539a920ef8e0537ef2e19126799Joe Perches		ath_err(common,
6613800276a40751539a920ef8e0537ef2e19126799Joe Perches			"Unable to initialize hardware; initialization status: %d\n",
6623800276a40751539a920ef8e0537ef2e19126799Joe Perches			ret);
663fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_hw;
664fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
665fb9987d0f748c983bb795a86f47522313f701a08Sujith
666fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_init_queues(priv);
667fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
668fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_queues;
669fb9987d0f748c983bb795a86f47522313f701a08Sujith
670832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
671832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan		priv->cur_beacon_conf.bslot[i] = NULL;
672832f6a18fc2aead14954c081ece03b7a5b425f81Sujith Manoharan
673f82b4bde17aeb6c2f8bf0540ee44811de4651cf6Rajkumar Manoharan	ath9k_cmn_init_crypto(ah);
674fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_channels_rates(priv);
675fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_misc(priv);
676cee5341d47fcd1cb79bbb71e430f502285fef8dbSujith Manoharan	ath9k_htc_init_btcoex(priv, product);
67721cb987914cb5334af78378141efed77505ea987Vivek Natarajan
678fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
679fb9987d0f748c983bb795a86f47522313f701a08Sujith
680fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_queues:
681fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_deinit(ah);
682fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_hw:
683fb9987d0f748c983bb795a86f47522313f701a08Sujith
684fb9987d0f748c983bb795a86f47522313f701a08Sujith	kfree(ah);
685fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = NULL;
686fb9987d0f748c983bb795a86f47522313f701a08Sujith
687fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
688fb9987d0f748c983bb795a86f47522313f701a08Sujith}
689fb9987d0f748c983bb795a86f47522313f701a08Sujith
690fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
691fb9987d0f748c983bb795a86f47522313f701a08Sujith			       struct ieee80211_hw *hw)
692fb9987d0f748c983bb795a86f47522313f701a08Sujith{
693fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
694fb9987d0f748c983bb795a86f47522313f701a08Sujith
695fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->flags = IEEE80211_HW_SIGNAL_DBM |
696fb9987d0f748c983bb795a86f47522313f701a08Sujith		IEEE80211_HW_AMPDU_AGGREGATION |
697fb9987d0f748c983bb795a86f47522313f701a08Sujith		IEEE80211_HW_SPECTRUM_MGMT |
69832fbccafed7e935432b601f0453c2b702a385a25Sujith		IEEE80211_HW_HAS_RATE_CONTROL |
699bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		IEEE80211_HW_RX_INCLUDES_FCS |
700bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		IEEE80211_HW_SUPPORTS_PS |
7017d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan		IEEE80211_HW_PS_NULLFUNC_STACK |
7028ae2e12f1534e647d4a816755e5a09c2de6f9fcaRajkumar Manoharan		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
7037d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
704fb9987d0f748c983bb795a86f47522313f701a08Sujith
705fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->wiphy->interface_modes =
706fb9987d0f748c983bb795a86f47522313f701a08Sujith		BIT(NL80211_IFTYPE_STATION) |
70709d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_ADHOC) |
70809d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_AP) |
70909d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_P2P_GO) |
71009d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010Sujith Manoharan		BIT(NL80211_IFTYPE_P2P_CLIENT);
711fb9987d0f748c983bb795a86f47522313f701a08Sujith
712bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
713bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
714d7d312cab41b2c973951fcc7f752411cbaaf8338Antonio Quartulli	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
715d7d312cab41b2c973951fcc7f752411cbaaf8338Antonio Quartulli
716fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->queues = 4;
717fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->channel_change_time = 5000;
718fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->max_listen_interval = 10;
7193a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan
720fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->vif_data_size = sizeof(struct ath9k_htc_vif);
721fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->sta_data_size = sizeof(struct ath9k_htc_sta);
722fb9987d0f748c983bb795a86f47522313f701a08Sujith
723fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* tx_frame_hdr is larger than tx_mgmt_hdr anyway */
724fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) +
725fb9987d0f748c983bb795a86f47522313f701a08Sujith		sizeof(struct htc_frame_hdr) + 4;
726fb9987d0f748c983bb795a86f47522313f701a08Sujith
727d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
728fb9987d0f748c983bb795a86f47522313f701a08Sujith		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
729fb9987d0f748c983bb795a86f47522313f701a08Sujith			&priv->sbands[IEEE80211_BAND_2GHZ];
730d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
731ea46e644e80bd4ac778964afd998df4f666486d4Sujith		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
732ea46e644e80bd4ac778964afd998df4f666486d4Sujith			&priv->sbands[IEEE80211_BAND_5GHZ];
733fb9987d0f748c983bb795a86f47522313f701a08Sujith
734fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
735d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
736fb9987d0f748c983bb795a86f47522313f701a08Sujith			setup_ht_cap(priv,
737fb9987d0f748c983bb795a86f47522313f701a08Sujith				     &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
738d4659912b557e9f68c0ad8be14e2cafd3210dd16Felix Fietkau		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
739ea46e644e80bd4ac778964afd998df4f666486d4Sujith			setup_ht_cap(priv,
740ea46e644e80bd4ac778964afd998df4f666486d4Sujith				     &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
741fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
742fb9987d0f748c983bb795a86f47522313f701a08Sujith
743fb9987d0f748c983bb795a86f47522313f701a08Sujith	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
744fb9987d0f748c983bb795a86f47522313f701a08Sujith}
745fb9987d0f748c983bb795a86f47522313f701a08Sujith
74629bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharanstatic int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
74729bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan{
74829bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	struct ieee80211_hw *hw = priv->hw;
74929bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	struct wmi_fw_version cmd_rsp;
75029bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	int ret;
75129bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
75229bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
75329bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
75429bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	WMI_CMD(WMI_GET_FW_VERSION);
75529bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	if (ret)
75629bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		return -EINVAL;
75729bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
75829bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
75929bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
76029bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
76129bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
76229bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_major,
76329bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_minor);
76429bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
76529bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
76629bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_major,
76729bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		 priv->fw_version_minor);
76829bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
7693a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	/*
7703a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	 * Check if the available FW matches the driver's
7713a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	 * required version.
7723a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	 */
7733a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	if (priv->fw_version_major != MAJOR_VERSION_REQ ||
7743a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	    priv->fw_version_minor != MINOR_VERSION_REQ) {
7753a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan		dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
7763a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan			MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
7773a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan		return -EINVAL;
7783a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan	}
7793a0593efd191c7eb13c79179c4c5ddbc519b2510Sujith Manoharan
78029bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	return 0;
78129bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan}
78229bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
78321cb987914cb5334af78378141efed77505ea987Vivek Natarajanstatic int ath9k_init_device(struct ath9k_htc_priv *priv,
784fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			     u16 devid, char *product, u32 drv_info)
785fb9987d0f748c983bb795a86f47522313f701a08Sujith{
786fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
787fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common;
788fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah;
789fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error = 0;
790fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_regulatory *reg;
7913e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan	char hw_name[64];
792fb9987d0f748c983bb795a86f47522313f701a08Sujith
793fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Bring up device */
794fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	error = ath9k_init_priv(priv, devid, product, drv_info);
795fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
796fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
797fb9987d0f748c983bb795a86f47522313f701a08Sujith
798fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah = priv->ah;
799fb9987d0f748c983bb795a86f47522313f701a08Sujith	common = ath9k_hw_common(ah);
800fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_set_hw_capab(priv, hw);
801fb9987d0f748c983bb795a86f47522313f701a08Sujith
80229bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	error = ath9k_init_firmware_version(priv);
80329bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	if (error != 0)
80429bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan		goto err_fw;
80529bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan
806fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Initialize regulatory */
807fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
808fb9987d0f748c983bb795a86f47522313f701a08Sujith			      ath9k_reg_notifier);
809fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error)
810fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_regd;
811fb9987d0f748c983bb795a86f47522313f701a08Sujith
812fb9987d0f748c983bb795a86f47522313f701a08Sujith	reg = &common->regulatory;
813fb9987d0f748c983bb795a86f47522313f701a08Sujith
814fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Setup TX */
815fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_tx_init(priv);
816fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
817fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_tx;
818fb9987d0f748c983bb795a86f47522313f701a08Sujith
819fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Setup RX */
820fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_rx_init(priv);
821fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
822fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_rx;
823fb9987d0f748c983bb795a86f47522313f701a08Sujith
824d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#ifdef CONFIG_MAC80211_LEDS
825d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	/* must be initialized before ieee80211_register_hw */
826d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan	priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
827d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan		IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink,
828d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan		ARRAY_SIZE(ath9k_htc_tpt_blink));
829d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan#endif
830d244f21e79162b829c9af09845421d9b4fac4253Sujith Manoharan
831fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Register with mac80211 */
832fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ieee80211_register_hw(hw);
833fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error)
834fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_register;
835fb9987d0f748c983bb795a86f47522313f701a08Sujith
836fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Handle world regulatory */
837fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath_is_world_regd(reg)) {
838fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = regulatory_hint(hw->wiphy, reg->alpha2);
839fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (error)
840fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto err_world;
841fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
842fb9987d0f748c983bb795a86f47522313f701a08Sujith
843e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	error = ath9k_htc_init_debug(priv->ah);
844e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	if (error) {
845e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan		ath_err(common, "Unable to create debugfs files\n");
846e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan		goto err_world;
847e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	}
848e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan
849d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CONFIG,
850d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, BE:%d, BK:%d, VI:%d, VO:%d\n",
8513e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->wmi_cmd_ep,
8523e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->beacon_ep,
8533e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->cab_ep,
8543e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->uapsd_ep,
8553e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->mgmt_ep,
8563e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_be_ep,
8573e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_bk_ep,
8583e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_vi_ep,
8593e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan		priv->data_vo_ep);
8603e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan
8613e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan	ath9k_hw_name(priv->ah, hw_name, sizeof(hw_name));
8623e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan	wiphy_info(hw->wiphy, "%s\n", hw_name);
8633e3f1d197f5a432b961fadb35604dba92583945eSujith Manoharan
864fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_leds(priv);
865fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_start_rfkill_poll(priv);
866fb9987d0f748c983bb795a86f47522313f701a08Sujith
867fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
868fb9987d0f748c983bb795a86f47522313f701a08Sujith
869fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_world:
870fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_unregister_hw(hw);
871fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_register:
872fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
873fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_rx:
874fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_tx_cleanup(priv);
875fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_tx:
876fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Nothing */
877fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_regd:
87829bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharan	/* Nothing */
87929bbfb2491316f9a3888e74b0de7fccdbde67aaaSujith Manoharanerr_fw:
880fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_priv(priv);
881fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init:
882fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
883fb9987d0f748c983bb795a86f47522313f701a08Sujith}
884fb9987d0f748c983bb795a86f47522313f701a08Sujith
885fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
886fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan			   u16 devid, char *product, u32 drv_info)
887fb9987d0f748c983bb795a86f47522313f701a08Sujith{
888fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw;
889fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv;
890fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
891fb9987d0f748c983bb795a86f47522313f701a08Sujith
892fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
893fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!hw)
894fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ENOMEM;
895fb9987d0f748c983bb795a86f47522313f701a08Sujith
896fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv = hw->priv;
897fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->hw = hw;
898fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->htc = htc_handle;
899fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->dev = dev;
900fb9987d0f748c983bb795a86f47522313f701a08Sujith	htc_handle->drv_priv = priv;
901fb9987d0f748c983bb795a86f47522313f701a08Sujith	SET_IEEE80211_DEV(hw, priv->dev);
902fb9987d0f748c983bb795a86f47522313f701a08Sujith
903fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_wait_for_target(priv);
904fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
905fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_free;
906fb9987d0f748c983bb795a86f47522313f701a08Sujith
907fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->wmi = ath9k_init_wmi(priv);
908fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!priv->wmi) {
909fb9987d0f748c983bb795a86f47522313f701a08Sujith		ret = -EINVAL;
910fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_free;
911fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
912fb9987d0f748c983bb795a86f47522313f701a08Sujith
913fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_init_htc_services(priv, devid, drv_info);
914fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
915fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
916fb9987d0f748c983bb795a86f47522313f701a08Sujith
917fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_init_device(priv, devid, product, drv_info);
918fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
919fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
920fb9987d0f748c983bb795a86f47522313f701a08Sujith
921fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
922fb9987d0f748c983bb795a86f47522313f701a08Sujith
923fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init:
924fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_wmi(priv);
925fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_free:
926fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_free_hw(hw);
927fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
928fb9987d0f748c983bb795a86f47522313f701a08Sujith}
929fb9987d0f748c983bb795a86f47522313f701a08Sujith
930fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
931fb9987d0f748c983bb795a86f47522313f701a08Sujith{
932fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (htc_handle->drv_priv) {
933a3be14b76da111ebe4d245b0542613f9317104e7Sujith
934a3be14b76da111ebe4d245b0542613f9317104e7Sujith		/* Check if the device has been yanked out. */
935a3be14b76da111ebe4d245b0542613f9317104e7Sujith		if (hotunplug)
93697dcec5715a381362c88d1542e52c63147764d3cSujith Manoharan			htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED;
937a3be14b76da111ebe4d245b0542613f9317104e7Sujith
938fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_deinit_device(htc_handle->drv_priv);
939fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_deinit_wmi(htc_handle->drv_priv);
940fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_free_hw(htc_handle->drv_priv->hw);
941fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
942fb9987d0f748c983bb795a86f47522313f701a08Sujith}
943fb9987d0f748c983bb795a86f47522313f701a08Sujith
944fb9987d0f748c983bb795a86f47522313f701a08Sujith#ifdef CONFIG_PM
945f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan
946f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharanvoid ath9k_htc_suspend(struct htc_target *htc_handle)
947f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan{
948f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan	ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP);
949f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan}
950f933ebed7888a9a7d73ebeeb6bcbb3f710c423b4Sujith Manoharan
951fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_resume(struct htc_target *htc_handle)
952fb9987d0f748c983bb795a86f47522313f701a08Sujith{
953fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	struct ath9k_htc_priv *priv = htc_handle->drv_priv;
954fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
955fb9987d0f748c983bb795a86f47522313f701a08Sujith
956fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_htc_wait_for_target(priv);
957fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
958fb9987d0f748c983bb795a86f47522313f701a08Sujith		return ret;
959fb9987d0f748c983bb795a86f47522313f701a08Sujith
960fa6e15e0b5952fd2cd99fc6d4f4473f6b9da18dfRajkumar Manoharan	ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,
9610b5ead91cda63e0db964dadc77601233434f60cbSujith Manoharan				      priv->ah->hw_version.usbdev);
962fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
963fb9987d0f748c983bb795a86f47522313f701a08Sujith}
964fb9987d0f748c983bb795a86f47522313f701a08Sujith#endif
965fb9987d0f748c983bb795a86f47522313f701a08Sujith
966fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int __init ath9k_htc_init(void)
967fb9987d0f748c983bb795a86f47522313f701a08Sujith{
968e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan	if (ath9k_hif_usb_init() < 0) {
969fb9987d0f748c983bb795a86f47522313f701a08Sujith		printk(KERN_ERR
970fb9987d0f748c983bb795a86f47522313f701a08Sujith			"ath9k_htc: No USB devices found,"
971fb9987d0f748c983bb795a86f47522313f701a08Sujith			" driver not installed.\n");
972e5facc75fa9104f074c4610437a9c717c9e5ecdeRajkumar Manoharan		return -ENODEV;
973fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
974fb9987d0f748c983bb795a86f47522313f701a08Sujith
975fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
976fb9987d0f748c983bb795a86f47522313f701a08Sujith}
977fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_init(ath9k_htc_init);
978fb9987d0f748c983bb795a86f47522313f701a08Sujith
979fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void __exit ath9k_htc_exit(void)
980fb9987d0f748c983bb795a86f47522313f701a08Sujith{
981fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hif_usb_exit();
982fb9987d0f748c983bb795a86f47522313f701a08Sujith	printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
983fb9987d0f748c983bb795a86f47522313f701a08Sujith}
984fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_exit(ath9k_htc_exit);
985