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
26static 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
34static 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
43static const u8 rtl8225se_tx_gain_cck_ofdm[] = {
44	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
45};
46
47static 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
56static 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
65static const u8 rtl8225se_tx_power_ofdm[] = {
66	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
67};
68
69static const u32 rtl8225se_chan[] = {
70	0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
71	0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x074A,
72};
73
74static const u8 rtl8225sez2_tx_power_cck_ch14[] = {
75	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
76};
77
78static const u8 rtl8225sez2_tx_power_cck_B[] = {
79	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
80};
81
82static const u8 rtl8225sez2_tx_power_cck_A[] = {
83	0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
84};
85
86static const u8 rtl8225sez2_tx_power_cck[] = {
87	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
88};
89
90static 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
109static 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
120static 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
177static 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
184static 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
191static 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
202static 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
212static 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
245static 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
255static 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
302void 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); mdelay(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); mdelay(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
433void 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
451void 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
465static 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
472const struct rtl818x_rf_ops *rtl8187se_detect_rf(struct ieee80211_hw *dev)
473{
474	return &rtl8225se_ops;
475}
476