18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * Radio tuning for Philips SA2400 on RTL8180 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Code from the BSD driver and the rtl8181 project have been 98c2ecf20Sopenharmony_ci * very useful to understand certain things 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * I want to thanks the Authors of such projects and the Ndiswrapper 128c2ecf20Sopenharmony_ci * project Authors. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * A special Big Thanks also is for all people who donated me cards, 158c2ecf20Sopenharmony_ci * making possible the creation of the original rtl8180 driver 168c2ecf20Sopenharmony_ci * from which this code is derived! 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/delay.h> 218c2ecf20Sopenharmony_ci#include <net/mac80211.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "rtl8180.h" 248c2ecf20Sopenharmony_ci#include "sa2400.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const u32 sa2400_chan[] = { 278c2ecf20Sopenharmony_ci 0x00096c, /* ch1 */ 288c2ecf20Sopenharmony_ci 0x080970, 298c2ecf20Sopenharmony_ci 0x100974, 308c2ecf20Sopenharmony_ci 0x180978, 318c2ecf20Sopenharmony_ci 0x000980, 328c2ecf20Sopenharmony_ci 0x080984, 338c2ecf20Sopenharmony_ci 0x100988, 348c2ecf20Sopenharmony_ci 0x18098c, 358c2ecf20Sopenharmony_ci 0x000994, 368c2ecf20Sopenharmony_ci 0x080998, 378c2ecf20Sopenharmony_ci 0x10099c, 388c2ecf20Sopenharmony_ci 0x1809a0, 398c2ecf20Sopenharmony_ci 0x0009a8, 408c2ecf20Sopenharmony_ci 0x0009b4, /* ch 14 */ 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 468c2ecf20Sopenharmony_ci u32 phy_config; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ 498c2ecf20Sopenharmony_ci phy_config = 0xb0000000; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci phy_config |= ((u32)(addr & 0xf)) << 24; 528c2ecf20Sopenharmony_ci phy_config |= data & 0xffffff; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, 558c2ecf20Sopenharmony_ci (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci msleep(3); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 638c2ecf20Sopenharmony_ci u8 ant = SA2400_ANTENNA; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (priv->rfparam & RF_PARAM_ANTBDEFAULT) 668c2ecf20Sopenharmony_ci ant |= BB_ANTENNA_B; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (chan == 14) 698c2ecf20Sopenharmony_ci ant |= BB_ANTATTEN_CHAN14; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0x10, ant); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic u8 sa2400_rf_rssi_map[] = { 768c2ecf20Sopenharmony_ci 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 778c2ecf20Sopenharmony_ci 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50, 788c2ecf20Sopenharmony_ci 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f, 798c2ecf20Sopenharmony_ci 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b, 808c2ecf20Sopenharmony_ci 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 818c2ecf20Sopenharmony_ci 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, 828c2ecf20Sopenharmony_ci 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f, 838c2ecf20Sopenharmony_ci 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, 848c2ecf20Sopenharmony_ci 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07, 858c2ecf20Sopenharmony_ci 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic u8 sa2400_rf_calc_rssi(u8 agc, u8 sq) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci if (sq == 0x80) 918c2ecf20Sopenharmony_ci return 1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (sq > 78) 948c2ecf20Sopenharmony_ci return 32; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* TODO: recalc sa2400_rf_rssi_map to avoid mult / div */ 978c2ecf20Sopenharmony_ci return 65 * sa2400_rf_rssi_map[sq] / 100; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void sa2400_rf_set_channel(struct ieee80211_hw *dev, 1018c2ecf20Sopenharmony_ci struct ieee80211_conf *conf) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 1048c2ecf20Sopenharmony_ci int channel = 1058c2ecf20Sopenharmony_ci ieee80211_frequency_to_channel(conf->chandef.chan->center_freq); 1068c2ecf20Sopenharmony_ci u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; 1078c2ecf20Sopenharmony_ci u32 chan = sa2400_chan[channel - 1]; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci write_sa2400(dev, 7, txpw); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci sa2400_write_phy_antenna(dev, channel); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci write_sa2400(dev, 0, chan); 1148c2ecf20Sopenharmony_ci write_sa2400(dev, 1, 0xbb50); 1158c2ecf20Sopenharmony_ci write_sa2400(dev, 2, 0x80); 1168c2ecf20Sopenharmony_ci write_sa2400(dev, 3, 0); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void sa2400_rf_stop(struct ieee80211_hw *dev) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void sa2400_rf_init(struct ieee80211_hw *dev) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 1278c2ecf20Sopenharmony_ci u32 anaparam, txconf; 1288c2ecf20Sopenharmony_ci u8 firdac; 1298c2ecf20Sopenharmony_ci int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci anaparam = priv->anaparam; 1328c2ecf20Sopenharmony_ci anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); 1338c2ecf20Sopenharmony_ci anaparam &= ~ANAPARAM_PWR1_MASK; 1348c2ecf20Sopenharmony_ci anaparam &= ~ANAPARAM_PWR0_MASK; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (analogphy) { 1378c2ecf20Sopenharmony_ci anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; 1388c2ecf20Sopenharmony_ci firdac = 0; 1398c2ecf20Sopenharmony_ci } else { 1408c2ecf20Sopenharmony_ci anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); 1418c2ecf20Sopenharmony_ci anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); 1428c2ecf20Sopenharmony_ci firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci rtl8180_set_anaparam(priv, anaparam); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci write_sa2400(dev, 0, sa2400_chan[0]); 1488c2ecf20Sopenharmony_ci write_sa2400(dev, 1, 0xbb50); 1498c2ecf20Sopenharmony_ci write_sa2400(dev, 2, 0x80); 1508c2ecf20Sopenharmony_ci write_sa2400(dev, 3, 0); 1518c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x19340 | firdac); 1528c2ecf20Sopenharmony_ci write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); 1538c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (!analogphy) 1568c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x1938c); /*???*/ 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x19340 | firdac); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci write_sa2400(dev, 0, sa2400_chan[0]); 1618c2ecf20Sopenharmony_ci write_sa2400(dev, 1, 0xbb50); 1628c2ecf20Sopenharmony_ci write_sa2400(dev, 2, 0x80); 1638c2ecf20Sopenharmony_ci write_sa2400(dev, 3, 0); 1648c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* new from rtl8180 embedded driver (rtl8181 project) */ 1678c2ecf20Sopenharmony_ci write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ 1688c2ecf20Sopenharmony_ci write_sa2400(dev, 8, 0); /* VCO */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (analogphy) { 1718c2ecf20Sopenharmony_ci rtl8180_set_anaparam(priv, anaparam | 1728c2ecf20Sopenharmony_ci (1 << ANAPARAM_TXDACOFF_SHIFT)); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); 1758c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TX_CONF, 1768c2ecf20Sopenharmony_ci txconf | RTL818X_TX_CONF_LOOPBACK_CONT); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x19341); /* calibrates DC */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* a 5us sleep is required here, 1818c2ecf20Sopenharmony_ci * we rely on the 3ms delay introduced in write_sa2400 */ 1828c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x19345); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* a 20us sleep is required here, 1858c2ecf20Sopenharmony_ci * we rely on the 3ms delay introduced in write_sa2400 */ 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci rtl8180_set_anaparam(priv, anaparam); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci /* end new code */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* baseband configuration */ 1968c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0, 0x98); 1978c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 3, 0x38); 1988c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 4, 0xe0); 1998c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 5, 0x90); 2008c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 6, 0x1a); 2018c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 7, 0x64); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci sa2400_write_phy_antenna(dev, 1); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0x11, 0x80); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & 2088c2ecf20Sopenharmony_ci RTL818X_CONFIG2_ANTENNA_DIV) 2098c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ 2108c2ecf20Sopenharmony_ci else 2118c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0x19, 0x0); 2168c2ecf20Sopenharmony_ci rtl8180_write_phy(dev, 0x1a, 0xa0); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciconst struct rtl818x_rf_ops sa2400_rf_ops = { 2208c2ecf20Sopenharmony_ci .name = "Philips", 2218c2ecf20Sopenharmony_ci .init = sa2400_rf_init, 2228c2ecf20Sopenharmony_ci .stop = sa2400_rf_stop, 2238c2ecf20Sopenharmony_ci .set_chan = sa2400_rf_set_channel, 2248c2ecf20Sopenharmony_ci .calc_rssi = sa2400_rf_calc_rssi, 2258c2ecf20Sopenharmony_ci}; 226