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