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