162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Radio tuning for Maxim max2820 on RTL8180 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2007 Andrea Merello <andrea.merello@gmail.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Code from the BSD driver and the rtl8181 project have been 862306a36Sopenharmony_ci * very useful to understand certain things 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * I want to thanks the Authors of such projects and the Ndiswrapper 1162306a36Sopenharmony_ci * project Authors. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * A special Big Thanks also is for all people who donated me cards, 1462306a36Sopenharmony_ci * making possible the creation of the original rtl8180 driver 1562306a36Sopenharmony_ci * from which this code is derived! 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/pci.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <net/mac80211.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "rtl8180.h" 2362306a36Sopenharmony_ci#include "max2820.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic const u32 max2820_chan[] = { 2662306a36Sopenharmony_ci 12, /* CH 1 */ 2762306a36Sopenharmony_ci 17, 2862306a36Sopenharmony_ci 22, 2962306a36Sopenharmony_ci 27, 3062306a36Sopenharmony_ci 32, 3162306a36Sopenharmony_ci 37, 3262306a36Sopenharmony_ci 42, 3362306a36Sopenharmony_ci 47, 3462306a36Sopenharmony_ci 52, 3562306a36Sopenharmony_ci 57, 3662306a36Sopenharmony_ci 62, 3762306a36Sopenharmony_ci 67, 3862306a36Sopenharmony_ci 72, 3962306a36Sopenharmony_ci 84, /* CH 14 */ 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 4562306a36Sopenharmony_ci u32 phy_config; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci phy_config = 0x90 + (data & 0xf); 4862306a36Sopenharmony_ci phy_config <<= 16; 4962306a36Sopenharmony_ci phy_config += addr; 5062306a36Sopenharmony_ci phy_config <<= 8; 5162306a36Sopenharmony_ci phy_config += (data >> 4) & 0xff; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci rtl818x_iowrite32(priv, 5462306a36Sopenharmony_ci (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci msleep(1); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 6262306a36Sopenharmony_ci u8 ant; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ant = MAXIM_ANTENNA; 6562306a36Sopenharmony_ci if (priv->rfparam & RF_PARAM_ANTBDEFAULT) 6662306a36Sopenharmony_ci ant |= BB_ANTENNA_B; 6762306a36Sopenharmony_ci if (chan == 14) 6862306a36Sopenharmony_ci ant |= BB_ANTATTEN_CHAN14; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x10, ant); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic u8 max2820_rf_calc_rssi(u8 agc, u8 sq) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci bool odd; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci odd = !!(agc & 1); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci agc >>= 1; 8062306a36Sopenharmony_ci if (odd) 8162306a36Sopenharmony_ci agc += 76; 8262306a36Sopenharmony_ci else 8362306a36Sopenharmony_ci agc += 66; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* TODO: change addends above to avoid mult / div below */ 8662306a36Sopenharmony_ci return 65 * agc / 100; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void max2820_rf_set_channel(struct ieee80211_hw *dev, 9062306a36Sopenharmony_ci struct ieee80211_conf *conf) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 9362306a36Sopenharmony_ci int channel = conf ? 9462306a36Sopenharmony_ci ieee80211_frequency_to_channel(conf->chandef.chan->center_freq) : 1; 9562306a36Sopenharmony_ci unsigned int chan_idx = channel - 1; 9662306a36Sopenharmony_ci u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; 9762306a36Sopenharmony_ci u32 chan = max2820_chan[chan_idx]; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* While philips SA2400 drive the PA bias from 10062306a36Sopenharmony_ci * sa2400, for MAXIM we do this directly from BB */ 10162306a36Sopenharmony_ci rtl8180_write_phy(dev, 3, txpw); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci max2820_write_phy_antenna(dev, channel); 10462306a36Sopenharmony_ci write_max2820(dev, 3, chan); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic void max2820_rf_stop(struct ieee80211_hw *dev) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci rtl8180_write_phy(dev, 3, 0x8); 11062306a36Sopenharmony_ci write_max2820(dev, 1, 0); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void max2820_rf_init(struct ieee80211_hw *dev) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct rtl8180_priv *priv = dev->priv; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* MAXIM from netbsd driver */ 11962306a36Sopenharmony_ci write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ 12062306a36Sopenharmony_ci write_max2820(dev, 1, 0x01e); /* enable register */ 12162306a36Sopenharmony_ci write_max2820(dev, 2, 0x001); /* synt register */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci max2820_rf_set_channel(dev, NULL); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci write_max2820(dev, 4, 0x313); /* rx register */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* PA is driven directly by the BB, we keep the MAXIM bias 12862306a36Sopenharmony_ci * at the highest value in case that setting it to lower 12962306a36Sopenharmony_ci * values may introduce some further attenuation somewhere.. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci write_max2820(dev, 5, 0x00f); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* baseband configuration */ 13462306a36Sopenharmony_ci rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ 13562306a36Sopenharmony_ci rtl8180_write_phy(dev, 3, 0x08); /* txagc */ 13662306a36Sopenharmony_ci rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ 13762306a36Sopenharmony_ci rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ 13862306a36Sopenharmony_ci rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ 13962306a36Sopenharmony_ci rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci max2820_write_phy_antenna(dev, 1); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & 14662306a36Sopenharmony_ci RTL818X_CONFIG2_ANTENNA_DIV) 14762306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x12, 0xc7); 14862306a36Sopenharmony_ci else 14962306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x12, 0x47); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x13, 0x9b); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ 15462306a36Sopenharmony_ci rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci max2820_rf_set_channel(dev, NULL); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ciconst struct rtl818x_rf_ops max2820_rf_ops = { 16062306a36Sopenharmony_ci .name = "Maxim", 16162306a36Sopenharmony_ci .init = max2820_rf_init, 16262306a36Sopenharmony_ci .stop = max2820_rf_stop, 16362306a36Sopenharmony_ci .set_chan = max2820_rf_set_channel, 16462306a36Sopenharmony_ci .calc_rssi = max2820_rf_calc_rssi, 16562306a36Sopenharmony_ci}; 166