Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Radio tuning for Maxim max2820 on RTL8180
0004  *
0005  * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
0006  *
0007  * Code from the BSD driver and the rtl8181 project have been
0008  * very useful to understand certain things
0009  *
0010  * I want to thanks the Authors of such projects and the Ndiswrapper
0011  * project Authors.
0012  *
0013  * A special Big Thanks also is for all people who donated me cards,
0014  * making possible the creation of the original rtl8180 driver
0015  * from which this code is derived!
0016  */
0017 
0018 #include <linux/pci.h>
0019 #include <linux/delay.h>
0020 #include <net/mac80211.h>
0021 
0022 #include "rtl8180.h"
0023 #include "max2820.h"
0024 
0025 static const u32 max2820_chan[] = {
0026     12, /* CH 1 */
0027     17,
0028     22,
0029     27,
0030     32,
0031     37,
0032     42,
0033     47,
0034     52,
0035     57,
0036     62,
0037     67,
0038     72,
0039     84, /* CH 14 */
0040 };
0041 
0042 static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data)
0043 {
0044     struct rtl8180_priv *priv = dev->priv;
0045     u32 phy_config;
0046 
0047     phy_config = 0x90 + (data & 0xf);
0048     phy_config <<= 16;
0049     phy_config += addr;
0050     phy_config <<= 8;
0051     phy_config += (data >> 4) & 0xff;
0052 
0053     rtl818x_iowrite32(priv,
0054         (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config);
0055 
0056     msleep(1);
0057 }
0058 
0059 static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan)
0060 {
0061     struct rtl8180_priv *priv = dev->priv;
0062     u8 ant;
0063 
0064     ant = MAXIM_ANTENNA;
0065     if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
0066         ant |= BB_ANTENNA_B;
0067     if (chan == 14)
0068         ant |= BB_ANTATTEN_CHAN14;
0069 
0070     rtl8180_write_phy(dev, 0x10, ant);
0071 }
0072 
0073 static u8 max2820_rf_calc_rssi(u8 agc, u8 sq)
0074 {
0075     bool odd;
0076 
0077     odd = !!(agc & 1);
0078 
0079     agc >>= 1;
0080     if (odd)
0081         agc += 76;
0082     else
0083         agc += 66;
0084 
0085     /* TODO: change addends above to avoid mult / div below */
0086     return 65 * agc / 100;
0087 }
0088 
0089 static void max2820_rf_set_channel(struct ieee80211_hw *dev,
0090                    struct ieee80211_conf *conf)
0091 {
0092     struct rtl8180_priv *priv = dev->priv;
0093     int channel = conf ?
0094         ieee80211_frequency_to_channel(conf->chandef.chan->center_freq) : 1;
0095     unsigned int chan_idx = channel - 1;
0096     u32 txpw = priv->channels[chan_idx].hw_value & 0xFF;
0097     u32 chan = max2820_chan[chan_idx];
0098 
0099     /* While philips SA2400 drive the PA bias from
0100      * sa2400, for MAXIM we do this directly from BB */
0101     rtl8180_write_phy(dev, 3, txpw);
0102 
0103     max2820_write_phy_antenna(dev, channel);
0104     write_max2820(dev, 3, chan);
0105 }
0106 
0107 static void max2820_rf_stop(struct ieee80211_hw *dev)
0108 {
0109     rtl8180_write_phy(dev, 3, 0x8);
0110     write_max2820(dev, 1, 0);
0111 }
0112 
0113 
0114 static void max2820_rf_init(struct ieee80211_hw *dev)
0115 {
0116     struct rtl8180_priv *priv = dev->priv;
0117 
0118     /* MAXIM from netbsd driver */
0119     write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */
0120     write_max2820(dev, 1, 0x01e); /* enable register */
0121     write_max2820(dev, 2, 0x001); /* synt register */
0122 
0123     max2820_rf_set_channel(dev, NULL);
0124 
0125     write_max2820(dev, 4, 0x313); /* rx register */
0126 
0127     /* PA is driven directly by the BB, we keep the MAXIM bias
0128      * at the highest value in case that setting it to lower
0129      * values may introduce some further attenuation somewhere..
0130      */
0131     write_max2820(dev, 5, 0x00f);
0132 
0133     /* baseband configuration */
0134     rtl8180_write_phy(dev, 0, 0x88); /* sys1       */
0135     rtl8180_write_phy(dev, 3, 0x08); /* txagc      */
0136     rtl8180_write_phy(dev, 4, 0xf8); /* lnadet     */
0137     rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit  */
0138     rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */
0139     rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet   */
0140 
0141     max2820_write_phy_antenna(dev, 1);
0142 
0143     rtl8180_write_phy(dev, 0x11, 0x88); /* trl */
0144 
0145     if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
0146         RTL818X_CONFIG2_ANTENNA_DIV)
0147         rtl8180_write_phy(dev, 0x12, 0xc7);
0148     else
0149         rtl8180_write_phy(dev, 0x12, 0x47);
0150 
0151     rtl8180_write_phy(dev, 0x13, 0x9b);
0152 
0153     rtl8180_write_phy(dev, 0x19, 0x0);  /* CHESTLIM */
0154     rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM  */
0155 
0156     max2820_rf_set_channel(dev, NULL);
0157 }
0158 
0159 const struct rtl818x_rf_ops max2820_rf_ops = {
0160     .name       = "Maxim",
0161     .init       = max2820_rf_init,
0162     .stop       = max2820_rf_stop,
0163     .set_chan   = max2820_rf_set_channel,
0164     .calc_rssi  = max2820_rf_calc_rssi,
0165 };