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 | ||
79 | static void sa2400_rf_set_channel(struct ieee80211_hw *dev, | |
80 | struct ieee80211_conf *conf) | |
81 | { | |
82 | struct rtl8180_priv *priv = dev->priv; | |
8318d78a JB |
83 | int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); |
84 | u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; | |
85 | u32 chan = sa2400_chan[channel - 1]; | |
f6532111 MW |
86 | |
87 | write_sa2400(dev, 7, txpw); | |
88 | ||
0823b2c3 | 89 | sa2400_write_phy_antenna(dev, channel); |
f6532111 MW |
90 | |
91 | write_sa2400(dev, 0, chan); | |
92 | write_sa2400(dev, 1, 0xbb50); | |
93 | write_sa2400(dev, 2, 0x80); | |
94 | write_sa2400(dev, 3, 0); | |
95 | } | |
96 | ||
97 | static void sa2400_rf_stop(struct ieee80211_hw *dev) | |
98 | { | |
99 | write_sa2400(dev, 4, 0); | |
100 | } | |
101 | ||
102 | static void sa2400_rf_init(struct ieee80211_hw *dev) | |
103 | { | |
104 | struct rtl8180_priv *priv = dev->priv; | |
105 | u32 anaparam, txconf; | |
106 | u8 firdac; | |
107 | int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; | |
108 | ||
109 | anaparam = priv->anaparam; | |
110 | anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); | |
111 | anaparam &= ~ANAPARAM_PWR1_MASK; | |
112 | anaparam &= ~ANAPARAM_PWR0_MASK; | |
113 | ||
114 | if (analogphy) { | |
115 | anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; | |
116 | firdac = 0; | |
117 | } else { | |
118 | anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); | |
119 | anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); | |
120 | firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; | |
121 | } | |
122 | ||
123 | rtl8180_set_anaparam(priv, anaparam); | |
124 | ||
125 | write_sa2400(dev, 0, sa2400_chan[0]); | |
126 | write_sa2400(dev, 1, 0xbb50); | |
127 | write_sa2400(dev, 2, 0x80); | |
128 | write_sa2400(dev, 3, 0); | |
129 | write_sa2400(dev, 4, 0x19340 | firdac); | |
130 | write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); | |
131 | write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ | |
132 | ||
133 | if (!analogphy) | |
134 | write_sa2400(dev, 4, 0x1938c); /*???*/ | |
135 | ||
136 | write_sa2400(dev, 4, 0x19340 | firdac); | |
137 | ||
138 | write_sa2400(dev, 0, sa2400_chan[0]); | |
139 | write_sa2400(dev, 1, 0xbb50); | |
140 | write_sa2400(dev, 2, 0x80); | |
141 | write_sa2400(dev, 3, 0); | |
142 | write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ | |
143 | ||
144 | /* new from rtl8180 embedded driver (rtl8181 project) */ | |
145 | write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ | |
146 | write_sa2400(dev, 8, 0); /* VCO */ | |
147 | ||
148 | if (analogphy) { | |
149 | rtl8180_set_anaparam(priv, anaparam | | |
150 | (1 << ANAPARAM_TXDACOFF_SHIFT)); | |
151 | ||
152 | txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); | |
153 | rtl818x_iowrite32(priv, &priv->map->TX_CONF, | |
154 | txconf | RTL818X_TX_CONF_LOOPBACK_CONT); | |
155 | ||
156 | write_sa2400(dev, 4, 0x19341); /* calibrates DC */ | |
157 | ||
158 | /* a 5us sleep is required here, | |
159 | * we rely on the 3ms delay introduced in write_sa2400 */ | |
160 | write_sa2400(dev, 4, 0x19345); | |
161 | ||
162 | /* a 20us sleep is required here, | |
163 | * we rely on the 3ms delay introduced in write_sa2400 */ | |
164 | ||
165 | rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); | |
166 | ||
167 | rtl8180_set_anaparam(priv, anaparam); | |
168 | } | |
169 | /* end new code */ | |
170 | ||
171 | write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ | |
172 | ||
173 | /* baseband configuration */ | |
174 | rtl8180_write_phy(dev, 0, 0x98); | |
175 | rtl8180_write_phy(dev, 3, 0x38); | |
176 | rtl8180_write_phy(dev, 4, 0xe0); | |
177 | rtl8180_write_phy(dev, 5, 0x90); | |
178 | rtl8180_write_phy(dev, 6, 0x1a); | |
179 | rtl8180_write_phy(dev, 7, 0x64); | |
180 | ||
181 | sa2400_write_phy_antenna(dev, 1); | |
182 | ||
183 | rtl8180_write_phy(dev, 0x11, 0x80); | |
184 | ||
185 | if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & | |
186 | RTL818X_CONFIG2_ANTENNA_DIV) | |
187 | rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ | |
188 | else | |
189 | rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ | |
190 | ||
191 | rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); | |
192 | ||
193 | rtl8180_write_phy(dev, 0x19, 0x0); | |
194 | rtl8180_write_phy(dev, 0x1a, 0xa0); | |
195 | } | |
196 | ||
197 | const struct rtl818x_rf_ops sa2400_rf_ops = { | |
198 | .name = "Philips", | |
199 | .init = sa2400_rf_init, | |
200 | .stop = sa2400_rf_stop, | |
201 | .set_chan = sa2400_rf_set_channel | |
202 | }; |