1f1d2b4d3SLarry Finger 2f1d2b4d3SLarry Finger /* 3f1d2b4d3SLarry Finger * Radio tuning for Philips SA2400 on RTL8180 4f1d2b4d3SLarry Finger * 5f1d2b4d3SLarry Finger * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> 6f1d2b4d3SLarry Finger * 7f1d2b4d3SLarry Finger * Code from the BSD driver and the rtl8181 project have been 8f1d2b4d3SLarry Finger * very useful to understand certain things 9f1d2b4d3SLarry Finger * 10f1d2b4d3SLarry Finger * I want to thanks the Authors of such projects and the Ndiswrapper 11f1d2b4d3SLarry Finger * project Authors. 12f1d2b4d3SLarry Finger * 13f1d2b4d3SLarry Finger * A special Big Thanks also is for all people who donated me cards, 14f1d2b4d3SLarry Finger * making possible the creation of the original rtl8180 driver 15f1d2b4d3SLarry Finger * from which this code is derived! 16f1d2b4d3SLarry Finger * 17f1d2b4d3SLarry Finger * This program is free software; you can redistribute it and/or modify 18f1d2b4d3SLarry Finger * it under the terms of the GNU General Public License version 2 as 19f1d2b4d3SLarry Finger * published by the Free Software Foundation. 20f1d2b4d3SLarry Finger */ 21f1d2b4d3SLarry Finger 22f1d2b4d3SLarry Finger #include <linux/pci.h> 23f1d2b4d3SLarry Finger #include <linux/delay.h> 24f1d2b4d3SLarry Finger #include <net/mac80211.h> 25f1d2b4d3SLarry Finger 26f1d2b4d3SLarry Finger #include "rtl8180.h" 27f1d2b4d3SLarry Finger #include "sa2400.h" 28f1d2b4d3SLarry Finger 29f1d2b4d3SLarry Finger static const u32 sa2400_chan[] = { 30f1d2b4d3SLarry Finger 0x00096c, /* ch1 */ 31f1d2b4d3SLarry Finger 0x080970, 32f1d2b4d3SLarry Finger 0x100974, 33f1d2b4d3SLarry Finger 0x180978, 34f1d2b4d3SLarry Finger 0x000980, 35f1d2b4d3SLarry Finger 0x080984, 36f1d2b4d3SLarry Finger 0x100988, 37f1d2b4d3SLarry Finger 0x18098c, 38f1d2b4d3SLarry Finger 0x000994, 39f1d2b4d3SLarry Finger 0x080998, 40f1d2b4d3SLarry Finger 0x10099c, 41f1d2b4d3SLarry Finger 0x1809a0, 42f1d2b4d3SLarry Finger 0x0009a8, 43f1d2b4d3SLarry Finger 0x0009b4, /* ch 14 */ 44f1d2b4d3SLarry Finger }; 45f1d2b4d3SLarry Finger 46f1d2b4d3SLarry Finger static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) 47f1d2b4d3SLarry Finger { 48f1d2b4d3SLarry Finger struct rtl8180_priv *priv = dev->priv; 49f1d2b4d3SLarry Finger u32 phy_config; 50f1d2b4d3SLarry Finger 51f1d2b4d3SLarry Finger /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ 52f1d2b4d3SLarry Finger phy_config = 0xb0000000; 53f1d2b4d3SLarry Finger 54f1d2b4d3SLarry Finger phy_config |= ((u32)(addr & 0xf)) << 24; 55f1d2b4d3SLarry Finger phy_config |= data & 0xffffff; 56f1d2b4d3SLarry Finger 57f1d2b4d3SLarry Finger rtl818x_iowrite32(priv, 58f1d2b4d3SLarry Finger (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); 59f1d2b4d3SLarry Finger 60f1d2b4d3SLarry Finger msleep(3); 61f1d2b4d3SLarry Finger } 62f1d2b4d3SLarry Finger 63f1d2b4d3SLarry Finger static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) 64f1d2b4d3SLarry Finger { 65f1d2b4d3SLarry Finger struct rtl8180_priv *priv = dev->priv; 66f1d2b4d3SLarry Finger u8 ant = SA2400_ANTENNA; 67f1d2b4d3SLarry Finger 68f1d2b4d3SLarry Finger if (priv->rfparam & RF_PARAM_ANTBDEFAULT) 69f1d2b4d3SLarry Finger ant |= BB_ANTENNA_B; 70f1d2b4d3SLarry Finger 71f1d2b4d3SLarry Finger if (chan == 14) 72f1d2b4d3SLarry Finger ant |= BB_ANTATTEN_CHAN14; 73f1d2b4d3SLarry Finger 74f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0x10, ant); 75f1d2b4d3SLarry Finger 76f1d2b4d3SLarry Finger } 77f1d2b4d3SLarry Finger 78f1d2b4d3SLarry Finger static u8 sa2400_rf_rssi_map[] = { 79f1d2b4d3SLarry Finger 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 80f1d2b4d3SLarry Finger 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50, 81f1d2b4d3SLarry Finger 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f, 82f1d2b4d3SLarry Finger 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b, 83f1d2b4d3SLarry Finger 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 84f1d2b4d3SLarry Finger 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, 85f1d2b4d3SLarry Finger 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f, 86f1d2b4d3SLarry Finger 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, 87f1d2b4d3SLarry Finger 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07, 88f1d2b4d3SLarry Finger 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 89f1d2b4d3SLarry Finger }; 90f1d2b4d3SLarry Finger 91f1d2b4d3SLarry Finger static u8 sa2400_rf_calc_rssi(u8 agc, u8 sq) 92f1d2b4d3SLarry Finger { 93f1d2b4d3SLarry Finger if (sq == 0x80) 94f1d2b4d3SLarry Finger return 1; 95f1d2b4d3SLarry Finger 96f1d2b4d3SLarry Finger if (sq > 78) 97f1d2b4d3SLarry Finger return 32; 98f1d2b4d3SLarry Finger 99f1d2b4d3SLarry Finger /* TODO: recalc sa2400_rf_rssi_map to avoid mult / div */ 100f1d2b4d3SLarry Finger return 65 * sa2400_rf_rssi_map[sq] / 100; 101f1d2b4d3SLarry Finger } 102f1d2b4d3SLarry Finger 103f1d2b4d3SLarry Finger static void sa2400_rf_set_channel(struct ieee80211_hw *dev, 104f1d2b4d3SLarry Finger struct ieee80211_conf *conf) 105f1d2b4d3SLarry Finger { 106f1d2b4d3SLarry Finger struct rtl8180_priv *priv = dev->priv; 107f1d2b4d3SLarry Finger int channel = 108f1d2b4d3SLarry Finger ieee80211_frequency_to_channel(conf->chandef.chan->center_freq); 109f1d2b4d3SLarry Finger u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; 110f1d2b4d3SLarry Finger u32 chan = sa2400_chan[channel - 1]; 111f1d2b4d3SLarry Finger 112f1d2b4d3SLarry Finger write_sa2400(dev, 7, txpw); 113f1d2b4d3SLarry Finger 114f1d2b4d3SLarry Finger sa2400_write_phy_antenna(dev, channel); 115f1d2b4d3SLarry Finger 116f1d2b4d3SLarry Finger write_sa2400(dev, 0, chan); 117f1d2b4d3SLarry Finger write_sa2400(dev, 1, 0xbb50); 118f1d2b4d3SLarry Finger write_sa2400(dev, 2, 0x80); 119f1d2b4d3SLarry Finger write_sa2400(dev, 3, 0); 120f1d2b4d3SLarry Finger } 121f1d2b4d3SLarry Finger 122f1d2b4d3SLarry Finger static void sa2400_rf_stop(struct ieee80211_hw *dev) 123f1d2b4d3SLarry Finger { 124f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0); 125f1d2b4d3SLarry Finger } 126f1d2b4d3SLarry Finger 127f1d2b4d3SLarry Finger static void sa2400_rf_init(struct ieee80211_hw *dev) 128f1d2b4d3SLarry Finger { 129f1d2b4d3SLarry Finger struct rtl8180_priv *priv = dev->priv; 130f1d2b4d3SLarry Finger u32 anaparam, txconf; 131f1d2b4d3SLarry Finger u8 firdac; 132f1d2b4d3SLarry Finger int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; 133f1d2b4d3SLarry Finger 134f1d2b4d3SLarry Finger anaparam = priv->anaparam; 135f1d2b4d3SLarry Finger anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); 136f1d2b4d3SLarry Finger anaparam &= ~ANAPARAM_PWR1_MASK; 137f1d2b4d3SLarry Finger anaparam &= ~ANAPARAM_PWR0_MASK; 138f1d2b4d3SLarry Finger 139f1d2b4d3SLarry Finger if (analogphy) { 140f1d2b4d3SLarry Finger anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; 141f1d2b4d3SLarry Finger firdac = 0; 142f1d2b4d3SLarry Finger } else { 143f1d2b4d3SLarry Finger anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); 144f1d2b4d3SLarry Finger anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); 145f1d2b4d3SLarry Finger firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; 146f1d2b4d3SLarry Finger } 147f1d2b4d3SLarry Finger 148f1d2b4d3SLarry Finger rtl8180_set_anaparam(priv, anaparam); 149f1d2b4d3SLarry Finger 150f1d2b4d3SLarry Finger write_sa2400(dev, 0, sa2400_chan[0]); 151f1d2b4d3SLarry Finger write_sa2400(dev, 1, 0xbb50); 152f1d2b4d3SLarry Finger write_sa2400(dev, 2, 0x80); 153f1d2b4d3SLarry Finger write_sa2400(dev, 3, 0); 154f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x19340 | firdac); 155f1d2b4d3SLarry Finger write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); 156f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ 157f1d2b4d3SLarry Finger 158f1d2b4d3SLarry Finger if (!analogphy) 159f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x1938c); /*???*/ 160f1d2b4d3SLarry Finger 161f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x19340 | firdac); 162f1d2b4d3SLarry Finger 163f1d2b4d3SLarry Finger write_sa2400(dev, 0, sa2400_chan[0]); 164f1d2b4d3SLarry Finger write_sa2400(dev, 1, 0xbb50); 165f1d2b4d3SLarry Finger write_sa2400(dev, 2, 0x80); 166f1d2b4d3SLarry Finger write_sa2400(dev, 3, 0); 167f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ 168f1d2b4d3SLarry Finger 169f1d2b4d3SLarry Finger /* new from rtl8180 embedded driver (rtl8181 project) */ 170f1d2b4d3SLarry Finger write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ 171f1d2b4d3SLarry Finger write_sa2400(dev, 8, 0); /* VCO */ 172f1d2b4d3SLarry Finger 173f1d2b4d3SLarry Finger if (analogphy) { 174f1d2b4d3SLarry Finger rtl8180_set_anaparam(priv, anaparam | 175f1d2b4d3SLarry Finger (1 << ANAPARAM_TXDACOFF_SHIFT)); 176f1d2b4d3SLarry Finger 177f1d2b4d3SLarry Finger txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); 178f1d2b4d3SLarry Finger rtl818x_iowrite32(priv, &priv->map->TX_CONF, 179f1d2b4d3SLarry Finger txconf | RTL818X_TX_CONF_LOOPBACK_CONT); 180f1d2b4d3SLarry Finger 181f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x19341); /* calibrates DC */ 182f1d2b4d3SLarry Finger 183f1d2b4d3SLarry Finger /* a 5us sleep is required here, 184f1d2b4d3SLarry Finger * we rely on the 3ms delay introduced in write_sa2400 */ 185f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x19345); 186f1d2b4d3SLarry Finger 187f1d2b4d3SLarry Finger /* a 20us sleep is required here, 188f1d2b4d3SLarry Finger * we rely on the 3ms delay introduced in write_sa2400 */ 189f1d2b4d3SLarry Finger 190f1d2b4d3SLarry Finger rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); 191f1d2b4d3SLarry Finger 192f1d2b4d3SLarry Finger rtl8180_set_anaparam(priv, anaparam); 193f1d2b4d3SLarry Finger } 194f1d2b4d3SLarry Finger /* end new code */ 195f1d2b4d3SLarry Finger 196f1d2b4d3SLarry Finger write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ 197f1d2b4d3SLarry Finger 198f1d2b4d3SLarry Finger /* baseband configuration */ 199f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0, 0x98); 200f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 3, 0x38); 201f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 4, 0xe0); 202f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 5, 0x90); 203f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 6, 0x1a); 204f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 7, 0x64); 205f1d2b4d3SLarry Finger 206f1d2b4d3SLarry Finger sa2400_write_phy_antenna(dev, 1); 207f1d2b4d3SLarry Finger 208f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0x11, 0x80); 209f1d2b4d3SLarry Finger 210f1d2b4d3SLarry Finger if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & 211f1d2b4d3SLarry Finger RTL818X_CONFIG2_ANTENNA_DIV) 212f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ 213f1d2b4d3SLarry Finger else 214f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ 215f1d2b4d3SLarry Finger 216f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); 217f1d2b4d3SLarry Finger 218f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0x19, 0x0); 219f1d2b4d3SLarry Finger rtl8180_write_phy(dev, 0x1a, 0xa0); 220f1d2b4d3SLarry Finger } 221f1d2b4d3SLarry Finger 222f1d2b4d3SLarry Finger const struct rtl818x_rf_ops sa2400_rf_ops = { 223f1d2b4d3SLarry Finger .name = "Philips", 224f1d2b4d3SLarry Finger .init = sa2400_rf_init, 225f1d2b4d3SLarry Finger .stop = sa2400_rf_stop, 226f1d2b4d3SLarry Finger .set_chan = sa2400_rf_set_channel, 227f1d2b4d3SLarry Finger .calc_rssi = sa2400_rf_calc_rssi, 228f1d2b4d3SLarry Finger }; 229