diff options
Diffstat (limited to 'drivers/net/wireless/b43/phy_a.c')
-rw-r--r-- | drivers/net/wireless/b43/phy_a.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c new file mode 100644 index 00000000000..dd347314b76 --- /dev/null +++ b/drivers/net/wireless/b43/phy_a.c | |||
@@ -0,0 +1,536 @@ | |||
1 | /* | ||
2 | |||
3 | Broadcom B43 wireless driver | ||
4 | IEEE 802.11a PHY driver | ||
5 | |||
6 | Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, | ||
7 | Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> | ||
8 | Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de> | ||
9 | Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> | ||
10 | Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2 of the License, or | ||
15 | (at your option) any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; see the file COPYING. If not, write to | ||
24 | the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, | ||
25 | Boston, MA 02110-1301, USA. | ||
26 | |||
27 | */ | ||
28 | |||
29 | #include "b43.h" | ||
30 | #include "phy_a.h" | ||
31 | #include "phy_common.h" | ||
32 | #include "wa.h" | ||
33 | #include "tables.h" | ||
34 | #include "main.h" | ||
35 | |||
36 | |||
37 | /* Get the freq, as it has to be written to the device. */ | ||
38 | static inline u16 channel2freq_a(u8 channel) | ||
39 | { | ||
40 | B43_WARN_ON(channel > 200); | ||
41 | |||
42 | return (5000 + 5 * channel); | ||
43 | } | ||
44 | |||
45 | static inline u16 freq_r3A_value(u16 frequency) | ||
46 | { | ||
47 | u16 value; | ||
48 | |||
49 | if (frequency < 5091) | ||
50 | value = 0x0040; | ||
51 | else if (frequency < 5321) | ||
52 | value = 0x0000; | ||
53 | else if (frequency < 5806) | ||
54 | value = 0x0080; | ||
55 | else | ||
56 | value = 0x0040; | ||
57 | |||
58 | return value; | ||
59 | } | ||
60 | |||
61 | void b43_radio_set_tx_iq(struct b43_wldev *dev) | ||
62 | { | ||
63 | static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; | ||
64 | static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; | ||
65 | u16 tmp = b43_radio_read16(dev, 0x001E); | ||
66 | int i, j; | ||
67 | |||
68 | for (i = 0; i < 5; i++) { | ||
69 | for (j = 0; j < 5; j++) { | ||
70 | if (tmp == (data_high[i] << 4 | data_low[j])) { | ||
71 | b43_phy_write(dev, 0x0069, | ||
72 | (i - j) << 8 | 0x00C0); | ||
73 | return; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) | ||
80 | { | ||
81 | u16 freq, r8, tmp; | ||
82 | |||
83 | freq = channel2freq_a(channel); | ||
84 | |||
85 | r8 = b43_radio_read16(dev, 0x0008); | ||
86 | b43_write16(dev, 0x03F0, freq); | ||
87 | b43_radio_write16(dev, 0x0008, r8); | ||
88 | |||
89 | //TODO: write max channel TX power? to Radio 0x2D | ||
90 | tmp = b43_radio_read16(dev, 0x002E); | ||
91 | tmp &= 0x0080; | ||
92 | //TODO: OR tmp with the Power out estimation for this channel? | ||
93 | b43_radio_write16(dev, 0x002E, tmp); | ||
94 | |||
95 | if (freq >= 4920 && freq <= 5500) { | ||
96 | /* | ||
97 | * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; | ||
98 | * = (freq * 0.025862069 | ||
99 | */ | ||
100 | r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ | ||
101 | } | ||
102 | b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); | ||
103 | b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); | ||
104 | b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); | ||
105 | b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) | ||
106 | & 0x000F) | (r8 << 4)); | ||
107 | b43_radio_write16(dev, 0x002A, (r8 << 4)); | ||
108 | b43_radio_write16(dev, 0x002B, (r8 << 4)); | ||
109 | b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) | ||
110 | & 0x00F0) | (r8 << 4)); | ||
111 | b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) | ||
112 | & 0xFF0F) | 0x00B0); | ||
113 | b43_radio_write16(dev, 0x0035, 0x00AA); | ||
114 | b43_radio_write16(dev, 0x0036, 0x0085); | ||
115 | b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) | ||
116 | & 0xFF20) | | ||
117 | freq_r3A_value(freq)); | ||
118 | b43_radio_write16(dev, 0x003D, | ||
119 | b43_radio_read16(dev, 0x003D) & 0x00FF); | ||
120 | b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) | ||
121 | & 0xFF7F) | 0x0080); | ||
122 | b43_radio_write16(dev, 0x0035, | ||
123 | b43_radio_read16(dev, 0x0035) & 0xFFEF); | ||
124 | b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) | ||
125 | & 0xFFEF) | 0x0010); | ||
126 | b43_radio_set_tx_iq(dev); | ||
127 | //TODO: TSSI2dbm workaround | ||
128 | //FIXME b43_phy_xmitpower(dev); | ||
129 | } | ||
130 | |||
131 | void b43_radio_init2060(struct b43_wldev *dev) | ||
132 | { | ||
133 | b43_radio_write16(dev, 0x0004, 0x00C0); | ||
134 | b43_radio_write16(dev, 0x0005, 0x0008); | ||
135 | b43_radio_write16(dev, 0x0009, 0x0040); | ||
136 | b43_radio_write16(dev, 0x0005, 0x00AA); | ||
137 | b43_radio_write16(dev, 0x0032, 0x008F); | ||
138 | b43_radio_write16(dev, 0x0006, 0x008F); | ||
139 | b43_radio_write16(dev, 0x0034, 0x008F); | ||
140 | b43_radio_write16(dev, 0x002C, 0x0007); | ||
141 | b43_radio_write16(dev, 0x0082, 0x0080); | ||
142 | b43_radio_write16(dev, 0x0080, 0x0000); | ||
143 | b43_radio_write16(dev, 0x003F, 0x00DA); | ||
144 | b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); | ||
145 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); | ||
146 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); | ||
147 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); | ||
148 | msleep(1); /* delay 400usec */ | ||
149 | |||
150 | b43_radio_write16(dev, 0x0081, | ||
151 | (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); | ||
152 | msleep(1); /* delay 400usec */ | ||
153 | |||
154 | b43_radio_write16(dev, 0x0005, | ||
155 | (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); | ||
156 | b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); | ||
157 | b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); | ||
158 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); | ||
159 | b43_radio_write16(dev, 0x0081, | ||
160 | (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); | ||
161 | b43_radio_write16(dev, 0x0005, | ||
162 | (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); | ||
163 | b43_phy_write(dev, 0x0063, 0xDDC6); | ||
164 | b43_phy_write(dev, 0x0069, 0x07BE); | ||
165 | b43_phy_write(dev, 0x006A, 0x0000); | ||
166 | |||
167 | aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev)); | ||
168 | |||
169 | msleep(1); | ||
170 | } | ||
171 | |||
172 | static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) | ||
173 | { | ||
174 | int i; | ||
175 | |||
176 | if (dev->phy.rev < 3) { | ||
177 | if (enable) | ||
178 | for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { | ||
179 | b43_ofdmtab_write16(dev, | ||
180 | B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); | ||
181 | b43_ofdmtab_write16(dev, | ||
182 | B43_OFDMTAB_WRSSI, i, 0xFFF8); | ||
183 | } | ||
184 | else | ||
185 | for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { | ||
186 | b43_ofdmtab_write16(dev, | ||
187 | B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); | ||
188 | b43_ofdmtab_write16(dev, | ||
189 | B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); | ||
190 | } | ||
191 | } else { | ||
192 | if (enable) | ||
193 | for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) | ||
194 | b43_ofdmtab_write16(dev, | ||
195 | B43_OFDMTAB_WRSSI, i, 0x0820); | ||
196 | else | ||
197 | for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) | ||
198 | b43_ofdmtab_write16(dev, | ||
199 | B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static void b43_phy_ww(struct b43_wldev *dev) | ||
204 | { | ||
205 | u16 b, curr_s, best_s = 0xFFFF; | ||
206 | int i; | ||
207 | |||
208 | b43_phy_write(dev, B43_PHY_CRS0, | ||
209 | b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); | ||
210 | b43_phy_write(dev, B43_PHY_OFDM(0x1B), | ||
211 | b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); | ||
212 | b43_phy_write(dev, B43_PHY_OFDM(0x82), | ||
213 | (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); | ||
214 | b43_radio_write16(dev, 0x0009, | ||
215 | b43_radio_read16(dev, 0x0009) | 0x0080); | ||
216 | b43_radio_write16(dev, 0x0012, | ||
217 | (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); | ||
218 | b43_wa_initgains(dev); | ||
219 | b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); | ||
220 | b = b43_phy_read(dev, B43_PHY_PWRDOWN); | ||
221 | b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); | ||
222 | b43_radio_write16(dev, 0x0004, | ||
223 | b43_radio_read16(dev, 0x0004) | 0x0004); | ||
224 | for (i = 0x10; i <= 0x20; i++) { | ||
225 | b43_radio_write16(dev, 0x0013, i); | ||
226 | curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; | ||
227 | if (!curr_s) { | ||
228 | best_s = 0x0000; | ||
229 | break; | ||
230 | } else if (curr_s >= 0x0080) | ||
231 | curr_s = 0x0100 - curr_s; | ||
232 | if (curr_s < best_s) | ||
233 | best_s = curr_s; | ||
234 | } | ||
235 | b43_phy_write(dev, B43_PHY_PWRDOWN, b); | ||
236 | b43_radio_write16(dev, 0x0004, | ||
237 | b43_radio_read16(dev, 0x0004) & 0xFFFB); | ||
238 | b43_radio_write16(dev, 0x0013, best_s); | ||
239 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); | ||
240 | b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); | ||
241 | b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); | ||
242 | b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); | ||
243 | b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); | ||
244 | b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); | ||
245 | b43_phy_write(dev, B43_PHY_OFDM(0xBB), | ||
246 | (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); | ||
247 | b43_phy_write(dev, B43_PHY_OFDM61, | ||
248 | (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); | ||
249 | b43_phy_write(dev, B43_PHY_OFDM(0x13), | ||
250 | (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); | ||
251 | b43_phy_write(dev, B43_PHY_OFDM(0x14), | ||
252 | (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); | ||
253 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); | ||
254 | for (i = 0; i < 6; i++) | ||
255 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); | ||
256 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); | ||
257 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); | ||
258 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); | ||
259 | b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); | ||
260 | b43_phy_write(dev, B43_PHY_CRS0, | ||
261 | b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); | ||
262 | } | ||
263 | |||
264 | static void hardware_pctl_init_aphy(struct b43_wldev *dev) | ||
265 | { | ||
266 | //TODO | ||
267 | } | ||
268 | |||
269 | void b43_phy_inita(struct b43_wldev *dev) | ||
270 | { | ||
271 | struct ssb_bus *bus = dev->dev->bus; | ||
272 | struct b43_phy *phy = &dev->phy; | ||
273 | |||
274 | /* This lowlevel A-PHY init is also called from G-PHY init. | ||
275 | * So we must not access phy->a, if called from G-PHY code. | ||
276 | */ | ||
277 | B43_WARN_ON((phy->type != B43_PHYTYPE_A) && | ||
278 | (phy->type != B43_PHYTYPE_G)); | ||
279 | |||
280 | might_sleep(); | ||
281 | |||
282 | if (phy->rev >= 6) { | ||
283 | if (phy->type == B43_PHYTYPE_A) | ||
284 | b43_phy_write(dev, B43_PHY_OFDM(0x1B), | ||
285 | b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); | ||
286 | if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) | ||
287 | b43_phy_write(dev, B43_PHY_ENCORE, | ||
288 | b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); | ||
289 | else | ||
290 | b43_phy_write(dev, B43_PHY_ENCORE, | ||
291 | b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); | ||
292 | } | ||
293 | |||
294 | b43_wa_all(dev); | ||
295 | |||
296 | if (phy->type == B43_PHYTYPE_A) { | ||
297 | if (phy->gmode && (phy->rev < 3)) | ||
298 | b43_phy_write(dev, 0x0034, | ||
299 | b43_phy_read(dev, 0x0034) | 0x0001); | ||
300 | b43_phy_rssiagc(dev, 0); | ||
301 | |||
302 | b43_phy_write(dev, B43_PHY_CRS0, | ||
303 | b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); | ||
304 | |||
305 | b43_radio_init2060(dev); | ||
306 | |||
307 | if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && | ||
308 | ((bus->boardinfo.type == SSB_BOARD_BU4306) || | ||
309 | (bus->boardinfo.type == SSB_BOARD_BU4309))) { | ||
310 | ; //TODO: A PHY LO | ||
311 | } | ||
312 | |||
313 | if (phy->rev >= 3) | ||
314 | b43_phy_ww(dev); | ||
315 | |||
316 | hardware_pctl_init_aphy(dev); | ||
317 | |||
318 | //TODO: radar detection | ||
319 | } | ||
320 | |||
321 | if ((phy->type == B43_PHYTYPE_G) && | ||
322 | (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { | ||
323 | b43_phy_write(dev, B43_PHY_OFDM(0x6E), | ||
324 | (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) | ||
325 | & 0xE000) | 0x3CF); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | static int b43_aphy_op_allocate(struct b43_wldev *dev) | ||
330 | { | ||
331 | struct b43_phy_a *aphy; | ||
332 | |||
333 | aphy = kzalloc(sizeof(*aphy), GFP_KERNEL); | ||
334 | if (!aphy) | ||
335 | return -ENOMEM; | ||
336 | dev->phy.a = aphy; | ||
337 | |||
338 | //TODO init struct b43_phy_a | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int b43_aphy_op_init(struct b43_wldev *dev) | ||
344 | { | ||
345 | struct b43_phy_a *aphy = dev->phy.a; | ||
346 | |||
347 | b43_phy_inita(dev); | ||
348 | aphy->initialised = 1; | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static void b43_aphy_op_exit(struct b43_wldev *dev) | ||
354 | { | ||
355 | struct b43_phy_a *aphy = dev->phy.a; | ||
356 | |||
357 | if (aphy->initialised) { | ||
358 | //TODO | ||
359 | aphy->initialised = 0; | ||
360 | } | ||
361 | //TODO | ||
362 | kfree(aphy); | ||
363 | dev->phy.a = NULL; | ||
364 | } | ||
365 | |||
366 | static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset) | ||
367 | { | ||
368 | /* OFDM registers are base-registers for the A-PHY. */ | ||
369 | if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { | ||
370 | offset &= ~B43_PHYROUTE; | ||
371 | offset |= B43_PHYROUTE_BASE; | ||
372 | } | ||
373 | |||
374 | #if B43_DEBUG | ||
375 | if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { | ||
376 | /* Ext-G registers are only available on G-PHYs */ | ||
377 | b43err(dev->wl, "Invalid EXT-G PHY access at " | ||
378 | "0x%04X on A-PHY\n", offset); | ||
379 | dump_stack(); | ||
380 | } | ||
381 | if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { | ||
382 | /* N-BMODE registers are only available on N-PHYs */ | ||
383 | b43err(dev->wl, "Invalid N-BMODE PHY access at " | ||
384 | "0x%04X on A-PHY\n", offset); | ||
385 | dump_stack(); | ||
386 | } | ||
387 | #endif /* B43_DEBUG */ | ||
388 | |||
389 | return offset; | ||
390 | } | ||
391 | |||
392 | static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg) | ||
393 | { | ||
394 | reg = adjust_phyreg(dev, reg); | ||
395 | b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); | ||
396 | return b43_read16(dev, B43_MMIO_PHY_DATA); | ||
397 | } | ||
398 | |||
399 | static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) | ||
400 | { | ||
401 | reg = adjust_phyreg(dev, reg); | ||
402 | b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); | ||
403 | b43_write16(dev, B43_MMIO_PHY_DATA, value); | ||
404 | } | ||
405 | |||
406 | static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg) | ||
407 | { | ||
408 | /* Register 1 is a 32-bit register. */ | ||
409 | B43_WARN_ON(reg == 1); | ||
410 | /* A-PHY needs 0x40 for read access */ | ||
411 | reg |= 0x40; | ||
412 | |||
413 | b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); | ||
414 | return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); | ||
415 | } | ||
416 | |||
417 | static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) | ||
418 | { | ||
419 | /* Register 1 is a 32-bit register. */ | ||
420 | B43_WARN_ON(reg == 1); | ||
421 | |||
422 | b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); | ||
423 | b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); | ||
424 | } | ||
425 | |||
426 | static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) | ||
427 | { | ||
428 | return (dev->phy.rev >= 5); | ||
429 | } | ||
430 | |||
431 | static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, | ||
432 | enum rfkill_state state) | ||
433 | {//TODO | ||
434 | } | ||
435 | |||
436 | static int b43_aphy_op_switch_channel(struct b43_wldev *dev, | ||
437 | unsigned int new_channel) | ||
438 | { | ||
439 | if (new_channel > 200) | ||
440 | return -EINVAL; | ||
441 | aphy_channel_switch(dev, new_channel); | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev) | ||
447 | { | ||
448 | return 36; /* Default to channel 36 */ | ||
449 | } | ||
450 | |||
451 | static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) | ||
452 | {//TODO | ||
453 | struct b43_phy *phy = &dev->phy; | ||
454 | u64 hf; | ||
455 | u16 tmp; | ||
456 | int autodiv = 0; | ||
457 | |||
458 | if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) | ||
459 | autodiv = 1; | ||
460 | |||
461 | hf = b43_hf_read(dev); | ||
462 | hf &= ~B43_HF_ANTDIVHELP; | ||
463 | b43_hf_write(dev, hf); | ||
464 | |||
465 | tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); | ||
466 | tmp &= ~B43_PHY_BBANDCFG_RXANT; | ||
467 | tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) | ||
468 | << B43_PHY_BBANDCFG_RXANT_SHIFT; | ||
469 | b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); | ||
470 | |||
471 | if (autodiv) { | ||
472 | tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); | ||
473 | if (antenna == B43_ANTENNA_AUTO0) | ||
474 | tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; | ||
475 | else | ||
476 | tmp |= B43_PHY_ANTDWELL_AUTODIV1; | ||
477 | b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); | ||
478 | } | ||
479 | if (phy->rev < 3) { | ||
480 | tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); | ||
481 | tmp = (tmp & 0xFF00) | 0x24; | ||
482 | b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); | ||
483 | } else { | ||
484 | tmp = b43_phy_read(dev, B43_PHY_OFDM61); | ||
485 | tmp |= 0x10; | ||
486 | b43_phy_write(dev, B43_PHY_OFDM61, tmp); | ||
487 | if (phy->analog == 3) { | ||
488 | b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, | ||
489 | 0x1D); | ||
490 | b43_phy_write(dev, B43_PHY_ADIVRELATED, | ||
491 | 8); | ||
492 | } else { | ||
493 | b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, | ||
494 | 0x3A); | ||
495 | tmp = | ||
496 | b43_phy_read(dev, | ||
497 | B43_PHY_ADIVRELATED); | ||
498 | tmp = (tmp & 0xFF00) | 8; | ||
499 | b43_phy_write(dev, B43_PHY_ADIVRELATED, | ||
500 | tmp); | ||
501 | } | ||
502 | } | ||
503 | |||
504 | hf |= B43_HF_ANTDIVHELP; | ||
505 | b43_hf_write(dev, hf); | ||
506 | } | ||
507 | |||
508 | static void b43_aphy_op_xmitpower(struct b43_wldev *dev) | ||
509 | {//TODO | ||
510 | } | ||
511 | |||
512 | static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) | ||
513 | {//TODO | ||
514 | } | ||
515 | |||
516 | static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev) | ||
517 | {//TODO | ||
518 | } | ||
519 | |||
520 | const struct b43_phy_operations b43_phyops_a = { | ||
521 | .allocate = b43_aphy_op_allocate, | ||
522 | .init = b43_aphy_op_init, | ||
523 | .exit = b43_aphy_op_exit, | ||
524 | .phy_read = b43_aphy_op_read, | ||
525 | .phy_write = b43_aphy_op_write, | ||
526 | .radio_read = b43_aphy_op_radio_read, | ||
527 | .radio_write = b43_aphy_op_radio_write, | ||
528 | .supports_hwpctl = b43_aphy_op_supports_hwpctl, | ||
529 | .software_rfkill = b43_aphy_op_software_rfkill, | ||
530 | .switch_channel = b43_aphy_op_switch_channel, | ||
531 | .get_default_chan = b43_aphy_op_get_default_chan, | ||
532 | .set_rx_antenna = b43_aphy_op_set_rx_antenna, | ||
533 | .xmitpower = b43_aphy_op_xmitpower, | ||
534 | .pwork_15sec = b43_aphy_op_pwork_15sec, | ||
535 | .pwork_60sec = b43_aphy_op_pwork_60sec, | ||
536 | }; | ||