xref: /illumos-gate/usr/src/uts/common/io/rtw/rtwphy.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 /*
6  * Copyright (c) 2004, 2005 David Young.  All rights reserved.
7  *
8  * Programmed for NetBSD by David Young.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of David Young may not be used to endorse or promote
19  *    products derived from this software without specific prior
20  *    written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL David
26  * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33  * OF SUCH DAMAGE.
34  */
35 /*
36  * Control the Philips SA2400 RF front-end and the baseband processor
37  * built into the Realtek RTL8180.
38  */
39 #pragma ident	"%Z%%M%	%I%	%E% SMI"
40 
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/signal.h>
44 #include <sys/stream.h>
45 #include <sys/termio.h>
46 #include <sys/errno.h>
47 #include <sys/file.h>
48 #include <sys/cmn_err.h>
49 #include <sys/stropts.h>
50 #include <sys/strtty.h>
51 #include <sys/kbio.h>
52 #include <sys/cred.h>
53 #include <sys/stat.h>
54 #include <sys/consdev.h>
55 #include <sys/kmem.h>
56 #include <sys/modctl.h>
57 #include <sys/ddi.h>
58 #include <sys/sunddi.h>
59 #include <sys/pci.h>
60 #include <sys/errno.h>
61 #include <sys/gld.h>
62 #include <sys/dlpi.h>
63 #include <sys/ethernet.h>
64 #include <sys/list.h>
65 #include <sys/byteorder.h>
66 #include <sys/strsun.h>
67 #include <inet/common.h>
68 #include <inet/nd.h>
69 #include <inet/mi.h>
70 
71 #include "rtwreg.h"
72 #include "rtwvar.h"
73 #include "max2820reg.h"
74 #include "sa2400reg.h"
75 #include "rtwphyio.h"
76 #include "rtwphy.h"
77 
78 static int rtw_max2820_pwrstate(struct rtw_rf *, enum rtw_pwrstate);
79 static int rtw_sa2400_pwrstate(struct rtw_rf *, enum rtw_pwrstate);
80 
81 static int
82 rtw_rf_init(struct rtw_rf *rf, uint_t freq, uint8_t opaque_txpower,
83     enum rtw_pwrstate power)
84 {
85 	return (*rf->rf_init)(rf, freq, opaque_txpower, power);
86 }
87 
88 static int
89 rtw_rf_tune(struct rtw_rf *rf, uint_t freq)
90 {
91 	return (*rf->rf_tune)(rf, freq);
92 }
93 
94 static int
95 rtw_rf_txpower(struct rtw_rf *rf, uint8_t opaque_txpower)
96 {
97 	return (*rf->rf_txpower)(rf, opaque_txpower);
98 }
99 
100 static int
101 rtw_rfbus_write(struct rtw_rfbus *bus, enum rtw_rfchipid rfchipid, uint_t addr,
102     uint32_t val)
103 {
104 	return (*bus->b_write)(bus->b_regs, rfchipid, addr, val);
105 }
106 
107 static int
108 rtw_bbp_preinit(struct rtw_regs *regs, uint_t antatten0, int dflantb,
109     uint_t freq)
110 {
111 	uint_t antatten = antatten0;
112 	if (dflantb)
113 		antatten |= RTW_BBP_ANTATTEN_DFLANTB;
114 	if (freq == 2484) /* channel 14 */
115 		antatten |= RTW_BBP_ANTATTEN_CHAN14;
116 	return (rtw_bbp_write(regs, RTW_BBP_ANTATTEN, antatten));
117 }
118 
119 static int
120 rtw_bbp_init(struct rtw_regs *regs, struct rtw_bbpset *bb, int antdiv,
121     int dflantb, uint8_t cs_threshold, uint_t freq)
122 {
123 	int rc;
124 	uint32_t sys2, sys3;
125 
126 	sys2 = bb->bb_sys2;
127 	if (antdiv)
128 		sys2 |= RTW_BBP_SYS2_ANTDIV;
129 	sys3 = bb->bb_sys3 |
130 	    LSHIFT(cs_threshold, RTW_BBP_SYS3_CSTHRESH_MASK);
131 
132 #define	RTW_BBP_WRITE_OR_RETURN(reg, val) \
133 	if ((rc = rtw_bbp_write(regs, reg, val)) != 0) \
134 		return (rc);
135 
136 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_SYS1,		bb->bb_sys1);
137 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_TXAGC,		bb->bb_txagc);
138 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_LNADET,		bb->bb_lnadet);
139 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_IFAGCINI,	bb->bb_ifagcini);
140 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_IFAGCLIMIT,	bb->bb_ifagclimit);
141 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_IFAGCDET,	bb->bb_ifagcdet);
142 
143 	if ((rc = rtw_bbp_preinit(regs, bb->bb_antatten, dflantb, freq)) != 0)
144 		return (rc);
145 
146 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_TRL,		bb->bb_trl);
147 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_SYS2,		sys2);
148 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_SYS3,		sys3);
149 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_CHESTLIM,	bb->bb_chestlim);
150 	RTW_BBP_WRITE_OR_RETURN(RTW_BBP_CHSQLIM,	bb->bb_chsqlim);
151 	return (0);
152 }
153 
154 static int
155 rtw_sa2400_txpower(struct rtw_rf *rf, uint8_t opaque_txpower)
156 {
157 	struct rtw_sa2400 *sa = (struct rtw_sa2400 *)rf;
158 	struct rtw_rfbus *bus = &sa->sa_bus;
159 
160 	return (rtw_rfbus_write(bus, RTW_RFCHIPID_PHILIPS, SA2400_TX,
161 	    opaque_txpower));
162 }
163 
164 #ifdef _RTW_FUTURE_DEBUG_
165 /*
166  * make sure we're using the same settings as the reference driver
167  */
168 static void
169 verify_syna(uint_t freq, uint32_t val)
170 {
171 	uint32_t expected_val = ~val;
172 
173 	switch (freq) {
174 	case 2412:
175 		expected_val = 0x0000096c; /* ch 1 */
176 		break;
177 	case 2417:
178 		expected_val = 0x00080970; /* ch 2 */
179 		break;
180 	case 2422:
181 		expected_val = 0x00100974; /* ch 3 */
182 		break;
183 	case 2427:
184 		expected_val = 0x00180978; /* ch 4 */
185 		break;
186 	case 2432:
187 		expected_val = 0x00000980; /* ch 5 */
188 		break;
189 	case 2437:
190 		expected_val = 0x00080984; /* ch 6 */
191 		break;
192 	case 2442:
193 		expected_val = 0x00100988; /* ch 7 */
194 		break;
195 	case 2447:
196 		expected_val = 0x0018098c; /* ch 8 */
197 		break;
198 	case 2452:
199 		expected_val = 0x00000994; /* ch 9 */
200 		break;
201 	case 2457:
202 		expected_val = 0x00080998; /* ch 10 */
203 		break;
204 	case 2462:
205 		expected_val = 0x0010099c; /* ch 11 */
206 		break;
207 	case 2467:
208 		expected_val = 0x001809a0; /* ch 12 */
209 		break;
210 	case 2472:
211 		expected_val = 0x000009a8; /* ch 13 */
212 		break;
213 	case 2484:
214 		expected_val = 0x000009b4; /* ch 14 */
215 		break;
216 	}
217 }
218 #endif /* _RTW_FUTURE_DEBUG_ */
219 
220 /* freq is in MHz */
221 static int
222 rtw_sa2400_tune(struct rtw_rf *rf, uint_t freq)
223 {
224 	struct rtw_sa2400 *sa = (struct rtw_sa2400 *)rf;
225 	struct rtw_rfbus *bus = &sa->sa_bus;
226 	int rc;
227 	uint32_t syna, synb, sync;
228 
229 	/*
230 	 * XO = 44MHz, R = 11, hence N is in units of XO / R = 4MHz.
231 	 *
232 	 * The channel spacing (5MHz) is not divisible by 4MHz, so
233 	 * we set the fractional part of N to compensate.
234 	 */
235 	int n = freq / 4, nf = (freq % 4) * 2;
236 
237 	syna = LSHIFT(nf, SA2400_SYNA_NF_MASK) | LSHIFT(n, SA2400_SYNA_N_MASK);
238 	/* verify_syna(freq, syna); */
239 
240 	/*
241 	 * Divide the 44MHz crystal down to 4MHz. Set the fractional
242 	 * compensation charge pump value to agree with the fractional
243 	 * modulus.
244 	 */
245 	synb = LSHIFT(11, SA2400_SYNB_R_MASK) | SA2400_SYNB_L_NORMAL |
246 	    SA2400_SYNB_ON | SA2400_SYNB_ONE |
247 	    LSHIFT(80, SA2400_SYNB_FC_MASK); /* agrees w/ SA2400_SYNA_FM = 0 */
248 
249 	sync = SA2400_SYNC_CP_NORMAL;
250 
251 	if ((rc = rtw_rfbus_write(bus, RTW_RFCHIPID_PHILIPS, SA2400_SYNA,
252 	    syna)) != 0)
253 		return (rc);
254 	if ((rc = rtw_rfbus_write(bus, RTW_RFCHIPID_PHILIPS, SA2400_SYNB,
255 	    synb)) != 0)
256 		return (rc);
257 	if ((rc = rtw_rfbus_write(bus, RTW_RFCHIPID_PHILIPS, SA2400_SYNC,
258 	    sync)) != 0)
259 		return (rc);
260 	return (rtw_rfbus_write(bus, RTW_RFCHIPID_PHILIPS, SA2400_SYND, 0x0));
261 }
262 
263 static int
264 rtw_sa2400_pwrstate(struct rtw_rf *rf, enum rtw_pwrstate power)
265 {
266 	struct rtw_sa2400 *sa = (struct rtw_sa2400 *)rf;
267 	struct rtw_rfbus *bus = &sa->sa_bus;
268 	uint32_t opmode;
269 	opmode = SA2400_OPMODE_DEFAULTS;
270 	switch (power) {
271 	case RTW_ON:
272 		opmode |= SA2400_OPMODE_MODE_TXRX;
273 		break;
274 	case RTW_SLEEP:
275 		opmode |= SA2400_OPMODE_MODE_WAIT;
276 		break;
277 	case RTW_OFF:
278 		opmode |= SA2400_OPMODE_MODE_SLEEP;
279 		break;
280 	}
281 
282 	if (sa->sa_digphy)
283 		opmode |= SA2400_OPMODE_DIGIN;
284 
285 	return (rtw_rfbus_write(bus, RTW_RFCHIPID_PHILIPS, SA2400_OPMODE,
286 	    opmode));
287 }
288 
289 static int
290 rtw_sa2400_manrx_init(struct rtw_sa2400 *sa)
291 {
292 	uint32_t manrx;
293 
294 	/*
295 	 * we are not supposed to be in RXMGC mode when we do
296 	 * this?
297 	 */
298 	manrx = SA2400_MANRX_AHSN;
299 	manrx |= SA2400_MANRX_TEN;
300 	manrx |= LSHIFT(1023, SA2400_MANRX_RXGAIN_MASK);
301 
302 	return (rtw_rfbus_write(&sa->sa_bus, RTW_RFCHIPID_PHILIPS, SA2400_MANRX,
303 	    manrx));
304 }
305 
306 static int
307 rtw_sa2400_vcocal_start(struct rtw_sa2400 *sa, int start)
308 {
309 	uint32_t opmode;
310 
311 	opmode = SA2400_OPMODE_DEFAULTS;
312 	if (start)
313 		opmode |= SA2400_OPMODE_MODE_VCOCALIB;
314 	else
315 		opmode |= SA2400_OPMODE_MODE_SLEEP;
316 
317 	if (sa->sa_digphy)
318 		opmode |= SA2400_OPMODE_DIGIN;
319 
320 	return (rtw_rfbus_write(&sa->sa_bus, RTW_RFCHIPID_PHILIPS,
321 	    SA2400_OPMODE, opmode));
322 }
323 
324 static int
325 rtw_sa2400_vco_calibration(struct rtw_sa2400 *sa)
326 {
327 	int rc;
328 	/*
329 	 * calibrate VCO
330 	 */
331 	if ((rc = rtw_sa2400_vcocal_start(sa, 1)) != 0)
332 		return (rc);
333 	DELAY(2200);	/* 2.2 milliseconds */
334 	/*
335 	 * XXX superfluous: SA2400 automatically entered SLEEP mode.
336 	 */
337 	return (rtw_sa2400_vcocal_start(sa, 0));
338 }
339 
340 static int
341 rtw_sa2400_filter_calibration(struct rtw_sa2400 *sa)
342 {
343 	uint32_t opmode;
344 
345 	opmode = SA2400_OPMODE_DEFAULTS | SA2400_OPMODE_MODE_FCALIB;
346 	if (sa->sa_digphy)
347 		opmode |= SA2400_OPMODE_DIGIN;
348 
349 	return (rtw_rfbus_write(&sa->sa_bus, RTW_RFCHIPID_PHILIPS,
350 	    SA2400_OPMODE, opmode));
351 }
352 
353 static int
354 rtw_sa2400_dc_calibration(struct rtw_sa2400 *sa)
355 {
356 	struct rtw_rf *rf = &sa->sa_rf;
357 	int rc;
358 	uint32_t dccal;
359 
360 	(*rf->rf_continuous_tx_cb)(rf->rf_continuous_tx_arg, 1);
361 
362 	dccal = SA2400_OPMODE_DEFAULTS | SA2400_OPMODE_MODE_TXRX;
363 
364 	rc = rtw_rfbus_write(&sa->sa_bus, RTW_RFCHIPID_PHILIPS, SA2400_OPMODE,
365 	    dccal);
366 	if (rc != 0)
367 		return (rc);
368 
369 	DELAY(5); /* DCALIB after being in Tx mode for 5 microseconds */
370 
371 	dccal &= ~SA2400_OPMODE_MODE_MASK;
372 	dccal |= SA2400_OPMODE_MODE_DCALIB;
373 
374 	rc = rtw_rfbus_write(&sa->sa_bus, RTW_RFCHIPID_PHILIPS, SA2400_OPMODE,
375 	    dccal);
376 	if (rc != 0)
377 		return (rc);
378 	DELAY(20); /* calibration takes at most 20 microseconds */
379 
380 	(*rf->rf_continuous_tx_cb)(rf->rf_continuous_tx_arg, 0);
381 
382 	return (0);
383 }
384 
385 static int
386 rtw_sa2400_agc_init(struct rtw_sa2400 *sa)
387 {
388 	uint32_t agc;
389 
390 	agc = LSHIFT(25, SA2400_AGC_MAXGAIN_MASK);
391 	agc |= LSHIFT(7, SA2400_AGC_BBPDELAY_MASK);
392 	agc |= LSHIFT(15, SA2400_AGC_LNADELAY_MASK);
393 	agc |= LSHIFT(27, SA2400_AGC_RXONDELAY_MASK);
394 
395 	return (rtw_rfbus_write(&sa->sa_bus, RTW_RFCHIPID_PHILIPS, SA2400_AGC,
396 	    agc));
397 }
398 
399 static void
400 rtw_sa2400_destroy(struct rtw_rf *rf)
401 {
402 	struct rtw_sa2400 *sa = (struct rtw_sa2400 *)rf;
403 	kmem_free(sa, sizeof (*sa));
404 }
405 
406 static int
407 rtw_sa2400_calibrate(struct rtw_rf *rf, uint_t freq)
408 {
409 	struct rtw_sa2400 *sa = (struct rtw_sa2400 *)rf;
410 	int i, rc;
411 
412 	/*
413 	 * XXX reference driver calibrates VCO twice. Is it a bug?
414 	 */
415 	for (i = 0; i < 2; i++) {
416 		if ((rc = rtw_sa2400_vco_calibration(sa)) != 0)
417 			return (rc);
418 	}
419 	/*
420 	 * VCO calibration erases synthesizer registers, so re-tune
421 	 */
422 	if ((rc = rtw_sa2400_tune(rf, freq)) != 0)
423 		return (rc);
424 	if ((rc = rtw_sa2400_filter_calibration(sa)) != 0)
425 		return (rc);
426 	/*
427 	 * analog PHY needs DC calibration
428 	 */
429 	if (!sa->sa_digphy)
430 		return (rtw_sa2400_dc_calibration(sa));
431 	return (0);
432 }
433 
434 static int
435 rtw_sa2400_init(struct rtw_rf *rf, uint_t freq, uint8_t opaque_txpower,
436     enum rtw_pwrstate power)
437 {
438 	struct rtw_sa2400 *sa = (struct rtw_sa2400 *)rf;
439 	int rc;
440 
441 	if ((rc = rtw_sa2400_txpower(rf, opaque_txpower)) != 0)
442 		return (rc);
443 
444 	/*
445 	 * skip configuration if it's time to sleep or to power-down.
446 	 */
447 	if (power == RTW_SLEEP || power == RTW_OFF)
448 		return (rtw_sa2400_pwrstate(rf, power));
449 
450 	/*
451 	 * go to sleep for configuration
452 	 */
453 	if ((rc = rtw_sa2400_pwrstate(rf, RTW_SLEEP)) != 0)
454 		return (rc);
455 
456 	if ((rc = rtw_sa2400_tune(rf, freq)) != 0)
457 		return (rc);
458 	if ((rc = rtw_sa2400_agc_init(sa)) != 0)
459 		return (rc);
460 	if ((rc = rtw_sa2400_manrx_init(sa)) != 0)
461 		return (rc);
462 	if ((rc = rtw_sa2400_calibrate(rf, freq)) != 0)
463 		return (rc);
464 
465 	/*
466 	 * enter Tx/Rx mode
467 	 */
468 	return (rtw_sa2400_pwrstate(rf, power));
469 }
470 
471 struct rtw_rf *
472 rtw_sa2400_create(struct rtw_regs *regs, rtw_rf_write_t rf_write, int digphy)
473 {
474 	struct rtw_sa2400 *sa;
475 	struct rtw_rfbus *bus;
476 	struct rtw_rf *rf;
477 	struct rtw_bbpset *bb;
478 
479 	sa = (struct rtw_sa2400 *)kmem_zalloc(sizeof (*sa), KM_SLEEP);
480 	if (sa == NULL)
481 		return (NULL);
482 
483 	sa->sa_digphy = digphy;
484 
485 	rf = &sa->sa_rf;
486 	bus = &sa->sa_bus;
487 
488 	rf->rf_init = rtw_sa2400_init;
489 	rf->rf_destroy = rtw_sa2400_destroy;
490 	rf->rf_txpower = rtw_sa2400_txpower;
491 	rf->rf_tune = rtw_sa2400_tune;
492 	rf->rf_pwrstate = rtw_sa2400_pwrstate;
493 	bb = &rf->rf_bbpset;
494 
495 	/*
496 	 * XXX magic
497 	 */
498 	bb->bb_antatten = RTW_BBP_ANTATTEN_PHILIPS_MAGIC;
499 	bb->bb_chestlim =	0x00;
500 	bb->bb_chsqlim =	0xa0;
501 	bb->bb_ifagcdet =	0x64;
502 	bb->bb_ifagcini =	0x90;
503 	bb->bb_ifagclimit =	0x1a;
504 	bb->bb_lnadet =		0xe0;
505 	bb->bb_sys1 =		0x98;
506 	bb->bb_sys2 =		0x47;
507 	bb->bb_sys3 =		0x90;
508 	bb->bb_trl =		0x88;
509 	bb->bb_txagc =		0x38;
510 
511 	bus->b_regs = regs;
512 	bus->b_write = rf_write;
513 
514 	return (&sa->sa_rf);
515 }
516 
517 /*
518  * freq is in MHz
519  */
520 static int
521 rtw_max2820_tune(struct rtw_rf *rf, uint_t freq)
522 {
523 	struct rtw_max2820 *mx = (struct rtw_max2820 *)rf;
524 	struct rtw_rfbus *bus = &mx->mx_bus;
525 
526 	if (freq < 2400 || freq > 2499)
527 		return (-1);
528 
529 	return (rtw_rfbus_write(bus, RTW_RFCHIPID_MAXIM, MAX2820_CHANNEL,
530 	    LSHIFT(freq - 2400, MAX2820_CHANNEL_CF_MASK)));
531 }
532 
533 static void
534 rtw_max2820_destroy(struct rtw_rf *rf)
535 {
536 	struct rtw_max2820 *mx = (struct rtw_max2820 *)rf;
537 	kmem_free(mx, sizeof (*mx));
538 }
539 
540 /*ARGSUSED*/
541 static int
542 rtw_max2820_init(struct rtw_rf *rf, uint_t freq, uint8_t opaque_txpower,
543     enum rtw_pwrstate power)
544 {
545 	struct rtw_max2820 *mx = (struct rtw_max2820 *)rf;
546 	struct rtw_rfbus *bus = &mx->mx_bus;
547 	int rc;
548 
549 	if ((rc = rtw_rfbus_write(bus, RTW_RFCHIPID_MAXIM, MAX2820_TEST,
550 	    MAX2820_TEST_DEFAULT)) != 0)
551 		return (rc);
552 
553 	if ((rc = rtw_rfbus_write(bus, RTW_RFCHIPID_MAXIM, MAX2820_ENABLE,
554 	    MAX2820_ENABLE_DEFAULT)) != 0)
555 		return (rc);
556 
557 	/*
558 	 * skip configuration if it's time to sleep or to power-down.
559 	 */
560 	if ((rc = rtw_max2820_pwrstate(rf, power)) != 0)
561 		return (rc);
562 	else if (power == RTW_OFF || power == RTW_SLEEP)
563 		return (0);
564 
565 	if ((rc = rtw_rfbus_write(bus, RTW_RFCHIPID_MAXIM, MAX2820_SYNTH,
566 	    MAX2820_SYNTH_R_44MHZ)) != 0)
567 		return (rc);
568 
569 	if ((rc = rtw_max2820_tune(rf, freq)) != 0)
570 		return (rc);
571 
572 	/*
573 	 * XXX The MAX2820 datasheet indicates that 1C and 2C should not
574 	 * be changed from 7, however, the reference driver sets them
575 	 * to 4 and 1, respectively.
576 	 */
577 	if ((rc = rtw_rfbus_write(bus, RTW_RFCHIPID_MAXIM, MAX2820_RECEIVE,
578 	    MAX2820_RECEIVE_DL_DEFAULT |
579 	    LSHIFT(4, MAX2820A_RECEIVE_1C_MASK) |
580 	    LSHIFT(1, MAX2820A_RECEIVE_2C_MASK))) != 0)
581 		return (rc);
582 
583 	return (rtw_rfbus_write(bus, RTW_RFCHIPID_MAXIM, MAX2820_TRANSMIT,
584 	    MAX2820_TRANSMIT_PA_DEFAULT));
585 }
586 
587 /*ARGSUSED*/
588 static int
589 rtw_max2820_txpower(struct rtw_rf *rf, uint8_t opaque_txpower)
590 {
591 	/* TBD */
592 	return (0);
593 }
594 
595 static int
596 rtw_max2820_pwrstate(struct rtw_rf *rf, enum rtw_pwrstate power)
597 {
598 	uint32_t enable;
599 	struct rtw_max2820 *mx;
600 	struct rtw_rfbus *bus;
601 
602 	mx = (struct rtw_max2820 *)rf;
603 	bus = &mx->mx_bus;
604 
605 	switch (power) {
606 	case RTW_OFF:
607 	case RTW_SLEEP:
608 	default:
609 		enable = 0x0;
610 		break;
611 	case RTW_ON:
612 		enable = MAX2820_ENABLE_DEFAULT;
613 		break;
614 	}
615 	return (rtw_rfbus_write(bus, RTW_RFCHIPID_MAXIM,
616 	    MAX2820_ENABLE, enable));
617 }
618 
619 struct rtw_rf *
620 rtw_max2820_create(struct rtw_regs *regs, rtw_rf_write_t rf_write, int is_a)
621 {
622 	struct rtw_max2820 *mx;
623 	struct rtw_rfbus *bus;
624 	struct rtw_rf *rf;
625 	struct rtw_bbpset *bb;
626 
627 	mx = (struct rtw_max2820 *)kmem_zalloc(sizeof (*mx), KM_SLEEP);
628 	if (mx == NULL)
629 		return (NULL);
630 
631 	mx->mx_is_a = is_a;
632 
633 	rf = &mx->mx_rf;
634 	bus = &mx->mx_bus;
635 
636 	rf->rf_init = rtw_max2820_init;
637 	rf->rf_destroy = rtw_max2820_destroy;
638 	rf->rf_txpower = rtw_max2820_txpower;
639 	rf->rf_tune = rtw_max2820_tune;
640 	rf->rf_pwrstate = rtw_max2820_pwrstate;
641 	bb = &rf->rf_bbpset;
642 
643 	/*
644 	 * XXX magic
645 	 */
646 	bb->bb_antatten = RTW_BBP_ANTATTEN_MAXIM_MAGIC;
647 	bb->bb_chestlim =	0;
648 	bb->bb_chsqlim =	159;
649 	bb->bb_ifagcdet =	100;
650 	bb->bb_ifagcini =	144;
651 	bb->bb_ifagclimit =	26;
652 	bb->bb_lnadet =		248;
653 	bb->bb_sys1 =		136;
654 	bb->bb_sys2 =		71;
655 	bb->bb_sys3 =		155;
656 	bb->bb_trl =		136;
657 	bb->bb_txagc =		8;
658 
659 	bus->b_regs = regs;
660 	bus->b_write = rf_write;
661 
662 	return (&mx->mx_rf);
663 }
664 
665 /*
666  * freq is in MHz
667  */
668 int
669 rtw_phy_init(struct rtw_regs *regs, struct rtw_rf *rf, uint8_t opaque_txpower,
670     uint8_t cs_threshold, uint_t freq, int antdiv, int dflantb,
671     enum rtw_pwrstate power)
672 {
673 	int rc;
674 
675 	/*
676 	 * XXX is this really necessary?
677 	 */
678 	if ((rc = rtw_rf_txpower(rf, opaque_txpower)) != 0)
679 		return (rc);
680 	if ((rc = rtw_bbp_preinit(regs, rf->rf_bbpset.bb_antatten, dflantb,
681 	    freq)) != 0)
682 		return (rc);
683 	if ((rc = rtw_rf_tune(rf, freq)) != 0)
684 		return (rc);
685 	/*
686 	 * initialize RF
687 	 */
688 	if ((rc = rtw_rf_init(rf, freq, opaque_txpower, power)) != 0)
689 		return (rc);
690 #ifdef _RTW_FUTURE_DEBUG_
691 	/* what is this redundant tx power setting here for? */
692 	if ((rc = rtw_rf_txpower(rf, opaque_txpower)) != 0)
693 		return (rc);
694 #endif /* _RTW_FUTURE_DEBUG */
695 	return (rtw_bbp_init(regs, &rf->rf_bbpset, antdiv, dflantb,
696 	    cs_threshold, freq));
697 }
698