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