1
2/*
3 * Radio tuning for RTL8225 on RTL8180
4 *
5 * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
6 * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
7 *
8 * Based on the r8180 driver, which is:
9 * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
10 *
11 * Thanks to Realtek for their support!
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
18#include <linux/init.h>
19#include <linux/pci.h>
20#include <linux/delay.h>
21#include <net/mac80211.h>
22
23#include "rtl8180.h"
24#include "rtl8225.h"
25
26static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
27{
28	struct rtl8180_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 | 0x400);
42	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
43	udelay(10);
44
45	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
46	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
47	udelay(2);
48	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
49	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
50	udelay(10);
51
52	for (i = 15; i >= 0; i--) {
53		u16 reg = reg80;
54
55		if (bangdata & (1 << i))
56			reg |= 1;
57
58		if (i & 1)
59			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
60
61		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
62		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
63
64		if (!(i & 1))
65			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
66	}
67
68	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
69	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
70	udelay(10);
71
72	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
73	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400);
74	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
75}
76
77static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
78{
79	struct rtl8180_priv *priv = dev->priv;
80	u16 reg80, reg82, reg84, out;
81	int i;
82
83	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
84	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
85	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400;
86
87	reg80 &= ~0xF;
88
89	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
90	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
91
92	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
93	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
94	udelay(4);
95	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
96	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
97	udelay(5);
98
99	for (i = 4; i >= 0; i--) {
100		u16 reg = reg80 | ((addr >> i) & 1);
101
102		if (!(i & 1)) {
103			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
104			rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
105			udelay(1);
106		}
107
108		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
109				  reg | (1 << 1));
110		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
111		udelay(2);
112		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
113				  reg | (1 << 1));
114		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
115		udelay(2);
116
117		if (i & 1) {
118			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
119			rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
120			udelay(1);
121		}
122	}
123
124	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E);
125	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E);
126	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
127	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
128			  reg80 | (1 << 3) | (1 << 1));
129	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
130	udelay(2);
131	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
132			  reg80 | (1 << 3));
133	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
134	udelay(2);
135	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
136			  reg80 | (1 << 3));
137	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
138	udelay(2);
139
140	out = 0;
141	for (i = 11; i >= 0; i--) {
142		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
143				  reg80 | (1 << 3));
144		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
145		udelay(1);
146		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
147				  reg80 | (1 << 3) | (1 << 1));
148		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
149		udelay(2);
150		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
151				  reg80 | (1 << 3) | (1 << 1));
152		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
153		udelay(2);
154		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
155				  reg80 | (1 << 3) | (1 << 1));
156		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
157		udelay(2);
158
159		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
160			out |= 1 << i;
161
162		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
163				  reg80 | (1 << 3));
164		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
165		udelay(2);
166	}
167
168	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
169			  reg80 | (1 << 3) | (1 << 2));
170	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
171	udelay(2);
172
173	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
174	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
175	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
176
177	return out;
178}
179
180static const u16 rtl8225bcd_rxgain[] = {
181	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
182	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
183	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
184	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
185	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
186	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
187	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
188	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
189	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
190	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
191	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
192	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
193};
194
195static const u8 rtl8225_agc[] = {
196	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
197	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
198	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
199	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
200	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
201	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
202	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
203	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
204	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
205	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
206	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
207	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
208	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
209	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
210	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
211	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
212};
213
214static const u8 rtl8225_gain[] = {
215	0x23, 0x88, 0x7c, 0xa5, /* -82dbm */
216	0x23, 0x88, 0x7c, 0xb5, /* -82dbm */
217	0x23, 0x88, 0x7c, 0xc5, /* -82dbm */
218	0x33, 0x80, 0x79, 0xc5, /* -78dbm */
219	0x43, 0x78, 0x76, 0xc5, /* -74dbm */
220	0x53, 0x60, 0x73, 0xc5, /* -70dbm */
221	0x63, 0x58, 0x70, 0xc5, /* -66dbm */
222};
223
224static const u8 rtl8225_threshold[] = {
225	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
226};
227
228static const u8 rtl8225_tx_gain_cck_ofdm[] = {
229	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
230};
231
232static const u8 rtl8225_tx_power_cck[] = {
233	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
234	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
235	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
236	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
237	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
238	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
239};
240
241static const u8 rtl8225_tx_power_cck_ch14[] = {
242	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
243	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
244	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
245	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
246	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
247	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
248};
249
250static const u8 rtl8225_tx_power_ofdm[] = {
251	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
252};
253
254static const u32 rtl8225_chan[] = {
255	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
256	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
257};
258
259static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
260{
261	struct rtl8180_priv *priv = dev->priv;
262	u8 cck_power, ofdm_power;
263	const u8 *tmp;
264	u32 reg;
265	int i;
266
267	cck_power = priv->channels[channel - 1].hw_value & 0xFF;
268	ofdm_power = priv->channels[channel - 1].hw_value >> 8;
269
270	cck_power = min(cck_power, (u8)35);
271	ofdm_power = min(ofdm_power, (u8)35);
272
273	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
274			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
275
276	if (channel == 14)
277		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
278	else
279		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
280
281	for (i = 0; i < 8; i++)
282		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
283
284	msleep(1); /* FIXME: optional? */
285
286	/* anaparam2 on */
287	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
288	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
289	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
290	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
291	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
292	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
293
294	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
295			 rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1);
296
297	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
298
299	rtl8225_write_phy_ofdm(dev, 5, *tmp);
300	rtl8225_write_phy_ofdm(dev, 7, *tmp);
301
302	msleep(1);
303}
304
305static void rtl8225_rf_init(struct ieee80211_hw *dev)
306{
307	struct rtl8180_priv *priv = dev->priv;
308	int i;
309
310	rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON);
311
312	/* host_pci_init */
313	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
314	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
315	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
316	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
317	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
318	msleep(200);	/* FIXME: ehh?? */
319	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
320
321	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
322
323	/* TODO: check if we need really to change BRSR to do RF config */
324	rtl818x_ioread16(priv, &priv->map->BRSR);
325	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
326	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
327	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
328	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
329	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
330
331	rtl8225_write(dev, 0x0, 0x067);
332	rtl8225_write(dev, 0x1, 0xFE0);
333	rtl8225_write(dev, 0x2, 0x44D);
334	rtl8225_write(dev, 0x3, 0x441);
335	rtl8225_write(dev, 0x4, 0x8BE);
336	rtl8225_write(dev, 0x5, 0xBF0);		/* TODO: minipci */
337	rtl8225_write(dev, 0x6, 0xAE6);
338	rtl8225_write(dev, 0x7, rtl8225_chan[0]);
339	rtl8225_write(dev, 0x8, 0x01F);
340	rtl8225_write(dev, 0x9, 0x334);
341	rtl8225_write(dev, 0xA, 0xFD4);
342	rtl8225_write(dev, 0xB, 0x391);
343	rtl8225_write(dev, 0xC, 0x050);
344	rtl8225_write(dev, 0xD, 0x6DB);
345	rtl8225_write(dev, 0xE, 0x029);
346	rtl8225_write(dev, 0xF, 0x914); msleep(1);
347
348	rtl8225_write(dev, 0x2, 0xC4D); msleep(100);
349
350	rtl8225_write(dev, 0x0, 0x127);
351
352	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
353		rtl8225_write(dev, 0x1, i + 1);
354		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
355	}
356
357	rtl8225_write(dev, 0x0, 0x027);
358	rtl8225_write(dev, 0x0, 0x22F);
359	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
360
361	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
362		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
363		msleep(1);
364		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
365		msleep(1);
366	}
367
368	msleep(1);
369
370	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
371	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
372	rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1);
373	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
374	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
375	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
376	rtl8225_write_phy_ofdm(dev, 0x06, 0x00); msleep(1);
377	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
378	rtl8225_write_phy_ofdm(dev, 0x08, 0x00); msleep(1);
379	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
380	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
381	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
382	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
383	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
384	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
385	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
386	rtl8225_write_phy_ofdm(dev, 0x11, 0x03); msleep(1);
387	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
388	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
389	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
390	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
391	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
392	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
393	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
394	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
395	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
396	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
397	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
398	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
399	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
400	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
401	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
402	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
403	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
404	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
405	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
406	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
407
408	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
409	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
410	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
411	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
412	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
413	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
414	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
415	rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1);
416	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
417	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
418	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
419	rtl8225_write_phy_cck(dev, 0x19, 0x00);
420	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
421	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
422	rtl8225_write_phy_cck(dev, 0x40, 0x86);
423	rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
424	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
425	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
426	rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
427	rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
428	rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
429	rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
430	rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
431	rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
432	rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
433	rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
434	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
435
436	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1);
437
438	rtl8225_rf_set_tx_power(dev, 1);
439
440	/* RX antenna default to A */
441	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
442	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
443
444	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
445	msleep(1);
446	rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002);
447	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
448
449	rtl8225_write(dev, 0x0c, 0x50);
450	/* set OFDM initial gain */
451	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]);
452	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]);
453	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]);
454	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]);
455	/* set CCK threshold */
456	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]);
457}
458
459static const u8 rtl8225z2_tx_power_cck_ch14[] = {
460	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
461};
462
463static const u8 rtl8225z2_tx_power_cck_B[] = {
464	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
465};
466
467static const u8 rtl8225z2_tx_power_cck_A[] = {
468	0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
469};
470
471static const u8 rtl8225z2_tx_power_cck[] = {
472	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
473};
474
475static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
476{
477	struct rtl8180_priv *priv = dev->priv;
478	u8 cck_power, ofdm_power;
479	const u8 *tmp;
480	int i;
481
482	cck_power = priv->channels[channel - 1].hw_value & 0xFF;
483	ofdm_power = priv->channels[channel - 1].hw_value >> 8;
484
485	if (channel == 14)
486		tmp = rtl8225z2_tx_power_cck_ch14;
487	else if (cck_power == 12)
488		tmp = rtl8225z2_tx_power_cck_B;
489	else if (cck_power == 13)
490		tmp = rtl8225z2_tx_power_cck_A;
491	else
492		tmp = rtl8225z2_tx_power_cck;
493
494	for (i = 0; i < 8; i++)
495		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
496
497	cck_power = min(cck_power, (u8)35);
498	if (cck_power == 13 || cck_power == 14)
499		cck_power = 12;
500	if (cck_power >= 15)
501		cck_power -= 2;
502
503	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power);
504	rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK);
505	msleep(1);
506
507	ofdm_power = min(ofdm_power, (u8)35);
508	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power);
509
510	rtl8225_write_phy_ofdm(dev, 2, 0x62);
511	rtl8225_write_phy_ofdm(dev, 5, 0x00);
512	rtl8225_write_phy_ofdm(dev, 6, 0x40);
513	rtl8225_write_phy_ofdm(dev, 7, 0x00);
514	rtl8225_write_phy_ofdm(dev, 8, 0x40);
515
516	msleep(1);
517}
518
519static const u16 rtl8225z2_rxgain[] = {
520	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
521	0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
522	0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
523	0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
524	0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
525	0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
526	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
527	0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
528	0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
529	0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
530	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
531	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
532};
533
534static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
535{
536	struct rtl8180_priv *priv = dev->priv;
537	int i;
538
539	rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON);
540
541	/* host_pci_init */
542	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
543	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
544	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
545	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
546	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
547	msleep(200);	/* FIXME: ehh?? */
548	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
549
550	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008);
551
552	/* TODO: check if we need really to change BRSR to do RF config */
553	rtl818x_ioread16(priv, &priv->map->BRSR);
554	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
555	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
556	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
557	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
558	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
559
560	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
561
562	rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
563	rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
564	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
565	rtl8225_write(dev, 0x3, 0x441); msleep(1);
566	rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
567	rtl8225_write(dev, 0x5, 0xC72); msleep(1);
568	rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
569	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
570	rtl8225_write(dev, 0x8, 0x03F); msleep(1);
571	rtl8225_write(dev, 0x9, 0x335); msleep(1);
572	rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
573	rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
574	rtl8225_write(dev, 0xc, 0x850); msleep(1);
575	rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
576	rtl8225_write(dev, 0xe, 0x02B); msleep(1);
577	rtl8225_write(dev, 0xf, 0x114); msleep(100);
578
579	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
580		rtl8225_write(dev, 0x02, 0x0C4D);
581		msleep(200);
582		rtl8225_write(dev, 0x02, 0x044D);
583		msleep(100);
584		/* TODO: readd calibration failure message when the calibration
585		   check works */
586	}
587
588	rtl8225_write(dev, 0x0, 0x1B7);
589	rtl8225_write(dev, 0x3, 0x002);
590	rtl8225_write(dev, 0x5, 0x004);
591
592	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
593		rtl8225_write(dev, 0x1, i + 1);
594		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
595	}
596
597	rtl8225_write(dev, 0x0, 0x0B7); msleep(100);
598	rtl8225_write(dev, 0x2, 0xC4D);
599
600	msleep(200);
601	rtl8225_write(dev, 0x2, 0x44D);
602	msleep(100);
603
604	rtl8225_write(dev, 0x00, 0x2BF);
605	rtl8225_write(dev, 0xFF, 0xFFFF);
606
607	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
608
609	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
610		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
611		msleep(1);
612		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
613		msleep(1);
614	}
615
616	msleep(1);
617
618	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
619	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
620	rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1);
621	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
622	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
623	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
624	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
625	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
626	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
627	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
628	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
629	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
630	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
631	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
632	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
633	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
634	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
635	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
636	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
637	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
638	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
639	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
640	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
641	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
642	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
643	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
644	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
645	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
646	rtl8225_write_phy_ofdm(dev, 0x1b, 0x11); msleep(1);
647	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
648	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
649	rtl8225_write_phy_ofdm(dev, 0x1e, 0xb3); msleep(1);
650	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
651	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
652	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
653	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
654	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); /* FIXME: not needed? */
655	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
656	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
657	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
658	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
659
660	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
661	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
662	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
663	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
664	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
665	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
666	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
667	rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1);
668	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
669	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
670	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
671	rtl8225_write_phy_cck(dev, 0x19, 0x00);
672	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
673	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
674	rtl8225_write_phy_cck(dev, 0x40, 0x86);
675	rtl8225_write_phy_cck(dev, 0x41, 0x8a); msleep(1);
676	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
677	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
678	rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
679	rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
680	rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
681	rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
682	rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
683	rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
684	rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
685	rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
686	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
687
688	rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 0x0D); msleep(1);
689
690	rtl8225z2_rf_set_tx_power(dev, 1);
691
692	/* RX antenna default to A */
693	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
694	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
695
696	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
697	msleep(1);
698	rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002);
699	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
700}
701
702static void rtl8225_rf_stop(struct ieee80211_hw *dev)
703{
704	struct rtl8180_priv *priv = dev->priv;
705	u8 reg;
706
707	rtl8225_write(dev, 0x4, 0x1f); msleep(1);
708
709	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
710	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
711	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
712	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
713	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
714	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
715	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
716}
717
718static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
719				   struct ieee80211_conf *conf)
720{
721	struct rtl8180_priv *priv = dev->priv;
722	int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
723
724	if (priv->rf->init == rtl8225_rf_init)
725		rtl8225_rf_set_tx_power(dev, chan);
726	else
727		rtl8225z2_rf_set_tx_power(dev, chan);
728
729	rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
730	msleep(10);
731}
732
733static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev,
734				struct ieee80211_bss_conf *info)
735{
736	struct rtl8180_priv *priv = dev->priv;
737
738	if (info->use_short_slot) {
739		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
740		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
741		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
742		rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
743		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
744	} else {
745		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
746		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44);
747		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
748		rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
749		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
750	}
751}
752
753static const struct rtl818x_rf_ops rtl8225_ops = {
754	.name		= "rtl8225",
755	.init		= rtl8225_rf_init,
756	.stop		= rtl8225_rf_stop,
757	.set_chan	= rtl8225_rf_set_channel,
758	.conf_erp	= rtl8225_rf_conf_erp,
759};
760
761static const struct rtl818x_rf_ops rtl8225z2_ops = {
762	.name		= "rtl8225z2",
763	.init		= rtl8225z2_rf_init,
764	.stop		= rtl8225_rf_stop,
765	.set_chan	= rtl8225_rf_set_channel,
766	.conf_erp	= rtl8225_rf_conf_erp,
767};
768
769const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev)
770{
771	struct rtl8180_priv *priv = dev->priv;
772	u16 reg8, reg9;
773
774	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
775	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
776	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
777	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
778	msleep(100);
779
780	rtl8225_write(dev, 0, 0x1B7);
781
782	reg8 = rtl8225_read(dev, 8);
783	reg9 = rtl8225_read(dev, 9);
784
785	rtl8225_write(dev, 0, 0x0B7);
786
787	if (reg8 != 0x588 || reg9 != 0x700)
788		return &rtl8225_ops;
789
790	return &rtl8225z2_ops;
791}
792