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