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