Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 /*
0004  * Radio tuning for Philips SA2400 on RTL8180
0005  *
0006  * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
0007  *
0008  * Code from the BSD driver and the rtl8181 project have been
0009  * very useful to understand certain things
0010  *
0011  * I want to thanks the Authors of such projects and the Ndiswrapper
0012  * project Authors.
0013  *
0014  * A special Big Thanks also is for all people who donated me cards,
0015  * making possible the creation of the original rtl8180 driver
0016  * from which this code is derived!
0017  */
0018 
0019 #include <linux/pci.h>
0020 #include <linux/delay.h>
0021 #include <net/mac80211.h>
0022 
0023 #include "rtl8180.h"
0024 #include "sa2400.h"
0025 
0026 static const u32 sa2400_chan[] = {
0027     0x00096c, /* ch1 */
0028     0x080970,
0029     0x100974,
0030     0x180978,
0031     0x000980,
0032     0x080984,
0033     0x100988,
0034     0x18098c,
0035     0x000994,
0036     0x080998,
0037     0x10099c,
0038     0x1809a0,
0039     0x0009a8,
0040     0x0009b4, /* ch 14 */
0041 };
0042 
0043 static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data)
0044 {
0045     struct rtl8180_priv *priv = dev->priv;
0046     u32 phy_config;
0047 
0048     /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */
0049     phy_config = 0xb0000000;
0050 
0051     phy_config |= ((u32)(addr & 0xf)) << 24;
0052     phy_config |= data & 0xffffff;
0053 
0054     rtl818x_iowrite32(priv,
0055         (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config);
0056 
0057     msleep(3);
0058 }
0059 
0060 static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan)
0061 {
0062     struct rtl8180_priv *priv = dev->priv;
0063     u8 ant = SA2400_ANTENNA;
0064 
0065     if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
0066         ant |= BB_ANTENNA_B;
0067 
0068     if (chan == 14)
0069         ant |= BB_ANTATTEN_CHAN14;
0070 
0071     rtl8180_write_phy(dev, 0x10, ant);
0072 
0073 }
0074 
0075 static u8 sa2400_rf_rssi_map[] = {
0076     0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e,
0077     0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50,
0078     0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f,
0079     0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b,
0080     0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17,
0081     0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13,
0082     0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f,
0083     0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
0084     0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
0085     0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02,
0086 };
0087 
0088 static u8 sa2400_rf_calc_rssi(u8 agc, u8 sq)
0089 {
0090     if (sq == 0x80)
0091         return 1;
0092 
0093     if (sq > 78)
0094         return 32;
0095 
0096     /* TODO: recalc sa2400_rf_rssi_map to avoid mult / div */
0097     return 65 * sa2400_rf_rssi_map[sq] / 100;
0098 }
0099 
0100 static void sa2400_rf_set_channel(struct ieee80211_hw *dev,
0101                   struct ieee80211_conf *conf)
0102 {
0103     struct rtl8180_priv *priv = dev->priv;
0104     int channel =
0105         ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
0106     u32 txpw = priv->channels[channel - 1].hw_value & 0xFF;
0107     u32 chan = sa2400_chan[channel - 1];
0108 
0109     write_sa2400(dev, 7, txpw);
0110 
0111     sa2400_write_phy_antenna(dev, channel);
0112 
0113     write_sa2400(dev, 0, chan);
0114     write_sa2400(dev, 1, 0xbb50);
0115     write_sa2400(dev, 2, 0x80);
0116     write_sa2400(dev, 3, 0);
0117 }
0118 
0119 static void sa2400_rf_stop(struct ieee80211_hw *dev)
0120 {
0121     write_sa2400(dev, 4, 0);
0122 }
0123 
0124 static void sa2400_rf_init(struct ieee80211_hw *dev)
0125 {
0126     struct rtl8180_priv *priv = dev->priv;
0127     u32 anaparam, txconf;
0128     u8 firdac;
0129     int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY;
0130 
0131     anaparam = priv->anaparam;
0132     anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT);
0133     anaparam &= ~ANAPARAM_PWR1_MASK;
0134     anaparam &= ~ANAPARAM_PWR0_MASK;
0135 
0136     if (analogphy) {
0137         anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT;
0138         firdac = 0;
0139     } else {
0140         anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT);
0141         anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT);
0142         firdac = 1 << SA2400_REG4_FIRDAC_SHIFT;
0143     }
0144 
0145     rtl8180_set_anaparam(priv, anaparam);
0146 
0147     write_sa2400(dev, 0, sa2400_chan[0]);
0148     write_sa2400(dev, 1, 0xbb50);
0149     write_sa2400(dev, 2, 0x80);
0150     write_sa2400(dev, 3, 0);
0151     write_sa2400(dev, 4, 0x19340 | firdac);
0152     write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15);
0153     write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */
0154 
0155     if (!analogphy)
0156         write_sa2400(dev, 4, 0x1938c); /*???*/
0157 
0158     write_sa2400(dev, 4, 0x19340 | firdac);
0159 
0160     write_sa2400(dev, 0, sa2400_chan[0]);
0161     write_sa2400(dev, 1, 0xbb50);
0162     write_sa2400(dev, 2, 0x80);
0163     write_sa2400(dev, 3, 0);
0164     write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */
0165 
0166     /* new from rtl8180 embedded driver (rtl8181 project) */
0167     write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */
0168     write_sa2400(dev, 8, 0); /* VCO */
0169 
0170     if (analogphy) {
0171         rtl8180_set_anaparam(priv, anaparam |
0172                      (1 << ANAPARAM_TXDACOFF_SHIFT));
0173 
0174         txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF);
0175         rtl818x_iowrite32(priv, &priv->map->TX_CONF,
0176             txconf | RTL818X_TX_CONF_LOOPBACK_CONT);
0177 
0178         write_sa2400(dev, 4, 0x19341); /* calibrates DC */
0179 
0180         /* a 5us sleep is required here,
0181          * we rely on the 3ms delay introduced in write_sa2400 */
0182         write_sa2400(dev, 4, 0x19345);
0183 
0184         /* a 20us sleep is required here,
0185          * we rely on the 3ms delay introduced in write_sa2400 */
0186 
0187         rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf);
0188 
0189         rtl8180_set_anaparam(priv, anaparam);
0190     }
0191     /* end new code */
0192 
0193     write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */
0194 
0195     /* baseband configuration */
0196     rtl8180_write_phy(dev, 0, 0x98);
0197     rtl8180_write_phy(dev, 3, 0x38);
0198     rtl8180_write_phy(dev, 4, 0xe0);
0199     rtl8180_write_phy(dev, 5, 0x90);
0200     rtl8180_write_phy(dev, 6, 0x1a);
0201     rtl8180_write_phy(dev, 7, 0x64);
0202 
0203     sa2400_write_phy_antenna(dev, 1);
0204 
0205     rtl8180_write_phy(dev, 0x11, 0x80);
0206 
0207     if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
0208         RTL818X_CONFIG2_ANTENNA_DIV)
0209         rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */
0210     else
0211         rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */
0212 
0213     rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold);
0214 
0215     rtl8180_write_phy(dev, 0x19, 0x0);
0216     rtl8180_write_phy(dev, 0x1a, 0xa0);
0217 }
0218 
0219 const struct rtl818x_rf_ops sa2400_rf_ops = {
0220     .name       = "Philips",
0221     .init       = sa2400_rf_init,
0222     .stop       = sa2400_rf_stop,
0223     .set_chan   = sa2400_rf_set_channel,
0224     .calc_rssi  = sa2400_rf_calc_rssi,
0225 };