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