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