Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2
  3  Broadcom B43 wireless driver
  4  IEEE 802.11n HT-PHY support
  5
  6  Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
  7
  8  This program is free software; you can redistribute it and/or modify
  9  it under the terms of the GNU General Public License as published by
 10  the Free Software Foundation; either version 2 of the License, or
 11  (at your option) any later version.
 12
 13  This program is distributed in the hope that it will be useful,
 14  but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16  GNU General Public License for more details.
 17
 18  You should have received a copy of the GNU General Public License
 19  along with this program; see the file COPYING.  If not, write to
 20  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 21  Boston, MA 02110-1301, USA.
 22
 23*/
 24
 25#include <linux/slab.h>
 26
 27#include "b43.h"
 28#include "phy_ht.h"
 29#include "tables_phy_ht.h"
 30#include "radio_2059.h"
 31#include "main.h"
 32
 33/**************************************************
 34 * Radio 2059.
 35 **************************************************/
 36
 37static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
 38			const struct b43_phy_ht_channeltab_e_radio2059 *e)
 39{
 40	u8 i;
 41	u16 routing;
 42
 43	b43_radio_write(dev, 0x16, e->radio_syn16);
 44	b43_radio_write(dev, 0x17, e->radio_syn17);
 45	b43_radio_write(dev, 0x22, e->radio_syn22);
 46	b43_radio_write(dev, 0x25, e->radio_syn25);
 47	b43_radio_write(dev, 0x27, e->radio_syn27);
 48	b43_radio_write(dev, 0x28, e->radio_syn28);
 49	b43_radio_write(dev, 0x29, e->radio_syn29);
 50	b43_radio_write(dev, 0x2c, e->radio_syn2c);
 51	b43_radio_write(dev, 0x2d, e->radio_syn2d);
 52	b43_radio_write(dev, 0x37, e->radio_syn37);
 53	b43_radio_write(dev, 0x41, e->radio_syn41);
 54	b43_radio_write(dev, 0x43, e->radio_syn43);
 55	b43_radio_write(dev, 0x47, e->radio_syn47);
 56	b43_radio_write(dev, 0x4a, e->radio_syn4a);
 57	b43_radio_write(dev, 0x58, e->radio_syn58);
 58	b43_radio_write(dev, 0x5a, e->radio_syn5a);
 59	b43_radio_write(dev, 0x6a, e->radio_syn6a);
 60	b43_radio_write(dev, 0x6d, e->radio_syn6d);
 61	b43_radio_write(dev, 0x6e, e->radio_syn6e);
 62	b43_radio_write(dev, 0x92, e->radio_syn92);
 63	b43_radio_write(dev, 0x98, e->radio_syn98);
 64
 65	for (i = 0; i < 2; i++) {
 66		routing = i ? R2059_RXRX1 : R2059_TXRX0;
 67		b43_radio_write(dev, routing | 0x4a, e->radio_rxtx4a);
 68		b43_radio_write(dev, routing | 0x58, e->radio_rxtx58);
 69		b43_radio_write(dev, routing | 0x5a, e->radio_rxtx5a);
 70		b43_radio_write(dev, routing | 0x6a, e->radio_rxtx6a);
 71		b43_radio_write(dev, routing | 0x6d, e->radio_rxtx6d);
 72		b43_radio_write(dev, routing | 0x6e, e->radio_rxtx6e);
 73		b43_radio_write(dev, routing | 0x92, e->radio_rxtx92);
 74		b43_radio_write(dev, routing | 0x98, e->radio_rxtx98);
 75	}
 76
 77	udelay(50);
 78
 79	/* Calibration */
 80	b43_radio_mask(dev, 0x2b, ~0x1);
 81	b43_radio_mask(dev, 0x2e, ~0x4);
 82	b43_radio_set(dev, 0x2e, 0x4);
 83	b43_radio_set(dev, 0x2b, 0x1);
 84
 85	udelay(300);
 86}
 87
 88static void b43_radio_2059_init(struct b43_wldev *dev)
 89{
 90	const u16 routing[] = { R2059_SYN, R2059_TXRX0, R2059_RXRX1 };
 91	const u16 radio_values[3][2] = {
 92		{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
 93	};
 94	u16 i, j;
 95
 96	b43_radio_write(dev, R2059_ALL | 0x51, 0x0070);
 97	b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003);
 98
 99	for (i = 0; i < ARRAY_SIZE(routing); i++)
100		b43_radio_set(dev, routing[i] | 0x146, 0x3);
101
102	b43_radio_set(dev, 0x2e, 0x0078);
103	b43_radio_set(dev, 0xc0, 0x0080);
104	msleep(2);
105	b43_radio_mask(dev, 0x2e, ~0x0078);
106	b43_radio_mask(dev, 0xc0, ~0x0080);
107
108	if (1) { /* FIXME */
109		b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x1);
110		udelay(10);
111		b43_radio_set(dev, R2059_RXRX1 | 0x0BF, 0x1);
112		b43_radio_maskset(dev, R2059_RXRX1 | 0x19B, 0x3, 0x2);
113
114		b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x2);
115		udelay(100);
116		b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x2);
117
118		for (i = 0; i < 10000; i++) {
119			if (b43_radio_read(dev, R2059_RXRX1 | 0x145) & 1) {
120				i = 0;
121				break;
122			}
123			udelay(100);
124		}
125		if (i)
126			b43err(dev->wl, "radio 0x945 timeout\n");
127
128		b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x1);
129		b43_radio_set(dev, 0xa, 0x60);
130
131		for (i = 0; i < 3; i++) {
132			b43_radio_write(dev, 0x17F, radio_values[i][0]);
133			b43_radio_write(dev, 0x13D, 0x6E);
134			b43_radio_write(dev, 0x13E, radio_values[i][1]);
135			b43_radio_write(dev, 0x13C, 0x55);
136
137			for (j = 0; j < 10000; j++) {
138				if (b43_radio_read(dev, 0x140) & 2) {
139					j = 0;
140					break;
141				}
142				udelay(500);
143			}
144			if (j)
145				b43err(dev->wl, "radio 0x140 timeout\n");
146
147			b43_radio_write(dev, 0x13C, 0x15);
148		}
149
150		b43_radio_mask(dev, 0x17F, ~0x1);
151	}
152
153	b43_radio_mask(dev, 0x11, ~0x0008);
154}
155
156/**************************************************
157 * Various PHY ops
158 **************************************************/
159
160static void b43_phy_ht_zero_extg(struct b43_wldev *dev)
161{
162	u8 i, j;
163	u16 base[] = { 0x40, 0x60, 0x80 };
164
165	for (i = 0; i < ARRAY_SIZE(base); i++) {
166		for (j = 0; j < 4; j++)
167			b43_phy_write(dev, B43_PHY_EXTG(base[i] + j), 0);
168	}
169
170	for (i = 0; i < ARRAY_SIZE(base); i++)
171		b43_phy_write(dev, B43_PHY_EXTG(base[i] + 0xc), 0);
172}
173
174/* Some unknown AFE (Analog Frondned) op */
175static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
176{
177	u8 i;
178
179	const u16 ctl_regs[3][2] = {
180		{ B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 },
181		{ B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 },
182		{ B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6},
183	};
184
185	for (i = 0; i < 3; i++) {
186		/* TODO: verify masks&sets */
187		b43_phy_set(dev, ctl_regs[i][1], 0x4);
188		b43_phy_set(dev, ctl_regs[i][0], 0x4);
189		b43_phy_mask(dev, ctl_regs[i][1], ~0x1);
190		b43_phy_set(dev, ctl_regs[i][0], 0x1);
191		b43_httab_write(dev, B43_HTTAB16(8, 5 + (i * 0x10)), 0);
192		b43_phy_mask(dev, ctl_regs[i][0], ~0x4);
193	}
194}
195
196static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
197{
198	u8 i;
199
200	u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
201	b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
202
203	b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
204	for (i = 0; i < 200; i++) {
205		if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
206			i = 0;
207			break;
208		}
209		msleep(1);
210	}
211	if (i)
212		b43err(dev->wl, "Forcing RF sequence timeout\n");
213
214	b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
215}
216
217static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
218{
219	clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES);
220	clip_st[1] = b43_phy_read(dev, B43_PHY_HT_C2_CLIP1THRES);
221	clip_st[2] = b43_phy_read(dev, B43_PHY_HT_C3_CLIP1THRES);
222}
223
224static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
225{
226	unsigned int i;
227	u16 val;
228
229	val = 0x1E1F;
230	for (i = 0; i < 16; i++) {
231		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
232		val -= 0x202;
233	}
234	val = 0x3E3F;
235	for (i = 0; i < 16; i++) {
236		b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
237		val -= 0x202;
238	}
239	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
240}
241
242/**************************************************
243 * Channel switching ops.
244 **************************************************/
245
246static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
247				const struct b43_phy_ht_channeltab_e_phy *e,
248				struct ieee80211_channel *new_channel)
249{
250	bool old_band_5ghz;
251	u8 i;
252
253	old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
254	if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
255		/* TODO */
256	} else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
257		/* TODO */
258	}
259
260	b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1);
261	b43_phy_write(dev, B43_PHY_HT_BW2, e->bw2);
262	b43_phy_write(dev, B43_PHY_HT_BW3, e->bw3);
263	b43_phy_write(dev, B43_PHY_HT_BW4, e->bw4);
264	b43_phy_write(dev, B43_PHY_HT_BW5, e->bw5);
265	b43_phy_write(dev, B43_PHY_HT_BW6, e->bw6);
266
267	/* TODO: some ops on PHY regs 0x0B0 and 0xC0A */
268
269	/* TODO: separated function? */
270	for (i = 0; i < 3; i++) {
271		u16 mask;
272		u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
273
274		if (0) /* FIXME */
275			mask = 0x2 << (i * 4);
276		else
277			mask = 0;
278		b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
279
280		b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
281		b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
282				tmp & 0xFF);
283		b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
284				tmp & 0xFF);
285	}
286
287	b43_phy_write(dev, 0x017e, 0x3830);
288}
289
290static int b43_phy_ht_set_channel(struct b43_wldev *dev,
291				  struct ieee80211_channel *channel,
292				  enum nl80211_channel_type channel_type)
293{
294	struct b43_phy *phy = &dev->phy;
295
296	const struct b43_phy_ht_channeltab_e_radio2059 *chent_r2059 = NULL;
297
298	if (phy->radio_ver == 0x2059) {
299		chent_r2059 = b43_phy_ht_get_channeltab_e_r2059(dev,
300							channel->center_freq);
301		if (!chent_r2059)
302			return -ESRCH;
303	} else {
304		return -ESRCH;
305	}
306
307	/* TODO: In case of N-PHY some bandwidth switching goes here */
308
309	if (phy->radio_ver == 0x2059) {
310		b43_radio_2059_channel_setup(dev, chent_r2059);
311		b43_phy_ht_channel_setup(dev, &(chent_r2059->phy_regs),
312					 channel);
313	} else {
314		return -ESRCH;
315	}
316
317	return 0;
318}
319
320/**************************************************
321 * Basic PHY ops.
322 **************************************************/
323
324static int b43_phy_ht_op_allocate(struct b43_wldev *dev)
325{
326	struct b43_phy_ht *phy_ht;
327
328	phy_ht = kzalloc(sizeof(*phy_ht), GFP_KERNEL);
329	if (!phy_ht)
330		return -ENOMEM;
331	dev->phy.ht = phy_ht;
332
333	return 0;
334}
335
336static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev)
337{
338	struct b43_phy *phy = &dev->phy;
339	struct b43_phy_ht *phy_ht = phy->ht;
340
341	memset(phy_ht, 0, sizeof(*phy_ht));
342}
343
344static int b43_phy_ht_op_init(struct b43_wldev *dev)
345{
346	u16 tmp;
347	u16 clip_state[3];
348
349	b43_phy_ht_tables_init(dev);
350
351	b43_phy_mask(dev, 0x0be, ~0x2);
352	b43_phy_set(dev, 0x23f, 0x7ff);
353	b43_phy_set(dev, 0x240, 0x7ff);
354	b43_phy_set(dev, 0x241, 0x7ff);
355
356	b43_phy_ht_zero_extg(dev);
357
358	b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3);
359
360	b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0);
361	b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0);
362	b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0);
363
364	b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20);
365	b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20);
366	b43_phy_write(dev, 0x20d, 0xb8);
367	b43_phy_write(dev, B43_PHY_EXTG(0x14f), 0xc8);
368	b43_phy_write(dev, 0x70, 0x50);
369	b43_phy_write(dev, 0x1ff, 0x30);
370
371	if (0) /* TODO: condition */
372		; /* TODO: PHY op on reg 0x217 */
373
374	b43_phy_read(dev, 0xb0); /* TODO: what for? */
375	b43_phy_set(dev, 0xb0, 0x1);
376
377	b43_phy_set(dev, 0xb1, 0x91);
378	b43_phy_write(dev, 0x32f, 0x0003);
379	b43_phy_write(dev, 0x077, 0x0010);
380	b43_phy_write(dev, 0x0b4, 0x0258);
381	b43_phy_mask(dev, 0x17e, ~0x4000);
382
383	b43_phy_write(dev, 0x0b9, 0x0072);
384
385	b43_httab_write_few(dev, B43_HTTAB16(7, 0x14e), 2, 0x010f, 0x010f);
386	b43_httab_write_few(dev, B43_HTTAB16(7, 0x15e), 2, 0x010f, 0x010f);
387	b43_httab_write_few(dev, B43_HTTAB16(7, 0x16e), 2, 0x010f, 0x010f);
388
389	b43_phy_ht_afe_unk1(dev);
390
391	b43_httab_write_few(dev, B43_HTTAB16(7, 0x130), 9, 0x777, 0x111, 0x111,
392			    0x777, 0x111, 0x111, 0x777, 0x111, 0x111);
393
394	b43_httab_write(dev, B43_HTTAB16(7, 0x120), 0x0777);
395	b43_httab_write(dev, B43_HTTAB16(7, 0x124), 0x0777);
396
397	b43_httab_write(dev, B43_HTTAB16(8, 0x00), 0x02);
398	b43_httab_write(dev, B43_HTTAB16(8, 0x10), 0x02);
399	b43_httab_write(dev, B43_HTTAB16(8, 0x20), 0x02);
400
401	b43_httab_write_few(dev, B43_HTTAB16(8, 0x08), 4,
402			    0x8e, 0x96, 0x96, 0x96);
403	b43_httab_write_few(dev, B43_HTTAB16(8, 0x18), 4,
404			    0x8f, 0x9f, 0x9f, 0x9f);
405	b43_httab_write_few(dev, B43_HTTAB16(8, 0x28), 4,
406			    0x8f, 0x9f, 0x9f, 0x9f);
407
408	b43_httab_write_few(dev, B43_HTTAB16(8, 0x0c), 4, 0x2, 0x2, 0x2, 0x2);
409	b43_httab_write_few(dev, B43_HTTAB16(8, 0x1c), 4, 0x2, 0x2, 0x2, 0x2);
410	b43_httab_write_few(dev, B43_HTTAB16(8, 0x2c), 4, 0x2, 0x2, 0x2, 0x2);
411
412	b43_phy_maskset(dev, 0x0280, 0xff00, 0x3e);
413	b43_phy_maskset(dev, 0x0283, 0xff00, 0x3e);
414	b43_phy_maskset(dev, B43_PHY_OFDM(0x0141), 0xff00, 0x46);
415	b43_phy_maskset(dev, 0x0283, 0xff00, 0x40);
416
417	b43_httab_write_few(dev, B43_HTTAB16(00, 0x8), 4,
418			    0x09, 0x0e, 0x13, 0x18);
419	b43_httab_write_few(dev, B43_HTTAB16(01, 0x8), 4,
420			    0x09, 0x0e, 0x13, 0x18);
421	/* TODO: Did wl mean 2 instead of 40? */
422	b43_httab_write_few(dev, B43_HTTAB16(40, 0x8), 4,
423			    0x09, 0x0e, 0x13, 0x18);
424
425	b43_phy_maskset(dev, B43_PHY_OFDM(0x24), 0x3f, 0xd);
426	b43_phy_maskset(dev, B43_PHY_OFDM(0x64), 0x3f, 0xd);
427	b43_phy_maskset(dev, B43_PHY_OFDM(0xa4), 0x3f, 0xd);
428
429	b43_phy_set(dev, B43_PHY_EXTG(0x060), 0x1);
430	b43_phy_set(dev, B43_PHY_EXTG(0x064), 0x1);
431	b43_phy_set(dev, B43_PHY_EXTG(0x080), 0x1);
432	b43_phy_set(dev, B43_PHY_EXTG(0x084), 0x1);
433
434	/* Copy some tables entries */
435	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x144));
436	b43_httab_write(dev, B43_HTTAB16(7, 0x14a), tmp);
437	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x154));
438	b43_httab_write(dev, B43_HTTAB16(7, 0x15a), tmp);
439	tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x164));
440	b43_httab_write(dev, B43_HTTAB16(7, 0x16a), tmp);
441
442	/* Reset CCA */
443	b43_phy_force_clock(dev, true);
444	tmp = b43_phy_read(dev, B43_PHY_HT_BBCFG);
445	b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp | B43_PHY_HT_BBCFG_RSTCCA);
446	b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp & ~B43_PHY_HT_BBCFG_RSTCCA);
447	b43_phy_force_clock(dev, false);
448
449	b43_mac_phy_clock_set(dev, true);
450
451	b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX);
452	b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
453
454	/* TODO: PHY op on reg 0xb0 */
455
456	/* TODO: Should we restore it? Or store it in global PHY info? */
457	b43_phy_ht_read_clip_detection(dev, clip_state);
458
459	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
460		b43_phy_ht_bphy_init(dev);
461
462	b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0),
463			B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late);
464
465	return 0;
466}
467
468static void b43_phy_ht_op_free(struct b43_wldev *dev)
469{
470	struct b43_phy *phy = &dev->phy;
471	struct b43_phy_ht *phy_ht = phy->ht;
472
473	kfree(phy_ht);
474	phy->ht = NULL;
475}
476
477/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */
478static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
479					bool blocked)
480{
481	if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
482		b43err(dev->wl, "MAC not suspended\n");
483
484	/* In the following PHY ops we copy wl's dummy behaviour.
485	 * TODO: Find out if reads (currently hidden in masks/masksets) are
486	 * needed and replace following ops with just writes or w&r.
487	 * Note: B43_PHY_HT_RF_CTL1 register is tricky, wrong operation can
488	 * cause delayed (!) machine lock up. */
489	if (blocked) {
490		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
491	} else {
492		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
493		b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x1);
494		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
495		b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x2);
496
497		if (dev->phy.radio_ver == 0x2059)
498			b43_radio_2059_init(dev);
499		else
500			B43_WARN_ON(1);
501
502		b43_switch_channel(dev, dev->phy.channel);
503	}
504}
505
506static void b43_phy_ht_op_switch_analog(struct b43_wldev *dev, bool on)
507{
508	if (on) {
509		b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00cd);
510		b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x0000);
511		b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00cd);
512		b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x0000);
513		b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00cd);
514		b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x0000);
515	} else {
516		b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x07ff);
517		b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00fd);
518		b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x07ff);
519		b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00fd);
520		b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x07ff);
521		b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00fd);
522	}
523}
524
525static int b43_phy_ht_op_switch_channel(struct b43_wldev *dev,
526					unsigned int new_channel)
527{
528	struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
529	enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
530
531	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
532		if ((new_channel < 1) || (new_channel > 14))
533			return -EINVAL;
534	} else {
535		return -EINVAL;
536	}
537
538	return b43_phy_ht_set_channel(dev, channel, channel_type);
539}
540
541static unsigned int b43_phy_ht_op_get_default_chan(struct b43_wldev *dev)
542{
543	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
544		return 11;
545	return 36;
546}
547
548/**************************************************
549 * R/W ops.
550 **************************************************/
551
552static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg)
553{
554	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
555	return b43_read16(dev, B43_MMIO_PHY_DATA);
556}
557
558static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value)
559{
560	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
561	b43_write16(dev, B43_MMIO_PHY_DATA, value);
562}
563
564static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
565				 u16 set)
566{
567	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
568	b43_write16(dev, B43_MMIO_PHY_DATA,
569		    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
570}
571
572static u16 b43_phy_ht_op_radio_read(struct b43_wldev *dev, u16 reg)
573{
574	/* HT-PHY needs 0x200 for read access */
575	reg |= 0x200;
576
577	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
578	return b43_read16(dev, B43_MMIO_RADIO24_DATA);
579}
580
581static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
582				      u16 value)
583{
584	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
585	b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
586}
587
588static enum b43_txpwr_result
589b43_phy_ht_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
590{
591	return B43_TXPWR_RES_DONE;
592}
593
594static void b43_phy_ht_op_adjust_txpower(struct b43_wldev *dev)
595{
596}
597
598/**************************************************
599 * PHY ops struct.
600 **************************************************/
601
602const struct b43_phy_operations b43_phyops_ht = {
603	.allocate		= b43_phy_ht_op_allocate,
604	.free			= b43_phy_ht_op_free,
605	.prepare_structs	= b43_phy_ht_op_prepare_structs,
606	.init			= b43_phy_ht_op_init,
607	.phy_read		= b43_phy_ht_op_read,
608	.phy_write		= b43_phy_ht_op_write,
609	.phy_maskset		= b43_phy_ht_op_maskset,
610	.radio_read		= b43_phy_ht_op_radio_read,
611	.radio_write		= b43_phy_ht_op_radio_write,
612	.software_rfkill	= b43_phy_ht_op_software_rfkill,
613	.switch_analog		= b43_phy_ht_op_switch_analog,
614	.switch_channel		= b43_phy_ht_op_switch_channel,
615	.get_default_chan	= b43_phy_ht_op_get_default_chan,
616	.recalc_txpower		= b43_phy_ht_op_recalc_txpower,
617	.adjust_txpower		= b43_phy_ht_op_adjust_txpower,
618};