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 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 59a72f7ea6Sql147931 rtw_rf_tune(struct rtw_rf *rf, uint_t freq) 60a72f7ea6Sql147931 { 61a72f7ea6Sql147931 return (*rf->rf_tune)(rf, freq); 62a72f7ea6Sql147931 } 63a72f7ea6Sql147931 64a72f7ea6Sql147931 static int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 559a72f7ea6Sql147931 rtw_max2820_txpower(struct rtw_rf *rf, uint8_t opaque_txpower) 560a72f7ea6Sql147931 { 561a72f7ea6Sql147931 /* TBD */ 562a72f7ea6Sql147931 return (0); 563a72f7ea6Sql147931 } 564a72f7ea6Sql147931 565a72f7ea6Sql147931 static int 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 * 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 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