1 
2 /* Radio tuning for RTL8225 on RTL8187SE
3  *
4  * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
5  * Copyright 2014 Andrea Merello <andrea.merello@gmail.com>
6  *
7  * Based on the r8180 and Realtek r8187se drivers, which are:
8  * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
9  *
10  * Also based on the rtl8187 driver, which is:
11  * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
12  * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>
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 <net/mac80211.h>
20 
21 #include "rtl8180.h"
22 #include "rtl8225se.h"
23 
24 #define PFX "rtl8225 (se) "
25 
26 static const u32 RF_GAIN_TABLE[] = {
27 	0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
28 	0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
29 	0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
30 	0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
31 	0x0183, 0x0163, 0x0143, 0x0123, 0x0103
32 };
33 
34 static const u8 cck_ofdm_gain_settings[] = {
35 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
36 	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
37 	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
38 	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
39 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
40 	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
41 };
42 
43 static const u8 rtl8225se_tx_gain_cck_ofdm[] = {
44 	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
45 };
46 
47 static const u8 rtl8225se_tx_power_cck[] = {
48 	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
49 	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
50 	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
51 	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
52 	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
53 	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
54 };
55 
56 static const u8 rtl8225se_tx_power_cck_ch14[] = {
57 	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
58 	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
59 	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
60 	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
61 	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
62 	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
63 };
64 
65 static const u8 rtl8225se_tx_power_ofdm[] = {
66 	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
67 };
68 
69 static const u32 rtl8225se_chan[] = {
70 	0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
71 	0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x074A,
72 };
73 
74 static const u8 rtl8225sez2_tx_power_cck_ch14[] = {
75 	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
76 };
77 
78 static const u8 rtl8225sez2_tx_power_cck_B[] = {
79 	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
80 };
81 
82 static const u8 rtl8225sez2_tx_power_cck_A[] = {
83 	0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
84 };
85 
86 static const u8 rtl8225sez2_tx_power_cck[] = {
87 	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
88 };
89 
90 static const u8 ZEBRA_AGC[] = {
91 	0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A,
92 	0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
93 	0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A,
94 	0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
95 	0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27,
96 	0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
97 	0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00,
98 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
100 	0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
101 	0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b,
102 	0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
103 	0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21,
104 	0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
105 	0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
106 	0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
107 };
108 
109 static const u8 OFDM_CONFIG[] = {
110 	0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
111 	0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
112 	0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
113 	0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
114 	0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
115 	0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
116 	0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
117 	0xD8, 0x3C, 0x7B, 0x10, 0x10
118 };
119 
120 static void rtl8187se_three_wire_io(struct ieee80211_hw *dev, u8 *data,
121 				    u8 len, bool write)
122 {
123 	struct rtl8180_priv *priv = dev->priv;
124 	int i;
125 	u8 tmp;
126 
127 	do {
128 		for (i = 0; i < 5; i++) {
129 			tmp = rtl818x_ioread8(priv, SW_3W_CMD1);
130 			if (!(tmp & 0x3))
131 				break;
132 			udelay(10);
133 		}
134 		if (i == 5)
135 			wiphy_err(dev->wiphy, PFX
136 				"CmdReg: 0x%x RE/WE bits aren't clear\n", tmp);
137 
138 		tmp = rtl818x_ioread8(priv, &priv->map->rf_sw_config) | 0x02;
139 		rtl818x_iowrite8(priv, &priv->map->rf_sw_config, tmp);
140 
141 		tmp = rtl818x_ioread8(priv, REG_ADDR1(0x84)) & 0xF7;
142 		rtl818x_iowrite8(priv, REG_ADDR1(0x84), tmp);
143 		if (write) {
144 			if (len == 16) {
145 				rtl818x_iowrite16(priv, SW_3W_DB0,
146 				  *(u16 *)data);
147 			} else if (len == 64) {
148 				rtl818x_iowrite32(priv, SW_3W_DB0_4,
149 				  *((u32 *)data));
150 				rtl818x_iowrite32(priv, SW_3W_DB1_4,
151 				  *((u32 *)(data + 4)));
152 			} else
153 				wiphy_err(dev->wiphy, PFX
154 					"Unimplemented length\n");
155 		} else {
156 			rtl818x_iowrite16(priv, SW_3W_DB0, *(u16 *)data);
157 		}
158 		if (write)
159 			tmp = 2;
160 		else
161 			tmp = 1;
162 		rtl818x_iowrite8(priv, SW_3W_CMD1, tmp);
163 		for (i = 0; i < 5; i++) {
164 			tmp = rtl818x_ioread8(priv, SW_3W_CMD1);
165 			if (!(tmp & 0x3))
166 				break;
167 			udelay(10);
168 		}
169 		rtl818x_iowrite8(priv, SW_3W_CMD1, 0);
170 		if (!write) {
171 			*((u16 *)data) = rtl818x_ioread16(priv, SI_DATA_REG);
172 			*((u16 *)data) &= 0x0FFF;
173 		}
174 	} while (0);
175 }
176 
177 static u32 rtl8187se_rf_readreg(struct ieee80211_hw *dev, u8 addr)
178 {
179 	u32 dataread = addr & 0x0F;
180 	rtl8187se_three_wire_io(dev, (u8 *)&dataread, 16, 0);
181 	return dataread;
182 }
183 
184 static void rtl8187se_rf_writereg(struct ieee80211_hw *dev, u8 addr, u32 data)
185 {
186 	u32 outdata = (data << 4) | (u32)(addr & 0x0F);
187 	rtl8187se_three_wire_io(dev, (u8 *)&outdata, 16, 1);
188 }
189 
190 
191 static void rtl8225se_write_zebra_agc(struct ieee80211_hw *dev)
192 {
193 	int i;
194 
195 	for (i = 0; i < 128; i++) {
196 		rtl8225se_write_phy_ofdm(dev, 0xF, ZEBRA_AGC[i]);
197 		rtl8225se_write_phy_ofdm(dev, 0xE, i+0x80);
198 		rtl8225se_write_phy_ofdm(dev, 0xE, 0);
199 	}
200 }
201 
202 static void rtl8187se_write_ofdm_config(struct ieee80211_hw *dev)
203 {
204 	/* write OFDM_CONFIG table */
205 	int i;
206 
207 	for (i = 0; i < 60; i++)
208 		rtl8225se_write_phy_ofdm(dev, i, OFDM_CONFIG[i]);
209 
210 }
211 
212 static void rtl8225sez2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
213 {
214 	struct rtl8180_priv *priv = dev->priv;
215 	u8 cck_power, ofdm_power;
216 
217 	cck_power = priv->channels[channel - 1].hw_value & 0xFF;
218 	if (cck_power > 35)
219 		cck_power = 35;
220 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
221 			 cck_ofdm_gain_settings[cck_power]);
222 
223 	usleep_range(1000, 5000);
224 	ofdm_power = priv->channels[channel - 1].hw_value >> 8;
225 	if (ofdm_power > 35)
226 		ofdm_power = 35;
227 
228 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
229 			 cck_ofdm_gain_settings[ofdm_power]);
230 	if (ofdm_power < 12) {
231 		rtl8225se_write_phy_ofdm(dev, 7, 0x5C);
232 		rtl8225se_write_phy_ofdm(dev, 9, 0x5C);
233 	}
234 	if (ofdm_power < 18) {
235 		rtl8225se_write_phy_ofdm(dev, 7, 0x54);
236 		rtl8225se_write_phy_ofdm(dev, 9, 0x54);
237 	} else {
238 		rtl8225se_write_phy_ofdm(dev, 7, 0x50);
239 		rtl8225se_write_phy_ofdm(dev, 9, 0x50);
240 	}
241 
242 	usleep_range(1000, 5000);
243 }
244 
245 static void rtl8187se_write_rf_gain(struct ieee80211_hw *dev)
246 {
247 	int i;
248 
249 	for (i = 0; i <= 36; i++) {
250 		rtl8187se_rf_writereg(dev, 0x01, i); mdelay(1);
251 		rtl8187se_rf_writereg(dev, 0x02, RF_GAIN_TABLE[i]); mdelay(1);
252 	}
253 }
254 
255 static void rtl8187se_write_initial_gain(struct ieee80211_hw *dev,
256 					int init_gain)
257 {
258 	switch (init_gain) {
259 	default:
260 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
261 		rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
262 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFA); mdelay(1);
263 		break;
264 	case 2:
265 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
266 		rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
267 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFA); mdelay(1);
268 		break;
269 	case 3:
270 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x36); mdelay(1);
271 		rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
272 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
273 		break;
274 	case 4:
275 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
276 		rtl8225se_write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
277 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
278 		break;
279 	case 5:
280 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x46); mdelay(1);
281 		rtl8225se_write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
282 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFB); mdelay(1);
283 		break;
284 	case 6:
285 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
286 		rtl8225se_write_phy_ofdm(dev, 0x24, 0x96); mdelay(1);
287 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
288 		break;
289 	case 7:
290 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x56); mdelay(1);
291 		rtl8225se_write_phy_ofdm(dev, 0x24, 0xA6); mdelay(1);
292 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
293 		break;
294 	case 8:
295 		rtl8225se_write_phy_ofdm(dev, 0x17, 0x66); mdelay(1);
296 		rtl8225se_write_phy_ofdm(dev, 0x24, 0xB6); mdelay(1);
297 		rtl8225se_write_phy_ofdm(dev, 0x05, 0xFC); mdelay(1);
298 		break;
299 	}
300 }
301 
302 void rtl8225se_rf_init(struct ieee80211_hw *dev)
303 {
304 	struct rtl8180_priv *priv = dev->priv;
305 	u32 rf23, rf24;
306 	u8 d_cut = 0;
307 	u8 tmp;
308 
309 	/* Page 1 */
310 	rtl8187se_rf_writereg(dev, 0x00, 0x013F); mdelay(1);
311 	rf23 = rtl8187se_rf_readreg(dev, 0x08); mdelay(1);
312 	rf24 = rtl8187se_rf_readreg(dev, 0x09); mdelay(1);
313 	if (rf23 == 0x0818 && rf24 == 0x070C)
314 		d_cut = 1;
315 
316 	wiphy_info(dev->wiphy, "RTL8225-SE version %s\n",
317 		d_cut ? "D" : "not-D");
318 
319 	/* Page 0: reg 0 - 15 */
320 	rtl8187se_rf_writereg(dev, 0x00, 0x009F); mdelay(1);
321 	rtl8187se_rf_writereg(dev, 0x01, 0x06E0); mdelay(1);
322 	rtl8187se_rf_writereg(dev, 0x02, 0x004D); mdelay(1);
323 	rtl8187se_rf_writereg(dev, 0x03, 0x07F1); mdelay(1);
324 	rtl8187se_rf_writereg(dev, 0x04, 0x0975); mdelay(1);
325 	rtl8187se_rf_writereg(dev, 0x05, 0x0C72); mdelay(1);
326 	rtl8187se_rf_writereg(dev, 0x06, 0x0AE6); mdelay(1);
327 	rtl8187se_rf_writereg(dev, 0x07, 0x00CA); mdelay(1);
328 	rtl8187se_rf_writereg(dev, 0x08, 0x0E1C); mdelay(1);
329 	rtl8187se_rf_writereg(dev, 0x09, 0x02F0); mdelay(1);
330 	rtl8187se_rf_writereg(dev, 0x0A, 0x09D0); mdelay(1);
331 	rtl8187se_rf_writereg(dev, 0x0B, 0x01BA); mdelay(1);
332 	rtl8187se_rf_writereg(dev, 0x0C, 0x0640); mdelay(1);
333 	rtl8187se_rf_writereg(dev, 0x0D, 0x08DF); mdelay(1);
334 	rtl8187se_rf_writereg(dev, 0x0E, 0x0020); mdelay(1);
335 	rtl8187se_rf_writereg(dev, 0x0F, 0x0990); mdelay(1);
336 	/* page 1: reg 16-30 */
337 	rtl8187se_rf_writereg(dev, 0x00, 0x013F); mdelay(1);
338 	rtl8187se_rf_writereg(dev, 0x03, 0x0806); mdelay(1);
339 	rtl8187se_rf_writereg(dev, 0x04, 0x03A7); mdelay(1);
340 	rtl8187se_rf_writereg(dev, 0x05, 0x059B); mdelay(1);
341 	rtl8187se_rf_writereg(dev, 0x06, 0x0081); mdelay(1);
342 	rtl8187se_rf_writereg(dev, 0x07, 0x01A0); mdelay(1);
343 	rtl8187se_rf_writereg(dev, 0x0A, 0x0001); mdelay(1);
344 	rtl8187se_rf_writereg(dev, 0x0B, 0x0418); mdelay(1);
345 	rtl8187se_rf_writereg(dev, 0x0C, 0x0FBE); mdelay(1);
346 	rtl8187se_rf_writereg(dev, 0x0D, 0x0008); mdelay(1);
347 	if (d_cut)
348 		rtl8187se_rf_writereg(dev, 0x0E, 0x0807);
349 	else
350 		rtl8187se_rf_writereg(dev, 0x0E, 0x0806);
351 	mdelay(1);
352 	rtl8187se_rf_writereg(dev, 0x0F, 0x0ACC); mdelay(1);
353 	rtl8187se_rf_writereg(dev, 0x00, 0x01D7); mdelay(1);
354 	rtl8187se_rf_writereg(dev, 0x03, 0x0E00); mdelay(1);
355 	rtl8187se_rf_writereg(dev, 0x04, 0x0E50); mdelay(1);
356 
357 	rtl8187se_write_rf_gain(dev);
358 
359 	rtl8187se_rf_writereg(dev, 0x05, 0x0203); mdelay(1);
360 	rtl8187se_rf_writereg(dev, 0x06, 0x0200); mdelay(1);
361 	rtl8187se_rf_writereg(dev, 0x00, 0x0137); mdelay(11);
362 	rtl8187se_rf_writereg(dev, 0x0D, 0x0008); mdelay(11);
363 	rtl8187se_rf_writereg(dev, 0x00, 0x0037); mdelay(11);
364 	rtl8187se_rf_writereg(dev, 0x04, 0x0160); mdelay(11);
365 	rtl8187se_rf_writereg(dev, 0x07, 0x0080); mdelay(11);
366 	rtl8187se_rf_writereg(dev, 0x02, 0x088D); msleep(221);
367 	rtl8187se_rf_writereg(dev, 0x00, 0x0137); mdelay(11);
368 	rtl8187se_rf_writereg(dev, 0x07, 0x0000); mdelay(1);
369 	rtl8187se_rf_writereg(dev, 0x07, 0x0180); mdelay(1);
370 	rtl8187se_rf_writereg(dev, 0x07, 0x0220); mdelay(1);
371 	rtl8187se_rf_writereg(dev, 0x07, 0x03E0); mdelay(1);
372 	rtl8187se_rf_writereg(dev, 0x06, 0x00C1); mdelay(1);
373 	rtl8187se_rf_writereg(dev, 0x0A, 0x0001); mdelay(1);
374 	if (priv->xtal_cal) {
375 		tmp = (priv->xtal_in << 4) | (priv->xtal_out << 1) |
376 		      (1 << 11) | (1 << 9);
377 		rtl8187se_rf_writereg(dev, 0x0F, tmp);
378 		wiphy_info(dev->wiphy, "Xtal cal\n");
379 		mdelay(1);
380 	} else {
381 		wiphy_info(dev->wiphy, "NO Xtal cal\n");
382 		rtl8187se_rf_writereg(dev, 0x0F, 0x0ACC);
383 		mdelay(1);
384 	}
385 	/* page 0 */
386 	rtl8187se_rf_writereg(dev, 0x00, 0x00BF); mdelay(1);
387 	rtl8187se_rf_writereg(dev, 0x0D, 0x08DF); mdelay(1);
388 	rtl8187se_rf_writereg(dev, 0x02, 0x004D); mdelay(1);
389 	rtl8187se_rf_writereg(dev, 0x04, 0x0975); msleep(31);
390 	rtl8187se_rf_writereg(dev, 0x00, 0x0197); mdelay(1);
391 	rtl8187se_rf_writereg(dev, 0x05, 0x05AB); mdelay(1);
392 
393 	rtl8187se_rf_writereg(dev, 0x00, 0x009F); mdelay(1);
394 	rtl8187se_rf_writereg(dev, 0x01, 0x0000); mdelay(1);
395 	rtl8187se_rf_writereg(dev, 0x02, 0x0000); mdelay(1);
396 	/* power save parameters */
397 	/* TODO: move to dev.c */
398 	rtl818x_iowrite8(priv, REG_ADDR1(0x024E),
399 		 rtl818x_ioread8(priv, REG_ADDR1(0x24E)) & 0x9F);
400 	rtl8225se_write_phy_cck(dev, 0x00, 0xC8);
401 	rtl8225se_write_phy_cck(dev, 0x06, 0x1C);
402 	rtl8225se_write_phy_cck(dev, 0x10, 0x78);
403 	rtl8225se_write_phy_cck(dev, 0x2E, 0xD0);
404 	rtl8225se_write_phy_cck(dev, 0x2F, 0x06);
405 	rtl8225se_write_phy_cck(dev, 0x01, 0x46);
406 
407 	/* power control */
408 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x10);
409 	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x1B);
410 
411 	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);
412 	rtl8225se_write_phy_ofdm(dev, 0x00, 0x12);
413 
414 	rtl8225se_write_zebra_agc(dev);
415 
416 	rtl8225se_write_phy_ofdm(dev, 0x10, 0x00);
417 
418 	rtl8187se_write_ofdm_config(dev);
419 
420 	/* turn on RF */
421 	rtl8187se_rf_writereg(dev, 0x00, 0x009F); udelay(500);
422 	rtl8187se_rf_writereg(dev, 0x04, 0x0972); udelay(500);
423 	/* turn on RF again */
424 	rtl8187se_rf_writereg(dev, 0x00, 0x009F); udelay(500);
425 	rtl8187se_rf_writereg(dev, 0x04, 0x0972); udelay(500);
426 	/* turn on BB */
427 	rtl8225se_write_phy_ofdm(dev, 0x10, 0x40);
428 	rtl8225se_write_phy_ofdm(dev, 0x12, 0x40);
429 
430 	rtl8187se_write_initial_gain(dev, 4);
431 }
432 
433 void rtl8225se_rf_stop(struct ieee80211_hw *dev)
434 {
435 	/* checked for 8187se */
436 	struct rtl8180_priv *priv = dev->priv;
437 
438 	/* turn off BB RXIQ matrix to cut off rx signal */
439 	rtl8225se_write_phy_ofdm(dev, 0x10, 0x00);
440 	rtl8225se_write_phy_ofdm(dev, 0x12, 0x00);
441 	/* turn off RF */
442 	rtl8187se_rf_writereg(dev, 0x04, 0x0000);
443 	rtl8187se_rf_writereg(dev, 0x00, 0x0000);
444 
445 	usleep_range(1000, 5000);
446 	/* turn off A/D and D/A */
447 	rtl8180_set_anaparam(priv, RTL8225SE_ANAPARAM_OFF);
448 	rtl8180_set_anaparam2(priv, RTL8225SE_ANAPARAM2_OFF);
449 }
450 
451 void rtl8225se_rf_set_channel(struct ieee80211_hw *dev,
452 				   struct ieee80211_conf *conf)
453 {
454 	int chan =
455 		ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
456 
457 	rtl8225sez2_rf_set_tx_power(dev, chan);
458 	rtl8187se_rf_writereg(dev, 0x7, rtl8225se_chan[chan - 1]);
459 	if ((rtl8187se_rf_readreg(dev, 0x7) & 0x0F80) !=
460 		rtl8225se_chan[chan - 1])
461 		rtl8187se_rf_writereg(dev, 0x7, rtl8225se_chan[chan - 1]);
462 	usleep_range(10000, 20000);
463 }
464 
465 static const struct rtl818x_rf_ops rtl8225se_ops = {
466 	.name		= "rtl8225-se",
467 	.init		= rtl8225se_rf_init,
468 	.stop		= rtl8225se_rf_stop,
469 	.set_chan	= rtl8225se_rf_set_channel,
470 };
471 
472 const struct rtl818x_rf_ops *rtl8187se_detect_rf(struct ieee80211_hw *dev)
473 {
474 	return &rtl8225se_ops;
475 }
476