1d2912cb1SThomas 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