blob: 1bae8990341096913c6800c19df076ac4f7e208a [file] [log] [blame]
Michael Wu605bebe2007-05-14 01:41:02 -04001/*
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 *
John W. Linville0aec00a2007-06-12 22:11:42 -040010 * 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!
Michael Wu605bebe2007-05-14 01:41:02 -040013 *
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
Michael Wu899413d2007-06-14 00:33:48 -070070static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
Michael Wu605bebe2007-05-14 01:41:02 -040071{
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
Michael Wuf6532112007-10-14 14:43:16 -0400104static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
Michael Wu605bebe2007-05-14 01:41:02 -0400105{
106 struct rtl8187_priv *priv = dev->priv;
107
108 if (priv->asic_rev)
Michael Wu899413d2007-06-14 00:33:48 -0700109 rtl8225_write_8051(dev, addr, cpu_to_le16(data));
Michael Wu605bebe2007-05-14 01:41:02 -0400110 else
111 rtl8225_write_bitbang(dev, addr, data);
112}
113
Michael Wuf6532112007-10-14 14:43:16 -0400114static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
Michael Wu605bebe2007-05-14 01:41:02 -0400115{
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
Johannes Berg8318d782008-01-24 19:38:38 +0100286 cck_power = priv->channels[channel - 1].hw_value & 0xF;
287 ofdm_power = priv->channels[channel - 1].hw_value >> 4;
Michael Wu605bebe2007-05-14 01:41:02 -0400288
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);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100308 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
309 reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
Herton Ronaldo Krzesinski4ece16a2008-07-10 18:55:23 -0300310 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
311 RTL8187_RTL8225_ANAPARAM2_ON);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100312 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
313 reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
Michael Wu605bebe2007-05-14 01:41:02 -0400314 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
315
316 rtl8225_write_phy_ofdm(dev, 2, 0x42);
317 rtl8225_write_phy_ofdm(dev, 6, 0x00);
318 rtl8225_write_phy_ofdm(dev, 8, 0x00);
319
320 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
321 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
322
323 tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
324
325 rtl8225_write_phy_ofdm(dev, 5, *tmp);
326 rtl8225_write_phy_ofdm(dev, 7, *tmp);
327
328 msleep(1);
329}
330
Michael Wuf6532112007-10-14 14:43:16 -0400331static void rtl8225_rf_init(struct ieee80211_hw *dev)
Michael Wu605bebe2007-05-14 01:41:02 -0400332{
333 struct rtl8187_priv *priv = dev->priv;
334 int i;
335
336 rtl8225_write(dev, 0x0, 0x067); msleep(1);
337 rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
338 rtl8225_write(dev, 0x2, 0x44D); msleep(1);
339 rtl8225_write(dev, 0x3, 0x441); msleep(1);
340 rtl8225_write(dev, 0x4, 0x486); msleep(1);
341 rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
342 rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
343 rtl8225_write(dev, 0x7, 0x82A); msleep(1);
344 rtl8225_write(dev, 0x8, 0x01F); msleep(1);
345 rtl8225_write(dev, 0x9, 0x334); msleep(1);
346 rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
347 rtl8225_write(dev, 0xB, 0x391); msleep(1);
348 rtl8225_write(dev, 0xC, 0x050); msleep(1);
349 rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
350 rtl8225_write(dev, 0xE, 0x029); msleep(1);
351 rtl8225_write(dev, 0xF, 0x914); msleep(100);
352
353 rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
354 rtl8225_write(dev, 0x2, 0x44D); msleep(200);
355
356 if (!(rtl8225_read(dev, 6) & (1 << 7))) {
357 rtl8225_write(dev, 0x02, 0x0c4d);
358 msleep(200);
359 rtl8225_write(dev, 0x02, 0x044d);
360 msleep(100);
361 if (!(rtl8225_read(dev, 6) & (1 << 7)))
362 printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
363 wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
364 }
365
366 rtl8225_write(dev, 0x0, 0x127);
367
368 for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
369 rtl8225_write(dev, 0x1, i + 1);
370 rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
371 }
372
373 rtl8225_write(dev, 0x0, 0x027);
374 rtl8225_write(dev, 0x0, 0x22F);
375
376 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
377 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
378 msleep(1);
379 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
380 msleep(1);
381 }
382
383 msleep(1);
384
385 rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
386 rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
387 rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
388 rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
389 rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
390 rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
391 rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
392 rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
393 rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
394 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
395 rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
396 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
397 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
398 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
399 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
400 rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
401 rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
402 rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
403 rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
404 rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
405 rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
406 rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
407 rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
408 rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
409 rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
410 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
411 rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
412 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
413 rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
414 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
415 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
416 rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
417 rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
418 rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
419 rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
420 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
421 rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
422
423 rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
424 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
425 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
426 rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
427
428 rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
429 rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
430 rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
431 rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
432 rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
433 rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
434 rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
435 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
436 rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
437 rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
438 rtl8225_write_phy_cck(dev, 0x13, 0xd0);
439 rtl8225_write_phy_cck(dev, 0x19, 0x00);
440 rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
441 rtl8225_write_phy_cck(dev, 0x1b, 0x08);
442 rtl8225_write_phy_cck(dev, 0x40, 0x86);
443 rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
444 rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
445 rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
446 rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
447 rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
448 rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
449 rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
450 rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
451 rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
452 rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
453 rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
454 rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
455
456 rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
457
458 rtl8225_rf_set_tx_power(dev, 1);
459
460 /* RX antenna default to A */
461 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
462 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
463
464 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
465 msleep(1);
466 rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
467
468 /* set sensitivity */
469 rtl8225_write(dev, 0x0c, 0x50);
470 rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
471 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
472 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
473 rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
474 rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
475}
476
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100477static const u8 rtl8225z2_agc[] = {
478 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f,
479 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
480 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f,
481 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
482 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
483 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
484 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28,
485 0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
486 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30,
487 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
488 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
489};
490static const u8 rtl8225z2_ofdm[] = {
491 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
492 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
493 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
494 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
495 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f,
496 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
497 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
498 0x6d, 0x3c, 0xfb, 0x07
499};
500
Michael Wu605bebe2007-05-14 01:41:02 -0400501static const u8 rtl8225z2_tx_power_cck_ch14[] = {
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100502 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
503 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
504 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
505 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
Michael Wu605bebe2007-05-14 01:41:02 -0400506};
507
508static const u8 rtl8225z2_tx_power_cck[] = {
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100509 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
510 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
511 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
512 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
Michael Wu605bebe2007-05-14 01:41:02 -0400513};
514
515static const u8 rtl8225z2_tx_power_ofdm[] = {
516 0x42, 0x00, 0x40, 0x00, 0x40
517};
518
519static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
520 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
521 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
522 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
523 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
524 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
525 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
526};
527
528static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
529{
530 struct rtl8187_priv *priv = dev->priv;
531 u8 cck_power, ofdm_power;
532 const u8 *tmp;
533 u32 reg;
534 int i;
535
Johannes Berg8318d782008-01-24 19:38:38 +0100536 cck_power = priv->channels[channel - 1].hw_value & 0xF;
537 ofdm_power = priv->channels[channel - 1].hw_value >> 4;
Michael Wu605bebe2007-05-14 01:41:02 -0400538
539 cck_power = min(cck_power, (u8)15);
540 cck_power += priv->txpwr_base & 0xF;
541 cck_power = min(cck_power, (u8)35);
542
543 ofdm_power = min(ofdm_power, (u8)15);
544 ofdm_power += priv->txpwr_base >> 4;
545 ofdm_power = min(ofdm_power, (u8)35);
546
547 if (channel == 14)
548 tmp = rtl8225z2_tx_power_cck_ch14;
549 else
550 tmp = rtl8225z2_tx_power_cck;
551
552 for (i = 0; i < 8; i++)
553 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
554
555 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
556 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
557 msleep(1);
558
559 /* anaparam2 on */
560 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
561 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100562 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
563 reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
Herton Ronaldo Krzesinski4ece16a2008-07-10 18:55:23 -0300564 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
565 RTL8187_RTL8225_ANAPARAM2_ON);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100566 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
567 reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
Michael Wu605bebe2007-05-14 01:41:02 -0400568 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
569
570 rtl8225_write_phy_ofdm(dev, 2, 0x42);
571 rtl8225_write_phy_ofdm(dev, 5, 0x00);
572 rtl8225_write_phy_ofdm(dev, 6, 0x40);
573 rtl8225_write_phy_ofdm(dev, 7, 0x00);
574 rtl8225_write_phy_ofdm(dev, 8, 0x40);
575
576 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
577 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
578 msleep(1);
579}
580
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100581static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
582{
583 struct rtl8187_priv *priv = dev->priv;
584 u8 cck_power, ofdm_power;
585 const u8 *tmp;
586 int i;
587
588 cck_power = priv->channels[channel - 1].hw_value & 0xF;
589 ofdm_power = priv->channels[channel - 1].hw_value >> 4;
590
591 if (cck_power > 15)
592 cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22;
593 else
594 cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7;
595 cck_power += priv->txpwr_base & 0xF;
596 cck_power = min(cck_power, (u8)35);
597
598 if (ofdm_power > 15)
599 ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25;
600 else
601 ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10;
602 ofdm_power += (priv->txpwr_base >> 4) & 0xF;
603 ofdm_power = min(ofdm_power, (u8)35);
604
605 if (channel == 14)
606 tmp = rtl8225z2_tx_power_cck_ch14;
607 else
608 tmp = rtl8225z2_tx_power_cck;
609
610 if (priv->hw_rev == RTL8187BvB) {
611 if (cck_power <= 6)
612 ; /* do nothing */
613 else if (cck_power <= 11)
614 tmp += 8;
615 else
616 tmp += 16;
617 } else {
618 if (cck_power <= 5)
619 ; /* do nothing */
620 else if (cck_power <= 11)
621 tmp += 8;
622 else if (cck_power <= 17)
623 tmp += 16;
624 else
625 tmp += 24;
626 }
627
628 for (i = 0; i < 8; i++)
629 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
630
631 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
632 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
633 msleep(1);
634
635 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
636 rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1);
637 if (priv->hw_rev == RTL8187BvB) {
638 if (ofdm_power <= 11) {
639 rtl8225_write_phy_ofdm(dev, 0x87, 0x60);
640 rtl8225_write_phy_ofdm(dev, 0x89, 0x60);
641 } else {
642 rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
643 rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
644 }
645 } else {
646 if (ofdm_power <= 11) {
647 rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
648 rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
649 } else if (ofdm_power <= 17) {
650 rtl8225_write_phy_ofdm(dev, 0x87, 0x54);
651 rtl8225_write_phy_ofdm(dev, 0x89, 0x54);
652 } else {
653 rtl8225_write_phy_ofdm(dev, 0x87, 0x50);
654 rtl8225_write_phy_ofdm(dev, 0x89, 0x50);
655 }
656 }
657 msleep(1);
658}
659
Michael Wu605bebe2007-05-14 01:41:02 -0400660static const u16 rtl8225z2_rxgain[] = {
661 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
662 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
663 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
664 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
665 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
666 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
667 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
668 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
669 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
670 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
671 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
672 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
673};
674
675static const u8 rtl8225z2_gain_bg[] = {
676 0x23, 0x15, 0xa5, /* -82-1dBm */
677 0x23, 0x15, 0xb5, /* -82-2dBm */
678 0x23, 0x15, 0xc5, /* -82-3dBm */
679 0x33, 0x15, 0xc5, /* -78dBm */
680 0x43, 0x15, 0xc5, /* -74dBm */
681 0x53, 0x15, 0xc5, /* -70dBm */
682 0x63, 0x15, 0xc5 /* -66dBm */
683};
684
Michael Wuf6532112007-10-14 14:43:16 -0400685static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
Michael Wu605bebe2007-05-14 01:41:02 -0400686{
687 struct rtl8187_priv *priv = dev->priv;
688 int i;
689
690 rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
691 rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
692 rtl8225_write(dev, 0x2, 0x44D); msleep(1);
693 rtl8225_write(dev, 0x3, 0x441); msleep(1);
694 rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
695 rtl8225_write(dev, 0x5, 0xC72); msleep(1);
696 rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
697 rtl8225_write(dev, 0x7, 0x82A); msleep(1);
698 rtl8225_write(dev, 0x8, 0x03F); msleep(1);
699 rtl8225_write(dev, 0x9, 0x335); msleep(1);
700 rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
701 rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
702 rtl8225_write(dev, 0xc, 0x850); msleep(1);
703 rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
704 rtl8225_write(dev, 0xe, 0x02B); msleep(1);
705 rtl8225_write(dev, 0xf, 0x114); msleep(100);
706
707 rtl8225_write(dev, 0x0, 0x1B7);
708
709 for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
710 rtl8225_write(dev, 0x1, i + 1);
711 rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
712 }
713
714 rtl8225_write(dev, 0x3, 0x080);
715 rtl8225_write(dev, 0x5, 0x004);
716 rtl8225_write(dev, 0x0, 0x0B7);
717 rtl8225_write(dev, 0x2, 0xc4D);
718
719 msleep(200);
720 rtl8225_write(dev, 0x2, 0x44D);
721 msleep(100);
722
723 if (!(rtl8225_read(dev, 6) & (1 << 7))) {
724 rtl8225_write(dev, 0x02, 0x0C4D);
725 msleep(200);
726 rtl8225_write(dev, 0x02, 0x044D);
727 msleep(100);
728 if (!(rtl8225_read(dev, 6) & (1 << 7)))
729 printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
730 wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
731 }
732
733 msleep(200);
734
735 rtl8225_write(dev, 0x0, 0x2BF);
736
737 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
738 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
739 msleep(1);
740 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
741 msleep(1);
742 }
743
744 msleep(1);
745
746 rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
747 rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
748 rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
749 rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
750 rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
751 rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
752 rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
753 rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
754 rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
755 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
756 rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
757 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
758 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
759 rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
760 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
761 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
762 rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
763 rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
764 rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
765 rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
766 rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
767 rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
768 rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
769 rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
770 rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
771 rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
772 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
773 rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
774 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
775 rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
776 rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
777 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
778 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
779 rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
780 rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
781 rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
782 rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
783 rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
784 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
785 rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
786
787 rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
788 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
789 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
790 rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
791
792 rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
793 rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
794 rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
795 rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
796 rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
797 rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
798 rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
799 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
800 rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
801 rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
802 rtl8225_write_phy_cck(dev, 0x13, 0xd0);
803 rtl8225_write_phy_cck(dev, 0x19, 0x00);
804 rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
805 rtl8225_write_phy_cck(dev, 0x1b, 0x08);
806 rtl8225_write_phy_cck(dev, 0x40, 0x86);
807 rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
808 rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
809 rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
810 rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
811 rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
812 rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
813 rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
814 rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
815 rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
816 rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
817 rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
818 rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
819
820 rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
821
822 rtl8225z2_rf_set_tx_power(dev, 1);
823
824 /* RX antenna default to A */
825 rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
826 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
827
828 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
829 msleep(1);
830 rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
831}
832
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100833static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
834{
835 struct rtl8187_priv *priv = dev->priv;
836 int i;
837
838 rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
839 rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
840 rtl8225_write(dev, 0x2, 0x44D); msleep(1);
841 rtl8225_write(dev, 0x3, 0x441); msleep(1);
842 rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
843 rtl8225_write(dev, 0x5, 0xC72); msleep(1);
844 rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
845 rtl8225_write(dev, 0x7, 0x82A); msleep(1);
846 rtl8225_write(dev, 0x8, 0x03F); msleep(1);
847 rtl8225_write(dev, 0x9, 0x335); msleep(1);
848 rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
849 rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
850 rtl8225_write(dev, 0xc, 0x850); msleep(1);
851 rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
852 rtl8225_write(dev, 0xe, 0x02B); msleep(1);
853 rtl8225_write(dev, 0xf, 0x114); msleep(1);
854
855 rtl8225_write(dev, 0x0, 0x1B7); msleep(1);
856
857 for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
858 rtl8225_write(dev, 0x1, i + 1); msleep(1);
859 rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1);
860 }
861
862 rtl8225_write(dev, 0x3, 0x080); msleep(1);
863 rtl8225_write(dev, 0x5, 0x004); msleep(1);
864 rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
865 msleep(3000);
866
867 rtl8225_write(dev, 0x2, 0xC4D); msleep(1);
868 msleep(2000);
869
870 rtl8225_write(dev, 0x2, 0x44D); msleep(1);
871 rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
872
873 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
874 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
875 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
876
877 rtl8225_write_phy_ofdm(dev, 0x80, 0x12);
878 for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) {
879 rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]);
880 rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i);
881 rtl8225_write_phy_ofdm(dev, 0xE, 0);
882 }
883 rtl8225_write_phy_ofdm(dev, 0x80, 0x10);
884
885 for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
886 rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
887
888 rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
889 rtl818x_iowrite8(priv, &priv->map->SLOT, 9);
890 rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28);
891 rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28);
892 rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28);
893 rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28);
894 rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B);
895 rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B);
896 rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28);
897 rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28);
898 rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28);
899 rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28);
900 rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
901
902 rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1);
903 rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1);
904 rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1);
905 rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1);
906}
907
Michael Wuf6532112007-10-14 14:43:16 -0400908static void rtl8225_rf_stop(struct ieee80211_hw *dev)
Michael Wu605bebe2007-05-14 01:41:02 -0400909{
910 u8 reg;
911 struct rtl8187_priv *priv = dev->priv;
912
913 rtl8225_write(dev, 0x4, 0x1f); msleep(1);
914
915 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
916 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
917 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
Herton Ronaldo Krzesinski4ece16a2008-07-10 18:55:23 -0300918 if (!priv->is_rtl8187b) {
919 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
920 RTL8187_RTL8225_ANAPARAM2_OFF);
921 rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
922 RTL8187_RTL8225_ANAPARAM_OFF);
923 } else {
924 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
925 RTL8187B_RTL8225_ANAPARAM2_OFF);
926 rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
927 RTL8187B_RTL8225_ANAPARAM_OFF);
928 rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
929 RTL8187B_RTL8225_ANAPARAM3_OFF);
930 }
Michael Wu605bebe2007-05-14 01:41:02 -0400931 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
932 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
933}
934
Michael Wuf6532112007-10-14 14:43:16 -0400935static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
936 struct ieee80211_conf *conf)
Michael Wu605bebe2007-05-14 01:41:02 -0400937{
938 struct rtl8187_priv *priv = dev->priv;
Johannes Berg8318d782008-01-24 19:38:38 +0100939 int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
Michael Wu605bebe2007-05-14 01:41:02 -0400940
Michael Wuf6532112007-10-14 14:43:16 -0400941 if (priv->rf->init == rtl8225_rf_init)
Johannes Berg8318d782008-01-24 19:38:38 +0100942 rtl8225_rf_set_tx_power(dev, chan);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100943 else if (priv->rf->init == rtl8225z2_rf_init)
Johannes Berg8318d782008-01-24 19:38:38 +0100944 rtl8225z2_rf_set_tx_power(dev, chan);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100945 else
946 rtl8225z2_b_rf_set_tx_power(dev, chan);
Michael Wu605bebe2007-05-14 01:41:02 -0400947
Johannes Berg8318d782008-01-24 19:38:38 +0100948 rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
Michael Wu605bebe2007-05-14 01:41:02 -0400949 msleep(10);
950}
Michael Wuf6532112007-10-14 14:43:16 -0400951
952static const struct rtl818x_rf_ops rtl8225_ops = {
953 .name = "rtl8225",
954 .init = rtl8225_rf_init,
955 .stop = rtl8225_rf_stop,
956 .set_chan = rtl8225_rf_set_channel
957};
958
959static const struct rtl818x_rf_ops rtl8225z2_ops = {
960 .name = "rtl8225z2",
961 .init = rtl8225z2_rf_init,
962 .stop = rtl8225_rf_stop,
963 .set_chan = rtl8225_rf_set_channel
964};
965
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100966static const struct rtl818x_rf_ops rtl8225z2_b_ops = {
967 .name = "rtl8225z2",
968 .init = rtl8225z2_b_rf_init,
969 .stop = rtl8225_rf_stop,
970 .set_chan = rtl8225_rf_set_channel
971};
972
Michael Wuf6532112007-10-14 14:43:16 -0400973const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev)
974{
975 u16 reg8, reg9;
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100976 struct rtl8187_priv *priv = dev->priv;
Michael Wuf6532112007-10-14 14:43:16 -0400977
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100978 if (!priv->is_rtl8187b) {
979 rtl8225_write(dev, 0, 0x1B7);
Michael Wuf6532112007-10-14 14:43:16 -0400980
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100981 reg8 = rtl8225_read(dev, 8);
982 reg9 = rtl8225_read(dev, 9);
Michael Wuf6532112007-10-14 14:43:16 -0400983
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100984 rtl8225_write(dev, 0, 0x0B7);
Michael Wuf6532112007-10-14 14:43:16 -0400985
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100986 if (reg8 != 0x588 || reg9 != 0x700)
987 return &rtl8225_ops;
Michael Wuf6532112007-10-14 14:43:16 -0400988
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100989 return &rtl8225z2_ops;
990 } else
991 return &rtl8225z2_b_ops;
Michael Wuf6532112007-10-14 14:43:16 -0400992}