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