blob: 4e75e8e7fa909036e89fca107f8acbad06e4d70c [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);
Michael Wu605bebe2007-05-14 01:41:02 -040067}
68
Michael Wu899413d2007-06-14 00:33:48 -070069static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
Michael Wu605bebe2007-05-14 01:41:02 -040070{
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);
Michael Wu605bebe2007-05-14 01:41:02 -0400100}
101
Michael Wuf6532112007-10-14 14:43:16 -0400102static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
Michael Wu605bebe2007-05-14 01:41:02 -0400103{
104 struct rtl8187_priv *priv = dev->priv;
105
106 if (priv->asic_rev)
Michael Wu899413d2007-06-14 00:33:48 -0700107 rtl8225_write_8051(dev, addr, cpu_to_le16(data));
Michael Wu605bebe2007-05-14 01:41:02 -0400108 else
109 rtl8225_write_bitbang(dev, addr, data);
110}
111
Michael Wuf6532112007-10-14 14:43:16 -0400112static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
Michael Wu605bebe2007-05-14 01:41:02 -0400113{
114 struct rtl8187_priv *priv = dev->priv;
115 u16 reg80, reg82, reg84, out;
116 int i;
117
118 reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
119 reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
120 reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
121
122 reg80 &= ~0xF;
123
124 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
125 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
126
127 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
128 udelay(4);
129 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
130 udelay(5);
131
132 for (i = 4; i >= 0; i--) {
133 u16 reg = reg80 | ((addr >> i) & 1);
134
135 if (!(i & 1)) {
136 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
137 udelay(1);
138 }
139
140 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
141 reg | (1 << 1));
142 udelay(2);
143 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
144 reg | (1 << 1));
145 udelay(2);
146
147 if (i & 1) {
148 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
149 udelay(1);
150 }
151 }
152
153 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
154 reg80 | (1 << 3) | (1 << 1));
155 udelay(2);
156 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
157 reg80 | (1 << 3));
158 udelay(2);
159 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
160 reg80 | (1 << 3));
161 udelay(2);
162
163 out = 0;
164 for (i = 11; i >= 0; i--) {
165 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
166 reg80 | (1 << 3));
167 udelay(1);
168 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
169 reg80 | (1 << 3) | (1 << 1));
170 udelay(2);
171 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
172 reg80 | (1 << 3) | (1 << 1));
173 udelay(2);
174 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
175 reg80 | (1 << 3) | (1 << 1));
176 udelay(2);
177
178 if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
179 out |= 1 << i;
180
181 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
182 reg80 | (1 << 3));
183 udelay(2);
184 }
185
186 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
187 reg80 | (1 << 3) | (1 << 2));
188 udelay(2);
189
190 rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
191 rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
192 rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
193
194 return out;
195}
196
197static const u16 rtl8225bcd_rxgain[] = {
198 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
199 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
200 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
201 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
202 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
203 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
204 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
205 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
206 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
207 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
208 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
209 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
210};
211
212static const u8 rtl8225_agc[] = {
213 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
214 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
215 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
216 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
217 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
218 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
219 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
220 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
221 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
222 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
223 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
224 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
225 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
226 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
227 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
228 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
229};
230
231static const u8 rtl8225_gain[] = {
232 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */
233 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */
234 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */
235 0x33, 0x80, 0x79, 0xc5, /* -78dBm */
236 0x43, 0x78, 0x76, 0xc5, /* -74dBm */
237 0x53, 0x60, 0x73, 0xc5, /* -70dBm */
238 0x63, 0x58, 0x70, 0xc5, /* -66dBm */
239};
240
241static const u8 rtl8225_threshold[] = {
242 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
243};
244
245static const u8 rtl8225_tx_gain_cck_ofdm[] = {
246 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
247};
248
249static const u8 rtl8225_tx_power_cck[] = {
250 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
251 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
252 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
253 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
254 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
255 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
256};
257
258static const u8 rtl8225_tx_power_cck_ch14[] = {
259 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
260 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
261 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
262 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
263 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
264 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
265};
266
267static const u8 rtl8225_tx_power_ofdm[] = {
268 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
269};
270
271static const u32 rtl8225_chan[] = {
272 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
273 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
274};
275
276static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
277{
278 struct rtl8187_priv *priv = dev->priv;
279 u8 cck_power, ofdm_power;
280 const u8 *tmp;
281 u32 reg;
282 int i;
283
Johannes Berg8318d782008-01-24 19:38:38 +0100284 cck_power = priv->channels[channel - 1].hw_value & 0xF;
285 ofdm_power = priv->channels[channel - 1].hw_value >> 4;
Michael Wu605bebe2007-05-14 01:41:02 -0400286
287 cck_power = min(cck_power, (u8)11);
288 ofdm_power = min(ofdm_power, (u8)35);
289
290 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
291 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
292
293 if (channel == 14)
294 tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
295 else
296 tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
297
298 for (i = 0; i < 8; i++)
299 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
300
301 msleep(1); // FIXME: optional?
302
303 /* anaparam2 on */
304 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
305 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100306 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
307 reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
Herton Ronaldo Krzesinski4ece16a2008-07-10 18:55:23 -0300308 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
309 RTL8187_RTL8225_ANAPARAM2_ON);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100310 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
311 reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
Michael Wu605bebe2007-05-14 01:41:02 -0400312 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
313
314 rtl8225_write_phy_ofdm(dev, 2, 0x42);
315 rtl8225_write_phy_ofdm(dev, 6, 0x00);
316 rtl8225_write_phy_ofdm(dev, 8, 0x00);
317
318 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
319 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
320
321 tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
322
323 rtl8225_write_phy_ofdm(dev, 5, *tmp);
324 rtl8225_write_phy_ofdm(dev, 7, *tmp);
325
326 msleep(1);
327}
328
Michael Wuf6532112007-10-14 14:43:16 -0400329static void rtl8225_rf_init(struct ieee80211_hw *dev)
Michael Wu605bebe2007-05-14 01:41:02 -0400330{
331 struct rtl8187_priv *priv = dev->priv;
332 int i;
333
Larry Finger946d1c22008-10-31 09:54:13 -0700334 rtl8225_write(dev, 0x0, 0x067);
335 rtl8225_write(dev, 0x1, 0xFE0);
336 rtl8225_write(dev, 0x2, 0x44D);
337 rtl8225_write(dev, 0x3, 0x441);
338 rtl8225_write(dev, 0x4, 0x486);
339 rtl8225_write(dev, 0x5, 0xBC0);
340 rtl8225_write(dev, 0x6, 0xAE6);
341 rtl8225_write(dev, 0x7, 0x82A);
342 rtl8225_write(dev, 0x8, 0x01F);
343 rtl8225_write(dev, 0x9, 0x334);
344 rtl8225_write(dev, 0xA, 0xFD4);
345 rtl8225_write(dev, 0xB, 0x391);
346 rtl8225_write(dev, 0xC, 0x050);
347 rtl8225_write(dev, 0xD, 0x6DB);
348 rtl8225_write(dev, 0xE, 0x029);
Michael Wu605bebe2007-05-14 01:41:02 -0400349 rtl8225_write(dev, 0xF, 0x914); msleep(100);
350
351 rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
352 rtl8225_write(dev, 0x2, 0x44D); msleep(200);
353
354 if (!(rtl8225_read(dev, 6) & (1 << 7))) {
355 rtl8225_write(dev, 0x02, 0x0c4d);
356 msleep(200);
357 rtl8225_write(dev, 0x02, 0x044d);
358 msleep(100);
359 if (!(rtl8225_read(dev, 6) & (1 << 7)))
360 printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
361 wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
362 }
363
364 rtl8225_write(dev, 0x0, 0x127);
365
366 for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
367 rtl8225_write(dev, 0x1, i + 1);
368 rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
369 }
370
371 rtl8225_write(dev, 0x0, 0x027);
372 rtl8225_write(dev, 0x0, 0x22F);
373
374 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
375 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
Michael Wu605bebe2007-05-14 01:41:02 -0400376 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
Michael Wu605bebe2007-05-14 01:41:02 -0400377 }
378
379 msleep(1);
380
Larry Finger35cc9882008-10-31 09:52:39 -0700381 rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
382 rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
383 rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
384 rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
385 rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
386 rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
387 rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
388 rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
389 rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
390 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
391 rtl8225_write_phy_ofdm(dev, 0x0a, 0x09);
392 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
393 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
394 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
395 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
396 rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
397 rtl8225_write_phy_ofdm(dev, 0x11, 0x06);
398 rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
399 rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
400 rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
401 rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
402 rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
403 rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
404 rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
405 rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
406 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
407 rtl8225_write_phy_ofdm(dev, 0x1b, 0x76);
408 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
409 rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
410 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
411 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
412 rtl8225_write_phy_ofdm(dev, 0x21, 0x27);
413 rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
414 rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
415 rtl8225_write_phy_ofdm(dev, 0x25, 0x20);
416 rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
417 rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
Michael Wu605bebe2007-05-14 01:41:02 -0400418
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
Larry Fingera3d67bc2008-10-31 09:52:58 -0700424 rtl8225_write_phy_cck(dev, 0x00, 0x98);
425 rtl8225_write_phy_cck(dev, 0x03, 0x20);
426 rtl8225_write_phy_cck(dev, 0x04, 0x7e);
427 rtl8225_write_phy_cck(dev, 0x05, 0x12);
428 rtl8225_write_phy_cck(dev, 0x06, 0xfc);
429 rtl8225_write_phy_cck(dev, 0x07, 0x78);
430 rtl8225_write_phy_cck(dev, 0x08, 0x2e);
431 rtl8225_write_phy_cck(dev, 0x10, 0x9b);
432 rtl8225_write_phy_cck(dev, 0x11, 0x88);
433 rtl8225_write_phy_cck(dev, 0x12, 0x47);
Michael Wu605bebe2007-05-14 01:41:02 -0400434 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);
Larry Fingera3d67bc2008-10-31 09:52:58 -0700439 rtl8225_write_phy_cck(dev, 0x41, 0x8d);
440 rtl8225_write_phy_cck(dev, 0x42, 0x15);
441 rtl8225_write_phy_cck(dev, 0x43, 0x18);
442 rtl8225_write_phy_cck(dev, 0x44, 0x1f);
443 rtl8225_write_phy_cck(dev, 0x45, 0x1e);
444 rtl8225_write_phy_cck(dev, 0x46, 0x1a);
445 rtl8225_write_phy_cck(dev, 0x47, 0x15);
446 rtl8225_write_phy_cck(dev, 0x48, 0x10);
447 rtl8225_write_phy_cck(dev, 0x49, 0x0a);
448 rtl8225_write_phy_cck(dev, 0x4a, 0x05);
449 rtl8225_write_phy_cck(dev, 0x4b, 0x02);
450 rtl8225_write_phy_cck(dev, 0x4c, 0x05);
Michael Wu605bebe2007-05-14 01:41:02 -0400451
452 rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
453
454 rtl8225_rf_set_tx_power(dev, 1);
455
456 /* RX antenna default to A */
Larry Fingera3d67bc2008-10-31 09:52:58 -0700457 rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */
Larry Finger35cc9882008-10-31 09:52:39 -0700458 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */
Michael Wu605bebe2007-05-14 01:41:02 -0400459
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
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100473static const u8 rtl8225z2_agc[] = {
474 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f,
475 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
476 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f,
477 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
478 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
479 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
480 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28,
481 0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
482 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30,
483 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
484 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
485};
486static const u8 rtl8225z2_ofdm[] = {
487 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
488 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
489 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
490 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
491 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f,
492 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
493 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
494 0x6d, 0x3c, 0xfb, 0x07
495};
496
Michael Wu605bebe2007-05-14 01:41:02 -0400497static const u8 rtl8225z2_tx_power_cck_ch14[] = {
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100498 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
499 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
500 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
501 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
Michael Wu605bebe2007-05-14 01:41:02 -0400502};
503
504static const u8 rtl8225z2_tx_power_cck[] = {
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100505 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
506 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
507 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
508 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
Michael Wu605bebe2007-05-14 01:41:02 -0400509};
510
511static const u8 rtl8225z2_tx_power_ofdm[] = {
512 0x42, 0x00, 0x40, 0x00, 0x40
513};
514
515static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
516 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
517 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
518 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
519 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
520 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
521 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
522};
523
524static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
525{
526 struct rtl8187_priv *priv = dev->priv;
527 u8 cck_power, ofdm_power;
528 const u8 *tmp;
529 u32 reg;
530 int i;
531
Johannes Berg8318d782008-01-24 19:38:38 +0100532 cck_power = priv->channels[channel - 1].hw_value & 0xF;
533 ofdm_power = priv->channels[channel - 1].hw_value >> 4;
Michael Wu605bebe2007-05-14 01:41:02 -0400534
535 cck_power = min(cck_power, (u8)15);
536 cck_power += priv->txpwr_base & 0xF;
537 cck_power = min(cck_power, (u8)35);
538
539 ofdm_power = min(ofdm_power, (u8)15);
540 ofdm_power += priv->txpwr_base >> 4;
541 ofdm_power = min(ofdm_power, (u8)35);
542
543 if (channel == 14)
544 tmp = rtl8225z2_tx_power_cck_ch14;
545 else
546 tmp = rtl8225z2_tx_power_cck;
547
548 for (i = 0; i < 8; i++)
549 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
550
551 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
552 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
553 msleep(1);
554
555 /* anaparam2 on */
556 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
557 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100558 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
559 reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
Herton Ronaldo Krzesinski4ece16a2008-07-10 18:55:23 -0300560 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
561 RTL8187_RTL8225_ANAPARAM2_ON);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100562 rtl818x_iowrite8(priv, &priv->map->CONFIG3,
563 reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
Michael Wu605bebe2007-05-14 01:41:02 -0400564 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
565
566 rtl8225_write_phy_ofdm(dev, 2, 0x42);
567 rtl8225_write_phy_ofdm(dev, 5, 0x00);
568 rtl8225_write_phy_ofdm(dev, 6, 0x40);
569 rtl8225_write_phy_ofdm(dev, 7, 0x00);
570 rtl8225_write_phy_ofdm(dev, 8, 0x40);
571
572 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
573 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
574 msleep(1);
575}
576
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100577static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
578{
579 struct rtl8187_priv *priv = dev->priv;
580 u8 cck_power, ofdm_power;
581 const u8 *tmp;
582 int i;
583
584 cck_power = priv->channels[channel - 1].hw_value & 0xF;
585 ofdm_power = priv->channels[channel - 1].hw_value >> 4;
586
587 if (cck_power > 15)
588 cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22;
589 else
590 cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7;
591 cck_power += priv->txpwr_base & 0xF;
592 cck_power = min(cck_power, (u8)35);
593
594 if (ofdm_power > 15)
595 ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25;
596 else
597 ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10;
598 ofdm_power += (priv->txpwr_base >> 4) & 0xF;
599 ofdm_power = min(ofdm_power, (u8)35);
600
601 if (channel == 14)
602 tmp = rtl8225z2_tx_power_cck_ch14;
603 else
604 tmp = rtl8225z2_tx_power_cck;
605
606 if (priv->hw_rev == RTL8187BvB) {
607 if (cck_power <= 6)
608 ; /* do nothing */
609 else if (cck_power <= 11)
610 tmp += 8;
611 else
612 tmp += 16;
613 } else {
614 if (cck_power <= 5)
615 ; /* do nothing */
616 else if (cck_power <= 11)
617 tmp += 8;
618 else if (cck_power <= 17)
619 tmp += 16;
620 else
621 tmp += 24;
622 }
623
624 for (i = 0; i < 8; i++)
625 rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
626
627 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
Larry Fingerc4832462008-10-31 09:40:44 -0700628 rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100629 msleep(1);
630
631 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
632 rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1);
633 if (priv->hw_rev == RTL8187BvB) {
634 if (ofdm_power <= 11) {
635 rtl8225_write_phy_ofdm(dev, 0x87, 0x60);
636 rtl8225_write_phy_ofdm(dev, 0x89, 0x60);
637 } else {
638 rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
639 rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
640 }
641 } else {
642 if (ofdm_power <= 11) {
643 rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
644 rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
645 } else if (ofdm_power <= 17) {
646 rtl8225_write_phy_ofdm(dev, 0x87, 0x54);
647 rtl8225_write_phy_ofdm(dev, 0x89, 0x54);
648 } else {
649 rtl8225_write_phy_ofdm(dev, 0x87, 0x50);
650 rtl8225_write_phy_ofdm(dev, 0x89, 0x50);
651 }
652 }
653 msleep(1);
654}
655
Michael Wu605bebe2007-05-14 01:41:02 -0400656static const u16 rtl8225z2_rxgain[] = {
657 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
658 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
659 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
660 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
661 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
662 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
663 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
664 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
665 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
666 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
667 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
668 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
669};
670
671static const u8 rtl8225z2_gain_bg[] = {
672 0x23, 0x15, 0xa5, /* -82-1dBm */
673 0x23, 0x15, 0xb5, /* -82-2dBm */
674 0x23, 0x15, 0xc5, /* -82-3dBm */
675 0x33, 0x15, 0xc5, /* -78dBm */
676 0x43, 0x15, 0xc5, /* -74dBm */
677 0x53, 0x15, 0xc5, /* -70dBm */
678 0x63, 0x15, 0xc5 /* -66dBm */
679};
680
Michael Wuf6532112007-10-14 14:43:16 -0400681static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
Michael Wu605bebe2007-05-14 01:41:02 -0400682{
683 struct rtl8187_priv *priv = dev->priv;
684 int i;
685
Larry Finger946d1c22008-10-31 09:54:13 -0700686 rtl8225_write(dev, 0x0, 0x2BF);
687 rtl8225_write(dev, 0x1, 0xEE0);
688 rtl8225_write(dev, 0x2, 0x44D);
689 rtl8225_write(dev, 0x3, 0x441);
690 rtl8225_write(dev, 0x4, 0x8C3);
691 rtl8225_write(dev, 0x5, 0xC72);
692 rtl8225_write(dev, 0x6, 0x0E6);
693 rtl8225_write(dev, 0x7, 0x82A);
694 rtl8225_write(dev, 0x8, 0x03F);
695 rtl8225_write(dev, 0x9, 0x335);
696 rtl8225_write(dev, 0xa, 0x9D4);
697 rtl8225_write(dev, 0xb, 0x7BB);
698 rtl8225_write(dev, 0xc, 0x850);
699 rtl8225_write(dev, 0xd, 0xCDF);
700 rtl8225_write(dev, 0xe, 0x02B);
701 rtl8225_write(dev, 0xf, 0x114);
702 msleep(100);
Michael Wu605bebe2007-05-14 01:41:02 -0400703
704 rtl8225_write(dev, 0x0, 0x1B7);
705
706 for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
707 rtl8225_write(dev, 0x1, i + 1);
708 rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
709 }
710
711 rtl8225_write(dev, 0x3, 0x080);
712 rtl8225_write(dev, 0x5, 0x004);
713 rtl8225_write(dev, 0x0, 0x0B7);
714 rtl8225_write(dev, 0x2, 0xc4D);
715
716 msleep(200);
717 rtl8225_write(dev, 0x2, 0x44D);
718 msleep(100);
719
720 if (!(rtl8225_read(dev, 6) & (1 << 7))) {
721 rtl8225_write(dev, 0x02, 0x0C4D);
722 msleep(200);
723 rtl8225_write(dev, 0x02, 0x044D);
724 msleep(100);
725 if (!(rtl8225_read(dev, 6) & (1 << 7)))
726 printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
727 wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
728 }
729
730 msleep(200);
731
732 rtl8225_write(dev, 0x0, 0x2BF);
733
734 for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
735 rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
Michael Wu605bebe2007-05-14 01:41:02 -0400736 rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
Michael Wu605bebe2007-05-14 01:41:02 -0400737 }
738
739 msleep(1);
740
Larry Finger35cc9882008-10-31 09:52:39 -0700741 rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
742 rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
743 rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
744 rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
745 rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
746 rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
747 rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
748 rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
749 rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
750 rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
751 rtl8225_write_phy_ofdm(dev, 0x0a, 0x08);
752 rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
753 rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
Michael Wu605bebe2007-05-14 01:41:02 -0400754 rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
Larry Finger35cc9882008-10-31 09:52:39 -0700755 rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
756 rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
757 rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
758 rtl8225_write_phy_ofdm(dev, 0x11, 0x07);
759 rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
760 rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
761 rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
762 rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
763 rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
764 rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
765 rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
766 rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
767 rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
768 rtl8225_write_phy_ofdm(dev, 0x1b, 0x15);
769 rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
770 rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5);
771 rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
772 rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
773 rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
774 rtl8225_write_phy_ofdm(dev, 0x21, 0x17);
775 rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
776 rtl8225_write_phy_ofdm(dev, 0x23, 0x80);
777 rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
778 rtl8225_write_phy_ofdm(dev, 0x25, 0x00);
779 rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
780 rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
Michael Wu605bebe2007-05-14 01:41:02 -0400781
782 rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
783 rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
784 rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
785 rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
786
Larry Fingera3d67bc2008-10-31 09:52:58 -0700787 rtl8225_write_phy_cck(dev, 0x00, 0x98);
788 rtl8225_write_phy_cck(dev, 0x03, 0x20);
789 rtl8225_write_phy_cck(dev, 0x04, 0x7e);
790 rtl8225_write_phy_cck(dev, 0x05, 0x12);
791 rtl8225_write_phy_cck(dev, 0x06, 0xfc);
792 rtl8225_write_phy_cck(dev, 0x07, 0x78);
793 rtl8225_write_phy_cck(dev, 0x08, 0x2e);
794 rtl8225_write_phy_cck(dev, 0x10, 0x9b);
795 rtl8225_write_phy_cck(dev, 0x11, 0x88);
796 rtl8225_write_phy_cck(dev, 0x12, 0x47);
Michael Wu605bebe2007-05-14 01:41:02 -0400797 rtl8225_write_phy_cck(dev, 0x13, 0xd0);
798 rtl8225_write_phy_cck(dev, 0x19, 0x00);
799 rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
800 rtl8225_write_phy_cck(dev, 0x1b, 0x08);
801 rtl8225_write_phy_cck(dev, 0x40, 0x86);
Larry Fingera3d67bc2008-10-31 09:52:58 -0700802 rtl8225_write_phy_cck(dev, 0x41, 0x8d);
803 rtl8225_write_phy_cck(dev, 0x42, 0x15);
804 rtl8225_write_phy_cck(dev, 0x43, 0x18);
805 rtl8225_write_phy_cck(dev, 0x44, 0x36);
806 rtl8225_write_phy_cck(dev, 0x45, 0x35);
807 rtl8225_write_phy_cck(dev, 0x46, 0x2e);
808 rtl8225_write_phy_cck(dev, 0x47, 0x25);
809 rtl8225_write_phy_cck(dev, 0x48, 0x1c);
810 rtl8225_write_phy_cck(dev, 0x49, 0x12);
811 rtl8225_write_phy_cck(dev, 0x4a, 0x09);
812 rtl8225_write_phy_cck(dev, 0x4b, 0x04);
813 rtl8225_write_phy_cck(dev, 0x4c, 0x05);
Michael Wu605bebe2007-05-14 01:41:02 -0400814
815 rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
816
817 rtl8225z2_rf_set_tx_power(dev, 1);
818
819 /* RX antenna default to A */
Larry Fingera3d67bc2008-10-31 09:52:58 -0700820 rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */
Larry Finger35cc9882008-10-31 09:52:39 -0700821 rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */
Michael Wu605bebe2007-05-14 01:41:02 -0400822
823 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
824 msleep(1);
825 rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
826}
827
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100828static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
829{
830 struct rtl8187_priv *priv = dev->priv;
831 int i;
832
Larry Finger946d1c22008-10-31 09:54:13 -0700833 rtl8225_write(dev, 0x0, 0x0B7);
834 rtl8225_write(dev, 0x1, 0xEE0);
835 rtl8225_write(dev, 0x2, 0x44D);
836 rtl8225_write(dev, 0x3, 0x441);
837 rtl8225_write(dev, 0x4, 0x8C3);
838 rtl8225_write(dev, 0x5, 0xC72);
839 rtl8225_write(dev, 0x6, 0x0E6);
840 rtl8225_write(dev, 0x7, 0x82A);
841 rtl8225_write(dev, 0x8, 0x03F);
842 rtl8225_write(dev, 0x9, 0x335);
843 rtl8225_write(dev, 0xa, 0x9D4);
844 rtl8225_write(dev, 0xb, 0x7BB);
845 rtl8225_write(dev, 0xc, 0x850);
846 rtl8225_write(dev, 0xd, 0xCDF);
847 rtl8225_write(dev, 0xe, 0x02B);
848 rtl8225_write(dev, 0xf, 0x114);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100849
Larry Finger946d1c22008-10-31 09:54:13 -0700850 rtl8225_write(dev, 0x0, 0x1B7);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100851
852 for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
Larry Finger946d1c22008-10-31 09:54:13 -0700853 rtl8225_write(dev, 0x1, i + 1);
854 rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100855 }
856
Larry Finger946d1c22008-10-31 09:54:13 -0700857 rtl8225_write(dev, 0x3, 0x080);
858 rtl8225_write(dev, 0x5, 0x004);
859 rtl8225_write(dev, 0x0, 0x0B7);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100860
Larry Finger946d1c22008-10-31 09:54:13 -0700861 rtl8225_write(dev, 0x2, 0xC4D);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100862
Larry Finger946d1c22008-10-31 09:54:13 -0700863 rtl8225_write(dev, 0x2, 0x44D);
864 rtl8225_write(dev, 0x0, 0x2BF);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100865
866 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
867 rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
868 rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
869
870 rtl8225_write_phy_ofdm(dev, 0x80, 0x12);
871 for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) {
872 rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]);
873 rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i);
874 rtl8225_write_phy_ofdm(dev, 0xE, 0);
875 }
876 rtl8225_write_phy_ofdm(dev, 0x80, 0x10);
877
878 for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
879 rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
880
Larry Finger35cc9882008-10-31 09:52:39 -0700881 rtl8225_write_phy_ofdm(dev, 0x97, 0x46);
882 rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
883 rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);
884 rtl8225_write_phy_cck(dev, 0xc1, 0x88);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100885}
886
Michael Wuf6532112007-10-14 14:43:16 -0400887static void rtl8225_rf_stop(struct ieee80211_hw *dev)
Michael Wu605bebe2007-05-14 01:41:02 -0400888{
889 u8 reg;
890 struct rtl8187_priv *priv = dev->priv;
891
Larry Finger946d1c22008-10-31 09:54:13 -0700892 rtl8225_write(dev, 0x4, 0x1f);
Michael Wu605bebe2007-05-14 01:41:02 -0400893
894 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
895 reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
896 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
Herton Ronaldo Krzesinski4ece16a2008-07-10 18:55:23 -0300897 if (!priv->is_rtl8187b) {
898 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
899 RTL8187_RTL8225_ANAPARAM2_OFF);
900 rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
901 RTL8187_RTL8225_ANAPARAM_OFF);
902 } else {
903 rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
904 RTL8187B_RTL8225_ANAPARAM2_OFF);
905 rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
906 RTL8187B_RTL8225_ANAPARAM_OFF);
907 rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
908 RTL8187B_RTL8225_ANAPARAM3_OFF);
909 }
Michael Wu605bebe2007-05-14 01:41:02 -0400910 rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
911 rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
912}
913
Michael Wuf6532112007-10-14 14:43:16 -0400914static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
915 struct ieee80211_conf *conf)
Michael Wu605bebe2007-05-14 01:41:02 -0400916{
917 struct rtl8187_priv *priv = dev->priv;
Johannes Berg8318d782008-01-24 19:38:38 +0100918 int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
Michael Wu605bebe2007-05-14 01:41:02 -0400919
Michael Wuf6532112007-10-14 14:43:16 -0400920 if (priv->rf->init == rtl8225_rf_init)
Johannes Berg8318d782008-01-24 19:38:38 +0100921 rtl8225_rf_set_tx_power(dev, chan);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100922 else if (priv->rf->init == rtl8225z2_rf_init)
Johannes Berg8318d782008-01-24 19:38:38 +0100923 rtl8225z2_rf_set_tx_power(dev, chan);
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100924 else
925 rtl8225z2_b_rf_set_tx_power(dev, chan);
Michael Wu605bebe2007-05-14 01:41:02 -0400926
Johannes Berg8318d782008-01-24 19:38:38 +0100927 rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
Michael Wu605bebe2007-05-14 01:41:02 -0400928 msleep(10);
929}
Michael Wuf6532112007-10-14 14:43:16 -0400930
931static const struct rtl818x_rf_ops rtl8225_ops = {
932 .name = "rtl8225",
933 .init = rtl8225_rf_init,
934 .stop = rtl8225_rf_stop,
935 .set_chan = rtl8225_rf_set_channel
936};
937
938static const struct rtl818x_rf_ops rtl8225z2_ops = {
939 .name = "rtl8225z2",
940 .init = rtl8225z2_rf_init,
941 .stop = rtl8225_rf_stop,
942 .set_chan = rtl8225_rf_set_channel
943};
944
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100945static const struct rtl818x_rf_ops rtl8225z2_b_ops = {
946 .name = "rtl8225z2",
947 .init = rtl8225z2_b_rf_init,
948 .stop = rtl8225_rf_stop,
949 .set_chan = rtl8225_rf_set_channel
950};
951
Michael Wuf6532112007-10-14 14:43:16 -0400952const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev)
953{
954 u16 reg8, reg9;
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100955 struct rtl8187_priv *priv = dev->priv;
Michael Wuf6532112007-10-14 14:43:16 -0400956
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100957 if (!priv->is_rtl8187b) {
958 rtl8225_write(dev, 0, 0x1B7);
Michael Wuf6532112007-10-14 14:43:16 -0400959
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100960 reg8 = rtl8225_read(dev, 8);
961 reg9 = rtl8225_read(dev, 9);
Michael Wuf6532112007-10-14 14:43:16 -0400962
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100963 rtl8225_write(dev, 0, 0x0B7);
Michael Wuf6532112007-10-14 14:43:16 -0400964
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100965 if (reg8 != 0x588 || reg9 != 0x700)
966 return &rtl8225_ops;
Michael Wuf6532112007-10-14 14:43:16 -0400967
Hin-Tak Leunge7d414f2008-07-08 12:31:57 +0100968 return &rtl8225z2_ops;
969 } else
970 return &rtl8225z2_b_ops;
Michael Wuf6532112007-10-14 14:43:16 -0400971}