• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/net/wireless/rtl818x/
1/*
2 * Radio tuning for RTL8225 on RTL8187
3 *
4 * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
5 * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
6 *
7 * Based on the r8187 driver, which is:
8 * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
9 *
10 * Magic delays, register offsets, and phy value tables below are
11 * taken from the original r8187 driver sources.  Thanks to Realtek
12 * for their support!
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
19#include <linux/init.h>
20#include <linux/usb.h>
21#include <net/mac80211.h>
22
23#include "rtl8187.h"
24#include "rtl8187_rtl8225.h"
25
26static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
27{
28	struct rtl8187_priv *priv = dev->priv;
29	u16 reg80, reg84, reg82;
30	u32 bangdata;
31	int i;
32
33	bangdata = (data << 4) | (addr & 0xf);
34
35	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
36	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
37
38	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
39
40	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
41	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);
42	udelay(10);
43
44	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
45	udelay(2);
46	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
47	udelay(10);
48
49	for (i = 15; i >= 0; i--) {
50		u16 reg = reg80 | (bangdata & (1 << i)) >> i;
51
52		if (i & 1)
53			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
54
55		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
56		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
57
58		if (!(i & 1))
59			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
60	}
61
62	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
63	udelay(10);
64
65	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
66	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
67}
68
69static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 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	mutex_lock(&priv->io_mutex);
92
93	priv->io_dmabuf->bits16 = data;
94	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
95			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
96			addr, 0x8225, &priv->io_dmabuf->bits16, sizeof(data),
97			HZ / 2);
98
99	mutex_unlock(&priv->io_mutex);
100
101	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
102	udelay(10);
103
104	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
105	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
106}
107
108static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
109{
110	struct rtl8187_priv *priv = dev->priv;
111
112	if (priv->asic_rev)
113		rtl8225_write_8051(dev, addr, cpu_to_le16(data));
114	else
115		rtl8225_write_bitbang(dev, addr, data);
116}
117
118static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
119{
120	struct rtl8187_priv *priv = dev->priv;
121	u16 reg80, reg82, reg84, out;
122	int i;
123
124	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
125	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
126	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
127
128	reg80 &= ~0xF;
129
130	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
131	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
132
133	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
134	udelay(4);
135	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
136	udelay(5);
137
138	for (i = 4; i >= 0; i--) {
139		u16 reg = reg80 | ((addr >> i) & 1);
140
141		if (!(i & 1)) {
142			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
143			udelay(1);
144		}
145
146		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
147				  reg | (1 << 1));
148		udelay(2);
149		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
150				  reg | (1 << 1));
151		udelay(2);
152
153		if (i & 1) {
154			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
155			udelay(1);
156		}
157	}
158
159	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
160			  reg80 | (1 << 3) | (1 << 1));
161	udelay(2);
162	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
163			  reg80 | (1 << 3));
164	udelay(2);
165	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
166			  reg80 | (1 << 3));
167	udelay(2);
168
169	out = 0;
170	for (i = 11; i >= 0; i--) {
171		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
172				  reg80 | (1 << 3));
173		udelay(1);
174		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
175				  reg80 | (1 << 3) | (1 << 1));
176		udelay(2);
177		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
178				  reg80 | (1 << 3) | (1 << 1));
179		udelay(2);
180		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
181				  reg80 | (1 << 3) | (1 << 1));
182		udelay(2);
183
184		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
185			out |= 1 << i;
186
187		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
188				  reg80 | (1 << 3));
189		udelay(2);
190	}
191
192	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
193			  reg80 | (1 << 3) | (1 << 2));
194	udelay(2);
195
196	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
197	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
198	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
199
200	return out;
201}
202
203static const u16 rtl8225bcd_rxgain[] = {
204	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
205	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
206	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
207	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
208	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
209	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
210	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
211	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
212	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
213	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
214	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
215	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
216};
217
218static const u8 rtl8225_agc[] = {
219	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
220	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
221	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
222	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
223	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
224	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
225	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
226	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
227	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
228	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
229	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
230	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
231	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
232	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
233	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
234	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
235};
236
237static const u8 rtl8225_gain[] = {
238	0x23, 0x88, 0x7c, 0xa5,	/* -82dBm */
239	0x23, 0x88, 0x7c, 0xb5,	/* -82dBm */
240	0x23, 0x88, 0x7c, 0xc5,	/* -82dBm */
241	0x33, 0x80, 0x79, 0xc5,	/* -78dBm */
242	0x43, 0x78, 0x76, 0xc5,	/* -74dBm */
243	0x53, 0x60, 0x73, 0xc5,	/* -70dBm */
244	0x63, 0x58, 0x70, 0xc5,	/* -66dBm */
245};
246
247static const u8 rtl8225_threshold[] = {
248	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
249};
250
251static const u8 rtl8225_tx_gain_cck_ofdm[] = {
252	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
253};
254
255static const u8 rtl8225_tx_power_cck[] = {
256	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
257	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
258	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
259	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
260	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
261	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
262};
263
264static const u8 rtl8225_tx_power_cck_ch14[] = {
265	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
266	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
267	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
268	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
269	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
270	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
271};
272
273static const u8 rtl8225_tx_power_ofdm[] = {
274	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
275};
276
277static const u32 rtl8225_chan[] = {
278	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
279	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
280};
281
282static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
283{
284	struct rtl8187_priv *priv = dev->priv;
285	u8 cck_power, ofdm_power;
286	const u8 *tmp;
287	u32 reg;
288	int i;
289
290	cck_power = priv->channels[channel - 1].hw_value & 0xF;
291	ofdm_power = priv->channels[channel - 1].hw_value >> 4;
292
293	cck_power = min(cck_power, (u8)11);
294	if (ofdm_power > (u8)15)
295		ofdm_power = 25;
296	else
297		ofdm_power += 10;
298
299	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
300			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
301
302	if (channel == 14)
303		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
304	else
305		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
306
307	for (i = 0; i < 8; i++)
308		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
309
310	msleep(1);
311
312	/* anaparam2 on */
313	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
314	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
315	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
316			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
317	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
318			  RTL8187_RTL8225_ANAPARAM2_ON);
319	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
320			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
321	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
322
323	rtl8225_write_phy_ofdm(dev, 2, 0x42);
324	rtl8225_write_phy_ofdm(dev, 6, 0x00);
325	rtl8225_write_phy_ofdm(dev, 8, 0x00);
326
327	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
328			 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
329
330	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
331
332	rtl8225_write_phy_ofdm(dev, 5, *tmp);
333	rtl8225_write_phy_ofdm(dev, 7, *tmp);
334
335	msleep(1);
336}
337
338static void rtl8225_rf_init(struct ieee80211_hw *dev)
339{
340	struct rtl8187_priv *priv = dev->priv;
341	int i;
342
343	rtl8225_write(dev, 0x0, 0x067);
344	rtl8225_write(dev, 0x1, 0xFE0);
345	rtl8225_write(dev, 0x2, 0x44D);
346	rtl8225_write(dev, 0x3, 0x441);
347	rtl8225_write(dev, 0x4, 0x486);
348	rtl8225_write(dev, 0x5, 0xBC0);
349	rtl8225_write(dev, 0x6, 0xAE6);
350	rtl8225_write(dev, 0x7, 0x82A);
351	rtl8225_write(dev, 0x8, 0x01F);
352	rtl8225_write(dev, 0x9, 0x334);
353	rtl8225_write(dev, 0xA, 0xFD4);
354	rtl8225_write(dev, 0xB, 0x391);
355	rtl8225_write(dev, 0xC, 0x050);
356	rtl8225_write(dev, 0xD, 0x6DB);
357	rtl8225_write(dev, 0xE, 0x029);
358	rtl8225_write(dev, 0xF, 0x914); msleep(100);
359
360	rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
361	rtl8225_write(dev, 0x2, 0x44D); msleep(200);
362
363	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
364		rtl8225_write(dev, 0x02, 0x0c4d);
365		msleep(200);
366		rtl8225_write(dev, 0x02, 0x044d);
367		msleep(100);
368		if (!(rtl8225_read(dev, 6) & (1 << 7)))
369			wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n",
370				   rtl8225_read(dev, 6));
371	}
372
373	rtl8225_write(dev, 0x0, 0x127);
374
375	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
376		rtl8225_write(dev, 0x1, i + 1);
377		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
378	}
379
380	rtl8225_write(dev, 0x0, 0x027);
381	rtl8225_write(dev, 0x0, 0x22F);
382
383	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
384		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
385		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
386	}
387
388	msleep(1);
389
390	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
391	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
392	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
393	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
394	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
395	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
396	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
397	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
398	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
399	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
400	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09);
401	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
402	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
403	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
404	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
405	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
406	rtl8225_write_phy_ofdm(dev, 0x11, 0x06);
407	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
408	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
409	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
410	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
411	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
412	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
413	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
414	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
415	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
416	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76);
417	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
418	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
419	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
420	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
421	rtl8225_write_phy_ofdm(dev, 0x21, 0x27);
422	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
423	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
424	rtl8225_write_phy_ofdm(dev, 0x25, 0x20);
425	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
426	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
427
428	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
429	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
430	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
431	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
432
433	rtl8225_write_phy_cck(dev, 0x00, 0x98);
434	rtl8225_write_phy_cck(dev, 0x03, 0x20);
435	rtl8225_write_phy_cck(dev, 0x04, 0x7e);
436	rtl8225_write_phy_cck(dev, 0x05, 0x12);
437	rtl8225_write_phy_cck(dev, 0x06, 0xfc);
438	rtl8225_write_phy_cck(dev, 0x07, 0x78);
439	rtl8225_write_phy_cck(dev, 0x08, 0x2e);
440	rtl8225_write_phy_cck(dev, 0x10, 0x9b);
441	rtl8225_write_phy_cck(dev, 0x11, 0x88);
442	rtl8225_write_phy_cck(dev, 0x12, 0x47);
443	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
444	rtl8225_write_phy_cck(dev, 0x19, 0x00);
445	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
446	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
447	rtl8225_write_phy_cck(dev, 0x40, 0x86);
448	rtl8225_write_phy_cck(dev, 0x41, 0x8d);
449	rtl8225_write_phy_cck(dev, 0x42, 0x15);
450	rtl8225_write_phy_cck(dev, 0x43, 0x18);
451	rtl8225_write_phy_cck(dev, 0x44, 0x1f);
452	rtl8225_write_phy_cck(dev, 0x45, 0x1e);
453	rtl8225_write_phy_cck(dev, 0x46, 0x1a);
454	rtl8225_write_phy_cck(dev, 0x47, 0x15);
455	rtl8225_write_phy_cck(dev, 0x48, 0x10);
456	rtl8225_write_phy_cck(dev, 0x49, 0x0a);
457	rtl8225_write_phy_cck(dev, 0x4a, 0x05);
458	rtl8225_write_phy_cck(dev, 0x4b, 0x02);
459	rtl8225_write_phy_cck(dev, 0x4c, 0x05);
460
461	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
462
463	rtl8225_rf_set_tx_power(dev, 1);
464
465	/* RX antenna default to A */
466	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */
467	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */
468
469	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
470	msleep(1);
471	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
472
473	/* set sensitivity */
474	rtl8225_write(dev, 0x0c, 0x50);
475	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
476	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
477	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
478	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
479	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
480}
481
482static const u8 rtl8225z2_agc[] = {
483	0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f,
484	0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
485	0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f,
486	0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
487	0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
488	0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
489	0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28,
490	0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
491	0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30,
492	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
493	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
494};
495static const u8 rtl8225z2_ofdm[] = {
496	0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
497	0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
498	0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
499	0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
500	0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f,
501	0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
502	0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
503	0x6d, 0x3c, 0xfb, 0x07
504};
505
506static const u8 rtl8225z2_tx_power_cck_ch14[] = {
507	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,
508	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
509	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,
510	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00
511};
512
513static const u8 rtl8225z2_tx_power_cck[] = {
514	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,
515	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,
516	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,
517	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
518};
519
520static const u8 rtl8225z2_tx_power_ofdm[] = {
521	0x42, 0x00, 0x40, 0x00, 0x40
522};
523
524static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
525	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
526	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
527	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
528	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
529	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
530	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
531};
532
533static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
534{
535	struct rtl8187_priv *priv = dev->priv;
536	u8 cck_power, ofdm_power;
537	const u8 *tmp;
538	u32 reg;
539	int i;
540
541	cck_power = priv->channels[channel - 1].hw_value & 0xF;
542	ofdm_power = priv->channels[channel - 1].hw_value >> 4;
543
544	cck_power = min(cck_power, (u8)15);
545	cck_power += priv->txpwr_base & 0xF;
546	cck_power = min(cck_power, (u8)35);
547
548	if (ofdm_power > (u8)15)
549		ofdm_power = 25;
550	else
551		ofdm_power += 10;
552	ofdm_power += priv->txpwr_base >> 4;
553	ofdm_power = min(ofdm_power, (u8)35);
554
555	if (channel == 14)
556		tmp = rtl8225z2_tx_power_cck_ch14;
557	else
558		tmp = rtl8225z2_tx_power_cck;
559
560	for (i = 0; i < 8; i++)
561		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
562
563	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
564			 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
565	msleep(1);
566
567	/* anaparam2 on */
568	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
569	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
570	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
571			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
572	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
573			  RTL8187_RTL8225_ANAPARAM2_ON);
574	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
575			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
576	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
577
578	rtl8225_write_phy_ofdm(dev, 2, 0x42);
579	rtl8225_write_phy_ofdm(dev, 5, 0x00);
580	rtl8225_write_phy_ofdm(dev, 6, 0x40);
581	rtl8225_write_phy_ofdm(dev, 7, 0x00);
582	rtl8225_write_phy_ofdm(dev, 8, 0x40);
583
584	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
585			 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
586	msleep(1);
587}
588
589static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
590{
591	struct rtl8187_priv *priv = dev->priv;
592	u8 cck_power, ofdm_power;
593	const u8 *tmp;
594	int i;
595
596	cck_power = priv->channels[channel - 1].hw_value & 0xF;
597	ofdm_power = priv->channels[channel - 1].hw_value >> 4;
598
599	if (cck_power > 15)
600		cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22;
601	else
602		cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7;
603	cck_power += priv->txpwr_base & 0xF;
604	cck_power = min(cck_power, (u8)35);
605
606	if (ofdm_power > 15)
607		ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25;
608	else
609		ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10;
610	ofdm_power += (priv->txpwr_base >> 4) & 0xF;
611	ofdm_power = min(ofdm_power, (u8)35);
612
613	if (channel == 14)
614		tmp = rtl8225z2_tx_power_cck_ch14;
615	else
616		tmp = rtl8225z2_tx_power_cck;
617
618	if (priv->hw_rev == RTL8187BvB) {
619		if (cck_power <= 6)
620			; /* do nothing */
621		else if (cck_power <= 11)
622			tmp += 8;
623		else
624			tmp += 16;
625	} else {
626		if (cck_power <= 5)
627			; /* do nothing */
628		else if (cck_power <= 11)
629			tmp += 8;
630		else if (cck_power <= 17)
631			tmp += 16;
632		else
633			tmp += 24;
634	}
635
636	for (i = 0; i < 8; i++)
637		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
638
639	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
640			 rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1);
641	msleep(1);
642
643	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
644			 rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1);
645	if (priv->hw_rev == RTL8187BvB) {
646		if (ofdm_power <= 11) {
647			rtl8225_write_phy_ofdm(dev, 0x87, 0x60);
648			rtl8225_write_phy_ofdm(dev, 0x89, 0x60);
649		} else {
650			rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
651			rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
652		}
653	} else {
654		if (ofdm_power <= 11) {
655			rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);
656			rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);
657		} else if (ofdm_power <= 17) {
658			rtl8225_write_phy_ofdm(dev, 0x87, 0x54);
659			rtl8225_write_phy_ofdm(dev, 0x89, 0x54);
660		} else {
661			rtl8225_write_phy_ofdm(dev, 0x87, 0x50);
662			rtl8225_write_phy_ofdm(dev, 0x89, 0x50);
663		}
664	}
665	msleep(1);
666}
667
668static const u16 rtl8225z2_rxgain[] = {
669	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
670	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
671	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
672	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
673	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
674	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
675	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
676	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
677	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
678	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
679	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
680	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
681};
682
683static const u8 rtl8225z2_gain_bg[] = {
684	0x23, 0x15, 0xa5, /* -82-1dBm */
685	0x23, 0x15, 0xb5, /* -82-2dBm */
686	0x23, 0x15, 0xc5, /* -82-3dBm */
687	0x33, 0x15, 0xc5, /* -78dBm */
688	0x43, 0x15, 0xc5, /* -74dBm */
689	0x53, 0x15, 0xc5, /* -70dBm */
690	0x63, 0x15, 0xc5  /* -66dBm */
691};
692
693static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
694{
695	struct rtl8187_priv *priv = dev->priv;
696	int i;
697
698	rtl8225_write(dev, 0x0, 0x2BF);
699	rtl8225_write(dev, 0x1, 0xEE0);
700	rtl8225_write(dev, 0x2, 0x44D);
701	rtl8225_write(dev, 0x3, 0x441);
702	rtl8225_write(dev, 0x4, 0x8C3);
703	rtl8225_write(dev, 0x5, 0xC72);
704	rtl8225_write(dev, 0x6, 0x0E6);
705	rtl8225_write(dev, 0x7, 0x82A);
706	rtl8225_write(dev, 0x8, 0x03F);
707	rtl8225_write(dev, 0x9, 0x335);
708	rtl8225_write(dev, 0xa, 0x9D4);
709	rtl8225_write(dev, 0xb, 0x7BB);
710	rtl8225_write(dev, 0xc, 0x850);
711	rtl8225_write(dev, 0xd, 0xCDF);
712	rtl8225_write(dev, 0xe, 0x02B);
713	rtl8225_write(dev, 0xf, 0x114);
714	msleep(100);
715
716	rtl8225_write(dev, 0x0, 0x1B7);
717
718	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
719		rtl8225_write(dev, 0x1, i + 1);
720		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
721	}
722
723	rtl8225_write(dev, 0x3, 0x080);
724	rtl8225_write(dev, 0x5, 0x004);
725	rtl8225_write(dev, 0x0, 0x0B7);
726	rtl8225_write(dev, 0x2, 0xc4D);
727
728	msleep(200);
729	rtl8225_write(dev, 0x2, 0x44D);
730	msleep(100);
731
732	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
733		rtl8225_write(dev, 0x02, 0x0C4D);
734		msleep(200);
735		rtl8225_write(dev, 0x02, 0x044D);
736		msleep(100);
737		if (!(rtl8225_read(dev, 6) & (1 << 7)))
738			wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n",
739				   rtl8225_read(dev, 6));
740	}
741
742	msleep(200);
743
744	rtl8225_write(dev, 0x0, 0x2BF);
745
746	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
747		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
748		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
749	}
750
751	msleep(1);
752
753	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
754	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
755	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
756	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
757	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
758	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
759	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
760	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
761	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
762	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
763	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08);
764	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
765	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
766	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
767	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
768	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
769	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
770	rtl8225_write_phy_ofdm(dev, 0x11, 0x07);
771	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
772	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
773	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
774	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
775	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
776	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
777	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
778	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
779	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
780	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15);
781	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
782	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5);
783	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
784	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
785	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
786	rtl8225_write_phy_ofdm(dev, 0x21, 0x17);
787	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
788	rtl8225_write_phy_ofdm(dev, 0x23, 0x80);
789	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
790	rtl8225_write_phy_ofdm(dev, 0x25, 0x00);
791	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
792	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
793
794	rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
795	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
796	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
797	rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
798
799	rtl8225_write_phy_cck(dev, 0x00, 0x98);
800	rtl8225_write_phy_cck(dev, 0x03, 0x20);
801	rtl8225_write_phy_cck(dev, 0x04, 0x7e);
802	rtl8225_write_phy_cck(dev, 0x05, 0x12);
803	rtl8225_write_phy_cck(dev, 0x06, 0xfc);
804	rtl8225_write_phy_cck(dev, 0x07, 0x78);
805	rtl8225_write_phy_cck(dev, 0x08, 0x2e);
806	rtl8225_write_phy_cck(dev, 0x10, 0x9b);
807	rtl8225_write_phy_cck(dev, 0x11, 0x88);
808	rtl8225_write_phy_cck(dev, 0x12, 0x47);
809	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
810	rtl8225_write_phy_cck(dev, 0x19, 0x00);
811	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
812	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
813	rtl8225_write_phy_cck(dev, 0x40, 0x86);
814	rtl8225_write_phy_cck(dev, 0x41, 0x8d);
815	rtl8225_write_phy_cck(dev, 0x42, 0x15);
816	rtl8225_write_phy_cck(dev, 0x43, 0x18);
817	rtl8225_write_phy_cck(dev, 0x44, 0x36);
818	rtl8225_write_phy_cck(dev, 0x45, 0x35);
819	rtl8225_write_phy_cck(dev, 0x46, 0x2e);
820	rtl8225_write_phy_cck(dev, 0x47, 0x25);
821	rtl8225_write_phy_cck(dev, 0x48, 0x1c);
822	rtl8225_write_phy_cck(dev, 0x49, 0x12);
823	rtl8225_write_phy_cck(dev, 0x4a, 0x09);
824	rtl8225_write_phy_cck(dev, 0x4b, 0x04);
825	rtl8225_write_phy_cck(dev, 0x4c, 0x05);
826
827	rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
828
829	rtl8225z2_rf_set_tx_power(dev, 1);
830
831	/* RX antenna default to A */
832	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */
833	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */
834
835	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
836	msleep(1);
837	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
838}
839
840static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
841{
842	struct rtl8187_priv *priv = dev->priv;
843	int i;
844
845	rtl8225_write(dev, 0x0, 0x0B7);
846	rtl8225_write(dev, 0x1, 0xEE0);
847	rtl8225_write(dev, 0x2, 0x44D);
848	rtl8225_write(dev, 0x3, 0x441);
849	rtl8225_write(dev, 0x4, 0x8C3);
850	rtl8225_write(dev, 0x5, 0xC72);
851	rtl8225_write(dev, 0x6, 0x0E6);
852	rtl8225_write(dev, 0x7, 0x82A);
853	rtl8225_write(dev, 0x8, 0x03F);
854	rtl8225_write(dev, 0x9, 0x335);
855	rtl8225_write(dev, 0xa, 0x9D4);
856	rtl8225_write(dev, 0xb, 0x7BB);
857	rtl8225_write(dev, 0xc, 0x850);
858	rtl8225_write(dev, 0xd, 0xCDF);
859	rtl8225_write(dev, 0xe, 0x02B);
860	rtl8225_write(dev, 0xf, 0x114);
861
862	rtl8225_write(dev, 0x0, 0x1B7);
863
864	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
865		rtl8225_write(dev, 0x1, i + 1);
866		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
867	}
868
869	rtl8225_write(dev, 0x3, 0x080);
870	rtl8225_write(dev, 0x5, 0x004);
871	rtl8225_write(dev, 0x0, 0x0B7);
872
873	rtl8225_write(dev, 0x2, 0xC4D);
874
875	rtl8225_write(dev, 0x2, 0x44D);
876	rtl8225_write(dev, 0x0, 0x2BF);
877
878	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
879	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
880	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
881
882	rtl8225_write_phy_ofdm(dev, 0x80, 0x12);
883	for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) {
884		rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]);
885		rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i);
886		rtl8225_write_phy_ofdm(dev, 0xE, 0);
887	}
888	rtl8225_write_phy_ofdm(dev, 0x80, 0x10);
889
890	for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
891		rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
892
893	rtl8225_write_phy_ofdm(dev, 0x97, 0x46);
894	rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
895	rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);
896	rtl8225_write_phy_cck(dev, 0xc1, 0x88);
897}
898
899static void rtl8225_rf_stop(struct ieee80211_hw *dev)
900{
901	u8 reg;
902	struct rtl8187_priv *priv = dev->priv;
903
904	rtl8225_write(dev, 0x4, 0x1f);
905
906	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
907	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
908	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
909	if (!priv->is_rtl8187b) {
910		rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
911				  RTL8187_RTL8225_ANAPARAM2_OFF);
912		rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
913				  RTL8187_RTL8225_ANAPARAM_OFF);
914	} else {
915		rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
916				  RTL8187B_RTL8225_ANAPARAM2_OFF);
917		rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
918				  RTL8187B_RTL8225_ANAPARAM_OFF);
919		rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
920				  RTL8187B_RTL8225_ANAPARAM3_OFF);
921	}
922	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
923	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
924}
925
926static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
927				   struct ieee80211_conf *conf)
928{
929	struct rtl8187_priv *priv = dev->priv;
930	int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
931
932	if (priv->rf->init == rtl8225_rf_init)
933		rtl8225_rf_set_tx_power(dev, chan);
934	else if (priv->rf->init == rtl8225z2_rf_init)
935		rtl8225z2_rf_set_tx_power(dev, chan);
936	else
937		rtl8225z2_b_rf_set_tx_power(dev, chan);
938
939	rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
940	msleep(10);
941}
942
943static const struct rtl818x_rf_ops rtl8225_ops = {
944	.name		= "rtl8225",
945	.init		= rtl8225_rf_init,
946	.stop		= rtl8225_rf_stop,
947	.set_chan	= rtl8225_rf_set_channel
948};
949
950static const struct rtl818x_rf_ops rtl8225z2_ops = {
951	.name		= "rtl8225z2",
952	.init		= rtl8225z2_rf_init,
953	.stop		= rtl8225_rf_stop,
954	.set_chan	= rtl8225_rf_set_channel
955};
956
957static const struct rtl818x_rf_ops rtl8225z2_b_ops = {
958	.name		= "rtl8225z2",
959	.init		= rtl8225z2_b_rf_init,
960	.stop		= rtl8225_rf_stop,
961	.set_chan	= rtl8225_rf_set_channel
962};
963
964const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev)
965{
966	u16 reg8, reg9;
967	struct rtl8187_priv *priv = dev->priv;
968
969	if (!priv->is_rtl8187b) {
970		rtl8225_write(dev, 0, 0x1B7);
971
972		reg8 = rtl8225_read(dev, 8);
973		reg9 = rtl8225_read(dev, 9);
974
975		rtl8225_write(dev, 0, 0x0B7);
976
977		if (reg8 != 0x588 || reg9 != 0x700)
978			return &rtl8225_ops;
979
980		return &rtl8225z2_ops;
981	} else
982		return &rtl8225z2_b_ops;
983}
984