aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rtl8187_rtl8225.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-09 18:26:43 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-09 18:26:43 -0400
commit71ba22fa739029bb158144813b9e82c00326497c (patch)
treecca33deab3b79b38e15e6b3f7d7f9dfbf7ab32a2 /drivers/net/wireless/rtl8187_rtl8225.c
parent27a278aa4309df244a2619f47031acce00ca1b7c (diff)
parentf2ec8030085a27c4ba8e95a10a96f248efb34177 (diff)
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (75 commits) Ethernet driver for EISA only SNI RM200/RM400 machines Extract chip specific code out of lasi_82596.c ehea: Whitespace cleanup pasemi_mac: Fix TX interrupt threshold spidernet: Replace literal with const r8169: perform RX config change after mac filtering r8169: mac address change support r8169: display some extra debug information during startup r8169: add endianess annotations to [RT]xDesc r8169: align the IP header when there is no DMA constraint r8169: add bit description for the TxPoll register r8169: cleanup r8169: remove the media option r8169: small 8101 comment r8169: confusion between hardware and IP header alignment r8169: merge with version 8.001.00 of Realtek's r8168 driver r8169: merge with version 6.001.00 of Realtek's r8169 driver r8169: prettify mac_version r8169: populate the hw_start handler for the 8110 r8169: populate the hw_start handler for the 8168 ...
Diffstat (limited to 'drivers/net/wireless/rtl8187_rtl8225.c')
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.c745
1 files changed, 745 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c
new file mode 100644
index 000000000000..e25a09f1b068
--- /dev/null
+++ b/drivers/net/wireless/rtl8187_rtl8225.c
@@ -0,0 +1,745 @@
1/*
2 * Radio tuning for RTL8225 on RTL8187
3 *
4 * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
5 * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
6 *
7 * Based on the r8187 driver, which is:
8 * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
9 *
10 * Magic delays, register offsets, and phy value tables below are
11 * taken from the original r8187 driver sources. Thanks to Realtek
12 * for their support!
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
19#include <linux/init.h>
20#include <linux/usb.h>
21#include <net/mac80211.h>
22
23#include "rtl8187.h"
24#include "rtl8187_rtl8225.h"
25
26static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
27{
28 struct rtl8187_priv *priv = dev->priv;
29 u16 reg80, reg84, reg82;
30 u32 bangdata;
31 int i;
32
33 bangdata = (data << 4) | (addr & 0xf);
34
35 reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
36 reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
37
38 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
39
40 reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
41 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);
42 udelay(10);
43
44 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
45 udelay(2);
46 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
47 udelay(10);
48
49 for (i = 15; i >= 0; i--) {
50 u16 reg = reg80 | (bangdata & (1 << i)) >> i;
51
52 if (i & 1)
53 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
54
55 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
56 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
57
58 if (!(i & 1))
59 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
60 }
61
62 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
63 udelay(10);
64
65 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
66 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
67 msleep(2);
68}
69
70static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data)
71{
72 struct rtl8187_priv *priv = dev->priv;
73 u16 reg80, reg82, reg84;
74
75 reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
76 reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
77 reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
78
79 reg80 &= ~(0x3 << 2);
80 reg84 &= ~0xF;
81
82 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007);
83 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007);
84 udelay(10);
85
86 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
87 udelay(2);
88
89 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
90 udelay(10);
91
92 usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
93 RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
94 addr, 0x8225, &data, sizeof(data), HZ / 2);
95
96 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
97 udelay(10);
98
99 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
100 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
101 msleep(2);
102}
103
104void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
105{
106 struct rtl8187_priv *priv = dev->priv;
107
108 if (priv->asic_rev)
109 rtl8225_write_8051(dev, addr, data);
110 else
111 rtl8225_write_bitbang(dev, addr, data);
112}
113
114u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
115{
116 struct rtl8187_priv *priv = dev->priv;
117 u16 reg80, reg82, reg84, out;
118 int i;
119
120 reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
121 reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
122 reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
123
124 reg80 &= ~0xF;
125
126 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
127 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
128
129 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
130 udelay(4);
131 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
132 udelay(5);
133
134 for (i = 4; i >= 0; i--) {
135 u16 reg = reg80 | ((addr >> i) & 1);
136
137 if (!(i & 1)) {
138 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
139 udelay(1);
140 }
141
142 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
143 reg | (1 << 1));
144 udelay(2);
145 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
146 reg | (1 << 1));
147 udelay(2);
148
149 if (i & 1) {
150 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
151 udelay(1);
152 }
153 }
154
155 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
156 reg80 | (1 << 3) | (1 << 1));
157 udelay(2);
158 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
159 reg80 | (1 << 3));
160 udelay(2);
161 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
162 reg80 | (1 << 3));
163 udelay(2);
164
165 out = 0;
166 for (i = 11; i >= 0; i--) {
167 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
168 reg80 | (1 << 3));
169 udelay(1);
170 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
171 reg80 | (1 << 3) | (1 << 1));
172 udelay(2);
173 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
174 reg80 | (1 << 3) | (1 << 1));
175 udelay(2);
176 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
177 reg80 | (1 << 3) | (1 << 1));
178 udelay(2);
179
180 if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
181 out |= 1 << i;
182
183 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
184 reg80 | (1 << 3));
185 udelay(2);
186 }
187
188 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
189 reg80 | (1 << 3) | (1 << 2));
190 udelay(2);
191
192 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
193 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
194 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
195
196 return out;
197}
198
199static const u16 rtl8225bcd_rxgain[] = {
200 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
201 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
202 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
203 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
204 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
205 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
206 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
207 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
208 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
209 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
210 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
211 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
212};
213
214static const u8 rtl8225_agc[] = {
215 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
216 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
217 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
218 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
219 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
220 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
221 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
222 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
223 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
224 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
225 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
226 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
227 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
228 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
229 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
230 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
231};
232
233static const u8 rtl8225_gain[] = {
234 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */
235 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */
236 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */
237 0x33, 0x80, 0x79, 0xc5, /* -78dBm */
238 0x43, 0x78, 0x76, 0xc5, /* -74dBm */
239 0x53, 0x60, 0x73, 0xc5, /* -70dBm */
240 0x63, 0x58, 0x70, 0xc5, /* -66dBm */
241};
242
243static const u8 rtl8225_threshold[] = {
244 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
245};
246
247static const u8 rtl8225_tx_gain_cck_ofdm[] = {
248 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
249};
250
251static const u8 rtl8225_tx_power_cck[] = {
252 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
253 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
254 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
255 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
256 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
257 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
258};
259
260static const u8 rtl8225_tx_power_cck_ch14[] = {
261 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
262 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
263 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
264 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
265 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
266 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
267};
268
269static const u8 rtl8225_tx_power_ofdm[] = {
270 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
271};
272
273static const u32 rtl8225_chan[] = {
274 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
275 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
276};
277
278static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
279{
280 struct rtl8187_priv *priv = dev->priv;
281 u8 cck_power, ofdm_power;
282 const u8 *tmp;
283 u32 reg;
284 int i;
285
286 cck_power = priv->channels[channel - 1].val & 0xF;
287 ofdm_power = priv->channels[channel - 1].val >> 4;
288
289 cck_power = min(cck_power, (u8)11);
290 ofdm_power = min(ofdm_power, (u8)35);
291
292 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
293 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
294
295 if (channel == 14)
296 tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
297 else
298 tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
299
300 for (i = 0; i < 8; i++)
301 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
302
303 msleep(1); // FIXME: optional?
304
305 /* anaparam2 on */
306 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
307 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
308 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
309 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
310 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
311 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
312
313 rtl8225_write_phy_ofdm(dev, 2, 0x42);
314 rtl8225_write_phy_ofdm(dev, 6, 0x00);
315 rtl8225_write_phy_ofdm(dev, 8, 0x00);
316
317 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
318 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
319
320 tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
321
322 rtl8225_write_phy_ofdm(dev, 5, *tmp);
323 rtl8225_write_phy_ofdm(dev, 7, *tmp);
324
325 msleep(1);
326}
327
328void rtl8225_rf_init(struct ieee80211_hw *dev)
329{
330 struct rtl8187_priv *priv = dev->priv;
331 int i;
332
333 rtl8225_write(dev, 0x0, 0x067); msleep(1);
334 rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
335 rtl8225_write(dev, 0x2, 0x44D); msleep(1);
336 rtl8225_write(dev, 0x3, 0x441); msleep(1);
337 rtl8225_write(dev, 0x4, 0x486); msleep(1);
338 rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
339 rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
340 rtl8225_write(dev, 0x7, 0x82A); msleep(1);
341 rtl8225_write(dev, 0x8, 0x01F); msleep(1);
342 rtl8225_write(dev, 0x9, 0x334); msleep(1);
343 rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
344 rtl8225_write(dev, 0xB, 0x391); msleep(1);
345 rtl8225_write(dev, 0xC, 0x050); msleep(1);
346 rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
347 rtl8225_write(dev, 0xE, 0x029); msleep(1);
348 rtl8225_write(dev, 0xF, 0x914); msleep(100);
349
350 rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
351 rtl8225_write(dev, 0x2, 0x44D); msleep(200);
352
353 if (!(rtl8225_read(dev, 6) & (1 << 7))) {
354 rtl8225_write(dev, 0x02, 0x0c4d);
355 msleep(200);
356 rtl8225_write(dev, 0x02, 0x044d);
357 msleep(100);
358 if (!(rtl8225_read(dev, 6) & (1 << 7)))
359 printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
360 wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
361 }
362
363 rtl8225_write(dev, 0x0, 0x127);
364
365 for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
366 rtl8225_write(dev, 0x1, i + 1);
367 rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
368 }
369
370 rtl8225_write(dev, 0x0, 0x027);
371 rtl8225_write(dev, 0x0, 0x22F);
372
373 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
374 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
375 msleep(1);
376 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
377 msleep(1);
378 }
379
380 msleep(1);
381
382 rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
383 rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
384 rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
385 rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
386 rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
387 rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
388 rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
389 rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
390 rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
391 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
392 rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
393 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
394 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
395 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
396 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
397 rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
398 rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
399 rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
400 rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
401 rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
402 rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
403 rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
404 rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
405 rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
406 rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
407 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
408 rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
409 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
410 rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
411 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
412 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
413 rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
414 rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
415 rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
416 rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
417 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
418 rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
419
420 rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
421 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
422 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
423 rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
424
425 rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
426 rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
427 rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
428 rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
429 rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
430 rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
431 rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
432 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
433 rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
434 rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
435 rtl8225_write_phy_cck(dev, 0x13, 0xd0);
436 rtl8225_write_phy_cck(dev, 0x19, 0x00);
437 rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
438 rtl8225_write_phy_cck(dev, 0x1b, 0x08);
439 rtl8225_write_phy_cck(dev, 0x40, 0x86);
440 rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
441 rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
442 rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
443 rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
444 rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
445 rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
446 rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
447 rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
448 rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
449 rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
450 rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
451 rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
452
453 rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
454
455 rtl8225_rf_set_tx_power(dev, 1);
456
457 /* RX antenna default to A */
458 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
459 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
460
461 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
462 msleep(1);
463 rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
464
465 /* set sensitivity */
466 rtl8225_write(dev, 0x0c, 0x50);
467 rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
468 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
469 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
470 rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
471 rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
472}
473
474static const u8 rtl8225z2_tx_power_cck_ch14[] = {
475 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
476};
477
478static const u8 rtl8225z2_tx_power_cck[] = {
479 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
480};
481
482static const u8 rtl8225z2_tx_power_ofdm[] = {
483 0x42, 0x00, 0x40, 0x00, 0x40
484};
485
486static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
487 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
488 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
489 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
490 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
491 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
492 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
493};
494
495static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
496{
497 struct rtl8187_priv *priv = dev->priv;
498 u8 cck_power, ofdm_power;
499 const u8 *tmp;
500 u32 reg;
501 int i;
502
503 cck_power = priv->channels[channel - 1].val & 0xF;
504 ofdm_power = priv->channels[channel - 1].val >> 4;
505
506 cck_power = min(cck_power, (u8)15);
507 cck_power += priv->txpwr_base & 0xF;
508 cck_power = min(cck_power, (u8)35);
509
510 ofdm_power = min(ofdm_power, (u8)15);
511 ofdm_power += priv->txpwr_base >> 4;
512 ofdm_power = min(ofdm_power, (u8)35);
513
514 if (channel == 14)
515 tmp = rtl8225z2_tx_power_cck_ch14;
516 else
517 tmp = rtl8225z2_tx_power_cck;
518
519 for (i = 0; i < 8; i++)
520 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
521
522 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
523 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
524 msleep(1);
525
526 /* anaparam2 on */
527 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
528 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
529 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
530 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
531 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
532 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
533
534 rtl8225_write_phy_ofdm(dev, 2, 0x42);
535 rtl8225_write_phy_ofdm(dev, 5, 0x00);
536 rtl8225_write_phy_ofdm(dev, 6, 0x40);
537 rtl8225_write_phy_ofdm(dev, 7, 0x00);
538 rtl8225_write_phy_ofdm(dev, 8, 0x40);
539
540 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
541 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
542 msleep(1);
543}
544
545static const u16 rtl8225z2_rxgain[] = {
546 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
547 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
548 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
549 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
550 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
551 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
552 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
553 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
554 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
555 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
556 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
557 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
558};
559
560static const u8 rtl8225z2_gain_bg[] = {
561 0x23, 0x15, 0xa5, /* -82-1dBm */
562 0x23, 0x15, 0xb5, /* -82-2dBm */
563 0x23, 0x15, 0xc5, /* -82-3dBm */
564 0x33, 0x15, 0xc5, /* -78dBm */
565 0x43, 0x15, 0xc5, /* -74dBm */
566 0x53, 0x15, 0xc5, /* -70dBm */
567 0x63, 0x15, 0xc5 /* -66dBm */
568};
569
570void rtl8225z2_rf_init(struct ieee80211_hw *dev)
571{
572 struct rtl8187_priv *priv = dev->priv;
573 int i;
574
575 rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
576 rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
577 rtl8225_write(dev, 0x2, 0x44D); msleep(1);
578 rtl8225_write(dev, 0x3, 0x441); msleep(1);
579 rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
580 rtl8225_write(dev, 0x5, 0xC72); msleep(1);
581 rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
582 rtl8225_write(dev, 0x7, 0x82A); msleep(1);
583 rtl8225_write(dev, 0x8, 0x03F); msleep(1);
584 rtl8225_write(dev, 0x9, 0x335); msleep(1);
585 rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
586 rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
587 rtl8225_write(dev, 0xc, 0x850); msleep(1);
588 rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
589 rtl8225_write(dev, 0xe, 0x02B); msleep(1);
590 rtl8225_write(dev, 0xf, 0x114); msleep(100);
591
592 rtl8225_write(dev, 0x0, 0x1B7);
593
594 for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
595 rtl8225_write(dev, 0x1, i + 1);
596 rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
597 }
598
599 rtl8225_write(dev, 0x3, 0x080);
600 rtl8225_write(dev, 0x5, 0x004);
601 rtl8225_write(dev, 0x0, 0x0B7);
602 rtl8225_write(dev, 0x2, 0xc4D);
603
604 msleep(200);
605 rtl8225_write(dev, 0x2, 0x44D);
606 msleep(100);
607
608 if (!(rtl8225_read(dev, 6) & (1 << 7))) {
609 rtl8225_write(dev, 0x02, 0x0C4D);
610 msleep(200);
611 rtl8225_write(dev, 0x02, 0x044D);
612 msleep(100);
613 if (!(rtl8225_read(dev, 6) & (1 << 7)))
614 printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
615 wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
616 }
617
618 msleep(200);
619
620 rtl8225_write(dev, 0x0, 0x2BF);
621
622 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
623 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
624 msleep(1);
625 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
626 msleep(1);
627 }
628
629 msleep(1);
630
631 rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
632 rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
633 rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
634 rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
635 rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
636 rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
637 rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
638 rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
639 rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
640 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
641 rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
642 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
643 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
644 rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
645 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
646 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
647 rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
648 rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
649 rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
650 rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
651 rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
652 rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
653 rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
654 rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
655 rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
656 rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
657 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
658 rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
659 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
660 rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
661 rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
662 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
663 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
664 rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
665 rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
666 rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
667 rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
668 rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
669 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
670 rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
671
672 rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
673 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
674 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
675 rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
676
677 rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
678 rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
679 rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
680 rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
681 rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
682 rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
683 rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
684 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
685 rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
686 rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
687 rtl8225_write_phy_cck(dev, 0x13, 0xd0);
688 rtl8225_write_phy_cck(dev, 0x19, 0x00);
689 rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
690 rtl8225_write_phy_cck(dev, 0x1b, 0x08);
691 rtl8225_write_phy_cck(dev, 0x40, 0x86);
692 rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
693 rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
694 rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
695 rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
696 rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
697 rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
698 rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
699 rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
700 rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
701 rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
702 rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
703 rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
704
705 rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
706
707 rtl8225z2_rf_set_tx_power(dev, 1);
708
709 /* RX antenna default to A */
710 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
711 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
712
713 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
714 msleep(1);
715 rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
716}
717
718void rtl8225_rf_stop(struct ieee80211_hw *dev)
719{
720 u8 reg;
721 struct rtl8187_priv *priv = dev->priv;
722
723 rtl8225_write(dev, 0x4, 0x1f); msleep(1);
724
725 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
726 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
727 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
728 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
729 rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
730 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
731 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
732}
733
734void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel)
735{
736 struct rtl8187_priv *priv = dev->priv;
737
738 if (priv->rf_init == rtl8225_rf_init)
739 rtl8225_rf_set_tx_power(dev, channel);
740 else
741 rtl8225z2_rf_set_tx_power(dev, channel);
742
743 rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]);
744 msleep(10);
745}