brintos

brintos / linux-shallow public Read only

0
0
Text · 31.6 KiB · 4efab90 Raw
1045 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Radio tuning for RTL8225 on RTL81874 *5 * Copyright 2007 Michael Wu <flamingice@sourmilk.net>6 * Copyright 2007 Andrea Merello <andrea.merello@gmail.com>7 *8 * Based on the r8187 driver, which is:9 * Copyright 2005 Andrea Merello <andrea.merello@gmail.com>, et al.10 *11 * Magic delays, register offsets, and phy value tables below are12 * taken from the original r8187 driver sources.  Thanks to Realtek13 * for their support!14 */15 16#include <linux/usb.h>17#include <net/mac80211.h>18 19#include "rtl8187.h"20#include "rtl8225.h"21 22u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv,23				u8 *addr, u8 idx)24{25	u8 val;26 27	mutex_lock(&priv->io_mutex);28	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),29			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,30			(unsigned long)addr, idx & 0x03,31			&priv->io_dmabuf->bits8, sizeof(val), 500);32 33	val = priv->io_dmabuf->bits8;34	mutex_unlock(&priv->io_mutex);35 36	return val;37}38 39u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv,40				__le16 *addr, u8 idx)41{42	__le16 val;43 44	mutex_lock(&priv->io_mutex);45	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),46			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,47			(unsigned long)addr, idx & 0x03,48			&priv->io_dmabuf->bits16, sizeof(val), 500);49 50	val = priv->io_dmabuf->bits16;51	mutex_unlock(&priv->io_mutex);52 53	return le16_to_cpu(val);54}55 56u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv,57				__le32 *addr, u8 idx)58{59	__le32 val;60 61	mutex_lock(&priv->io_mutex);62	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),63			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,64			(unsigned long)addr, idx & 0x03,65			&priv->io_dmabuf->bits32, sizeof(val), 500);66 67	val = priv->io_dmabuf->bits32;68	mutex_unlock(&priv->io_mutex);69 70	return le32_to_cpu(val);71}72 73void rtl818x_iowrite8_idx(struct rtl8187_priv *priv,74				u8 *addr, u8 val, u8 idx)75{76	mutex_lock(&priv->io_mutex);77 78	priv->io_dmabuf->bits8 = val;79	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),80			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,81			(unsigned long)addr, idx & 0x03,82			&priv->io_dmabuf->bits8, sizeof(val), 500);83 84	mutex_unlock(&priv->io_mutex);85}86 87void rtl818x_iowrite16_idx(struct rtl8187_priv *priv,88				__le16 *addr, u16 val, u8 idx)89{90	mutex_lock(&priv->io_mutex);91 92	priv->io_dmabuf->bits16 = cpu_to_le16(val);93	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),94			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,95			(unsigned long)addr, idx & 0x03,96			&priv->io_dmabuf->bits16, sizeof(val), 500);97 98	mutex_unlock(&priv->io_mutex);99}100 101void rtl818x_iowrite32_idx(struct rtl8187_priv *priv,102				__le32 *addr, u32 val, u8 idx)103{104	mutex_lock(&priv->io_mutex);105 106	priv->io_dmabuf->bits32 = cpu_to_le32(val);107	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),108			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,109			(unsigned long)addr, idx & 0x03,110			&priv->io_dmabuf->bits32, sizeof(val), 500);111 112	mutex_unlock(&priv->io_mutex);113}114 115static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)116{117	struct rtl8187_priv *priv = dev->priv;118	u16 reg80, reg84, reg82;119	u32 bangdata;120	int i;121 122	bangdata = (data << 4) | (addr & 0xf);123 124	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;125	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);126 127	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);128 129	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);130	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);131	udelay(10);132 133	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));134	udelay(2);135	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);136	udelay(10);137 138	for (i = 15; i >= 0; i--) {139		u16 reg = reg80 | (bangdata & (1 << i)) >> i;140 141		if (i & 1)142			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);143 144		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));145		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));146 147		if (!(i & 1))148			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);149	}150 151	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));152	udelay(10);153 154	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));155	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);156}157 158static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)159{160	struct rtl8187_priv *priv = dev->priv;161	u16 reg80, reg82, reg84;162 163	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);164	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);165	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);166 167	reg80 &= ~(0x3 << 2);168	reg84 &= ~0xF;169 170	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007);171	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007);172	udelay(10);173 174	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));175	udelay(2);176 177	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);178	udelay(10);179 180	mutex_lock(&priv->io_mutex);181 182	priv->io_dmabuf->bits16 = data;183	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),184			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,185			addr, 0x8225, &priv->io_dmabuf->bits16, sizeof(data),186			500);187 188	mutex_unlock(&priv->io_mutex);189 190	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));191	udelay(10);192 193	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));194	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);195}196 197static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)198{199	struct rtl8187_priv *priv = dev->priv;200 201	if (priv->asic_rev)202		rtl8225_write_8051(dev, addr, cpu_to_le16(data));203	else204		rtl8225_write_bitbang(dev, addr, data);205}206 207static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)208{209	struct rtl8187_priv *priv = dev->priv;210	u16 reg80, reg82, reg84, out;211	int i;212 213	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);214	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);215	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);216 217	reg80 &= ~0xF;218 219	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);220	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);221 222	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));223	udelay(4);224	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);225	udelay(5);226 227	for (i = 4; i >= 0; i--) {228		u16 reg = reg80 | ((addr >> i) & 1);229 230		if (!(i & 1)) {231			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);232			udelay(1);233		}234 235		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,236				  reg | (1 << 1));237		udelay(2);238		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,239				  reg | (1 << 1));240		udelay(2);241 242		if (i & 1) {243			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);244			udelay(1);245		}246	}247 248	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,249			  reg80 | (1 << 3) | (1 << 1));250	udelay(2);251	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,252			  reg80 | (1 << 3));253	udelay(2);254	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,255			  reg80 | (1 << 3));256	udelay(2);257 258	out = 0;259	for (i = 11; i >= 0; i--) {260		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,261				  reg80 | (1 << 3));262		udelay(1);263		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,264				  reg80 | (1 << 3) | (1 << 1));265		udelay(2);266		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,267				  reg80 | (1 << 3) | (1 << 1));268		udelay(2);269		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,270				  reg80 | (1 << 3) | (1 << 1));271		udelay(2);272 273		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))274			out |= 1 << i;275 276		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,277				  reg80 | (1 << 3));278		udelay(2);279	}280 281	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,282			  reg80 | (1 << 3) | (1 << 2));283	udelay(2);284 285	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);286	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);287	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);288 289	return out;290}291 292static const u16 rtl8225bcd_rxgain[] = {293	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,294	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,295	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,296	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,297	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,298	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,299	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,300	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,301	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,302	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,303	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,304	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb305};306 307static const u8 rtl8225_agc[] = {308	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,309	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,310	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,311	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,312	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,313	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,314	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,315	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,316	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,317	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,318	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,319	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,320	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,321	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,322	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,323	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01324};325 326static const u8 rtl8225_gain[] = {327	0x23, 0x88, 0x7c, 0xa5,	/* -82dBm */328	0x23, 0x88, 0x7c, 0xb5,	/* -82dBm */329	0x23, 0x88, 0x7c, 0xc5,	/* -82dBm */330	0x33, 0x80, 0x79, 0xc5,	/* -78dBm */331	0x43, 0x78, 0x76, 0xc5,	/* -74dBm */332	0x53, 0x60, 0x73, 0xc5,	/* -70dBm */333	0x63, 0x58, 0x70, 0xc5,	/* -66dBm */334};335 336static const u8 rtl8225_threshold[] = {337	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd338};339 340static const u8 rtl8225_tx_gain_cck_ofdm[] = {341	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e342};343 344static const u8 rtl8225_tx_power_cck[] = {345	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,346	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,347	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,348	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,349	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,350	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03351};352 353static const u8 rtl8225_tx_power_cck_ch14[] = {354	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,355	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,356	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,357	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,358	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,359	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00360};361 362static const u8 rtl8225_tx_power_ofdm[] = {363	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4364};365 366static const u32 rtl8225_chan[] = {367	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,368	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72369};370 371static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)372{373	struct rtl8187_priv *priv = dev->priv;374	u8 cck_power, ofdm_power;375	const u8 *tmp;376	u32 reg;377	int i;378 379	cck_power = priv->channels[channel - 1].hw_value & 0xF;380	ofdm_power = priv->channels[channel - 1].hw_value >> 4;381 382	cck_power = min(cck_power, (u8)11);383	if (ofdm_power > (u8)15)384		ofdm_power = 25;385	else386		ofdm_power += 10;387 388	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,389			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);390 391	if (channel == 14)392		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];393	else394		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];395 396	for (i = 0; i < 8; i++)397		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);398 399	msleep(1); // FIXME: optional?400 401	/* anaparam2 on */402	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);403	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);404	rtl818x_iowrite8(priv, &priv->map->CONFIG3,405			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);406	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,407			  RTL8187_RTL8225_ANAPARAM2_ON);408	rtl818x_iowrite8(priv, &priv->map->CONFIG3,409			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);410	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);411 412	rtl8225_write_phy_ofdm(dev, 2, 0x42);413	rtl8225_write_phy_ofdm(dev, 6, 0x00);414	rtl8225_write_phy_ofdm(dev, 8, 0x00);415 416	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,417			 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);418 419	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];420 421	rtl8225_write_phy_ofdm(dev, 5, *tmp);422	rtl8225_write_phy_ofdm(dev, 7, *tmp);423 424	msleep(1);425}426 427static void rtl8225_rf_init(struct ieee80211_hw *dev)428{429	struct rtl8187_priv *priv = dev->priv;430	int i;431 432	rtl8225_write(dev, 0x0, 0x067);433	rtl8225_write(dev, 0x1, 0xFE0);434	rtl8225_write(dev, 0x2, 0x44D);435	rtl8225_write(dev, 0x3, 0x441);436	rtl8225_write(dev, 0x4, 0x486);437	rtl8225_write(dev, 0x5, 0xBC0);438	rtl8225_write(dev, 0x6, 0xAE6);439	rtl8225_write(dev, 0x7, 0x82A);440	rtl8225_write(dev, 0x8, 0x01F);441	rtl8225_write(dev, 0x9, 0x334);442	rtl8225_write(dev, 0xA, 0xFD4);443	rtl8225_write(dev, 0xB, 0x391);444	rtl8225_write(dev, 0xC, 0x050);445	rtl8225_write(dev, 0xD, 0x6DB);446	rtl8225_write(dev, 0xE, 0x029);447	rtl8225_write(dev, 0xF, 0x914); msleep(100);448 449	rtl8225_write(dev, 0x2, 0xC4D); msleep(200);450	rtl8225_write(dev, 0x2, 0x44D); msleep(200);451 452	if (!(rtl8225_read(dev, 6) & (1 << 7))) {453		rtl8225_write(dev, 0x02, 0x0c4d);454		msleep(200);455		rtl8225_write(dev, 0x02, 0x044d);456		msleep(100);457		if (!(rtl8225_read(dev, 6) & (1 << 7)))458			wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n",459				   rtl8225_read(dev, 6));460	}461 462	rtl8225_write(dev, 0x0, 0x127);463 464	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {465		rtl8225_write(dev, 0x1, i + 1);466		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);467	}468 469	rtl8225_write(dev, 0x0, 0x027);470	rtl8225_write(dev, 0x0, 0x22F);471 472	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {473		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);474		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);475	}476 477	msleep(1);478 479	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);480	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);481	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);482	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);483	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);484	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);485	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);486	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);487	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);488	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);489	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09);490	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);491	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);492	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);493	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);494	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);495	rtl8225_write_phy_ofdm(dev, 0x11, 0x06);496	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);497	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);498	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);499	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);500	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);501	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);502	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);503	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);504	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);505	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76);506	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);507	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);508	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);509	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);510	rtl8225_write_phy_ofdm(dev, 0x21, 0x27);511	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);512	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);513	rtl8225_write_phy_ofdm(dev, 0x25, 0x20);514	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);515	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);516 517	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);518	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);519	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);520	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);521 522	rtl8225_write_phy_cck(dev, 0x00, 0x98);523	rtl8225_write_phy_cck(dev, 0x03, 0x20);524	rtl8225_write_phy_cck(dev, 0x04, 0x7e);525	rtl8225_write_phy_cck(dev, 0x05, 0x12);526	rtl8225_write_phy_cck(dev, 0x06, 0xfc);527	rtl8225_write_phy_cck(dev, 0x07, 0x78);528	rtl8225_write_phy_cck(dev, 0x08, 0x2e);529	rtl8225_write_phy_cck(dev, 0x10, 0x9b);530	rtl8225_write_phy_cck(dev, 0x11, 0x88);531	rtl8225_write_phy_cck(dev, 0x12, 0x47);532	rtl8225_write_phy_cck(dev, 0x13, 0xd0);533	rtl8225_write_phy_cck(dev, 0x19, 0x00);534	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);535	rtl8225_write_phy_cck(dev, 0x1b, 0x08);536	rtl8225_write_phy_cck(dev, 0x40, 0x86);537	rtl8225_write_phy_cck(dev, 0x41, 0x8d);538	rtl8225_write_phy_cck(dev, 0x42, 0x15);539	rtl8225_write_phy_cck(dev, 0x43, 0x18);540	rtl8225_write_phy_cck(dev, 0x44, 0x1f);541	rtl8225_write_phy_cck(dev, 0x45, 0x1e);542	rtl8225_write_phy_cck(dev, 0x46, 0x1a);543	rtl8225_write_phy_cck(dev, 0x47, 0x15);544	rtl8225_write_phy_cck(dev, 0x48, 0x10);545	rtl8225_write_phy_cck(dev, 0x49, 0x0a);546	rtl8225_write_phy_cck(dev, 0x4a, 0x05);547	rtl8225_write_phy_cck(dev, 0x4b, 0x02);548	rtl8225_write_phy_cck(dev, 0x4c, 0x05);549 550	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);551 552	rtl8225_rf_set_tx_power(dev, 1);553 554	/* RX antenna default to A */555	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */556	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */557 558	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */559	msleep(1);560	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);561 562	/* set sensitivity */563	rtl8225_write(dev, 0x0c, 0x50);564	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);565	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);566	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);567	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);568	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);569}570 571static const u8 rtl8225z2_agc[] = {572	0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f,573	0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,574	0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f,575	0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,576	0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,577	0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,578	0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28,579	0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,580	0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30,581	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,582	0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31583};584static const u8 rtl8225z2_ofdm[] = {585	0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,586	0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,587	0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,588	0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,589	0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f,590	0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,591	0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,592	0x6d, 0x3c, 0xfb, 0x07593};594 595static const u8 rtl8225z2_tx_power_cck_ch14[] = {596	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00,597	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,598	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00,599	0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00600};601 602static const u8 rtl8225z2_tx_power_cck[] = {603	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04,604	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03,605	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03,606	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03607};608 609static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {610	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,611	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,612	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,613	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,614	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,615	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23616};617 618static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)619{620	struct rtl8187_priv *priv = dev->priv;621	u8 cck_power, ofdm_power;622	const u8 *tmp;623	u32 reg;624	int i;625 626	cck_power = priv->channels[channel - 1].hw_value & 0xF;627	ofdm_power = priv->channels[channel - 1].hw_value >> 4;628 629	cck_power = min(cck_power, (u8)15);630	cck_power += priv->txpwr_base & 0xF;631	cck_power = min(cck_power, (u8)35);632 633	if (ofdm_power > (u8)15)634		ofdm_power = 25;635	else636		ofdm_power += 10;637	ofdm_power += priv->txpwr_base >> 4;638	ofdm_power = min(ofdm_power, (u8)35);639 640	if (channel == 14)641		tmp = rtl8225z2_tx_power_cck_ch14;642	else643		tmp = rtl8225z2_tx_power_cck;644 645	for (i = 0; i < 8; i++)646		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);647 648	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,649			 rtl8225z2_tx_gain_cck_ofdm[cck_power]);650	msleep(1);651 652	/* anaparam2 on */653	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);654	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);655	rtl818x_iowrite8(priv, &priv->map->CONFIG3,656			reg | RTL818X_CONFIG3_ANAPARAM_WRITE);657	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,658			  RTL8187_RTL8225_ANAPARAM2_ON);659	rtl818x_iowrite8(priv, &priv->map->CONFIG3,660			reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);661	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);662 663	rtl8225_write_phy_ofdm(dev, 2, 0x42);664	rtl8225_write_phy_ofdm(dev, 5, 0x00);665	rtl8225_write_phy_ofdm(dev, 6, 0x40);666	rtl8225_write_phy_ofdm(dev, 7, 0x00);667	rtl8225_write_phy_ofdm(dev, 8, 0x40);668 669	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,670			 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);671	msleep(1);672}673 674static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)675{676	struct rtl8187_priv *priv = dev->priv;677	u8 cck_power, ofdm_power;678	const u8 *tmp;679	int i;680 681	cck_power = priv->channels[channel - 1].hw_value & 0xF;682	ofdm_power = priv->channels[channel - 1].hw_value >> 4;683 684	cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7;685	cck_power += priv->txpwr_base & 0xF;686	cck_power = min(cck_power, (u8)35);687 688	if (ofdm_power > 15)689		ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25;690	else691		ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10;692	ofdm_power += (priv->txpwr_base >> 4) & 0xF;693	ofdm_power = min(ofdm_power, (u8)35);694 695	if (channel == 14)696		tmp = rtl8225z2_tx_power_cck_ch14;697	else698		tmp = rtl8225z2_tx_power_cck;699 700	if (priv->hw_rev == RTL8187BvB) {701		if (cck_power <= 6)702			; /* do nothing */703		else if (cck_power <= 11)704			tmp += 8;705		else706			tmp += 16;707	} else {708		if (cck_power <= 5)709			; /* do nothing */710		else if (cck_power <= 11)711			tmp += 8;712		else if (cck_power <= 17)713			tmp += 16;714		else715			tmp += 24;716	}717 718	for (i = 0; i < 8; i++)719		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);720 721	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,722			 rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1);723	msleep(1);724 725	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,726			 rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1);727	if (priv->hw_rev == RTL8187BvB) {728		if (ofdm_power <= 11) {729			rtl8225_write_phy_ofdm(dev, 0x87, 0x60);730			rtl8225_write_phy_ofdm(dev, 0x89, 0x60);731		} else {732			rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);733			rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);734		}735	} else {736		if (ofdm_power <= 11) {737			rtl8225_write_phy_ofdm(dev, 0x87, 0x5c);738			rtl8225_write_phy_ofdm(dev, 0x89, 0x5c);739		} else if (ofdm_power <= 17) {740			rtl8225_write_phy_ofdm(dev, 0x87, 0x54);741			rtl8225_write_phy_ofdm(dev, 0x89, 0x54);742		} else {743			rtl8225_write_phy_ofdm(dev, 0x87, 0x50);744			rtl8225_write_phy_ofdm(dev, 0x89, 0x50);745		}746	}747	msleep(1);748}749 750static const u16 rtl8225z2_rxgain[] = {751	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,752	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,753	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,754	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,755	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,756	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,757	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,758	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,759	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,760	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,761	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,762	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb763};764 765static const u8 rtl8225z2_gain_bg[] = {766	0x23, 0x15, 0xa5, /* -82-1dBm */767	0x23, 0x15, 0xb5, /* -82-2dBm */768	0x23, 0x15, 0xc5, /* -82-3dBm */769	0x33, 0x15, 0xc5, /* -78dBm */770	0x43, 0x15, 0xc5, /* -74dBm */771	0x53, 0x15, 0xc5, /* -70dBm */772	0x63, 0x15, 0xc5  /* -66dBm */773};774 775static void rtl8225z2_rf_init(struct ieee80211_hw *dev)776{777	struct rtl8187_priv *priv = dev->priv;778	int i;779 780	rtl8225_write(dev, 0x0, 0x2BF);781	rtl8225_write(dev, 0x1, 0xEE0);782	rtl8225_write(dev, 0x2, 0x44D);783	rtl8225_write(dev, 0x3, 0x441);784	rtl8225_write(dev, 0x4, 0x8C3);785	rtl8225_write(dev, 0x5, 0xC72);786	rtl8225_write(dev, 0x6, 0x0E6);787	rtl8225_write(dev, 0x7, 0x82A);788	rtl8225_write(dev, 0x8, 0x03F);789	rtl8225_write(dev, 0x9, 0x335);790	rtl8225_write(dev, 0xa, 0x9D4);791	rtl8225_write(dev, 0xb, 0x7BB);792	rtl8225_write(dev, 0xc, 0x850);793	rtl8225_write(dev, 0xd, 0xCDF);794	rtl8225_write(dev, 0xe, 0x02B);795	rtl8225_write(dev, 0xf, 0x114);796	msleep(100);797 798	rtl8225_write(dev, 0x0, 0x1B7);799 800	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {801		rtl8225_write(dev, 0x1, i + 1);802		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);803	}804 805	rtl8225_write(dev, 0x3, 0x080);806	rtl8225_write(dev, 0x5, 0x004);807	rtl8225_write(dev, 0x0, 0x0B7);808	rtl8225_write(dev, 0x2, 0xc4D);809 810	msleep(200);811	rtl8225_write(dev, 0x2, 0x44D);812	msleep(100);813 814	if (!(rtl8225_read(dev, 6) & (1 << 7))) {815		rtl8225_write(dev, 0x02, 0x0C4D);816		msleep(200);817		rtl8225_write(dev, 0x02, 0x044D);818		msleep(100);819		if (!(rtl8225_read(dev, 6) & (1 << 7)))820			wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n",821				   rtl8225_read(dev, 6));822	}823 824	msleep(200);825 826	rtl8225_write(dev, 0x0, 0x2BF);827 828	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {829		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);830		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);831	}832 833	msleep(1);834 835	rtl8225_write_phy_ofdm(dev, 0x00, 0x01);836	rtl8225_write_phy_ofdm(dev, 0x01, 0x02);837	rtl8225_write_phy_ofdm(dev, 0x02, 0x42);838	rtl8225_write_phy_ofdm(dev, 0x03, 0x00);839	rtl8225_write_phy_ofdm(dev, 0x04, 0x00);840	rtl8225_write_phy_ofdm(dev, 0x05, 0x00);841	rtl8225_write_phy_ofdm(dev, 0x06, 0x40);842	rtl8225_write_phy_ofdm(dev, 0x07, 0x00);843	rtl8225_write_phy_ofdm(dev, 0x08, 0x40);844	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);845	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08);846	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);847	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);848	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);849	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);850	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);851	rtl8225_write_phy_ofdm(dev, 0x10, 0x84);852	rtl8225_write_phy_ofdm(dev, 0x11, 0x07);853	rtl8225_write_phy_ofdm(dev, 0x12, 0x20);854	rtl8225_write_phy_ofdm(dev, 0x13, 0x20);855	rtl8225_write_phy_ofdm(dev, 0x14, 0x00);856	rtl8225_write_phy_ofdm(dev, 0x15, 0x40);857	rtl8225_write_phy_ofdm(dev, 0x16, 0x00);858	rtl8225_write_phy_ofdm(dev, 0x17, 0x40);859	rtl8225_write_phy_ofdm(dev, 0x18, 0xef);860	rtl8225_write_phy_ofdm(dev, 0x19, 0x19);861	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);862	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15);863	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);864	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5);865	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);866	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);867	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);868	rtl8225_write_phy_ofdm(dev, 0x21, 0x17);869	rtl8225_write_phy_ofdm(dev, 0x22, 0x16);870	rtl8225_write_phy_ofdm(dev, 0x23, 0x80);871	rtl8225_write_phy_ofdm(dev, 0x24, 0x46);872	rtl8225_write_phy_ofdm(dev, 0x25, 0x00);873	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);874	rtl8225_write_phy_ofdm(dev, 0x27, 0x88);875 876	rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);877	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);878	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);879	rtl8225_write_phy_ofdm(dev, 0x21, 0x37);880 881	rtl8225_write_phy_cck(dev, 0x00, 0x98);882	rtl8225_write_phy_cck(dev, 0x03, 0x20);883	rtl8225_write_phy_cck(dev, 0x04, 0x7e);884	rtl8225_write_phy_cck(dev, 0x05, 0x12);885	rtl8225_write_phy_cck(dev, 0x06, 0xfc);886	rtl8225_write_phy_cck(dev, 0x07, 0x78);887	rtl8225_write_phy_cck(dev, 0x08, 0x2e);888	rtl8225_write_phy_cck(dev, 0x10, 0x9b);889	rtl8225_write_phy_cck(dev, 0x11, 0x88);890	rtl8225_write_phy_cck(dev, 0x12, 0x47);891	rtl8225_write_phy_cck(dev, 0x13, 0xd0);892	rtl8225_write_phy_cck(dev, 0x19, 0x00);893	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);894	rtl8225_write_phy_cck(dev, 0x1b, 0x08);895	rtl8225_write_phy_cck(dev, 0x40, 0x86);896	rtl8225_write_phy_cck(dev, 0x41, 0x8d);897	rtl8225_write_phy_cck(dev, 0x42, 0x15);898	rtl8225_write_phy_cck(dev, 0x43, 0x18);899	rtl8225_write_phy_cck(dev, 0x44, 0x36);900	rtl8225_write_phy_cck(dev, 0x45, 0x35);901	rtl8225_write_phy_cck(dev, 0x46, 0x2e);902	rtl8225_write_phy_cck(dev, 0x47, 0x25);903	rtl8225_write_phy_cck(dev, 0x48, 0x1c);904	rtl8225_write_phy_cck(dev, 0x49, 0x12);905	rtl8225_write_phy_cck(dev, 0x4a, 0x09);906	rtl8225_write_phy_cck(dev, 0x4b, 0x04);907	rtl8225_write_phy_cck(dev, 0x4c, 0x05);908 909	rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);910 911	rtl8225z2_rf_set_tx_power(dev, 1);912 913	/* RX antenna default to A */914	rtl8225_write_phy_cck(dev, 0x10, 0x9b);			/* B: 0xDB */915	rtl8225_write_phy_ofdm(dev, 0x26, 0x90);		/* B: 0x10 */916 917	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */918	msleep(1);919	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);920}921 922static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)923{924	struct rtl8187_priv *priv = dev->priv;925	int i;926 927	rtl8225_write(dev, 0x0, 0x0B7);928	rtl8225_write(dev, 0x1, 0xEE0);929	rtl8225_write(dev, 0x2, 0x44D);930	rtl8225_write(dev, 0x3, 0x441);931	rtl8225_write(dev, 0x4, 0x8C3);932	rtl8225_write(dev, 0x5, 0xC72);933	rtl8225_write(dev, 0x6, 0x0E6);934	rtl8225_write(dev, 0x7, 0x82A);935	rtl8225_write(dev, 0x8, 0x03F);936	rtl8225_write(dev, 0x9, 0x335);937	rtl8225_write(dev, 0xa, 0x9D4);938	rtl8225_write(dev, 0xb, 0x7BB);939	rtl8225_write(dev, 0xc, 0x850);940	rtl8225_write(dev, 0xd, 0xCDF);941	rtl8225_write(dev, 0xe, 0x02B);942	rtl8225_write(dev, 0xf, 0x114);943 944	rtl8225_write(dev, 0x0, 0x1B7);945 946	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {947		rtl8225_write(dev, 0x1, i + 1);948		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);949	}950 951	rtl8225_write(dev, 0x3, 0x080);952	rtl8225_write(dev, 0x5, 0x004);953	rtl8225_write(dev, 0x0, 0x0B7);954 955	rtl8225_write(dev, 0x2, 0xC4D);956 957	rtl8225_write(dev, 0x2, 0x44D);958	rtl8225_write(dev, 0x0, 0x2BF);959 960	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);961	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);962	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);963 964	rtl8225_write_phy_ofdm(dev, 0x80, 0x12);965	for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) {966		rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]);967		rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i);968		rtl8225_write_phy_ofdm(dev, 0xE, 0);969	}970	rtl8225_write_phy_ofdm(dev, 0x80, 0x10);971 972	for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)973		rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);974 975	rtl8225_write_phy_ofdm(dev, 0x97, 0x46);976	rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);977	rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);978	rtl8225_write_phy_cck(dev, 0xc1, 0x88);979}980 981static void rtl8225_rf_stop(struct ieee80211_hw *dev)982{983	rtl8225_write(dev, 0x4, 0x1f);984}985 986static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,987				   struct ieee80211_conf *conf)988{989	struct rtl8187_priv *priv = dev->priv;990	int chan =991		ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);992 993	if (priv->rf->init == rtl8225_rf_init)994		rtl8225_rf_set_tx_power(dev, chan);995	else if (priv->rf->init == rtl8225z2_rf_init)996		rtl8225z2_rf_set_tx_power(dev, chan);997	else998		rtl8225z2_b_rf_set_tx_power(dev, chan);999 1000	rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);1001	msleep(10);1002}1003 1004static const struct rtl818x_rf_ops rtl8225_ops = {1005	.name		= "rtl8225",1006	.init		= rtl8225_rf_init,1007	.stop		= rtl8225_rf_stop,1008	.set_chan	= rtl8225_rf_set_channel1009};1010 1011static const struct rtl818x_rf_ops rtl8225z2_ops = {1012	.name		= "rtl8225z2",1013	.init		= rtl8225z2_rf_init,1014	.stop		= rtl8225_rf_stop,1015	.set_chan	= rtl8225_rf_set_channel1016};1017 1018static const struct rtl818x_rf_ops rtl8225z2_b_ops = {1019	.name		= "rtl8225z2",1020	.init		= rtl8225z2_b_rf_init,1021	.stop		= rtl8225_rf_stop,1022	.set_chan	= rtl8225_rf_set_channel1023};1024 1025const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev)1026{1027	u16 reg8, reg9;1028	struct rtl8187_priv *priv = dev->priv;1029 1030	if (!priv->is_rtl8187b) {1031		rtl8225_write(dev, 0, 0x1B7);1032 1033		reg8 = rtl8225_read(dev, 8);1034		reg9 = rtl8225_read(dev, 9);1035 1036		rtl8225_write(dev, 0, 0x0B7);1037 1038		if (reg8 != 0x588 || reg9 != 0x700)1039			return &rtl8225_ops;1040 1041		return &rtl8225z2_ops;1042	} else1043		return &rtl8225z2_b_ops;1044}1045