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