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