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