162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Radio tuning for Philips SA2400 on RTL8180 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Code from the BSD driver and the rtl8181 project have been 962306a36Sopenharmony_ci * very useful to understand certain things 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * I want to thanks the Authors of such projects and the Ndiswrapper 1262306a36Sopenharmony_ci * project Authors. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * A special Big Thanks also is for all people who donated me cards, 1562306a36Sopenharmony_ci * making possible the creation of the original rtl8180 driver 1662306a36Sopenharmony_ci * from which this code is derived! 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/pci.h> 2062306a36Sopenharmony_ci#include <linux/delay.h> 2162306a36Sopenharmony_ci#include <net/mac80211.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "rtl8180.h" 2462306a36Sopenharmony_ci#include "sa2400.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const u32 sa2400_chan[] = { 2762306a36Sopenharmony_ci 0x00096c, /* ch1 */ 2862306a36Sopenharmony_ci 0x080970, 2962306a36Sopenharmony_ci 0x100974, 3062306a36Sopenharmony_ci 0x180978, 3162306a36Sopenharmony_ci 0x000980, 3262306a36Sopenharmony_ci 0x080984, 3362306a36Sopenharmony_ci 0x100988, 3462306a36Sopenharmony_ci 0x18098c, 3562306a36Sopenharmony_ci 0x000994, 3662306a36Sopenharmony_ci 0x080998, 3762306a36Sopenharmony_ci 0x10099c, 3862306a36Sopenharmony_ci 0x1809a0, 3962306a36Sopenharmony_ci 0x0009a8, 4062306a36Sopenharmony_ci 0x0009b4, /* ch 14 */ 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 4662306a36Sopenharmony_ci u32 phy_config; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ 4962306a36Sopenharmony_ci phy_config = 0xb0000000; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci phy_config |= ((u32)(addr & 0xf)) << 24; 5262306a36Sopenharmony_ci phy_config |= data & 0xffffff; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci rtl818x_iowrite32(priv, 5562306a36Sopenharmony_ci (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci msleep(3); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 6362306a36Sopenharmony_ci u8 ant = SA2400_ANTENNA; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (priv->rfparam & RF_PARAM_ANTBDEFAULT) 6662306a36Sopenharmony_ci ant |= BB_ANTENNA_B; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (chan == 14) 6962306a36Sopenharmony_ci ant |= BB_ANTATTEN_CHAN14; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x10, ant); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic u8 sa2400_rf_rssi_map[] = { 7662306a36Sopenharmony_ci 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 7762306a36Sopenharmony_ci 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50, 7862306a36Sopenharmony_ci 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f, 7962306a36Sopenharmony_ci 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b, 8062306a36Sopenharmony_ci 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 8162306a36Sopenharmony_ci 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, 8262306a36Sopenharmony_ci 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f, 8362306a36Sopenharmony_ci 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, 8462306a36Sopenharmony_ci 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07, 8562306a36Sopenharmony_ci 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic u8 sa2400_rf_calc_rssi(u8 agc, u8 sq) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci if (sq == 0x80) 9162306a36Sopenharmony_ci return 1; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (sq > 78) 9462306a36Sopenharmony_ci return 32; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* TODO: recalc sa2400_rf_rssi_map to avoid mult / div */ 9762306a36Sopenharmony_ci return 65 * sa2400_rf_rssi_map[sq] / 100; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void sa2400_rf_set_channel(struct ieee80211_hw *dev, 10162306a36Sopenharmony_ci struct ieee80211_conf *conf) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 10462306a36Sopenharmony_ci int channel = 10562306a36Sopenharmony_ci ieee80211_frequency_to_channel(conf->chandef.chan->center_freq); 10662306a36Sopenharmony_ci u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; 10762306a36Sopenharmony_ci u32 chan = sa2400_chan[channel - 1]; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci write_sa2400(dev, 7, txpw); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci sa2400_write_phy_antenna(dev, channel); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci write_sa2400(dev, 0, chan); 11462306a36Sopenharmony_ci write_sa2400(dev, 1, 0xbb50); 11562306a36Sopenharmony_ci write_sa2400(dev, 2, 0x80); 11662306a36Sopenharmony_ci write_sa2400(dev, 3, 0); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void sa2400_rf_stop(struct ieee80211_hw *dev) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci write_sa2400(dev, 4, 0); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void sa2400_rf_init(struct ieee80211_hw *dev) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 12762306a36Sopenharmony_ci u32 anaparam, txconf; 12862306a36Sopenharmony_ci u8 firdac; 12962306a36Sopenharmony_ci int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci anaparam = priv->anaparam; 13262306a36Sopenharmony_ci anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); 13362306a36Sopenharmony_ci anaparam &= ~ANAPARAM_PWR1_MASK; 13462306a36Sopenharmony_ci anaparam &= ~ANAPARAM_PWR0_MASK; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (analogphy) { 13762306a36Sopenharmony_ci anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; 13862306a36Sopenharmony_ci firdac = 0; 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); 14162306a36Sopenharmony_ci anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); 14262306a36Sopenharmony_ci firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci rtl8180_set_anaparam(priv, anaparam); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci write_sa2400(dev, 0, sa2400_chan[0]); 14862306a36Sopenharmony_ci write_sa2400(dev, 1, 0xbb50); 14962306a36Sopenharmony_ci write_sa2400(dev, 2, 0x80); 15062306a36Sopenharmony_ci write_sa2400(dev, 3, 0); 15162306a36Sopenharmony_ci write_sa2400(dev, 4, 0x19340 | firdac); 15262306a36Sopenharmony_ci write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); 15362306a36Sopenharmony_ci write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (!analogphy) 15662306a36Sopenharmony_ci write_sa2400(dev, 4, 0x1938c); /*???*/ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci write_sa2400(dev, 4, 0x19340 | firdac); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci write_sa2400(dev, 0, sa2400_chan[0]); 16162306a36Sopenharmony_ci write_sa2400(dev, 1, 0xbb50); 16262306a36Sopenharmony_ci write_sa2400(dev, 2, 0x80); 16362306a36Sopenharmony_ci write_sa2400(dev, 3, 0); 16462306a36Sopenharmony_ci write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* new from rtl8180 embedded driver (rtl8181 project) */ 16762306a36Sopenharmony_ci write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ 16862306a36Sopenharmony_ci write_sa2400(dev, 8, 0); /* VCO */ 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (analogphy) { 17162306a36Sopenharmony_ci rtl8180_set_anaparam(priv, anaparam | 17262306a36Sopenharmony_ci (1 << ANAPARAM_TXDACOFF_SHIFT)); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); 17562306a36Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TX_CONF, 17662306a36Sopenharmony_ci txconf | RTL818X_TX_CONF_LOOPBACK_CONT); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci write_sa2400(dev, 4, 0x19341); /* calibrates DC */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* a 5us sleep is required here, 18162306a36Sopenharmony_ci * we rely on the 3ms delay introduced in write_sa2400 */ 18262306a36Sopenharmony_ci write_sa2400(dev, 4, 0x19345); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* a 20us sleep is required here, 18562306a36Sopenharmony_ci * we rely on the 3ms delay introduced in write_sa2400 */ 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci rtl8180_set_anaparam(priv, anaparam); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci /* end new code */ 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* baseband configuration */ 19662306a36Sopenharmony_ci rtl8180_write_phy(dev, 0, 0x98); 19762306a36Sopenharmony_ci rtl8180_write_phy(dev, 3, 0x38); 19862306a36Sopenharmony_ci rtl8180_write_phy(dev, 4, 0xe0); 19962306a36Sopenharmony_ci rtl8180_write_phy(dev, 5, 0x90); 20062306a36Sopenharmony_ci rtl8180_write_phy(dev, 6, 0x1a); 20162306a36Sopenharmony_ci rtl8180_write_phy(dev, 7, 0x64); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci sa2400_write_phy_antenna(dev, 1); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x11, 0x80); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & 20862306a36Sopenharmony_ci RTL818X_CONFIG2_ANTENNA_DIV) 20962306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ 21062306a36Sopenharmony_ci else 21162306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x19, 0x0); 21662306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x1a, 0xa0); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciconst struct rtl818x_rf_ops sa2400_rf_ops = { 22062306a36Sopenharmony_ci .name = "Philips", 22162306a36Sopenharmony_ci .init = sa2400_rf_init, 22262306a36Sopenharmony_ci .stop = sa2400_rf_stop, 22362306a36Sopenharmony_ci .set_chan = sa2400_rf_set_channel, 22462306a36Sopenharmony_ci .calc_rssi = sa2400_rf_calc_rssi, 22562306a36Sopenharmony_ci}; 226