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