1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Radio tuning for Maxim max2820 on RTL8180 4 * 5 * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> 6 * 7 * Code from the BSD driver and the rtl8181 project have been 8 * very useful to understand certain things 9 * 10 * I want to thanks the Authors of such projects and the Ndiswrapper 11 * project Authors. 12 * 13 * A special Big Thanks also is for all people who donated me cards, 14 * making possible the creation of the original rtl8180 driver 15 * from which this code is derived! 16 */ 17 18 #include <linux/pci.h> 19 #include <linux/delay.h> 20 #include <net/mac80211.h> 21 22 #include "rtl8180.h" 23 #include "max2820.h" 24 25 static const u32 max2820_chan[] = { 26 12, /* CH 1 */ 27 17, 28 22, 29 27, 30 32, 31 37, 32 42, 33 47, 34 52, 35 57, 36 62, 37 67, 38 72, 39 84, /* CH 14 */ 40 }; 41 42 static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) 43 { 44 struct rtl8180_priv *priv = dev->priv; 45 u32 phy_config; 46 47 phy_config = 0x90 + (data & 0xf); 48 phy_config <<= 16; 49 phy_config += addr; 50 phy_config <<= 8; 51 phy_config += (data >> 4) & 0xff; 52 53 rtl818x_iowrite32(priv, 54 (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); 55 56 msleep(1); 57 } 58 59 static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) 60 { 61 struct rtl8180_priv *priv = dev->priv; 62 u8 ant; 63 64 ant = MAXIM_ANTENNA; 65 if (priv->rfparam & RF_PARAM_ANTBDEFAULT) 66 ant |= BB_ANTENNA_B; 67 if (chan == 14) 68 ant |= BB_ANTATTEN_CHAN14; 69 70 rtl8180_write_phy(dev, 0x10, ant); 71 } 72 73 static u8 max2820_rf_calc_rssi(u8 agc, u8 sq) 74 { 75 bool odd; 76 77 odd = !!(agc & 1); 78 79 agc >>= 1; 80 if (odd) 81 agc += 76; 82 else 83 agc += 66; 84 85 /* TODO: change addends above to avoid mult / div below */ 86 return 65 * agc / 100; 87 } 88 89 static void max2820_rf_set_channel(struct ieee80211_hw *dev, 90 struct ieee80211_conf *conf) 91 { 92 struct rtl8180_priv *priv = dev->priv; 93 int channel = conf ? 94 ieee80211_frequency_to_channel(conf->chandef.chan->center_freq) : 1; 95 unsigned int chan_idx = channel - 1; 96 u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; 97 u32 chan = max2820_chan[chan_idx]; 98 99 /* While philips SA2400 drive the PA bias from 100 * sa2400, for MAXIM we do this directly from BB */ 101 rtl8180_write_phy(dev, 3, txpw); 102 103 max2820_write_phy_antenna(dev, channel); 104 write_max2820(dev, 3, chan); 105 } 106 107 static void max2820_rf_stop(struct ieee80211_hw *dev) 108 { 109 rtl8180_write_phy(dev, 3, 0x8); 110 write_max2820(dev, 1, 0); 111 } 112 113 114 static void max2820_rf_init(struct ieee80211_hw *dev) 115 { 116 struct rtl8180_priv *priv = dev->priv; 117 118 /* MAXIM from netbsd driver */ 119 write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ 120 write_max2820(dev, 1, 0x01e); /* enable register */ 121 write_max2820(dev, 2, 0x001); /* synt register */ 122 123 max2820_rf_set_channel(dev, NULL); 124 125 write_max2820(dev, 4, 0x313); /* rx register */ 126 127 /* PA is driven directly by the BB, we keep the MAXIM bias 128 * at the highest value in case that setting it to lower 129 * values may introduce some further attenuation somewhere.. 130 */ 131 write_max2820(dev, 5, 0x00f); 132 133 /* baseband configuration */ 134 rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ 135 rtl8180_write_phy(dev, 3, 0x08); /* txagc */ 136 rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ 137 rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ 138 rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ 139 rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ 140 141 max2820_write_phy_antenna(dev, 1); 142 143 rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ 144 145 if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & 146 RTL818X_CONFIG2_ANTENNA_DIV) 147 rtl8180_write_phy(dev, 0x12, 0xc7); 148 else 149 rtl8180_write_phy(dev, 0x12, 0x47); 150 151 rtl8180_write_phy(dev, 0x13, 0x9b); 152 153 rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ 154 rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ 155 156 max2820_rf_set_channel(dev, NULL); 157 } 158 159 const struct rtl818x_rf_ops max2820_rf_ops = { 160 .name = "Maxim", 161 .init = max2820_rf_init, 162 .stop = max2820_rf_stop, 163 .set_chan = max2820_rf_set_channel, 164 .calc_rssi = max2820_rf_calc_rssi, 165 }; 166